提交 3018428e 作者: 龚洪江

Merge branch 'develop'

...@@ -14,4 +14,4 @@ patches: ...@@ -14,4 +14,4 @@ patches:
images: images:
- name: REGISTRY/NAMESPACE/IMAGE:TAG - name: REGISTRY/NAMESPACE/IMAGE:TAG
newName: mmc-registry.cn-shenzhen.cr.aliyuncs.com/sharefly-dev/admin newName: mmc-registry.cn-shenzhen.cr.aliyuncs.com/sharefly-dev/admin
newTag: 076c71a473e24a5f127df294af6ea3eb20b5858c newTag: 063cc3527bbd3e1199f9aec0d902b1c76c712a0a
...@@ -72,3 +72,62 @@ export type categoryDetailsType = InterFunction< ...@@ -72,3 +72,62 @@ export type categoryDetailsType = InterFunction<
>; >;
//分类-关联列表 //分类-关联列表
export type categoryRelevantType = InterFunction<{ id: number; type: number }, any>; export type categoryRelevantType = InterFunction<{ id: number; type: number }, any>;
//分类管理-分类列表(新)
type categoryItemType = {
id: number;
name: string;
createTime: string;
icon: string;
description: string;
subDTOList: (Omit<categoryItemType, 'createTime' | 'icon' | 'subDTOList' | 'sort'> & {
categoryPrimaryId: number;
})[];
sort: number;
};
export type categoryListRespType = InterItemFunction<{ id?: number }, categoryItemType[]>;
//分类管理-1级分类新增(新)
export type addPrimaryCategoryType = InterFunction<
{
description: string;
icon: string;
name: string;
},
any
>;
//分类管理-1级分类编辑(新)
export type updatePrimaryCategoryType = InterFunction<
{
description: string;
icon: string;
name: string;
id?: number;
},
any
>;
//分类管理-1级分类删除(新)
export type deletePrimaryCategoryType = InterFunction<{ id: number }, any>;
//分类管理-1级分类交换顺序(新)
export type exchangeType = InterFunction<{ id: number; sort: number }[], any>;
//分类管理-2级分类新增(新)
export type addSubCategoryType = InterFunction<
{
categoryPrimaryId: number;
description: string;
name: string;
},
any
>;
//分类管理-2级分类编辑(新)
export type updateSubCategoryType = InterFunction<
{
categoryPrimaryId: number;
description: string;
name: string;
id?: number;
},
any
>;
//分类管理-2级分类删除(新)
export type deleteSubCategoryType = InterFunction<{ id: number }, any>;
...@@ -11,6 +11,7 @@ export type BackEndLoginType = InterFunction< ...@@ -11,6 +11,7 @@ export type BackEndLoginType = InterFunction<
phoneNum: string; phoneNum: string;
userName: string; userName: string;
nickName: string; nickName: string;
appUserAccountId?: number;
companyInfoVO: { companyInfoVO: {
id: number; id: number;
companyType: number; companyType: number;
...@@ -23,6 +24,7 @@ export type BackEndLoginType = InterFunction< ...@@ -23,6 +24,7 @@ export type BackEndLoginType = InterFunction<
companyUserName: string; companyUserName: string;
phoneNum: string; phoneNum: string;
remark: string; remark: string;
leader: number;
}; };
roleInfo: { roleInfo: {
id: number; id: number;
...@@ -157,3 +159,13 @@ export type batchRemoveBannerInfo = InterFunction<any, NonNullable<unknown>>; ...@@ -157,3 +159,13 @@ export type batchRemoveBannerInfo = InterFunction<any, NonNullable<unknown>>;
export type removeBannerInfo = InterFunction<{ id: number }, NonNullable<unknown>>; export type removeBannerInfo = InterFunction<{ id: number }, NonNullable<unknown>>;
// V1.0.1-banner-排序交换 // V1.0.1-banner-排序交换
export type exchangeBannerInfo = InterFunction<Array<any>, NonNullable<unknown>>; export type exchangeBannerInfo = InterFunction<Array<any>, NonNullable<unknown>>;
//手机号筛选小程序用户
export type getUserAccountByPhoneNumType = InterFunction<
{ phoneNum: string },
{ id: number; nickName: string; userName: string; phoneNum: string; uid: string }[]
>;
//获取小程序二维码
export type appletQRCodeType = InterFunction<{ page: string; scene: string }, string>;
//登录信息-获取
export type getLoginInfoType = InterFunction<{ randomLoginCode: string }, any>;
...@@ -99,7 +99,171 @@ export type otherServiceType = InterFunction<any, { id: number; saleServiceName: ...@@ -99,7 +99,171 @@ export type otherServiceType = InterFunction<any, { id: number; saleServiceName:
export type skuUnitType = InterFunction<any, { id: number; unitName: string }[]>; export type skuUnitType = InterFunction<any, { id: number; unitName: string }[]>;
//商品-批量上下架 //商品-批量上下架
export type batchOnShelfOrTakeDownType = InterFunction<{ goodsIds: number[]; status: number }, any>; export type batchOnShelfOrTakeDownType = InterFunction<{ goodsIds: number[]; status: number }, any>;
//商品-单个上下架(新)
export type upOrDownShelfType = InterFunction<{ id: number; status: number }, any>;
//商品批量删除 //商品批量删除
export type batchRemoveWareInfoType = InterFunction<number[], any>; export type batchRemoveWareInfoType = InterFunction<number[], any>;
//商品-单个删除
export type removeMallGoodsType = InterFunction<{ id: number }, any>;
//商品-上下移动 //商品-上下移动
export type exchangeGoodsInfoType = InterFunction<{ firstId: number; secondId: number }, any>; export type exchangeGoodsInfoType = InterFunction<{ firstId: number; secondId: number }, any>;
//商品-新增(新)
export type addMallGoodsType = InterFunction<
{
categoryPrimaryId: number;
categorySubId: number;
description: string;
goodsDetails: string;
goodsLabel: string;
goodsSpecList: {
chooseType: number;
goodsSpecValuesList: {
channelPrice?: number;
id: any;
partNo: string;
salePrice: number;
showPrice: number;
specValueImage: string;
specValueName: string;
stock?: number;
goodsSpecId?: number;
}[];
id: any;
mallGoodsId: number;
must: number;
skuUnitId: number;
specName: string;
}[];
labelShow: number;
resourcesList: {
id: number;
type: number;
url: string;
}[];
shelfStatus: number;
tradeName: string;
},
any
>;
//商品-编辑(新)
export type editMallGoodsType = InterFunction<
{
categoryPrimaryId: number;
categorySubId: number;
description: string;
goodsDetails: string;
goodsLabel: string;
goodsSpecList: {
chooseType: number;
goodsSpecValuesList: {
channelPrice?: number;
id: any;
partNo: string;
salePrice: number;
showPrice: number;
specValueImage: string;
specValueName: string;
stock?: number;
goodsSpecId: number;
}[];
id: any;
mallGoodsId: number;
must: number;
skuUnitId: number;
specName: string;
}[];
id: number;
labelShow: number;
resourcesList: {
id: number;
type: number;
url: string;
}[];
shelfStatus: number;
tradeName: string;
},
any
>;
//商品-列表(新)
export type listPageGoodsInfoType = InterItemFunction<
{ categoryPrimaryId?: number; tradeName?: string; shelfStatus?: number },
{
categoryPrimaryId: number;
categorySubId: number;
createTime: string;
description: string;
goodsDetails: string;
goodsLabel: string;
goodsSpecList: {
chooseType: number;
goodsSpecValuesList: {
channelPrice: number;
goodsSpecId: number;
id: number;
partNo: string;
salePrice: number;
showPrice: number;
specValueImage: string;
specValueName: string;
stock: number;
}[];
id: number;
mallGoodsId: number;
must: number;
skuUnitId: number;
specName: string;
}[];
id: number;
labelShow: number;
resourcesList: {
id: number;
type: number;
url: string;
}[];
shelfStatus: number;
tradeName: string;
userAccountId: number;
}[]
>;
//商城-详情(新)
export type mallGoodsDetailsType = InterFunction<
{ id: number },
{
categoryPrimaryId: number;
categorySubId: number;
createTime: string;
description: string;
goodsDetails: string;
goodsLabel: string;
goodsSpecList: {
chooseType: number;
goodsSpecValuesList: {
channelPrice: number;
goodsSpecId: number;
id: number;
partNo: string;
salePrice: number;
showPrice: number;
specValueImage: string;
specValueName: string;
stock: number;
}[];
id: number;
mallGoodsId: number;
must: number;
skuUnitId: number;
specName: string;
}[];
id: number;
labelShow: number;
resourcesList: {
id: number;
type: number;
url: string;
}[];
shelfStatus: number;
tradeName: string;
userAccountId: number;
}
>;
...@@ -130,6 +130,8 @@ export type listCompanyPage = InterListFunction< ...@@ -130,6 +130,8 @@ export type listCompanyPage = InterListFunction<
phoneNum: string; phoneNum: string;
province: string; province: string;
remark: string; remark: string;
lat: number;
lon: number;
} }
>; >;
// 单位-新增 // 单位-新增
...@@ -147,6 +149,8 @@ export type listCompanyAdd = InterFunction< ...@@ -147,6 +149,8 @@ export type listCompanyAdd = InterFunction<
province?: string; province?: string;
remark?: string; remark?: string;
area?: string[]; area?: string[];
lat: number;
lon: number;
}, },
NonNullable<unknown> NonNullable<unknown>
>; >;
...@@ -165,6 +169,8 @@ export type listCompanyUpdate = InterFunction< ...@@ -165,6 +169,8 @@ export type listCompanyUpdate = InterFunction<
province?: string; province?: string;
remark?: string; remark?: string;
area?: string[]; area?: string[];
lat: number;
lon: number;
}, },
NonNullable<unknown> NonNullable<unknown>
>; >;
...@@ -184,6 +190,82 @@ export type listCompanyRemove = InterFunction< ...@@ -184,6 +190,82 @@ export type listCompanyRemove = InterFunction<
}, },
NonNullable<unknown> NonNullable<unknown>
>; >;
//单位-详情
export type getCompanyInfoByIdType = InterFunction<
{ id: number },
{
address: string;
city: string;
companyName: string;
companyType: number;
companyUserName: string;
district: string;
fullName: string;
id: number;
phoneNum: string;
province: string;
remark: string;
}
>;
//单位-成员列表
export type listCompanyMembersType = InterItemFunction<
{ companyInfoId: number },
{
accountStatus: number;
accountType: number;
companyAuthStatus: number;
companyName: string;
cooperationTagVOS: {
createTime: string;
id: number;
tagDescription: string;
tagImg: string;
tagName: string;
tagRequire: string;
}[];
createTime: string;
deleted: number;
email: string;
id: number;
inviteCount: number;
leader: number;
nickName: string;
phoneNum: string;
portType: number;
realNameAuthStatus: number;
remark: string;
source: number;
uid: string;
userImg: string;
userName: string;
userRcdVO: {
createTime: string;
id: number;
rcdNickname: string;
rcdUserId: number;
rcdUserName: string;
remark: string;
userAccountId: number;
};
userSex: number;
}[]
>;
//单位-成员绑定
export type bindingCompanyMemberType = InterFunction<
{ companyInfoId: number; userAccountId: number },
any
>;
//单位-成员解绑
export type unbindCompanyMemberType = InterFunction<
{ companyInfoId: number; userAccountId: number },
any
>;
//单位-管理员转让
export type transferLeaderType = InterFunction<
{ companyInfoId: number; fromUserAccountId: number; toUserAccountId: number },
any
>;
//账号权限-列表 //账号权限-列表
export type listRoleInfoPageType = InterItemFunction< export type listRoleInfoPageType = InterItemFunction<
{ numberOrName?: string }, { numberOrName?: string },
......
import axios from '../request'; import axios from '../request';
import { import {
addPrimaryCategoryType,
addSubCategoryType,
categoryDetailsType, categoryDetailsType,
categoryListRespType,
categoryListType, categoryListType,
categoryRelevantType, categoryRelevantType,
deletePrimaryCategoryType,
deleteSubCategoryType,
directoryListType, directoryListType,
directoryPageListType, directoryPageListType,
exchangeType,
updatePrimaryCategoryType,
updateSubCategoryType,
} from '~/api/interface/categoryManage'; } from '~/api/interface/categoryManage';
export class CategoryManageAPI { export class CategoryManageAPI {
...@@ -97,4 +105,28 @@ export class CategoryManageAPI { ...@@ -97,4 +105,28 @@ export class CategoryManageAPI {
static getRelevantBusiness: categoryRelevantType = (params) => { static getRelevantBusiness: categoryRelevantType = (params) => {
return axios.get('/pms/classify/queryRelevantBusiness', { params }); return axios.get('/pms/classify/queryRelevantBusiness', { params });
}; };
// 分类管理-分类列表(新)
static getCategoryRespList: categoryListRespType = (data) =>
axios.post('/pms/category/categoryList', data);
// 分类管理-1级分类新增(新)
static addPrimaryCategory: addPrimaryCategoryType = (data) =>
axios.post('/pms/category/addPrimaryCategory', data);
// 分类管理-1级分类编辑(新)
static updatePrimaryCategory: updatePrimaryCategoryType = (data) =>
axios.post('/pms/category/updatePrimaryCategory', data);
// 分类管理-1级分类删除(新)
static deletePrimaryCategory: deletePrimaryCategoryType = (params) =>
axios.get('/pms/category/deletePrimaryCategory', { params });
//分类管理-1级分类交换顺序
static exchangeCategory: exchangeType = (data) => axios.post('/pms/category/exchange', data);
// 分类管理-2级分类新增(新)
static addSubCategory: addSubCategoryType = (data) =>
axios.post('/pms/category/addSubCategory', data);
// 分类管理-2级分类编辑(新)
static updateSubCategory: updateSubCategoryType = (data) =>
axios.post('/pms/category/updateSubCategory', data);
// 分类管理-2级分类删除(新)
static deleteSubCategory: deleteSubCategoryType = (params) =>
axios.get('/pms/category/deleteSubCategory', { params });
} }
import axios from '../request'; import axios from '../request';
import { import {
appletQRCodeType,
BackEndLoginType, BackEndLoginType,
batchRemoveBannerInfo, batchRemoveBannerInfo,
exchangeBannerInfo, exchangeBannerInfo,
getLoginInfoType,
getUserAccountByPhoneNumType,
insertBannerInfo, insertBannerInfo,
insertModuleInfo, insertModuleInfo,
listBannerInfoPage, listBannerInfoPage,
...@@ -70,4 +73,15 @@ export class CommonAPI { ...@@ -70,4 +73,15 @@ export class CommonAPI {
// V1.0.1-banner-排序交换 // V1.0.1-banner-排序交换
static exchangeBannerInfo: exchangeBannerInfo = (params) => static exchangeBannerInfo: exchangeBannerInfo = (params) =>
axios.post('/release/module/exchangeBannerInfo', params); axios.post('/release/module/exchangeBannerInfo', params);
//手机号筛选小程序用户
static getUserAccountByPhoneNum: getUserAccountByPhoneNumType = (params) =>
axios.get('/userapp/user-account/getUserAccountByPhoneNum', { params });
//获取小程序二维码
static getAppletQRCode: appletQRCodeType = (params) => {
return axios.get('/userapp/wx/getAppletQRCode', { params });
};
//获取登录信息
static getLoginInfo: getLoginInfoType = (params) =>
axios.get('/userapp/temp-auth/getLoginInfo', { params });
} }
import { import {
addGoodsType, addGoodsType,
addMallGoodsType,
batchOnShelfOrTakeDownType, batchOnShelfOrTakeDownType,
batchRemoveWareInfoType, batchRemoveWareInfoType,
detailGoodsType, detailGoodsType,
editGoodsType, editGoodsType,
editMallGoodsType,
exchangeGoodsInfoType, exchangeGoodsInfoType,
listGoodsType, listGoodsType,
listPageGoodsInfoType,
mallGoodsDetailsType,
otherServiceType, otherServiceType,
removeMallGoodsType,
skuUnitType, skuUnitType,
upOrDownShelfType,
} from '~/api/interface/goodsType'; } from '~/api/interface/goodsType';
import axios from '../request'; import axios from '../request';
...@@ -30,7 +36,7 @@ class GoodsAPI { ...@@ -30,7 +36,7 @@ class GoodsAPI {
}; };
// 商品-单位 // 商品-单位
static getSkuUnit: skuUnitType = () => { static getSkuUnit: skuUnitType = () => {
return axios.get('/pms/goods/getSkuUnit'); return axios.get('/pms/mall/goods/getSkuUnit');
}; };
// 商品-其它服务列表 // 商品-其它服务列表
static getOtherServiceList: otherServiceType = () => { static getOtherServiceList: otherServiceType = () => {
...@@ -40,13 +46,35 @@ class GoodsAPI { ...@@ -40,13 +46,35 @@ class GoodsAPI {
static batchOnShelfOrTakeDown: batchOnShelfOrTakeDownType = (data) => { static batchOnShelfOrTakeDown: batchOnShelfOrTakeDownType = (data) => {
return axios.post('/pms/goods/batchOnShelfOrTakeDown', data); return axios.post('/pms/goods/batchOnShelfOrTakeDown', data);
}; };
//商品-单个上下架(新)
static upOrDownShelf: upOrDownShelfType = (params) =>
axios.get('/pms/mall/goods/upOrDownShelf', { params });
// 商品-批量删除 // 商品-批量删除
static batchRemoveWareInfo: batchRemoveWareInfoType = (data) => { static batchRemoveWareInfo: batchRemoveWareInfoType = (data) => {
return axios.post('/pms/goods/batchRemoveWareInfo', data); return axios.post('/pms/goods/batchRemoveWareInfo', data);
}; };
//商品-单个删除
static removeMallGoods: removeMallGoodsType = (params) =>
axios.get('/pms/mall/goods/removeMallGoods', { params });
// 商品-上下移动 // 商品-上下移动
static exchangeGoodsInfo: exchangeGoodsInfoType = (params) => { static exchangeGoodsInfo: exchangeGoodsInfoType = (params) => {
return axios.get('/pms/goods/exchangeGoodsInfo', { params }); return axios.get('/pms/goods/exchangeGoodsInfo', { params });
}; };
//商品-上下移动
static exchange: exchangeGoodsInfoType = (params) =>
axios.get('/pms/mall/goods/exchange', { params });
// 商品-新增(新)
static addMallGoods: addMallGoodsType = (data) =>
axios.post('/pms/mall/goods/addMallGoods', data);
//商品-编辑(新)
static editMallGoods: editMallGoodsType = (data) =>
axios.post('/pms/mall/goods/editMallGoods', data);
// 商品-列表(新)
static getListPageGoodsInfo: listPageGoodsInfoType = (data) =>
axios.post('/pms/mall/goods/listPageGoodsInfo', data);
// 商品-详情(新)
static getMallGoodsDetails: mallGoodsDetailsType = (params) =>
axios.get('/pms/mall/goods/mallGoodsDetails', { params });
} }
export default GoodsAPI; export default GoodsAPI;
import { import {
bindingCompanyMemberType,
deleteRoleInfoType, deleteRoleInfoType,
getCompanyInfoByIdType,
getSecondDistrictInfo, getSecondDistrictInfo,
insertBAccountType, insertBAccountType,
insertRoleInfoType, insertRoleInfoType,
listBAccountPageType, listBAccountPageType,
listCompanyAdd, listCompanyAdd,
listCompanyMembersType,
listCompanyPage, listCompanyPage,
listCompanyRemove, listCompanyRemove,
listCompanyUpdate, listCompanyUpdate,
...@@ -12,6 +15,8 @@ import { ...@@ -12,6 +15,8 @@ import {
listRoleInfoPageType, listRoleInfoPageType,
listRoleMenuInfoType, listRoleMenuInfoType,
removeBAccountType, removeBAccountType,
transferLeaderType,
unbindCompanyMemberType,
updateBAccountType, updateBAccountType,
updatePasswordType, updatePasswordType,
updateRoleInfoType, updateRoleInfoType,
...@@ -58,10 +63,25 @@ export class SystemManageAPI { ...@@ -58,10 +63,25 @@ export class SystemManageAPI {
// 单位-删除 // 单位-删除
static listCompanyRemove: listCompanyRemove = (params) => static listCompanyRemove: listCompanyRemove = (params) =>
axios.get('/userapp/company/remove', { params }); axios.get('/userapp/company/remove', { params });
//单位-详情
static getCompanyInfoById: getCompanyInfoByIdType = (params) =>
axios.get('/userapp/company/getCompanyInfoById', { params });
// 单位-区域 // 单位-区域
static getSecondDistrictInfo: getSecondDistrictInfo = (params) => static getSecondDistrictInfo: getSecondDistrictInfo = (params) =>
axios.get('/pms/webDevice/getSecondDistrictInfo', { params }); axios.get('/pms/webDevice/getSecondDistrictInfo', { params });
//单位-成员列表
static getListCompanyMembers: listCompanyMembersType = (params) =>
axios.get('/userapp/company/listCompanyMembers', { params });
//单位-成员绑定
static bindingCompanyMember: bindingCompanyMemberType = (params) =>
axios.get('/userapp/company/bindingCompanyMember', { params });
//单位-成员解除绑定
static unbindCompanyMember: unbindCompanyMemberType = (params) =>
axios.get('/userapp/company/unbindCompanyMember', { params });
//单位-管理员转让
static transferLeader: transferLeaderType = (params) =>
axios.get('/userapp/company/transferLeader', { params });
//账号权限-列表 //账号权限-列表
static getListRoleInfoPage: listRoleInfoPageType = (data) => static getListRoleInfoPage: listRoleInfoPageType = (data) =>
......
...@@ -36,7 +36,7 @@ service.interceptors.response.use( ...@@ -36,7 +36,7 @@ service.interceptors.response.use(
// 当接口返回正常时执行 // 当接口返回正常时执行
if (status === 200) { if (status === 200) {
// 如果不报错就直接返回数据 // 如果不报错就直接返回数据
if (data.code === '200') { if (['200', '7002'].includes(data.code)) {
return Promise.resolve(data); return Promise.resolve(data);
} }
// 重新登录? // 重新登录?
......
<svg width="50" height="50" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><filter x="-5.7%" y="-8.7%" width="112.4%" height="117.4%" filterUnits="objectBoundingBox" id="a"><feOffset dx="2" in="SourceAlpha" result="shadowOffsetOuter1"/><feGaussianBlur stdDeviation="7.5" in="shadowOffsetOuter1" result="shadowBlurOuter1"/><feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.15 0" in="shadowBlurOuter1"/></filter><path d="M2 0h327.586a1 1 0 01.707.293l49.414 49.414a1 1 0 01.293.707V268a2 2 0 01-2 2H2a2 2 0 01-2-2V2a2 2 0 012-2z" id="b"/></defs><g transform="translate(-330)" fill="none" fill-rule="evenodd"><rect fill="#FFF" width="380" height="270" rx="2"/><path d="M366.833 10.833v2.334h2.334v-2.334h-2.334zm-7 16.334h2.334V29.5h-2.334v-2.333zm9.334-9.334h2.333v2.334h-2.333v-2.334zm-9.334 4.667h2.334v2.333h-2.334V22.5zm4.667-4.667h2.333v2.334H364.5v-2.334zM351.667 8.5H361c.644 0 1.167.522 1.167 1.167V19c0 .644-.523 1.167-1.167 1.167h-9.333A1.167 1.167 0 01350.5 19V9.667c0-.645.522-1.167 1.167-1.167zm1.166 2.333v7h7v-7h-7zm2.334 2.334h2.333V15.5h-2.333v-2.333zm10.5-4.667h4.666c.645 0 1.167.522 1.167 1.167v4.666c0 .645-.522 1.167-1.167 1.167h-4.666a1.167 1.167 0 01-1.167-1.167V9.667c0-.645.522-1.167 1.167-1.167zm0 14h4.666c.645 0 1.167.522 1.167 1.167v4.666c0 .645-.522 1.167-1.167 1.167h-4.666a1.167 1.167 0 01-1.167-1.167v-4.666c0-.645.522-1.167 1.167-1.167zm1.166 2.333v2.334h2.334v-2.334h-2.334zM351.667 22.5h4.666c.645 0 1.167.522 1.167 1.167v4.666c0 .645-.522 1.167-1.167 1.167h-4.666a1.167 1.167 0 01-1.167-1.167v-4.666c0-.645.522-1.167 1.167-1.167zm1.166 2.333v2.334h2.334v-2.334h-2.334z" opacity=".5" fill="#000" fill-opacity=".9"/><use fill="#000" filter="url(#a)" xlink:href="#b"/><use fill="#FFF" xlink:href="#b"/></g></svg>
\ No newline at end of file
import { Form, InputNumber, Input, Select } from 'antd'; import { Form, InputNumber, Input, Select, Radio } from 'antd';
import React from 'react'; import React from 'react';
import { Uploader } from '~/components/uploader'; import { Uploader } from '~/components/uploader';
import { UploadOutlined } from '@ant-design/icons'; import { UploadOutlined } from '@ant-design/icons';
...@@ -8,7 +8,7 @@ export interface EditableCellProps extends React.HTMLAttributes<HTMLElement> { ...@@ -8,7 +8,7 @@ export interface EditableCellProps extends React.HTMLAttributes<HTMLElement> {
editing: boolean; editing: boolean;
dataIndex: string; dataIndex: string;
title: any; title: any;
inputType: 'number' | 'text' | 'select' | 'uploader'; inputType: 'number' | 'text' | 'select' | 'uploader' | 'radio' | 'textArea';
record: any; record: any;
index: number; index: number;
children: React.ReactNode; children: React.ReactNode;
...@@ -16,8 +16,10 @@ export interface EditableCellProps extends React.HTMLAttributes<HTMLElement> { ...@@ -16,8 +16,10 @@ export interface EditableCellProps extends React.HTMLAttributes<HTMLElement> {
const EditableCell: React.FC< const EditableCell: React.FC<
EditableCellProps & { EditableCellProps & {
selectOption?: { name: string; id: number }[]; selectOption?: { name: string; id: number }[];
radioOption?: { name: string; id: number }[];
uploadSuccess?: (record: any, result: any) => void; uploadSuccess?: (record: any, result: any) => void;
rules?: any; rules?: any;
maxLength?: number;
} }
> = ({ > = ({
editing, editing,
...@@ -27,15 +29,17 @@ const EditableCell: React.FC< ...@@ -27,15 +29,17 @@ const EditableCell: React.FC<
record, record,
index, index,
selectOption, selectOption,
radioOption,
uploadSuccess, uploadSuccess,
children, children,
rules, rules,
maxLength,
...restProps ...restProps
}) => { }) => {
const inputNode = () => { const inputNode = () => {
switch (inputType) { switch (inputType) {
case 'number': case 'number':
return <InputNumber />; return <InputNumber placeholder={`请输入${title}`} maxLength={maxLength} />;
case 'select': case 'select':
return ( return (
<Select placeholder={`请选择${title}`} style={{ textAlign: 'start' }}> <Select placeholder={`请选择${title}`} style={{ textAlign: 'start' }}>
...@@ -58,8 +62,20 @@ const EditableCell: React.FC< ...@@ -58,8 +62,20 @@ const EditableCell: React.FC<
<UploadOutlined /> <UploadOutlined />
</Uploader> </Uploader>
); );
case 'radio':
return (
<Radio.Group>
{radioOption?.map((v) => (
<Radio value={v.id} key={v.id}>
{v.name}
</Radio>
))}
</Radio.Group>
);
case 'textArea':
return <Input.TextArea placeholder={`请输入${title}`} maxLength={maxLength} showCount />;
default: default:
return <Input placeholder={`请输入${title}`} />; return <Input placeholder={`请输入${title}`} maxLength={maxLength} />;
} }
}; };
return ( return (
......
...@@ -113,6 +113,7 @@ $page-background: #f3f6ff; ...@@ -113,6 +113,7 @@ $page-background: #f3f6ff;
.logo-img { .logo-img {
width: 32px; width: 32px;
height: 32px; height: 32px;
border-radius: 4px;
} }
.logo-text { .logo-text {
......
...@@ -5,7 +5,6 @@ import { Button, Dropdown, MenuProps, Modal } from 'antd'; ...@@ -5,7 +5,6 @@ import { Button, Dropdown, MenuProps, Modal } from 'antd';
import Logo from '../../../assets/icon/logo_big.png'; import Logo from '../../../assets/icon/logo_big.png';
import './index.scss'; import './index.scss';
import { REMOVE_MENU, REMOVE_MENU_ID, SET_COLLAPSE } from '~/store/module/menu'; import { REMOVE_MENU, REMOVE_MENU_ID, SET_COLLAPSE } from '~/store/module/menu';
import { REMOVE_ROLE_ID } from '~/store/module/userInfo';
import { useDispatch, useSelector } from 'react-redux'; import { useDispatch, useSelector } from 'react-redux';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import Cookies from 'js-cookie'; import Cookies from 'js-cookie';
...@@ -42,7 +41,6 @@ export function TitleView() { ...@@ -42,7 +41,6 @@ export function TitleView() {
Cookies.remove('SHAREFLY-TOKEN'); Cookies.remove('SHAREFLY-TOKEN');
dispatch(REMOVE_MENU()); dispatch(REMOVE_MENU());
dispatch(REMOVE_MENU_ID()); dispatch(REMOVE_MENU_ID());
dispatch(REMOVE_ROLE_ID());
}, },
}); });
}} }}
...@@ -62,8 +60,8 @@ export function TitleView() { ...@@ -62,8 +60,8 @@ export function TitleView() {
}} }}
> >
<div className='layout-logo'> <div className='layout-logo'>
<img className='logo-img' src={Logo} alt='云享飞' /> <img src={userInfo.companyInfoVO.brandLogo || Logo} className='logo-img' alt='云享飞' />
<div className='logo-text'>云享飞后台管理</div> <div className='logo-text'>{userInfo.companyInfoVO.brandName || '云享飞管理后台'}</div>
<div onClick={setMenuCollapsed}> <div onClick={setMenuCollapsed}>
<svg <svg
className={`hamburger ${isActive ? 'is-active' : ''}`} className={`hamburger ${isActive ? 'is-active' : ''}`}
......
import { Form, Input, message, Modal, ModalProps } from 'antd';
import { FC, useEffect, useState } from 'react';
import { Uploader } from '~/components/uploader';
import { UploadOutlined } from '@ant-design/icons';
import { InterDataType, InterReqType } from '~/api/interface';
import { addPrimaryCategoryType, categoryListRespType } from '~/api/interface/categoryManage';
import { CategoryManageAPI } from '~/api';
//分类列表返回类型
type categoryType = InterDataType<categoryListRespType>['list'];
//新增分类请求参数类型
type addPrimaryCategoryParameter = InterReqType<addPrimaryCategoryType>;
interface selfProps {
onCancel: () => void;
onOK: () => void;
currentCategory: categoryType[0] | undefined;
}
const AddOrEditCategoryModal: FC<ModalProps & selfProps> = ({
open,
onCancel,
onOK,
currentCategory,
}) => {
const [form] = Form.useForm<addPrimaryCategoryParameter>();
const [fileList, setFileList] = useState<
{
id: number;
name: string;
uid: number;
url: string;
}[]
>([]);
//上传成功
const uploadSuccess = (
value: {
id: number;
name: string;
uid: number;
url: string;
}[],
) => {
form.setFieldValue('icon', value[0].url);
setFileList([...value]);
};
//提交
const handleOk = () => {
form.validateFields().then((values: any) => {
CategoryManageAPI[currentCategory ? 'updatePrimaryCategory' : 'addPrimaryCategory']({
...values,
id: currentCategory ? currentCategory.id : undefined,
}).then(({ code }) => {
if (code === '200') {
message.success('新增成功');
form.resetFields();
setFileList([]);
onOK();
}
});
});
};
const handleCancel = () => {
form.resetFields();
setFileList([]);
onCancel();
};
useEffect(() => {
if (currentCategory) {
form.setFieldsValue({
name: currentCategory.name,
icon: currentCategory.icon,
description: currentCategory.description || undefined,
});
setFileList([
{
name: 'categoryImg',
id: Math.random(),
uid: Math.random(),
url: currentCategory.icon,
},
]);
}
}, [currentCategory]);
return (
<Modal
open={open}
title={currentCategory ? '编辑分类' : '新增分类'}
onCancel={handleCancel}
onOk={handleOk}
>
<Form wrapperCol={{ span: 16 }} labelCol={{ span: 4 }} form={form}>
<Form.Item
label='分类名称'
name='name'
rules={[{ required: true, message: '请输入分类名称' }]}
>
<Input placeholder='请输入分类名称' maxLength={15} />
</Form.Item>
<Form.Item
label='分类图标'
name='icon'
rules={[{ required: true, message: '请上传分类图标' }]}
>
<Uploader
fileUpload
listType='picture-card'
onChange={uploadSuccess}
fileLength={1}
fileSize={5}
defaultFileList={fileList}
>
<UploadOutlined />
</Uploader>
</Form.Item>
<Form.Item label='分类描述' name='description'>
<Input.TextArea placeholder='请输入分类描述' rows={4} maxLength={70} showCount />
</Form.Item>
</Form>
</Modal>
);
};
export default AddOrEditCategoryModal;
.category-list{
&-row-bg{
td{
background-color: rgba($color: #000000, $alpha: 0.1) !important;
}
}
}
...@@ -17,8 +17,16 @@ body { ...@@ -17,8 +17,16 @@ body {
box-shadow: 0px 20px 30px rgba(112, 158, 254, 0.45); box-shadow: 0px 20px 30px rgba(112, 158, 254, 0.45);
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
position: relative;
.login-flex { .login-flex {
flex: 1; flex: 1;
position: relative;
.qr-code-wrap{
position: absolute;
top:50%;
left: 50%;
transform: translate(-50%, -50%);
}
} }
.login-content { .login-content {
text-align: center; text-align: center;
...@@ -37,6 +45,7 @@ body { ...@@ -37,6 +45,7 @@ body {
color: rgba(0, 0, 0, 0.5); color: rgba(0, 0, 0, 0.5);
} }
} }
.login-form { .login-form {
.login-image { .login-image {
margin: 62px auto 46px; margin: 62px auto 46px;
...@@ -79,5 +88,16 @@ body { ...@@ -79,5 +88,16 @@ body {
box-shadow: 3px 3px 30px #dddddd; box-shadow: 3px 3px 30px #dddddd;
} }
} }
.qrCode-icon{
position: absolute;
top: 0;
right: 0;
}
.account-login-operate{
position: absolute;
top: 10px;
right: 10px;
}
} }
} }
import { Button, Checkbox, Form, Input, message } from 'antd'; import { Button, Checkbox, Form, Image, Input, message, QRCode } from 'antd';
import { useEffect } from 'react'; import { useEffect, useState } from 'react';
import { LockOutlined, UserOutlined } from '@ant-design/icons'; import { LockOutlined, UserOutlined } from '@ant-design/icons';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import Cookies from 'js-cookie'; import Cookies from 'js-cookie';
...@@ -10,18 +10,27 @@ import { CommonAPI } from '~/api'; ...@@ -10,18 +10,27 @@ import { CommonAPI } from '~/api';
import { useDispatch } from 'react-redux'; import { useDispatch } from 'react-redux';
import { SET_USERINFO } from '~/store/module/userInfo'; import { SET_USERINFO } from '~/store/module/userInfo';
import { authRouterList } from '~/router'; import { authRouterList } from '~/router';
import qrCodeIcon from '~/assets/image/qr-code-icon.svg';
// 请求的类型 // 请求的类型
type ReqType = InterReqType<BackEndLoginType>; type ReqType = InterReqType<BackEndLoginType>;
//定时器暂存
let time: NodeJS.Timer;
function LoginView() { function LoginView() {
// eslint-disable-next-line @typescript-eslint/no-unused-vars,@typescript-eslint/ban-ts-comment
// @ts-ignore
const navigate = useNavigate(); const navigate = useNavigate();
// redux // redux
const dispatch = useDispatch(); const dispatch = useDispatch();
// 表单钩子 // 表单钩子
const [form] = Form.useForm<ReqType>(); const [form] = Form.useForm<ReqType>();
//是否二维码登录
const [isLoginCode, setIsLoginCode] = useState<boolean>(false);
//获取小程序二维码唯一标识
const [randomLoginCode] = useState<string>(parseInt(String(Math.random() * 10001), 10) + '');
//小程序二维码地址
const [qrCodeUrl, setQrCodeUrl] = useState<string>('');
// 提交数据 // 提交数据
const onFinish = async (values: ReqType) => { const onFinish = async (values: ReqType) => {
const res = await CommonAPI.BackEndLogin({ const res = await CommonAPI.BackEndLogin({
...@@ -29,6 +38,7 @@ function LoginView() { ...@@ -29,6 +38,7 @@ function LoginView() {
passWord: values?.passWord, passWord: values?.passWord,
}); });
if (res && res.code === '200') { if (res && res.code === '200') {
message.success('登录成功');
const { token } = res.result; const { token } = res.result;
await Cookies.set('SHAREFLY-TOKEN', token); await Cookies.set('SHAREFLY-TOKEN', token);
// 记住密码 // 记住密码
...@@ -49,7 +59,50 @@ function LoginView() { ...@@ -49,7 +59,50 @@ function LoginView() {
message.error('登录失败,请检查账号信息'); message.error('登录失败,请检查账号信息');
} }
}; };
//显示二维码登录方式
const changeLoginUseEvent = () => {
//第一次二维码
if (!isLoginCode && !qrCodeUrl) {
CommonAPI.getAppletQRCode({
page: 'page-identity/identity-empower/index',
scene: `randomLoginCode=${randomLoginCode}&port=1`,
}).then(({ result }) => {
setQrCodeUrl(result ? `data:image/png;base64,${result}` : '');
time = setInterval(() => {
getLoginInfo();
}, 1000);
});
} else if (!isLoginCode && qrCodeUrl) {
time = setInterval(() => {
getLoginInfo();
}, 1000);
} else {
if (time) {
clearInterval(time);
}
}
setIsLoginCode(!isLoginCode);
};
//二维码登录
const getLoginInfo = () => {
CommonAPI.getLoginInfo({ randomLoginCode }).then(async ({ result, code }) => {
if (code === '200') {
clearInterval(time);
message.success('登录成功');
const { token } = result;
await Cookies.set('SHAREFLY-TOKEN', token);
dispatch(SET_USERINFO(result));
localStorage.setItem('roleId', result.roleInfo.id.toString());
authRouterList().then((value: any) => {
if (value.length) {
navigate({ pathname: value[0].children.find((v: any) => !v.meta.hidden)?.path });
} else {
message.warning('请先配置权限');
}
});
}
});
};
// componentDidMount // componentDidMount
useEffect(() => { useEffect(() => {
// 是否保存密码 // 是否保存密码
...@@ -62,65 +115,96 @@ function LoginView() { ...@@ -62,65 +115,96 @@ function LoginView() {
remember: Boolean(Cookies.get('remember')), remember: Boolean(Cookies.get('remember')),
}); });
}, []); }, []);
return ( return (
<div className='login-warp'> <div className='login-warp'>
<div className='login-view'> <div className='login-view'>
<div className='login-flex login-content'> <div className='login-flex login-content'>
<div className='login-title'>欢迎来到</div> <div className='login-title'></div>
<div className='login-text'>科比特 · 云享飞管理平台</div> <div className='login-text'>云享飞管理平台</div>
<div className='login-detail'>让天空为世界所用</div> <div className='login-detail'>让天空为世界所用</div>
</div> </div>
<div className='login-flex login-form'> <div className='login-flex login-form'>
<div className='login-image' /> {isLoginCode ? (
<div className='login-input'> <div className='qr-code-wrap'>
<Form {qrCodeUrl ? (
name='basic' <Image src={qrCodeUrl} alt='' width={200} height={200} preview={false} />
form={form} ) : (
wrapperCol={{ span: 16, offset: 4 }} <QRCode value='https://ant.design/' status='loading' />
initialValues={{ remember: true }} )}
onFinish={onFinish} </div>
autoComplete='off' ) : (
> <>
<Form.Item name='accountNo' rules={[{ required: true, message: '请输入用户名' }]}> <div className='login-image' />
<Input size='large' prefix={<UserOutlined />} placeholder='请输入账号' allowClear /> <div className='login-input'>
</Form.Item> <Form
name='basic'
form={form}
wrapperCol={{ span: 16, offset: 4 }}
initialValues={{ remember: true }}
onFinish={onFinish}
autoComplete='off'
>
<Form.Item name='accountNo' rules={[{ required: true, message: '请输入用户名' }]}>
<Input
size='large'
prefix={<UserOutlined />}
placeholder='请输入账号'
allowClear
/>
</Form.Item>
<Form.Item <Form.Item
name='passWord' name='passWord'
className='login-password' className='login-password'
rules={[{ required: true, message: '请输入密码' }]} rules={[{ required: true, message: '请输入密码' }]}
> >
<Input.Password <Input.Password
size='large' size='large'
prefix={<LockOutlined />} prefix={<LockOutlined />}
placeholder='请输入密码' placeholder='请输入密码'
allowClear allowClear
/> />
</Form.Item> </Form.Item>
<Form.Item <Form.Item
name='remember' name='remember'
className='login-remember' className='login-remember'
valuePropName='checked' valuePropName='checked'
wrapperCol={{ offset: 4, span: 8 }} wrapperCol={{ offset: 4, span: 8 }}
> >
<Checkbox>记住密码</Checkbox> <Checkbox>记住密码</Checkbox>
</Form.Item> </Form.Item>
<Form.Item wrapperCol={{ offset: 7, span: 15 }}> <Form.Item wrapperCol={{ offset: 7, span: 15 }}>
<Button <Button
type='primary' type='primary'
htmlType='submit' htmlType='submit'
shape='round' shape='round'
size='large' size='large'
className='login-submit' className='login-submit'
> >
登录 登录
</Button> </Button>
</Form.Item> </Form.Item>
</Form> </Form>
</div> </div>
</>
)}
</div> </div>
{isLoginCode ? (
<div className='account-login-operate'>
<Button type='link' onClick={changeLoginUseEvent}>
使用账号登录
</Button>
</div>
) : (
<div className='qrCode-icon'>
<img src={qrCodeIcon} alt='icon' onClick={changeLoginUseEvent} />
</div>
)}
</div> </div>
</div> </div>
); );
......
...@@ -239,7 +239,7 @@ function CustomListView() { ...@@ -239,7 +239,7 @@ function CustomListView() {
label: '手机号', label: '手机号',
name: 'phoneNum', name: 'phoneNum',
type: 'input', type: 'input',
placeholder: '请输入用户账号', placeholder: '请输入手机号',
}, },
{ {
label: '来源', label: '来源',
......
.goods-video-wrap{
position: relative;
width: 200px;
img{
position: absolute;
right: 0;
top: 0;
transform: translate(50%,-25%);
}
}
import { Button, Cascader, Form, Input, Radio, Select } from 'antd';
import { Uploader } from '~/components/uploader';
import type { RadioChangeEvent } from 'antd';
import { UploadOutlined } from '@ant-design/icons';
import React, { forwardRef, useEffect, useImperativeHandle, useState } from 'react';
import { InterDataType } from '~/api/interface';
import { categoryListRespType } from '~/api/interface/categoryManage';
import { CategoryManageAPI } from '~/api';
import deletePng from '~/assets/image/delete.png';
import './index.scss';
//分类返回类型
type categoryType = InterDataType<categoryListRespType>['list'];
interface selfProps {
ref: any;
}
//基本信息表单类型
export type baseInfoType = {
tradeName: string;
description: string;
mainImgList: {
id: number;
name: string;
uid: number;
url: string;
}[];
subImgList: {
id: number;
name: string;
uid: number;
url: string;
}[];
videoList: {
id: number;
name: string;
uid: number;
url: string;
}[];
categoryId: number[];
shelfStatus: number;
labelShow: number;
goodsLabel: string;
};
const BaseInfo = forwardRef<any, selfProps>((_props, ref) => {
const [baseInfoForm] = Form.useForm<baseInfoType>();
const [labelShow, setLabelShow] = useState<boolean>(false);
//分类列表
const [categoryList, setCategoryList] = useState<categoryType>([]);
//主图
const [mainFileList, setMainFileList] = useState<
{
id: number;
name: string;
uid: number;
url: string;
}[]
>([]);
//副图
const [subFileList, setSubFileList] = useState<
{
id: number;
name: string;
uid: number;
url: string;
}[]
>([]);
//视频
const [videoFileList, setVideoFileList] = useState<
{
id: number;
name: string;
uid: number;
url: string;
}[]
>([]);
useImperativeHandle(ref, () => ({
getForm: () => baseInfoForm,
setLabelShow: (value: boolean) => setLabelShow(value),
mediaData: {
setMainFileList,
setSubFileList,
setVideoFileList,
},
}));
//标签选中监听
const labelRadioChange = (e: RadioChangeEvent) => {
setLabelShow(!!e.target.value);
};
//上传结果
const uploadSuccess = (
fileList: {
id: number;
name: string;
uid: number;
url: string;
}[],
type: string,
) => {
switch (type) {
case 'mainImgList':
setMainFileList(fileList);
baseInfoForm.setFieldValue('mainImgList', fileList);
break;
case 'subImgList':
setSubFileList(fileList);
baseInfoForm.setFieldValue('subImgList', fileList);
break;
case 'videoList':
setVideoFileList(fileList);
baseInfoForm.setFieldValue('videoList', fileList);
break;
default:
break;
}
};
//分类列表
const getCategoryList = () => {
CategoryManageAPI.getCategoryRespList({ pageNo: 1, pageSize: 99999 }).then(({ result }) => {
setCategoryList(result.list || []);
});
};
//视频删除
const deleteVideo = () => {
setVideoFileList([]);
baseInfoForm.setFieldValue('videoList', undefined);
};
useEffect(() => {
getCategoryList();
}, []);
return (
<div className='base-info'>
<Form
labelCol={{ span: 2 }}
wrapperCol={{ span: 8 }}
form={baseInfoForm}
initialValues={{ labelShow: 0, shelfStatus: 1 }}
>
<Form.Item
label='商品名称'
name='tradeName'
rules={[{ required: true, message: '请输入商品名称' }]}
>
<Input placeholder='请输入商品名称' maxLength={50} />
</Form.Item>
<Form.Item
label='商品描述'
name='description'
rules={[{ required: true, message: '请输入商品描述' }]}
>
<Input.TextArea rows={4} placeholder='请输入商品描述' maxLength={70} showCount />
</Form.Item>
<Form.Item
label='商品主图'
name='mainImgList'
rules={[{ required: true, message: '请上传商品主图' }]}
>
<Uploader
fileUpload
listType='picture-card'
onChange={(fileList) => uploadSuccess(fileList, 'mainImgList')}
defaultFileList={mainFileList}
>
<UploadOutlined />
</Uploader>
</Form.Item>
<Form.Item label='商品副图' name='subImgList'>
<Uploader
fileUpload
listType='picture-card'
onChange={(fileList) => uploadSuccess(fileList, 'subImgList')}
defaultFileList={subFileList}
fileLength={4}
>
<UploadOutlined />
</Uploader>
</Form.Item>
<Form.Item label='商品视频' name='videoList'>
{videoFileList.length ? (
<div className='goods-video-wrap'>
<video
src={videoFileList[0].url}
style={{ width: '200px', height: '200px' }}
controls
/>
<img src={deletePng} alt='删除' onClick={deleteVideo} />
</div>
) : (
<Uploader
fileUpload
listType='text'
onChange={(fileList) => uploadSuccess(fileList, 'videoList')}
defaultFileList={videoFileList}
fileType={['video/mp4', 'video/avi', 'video/wmv', 'video/rmvb']}
fileSize={50}
>
<Button icon={<UploadOutlined />}>上传视频</Button>
</Uploader>
)}
</Form.Item>
<Form.Item
label='商品分类'
name='categoryId'
rules={[{ required: true, message: '请选择商品分类' }]}
>
<Cascader
placeholder='请选择商品分类'
options={categoryList}
fieldNames={{ label: 'name', value: 'id', children: 'subDTOList' }}
/>
</Form.Item>
<Form.Item
label='商品状态'
name='shelfStatus'
rules={[{ required: true, message: '请选择商品状态' }]}
>
<Select placeholder='请选择商品状态'>
<Select.Option value={1}>上架</Select.Option>
<Select.Option value={0}>下架</Select.Option>
</Select>
</Form.Item>
<Form.Item label='显示标签' name='labelShow'>
<Radio.Group onChange={labelRadioChange}>
<Radio value={1}>显示</Radio>
<Radio value={0}>不显示</Radio>
</Radio.Group>
</Form.Item>
{labelShow ? (
<Form.Item
label='商品标签'
name='goodsLabel'
rules={[{ required: true, message: '请输入商品标签' }]}
>
<Input placeholder='请输入商品标签' maxLength={10} />
</Form.Item>
) : (
''
)}
</Form>
</div>
);
});
export default BaseInfo;
import RichText from '~/components/richText';
import { FC } from 'react';
interface selfProps {
onChange: (html: string) => void;
introduceInfo: string;
}
const IntroduceInfo: FC<selfProps> = ({ onChange, introduceInfo }) => {
//富文本修改
const richTextOnChange = (html?: string) => {
onChange(html || '');
};
return (
<div className='introduce-info'>
<RichText richTextContent={introduceInfo} height={400} onChange={richTextOnChange} />
</div>
);
};
export default IntroduceInfo;
import { Button, Popconfirm, Table, Tag } from 'antd';
import { PlusOutlined } from '@ant-design/icons';
import { ColumnsType } from 'antd/es/table';
import { FC, useState } from 'react';
import { InterDataType, InterReqType, PaginationProps } from '~/api/interface';
import { addMallGoodsType, skuUnitType } from '~/api/interface/goodsType';
//商品sku规格类型
type goodsSpecType = Exclude<InterReqType<addMallGoodsType>, undefined>['goodsSpecList'][0];
//单位返回类型
type unitType = InterDataType<skuUnitType>;
interface selfProps {
addOrEditSkuClick: () => void;
skuTableData: goodsSpecType[];
skuUnitList: unitType;
deleteSkuClick: (record: goodsSpecType) => void;
editSkuClick: (record: goodsSpecType) => void;
}
const SkuInfo: FC<selfProps> = ({
addOrEditSkuClick,
skuTableData,
skuUnitList,
deleteSkuClick,
editSkuClick,
}) => {
const tableColumns: ColumnsType<goodsSpecType> = [
{
title: '序号',
align: 'center',
render: (_text: string, _record, index: number) => index + 1,
},
{
title: '规格名称',
align: 'center',
dataIndex: 'specName',
},
{
title: '选择方式',
align: 'center',
dataIndex: 'chooseType',
render: (text: number) => (text ? '多选' : '单选'),
},
{
title: '是否必选',
align: 'center',
dataIndex: 'must',
render: (text: number) => (text ? '必选' : '非必选'),
},
{
title: '规格单位',
align: 'center',
dataIndex: 'skuUnitId',
render: (text: number) => skuUnitList.find((v) => v.id === text)?.unitName || '',
},
{
title: '规格值',
align: 'center',
dataIndex: 'goodsSpecValuesList',
render: (text: goodsSpecType['goodsSpecValuesList']) =>
text.map((v) => (
<Tag key={v.id}>
{v.specValueName}
{v.partNo ? `(${v.partNo})` : ''}
</Tag>
)),
},
{
title: '操作',
align: 'center',
render: (_text: string, record) => (
<>
<Button type='link' onClick={() => editSkuClick(record)}>
编辑
</Button>
<Popconfirm
placement='topLeft'
title={'删除规格'}
description={'确认删除该规格吗?'}
onConfirm={() => deleteSkuClick(record)}
okText='确定'
cancelText='取消'
>
<Button type='link' danger>
删除
</Button>
</Popconfirm>
</>
),
},
];
const [pagination, setPagination] = useState<PaginationProps>({
pageNo: 1,
pageSize: 10,
});
//分页
const paginationChange = (pageNo: number, pageSize: number) => {
pagination.pageNo = pageNo;
pagination.pageSize = pageSize;
setPagination({ ...pagination });
};
return (
<div className='sku-info'>
<div className='sku-info-operate' style={{ margin: ' 20px 0 ' }}>
<Button
type='primary'
icon={<PlusOutlined></PlusOutlined>}
onClick={() => addOrEditSkuClick()}
>
添加规格
</Button>
</div>
<Table
bordered
columns={tableColumns}
dataSource={skuTableData.slice(
(pagination.pageNo - 1) * pagination.pageSize,
pagination.pageNo * pagination.pageSize,
)}
rowKey='id'
pagination={{
total: skuTableData.length,
pageSize: pagination.pageSize,
current: pagination.pageNo,
showSizeChanger: true,
showQuickJumper: true,
onChange: (page: number, pageSize: number) => paginationChange(page, pageSize),
showTotal: (total, range) => `当前 ${range[0]}-${range[1]} 条记录 / 共 ${total} 条数据`,
}}
/>
</div>
);
};
export default SkuInfo;
.goods-info { .goods-operate-wrap{
&-operate { position: relative;
margin-top: 50px; .next-step{
display: flex; margin: 20px 0 0 0px;
justify-content: center; text-align: center;
button { button{
width: 100px; &:first-child{
height: 40px; margin-right: 20px;
&:first-child {
margin-right: 50px;
} }
width: 100px;
} }
} }
.back-btn{
position: absolute;
right: 0;
top: 0;
}
} }
.goods-detail{
position: relative;
&-info{
margin-bottom: 20px;
}
&-sku{
.sku-title{
line-height: 50px;
font-weight: bold;
font-size: 14px;
}
}
&-introduce{
.introduce-title{
line-height: 50px;
font-weight: bold;
font-size: 14px;
}
}
&-operate{
position: absolute;
right: 0;
top: 0;
}
}
import { useSearchParams, useNavigate } from 'react-router-dom';
import { useEffect, useState } from 'react';
import GoodsAPI from '~/api/modules/goodsAPI';
import { InterDataType } from '~/api/interface';
import { mallGoodsDetailsType, skuUnitType } from '~/api/interface/goodsType';
import { Badge, Button, Descriptions, Image, Table, Tag } from 'antd';
import { CategoryManageAPI } from '~/api';
import { categoryListRespType } from '~/api/interface/categoryManage';
import './index.scss';
import { ColumnsType } from 'antd/es/table';
//详情返回类型
type detailType = InterDataType<mallGoodsDetailsType>;
//分类返回类型
type categoryType = InterDataType<categoryListRespType>['list'];
//单位返回类型
type unitType = InterDataType<skuUnitType>;
const GoodsDetails = () => {
const [searchParams] = useSearchParams();
const navigate = useNavigate();
//分类列表
const [categoryList, setCategoryList] = useState<categoryType>([]);
//单位列表
const [skuUnitList, setSkuUnitList] = useState<unitType>([]);
const [goodsInfoDetails, setGoodsInfoDetails] = useState<detailType>();
const tableColumns: ColumnsType<detailType['goodsSpecList'][0]> = [
{
title: '序号',
align: 'center',
render: (_text: string, _record, index: number) => index + 1,
},
{
title: '规格名称',
align: 'center',
dataIndex: 'specName',
},
{
title: '选择方式',
align: 'center',
dataIndex: 'chooseType',
render: (text: number) => (text ? '多选' : '单选'),
},
{
title: '是否必选',
align: 'center',
dataIndex: 'must',
render: (text: number) => (text ? '必选' : '非必选'),
},
{
title: '规格单位',
align: 'center',
dataIndex: 'skuUnitId',
render: (text: number) => skuUnitList.find((v) => v.id === text)?.unitName || '',
},
{
title: '规格值',
align: 'center',
dataIndex: 'goodsSpecValuesList',
render: (text: detailType['goodsSpecList'][0]['goodsSpecValuesList']) =>
text.map((v) => (
<Tag key={v.id}>
{v.specValueName}
{v.partNo ? `(${v.partNo})` : ''}
</Tag>
)),
},
];
const getGoodsDetails = (id: number) => {
GoodsAPI.getMallGoodsDetails({ id }).then(({ result }) => {
setGoodsInfoDetails(result);
});
};
//分类列表
const getCategoryList = () => {
CategoryManageAPI.getCategoryRespList({ pageNo: 1, pageSize: 99999 }).then(({ result }) => {
setCategoryList(result.list || []);
});
};
//单位列表
const getSkuUnit = () => {
GoodsAPI.getSkuUnit().then(({ result }) => {
setSkuUnitList(result || []);
});
};
//返回
const backRoute = () => {
navigate(-1);
};
useEffect(() => {
getGoodsDetails(Number(searchParams.get('id')));
getCategoryList();
getSkuUnit();
}, []);
return (
<div className='goods-detail'>
<div className='goods-detail-info'>
<Descriptions title='基本信息' bordered>
<Descriptions.Item label='商品名称'>{goodsInfoDetails?.tradeName}</Descriptions.Item>
<Descriptions.Item label='商品副图'>
{goodsInfoDetails?.resourcesList
.filter((v) => v.type === 1)
.map((v) => (
<Image src={v.url} width={50} height={50} key={v.id} />
))}
</Descriptions.Item>
<Descriptions.Item label='商品主图'>
{goodsInfoDetails?.resourcesList
.filter((v) => v.type === 0)
.map((v) => (
<Image src={v.url} width={50} height={50} key={v.id} />
))}
</Descriptions.Item>
<Descriptions.Item label='商品标签'>
{goodsInfoDetails?.goodsLabel || '暂无'}
</Descriptions.Item>
<Descriptions.Item label='商品分类'>
{categoryList
.reduce((pre: string[], cur) => {
if (cur.id === goodsInfoDetails?.categoryPrimaryId) {
pre.push(cur.name);
if (goodsInfoDetails?.categorySubId) {
pre.push(
cur.subDTOList.find((v) => v.id === goodsInfoDetails?.categorySubId)?.name ||
'',
);
}
}
return pre;
}, [])
.join('/')}
</Descriptions.Item>
<Descriptions.Item label='商品状态'>
<Badge
status={goodsInfoDetails?.shelfStatus ? 'processing' : 'default'}
text={goodsInfoDetails?.shelfStatus ? '上架中' : '已下架'}
/>
</Descriptions.Item>
<Descriptions.Item label='商品视频' span={1}>
{goodsInfoDetails?.resourcesList
.filter((v) => v.type === 2)
.map((v) => (
<video
src={v.url}
key={v.id}
style={{ width: '200px', height: '200px' }}
controls
/>
))}
</Descriptions.Item>
<Descriptions.Item label='商品描述'>{goodsInfoDetails?.description}</Descriptions.Item>
</Descriptions>
</div>
<div className='goods-detail-sku'>
<div className='sku-title'>商品规格</div>
<Table
bordered
columns={tableColumns}
dataSource={goodsInfoDetails?.goodsSpecList}
rowKey='id'
pagination={false}
></Table>
</div>
<div className='goods-detail-introduce'>
<div className='introduce-title'>商品详情</div>
<div
className='introduce-content'
dangerouslySetInnerHTML={{ __html: goodsInfoDetails?.goodsDetails || '' }}
></div>
</div>
<div className='goods-detail-operate'>
<Button type='primary' onClick={backRoute}>
返回
</Button>
</div>
</div>
);
};
export default GoodsDetails;
import { FC, useState } from 'react';
import { Form, message, Modal, ModalProps, Select } from 'antd';
import { CommonAPI, SystemManageAPI } from '~/api';
interface selfProps {
onOk: () => void;
companyInfoId: number;
}
const AddPeopleModal: FC<ModalProps & selfProps> = ({ open, onCancel, onOk, companyInfoId }) => {
const [form] = Form.useForm<{ userAccountId: number }>();
const [options, setOptions] = useState<{ label: string; value: number; key: string }[]>([]);
const handleOk = () => {
form.validateFields().then((values) => {
SystemManageAPI.bindingCompanyMember({ ...values, companyInfoId }).then(({ code }) => {
if (code === '200') {
message.success('绑定成功');
onOk();
form.resetFields();
}
});
});
};
//select 搜索
const selectSearchEvent = (value: string) => {
CommonAPI.getUserAccountByPhoneNum({ phoneNum: value }).then(({ result }) => {
const list = (result || []).map((v) => ({
label: v.phoneNum + `(${v.uid})`,
value: v.id,
key: value,
}));
setOptions(list);
});
};
return (
<Modal open={open} title='添加成员' onOk={handleOk} onCancel={onCancel}>
<Form form={form}>
<Form.Item
label='成员'
name='userAccountId'
rules={[{ required: true, message: '请选择成员' }]}
>
<Select
placeholder='请输入成员手机号码'
showSearch
onSearch={selectSearchEvent}
filterOption={(input, option) =>
(option?.key ?? '').toLowerCase().includes(input.toLowerCase())
}
options={options}
></Select>
</Form.Item>
</Form>
</Modal>
);
};
export default AddPeopleModal;
import { Form, message, Modal, ModalProps, Select } from 'antd';
import { FC, useEffect, useState } from 'react';
import { SystemManageAPI } from '~/api';
import { InterDataType } from '~/api/interface';
import { listCompanyMembersType } from '~/api/interface/systemManageType';
//单位-成员列表返回类型
type companyMembersType = InterDataType<listCompanyMembersType>['list'];
interface selfProps {
onOk: () => void;
companyInfoId: number;
currentCompanyMembers: companyMembersType[0] | undefined;
}
const TransferLeaderModal: FC<ModalProps & selfProps> = ({
open,
onOk,
onCancel,
companyInfoId,
currentCompanyMembers,
}) => {
const [form] = Form.useForm<{ toUserAccountId: number }>();
const [listCompanyMembers, setListCompanyMembers] = useState<companyMembersType>([]);
const handleOk = () => {
form.validateFields().then((values) => {
if (currentCompanyMembers) {
SystemManageAPI.transferLeader({
companyInfoId,
fromUserAccountId: currentCompanyMembers.id,
...values,
}).then(({ code }) => {
if (code === '200') {
message.success('转让成功');
onOk();
}
});
}
});
};
//单位成员列表
const getListCompanyMembers = () => {
SystemManageAPI.getListCompanyMembers({
companyInfoId,
pageNo: 1,
pageSize: 999999,
}).then(({ result }) => {
setListCompanyMembers((result.list || []).filter((v) => !v.leader));
});
};
useEffect(() => {
if (currentCompanyMembers) {
getListCompanyMembers();
}
}, [currentCompanyMembers]);
return (
<Modal open={open} title='转让管理员' onCancel={onCancel} onOk={handleOk}>
<Form form={form}>
<Form.Item label='转让人' name='toUserAccountId'>
<Select
placeholder='请选择受让人'
filterOption={(input, option) =>
(option!.children as unknown as string).toLowerCase().includes(input.toLowerCase())
}
>
{listCompanyMembers.map((v) => (
<Select.Option key={v.id} value={v.id}>
{v.phoneNum}({v.uid})
</Select.Option>
))}
</Select>
</Form.Item>
</Form>
</Modal>
);
};
export default TransferLeaderModal;
.company-detail{
position: relative;
&-info{
margin-bottom: 20px;
}
&-people{
&-title{
line-height: 50px;
font-weight: bold;
font-size: 14px;
}
&-operate{
margin-bottom: 10px;
}
}
&-operate{
position: absolute;
right: 0;
top: 0;
}
}
import { useSearchParams, useNavigate } from 'react-router-dom';
import { useEffect, useState } from 'react';
import { SystemManageAPI } from '~/api';
import { InterDataType, PaginationProps } from '~/api/interface';
import { getCompanyInfoByIdType, listCompanyMembersType } from '~/api/interface/systemManageType';
import { Button, Descriptions, message, Modal, Table } from 'antd';
import './index.scss';
import { ColumnsType } from 'antd/es/table';
import { PlusOutlined } from '@ant-design/icons';
import AddPeopleModal from './components/addPeopleModal';
import { useSelector } from 'react-redux';
import TransferLeaderModal from '~/pages/systemManage/companyManage/companyDetail/components/transferLeaderModal';
//单位详情-返回类型
type companyDetailType = InterDataType<getCompanyInfoByIdType>;
//单位-成员列表返回类型
type companyMembersType = InterDataType<listCompanyMembersType>['list'];
const CompanyDetail = () => {
const [searchParams] = useSearchParams();
const navigate = useNavigate();
const { userInfo } = useSelector((state: any) => state.UserInfo);
const tableColumns: ColumnsType<companyMembersType[0]> = [
{
title: 'uid',
align: 'center',
dataIndex: 'uid',
},
{
title: '姓名',
align: 'center',
dataIndex: 'userName',
},
{
title: '角色',
align: 'center',
dataIndex: 'leader',
render: (text: number) => (text ? '单位管理员' : '普通员工'),
},
{
title: '手机号',
align: 'center',
dataIndex: 'phoneNum',
},
{
title: '操作',
width: '15%',
onHeaderCell: () => ({
style: {
textAlign: 'center',
},
}),
render: (_text: string, record) => (
<>
<Button
type='link'
disabled={!userInfo.companyInfoVO.leader || !record.leader}
onClick={() => transferLeaderClick(record)}
>
转让
</Button>
<Button
type='link'
disabled={!userInfo.companyInfoVO.leader || !!record.leader}
onClick={() => unbindCompanyClick(record)}
>
解绑
</Button>
</>
),
},
];
const [companyId, setCompanyId] = useState<number>(-1);
const [companyDetail, setCompanyDetail] = useState<companyDetailType>();
const [pagination, setPagination] = useState<PaginationProps & { totalCount: number }>({
pageNo: 1,
pageSize: 10,
totalCount: 0,
});
const [listCompanyMembers, setListCompanyMembers] = useState<companyMembersType>([]);
const [currentCompanyMembers, setCurrentCompanyMembers] = useState<companyMembersType[0]>();
const [addPeopleModalShow, setAddPeopleModalShow] = useState<boolean>(false);
const [transferLeaderModalShow, setTransferLeaderModalShow] = useState<boolean>(false);
//单位详情
const getCompanyDetailInfo = (id: number) => {
SystemManageAPI.getCompanyInfoById({ id }).then(({ result }) => {
setCompanyDetail(result);
});
};
//单位成员列表
const getListCompanyMembers = (companyInfoId: number) => {
SystemManageAPI.getListCompanyMembers({
companyInfoId,
pageNo: pagination.pageNo,
pageSize: pagination.pageSize,
}).then(({ result }) => {
pagination.totalCount = result.totalCount;
setPagination(pagination);
setListCompanyMembers(result.list || []);
});
};
//分页
const paginationChange = (pageNo: number, pageSize: number) => {
pagination.pageNo = pageNo;
pagination.pageSize = pageSize;
getListCompanyMembers(companyId);
};
//添加成员弹窗
const addPeopleClick = () => {
setAddPeopleModalShow(true);
};
const addPeopleModalOk = () => {
getListCompanyMembers(companyId);
setAddPeopleModalShow(false);
};
const addPeopleModalCancel = () => {
setAddPeopleModalShow(false);
};
//转让管理员弹窗
const transferLeaderClick = (record: companyMembersType[0]) => {
setCurrentCompanyMembers(record);
setTransferLeaderModalShow(true);
};
const transferLeaderModalCancel = () => {
setTransferLeaderModalShow(false);
};
const transferLeaderModalOk = () => {
setTransferLeaderModalShow(false);
getListCompanyMembers(companyId);
};
//接触绑定
const unbindCompanyClick = (record: companyMembersType[0]) => {
Modal.confirm({
title: '提示',
content: '确认解除绑定该成员?',
onOk: () => {
SystemManageAPI.unbindCompanyMember({
userAccountId: record.id,
companyInfoId: companyId,
}).then(({ code }) => {
if (code === '200') {
message.success('解除成功');
if (pagination.pageNo !== 1 && listCompanyMembers?.length === 1) {
pagination.pageNo -= 1;
}
getListCompanyMembers(companyId);
}
});
},
});
};
//返回
const backRoute = () => {
navigate(-1);
};
useEffect(() => {
setCompanyId(Number(searchParams.get('id')));
getCompanyDetailInfo(Number(searchParams.get('id')));
getListCompanyMembers(Number(searchParams.get('id')));
}, []);
return (
<div className='company-detail'>
<div className='company-detail-info'>
<Descriptions title='基本信息' bordered column={4}>
<Descriptions.Item label='单位名称'>{companyDetail?.companyName}</Descriptions.Item>
<Descriptions.Item label='详细地址'>{companyDetail?.address}</Descriptions.Item>
<Descriptions.Item label='联系人'>
{companyDetail?.companyUserName || ''}
</Descriptions.Item>
<Descriptions.Item label='联系电话'>{companyDetail?.phoneNum || ''}</Descriptions.Item>
</Descriptions>
</div>
<div className='company-detail-people'>
<div className='company-detail-people-title'>成员信息</div>
<div className='company-detail-people-operate'>
<Button
type='primary'
icon={<PlusOutlined></PlusOutlined>}
onClick={addPeopleClick}
disabled={!userInfo.companyInfoVO.leader}
>
添加成员
</Button>
</div>
<Table
bordered
columns={tableColumns}
dataSource={listCompanyMembers}
pagination={{
total: pagination.totalCount,
pageSize: pagination.pageSize,
current: pagination.pageNo,
showSizeChanger: true,
showQuickJumper: true,
onChange: (page: number, pageSize: number) => paginationChange(page, pageSize),
showTotal: (total, range) => `当前 ${range[0]}-${range[1]} 条记录 / 共 ${total} 条数据`,
}}
/>
</div>
<div className='company-detail-operate'>
<Button type='primary' onClick={backRoute}>
返回
</Button>
</div>
{/*添加成员*/}
<AddPeopleModal
open={addPeopleModalShow}
onCancel={addPeopleModalCancel}
onOk={addPeopleModalOk}
companyInfoId={companyId}
/>
{/*转让管理员*/}
<TransferLeaderModal
open={transferLeaderModalShow}
onCancel={transferLeaderModalCancel}
onOk={transferLeaderModalOk}
companyInfoId={companyId}
currentCompanyMembers={currentCompanyMembers}
/>
</div>
);
};
export default CompanyDetail;
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { InterListType, InterReqType } from '~/api/interface'; import { InterListType, InterReqType } from '~/api/interface';
import { listCompanyAdd, listCompanyPage } from '~/api/interface/systemManageType'; import { listCompanyAdd, listCompanyPage } from '~/api/interface/systemManageType';
import { Cascader, Form, Input, message, Modal } from 'antd'; import { Button, Col, Form, Input, message, Modal, Row } from 'antd';
import { SystemManageAPI } from '~/api'; import { SystemManageAPI } from '~/api';
import DistrictData from '~/assets/json/district.json'; import { EnvironmentOutlined } from '@ant-design/icons';
import SelectMap from '~/components/select-map';
// 列表的类型 // 列表的类型
type TableType = InterListType<listCompanyPage>; type TableType = InterListType<listCompanyPage>;
// 请求的表单类型 // 请求的表单类型
type ReqType = InterReqType<listCompanyAdd>; type ReqType = Exclude<InterReqType<listCompanyAdd>, undefined>;
// 传参类型 // 传参类型
interface propType { interface propType {
title: string; title: string;
...@@ -21,14 +22,15 @@ const AddEditModal: React.FC<propType> = (props) => { ...@@ -21,14 +22,15 @@ const AddEditModal: React.FC<propType> = (props) => {
const { title, open, closed, data } = props; const { title, open, closed, data } = props;
/// 表单钩子 /// 表单钩子
const [form] = Form.useForm<ReqType>(); const [form] = Form.useForm<ReqType>();
// 地区 //选点信息
const [localList, setLocalList] = useState< const [position, setPosition] = useState<{
{ lat: number;
childInfo: any[]; lon: number;
id: number; address: string;
name: string; }>();
}[] //地图选点弹窗
>(); const [selectMapShow, setSelectMapShow] = useState<boolean>(false);
// 关闭弹窗 // 关闭弹窗
const handleCancel = () => { const handleCancel = () => {
form.resetFields(); form.resetFields();
...@@ -39,13 +41,14 @@ const AddEditModal: React.FC<propType> = (props) => { ...@@ -39,13 +41,14 @@ const AddEditModal: React.FC<propType> = (props) => {
form form
.validateFields() .validateFields()
.then(async (values) => { .then(async (values) => {
await handleSubmit({ if (position) {
...values, await handleSubmit({
province: values?.area?.at(0), ...values,
city: values?.area?.at(1), lat: position.lat,
district: values?.area?.at(2), lon: position.lon,
companyType: data?.id === 1 ? 0 : 1, companyType: data?.id === 1 ? 0 : 1,
}); });
}
}) })
.catch((err) => { .catch((err) => {
message message
...@@ -66,22 +69,40 @@ const AddEditModal: React.FC<propType> = (props) => { ...@@ -66,22 +69,40 @@ const AddEditModal: React.FC<propType> = (props) => {
handleCancel(); handleCancel();
} }
}; };
// 获取地区信息
const getSecondDistrictInfo = async () => { const selectMapShowClick = () => {
setLocalList(DistrictData || []); setSelectMapShow(true);
};
const selectMapClose = () => {
setSelectMapShow(false);
};
const selectMapSubmit = (value: { lat: number; lon: number; address: string }) => {
form.setFieldValue('address', value.address);
setPosition(value);
setSelectMapShow(false);
}; };
const addressInputEvent = (e: any) => {
if (position) {
position.address = e.target.value;
form.setFieldValue('address', e.target.value || undefined);
setPosition({ ...position });
}
};
// componentDidMount // componentDidMount
useEffect(() => { useEffect(() => {
if (!open) return; if (!open) return;
getSecondDistrictInfo().then();
if (!data) return; if (!data) return;
// eslint-disable-next-line @typescript-eslint/ban-ts-comment // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore // @ts-ignore
form.setFieldsValue({ form.setFieldsValue({
...data, ...data,
area: [data?.province, data?.city, data?.district],
}); });
// console.log('data --->', data); setPosition({
address: data.address,
lat: data.lat,
lon: data.lon,
});
}, [open]); }, [open]);
return ( return (
<Modal <Modal
...@@ -100,35 +121,55 @@ const AddEditModal: React.FC<propType> = (props) => { ...@@ -100,35 +121,55 @@ const AddEditModal: React.FC<propType> = (props) => {
> >
<Input placeholder={'请输入单位名称'} maxLength={25} allowClear /> <Input placeholder={'请输入单位名称'} maxLength={25} allowClear />
</Form.Item> </Form.Item>
<Form.Item {/*<Form.Item*/}
label='单位全称' {/* label='单位全称'*/}
rules={[{ required: false, message: '请输入单位全称' }]} {/* rules={[{ required: false, message: '请输入单位全称' }]}*/}
name='fullName' {/* name='fullName'*/}
> {/*>*/}
<Input placeholder={'请输入单位全称'} maxLength={50} allowClear /> {/* <Input placeholder={'请输入单位全称'} maxLength={50} allowClear />*/}
</Form.Item> {/*</Form.Item>*/}
<Form.Item {/*<Form.Item*/}
label='行政区划' {/* label='行政区划'*/}
name='area' {/* name='area'*/}
rules={[{ required: true, message: '请选择行政区划' }]} {/* rules={[{ required: true, message: '请选择行政区划' }]}*/}
> {/*>*/}
<Cascader {/* <Cascader*/}
options={localList} {/* options={localList}*/}
placeholder='请选择行政区划' {/* placeholder='请选择行政区划'*/}
allowClear {/* allowClear*/}
fieldNames={{ {/* fieldNames={{*/}
label: 'name', {/* label: 'name',*/}
value: 'name', {/* value: 'name',*/}
children: 'childInfo', {/* children: 'childInfo',*/}
}} {/* }}*/}
/> {/* />*/}
</Form.Item> {/*</Form.Item>*/}
<Form.Item <Form.Item
label='详细地址' label='详细地址'
name='address' name='address'
rules={[{ required: true, message: '请输入详细地址' }]} rules={[{ required: true, message: '请输入详细地址' }]}
> >
<Input.TextArea placeholder='请输入详细地址' maxLength={50} showCount /> {/*<Input.TextArea placeholder='请输入详细地址' maxLength={50} showCount />*/}
<Row justify='space-between'>
{position ? (
<Col span={21}>
<Input
placeholder='请输入详细地址'
value={position.address}
onChange={addressInputEvent}
/>
</Col>
) : (
''
)}
<Col span={2}>
<Button
icon={<EnvironmentOutlined />}
type='primary'
onClick={selectMapShowClick}
></Button>
</Col>
</Row>
</Form.Item> </Form.Item>
<Form.Item label='联系人' name='companyUserName'> <Form.Item label='联系人' name='companyUserName'>
<Input placeholder='请输入联系人' maxLength={15} /> <Input placeholder='请输入联系人' maxLength={15} />
...@@ -152,6 +193,7 @@ const AddEditModal: React.FC<propType> = (props) => { ...@@ -152,6 +193,7 @@ const AddEditModal: React.FC<propType> = (props) => {
<Form.Item label='备注' name='remark'> <Form.Item label='备注' name='remark'>
<Input.TextArea placeholder='请输入备注' maxLength={50} showCount /> <Input.TextArea placeholder='请输入备注' maxLength={50} showCount />
</Form.Item> </Form.Item>
<SelectMap open={selectMapShow} closed={selectMapClose} submit={selectMapSubmit} />
</Form> </Form>
</Modal> </Modal>
); );
......
...@@ -6,6 +6,7 @@ import { InterListType, InterReqType } from '~/api/interface'; ...@@ -6,6 +6,7 @@ import { InterListType, InterReqType } from '~/api/interface';
import { ColumnsType } from 'antd/es/table'; import { ColumnsType } from 'antd/es/table';
import { SystemManageAPI } from '~/api'; import { SystemManageAPI } from '~/api';
import { listCompanyPage } from '~/api/interface/systemManageType'; import { listCompanyPage } from '~/api/interface/systemManageType';
import { useNavigate } from 'react-router-dom';
import AddEditModal from './comp/addEditModal'; import AddEditModal from './comp/addEditModal';
// 列表的数据类型 // 列表的数据类型
...@@ -16,6 +17,7 @@ type ReqType = InterReqType<listCompanyPage>; ...@@ -16,6 +17,7 @@ type ReqType = InterReqType<listCompanyPage>;
let query: ReqType = {}; let query: ReqType = {};
const CompanyManageView = () => { const CompanyManageView = () => {
const navigate = useNavigate();
const { confirm } = Modal; const { confirm } = Modal;
// 新增编辑弹窗是否开启 // 新增编辑弹窗是否开启
const [addEditModalVisible, setAddEditModalVisible] = useState(false); const [addEditModalVisible, setAddEditModalVisible] = useState(false);
...@@ -63,7 +65,7 @@ const CompanyManageView = () => { ...@@ -63,7 +65,7 @@ const CompanyManageView = () => {
// 删除单位 // 删除单位
const handleDelete = (value: TableType[0]) => { const handleDelete = (value: TableType[0]) => {
confirm({ confirm({
title: '提示', title: '提示(删除会造成该单位下的商品全部删除)',
content: '是否删除该单位?', content: '是否删除该单位?',
onOk: async () => { onOk: async () => {
const res = await SystemManageAPI.listCompanyRemove({ id: value.id }); const res = await SystemManageAPI.listCompanyRemove({ id: value.id });
...@@ -77,6 +79,14 @@ const CompanyManageView = () => { ...@@ -77,6 +79,14 @@ const CompanyManageView = () => {
}, },
}); });
}; };
//跳转单位详情
const toCompanyDetail = (record: TableType[0]) => {
navigate({
pathname: '/systemManage/companyDetail',
search: `id=${record.id}`,
});
};
// componentDidMount // componentDidMount
useEffect(() => { useEffect(() => {
query = {}; query = {};
...@@ -88,17 +98,11 @@ const CompanyManageView = () => { ...@@ -88,17 +98,11 @@ const CompanyManageView = () => {
title: '单位名称', title: '单位名称',
dataIndex: 'companyName', dataIndex: 'companyName',
align: 'center', align: 'center',
width: '150px', width: '20%',
fixed: 'left', fixed: 'left',
ellipsis: true, ellipsis: true,
}, },
{ {
title: '行政区划',
dataIndex: 'province',
align: 'center',
render: (_value, record) => `${record.province} / ${record.city} / ${record.district}`,
},
{
title: '详细地址', title: '详细地址',
dataIndex: 'address', dataIndex: 'address',
align: 'center', align: 'center',
...@@ -117,7 +121,7 @@ const CompanyManageView = () => { ...@@ -117,7 +121,7 @@ const CompanyManageView = () => {
}, },
{ {
title: '操作', title: '操作',
width: '100px', width: '20%',
fixed: 'right', fixed: 'right',
align: 'center', align: 'center',
render: (_text, record) => ( render: (_text, record) => (
...@@ -131,6 +135,9 @@ const CompanyManageView = () => { ...@@ -131,6 +135,9 @@ const CompanyManageView = () => {
> >
变更 变更
</Button> </Button>
<Button type='link' onClick={() => toCompanyDetail(record)}>
详情
</Button>
<Button <Button
type='link' type='link'
danger danger
......
...@@ -3,44 +3,40 @@ import { RouteObjectType, routerList } from '~/router/router'; ...@@ -3,44 +3,40 @@ import { RouteObjectType, routerList } from '~/router/router';
import { InterDataType } from '~/api/interface'; import { InterDataType } from '~/api/interface';
import { listMenuInfoType } from '~/api/interface/systemManageType'; import { listMenuInfoType } from '~/api/interface/systemManageType';
import { SystemManageAPI } from '~/api'; import { SystemManageAPI } from '~/api';
import Cookies from 'js-cookie'; import { store } from '~/store';
import { SET_MENU } from '~/store/module/menu';
//菜单类型 //菜单类型
type menuType = InterDataType<listMenuInfoType>; type menuType = InterDataType<listMenuInfoType>;
// 缓存路由列表
let routerListStore: any[] = [];
// 获取用户权限路由列表 // 获取用户权限路由列表
export const authRouterList = async () => { export const authRouterList = async () => {
if (localStorage.getItem('roleId') && Cookies.get('SHAREFLY-TOKEN')) { // 如果缓存中没有数据
// 如果缓存中没有数据 if (store.getState().Menu.menuList.length === 0) {
if (routerListStore.length === 0) { // 加载路由数据
// 加载路由数据 const { result } = await SystemManageAPI.getListRoleMenuInfo({
const { result } = await SystemManageAPI.getListRoleMenuInfo({ roleId: Number(localStorage.getItem('roleId')),
roleId: Number(localStorage.getItem('roleId')), });
}); const ids: number[] = getAllKeys([result]);
const ids: number[] = getAllKeys([result]); const getRouteList = (data: RouteObjectType[]) => {
const getRouteList = (data: RouteObjectType[]) => { return data.reduce((pre: RouteObjectType[], cur) => {
return data.reduce((pre: RouteObjectType[], cur) => { const Obj: RouteObjectType = { ...cur };
const Obj: RouteObjectType = { ...cur }; if (ids.includes(Obj.meta.id) || Obj.meta.hidden) {
if (ids.includes(Obj.meta.id) || Obj.meta.hidden) { if (Obj.children) {
if (Obj.children) { Obj.children = [...getRouteList(Obj.children)];
Obj.children = [...getRouteList(Obj.children)];
}
pre.push(Obj);
} }
return pre; pre.push(Obj);
}, []); }
}; return pre;
const arr = [...getRouteList(routerList)]; }, []);
// 将路由数据存到store中 };
routerListStore = arr; const arr = [...getRouteList(routerList)];
// 完成后返回路由数据 // 将路由数据存到store中
return Promise.resolve(arr); store.dispatch(SET_MENU(arr));
} else { // 完成后返回路由数据
return Promise.resolve(routerListStore); return Promise.resolve(arr);
} } else {
return Promise.resolve(store.getState().Menu.menuList);
} }
return Promise.resolve([]);
}; };
//获取全部节点 //获取全部节点
const getAllKeys = (data: menuType[]) => { const getAllKeys = (data: menuType[]) => {
......
...@@ -14,23 +14,29 @@ function PrivateRouter() { ...@@ -14,23 +14,29 @@ function PrivateRouter() {
// TODO: 判断是否登录 (需要改为实时获取地址栏的路由) // TODO: 判断是否登录 (需要改为实时获取地址栏的路由)
const path = location.pathname; const path = location.pathname;
const token = Cookies.get('SHAREFLY-TOKEN'); const token = Cookies.get('SHAREFLY-TOKEN');
const roleId = localStorage.getItem('roleId');
if (!token && path !== '/login') { if (!token && path !== '/login') {
navigate('/login', { replace: true }); navigate('/login', { replace: true });
return; return;
} }
if (roleId && token) {
// 整合路由数据
authRouterList().then((value) => {
if (value.length) {
const routes = [...value, ...whiteRouterList];
setRouter(routes);
if (path === '/') {
navigate({ pathname: value[0].children?.find((v: any) => !v.meta.hidden)?.path });
}
} else {
message.warning('该账号暂无权限');
navigate('/login', { replace: true });
}
});
}
}; };
useEffect(() => { useEffect(() => {
beforeEach(); beforeEach();
// 整合路由数据
authRouterList().then((value) => {
if (value.length) {
const routes = [...value, ...whiteRouterList];
setRouter(routes); //不同账号登录时,重新更新路由(有瑕疵)
} else if (localStorage.getItem('roleId')) {
message.warning('该账号暂无权限');
navigate('/login', { replace: true });
}
});
}, [location.pathname]); }, [location.pathname]);
return useRoutes(router); return useRoutes(router);
......
...@@ -91,13 +91,16 @@ const RentAddOrEditOrDetailView = React.lazy( ...@@ -91,13 +91,16 @@ const RentAddOrEditOrDetailView = React.lazy(
const MallGoodsView = React.lazy(() => import('~/pages/mallManage/mallGoods/goodsList')); //商城商品 const MallGoodsView = React.lazy(() => import('~/pages/mallManage/mallGoods/goodsList')); //商城商品
const MallAddOrEditOrDetailView = React.lazy( const MallAddOrEditOrDetailView = React.lazy(
() => import('~/pages/mallManage/mallGoods/goodsAddOrEditOrDetail'), () => import('~/pages/mallManage/mallGoods/goodsAddOrEditOrDetail'),
); //商城商品新增、编辑、详情 ); //商城商品新增、编辑、租赁商品详情
const MallGoodsDetailsView = React.lazy(() => import('~/pages/mallManage/mallGoods/goodsDetails')); //商城商品(新)
const ProduceListView = React.lazy(() => import('~/pages/mallManage/produceManage/produceList')); //产品列表 const ProduceListView = React.lazy(() => import('~/pages/mallManage/produceManage/produceList')); //产品列表
const ProduceDetailView = React.lazy( const ProduceDetailView = React.lazy(
() => import('~/pages/mallManage/produceManage/produceDetail'), () => import('~/pages/mallManage/produceManage/produceDetail'),
); //产品详情 ); //产品详情
const MakeListView = React.lazy(() => import('~/pages/mallManage/makeManage/makeList')); const MakeListView = React.lazy(() => import('~/pages/mallManage/makeManage/makeList'));
// 分类管理 // 分类管理
const CategoryListView = React.lazy(() => import('~/pages/categoryManage/categoryList'));
const CategoryManage = React.lazy(() => import('~/pages/categoryManage/category')); const CategoryManage = React.lazy(() => import('~/pages/categoryManage/category'));
const CategoryDetail = React.lazy(() => import('~/pages/categoryManage/category/detail')); const CategoryDetail = React.lazy(() => import('~/pages/categoryManage/category/detail'));
// 目录管理 // 目录管理
...@@ -119,7 +122,10 @@ import TenderManageDetail from '~/pages/resourceManage/tenderManage/detail'; ...@@ -119,7 +122,10 @@ import TenderManageDetail from '~/pages/resourceManage/tenderManage/detail';
import TenderManageFeedback from '~/pages/resourceManage/tenderManage/feedback'; import TenderManageFeedback from '~/pages/resourceManage/tenderManage/feedback';
import BusinessCaseManage from '~/pages/resourceManage/businessCaseManage'; import BusinessCaseManage from '~/pages/resourceManage/businessCaseManage';
import CustomIdentityView from '~/pages/customManage/customIdentity'; import CustomIdentityView from '~/pages/customManage/customIdentity';
import CompanyManageView from '~/pages/systemManage/companyManage'; import CompanyListView from '~/pages/systemManage/companyManage/companyList'; //单位列表
const CompanyDetailView = React.lazy(
() => import('~/pages/systemManage/companyManage/companyDetail'),
);
import AccountLimit from '~/pages/systemManage/limitManage/roleList'; //账号权限 import AccountLimit from '~/pages/systemManage/limitManage/roleList'; //账号权限
import LimitInfo from '~/pages/systemManage/limitManage/limitInfo'; import LimitInfo from '~/pages/systemManage/limitManage/limitInfo';
import CustomListDetail from '~/pages/customManage/customList/detail'; //权限信息 import CustomListDetail from '~/pages/customManage/customList/detail'; //权限信息
...@@ -467,16 +473,6 @@ export const routerList: Array<RouteObjectType> = [ ...@@ -467,16 +473,6 @@ export const routerList: Array<RouteObjectType> = [
}, },
children: [ children: [
{ {
path: '/mallManage/courseManage',
element: withLoadingComponent(<CourseManageView />),
errorElement: <ErrorPage />,
meta: {
id: 1010,
icon: <BookOutlined />,
title: '课程管理',
},
},
{
path: '/mallManage/serviceList', path: '/mallManage/serviceList',
element: withLoadingComponent(<ServiceListView />), element: withLoadingComponent(<ServiceListView />),
errorElement: <ErrorPage />, errorElement: <ErrorPage />,
...@@ -585,7 +581,7 @@ export const routerList: Array<RouteObjectType> = [ ...@@ -585,7 +581,7 @@ export const routerList: Array<RouteObjectType> = [
}, },
{ {
path: '/mallManage/mallGoods/detail', path: '/mallManage/mallGoods/detail',
element: withLoadingComponent(<MallAddOrEditOrDetailView />), element: withLoadingComponent(<MallGoodsDetailsView />),
errorElement: <ErrorPage />, errorElement: <ErrorPage />,
meta: { meta: {
id: 10146, id: 10146,
...@@ -687,8 +683,8 @@ export const routerList: Array<RouteObjectType> = [ ...@@ -687,8 +683,8 @@ export const routerList: Array<RouteObjectType> = [
}, },
}, },
{ {
path: '/categoryManage/jobServicesCategory/4', path: '/categoryManage/categoryList',
element: withLoadingComponent(<CategoryManage />), element: withLoadingComponent(<CategoryListView />),
errorElement: <ErrorPage />, errorElement: <ErrorPage />,
meta: { meta: {
id: 1240, id: 1240,
...@@ -696,6 +692,16 @@ export const routerList: Array<RouteObjectType> = [ ...@@ -696,6 +692,16 @@ export const routerList: Array<RouteObjectType> = [
icon: <AppstoreOutlined />, icon: <AppstoreOutlined />,
}, },
}, },
// {
// path: '/categoryManage/jobServicesCategory/4',
// element: withLoadingComponent(<CategoryManage />),
// errorElement: <ErrorPage />,
// meta: {
// id: 1240,
// title: '产品商城分类',
// icon: <AppstoreOutlined />,
// },
// },
{ {
path: '/categoryManage/jobServicesCategory/0', path: '/categoryManage/jobServicesCategory/0',
element: withLoadingComponent(<CategoryManage />), element: withLoadingComponent(<CategoryManage />),
...@@ -903,7 +909,7 @@ export const routerList: Array<RouteObjectType> = [ ...@@ -903,7 +909,7 @@ export const routerList: Array<RouteObjectType> = [
meta: { meta: {
id: 1600, id: 1600,
icon: <BankOutlined />, icon: <BankOutlined />,
title: '飞手培训', title: '执照培训',
}, },
children: [ children: [
{ {
...@@ -938,6 +944,16 @@ export const routerList: Array<RouteObjectType> = [ ...@@ -938,6 +944,16 @@ export const routerList: Array<RouteObjectType> = [
hidden: true, hidden: true,
}, },
}, },
{
path: '/pilotTraining/courseManage',
element: withLoadingComponent(<CourseManageView />),
errorElement: <ErrorPage />,
meta: {
id: 1010,
icon: <BookOutlined />,
title: '课程管理',
},
},
], ],
}, },
{ {
...@@ -982,13 +998,24 @@ export const routerList: Array<RouteObjectType> = [ ...@@ -982,13 +998,24 @@ export const routerList: Array<RouteObjectType> = [
}, },
}, },
{ {
path: '/systemManage/companyManage', path: '/systemManage/companyList',
element: withLoadingComponent(<CompanyManageView />), element: withLoadingComponent(<CompanyListView />),
errorElement: <ErrorPage />, errorElement: <ErrorPage />,
meta: { meta: {
id: 1430, id: 1430,
title: '单位管理', title: '单位列表',
icon: <BankOutlined />,
},
},
{
path: '/systemManage/companyDetail',
element: withLoadingComponent(<CompanyDetailView />),
errorElement: <ErrorPage />,
meta: {
id: 1440,
title: '单位详情',
icon: <BankOutlined />, icon: <BankOutlined />,
hidden: true,
}, },
}, },
], ],
......
import { createSlice } from '@reduxjs/toolkit'; import { createSlice } from '@reduxjs/toolkit';
const initialState = { const initialState = {
menuList: JSON.parse(localStorage.getItem('SXTB-ADMIN-MENU-LIST') as string) || [], menuList: [],
collapsedActive: false, collapsedActive: false,
menuId: JSON.parse(localStorage.getItem('SXTB-ADMIN-MENU-ID') as string) || null, roleId: localStorage.getItem('roleId') ? Number(localStorage.getItem('roleId')) : -1,
}; };
export const menuSlice = createSlice({ export const menuSlice = createSlice({
...@@ -12,22 +12,19 @@ export const menuSlice = createSlice({ ...@@ -12,22 +12,19 @@ export const menuSlice = createSlice({
reducers: { reducers: {
SET_MENU(state, action) { SET_MENU(state, action) {
state.menuList = action.payload; state.menuList = action.payload;
localStorage.setItem('SXTB-ADMIN-MENU-LIST', JSON.stringify(action.payload));
}, },
SET_COLLAPSE(state, action) { SET_COLLAPSE(state, action) {
state.collapsedActive = action.payload; state.collapsedActive = action.payload;
}, },
REMOVE_MENU(state) { REMOVE_MENU(state) {
localStorage.setItem('SXTB-ADMIN-MENU-LIST', JSON.stringify([]));
state.menuList = []; state.menuList = [];
}, },
SET_MENU_ID(state, action) { SET_MENU_ID(state, action) {
localStorage.setItem('SXTB-ADMIN-MENU-ID', JSON.stringify(action.payload)); state.roleId = action.payload;
state.menuId = action.payload; localStorage.setItem('roleId', action.payload);
}, },
REMOVE_MENU_ID(state) { REMOVE_MENU_ID() {
localStorage.setItem('SXTB-ADMIN-MENU-ID', JSON.stringify(null)); localStorage.removeItem('roleId');
state.menuId = null;
}, },
}, },
}); });
......
...@@ -2,8 +2,6 @@ import { createSlice } from '@reduxjs/toolkit'; ...@@ -2,8 +2,6 @@ import { createSlice } from '@reduxjs/toolkit';
const initialState = { const initialState = {
userInfo: JSON.parse(localStorage.getItem('SXTB-ADMIN-USER-INFO') as string) || [], userInfo: JSON.parse(localStorage.getItem('SXTB-ADMIN-USER-INFO') as string) || [],
roleId: -1,
roleList: [],
}; };
export const userInfoSlice = createSlice({ export const userInfoSlice = createSlice({
...@@ -14,24 +12,9 @@ export const userInfoSlice = createSlice({ ...@@ -14,24 +12,9 @@ export const userInfoSlice = createSlice({
state.userInfo = action.payload; state.userInfo = action.payload;
localStorage.setItem('SXTB-ADMIN-USER-INFO', JSON.stringify(action.payload)); localStorage.setItem('SXTB-ADMIN-USER-INFO', JSON.stringify(action.payload));
}, },
SET_ROLE_ID(state, action) {
state.roleId = action.payload;
localStorage.setItem('roleId', action.payload);
},
REMOVE_ROLE_ID() {
localStorage.removeItem('roleId');
},
SET_ROLE_LIST(state, action) {
state.roleList = action.payload;
localStorage.setItem('roleObj', JSON.stringify(action.payload));
},
REMOVE_ROLE_LIST() {
localStorage.removeItem('roleObj');
},
}, },
}); });
export const { SET_USERINFO, SET_ROLE_ID, SET_ROLE_LIST, REMOVE_ROLE_LIST, REMOVE_ROLE_ID } = export const { SET_USERINFO } = userInfoSlice.actions;
userInfoSlice.actions;
export const UserInfo = userInfoSlice.reducer; export const UserInfo = userInfoSlice.reducer;
import _ from 'lodash';
// 不能输入数字,其他可以输入 // 不能输入数字,其他可以输入
export const exceptNumber = (val: any) => { export const exceptNumber = (val: any) => {
val.target.value = val.target.value.replace(/1?(\d|([1-9]\d+))(.\d+)?$/g, '').replace(/\s/g, ''); val.target.value = val.target.value.replace(/1?(\d|([1-9]\d+))(.\d+)?$/g, '').replace(/\s/g, '');
...@@ -105,3 +107,13 @@ export const maxLength6 = (val: any) => { ...@@ -105,3 +107,13 @@ export const maxLength6 = (val: any) => {
val.target.value = val.target.value.replace(/\D/g, ''); val.target.value = val.target.value.replace(/\D/g, '');
} }
}; };
//通用价格,且保留两位小数正则
export const regPriceNumber = (value: string): boolean => {
const reg = /^\d+(\.\d{1,2})?$/;
return reg.test(value);
};
//判断空值
export const isEmptyBol = (value: any): boolean => {
return _.isNull(value) || _.isNaN(value) || _.isNull(value) || _.isUndefined(value);
};
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论