提交 1e06d1bb 作者: 龚洪江

联调:商品联调

上级 f05360e1
import { UploadFile } from 'antd/es/upload/interface';
// 商城-新增商品
import { InterFunction } from '~/api/interface';
import { InterFunction, InterItemFunction } from '~/api/interface';
//商品列表
export type listGoodsType = InterItemFunction<
{
directoryId?: number;
goodsName?: string;
goodsType: number;
status?: number;
startTime?: string;
endTime?: string;
},
{
createTime: string;
directoryId: number;
directoryName: string;
goodsDesc: string;
goodsName: string;
imgUrl: string;
isCoupons: number;
status: number;
}[]
>;
//商品-新增
export type BaseInfoType = {
goodsName: string;
......@@ -62,11 +83,11 @@ export type editGoodsType = InterFunction<
>;
//商品-详情
export type detailGoodsType = InterFunction<
{ goodsInfoId: number },
{ goodsInfoId: number; type: number; leaseTerm?: number },
BaseInfoType & {
goodsSpec: specEntity[];
goodsDetail: { goodsDesc: string; productDesc: string };
otherService: number[];
goodsDetail: { goodsDesc: string; productDesc: string; content: string };
otherService: { id: number; saleServiceName: string; saleServiceId: number }[];
goodsVideoId: number;
id: number;
}
......@@ -75,3 +96,7 @@ export type detailGoodsType = InterFunction<
export type otherServiceType = InterFunction<any, { id: number; saleServiceName: string }[]>;
//商品-规格单位
export type skuUnitType = InterFunction<any, { id: number; unitName: string }[]>;
//商品-批量上下架
export type batchOnShelfOrTakeDownType = InterFunction<{ goodsIds: number[]; status: number }, any>;
//商品批量删除
export type batchRemoveWareInfoType = InterFunction<number[], any>;
import {
addGoodsType,
batchOnShelfOrTakeDownType,
batchRemoveWareInfoType,
detailGoodsType,
editGoodsType,
listGoodsType,
otherServiceType,
skuUnitType,
} from '~/api/interface/goodsType';
import axios from '../request';
class GoodsAPI {
//商品-列表
static getGoodsList: listGoodsType = (data) => {
return axios.post('/pms/goods/listPageGoodsInfo', data);
};
//商品-新增
static addGoods: addGoodsType = (data) => {
return axios.post('/pms/goods/addGoodsInfo', data);
......@@ -28,5 +35,13 @@ class GoodsAPI {
static getOtherServiceList: otherServiceType = () => {
return axios.get('/pms/goods/listOtherService');
};
// 商品-批量上下架
static batchOnShelfOrTakeDown: batchOnShelfOrTakeDownType = (data) => {
return axios.post('/pms/goods/batchOnShelfOrTakeDown', data);
};
// 商品-批量删除
static batchRemoveWareInfo: batchRemoveWareInfoType = (data) => {
return axios.post('/pms/goods/batchRemoveWareInfo', data);
};
}
export default GoodsAPI;
......@@ -34,6 +34,7 @@ interface selfProps {
categoryList: categoryType;
curtRowData: Partial<specEntity>;
skuUnitList: unitType;
goodsType: number;
}
// interface tableRowEntity {
......@@ -51,6 +52,7 @@ const AddOrEditSkuModal: React.FC<ModalProps & selfProps> = ({
categoryList,
curtRowData,
skuUnitList,
goodsType,
}) => {
// 弹窗标题
const [dialogTitle, setDialogTitle] = useState<string>('添加');
......@@ -287,7 +289,7 @@ const AddOrEditSkuModal: React.FC<ModalProps & selfProps> = ({
setConfigurePriceModalShow(true);
setCustomRowData({ ...record });
};
const configurePriceHandleOk = (specPrice: any) => {
const configurePriceHandleOk = (specPrice: any, leaseTerm?: number) => {
setConfigurePriceModalShow(false);
const index: number = selfProductData.findIndex(
(i: customizeEntity) => i.id === customRowData.id,
......@@ -295,7 +297,8 @@ const AddOrEditSkuModal: React.FC<ModalProps & selfProps> = ({
selfProductData[index].productSpecCPQVO = {
productSpecId: selfProductData[index].productSpecCPQVO.productSpecId || undefined,
specPrice,
type: 0,
type: goodsType,
leaseTerm,
};
selfProductData.splice(index, 1, selfProductData[index]);
setSelfProductData([...selfProductData]);
......@@ -337,7 +340,7 @@ const AddOrEditSkuModal: React.FC<ModalProps & selfProps> = ({
});
return pre;
}, []);
handleOk({ ...values, id: curtRowData?.id || undefined });
handleOk({ ...values, id: curtRowData?.id || Math.random() });
} else {
const res: any = await Promise.all([validateCustomForm()]);
handleOk({
......@@ -394,6 +397,10 @@ const AddOrEditSkuModal: React.FC<ModalProps & selfProps> = ({
useEffect(() => {
if (Object.keys(curtRowData).length !== 0) {
setDialogTitle('编辑');
getProductList(curtRowData.categoryId as number);
if (!curtRowData.flag) {
getProductSpecList(curtRowData.skuId as number);
}
const specIds: number[] =
curtRowData.specIds && curtRowData.specIds.map((i: any) => i.mallSpecId);
skuForm.setFieldsValue({
......@@ -449,7 +456,9 @@ const AddOrEditSkuModal: React.FC<ModalProps & selfProps> = ({
<Form.Item label='规格来源' name='flag'>
<Radio.Group onChange={skuSourceRadioChange}>
<Radio value={0}>获取</Radio>
<Radio value={1}>自定义</Radio>
<Radio value={1} disabled={goodsType === 1}>
自定义
</Radio>
</Radio.Group>
</Form.Item>
)}
......@@ -601,7 +610,9 @@ const AddOrEditSkuModal: React.FC<ModalProps & selfProps> = ({
<Form.Item label='选择方式' name='chooseType'>
<Radio.Group>
<Radio value={0}>单选</Radio>
<Radio value={1}>多选</Radio>
<Radio value={1} disabled={goodsType === 1}>
多选
</Radio>
</Radio.Group>
</Form.Item>
<Form.Item label='是否必选' name='must'>
......@@ -634,6 +645,7 @@ const AddOrEditSkuModal: React.FC<ModalProps & selfProps> = ({
handleCancel={configurePriceHandleCancel}
customRowData={customRowData}
tagInfoList={tagInfoList}
goodsType={goodsType}
/>
</div>
);
......
......@@ -8,4 +8,14 @@
color: red;
}
}
.goods-video-wrap{
position: relative;
width: 200px;
img{
position: absolute;
right: 0;
top: 0;
transform: translate(50%,-25%);
}
}
}
......@@ -7,6 +7,7 @@ import { BaseInfoType, detailGoodsType } from '~/api/interface/goodsType';
import { CategoryManageAPI } from '~/api';
import { InterDataType } from '~/api/interface';
import { categoryListType, directoryPageListType } from '~/api/interface/categoryManage';
import deletePng from '~/assets/image/delete.png';
//目录返回类型
type directoryType = InterDataType<directoryPageListType>['list'];
......@@ -20,10 +21,12 @@ interface selfProps {
categoryList: categoryType;
ref: any;
goodsDetail: goodsDetailType | undefined;
isDetail: boolean; //是否详情
goodsType: number; //0:销售,1:租赁
}
const BaseInfo: React.FC<selfProps> = forwardRef(
({ getCategoryList, categoryList, goodsDetail }, ref) => {
({ getCategoryList, categoryList, goodsDetail, isDetail, goodsType }: selfProps, ref) => {
const [form] = Form.useForm<
BaseInfoType & {
mainImg: {
......@@ -31,7 +34,7 @@ const BaseInfo: React.FC<selfProps> = forwardRef(
name: string;
uid: number;
url: string;
};
}[];
subImg: {
id: number;
name: string;
......@@ -79,7 +82,7 @@ const BaseInfo: React.FC<selfProps> = forwardRef(
//获取目录列表
const getDirectoryList = () => {
CategoryManageAPI.getDirectoryListClone({ type: 4 }).then(({ result }) => {
CategoryManageAPI.getDirectoryListClone({ type: goodsType ? 2 : 4 }).then(({ result }) => {
setDirectoryList(result || []);
});
};
......@@ -132,6 +135,13 @@ const BaseInfo: React.FC<selfProps> = forwardRef(
goodsVideo: fileList[0].url,
});
};
//视频移除
const deleteVideo = () => {
setVideoList([]);
form.setFieldsValue({
goodsVideo: undefined,
});
};
useEffect(() => {
getDirectoryList();
}, []);
......@@ -188,6 +198,7 @@ const BaseInfo: React.FC<selfProps> = forwardRef(
wrapperCol={{ span: 16 }}
initialValues={{ shelfStatus: 1 }}
form={form}
disabled={isDetail}
>
<Form.Item
name='mainImg'
......@@ -205,22 +216,25 @@ const BaseInfo: React.FC<selfProps> = forwardRef(
</Form.Item>
<Form.Item label='商品副图' name='subImg'>
<Uploader
listType='picture-card'
listType={isDetail && subImgList.length === 0 ? 'text' : 'picture-card'}
fileUpload
onChange={subImgUploadSuccess}
fileLength={3}
defaultFileList={subImgList}
>
<UploadOutlined />
{isDetail ? subImgList.length ? '' : '暂无' : <UploadOutlined />}
</Uploader>
</Form.Item>
<Form.Item label='商品视频' name='goodsVideo'>
{videoList.length ? (
<div className='goods-video-wrap'>
<video
src={videoList[0].url}
style={{ width: '200px', height: '200px' }}
controls
/>
{!isDetail && <img src={deletePng} alt='删除' onClick={deleteVideo} />}
</div>
) : (
<Uploader
listType='text'
......@@ -228,7 +242,15 @@ const BaseInfo: React.FC<selfProps> = forwardRef(
onChange={videoUploadSuccess}
defaultFileList={videoList}
>
{isDetail ? (
videoList.length ? (
''
) : (
'暂无'
)
) : (
<Button icon={<UploadOutlined />}>上传视频</Button>
)}
</Uploader>
)}
</Form.Item>
......
......@@ -3,14 +3,16 @@ import { Modal, Form, Select, Input, message, Button, ModalProps } from 'antd';
import { InterDataType } from '~/api/interface';
import { cooperationTagType } from '~/api/interface/produceManageType';
import { customizeEntity } from '~/api/interface/goodsType';
import { filterObjAttr } from '~/utils';
//加盟标签返回类型
type cooperationTagResponseType = InterDataType<cooperationTagType>;
interface selfProps {
handleOk: (specPrice: any) => void;
handleOk: (specPrice: any, leaseTerm: number) => void;
handleCancel: () => void;
customRowData: Partial<customizeEntity>;
tagInfoList: cooperationTagResponseType;
goodsType: number;
}
const ConfigurePriceModal: React.FC<ModalProps & selfProps> = ({
......@@ -19,6 +21,7 @@ const ConfigurePriceModal: React.FC<ModalProps & selfProps> = ({
handleCancel,
customRowData,
tagInfoList,
goodsType,
}) => {
// 选择的列表
const [selectList, setSelectList] = useState<number[]>([]);
......@@ -46,7 +49,8 @@ const ConfigurePriceModal: React.FC<ModalProps & selfProps> = ({
cfgPriceForm
.validateFields()
.then(async (values) => {
const specPrice = Object.keys(values).reduce((pre: any, cur: string) => {
const specPrice = Object.keys(filterObjAttr(values, ['leaseTerm'])).reduce(
(pre: any, cur: string) => {
if (Object.keys(customRowData.productSpecCPQVO).length != 0) {
const priceItem: any = customRowData.productSpecCPQVO.specPrice.find(
(i: any) => i.cooperationTag === Number(cur),
......@@ -60,8 +64,10 @@ const ConfigurePriceModal: React.FC<ModalProps & selfProps> = ({
pre.push({ price: values[cur], cooperationTag: cur });
}
return pre;
}, []);
handleOk([...specPrice]);
},
[],
);
handleOk([...specPrice], values.leaseTerm);
})
.catch((err) => {
message.warning(err.errorFields[0].errors[0]).then();
......@@ -92,11 +98,12 @@ const ConfigurePriceModal: React.FC<ModalProps & selfProps> = ({
cfgPriceForm.resetFields();
setSelectList([]);
} else {
cfgPriceForm.setFieldValue('leaseTerm', customRowData.productSpecCPQVO.leaseTerm);
const ids: number[] = [];
customRowData.productSpecCPQVO.specPrice.map((item: any) => {
cfgPriceForm.setFieldValue(Number(item.tagInfoId), item.price);
if (item.tagInfoId != '0') {
ids.push(Number(item.tagInfoId));
cfgPriceForm.setFieldValue(Number(item.cooperationTag), item.price);
if (item.cooperationTag != '0') {
ids.push(Number(item.cooperationTag));
}
setSelectList(ids);
});
......@@ -118,7 +125,26 @@ const ConfigurePriceModal: React.FC<ModalProps & selfProps> = ({
</Button>,
]}
>
<Form labelCol={{ span: 7 }} wrapperCol={{ span: 14 }} form={cfgPriceForm}>
<Form
labelCol={{ span: 7 }}
wrapperCol={{ span: 14 }}
form={cfgPriceForm}
initialValues={{ leaseTerm: 0 }}
>
{goodsType && (
<Form.Item
label='租期'
name='leaseTerm'
rules={[{ required: true, message: '请选择租期' }]}
>
<Select>
<Select.Option value={0}>1-7天</Select.Option>
<Select.Option value={1}>8-15天</Select.Option>
<Select.Option value={2}>16-30天</Select.Option>
<Select.Option value={3}>31天以上</Select.Option>
</Select>
</Form.Item>
)}
<Form.Item label='渠道等级'>
<Select
placeholder='请选择渠道等级'
......
import './index.scss';
import RichText from '~/components/richText';
import { FC } from 'react';
import { InterDataType } from '~/api/interface';
import { detailGoodsType } from '~/api/interface/goodsType';
//商品返回类型
type goodsDetailType = InterDataType<detailGoodsType>;
interface selfProps {
getRichText: (html?: string) => void;
goodsDetail: goodsDetailType | undefined;
isDetail: boolean;
}
const GoodsIntroduce: FC<selfProps> = ({ getRichText }) => {
const GoodsIntroduce: FC<selfProps> = ({ getRichText, goodsDetail, isDetail }) => {
const richTextChange = (html?: string) => {
getRichText(html);
};
......@@ -14,7 +20,11 @@ const GoodsIntroduce: FC<selfProps> = ({ getRichText }) => {
<div className='goods-introduce'>
<div className='goods-introduce-title'>产品介绍图</div>
<div className='goods-introduce-content'>
<RichText value='' onChange={richTextChange} />
<RichText
value={goodsDetail?.goodsDetail.content}
onChange={richTextChange}
isDetail={isDetail}
/>
</div>
</div>
);
......
......@@ -10,11 +10,13 @@ type goodsDetailType = InterDataType<detailGoodsType>;
interface selfProps {
otherServiceSelect: (id: number[]) => void;
goodsDetail: goodsDetailType | undefined;
isDetail: boolean;
}
//其它服务返回类型
type otherServiceListType = InterDataType<otherServiceType>;
const OtherInfo: React.FC<selfProps> = ({ otherServiceSelect, goodsDetail }) => {
const OtherInfo: React.FC<selfProps> = ({ otherServiceSelect, goodsDetail, isDetail }) => {
const [otherInfoForm] = Form.useForm();
//其它服务
const [otherServiceList, setOtherServiceList] = useState<otherServiceListType>([]);
const otherServiceRadioChange = (e: any) => {
......@@ -29,17 +31,22 @@ const OtherInfo: React.FC<selfProps> = ({ otherServiceSelect, goodsDetail }) =>
useEffect(() => {
getOtherServiceList();
}, []);
useEffect(() => {
if (goodsDetail) {
otherInfoForm.setFieldsValue({
otherService: goodsDetail.otherService.map((v) => v.saleServiceId),
});
}
}, [goodsDetail]);
return (
<div className='other-info'>
<div className='other-info-title'>其它信息</div>
<div className='other-info-form'>
<Form>
<Form form={otherInfoForm} disabled={isDetail}>
<Form.Item label='搭配服务' name='otherService'>
<Checkbox.Group
onChange={otherServiceRadioChange}
value={goodsDetail?.otherService || []}
>
<Checkbox.Group onChange={otherServiceRadioChange}>
{otherServiceList.map((item: any, index: number) => (
<Checkbox value={item.id} key={index}>
{item.saleServiceName}
......
......@@ -18,9 +18,18 @@ interface selfProps {
specData: specEntity[];
categoryList: categoryType;
skuUnitList: unitType;
deleteSku: (record: specEntity) => void;
isDetail: boolean;
}
const StockSku: React.FC<selfProps> = ({ addOrEditSku, specData, categoryList, skuUnitList }) => {
const StockSku: React.FC<selfProps> = ({
addOrEditSku,
specData,
categoryList,
skuUnitList,
deleteSku,
isDetail,
}) => {
const columns: ColumnsType<specEntity> = [
{
title: '序号',
......@@ -97,7 +106,9 @@ const StockSku: React.FC<selfProps> = ({ addOrEditSku, specData, categoryList, s
>
编辑
</Button>
<Button type='link'>删除</Button>
<Button type='link' onClick={() => deleteSkuClick(record)}>
删除
</Button>
</div>
);
},
......@@ -107,6 +118,10 @@ const StockSku: React.FC<selfProps> = ({ addOrEditSku, specData, categoryList, s
const addOrEditSkuClick = (record?: specEntity) => {
addOrEditSku(record);
};
//删除规格操作
const deleteSkuClick = (record: specEntity) => {
deleteSku(record);
};
// 自定义选项来源名称
const getSelfSpecName = (obj: customizeEntity) => {
return `${obj.specName}(${obj.partNo || ''})`;
......@@ -125,18 +140,21 @@ const StockSku: React.FC<selfProps> = ({ addOrEditSku, specData, categoryList, s
<div className='stock-sku'>
<div className='stock-sku-title'>库存规格</div>
<div className='stock-sku-content'>
{!isDetail && (
<div className='stock-sku-operate'>
<Button icon={<PlusOutlined />} type='primary' onClick={() => addOrEditSkuClick()}>
添加规格
</Button>
</div>
)}
<Table
size='small'
bordered
dataSource={specData}
rowKey='id'
pagination={false}
columns={columns}
columns={isDetail ? columns.filter((v) => v.title !== '操作') : columns}
/>
</div>
</div>
......
......@@ -8,7 +8,7 @@ let editor: any = null;
interface PropsType {
onChange: (html?: string) => void;
value: string;
value: string | undefined;
// eslint-disable-next-line react/require-default-props
isDetail?: boolean;
height?: number;
......@@ -86,7 +86,7 @@ const RichText: React.FC<PropsType> = ({ onChange, value, isDetail, height }) =>
}, []);
useEffect(() => {
if (editor) {
editor.txt.html(value);
editor.txt.html(value || '');
}
if (isDetail) {
editor.disable();
......
......@@ -113,6 +113,7 @@ export const Uploader: React.FC<PropsType> = (props) => {
onRemove: (res) => {
const newFileList = fileList.filter((item) => item.uid !== res.uid);
setFileList(newFileList);
onChange?.(newFileList);
},
// onPreview: { onPreview },
};
......
import BaseInfo from './components/baseInfo';
import StockSku from './components/stockSku';
import OtherInfo from './components/otherInfo';
import GoodsIntroduce from './components/goodsIntroduce';
import AddOrEditSkuModal from './components/addOrEditSkuModal';
import BaseInfo from '~/components/goods/commonAddOrEdit/baseInfo';
import StockSku from '~/components/goods/commonAddOrEdit/stockSku';
import OtherInfo from '~/components/goods/commonAddOrEdit/otherInfo';
import GoodsIntroduce from '~/components/goods/commonAddOrEdit/goodsIntroduce';
import AddOrEditSkuModal from '~/components/goods/commonAddOrEdit/addOrEditSkuModal';
import { Button, message } from 'antd';
import { useNavigate, useSearchParams } from 'react-router-dom';
import './index.scss';
......@@ -53,6 +53,8 @@ const GoodsAddOrEditOrDetail = () => {
const [goodsDetail, setGoodsDetail] = useState<goodsDetailType>();
//产品介绍
const [productIntroduce, setProductIntroduce] = useState<string>('');
//是否商品详情
const [isDetail, setIsDetail] = useState<boolean>(false);
//添加、编辑规格
const addOrEditSkuShowEvent = (record?: specEntity) => {
......@@ -66,6 +68,12 @@ const GoodsAddOrEditOrDetail = () => {
}
setAddOrEditSkuModalShow(true);
};
//删除规格
const deleteSkuEvent = (record: specEntity) => {
const index = specData.findIndex((v) => v.id === record.id);
specData.splice(index, 1);
setSpecData([...specData]);
};
const addOrEditSkuModalCancel = () => {
setAddOrEditSkuModalShow(false);
};
......@@ -75,7 +83,6 @@ const GoodsAddOrEditOrDetail = () => {
specData.splice(index, 1, data);
setSpecData([...specData]);
} else {
console.log('执行了--->', curtRowData);
setSpecData([...specData, data]);
}
setAddOrEditSkuModalShow(false);
......@@ -104,7 +111,7 @@ const GoodsAddOrEditOrDetail = () => {
};
//商品详情
const getGoodsDetail = (goodsInfoId: number) => {
GoodsAPI.getGoodsDetail({ goodsInfoId }).then(({ result }) => {
GoodsAPI.getGoodsDetail({ goodsInfoId, type: 0 }).then(({ result }) => {
setGoodsDetail(result);
getCategoryList(result.directoryId);
const specList: specEntity[] = result.goodsSpec.reduce((pre: any, cur: specEntity) => {
......@@ -174,7 +181,11 @@ const GoodsAddOrEditOrDetail = () => {
...values.subImg.map((v: any) => ({
imgType: 1,
imgUrl: v.url,
id: goodsDetail ? v.id : undefined,
id: goodsDetail
? goodsDetail.images.some((i) => i.id === v.id)
? v.id
: undefined
: undefined,
})),
);
}
......@@ -237,6 +248,7 @@ const GoodsAddOrEditOrDetail = () => {
if (searchParams.get('id')) {
getGoodsDetail(Number(searchParams.get('id')));
}
setIsDetail(!!searchParams.get('isDetail'));
getSkuUnit();
}, []);
return (
......@@ -247,6 +259,8 @@ const GoodsAddOrEditOrDetail = () => {
categoryList={categoryList}
getCategoryList={getCategoryList}
goodsDetail={goodsDetail}
isDetail={isDetail}
goodsType={0}
/>
{/* 库存规格*/}
<StockSku
......@@ -254,11 +268,17 @@ const GoodsAddOrEditOrDetail = () => {
specData={specData}
categoryList={categoryList}
skuUnitList={skuUnitList}
deleteSku={deleteSkuEvent}
isDetail={isDetail}
/>
{/*其它信息*/}
<OtherInfo otherServiceSelect={otherServiceSelect} goodsDetail={goodsDetail} />
<OtherInfo
otherServiceSelect={otherServiceSelect}
goodsDetail={goodsDetail}
isDetail={isDetail}
/>
{/*产品介绍图*/}
<GoodsIntroduce getRichText={getRichText} />
<GoodsIntroduce getRichText={getRichText} goodsDetail={goodsDetail} isDetail={isDetail} />
{/*库存规格,添加、编辑弹窗*/}
<AddOrEditSkuModal
currentDesc={currentDesc}
......@@ -268,11 +288,14 @@ const GoodsAddOrEditOrDetail = () => {
categoryList={categoryList}
skuUnitList={skuUnitList}
curtRowData={curtRowData}
goodsType={0}
/>
<div className='goods-info-operate'>
{!isDetail && (
<Button type='primary' onClick={saveSubmit}>
保存
</Button>
)}
<Button onClick={backRoute}>返回</Button>
</div>
</div>
......
import SearchBox, { searchColumns } from '~/components/search-box';
import { useState } from 'react';
import React, { useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { Button, Card, Table } from 'antd';
import { Button, Card, Image, message, Table } from 'antd';
import {
ArrowDownOutlined,
ArrowUpOutlined,
......@@ -9,6 +9,17 @@ import {
PlusOutlined,
} from '@ant-design/icons';
import { ColumnsType } from 'antd/es/table';
import GoodsAPI from '~/api/modules/goodsAPI';
import { InterDataType, InterReqType, PaginationProps } from '~/api/interface';
import { listGoodsType } from '~/api/interface/goodsType';
import { CategoryManageAPI } from '~/api';
import { filterObjAttr } from '~/utils';
//商品返回类型
type goodsType = InterDataType<listGoodsType>['list'];
//商品列表筛选类型
type goodsSearchParameters = Omit<InterReqType<listGoodsType>, 'pageNo' | 'pageSize' | 'goodsType'>;
const GoodsList = () => {
const navigate = useNavigate();
const tabList = [
......@@ -26,63 +37,173 @@ const GoodsList = () => {
},
];
const [activeTabKey, setActiveTabKey] = useState<string>('1');
const [searchColumns] = useState<searchColumns[]>([
const [searchColumns, setSearchColumns] = useState<searchColumns[]>([
{
label: '商品名称',
placeholder: '请输入商品名称',
name: '',
name: 'goodsName',
type: 'input',
},
{
label: '所属目录',
placeholder: '请选择所属目录',
name: '',
name: 'directoryId',
type: 'select',
options: [],
},
{
label: '创建时间',
placeholder: '请输入选择创建时间',
name: '',
name: 'time',
type: 'rangePicker',
},
]);
const tableColumns: ColumnsType<any> = [
{ title: '序号', align: 'center' },
{ title: '图片', align: 'center' },
{ title: '商品名称', align: 'center' },
{ title: '所属目录', align: 'center' },
{ title: '创建时间', align: 'center' },
{ title: '状态', align: 'center' },
const tableColumns: ColumnsType<goodsType[0]> = [
{
title: '序号',
align: 'center',
render: (_text: any, _record, index: number) =>
(pagination.pageNo - 1) * pagination.pageSize + index + 1,
},
{
title: '图片',
align: 'center',
dataIndex: 'imgUrl',
render: (text: string) => <Image src={text} width={50} height={50} />,
},
{ title: '商品名称', align: 'center', dataIndex: 'goodsName' },
{ title: '所属目录', align: 'center', dataIndex: 'directoryName' },
{ title: '创建时间', align: 'center', dataIndex: 'createTime' },
{
title: '状态',
align: 'center',
dataIndex: 'status',
render: (text: number) => (text ? '上架' : '下架'),
},
{
title: '操作',
align: 'center',
render: () => (
dataIndex: 'id',
render: (id: number) => (
<>
<Button type='link' onClick={toEditGoods}>
<Button type='link' onClick={() => toEditGoods(id)}>
编辑
</Button>
<Button type='link'>详情</Button>
<Button type='link' onClick={() => toGoodsDetail(id)}>
详情
</Button>
</>
),
},
];
const [tableData] = useState<{ id: number }[]>([{ id: 1 }]);
const [tableData, setTableData] = useState<goodsType>([]);
//分页
const [pagination, setPagination] = useState<PaginationProps & { totalCount: number }>({
pageNo: 1,
pageSize: 10,
totalCount: 0,
});
//筛选
const [query, setQuery] = useState<goodsSearchParameters>({ status: undefined });
// 表格多选
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
const onTabChange = (key: string) => {
pagination.pageNo = 1;
query.status = key === '1' ? undefined : key === '2' ? 1 : 0;
getGoodsList(query);
setQuery(query);
setActiveTabKey(key);
};
const paginationChange = (pageNo: number, pageSize: number) => {
pagination.pageSize = pageSize;
pagination.pageNo = pageNo;
getGoodsList(query);
};
//筛选
const searchSuccess = (data: any) => {
pagination.pageNo = 1;
setQuery(filterObjAttr(data, ['time']));
getGoodsList(filterObjAttr(data, ['time']));
};
//商品列表
const getGoodsList = (query?: goodsSearchParameters) => {
GoodsAPI.getGoodsList({
pageNo: pagination.pageNo,
pageSize: pagination.pageSize,
goodsType: 0,
...query,
}).then(({ result }) => {
setTableData(result.list || []);
pagination.totalCount = result.totalCount;
setPagination(pagination);
});
};
//新增商品
const toAddMallGoods = () => {
navigate({ pathname: '/mallManage/mallGoods/add' });
};
//编辑商品
const toEditGoods = () => {
const toEditGoods = (id: number) => {
navigate({
pathname: '/mallManage/mallGoods/add',
search: `id=${43}`,
search: `id=${id}`,
});
};
//商品详情
const toGoodsDetail = (id: number) => {
navigate({
pathname: '/mallManage/mallGoods/detail',
search: `id=${id}&isDetail=1`,
});
};
// 表格多选事件
const onSelectChange = (newSelectedRowKeys: React.Key[]) => {
setSelectedRowKeys(newSelectedRowKeys);
};
//获取目录列表
const getDirectoryList = () => {
CategoryManageAPI.getDirectoryListClone({ type: 4 }).then(({ result }) => {
if (result) {
const options = result.map((v) => ({ id: v.id, name: v.directoryName }));
searchColumns[1].options = options;
setSearchColumns(searchColumns);
}
});
};
//商品-批量上下架
const batchOnShelfOrTakeDown = (status: number) => {
if (selectedRowKeys.length === 0) {
return message.warning('请先选择商品');
}
GoodsAPI.batchOnShelfOrTakeDown({ goodsIds: selectedRowKeys as number[], status }).then(
({ code }) => {
if (code === '200') {
message.success(status ? '上架成功' : '下架成功');
getGoodsList(query);
}
},
);
};
//商品-删除
const deleteGoods = () => {
if (selectedRowKeys.length === 0) {
return message.warning('请先选择商品');
}
GoodsAPI.batchRemoveWareInfo(selectedRowKeys as number[]).then(({ code }) => {
if (code === '200') {
if (pagination.pageNo !== 1 && tableData.length == 1) {
pagination.pageNo -= 1;
}
message.success('删除成功');
getGoodsList(query);
}
});
};
useEffect(() => {
getGoodsList();
getDirectoryList();
}, []);
return (
<div className='goods-list'>
<SearchBox
......@@ -92,20 +213,54 @@ const GoodsList = () => {
新增商品
</Button>
}
searchData={searchSuccess}
/>
<Card tabList={tabList} activeTabKey={activeTabKey} onTabChange={onTabChange}>
<div className='header-operate' style={{ marginBottom: '10px' }}>
<Button type='primary' style={{ marginRight: '10px' }} icon={<ArrowUpOutlined />}>
{activeTabKey !== '2' && (
<Button
type='primary'
style={{ marginRight: '10px' }}
icon={<ArrowUpOutlined />}
onClick={() => batchOnShelfOrTakeDown(1)}
>
上架
</Button>
<Button type='primary' style={{ marginRight: '10px' }} icon={<ArrowDownOutlined />}>
)}
{activeTabKey !== '3' && (
<Button
type='primary'
style={{ marginRight: '10px' }}
icon={<ArrowDownOutlined />}
onClick={() => batchOnShelfOrTakeDown(0)}
>
下架
</Button>
<Button danger icon={<DeleteOutlined />}>
)}
<Button danger icon={<DeleteOutlined />} onClick={deleteGoods}>
删除
</Button>
</div>
<Table columns={tableColumns} bordered dataSource={tableData} />
<Table
columns={tableColumns}
bordered
dataSource={tableData}
rowKey='id'
rowSelection={{
selectedRowKeys,
onChange: onSelectChange,
}}
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} 条数据`,
}}
/>
</Card>
</div>
);
......
......@@ -51,11 +51,25 @@ const SetProduceSpecPriceModal: FC<ModalProps & PropsType> = ({ open, onCancel,
return { ...pre };
}, {});
if (result.length) {
form.setFieldsValue({ ...Obj, level: levelNumber });
//没有设置价格的清空
const setDefaultObj = tagInfoList.reduce((pre: any, cur) => {
if (!Object.keys(Obj).includes(cur.id.toString())) {
pre[cur.id] = undefined;
}
return pre;
}, {});
console.log('数据-->', setDefaultObj);
form.setFieldsValue({ ...Obj, level: levelNumber, ...setDefaultObj });
} else {
//如果没有返回价格,清楚上一次选择的租期价格
const defaultObj = tagInfoList.reduce((pre: any, cur) => {
pre[cur.id] = undefined;
return pre;
}, {});
form.setFieldsValue({
0: undefined,
level: undefined,
...defaultObj,
});
}
const arr = result
......
......@@ -157,6 +157,7 @@ function ProduceManage() {
}).then(({ result }) => {
setLoading(false);
setTableData(result.list || []);
pagination.totalCount = result.totalCount;
setPagination(pagination);
});
};
......
.base-info {
&-title {
font-size: 15px;
font-weight: bold;
margin-bottom: 20px;
&::before {
content: '*';
color: red;
}
}
}
import React, { forwardRef } from 'react';
import { Button, Form, Upload, Input, Radio, Select, Cascader } from 'antd';
import { UploadOutlined } from '@ant-design/icons';
import { Uploader } from '~/components/uploader';
import './index.scss';
const BaseInfo: React.FC<any> = forwardRef(() => {
return (
<div className='base-info'>
<div className='base-info-title'>基本信息</div>
<div className='base-info-form'>
<Form labelCol={{ span: 2 }} wrapperCol={{ span: 16 }} initialValues={{ shelfStatus: 1 }}>
<Form.Item
name='mainFileList'
label='商品主图'
rules={[{ required: true, message: '请上传商品主图' }]}
>
<Uploader listType='picture-card'>
<div>上传</div>
</Uploader>
</Form.Item>
<Form.Item label='商品副图' name='subFileList'>
<Uploader listType='picture-card'>
<div>上传</div>
</Uploader>
</Form.Item>
<Form.Item label='商品视频'>
<Upload>
<Button icon={<UploadOutlined />}>上传视频</Button>
</Upload>
</Form.Item>
<Form.Item
name='goodsName'
label='商品名称'
rules={[{ required: true, message: '请输入商品名称' }]}
>
<Input placeholder='请输入商品名称' maxLength={50} style={{ width: '400px' }} />
</Form.Item>
<Form.Item
name='goodsDesc'
label='商品描述'
rules={[{ required: true, message: '请输入商品描述' }]}
>
<Input.TextArea
placeholder='请输入商品描述'
maxLength={70}
style={{ width: '400px' }}
rows={4}
showCount
/>
</Form.Item>
<Form.Item
name='sortTypeId'
label='所属目录'
rules={[{ required: true, message: '请选择所属目录' }]}
>
<Select placeholder='请选择所属目录' style={{ width: '400px' }}>
<Select.Option>1</Select.Option>
</Select>
</Form.Item>
<Form.Item
name='masterTypeId'
label='商品分类'
rules={[{ required: true, message: '请选择商品分类' }]}
>
<Cascader
style={{ width: '400px' }}
fieldNames={{
label: 'goodsMasterType',
value: 'goodsMasterTypeId',
children: 'goodsSlaveTypeDTO',
}}
placeholder='请选择商品分类'
allowClear
/>
</Form.Item>
<Form.Item label='商品标签'>
<Radio.Group>
<Radio value={false}>不加</Radio>
<Radio value></Radio>
</Radio.Group>
</Form.Item>
<Form.Item
name='tag'
label='标签名称'
rules={[{ required: true, message: '请输入标签名称' }]}
>
<Input placeholder='请输入标签名称' style={{ width: '400px' }} maxLength={5} />
</Form.Item>
<Form.Item
label='商品状态'
name='shelfStatus'
rules={[{ required: true, message: '请选择商品状态' }]}
>
<Select placeholder='请选择商品状态' style={{ width: '400px' }}>
<Select.Option value={1}>上架</Select.Option>
<Select.Option value={0}>下架</Select.Option>
</Select>
</Form.Item>
</Form>
</div>
</div>
);
});
export default BaseInfo;
.goods-introduce {
&-title {
font-size: 15px;
font-weight: bold;
margin: 20px 0;
}
&-content {
margin-left: 50px;
}
}
import './index.scss';
import RichText from '~/components/richText';
const GoodsIntroduce = () => {
return (
<div className='goods-introduce'>
<div className='goods-introduce-title'>产品介绍图</div>
<div className='goods-introduce-content'>
<RichText richTextHeight={300} />
</div>
</div>
);
};
export default GoodsIntroduce;
.other-info {
&-title {
font-size: 15px;
font-weight: bold;
margin: 20px 0;
}
&-form {
margin-left: 50px;
}
}
import React, { forwardRef } from 'react';
import { Checkbox, Form, Select, Row, Col } from 'antd';
import './index.scss';
const OtherInfo: React.FC<any> = forwardRef(() => {
return (
<div className='other-info'>
<div className='other-info-title'>其它信息</div>
<div className='other-info-form'>
<Form>
<Form.Item label='搭配服务' name='otherService'>
<Checkbox.Group>
<Checkbox>1</Checkbox>
</Checkbox.Group>
</Form.Item>
<Row>
<Col>
<span>用服务&gt;云享飞:</span>
</Col>
<Col span={8}>
<Form.Item name='shareFlyServiceId'>
<Select
allowClear
placeholder='请选择服务'
showSearch
filterOption={(input, option) =>
(option!.children as unknown as string)
.toLowerCase()
.includes(input.toLowerCase())
}
>
<Select.Option>1</Select.Option>
</Select>
</Form.Item>
</Col>
</Row>
<Row>
<Col>
<span>&nbsp;&nbsp;&nbsp;&nbsp;我要租&gt;云仓:</span>
</Col>
<Col span={8}>
<Form.Item name='repoId'>
<Select
allowClear
placeholder='请选择商品'
showSearch
filterOption={(input, option) =>
(option!.children as unknown as string)
.toLowerCase()
.includes(input.toLowerCase())
}
>
<Select.Option>1</Select.Option>
</Select>
</Form.Item>
</Col>
</Row>
</Form>
</div>
</div>
);
});
export default OtherInfo;
.stock-sku {
&-title {
font-size: 15px;
font-weight: bold;
margin: 20px 0;
}
&-content {
margin-left: 50px;
}
&-operate {
margin-bottom: 10px;
}
}
import React from 'react';
import { Table, Button } from 'antd';
import { PlusOutlined } from '@ant-design/icons';
import './index.scss';
import { ColumnsType } from 'antd/es/table';
const StockSku: React.FC<any> = () => {
const columns: ColumnsType<any> = [
{
title: '序号',
align: 'center',
render: () => <div>--</div>,
},
{
title: `产品类型`,
align: 'center',
// dataIndex: "goodsTypeId",
render: () => <div>--</div>,
},
{
title: '规格名称',
align: 'center',
dataIndex: 'goodsSpecName',
},
{
title: `方案`,
align: 'center',
dataIndex: 'skuName',
},
{
title: '选项来源',
align: 'center',
dataIndex: 'specIds',
render: () => <div>--</div>,
},
{
title: '选择方式',
align: 'center',
dataIndex: 'chooseType',
render: () => <div>--</div>,
},
{
title: '是否必选',
align: 'center',
dataIndex: 'must',
render: () => <div>--</div>,
},
{
title: '规格单位',
align: 'center',
dataIndex: 'skuUnitId',
render: () => {
return <div>--</div>;
},
},
{
title: '操作',
align: 'center',
width: '20%',
render: () => {
return (
<div>
<Button type='link' style={{ marginRight: '10px' }}>
编辑
</Button>
<Button type='link'>删除</Button>
</div>
);
},
},
];
return (
<div className='stock-sku'>
<div className='stock-sku-title'>库存规格</div>
<div className='stock-sku-content'>
<div className='stock-sku-operate'>
<Button icon={<PlusOutlined />} type='primary'>
添加规格
</Button>
</div>
<Table size='small' bordered rowKey='id' pagination={false} columns={columns} />
</div>
</div>
);
};
export default StockSku;
.rent-info {
.goods-info {
&-operate {
margin-top: 50px;
display: flex;
......
import SearchBox, { searchColumns } from '~/components/search-box';
import React, { useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { useState } from 'react';
import { Button, Card, Table } from 'antd';
import { Button, Card, Image, message, Table } from 'antd';
import {
ArrowDownOutlined,
ArrowUpOutlined,
......@@ -9,6 +9,16 @@ import {
PlusOutlined,
} from '@ant-design/icons';
import { ColumnsType } from 'antd/es/table';
import GoodsAPI from '~/api/modules/goodsAPI';
import { InterDataType, InterReqType, PaginationProps } from '~/api/interface';
import { listGoodsType } from '~/api/interface/goodsType';
import { CategoryManageAPI } from '~/api';
import { filterObjAttr } from '~/utils';
//商品返回类型
type goodsType = InterDataType<listGoodsType>['list'];
//商品列表筛选类型
type goodsSearchParameters = Omit<InterReqType<listGoodsType>, 'pageNo' | 'pageSize' | 'goodsType'>;
const RentList = () => {
const navigate = useNavigate();
const tabList = [
......@@ -26,56 +36,175 @@ const RentList = () => {
},
];
const [activeTabKey, setActiveTabKey] = useState<string>('1');
const [searchColumns] = useState<searchColumns[]>([
const [searchColumns, setSearchColumns] = useState<searchColumns[]>([
{
label: '商品名称',
placeholder: '请输入商品名称',
name: '',
name: 'goodsName',
type: 'input',
},
{
label: '所属目录',
placeholder: '请选择所属目录',
name: '',
name: 'directoryId',
type: 'select',
options: [],
},
{
label: '创建时间',
placeholder: '请输入选择创建时间',
name: '',
name: 'time',
type: 'rangePicker',
},
]);
const tableColumns: ColumnsType<any> = [
{ title: '序号', align: 'center' },
{ title: '图片', align: 'center' },
{ title: '商品名称', align: 'center' },
{ title: '所属目录', align: 'center' },
{ title: '创建时间', align: 'center' },
{ title: '状态', align: 'center' },
const tableColumns: ColumnsType<goodsType[0]> = [
{
title: '序号',
align: 'center',
render: (_text: any, _record, index: number) =>
(pagination.pageNo - 1) * pagination.pageSize + index + 1,
},
{
title: '图片',
align: 'center',
dataIndex: 'imgUrl',
render: (text: string) => <Image src={text} width={50} height={50} />,
},
{ title: '商品名称', align: 'center', dataIndex: 'goodsName' },
{ title: '所属目录', align: 'center', dataIndex: 'directoryName' },
{ title: '创建时间', align: 'center', dataIndex: 'createTime' },
{
title: '状态',
align: 'center',
dataIndex: 'status',
render: (text: number) => (text ? '上架' : '下架'),
},
{
title: '操作',
align: 'center',
render: () => (
dataIndex: 'id',
render: (id: number) => (
<>
<Button type='link'>编辑</Button>
<Button type='link'>详情</Button>
<Button type='link' onClick={() => toEditGoods(id)}>
编辑
</Button>
<Button type='link' onClick={() => toRentGoodsDetail(id)}>
详情
</Button>
</>
),
},
];
const [tableData] = useState<{ id: number }[]>([{ id: 1 }]);
const [tableData, setTableData] = useState<goodsType>([]);
//分页
const [pagination, setPagination] = useState<PaginationProps & { totalCount: number }>({
pageNo: 1,
pageSize: 10,
totalCount: 0,
});
//筛选
const [query, setQuery] = useState<goodsSearchParameters>({ status: undefined });
// 表格多选
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
const onTabChange = (key: string) => {
pagination.pageNo = 1;
query.status = key === '1' ? undefined : key === '2' ? 1 : 0;
getGoodsList(query);
setQuery(query);
setActiveTabKey(key);
};
//新增租赁商品
const paginationChange = (pageNo: number, pageSize: number) => {
pagination.pageSize = pageSize;
pagination.pageNo = pageNo;
getGoodsList(query);
};
//筛选
const searchSuccess = (data: any) => {
pagination.pageNo = 1;
setQuery(filterObjAttr(data, ['time']));
getGoodsList(filterObjAttr(data, ['time']));
};
//商品列表
const getGoodsList = (query?: goodsSearchParameters) => {
GoodsAPI.getGoodsList({
pageNo: pagination.pageNo,
pageSize: pagination.pageSize,
goodsType: 1,
...query,
}).then(({ result }) => {
setTableData(result.list || []);
pagination.totalCount = result.totalCount;
setPagination(pagination);
});
};
//新增商品
const toAddRentGoods = () => {
navigate({ pathname: '/mallManage/rentGoods/add' });
};
//编辑商品
const toEditGoods = (id: number) => {
navigate({
pathname: '/mallManage/rentGoods/edit',
search: `id=${id}`,
});
};
//商品详情
const toRentGoodsDetail = (id: number) => {
navigate({
pathname: '/mallManage/rentGoods/detail',
search: `id=${id}&isDetail=1`,
});
};
// 表格多选事件
const onSelectChange = (newSelectedRowKeys: React.Key[]) => {
setSelectedRowKeys(newSelectedRowKeys);
};
//获取目录列表
const getDirectoryList = () => {
CategoryManageAPI.getDirectoryListClone({ type: 4 }).then(({ result }) => {
if (result) {
const options = result.map((v) => ({ id: v.id, name: v.directoryName }));
searchColumns[1].options = options;
setSearchColumns(searchColumns);
}
});
};
//商品-批量上下架
const batchOnShelfOrTakeDown = (status: number) => {
if (selectedRowKeys.length === 0) {
return message.warning('请先选择商品');
}
GoodsAPI.batchOnShelfOrTakeDown({ goodsIds: selectedRowKeys as number[], status }).then(
({ code }) => {
if (code === '200') {
message.success(status ? '上架成功' : '下架成功');
getGoodsList(query);
}
},
);
};
//商品-删除
const deleteGoods = () => {
if (selectedRowKeys.length === 0) {
return message.warning('请先选择商品');
}
GoodsAPI.batchRemoveWareInfo(selectedRowKeys as number[]).then(({ code }) => {
if (code === '200') {
if (pagination.pageNo !== 1 && tableData.length == 1) {
pagination.pageNo -= 1;
}
message.success('删除成功');
getGoodsList(query);
}
});
};
useEffect(() => {
getGoodsList();
getDirectoryList();
}, []);
return (
<div className='rent-list'>
<div className='goods-list'>
<SearchBox
search={searchColumns}
child={
......@@ -83,20 +212,54 @@ const RentList = () => {
新增商品
</Button>
}
searchData={searchSuccess}
/>
<Card tabList={tabList} activeTabKey={activeTabKey} onTabChange={onTabChange}>
<div className='header-operate' style={{ marginBottom: '10px' }}>
<Button type='primary' style={{ marginRight: '10px' }} icon={<ArrowUpOutlined />}>
{activeTabKey !== '2' && (
<Button
type='primary'
style={{ marginRight: '10px' }}
icon={<ArrowUpOutlined />}
onClick={() => batchOnShelfOrTakeDown(1)}
>
上架
</Button>
<Button type='primary' style={{ marginRight: '10px' }} icon={<ArrowDownOutlined />}>
)}
{activeTabKey !== '3' && (
<Button
type='primary'
style={{ marginRight: '10px' }}
icon={<ArrowDownOutlined />}
onClick={() => batchOnShelfOrTakeDown(0)}
>
下架
</Button>
<Button danger icon={<DeleteOutlined />}>
)}
<Button danger icon={<DeleteOutlined />} onClick={deleteGoods}>
删除
</Button>
</div>
<Table columns={tableColumns} bordered dataSource={tableData} />
<Table
columns={tableColumns}
bordered
dataSource={tableData}
rowKey='id'
rowSelection={{
selectedRowKeys,
onChange: onSelectChange,
}}
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} 条数据`,
}}
/>
</Card>
</div>
);
......
......@@ -285,6 +285,26 @@ export const routerList: Array<RouteObjectType> = [
},
},
{
path: '/mallManage/rentGoods/edit',
element: withLoadingComponent(<RentAddOrEditOrDetailView />),
meta: {
id: 10136,
icon: <SmileOutlined />,
title: '租赁商品编辑',
hidden: true,
},
},
{
path: '/mallManage/rentGoods/detail',
element: withLoadingComponent(<RentAddOrEditOrDetailView />),
meta: {
id: 10136,
icon: <SmileOutlined />,
title: '租赁商品详情',
hidden: true,
},
},
{
path: '/mallManage/mallGoods',
element: withLoadingComponent(<MallGoodsView />),
meta: {
......@@ -314,6 +334,16 @@ export const routerList: Array<RouteObjectType> = [
},
},
{
path: '/mallManage/mallGoods/detail',
element: withLoadingComponent(<MallAddOrEditOrDetailView />),
meta: {
id: 10146,
icon: <SmileOutlined />,
title: '商城商品详情',
hidden: true,
},
},
{
path: '/mallManage/produceList',
element: withLoadingComponent(<ProduceListView />),
meta: {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论