提交 1e06d1bb 作者: 龚洪江

联调:商品联调

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