提交 196886f0 作者: 龚洪江

功能:租赁联调(100%)

上级 b26c4e6b
......@@ -177,5 +177,4 @@ type locationType = {
level: number;
childInfo: locationType[];
};
export type getSecondDistrictInfoType = InterFunction<any, locationType[]>;
......@@ -93,8 +93,6 @@ export type detailGoodsType = InterFunction<
id: number;
}
>;
//商品-其它服务列表
export type otherServiceType = InterFunction<any, { id: number; saleServiceName: string }[]>;
//商品-规格单位
export type skuUnitType = InterFunction<any, { id: number; unitName: string }[]>;
//商品-批量上下架
......
......@@ -48,22 +48,22 @@ export type addRentGoodsType = InterFunction<
deviceModeId: number;
leasePartsList: { name: string; number: number; price: number }[];
level: number;
logisticsCompany: number;
logisticsCompany: string;
maxLeaseTerm: number;
minLeaseTerm: number;
modeOfDelivery: number;
priceStock: {
cashPledge: number;
maxDaysRental: number;
ninetyDaysRental: number;
maxDaysRental?: number;
ninetyDaysRental?: number;
productSpec: string;
sevenDaysRental: number;
showPrice: number;
skuImage: string;
stock: number;
sevenDaysRental?: number;
showPrice?: number;
skuImage?: string;
stock?: number;
stockOut: number;
thirtyDaysRental: number;
threeDaysRental: number;
thirtyDaysRental?: number;
threeDaysRental?: number;
}[];
productDetails: string;
productParam: string;
......@@ -78,5 +78,108 @@ export type addRentGoodsType = InterFunction<
},
any
>;
//租赁商品-列表
type rentGoodsType = {
brandInfoId: number;
deviceModeId: number;
leasePartsList: { id: number; name: string; number: number; price: number }[];
level: number;
logisticsCompany: string;
maxLeaseTerm: number;
minLeaseTerm: number;
modeOfDelivery: number;
priceStock: {
cashPledge: number;
maxDaysRental?: number;
ninetyDaysRental?: number;
productSpec: string;
sevenDaysRental?: number;
showPrice?: number;
skuImage?: string;
stock?: number;
stockOut: number;
thirtyDaysRental?: number;
threeDaysRental?: number;
id: number;
}[];
productDetails: string;
productParam: string;
productTypeId: number;
resourcesList: { id: number; type: number; url: string }[];
returnAddress: number;
sellingPoint: string;
shelfStatus: number;
shipAddress: number;
tradeName: string;
specAttrList: {
id: number;
specName: string;
specValuesList: { specName: string; id: number }[];
}[];
id: number;
createTime: string;
};
export type leaseGoodsListType = InterItemFunction<
{
brandInfoId?: number;
districtCode?: number;
productTypeId?: number;
shelfStatus?: number;
tradeName?: string;
},
rentGoodsType[]
>;
//租赁-商品-编辑
export type editLeaseGoodsType = InterFunction<
{
brandInfoId: number;
deviceModeId: number;
leasePartsList: { id?: number; name: string; number: number; price: number }[];
level: number;
logisticsCompany: string;
maxLeaseTerm: number;
minLeaseTerm: number;
modeOfDelivery: number;
priceStock: {
cashPledge: number;
maxDaysRental?: number;
ninetyDaysRental?: number;
productSpec: string;
sevenDaysRental?: number;
showPrice?: number;
skuImage?: string;
stock?: number;
stockOut: number;
thirtyDaysRental?: number;
threeDaysRental?: number;
id?: number;
}[];
productDetails: string;
productParam: string;
productTypeId: number;
resourcesList: { type: number; url: string }[];
returnAddress: number;
sellingPoint: string;
shelfStatus: number;
shipAddress: number;
tradeName: string;
specAttrList: {
id: number;
specName: string;
specValuesList: { id: number; specName: string }[];
}[];
id: number;
},
any
>;
//租赁-商品-详情
export type leaseGoodsDetailsType = InterFunction<{ id: number }, rentGoodsType>;
//租赁-商品-租期信息
export type leaseTermInfoType = InterFunction<any, { id: number; leaseDate: string }[]>;
//租赁-商品-物流-配送方式
export type otherServiceType = InterFunction<any, { id: number; saleServiceName: string }[]>;
//租赁-商品-上下架-批量
export type batchOnShelfOrTakeDownType = InterFunction<{ goodsIds: number[]; status: number }, any>;
//租赁-商品-删除-批量
export type batchRemoveWareInfoType = InterFunction<number[], any>;
......@@ -299,3 +299,44 @@ export type listMenuInfoType = InterFunction<any, menType>;
export type listRoleMenuInfoType = InterFunction<{ roleId: number }, any>;
//账号权限-修改角色菜单权限
export type updateRoleMenuInfoType = InterFunction<{ menuInfoIds: number[]; roleId: number }, any>;
//地址管理-列表
export type addressListType = InterFunction<
any,
{
takeAddress: string;
takeName: string;
takePhone: string;
takeRegion: string;
type: number;
id: number;
districtCode: string;
}[]
>;
//地址管理-添加地址
export type addressInsetType = InterFunction<
{
takeAddress: string;
takeName: string;
takePhone: string;
takeRegion: string;
type: number;
districtCode: string;
},
any
>;
//地址管理-编辑地址
export type editAddressType = InterFunction<
{
id?: number;
takeAddress: string;
takeName: string;
takePhone: string;
takeRegion: string;
type: number;
districtCode: string;
},
any
>;
//地址管理-删除地址
export type deleteAddressType = InterFunction<{ id: number }, any>;
......@@ -10,7 +10,6 @@ import {
listGoodsType,
listPageGoodsInfoType,
mallGoodsDetailsType,
otherServiceType,
removeMallGoodsType,
skuUnitType,
upOrDownShelfType,
......@@ -38,10 +37,6 @@ class GoodsAPI {
static getSkuUnit: skuUnitType = () => {
return axios.get('/pms/mall/goods/getSkuUnit');
};
// 商品-其它服务列表
static getOtherServiceList: otherServiceType = () => {
return axios.get('/pms/goods/listOtherService');
};
// 商品-批量上下架
static batchOnShelfOrTakeDown: batchOnShelfOrTakeDownType = (data) => {
return axios.post('/pms/goods/batchOnShelfOrTakeDown', data);
......
......@@ -2,16 +2,22 @@ import {
addRentGoodsType,
addRentModeType,
addType,
batchRemoveWareInfoType,
editBrandInfoType,
editLeaseGoodsType,
getTypeListType,
leaseGoodsDetailsType,
leaseGoodsListType,
leaseTermInfoType,
listBrandInfoType,
otherServiceType,
rentMakeAddType,
rentModeListType,
rentTypeEditType,
rentTypeRemoveType,
} from '~/api/interface/rentManageType';
import axios from '../request';
import { batchOnShelfOrTakeDownType } from '~/api/interface/goodsType';
export class RentManageAPI {
//租赁-类型-新增
......@@ -43,7 +49,26 @@ export class RentManageAPI {
// 租赁-商品-新增
static addRentGoods: addRentGoodsType = (data) =>
axios.post('/pms/lease/goods/addLeaseGoods', data);
//租赁-商品-列表
static getLeaseGoodsList: leaseGoodsListType = (data) =>
axios.post('/pms/lease/goods/leaseGoodsList', data);
//租赁-商品-编辑
static editLeaseGoods: editLeaseGoodsType = (data) =>
axios.post('/pms/lease/goods/editLeaseGoods', data);
//租赁-商品-详情
static getLeaseGoodsDetails: leaseGoodsDetailsType = (params) =>
axios.get('/pms/lease/goods/leaseGoodsDetails', { params });
// 租赁-商品-租期信息
static getLeaseTermInfo: leaseTermInfoType = () =>
axios.post('/pms/lease/goods/getLeaseTermInfo');
//租赁-商品-上下架-批量
static batchOnShelfOrTakeDown: batchOnShelfOrTakeDownType = (data) =>
axios.post('/pms/lease/goods/batchOnShelfOrTakeDown', data);
////租赁-商品-删除-批量
static batchRemoveWareInfo: batchRemoveWareInfoType = (data) =>
axios.post('/pms/lease/goods/batchRemoveWareInfo', data);
// 商品-其它服务列表
static getOtherServiceList: otherServiceType = () => {
return axios.get('/pms/goods/listOtherService');
};
}
import {
addressInsetType,
addressListType,
bindingCompanyMemberType,
deleteAddressType,
deleteRoleInfoType,
editAddressType,
getCompanyInfoByIdType,
getSecondDistrictInfo,
insertBAccountType,
......@@ -104,4 +108,15 @@ export class SystemManageAPI {
//账号权限-修改角色菜单权限
static updateRoleMenuInfo: updateRoleMenuInfoType = (data) =>
axios.post('/userapp/role/updateRoleMenuInfo', data);
// 地址管理-新增
static addressInset: addressInsetType = (data) => axios.post('/oms/user-address/insert', data);
// 地址管理-列表
static getAddressList: addressListType = (data) =>
axios.post('/oms/user-address/selectList', data);
// 地址管理-编辑
static editAddress: editAddressType = (data) => axios.post('/oms/user-address/update', data);
// 地址管理-删除
static deleteAddress: deleteAddressType = (params) =>
axios.get('/oms/user-address/deleteById', { params });
}
import { Form, InputNumber, Input, Select, Radio } from 'antd';
import { Form, InputNumber, Input, Select, Radio, Switch } from 'antd';
import React from 'react';
import { Uploader } from '~/components/uploader';
import { UploadOutlined } from '@ant-design/icons';
......@@ -8,7 +8,7 @@ export interface EditableCellProps extends React.HTMLAttributes<HTMLElement> {
editing: boolean;
dataIndex: string;
title: any;
inputType: 'number' | 'text' | 'select' | 'uploader' | 'radio' | 'textArea';
inputType: 'number' | 'text' | 'select' | 'uploader' | 'radio' | 'textArea' | 'switch';
record: any;
index: number;
children: React.ReactNode;
......@@ -82,6 +82,8 @@ const EditableCell: React.FC<
showCount
/>
);
case 'switch':
return <Switch />;
default:
return <Input placeholder={`请输入${placeholder || title}`} maxLength={maxLength} />;
}
......
.accessory-list{
&-title{
font-size: 15px;
font-weight: bold;
line-height: 40px;
}
}
import './index.scss';
import { Button, Col, Form, Row, Table } from 'antd';
import { forwardRef, useEffect, useImperativeHandle, useState } from 'react';
import { InterDataType, InterReqType } from '~/api/interface';
import { addRentGoodsType, leaseGoodsDetailsType } from '~/api/interface/rentManageType';
import EditableCell from '~/components/EditableCell';
import { MinusOutlined, PlusOutlined } from '@ant-design/icons';
//租赁商品详情返回类型
type rentGoodsDetailType = InterDataType<leaseGoodsDetailsType>;
//租赁-清单类型
type leasePartsListType = Exclude<
InterReqType<addRentGoodsType>,
undefined
>['leasePartsList'][0] & { id?: number };
type EditableTableProps = Parameters<typeof Table>[0];
type ColumnTypes = Exclude<EditableTableProps['columns'], undefined>;
interface selfProps {
ref: any;
rentGoodsDetails: rentGoodsDetailType | undefined;
}
const AccessoryList = forwardRef<any, selfProps>(({ rentGoodsDetails }, ref) => {
const [accessoryTableForm] = Form.useForm<{ [x: string]: string | number }>();
const accessoryTableDefaultColumns: (ColumnTypes[number] & {
editable?: boolean;
dataIndex?: string;
inputType?: string;
rules?: any;
maxLength?: number;
})[] = [
{
title: '序号',
align: 'center',
render: (_: any, _record: any, index: number) => index + 1,
},
{
title: '名称',
editable: true,
dataIndex: 'name',
align: 'center',
},
{
title: '数量',
editable: true,
dataIndex: 'number',
align: 'center',
inputType: 'number',
},
{
title: '参考价格',
editable: true,
dataIndex: 'price',
align: 'center',
inputType: 'number',
},
{
title: '操作',
align: 'center',
render: (_: any, _record: any, index: number) => (
<>
{index === accessoryTableData.length - 1 ? (
<Button
type='primary'
icon={<PlusOutlined />}
style={{ marginRight: '5px' }}
onClick={addAccessoryTableClick}
></Button>
) : (
''
)}
{index ? (
<Button
type='primary'
icon={<MinusOutlined />}
onClick={() => deleteAccessoryTableClick(index)}
></Button>
) : (
''
)}
</>
),
},
];
const accessoryTableColumns = accessoryTableDefaultColumns.map((col) => {
if (!col.editable) {
return col;
}
return {
...col,
onCell: (record: any) => ({
record,
dataIndex: col.dataIndex,
title: col.title,
editing: col.editable,
inputType: col.inputType,
rules: col.rules,
}),
};
});
const [accessoryTableData, setAccessoryTableData] = useState<leasePartsListType[]>([
{ id: Math.random(), name: '', number: 0, price: 0 },
]);
useImperativeHandle(ref, () => ({
accessoryTableFormSubmit,
}));
//新加一行
const addAccessoryTableClick = () => {
setAccessoryTableData([
...accessoryTableData,
{ id: Math.random(), name: '', number: 0, price: 0 },
]);
};
//删除一行
const deleteAccessoryTableClick = (index: number) => {
accessoryTableData.splice(index, 1);
setAccessoryTableData([...accessoryTableData]);
};
//配件清单表单提交
const accessoryTableFormSubmit = () => {
return new Promise((resolve, reject) => {
accessoryTableForm
.validateFields()
.then((value: any) => {
resolve(
accessoryTableData.reduce((pre: leasePartsListType[], cur) => {
if (value['name' + cur.id] || value['price' + cur.id] || value['number' + cur.id]) {
pre.push({
name: value['name' + cur.id],
price: value['price' + cur.id],
number: value['number' + cur.id],
id: rentGoodsDetails
? rentGoodsDetails.leasePartsList.some((v) => v.id === cur.id)
? cur.id
: undefined
: undefined,
});
}
return pre;
}, []),
);
})
.catch((err) => {
reject(err);
});
});
};
useEffect(() => {
if (rentGoodsDetails) {
if (rentGoodsDetails.leasePartsList) {
setAccessoryTableData(rentGoodsDetails.leasePartsList);
const defaultFormValue: { [x: string]: string | undefined | number } =
rentGoodsDetails.leasePartsList.reduce(
(pre: { [x: string]: string | undefined | number }, cur) => {
pre['name' + cur.id] = cur.name || undefined;
pre['number' + cur.id] = cur.number || undefined;
pre['price' + cur.id] = cur.price || undefined;
return pre;
},
{},
);
accessoryTableForm.setFieldsValue(defaultFormValue);
}
}
}, [rentGoodsDetails]);
return (
<div className='accessory-list'>
<div className='accessory-list-title'>配件清单</div>
<Row>
<Col span={2}></Col>
<Col span={11}>
<Form form={accessoryTableForm}>
<Table
columns={accessoryTableColumns as ColumnTypes}
bordered
dataSource={accessoryTableData}
rowKey='id'
pagination={false}
components={{
body: {
cell: EditableCell,
},
}}
/>
</Form>
</Col>
</Row>
</div>
);
});
export default AccessoryList;
import './index.scss';
import { Form, Radio, Select } from 'antd';
import { Button, Col, Form, Radio, Row, Select } from 'antd';
import { OrderManageAPI, RentManageAPI, SystemManageAPI } from '~/api';
import { forwardRef, useEffect, useImperativeHandle, useState } from 'react';
import { PlusOutlined } from '@ant-design/icons';
import AddOrEditAddressModal from '~/pages/systemManage/addressManage/components/addOrEditAddressModal';
import { InterDataType } from '~/api/interface';
import { leaseGoodsDetailsType } from '~/api/interface/rentManageType';
const AddressInfo = () => {
//租赁商品详情返回类型
type rentGoodsDetailType = InterDataType<leaseGoodsDetailsType>;
interface selfProps {
ref: any;
rentGoodsDetails: rentGoodsDetailType | undefined;
}
const AddressInfo = forwardRef<any, selfProps>(({ rentGoodsDetails }, ref) => {
const [addressInfoForm] = Form.useForm<{
shipAddress: number;
returnAddress: number;
logisticsCompany: string;
modeOfDelivery: number;
}>();
const [addOrEditAddressModalShow, setAddOrEditAddressModalShow] = useState<boolean>(false);
const [addressOptionList, setAddressOptionList] = useState<
{ label: string; value: number; districtCode: string }[]
>([]);
const [expressOptionList, setExpressOptionList] = useState<{ label: string; value: string }[]>(
[],
);
//配送方式
const [shippingMethodList, setShippingMethodList] = useState<
{ id: number; saleServiceName: string }[]
>([]);
useImperativeHandle(ref, () => ({
addressInfoFormSubmit,
}));
//地址列表
const getAddressList = () => {
SystemManageAPI.getAddressList({}).then(({ result }) => {
if (result) {
const optionList = result.map((v) => ({
label: v.takeName + v.takePhone + `(${v.takeRegion.split('/').join('') + v.takeAddress})`,
value: v.id,
districtCode: v.districtCode,
}));
const addressItemObj = result.find((v) => v.type === 1);
if (addressItemObj) {
addressInfoForm.setFieldsValue({
returnAddress: addressItemObj.id,
shipAddress: addressItemObj.id,
});
}
setAddressOptionList(optionList);
}
});
};
//物流公司列表
const getListExpressInfo = () => {
OrderManageAPI.listExpressInfo().then(({ result }) => {
if (result) {
const optionList = result.map((v) => ({
label: v.exName,
value: v.exCode,
}));
setExpressOptionList(optionList);
}
});
};
//物流-配送方式
const getOtherService = () => {
RentManageAPI.getOtherServiceList().then(({ result }) => {
setShippingMethodList(result || []);
});
};
//物流表单提交
const addressInfoFormSubmit = () => {
return new Promise((resolve, reject) => {
addressInfoForm
.validateFields()
.then((values) => {
resolve({
...values,
districtCode: addressOptionList.find((v) => v.value === values.shipAddress)
?.districtCode,
});
})
.then((err) => {
reject(err);
});
});
};
//新增地址弹窗
const addAddressClick = () => [setAddOrEditAddressModalShow(true)];
const addOrEditAddressModalOk = () => {
getAddressList();
setAddOrEditAddressModalShow(false);
};
const addOrEditAddressModalCancel = () => {
setAddOrEditAddressModalShow(false);
};
useEffect(() => {
getAddressList();
getListExpressInfo();
getOtherService();
}, []);
useEffect(() => {
if (rentGoodsDetails) {
addressInfoForm.setFieldsValue({
shipAddress: rentGoodsDetails.shipAddress,
returnAddress: rentGoodsDetails.returnAddress,
logisticsCompany: rentGoodsDetails.logisticsCompany,
modeOfDelivery: rentGoodsDetails.modeOfDelivery,
});
}
}, [rentGoodsDetails]);
return (
<div className='address-info'>
<div className='address-info-title'>物流信息</div>
<Form labelCol={{ span: 2 }} wrapperCol={{ span: 10 }}>
<Form.Item label='发货地址'>
<Select placeholder='请选择发货地址'>
<Select.Option>1</Select.Option>
</Select>
<Form labelCol={{ span: 2 }} wrapperCol={{ span: 10 }} form={addressInfoForm}>
<Form.Item
label='发货地址'
name='shipAddress'
rules={[{ required: true, message: '请选择发货地址' }]}
>
<Select placeholder='请选择发货地址' options={addressOptionList}></Select>
</Form.Item>
<Form.Item label='归还地址'>
<Select placeholder='请选择归还地址'>
<Select.Option>1</Select.Option>
</Select>
<Form.Item>
<Row>
<Col span={5}></Col>
<Col>
<Button type='link' icon={<PlusOutlined />} onClick={addAddressClick}>
新增地址
</Button>
</Col>
</Row>
</Form.Item>
<Form.Item
label='归还地址'
name='returnAddress'
rules={[{ required: true, message: '请选择归还地址' }]}
>
<Select placeholder='请选择归还地址' options={addressOptionList}></Select>
</Form.Item>
<Form.Item label='寄出物流'>
<Select placeholder='请选择寄出物流'>
<Select.Option>1</Select.Option>
</Select>
<Form.Item>
<Row>
<Col span={5}></Col>
<Col>
<Button type='link' icon={<PlusOutlined />} onClick={addAddressClick}>
新增地址
</Button>
</Col>
</Row>
</Form.Item>
<Form.Item label='寄出物流'>
<Select placeholder='请选择寄出物流'>
<Select.Option>1</Select.Option>
</Select>
<Form.Item
label='寄出物流'
name='logisticsCompany'
rules={[{ required: true, message: '请选择寄出物流' }]}
>
<Select placeholder='请选择寄出物流' options={expressOptionList}></Select>
</Form.Item>
<Form.Item label='配送方式(寄出)'>
<Form.Item
label='配送方式(寄出)'
name='modeOfDelivery'
rules={[{ required: true, message: '请选择配送方式(寄出)' }]}
>
<Radio.Group>
<Radio>包邮</Radio>
<Radio>到付(租户支付)</Radio>
{shippingMethodList.map((v) => (
<Radio value={v.id} key={v.id}>
{v.saleServiceName}
</Radio>
))}
</Radio.Group>
</Form.Item>
</Form>
<AddOrEditAddressModal
open={addOrEditAddressModalShow}
onOk={addOrEditAddressModalOk}
onCancel={addOrEditAddressModalCancel}
/>
</div>
);
};
});
export default AddressInfo;
.rent-footer-operate{
background: #fff;
height: 70px;
position: fixed;
bottom: 10px;
left: 180px;
right: 10px;
box-shadow: 0 -5px 1px -5px rgba(0,0,0,0.5);
display: flex;
align-items: center;
justify-content: center;
button{
height: 40px;
width: 80px;
&:first-child{
margin-right: 50px;
}
}
}
import './index.scss';
import { Button } from 'antd';
import { useNavigate } from 'react-router-dom';
import { FC } from 'react';
interface selfProps {
saveRentGoods: () => void;
}
const FooterOperate: FC<selfProps> = ({ saveRentGoods }) => {
const navigate = useNavigate();
//返回
const backRoute = () => {
navigate(-1);
};
return (
<div className='rent-footer-operate'>
<Button onClick={backRoute}>返回</Button>
<Button type='primary' onClick={saveRentGoods}>
保存
</Button>
</div>
);
};
export default FooterOperate;
import { Form, Input, Radio } from 'antd';
import './index.scss';
import { forwardRef, useEffect, useImperativeHandle } from 'react';
import { InterDataType } from '~/api/interface';
import { leaseGoodsDetailsType } from '~/api/interface/rentManageType';
//租赁商品详情返回类型
type rentGoodsDetailType = InterDataType<leaseGoodsDetailsType>;
type goodsInfoForm = {
tradeName: string;
sellingPoint: string;
level: number;
shelfStatus: number;
};
interface selfProps {
ref: any;
rentGoodsDetails: rentGoodsDetailType | undefined;
}
const GoodsInfo = () => {
const GoodsInfo = forwardRef<any, selfProps>(({ rentGoodsDetails }, ref) => {
const qualityList = [
{
label: '全新',
......@@ -33,13 +42,41 @@ const GoodsInfo = () => {
];
const [form] = Form.useForm<goodsInfoForm>();
useImperativeHandle(ref, () => ({
submitGoodsInfoForm,
}));
const submitGoodsInfoForm = () => {
return new Promise((resolve, reject) => {
form
.validateFields()
.then((value) => {
resolve(value);
})
.catch((error) => {
reject(error);
});
});
};
useEffect(() => {
if (rentGoodsDetails) {
form.setFieldsValue({
tradeName: rentGoodsDetails.tradeName,
sellingPoint: rentGoodsDetails.sellingPoint,
level: rentGoodsDetails.level,
shelfStatus: rentGoodsDetails.shelfStatus,
});
}
}, [rentGoodsDetails]);
return (
<div className='goods-info'>
<div className='goods-info-title'>商品信息</div>
<Form
labelCol={{ span: 2 }}
wrapperCol={{ span: 10 }}
initialValues={{ level: 0 }}
initialValues={{ level: 0, shelfStatus: 1 }}
form={form}
>
<Form.Item
......@@ -74,5 +111,5 @@ const GoodsInfo = () => {
</Form>
</div>
);
};
});
export default GoodsInfo;
......@@ -4,4 +4,14 @@
font-weight: bold;
line-height: 40px;
}
.rent-goods-video-wrap{
position: relative;
width: 200px;
img{
position: absolute;
right: 0;
top: 0;
transform: translate(50%,-25%);
}
}
}
import './index.scss';
import { Button, Form, Select, Table } from 'antd';
import EditableCell from '~/components/EditableCell';
import { useEffect, useState } from 'react';
import React, { forwardRef, useEffect, useImperativeHandle, useState } from 'react';
import { MinusOutlined, PlusOutlined, UploadOutlined } from '@ant-design/icons';
import { Uploader } from '~/components/uploader';
import RichText from '~/components/richText';
import { RentManageAPI } from '../../../../../../api';
import deletePng from '~/assets/image/delete.png';
import { InterDataType } from '~/api/interface';
import { leaseGoodsDetailsType } from '~/api/interface/rentManageType';
//租赁商品详情返回类型
type rentGoodsDetailType = InterDataType<leaseGoodsDetailsType>;
type EditableTableProps = Parameters<typeof Table>[0];
type ColumnTypes = Exclude<EditableTableProps['columns'], undefined>;
......@@ -13,7 +19,8 @@ type RentAttrFormType = {
productTypeId: number;
brandInfoId: number;
deviceModeId: number;
goodsImage: string[];
mainImage: string;
subImage: string[];
goodsVideo: string;
productDetails: string;
};
......@@ -23,8 +30,12 @@ type productParamType = {
productParamName: string;
productParamValue: string;
};
interface selfProps {
ref: any;
rentGoodsDetails: rentGoodsDetailType | undefined;
}
const RentAttr = () => {
const RentAttr = forwardRef<any, selfProps>(({ rentGoodsDetails }, ref) => {
//商品属性表单
const [rentAttrForm] = Form.useForm<RentAttrFormType>();
//商品参数表单
......@@ -103,8 +114,17 @@ const RentAttr = () => {
const [brandInfoList, setBrandInfoList] = useState<{ label: string; value: number }[]>([]);
//型号下拉列表
const [modeTypeList, setModeTypeList] = useState<{ label: string; value: number }[]>([]);
//商品图片文件列表
const [imgFileList, setImgFileList] = useState<
//商品主图文件列表
const [mainImgFileList, setMainImgFileList] = useState<
{
id: number;
name: string;
uid: number;
url: string;
}[]
>([]);
//商品副图文件列表
const [subImgFileList, setSubImgFileList] = useState<
{
id: number;
name: string;
......@@ -112,6 +132,7 @@ const RentAttr = () => {
url: string;
}[]
>([]);
//商品视频文件列表
const [videoFileList, setVideoFileList] = useState<
{
......@@ -122,6 +143,10 @@ const RentAttr = () => {
}[]
>([]);
useImperativeHandle(ref, () => ({
submitAttrForm,
}));
//商品参数新增
const addParameterDataEvent = () => {
setParameterTableData([
......@@ -181,12 +206,22 @@ const RentAttr = () => {
uid: number;
url: string;
}[],
type: string,
) => {
rentAttrForm.setFieldValue(
'goodsImage',
value.map((v) => v.url),
);
setImgFileList(value);
switch (type) {
case 'mainImage':
rentAttrForm.setFieldValue('mainImage', value[0].url);
setMainImgFileList(value);
break;
case 'subImage':
rentAttrForm.setFieldValue(
'subImage',
value.map((v) => v.url),
);
setSubImgFileList(value);
break;
default:
}
};
//商品视频上传成功
const videoUploadSuccess = (
......@@ -200,6 +235,11 @@ const RentAttr = () => {
rentAttrForm.setFieldValue('goodsVideo', value[0].url);
setVideoFileList(value);
};
//商品视频删除
const deleteVideo = () => {
setVideoFileList([]);
};
//商品参数表单验证
const productParamFormSubmit = () => {
return new Promise((resolve, reject) => {
......@@ -209,8 +249,10 @@ const RentAttr = () => {
const productParamList = parameterTableData.reduce(
(pre: { [key: string]: string }[], cur) => {
const Obj = Object.create(null);
Obj[values['productParamName' + cur.id]] = values['productParamValue' + cur.id];
pre.push(Obj);
if (values['productParamName' + cur.id] && values['productParamValue' + cur.id]) {
Obj[values['productParamName' + cur.id]] = values['productParamValue' + cur.id];
pre.push(Obj);
}
return pre;
},
[],
......@@ -223,11 +265,79 @@ const RentAttr = () => {
});
};
const submitAttrForm = async () => {
try {
const values: any[] = await Promise.all([
rentAttrForm.validateFields(),
productParamFormSubmit(),
]);
return Promise.resolve({
...values[0],
productParam: values[1].length ? JSON.stringify(values[1]) : undefined,
});
} catch (e) {
return Promise.reject(e);
}
};
useEffect(() => {
getRentTypeList();
getRentMakeList();
}, []);
//编辑回显
useEffect(() => {
if (rentGoodsDetails) {
rentAttrForm.setFieldsValue({
productTypeId: rentGoodsDetails.productTypeId,
brandInfoId: rentGoodsDetails.brandInfoId,
deviceModeId: rentGoodsDetails.deviceModeId,
mainImage: rentGoodsDetails.resourcesList.filter((v) => v.type === 0)[0].url,
subImage: rentGoodsDetails.resourcesList.filter((v) => v.type === 1).length
? rentGoodsDetails.resourcesList.filter((v) => v.type === 1).map((v) => v.url)
: undefined,
goodsVideo: rentGoodsDetails.resourcesList.filter((v) => v.type === 2).length
? rentGoodsDetails.resourcesList.filter((v) => v.type === 2)[0].url
: undefined,
});
getRentModelList(rentGoodsDetails.brandInfoId, rentGoodsDetails.productTypeId);
if (rentGoodsDetails.productParam) {
const tableData: productParamType[] = JSON.parse(rentGoodsDetails.productParam).map(
(v: { [x: string]: string }) => ({
productParamName: Object.getOwnPropertyNames(v)[0],
productParamValue: v[Object.getOwnPropertyNames(v)[0]],
id: Math.random(),
}),
);
setParameterTableData(tableData);
const defaultFormValue: { [x: string]: string } = tableData.reduce(
(pre: { [x: string]: string }, cur) => {
pre['productParamName' + cur.id] = cur.productParamName;
pre['productParamValue' + cur.id] = cur.productParamValue;
return pre;
},
{},
);
productParamForm.setFieldsValue(defaultFormValue);
}
setMainImgFileList(
rentGoodsDetails.resourcesList
.filter((v) => v.type === 0)
.map((v) => ({ id: Math.random(), uid: Math.random(), name: '主图', url: v.url })),
);
setSubImgFileList(
rentGoodsDetails.resourcesList
.filter((v) => v.type === 1)
.map((v) => ({ id: Math.random(), uid: Math.random(), name: '主图', url: v.url })),
);
setVideoFileList(
rentGoodsDetails.resourcesList
.filter((v) => v.type === 2)
.map((v) => ({ id: Math.random(), uid: Math.random(), name: '主图', url: v.url })),
);
}
}, [rentGoodsDetails]);
return (
<div className='rent-attr'>
<div className='rent-attr-title'>商品属性</div>
......@@ -278,42 +388,62 @@ const RentAttr = () => {
</Form>
</Form.Item>
<Form.Item
label='商品图片'
name='goodsImage'
rules={[{ required: true, message: '请选择商品图片' }]}
label='商品主图'
name='mainImage'
rules={[{ required: true, message: '请上传商品主图' }]}
>
<Uploader
fileUpload
listType='picture-card'
onChange={imgUploadSuccess}
defaultFileList={imgFileList}
fileSize={3}
fileLength={5}
onChange={(fileList) => imgUploadSuccess(fileList, 'mainImage')}
defaultFileList={mainImgFileList}
fileSize={2}
fileLength={1}
>
<UploadOutlined />
</Uploader>
</Form.Item>
<Form.Item label='商品视频' name='goodsVideo'>
<Form.Item label='商品副图' name='subImage'>
<Uploader
fileUpload
listType='picture-card'
onChange={videoUploadSuccess}
defaultFileList={videoFileList}
fileSize={30}
fileLength={1}
onChange={(fileList) => imgUploadSuccess(fileList, 'subImage')}
defaultFileList={subImgFileList}
fileSize={2}
fileLength={4}
>
<UploadOutlined />
</Uploader>
</Form.Item>
<Form.Item
label='商品详情页'
name='productDetails'
rules={[{ required: true, message: '请输入商品详情页' }]}
>
<RichText richTextContent='' />
<Form.Item label='商品视频' name='goodsVideo'>
{videoFileList.length ? (
<div className='rent-goods-video-wrap'>
<video
src={videoFileList[0].url}
style={{ width: '200px', height: '200px' }}
controls
/>
<img src={deletePng} alt='删除' onClick={deleteVideo} />
</div>
) : (
<Uploader
fileUpload
listType='picture-card'
onChange={videoUploadSuccess}
defaultFileList={videoFileList}
fileSize={30}
fileLength={1}
fileType={['video/mp4', 'video/avi', 'video/wmv', 'video/rmvb']}
>
<UploadOutlined />
</Uploader>
)}
</Form.Item>
<Form.Item label='商品详情页' name='productDetails'>
<RichText richTextContent={rentGoodsDetails?.productDetails} />
</Form.Item>
</Form>
</div>
);
};
});
export default RentAttr;
......@@ -3,18 +3,67 @@ import { Col, Form, Row, Select, Table } from 'antd';
import CommonSkuInfo from '~/components/goods/commonSkuInfo';
import { forwardRef, useEffect, useImperativeHandle, useRef, useState } from 'react';
import { RentManageAPI } from '~/api';
import { isEmptyBol, regPriceNumber } from '~/utils/validateUtils';
import { InterDataType, InterReqType } from '~/api/interface';
import { addRentGoodsType, leaseGoodsDetailsType } from '~/api/interface/rentManageType';
import { filterObjAttr } from '~/utils';
//租赁商品详情返回类型
type rentGoodsDetailType = InterDataType<leaseGoodsDetailsType>;
type EditableTableProps = Parameters<typeof Table>[0];
type ColumnTypes = Exclude<EditableTableProps['columns'], undefined>;
interface selfProps {
ref: any;
rentGoodsDetails: rentGoodsDetailType | undefined;
}
//规格表单数据类型
type specificationFormListType = {
optionList: { label: string; value: string }[];
id: number;
name: string;
addSpecificationValueShow: boolean;
specificationValueList: { name: string; id: number; specificationName: string }[];
};
//sku返回类型
type priceStockType = (Exclude<InterReqType<addRentGoodsType>, undefined>['priceStock'][0] & {
id: number;
})[];
const SkuInfo = forwardRef<any, selfProps>((_props, ref) => {
const SkuInfo = forwardRef<any, selfProps>(({ rentGoodsDetails }, ref) => {
const [form] = Form.useForm<{ minLeaseTerm: number; maxLeaseTerm: number }>();
const commonSkuInfoRef = useRef<any>();
//库存正则校验
const stockValidator = (_rules: any, value: number) => {
if (!isEmptyBol(value)) {
if (/^[+]{0,1}(\d+)$/.test(value.toString())) {
if (value > 99999999 || value < 0) {
return Promise.reject(new Error('库存最大为99999999且大于0'));
}
return Promise.resolve();
} else {
return Promise.reject(new Error('请输入正整数'));
}
} else {
return Promise.resolve();
}
};
//价格正则校验
const priceValidator = (_rules: any, value: number) => {
if (!isEmptyBol(value)) {
if (regPriceNumber(value.toString())) {
if (value > 99999999 || value < 0) {
return Promise.reject(new Error('价格最大为99999999且大于0'));
}
return Promise.resolve();
} else {
return Promise.reject(new Error('为整数且最多保留两位小数'));
}
} else {
return Promise.reject(new Error('请输入金额'));
}
};
const [defaultColumns, setDefaultColumns] = useState<
(ColumnTypes[number] & {
editable?: boolean;
......@@ -33,18 +82,42 @@ const SkuInfo = forwardRef<any, selfProps>((_props, ref) => {
children: [],
},
{
title: '押金',
title: '缺货',
align: 'center',
editable: true,
dataIndex: 'skuImage',
inputType: 'switch',
dataIndex: 'stockOut',
},
{
title: (
<div>
<span style={{ color: 'red' }}>*</span>
<span>押金</span>
</div>
),
align: 'center',
editable: true,
dataIndex: 'cashPledge',
width: '15%',
placeholder: '押金',
rules: [{ required: false, validator: priceValidator }],
},
{
title: '库存',
align: 'center',
editable: true,
dataIndex: 'stock',
width: '10%',
rules: [{ required: false, validator: stockValidator }],
},
]);
const [tableData, setTableData] = useState<any>([]);
const [tableData, setTableData] = useState<priceStockType>([]);
//全部租期下拉
const [allLeaseTermInfoList, setAllLeaseTermInfoList] = useState<
{
label: string;
value: number;
key: string;
}[]
>([]);
// 低租期下拉
......@@ -52,6 +125,7 @@ const SkuInfo = forwardRef<any, selfProps>((_props, ref) => {
{
label: string;
value: number;
key: string;
}[]
>([]);
//高租期下拉
......@@ -59,11 +133,13 @@ const SkuInfo = forwardRef<any, selfProps>((_props, ref) => {
{
label: string;
value: number;
key: string;
}[]
>([]);
useImperativeHandle(ref, () => ({
getForm: () => form,
skuFormSubmit,
}));
const updateTableData = (tableData: any) => {
......@@ -77,7 +153,17 @@ const SkuInfo = forwardRef<any, selfProps>((_props, ref) => {
const getLeaseTermInfo = () => {
RentManageAPI.getLeaseTermInfo().then(({ result }) => {
if (result) {
const optionList = result.map((v) => ({ label: v.leaseDate, value: v.id }));
const optionList = result.map((v, index) => ({
label: v.leaseDate,
value: v.id,
key: [
'threeDaysRental',
'sevenDaysRental',
'thirtyDaysRental',
'ninetyDaysRental',
'maxDaysRental',
][index],
}));
setLowLeaseTermInfoList(optionList);
setUpLeaseTermInfoList(optionList);
setAllLeaseTermInfoList(optionList);
......@@ -101,10 +187,18 @@ const SkuInfo = forwardRef<any, selfProps>((_props, ref) => {
setDefaultColumns(
defaultColumns.concat(
filterLeaseTermInfo.map((v) => ({
title: v.label,
title: (
<div>
<span style={{ color: 'red' }}>*</span>
<span>{v.label}</span>
</div>
),
align: 'center',
editable: true,
dataIndex: v.label,
dataIndex: v.key,
width: '15%',
placeholder: `${v.label}租金价格`,
rules: [{ required: false, validator: priceValidator }],
})),
),
);
......@@ -126,10 +220,18 @@ const SkuInfo = forwardRef<any, selfProps>((_props, ref) => {
setDefaultColumns(
defaultColumns.concat(
filterLeaseTermInfo.map((v) => ({
title: v.label,
title: (
<div>
<span style={{ color: 'red' }}>*</span>
<span>{v.label}</span>
</div>
),
align: 'center',
editable: true,
dataIndex: v.label,
dataIndex: v.key,
width: '15%',
placeholder: `${v.label}租金价格`,
rules: [{ required: false, validator: priceValidator }],
})),
),
);
......@@ -137,10 +239,209 @@ const SkuInfo = forwardRef<any, selfProps>((_props, ref) => {
}
};
const skuFormSubmit = async () => {
try {
const values: any[] = await Promise.all([
form.validateFields(),
commonSkuInfoRef.current.getSpecificationValueForm().validateFields(),
commonSkuInfoRef.current.getSpecificationForm().validateFields(),
]);
const specificationFormList: specificationFormListType[] =
commonSkuInfoRef.current.getSpecificationFormList();
const specificationFormItem = specificationFormList.find(
(v) => !v.specificationValueList.length,
);
if (specificationFormItem) {
return Promise.reject(`请为规格项${specificationFormItem.optionList[0].value}添加规格值`);
} else {
//规格项数据转化
const specAttrList = specificationFormList.map((v) => ({
specName: v.optionList[0].value,
id: rentGoodsDetails
? rentGoodsDetails.specAttrList.find((i) => i.id === v.id)?.id
: undefined,
specValuesList: v.specificationValueList.map((j) => ({
specName: j.name,
id: rentGoodsDetails
? rentGoodsDetails.specAttrList
.find((i) => i.id === v.id)
?.specValuesList.find((i) => i.id === j.id)?.id
: undefined,
})),
}));
//规格值数据转化
const priceStock: priceStockType = tableData.reduce((pre: priceStockType, cur: any) => {
//规格名,规格值组合类型
const productSpec = specificationFormList.reduce(
(a: { [x: string]: string }, b, currentIndex) => {
a[b.optionList[0].value] = cur['name' + (currentIndex + 1)];
return a;
},
{},
);
pre.push({
...Object.getOwnPropertyNames(values[1]).reduce((a: any, b) => {
if (b.includes(cur.id)) {
a[b.replace(cur.id, '')] = values[1][b];
}
return a;
}, {}),
productSpec: JSON.stringify(productSpec),
});
return pre;
}, []);
//获取租期内的最低价格
const rentDateMinPrice = priceStock
.reduce((pre: number[], cur: any) => {
[
'threeDaysRental',
'sevenDaysRental',
'thirtyDaysRental',
'ninetyDaysRental',
'maxDaysRental',
].map((key) => {
if (cur[key]) {
pre.push(Number(cur[key]));
}
});
return pre;
}, [])
.sort((a, b) => a - b)[0];
return Promise.resolve({
...values[0],
priceStock,
specAttrList,
showPrice: rentDateMinPrice,
});
}
} catch (e) {
return Promise.reject(e);
}
};
//表头拆分及合并列
const mergeTableRow = (filterSpecificationFormList: specificationFormListType[]) => {
const columns = filterSpecificationFormList.map((v, index) => ({
title: v.optionList[0].value,
dataIndex: 'name' + (index + 1),
align: 'center',
onCell: (_: any, i: number) => {
//合并列
if (index < filterSpecificationFormList.length - 1) {
const count: number = filterSpecificationFormList
.slice(index + 1, filterSpecificationFormList.length)
.reduce((pre: number, cur) => {
return pre * cur.specificationValueList.length;
}, 1);
return {
rowSpan: count !== 1 ? ((i + 1) % count === 1 ? count : 0) : 1,
};
} else {
return {
rowSpan: 1,
};
}
},
}));
defaultColumns[0].children = columns;
setDefaultColumns([...defaultColumns]);
};
//排列组合规格值表单默认数据
const setTableFormDefault = (tableDataList: any) => {
const tableFormDefault = tableDataList.reduce((pre: any, cur: any) => {
return {
...pre,
...Object.getOwnPropertyNames(filterObjAttr(cur, ['id'])).reduce((a: any, b) => {
a[b + cur.id] = cur[b];
return a;
}, {}),
};
}, {});
commonSkuInfoRef.current.getSpecificationValueForm().setFieldsValue(tableFormDefault);
};
useEffect(() => {
getLeaseTermInfo();
}, []);
useEffect(() => {
if (rentGoodsDetails) {
form.setFieldsValue({
minLeaseTerm: rentGoodsDetails.minLeaseTerm,
maxLeaseTerm: rentGoodsDetails.maxLeaseTerm,
});
//转化数据
const covertSpecAttrList = rentGoodsDetails.specAttrList.map((v, index) => ({
id: v.id,
name: 'specName' + index,
optionList: [{ label: v.specName, value: v.specName }],
specificationValueList: v.specValuesList.map((i) => ({
id: i.id,
name: i.specName,
specificationName: v.specName,
})),
addSpecificationValueShow: false,
}));
//规格项表单数据默认数据
const specFormDefault = rentGoodsDetails.specAttrList.reduce(
(pre: any, cur: any, currentIndex) => {
pre['specName' + currentIndex] = cur.specName;
return pre;
},
{},
);
commonSkuInfoRef.current.getSpecificationForm().setFieldsValue(specFormDefault);
commonSkuInfoRef.current.updateSpecificationFormList([...covertSpecAttrList]);
const upLeaseTermInfoIndex = allLeaseTermInfoList.findIndex(
(v) => v.value === rentGoodsDetails.maxLeaseTerm,
);
const lowLeaseTermInfoIndex = allLeaseTermInfoList.findIndex(
(v) => v.value === rentGoodsDetails.minLeaseTerm,
);
const filterLeaseTermInfo = allLeaseTermInfoList.slice(
lowLeaseTermInfoIndex,
upLeaseTermInfoIndex + 1,
);
const addColumnsList: any = filterLeaseTermInfo.map((v) => ({
title: (
<div>
<span style={{ color: 'red' }}>*</span>
<span>{v.label}</span>
</div>
),
align: 'center',
editable: true,
dataIndex: v.key,
width: '15%',
placeholder: `${v.label}租金价格`,
rules: [{ required: false, validator: priceValidator }],
}));
defaultColumns.push(...addColumnsList);
mergeTableRow(covertSpecAttrList);
const tableDataList: priceStockType = rentGoodsDetails.priceStock.map((v) => ({
id: v.id,
stockOut: !!v.stockOut,
stock: v.stock || undefined,
threeDaysRental: v.threeDaysRental || undefined,
sevenDaysRental: v.sevenDaysRental || undefined,
thirtyDaysRental: v.thirtyDaysRental || undefined,
ninetyDaysRental: v.ninetyDaysRental || undefined,
maxDaysRental: v.maxDaysRental || undefined,
cashPledge: v.cashPledge,
...Object.getOwnPropertyNames(JSON.parse(v.productSpec)).reduce(
(pre: any, cur, currentIndex) => {
pre['name' + (currentIndex + 1)] = JSON.parse(v.productSpec)[cur];
pre['specificationName' + (currentIndex + 1)] = cur;
return pre;
},
{},
),
}));
setTableFormDefault(tableDataList);
setTableData(tableDataList);
}
}, [rentGoodsDetails]);
return (
<div className='sku-info'>
<div className='sku-info-title'>价格库存信息</div>
......
.goods-info {
&-operate {
margin-top: 50px;
display: flex;
justify-content: center;
button {
width: 100px;
height: 40px;
&:first-child {
margin-right: 50px;
}
}
}
.rent-create-edit{
padding-bottom: 80px;
}
......@@ -2,17 +2,99 @@ import GoodsInfo from './components/goodsInfo';
import RentAttr from './components/rentAttr';
import SkuInfo from './components/skuInfo';
import AddressInfo from './components/addressInfo';
import FooterOperate from './components/footerOperate';
import AccessoryList from './components/accessoryList';
import './index.scss';
import { useEffect, useRef, useState } from 'react';
import { RentManageAPI } from '~/api';
import { filterObjAttr } from '~/utils';
import { message } from 'antd';
import { useNavigate, useSearchParams } from 'react-router-dom';
import { InterDataType } from '~/api/interface';
import { leaseGoodsDetailsType } from '~/api/interface/rentManageType';
//租赁商品详情返回类型
type rentGoodsDetailType = InterDataType<leaseGoodsDetailsType>;
const RentAddOrEdit = () => {
const navigate = useNavigate();
const [searchParams] = useSearchParams();
const goodsInfoRef = useRef<any>();
const rentAttrRef = useRef<any>();
const skuInfoRef = useRef<any>();
const accessoryListRef = useRef<any>();
const addressInfoRef = useRef<any>();
//租赁商品-编辑-id
const [rentGoodsId, setRentGoodsId] = useState<number>(-1);
//租赁-编辑-商品详情
const [rentGoodsDetails, setRentGoodsDetails] = useState<rentGoodsDetailType>();
// 保存
const saveRentGoods = () => {
Promise.all([
goodsInfoRef.current.submitGoodsInfoForm(),
rentAttrRef.current.submitAttrForm(),
skuInfoRef.current.skuFormSubmit(),
accessoryListRef.current.accessoryTableFormSubmit(),
addressInfoRef.current.addressInfoFormSubmit(),
]).then((values) => {
const resourcesList = [
{ type: 0, url: values[1].mainImage },
...(values[1].subImage?.map((v: string) => ({ type: 1, url: v })) || []),
...(values[1].goodsVideo ? [{ type: 2, url: values[1].goodsVideo }] : []),
];
values[2].priceStock = values[2].priceStock.map((v: any) => ({
...v,
stockOut: v.stockOut ? 1 : 0,
}));
RentManageAPI[rentGoodsId ? 'editLeaseGoods' : 'addRentGoods']({
...values[0],
...filterObjAttr(values[1], ['goodsImage', 'goodsVideo']),
...values[2],
leasePartsList: values[3],
...values[4],
resourcesList,
id: rentGoodsId ? rentGoodsId : undefined,
}).then(({ code }) => {
if (code === '200') {
message.success(rentGoodsId ? '编辑成功' : '新增成功');
navigate(-1);
}
});
});
};
//获取租赁商品详情
const getRentGoodsDetail = (id: number) => {
RentManageAPI.getLeaseGoodsDetails({ id }).then(({ result }) => {
if (result) {
setRentGoodsDetails({ ...result });
}
});
};
useEffect(() => {
if (searchParams.get('id')) {
getRentGoodsDetail(Number(searchParams.get('id')));
setRentGoodsId(Number(searchParams.get('id')));
}
}, []);
return (
<div className='rent-create-edit'>
{/*商品信息*/}
<GoodsInfo />
<GoodsInfo ref={goodsInfoRef} rentGoodsDetails={rentGoodsDetails} />
{/*商品属性*/}
<RentAttr />
<RentAttr ref={rentAttrRef} rentGoodsDetails={rentGoodsDetails} />
{/*价格库存信息*/}
<SkuInfo />
<SkuInfo ref={skuInfoRef} rentGoodsDetails={rentGoodsDetails} />
{/*配件清单*/}
<AccessoryList ref={accessoryListRef} rentGoodsDetails={rentGoodsDetails} />
{/*物流信息*/}
<AddressInfo />
<AddressInfo ref={addressInfoRef} rentGoodsDetails={rentGoodsDetails} />
{/*底部操作栏*/}
<FooterOperate saveRentGoods={saveRentGoods} />
</div>
);
};
......
import { useSearchParams, useNavigate } from 'react-router-dom';
import { useEffect, useState } from 'react';
import { RentManageAPI } from '~/api';
import { InterDataType } from '~/api/interface';
import { leaseGoodsDetailsType } from '~/api/interface/rentManageType';
import { Badge, Button, Col, Descriptions, Image, Row, Switch, Table } from 'antd';
//租赁商品详情返回类型
type rentGoodsDetailType = InterDataType<leaseGoodsDetailsType>;
//规格表单数据类型
type specificationFormListType = {
optionList: { label: string; value: string }[];
id: number;
name: string;
addSpecificationValueShow: boolean;
specificationValueList: { name: string; id: number; specificationName: string }[];
};
const RentDetail = () => {
const [searchParams] = useSearchParams();
const navigate = useNavigate();
//租赁-编辑-商品详情
const [rentGoodsDetails, setRentGoodsDetails] = useState<rentGoodsDetailType>();
const [skuColumns, setSkuColumns] = useState<any>([
{
title: '商品规格',
align: 'center',
children: [],
},
{
title: '是否缺货',
align: 'center',
dataIndex: 'stockOut',
render: (text: number) => <Switch checked={!!text} />,
},
{
title: '押金',
align: 'center',
dataIndex: 'cashPledge',
render: (text: number) => text.toLocaleString() + '元',
},
{
title: '库存',
align: 'center',
dataIndex: 'stock',
},
]);
const [skuTableData, setSkuTableData] = useState<
(rentGoodsDetailType['priceStock'][0] & { [x: string]: string })[]
>([]);
//全部租期
const [allLeaseTermInfoList, setAllLeaseTermInfoList] = useState<
{
label: string;
value: number;
key: string;
}[]
>([]);
//获取租赁商品详情
const getRentGoodsDetail = (id: number) => {
RentManageAPI.getLeaseGoodsDetails({ id }).then(({ result }) => {
if (result) {
setRentGoodsDetails({ ...result });
//转化数据
const covertSpecAttrList = result.specAttrList.map((v, index) => ({
id: v.id,
name: 'specName' + index,
optionList: [{ label: v.specName, value: v.specName }],
specificationValueList: v.specValuesList.map((i) => ({
id: i.id,
name: i.specName,
specificationName: v.specName,
})),
addSpecificationValueShow: false,
}));
const upLeaseTermInfoIndex = allLeaseTermInfoList.findIndex(
(v) => v.value === result.maxLeaseTerm,
);
const lowLeaseTermInfoIndex = allLeaseTermInfoList.findIndex(
(v) => v.value === result.minLeaseTerm,
);
const filterLeaseTermInfo = allLeaseTermInfoList.slice(
lowLeaseTermInfoIndex,
upLeaseTermInfoIndex + 1,
);
const addColumnsList: any = filterLeaseTermInfo.map((v) => ({
title: v.label,
align: 'center',
dataIndex: v.key,
width: '15%',
render: (text: number) => text.toLocaleString() + '元',
}));
skuColumns.push(...addColumnsList);
mergeTableRow(covertSpecAttrList);
const tableDataList: (rentGoodsDetailType['priceStock'][0] & { [x: string]: string })[] =
result.priceStock.map((v) => ({
id: v.id,
stockOut: !!v.stockOut,
stock: v.stock || undefined,
threeDaysRental: v.threeDaysRental || undefined,
sevenDaysRental: v.sevenDaysRental || undefined,
thirtyDaysRental: v.thirtyDaysRental || undefined,
ninetyDaysRental: v.ninetyDaysRental || undefined,
maxDaysRental: v.maxDaysRental || undefined,
cashPledge: v.cashPledge,
...Object.getOwnPropertyNames(JSON.parse(v.productSpec)).reduce(
(pre: any, cur, currentIndex) => {
pre['name' + (currentIndex + 1)] = JSON.parse(v.productSpec)[cur];
pre['specificationName' + (currentIndex + 1)] = cur;
return pre;
},
{},
),
}));
setSkuTableData(tableDataList);
}
});
};
//表头拆分及合并列
const mergeTableRow = (filterSpecificationFormList: specificationFormListType[]) => {
const columns = filterSpecificationFormList.map((v, index) => ({
title: v.optionList[0].value,
dataIndex: 'name' + (index + 1),
align: 'center',
onCell: (_: any, i: number) => {
//合并列
if (index < filterSpecificationFormList.length - 1) {
const count: number = filterSpecificationFormList
.slice(index + 1, filterSpecificationFormList.length)
.reduce((pre: number, cur) => {
return pre * cur.specificationValueList.length;
}, 1);
return {
rowSpan: count !== 1 ? ((i + 1) % count === 1 ? count : 0) : 1,
};
} else {
return {
rowSpan: 1,
};
}
},
}));
skuColumns[0].children = columns;
setSkuColumns([...skuColumns]);
};
//租赁-商品-租期信息
const getLeaseTermInfo = () => {
RentManageAPI.getLeaseTermInfo().then(({ result }) => {
if (result) {
const optionList = result.map((v, index) => ({
label: v.leaseDate,
value: v.id,
key: [
'threeDaysRental',
'sevenDaysRental',
'thirtyDaysRental',
'ninetyDaysRental',
'maxDaysRental',
][index],
}));
setAllLeaseTermInfoList(optionList);
}
});
};
//返回
const backRoute = () => {
navigate(-1);
};
useEffect(() => {
getLeaseTermInfo();
}, []);
useEffect(() => {
if (allLeaseTermInfoList.length) {
getRentGoodsDetail(Number(searchParams.get('id')));
}
}, [allLeaseTermInfoList]);
return (
<div className='rent-detail'>
<Descriptions
title='商品信息'
bordered
column={4}
extra={
<Button type='primary' onClick={backRoute}>
返回
</Button>
}
>
<Descriptions.Item label='商品标题'>{rentGoodsDetails?.tradeName}</Descriptions.Item>
<Descriptions.Item label='商品卖点'>{rentGoodsDetails?.sellingPoint}</Descriptions.Item>
<Descriptions.Item label='商品成新'>{rentGoodsDetails?.level}</Descriptions.Item>
<Descriptions.Item label='商品状态'>
<Badge
status={rentGoodsDetails?.shelfStatus ? 'processing' : 'default'}
text={rentGoodsDetails?.shelfStatus ? '上架中' : '仓库中'}
/>
</Descriptions.Item>
</Descriptions>
<Descriptions title='商品属性' bordered column={3} style={{ marginTop: '10px' }}>
<Descriptions.Item label='商品类型'>{rentGoodsDetails?.productTypeId}</Descriptions.Item>
<Descriptions.Item label='商品品牌'>{rentGoodsDetails?.brandInfoId}</Descriptions.Item>
<Descriptions.Item label='商品型号'>{rentGoodsDetails?.deviceModeId}</Descriptions.Item>
<Descriptions.Item label='商品主图'>
<Image src={rentGoodsDetails?.resourcesList.find((v) => v.type === 0)?.url} width={50} />
</Descriptions.Item>
<Descriptions.Item label='商品副图' span={2}>
{rentGoodsDetails?.resourcesList.filter((v) => v.type === 1).length
? rentGoodsDetails?.resourcesList
.filter((v) => v.type === 1)
.map((v) => <Image src={v.url} width={50} height={50} key={v.id} />)
: '暂无'}
</Descriptions.Item>
<Descriptions.Item label='商品视频'>
{rentGoodsDetails?.resourcesList.find((v) => v.type === 2)?.url ? (
<video
src={rentGoodsDetails?.resourcesList.find((v) => v.type === 2)?.url}
controls
style={{ width: '100px', height: '100px' }}
/>
) : (
'暂无'
)}
</Descriptions.Item>
<Descriptions.Item label='商品参数'>
{rentGoodsDetails?.productParam
? JSON.parse(rentGoodsDetails?.productParam).map(
(v: { [x: string]: string }, index: number) => (
<Row key={index} style={{ lineHeight: '40px' }}>
<Col>{Object.getOwnPropertyNames(v)[0]}</Col>
<Col>{v[Object.getOwnPropertyNames(v)[0]]}</Col>
</Row>
),
)
: '暂无'}
</Descriptions.Item>
</Descriptions>
<Descriptions title='价格库存信息' column={1} style={{ marginTop: '10px' }}>
<Descriptions.Item>
<Table
style={{ width: '100%' }}
bordered
columns={skuColumns}
dataSource={skuTableData}
pagination={false}
/>
</Descriptions.Item>
</Descriptions>
<Descriptions title='配件清单' column={1} style={{ marginTop: '10px' }}>
<Descriptions.Item>
<Table
style={{ width: '100%' }}
bordered
columns={[
{
title: '名称',
dataIndex: 'name',
align: 'center',
},
{
title: '数量',
dataIndex: 'number',
align: 'center',
},
{
title: '价格',
dataIndex: 'price',
align: 'center',
render: (text: number) => text.toLocaleString() + '元',
},
]}
dataSource={rentGoodsDetails?.leasePartsList}
pagination={false}
/>
</Descriptions.Item>
</Descriptions>
</div>
);
};
export default RentDetail;
.rent-goods-info{
display: flex;
.info-meta{
margin-left: 5px;
word-break: break-all;
.title{
margin-bottom: 10px;
}
}
}
import SearchBox, { searchColumns as searchColumnsType } from '~/components/search-box';
import { Button, Card, Table } from 'antd';
import { Button, Card, Image, message, Modal, Table } from 'antd';
import {
ArrowDownOutlined,
ArrowUpOutlined,
DeleteOutlined,
PlusOutlined,
} from '@ant-design/icons';
import { useState } from 'react';
import { useEffect, useState } from 'react';
import { ColumnsType } from 'antd/es/table';
import { useNavigate } from 'react-router-dom';
import { RentManageAPI } from '../../../../api';
import { InterDataType, InterReqListType, PaginationProps } from '../../../../api/interface';
import { leaseGoodsListType } from '../../../../api/interface/rentManageType';
import './index.scss';
//租赁列表返回类型
type rentGoodsType = InterDataType<leaseGoodsListType>['list'];
//租赁列表参数类型
type rentGoodsParametersType = Exclude<InterReqListType<leaseGoodsListType>, undefined>;
const RentList = () => {
const navigate = useNavigate();
//类型下拉列表
const [rentTypeSelectList, setRentTypeSelectList] = useState<{ label: string; value: number }[]>(
[],
);
//品牌下拉列表
const [brandInfoList, setBrandInfoList] = useState<{ label: string; value: number }[]>([]);
const searchColumns: searchColumnsType[] = [
{
label: '商品名称',
name: '',
name: 'tradeName',
type: 'input',
placeholder: '请输入商品名称',
},
{
label: '商品类型',
name: '',
type: 'select',
name: 'productTypeId',
type: 'Select',
placeholder: '请选择商品类型',
options: [],
options: rentTypeSelectList,
},
{
label: '商品品牌',
name: '',
type: 'select',
name: 'brandInfoId',
type: 'Select',
placeholder: '请选择商品品牌',
options: [],
options: brandInfoList,
},
];
const tabList = [
{
key: '1',
......@@ -49,57 +67,221 @@ const RentList = () => {
},
];
const [activeTabKey, setActiveTabKey] = useState<string>('1');
const tableColumns: ColumnsType<any> = [
const tableColumns: ColumnsType<rentGoodsType[0]> = [
{
title: '商品名称',
align: 'center',
width: '30%',
onHeaderCell: () => ({
style: {
textAlign: 'center',
},
}),
render: (_: any, record) => (
<div className='rent-goods-info'>
<div className='goods-img'>
<Image
src={record.resourcesList.find((v) => v.type === 0)?.url}
width={50}
height={50}
/>
</div>
<div className='info-meta'>
<div className='title'>{record.tradeName}</div>
<div className='type'>
{rentTypeSelectList.find((v) => v.value === record.productTypeId)?.label}
</div>
</div>
</div>
),
},
{
title: '押金范围',
align: 'center',
dataIndex: 'cashPledgeRange',
},
{
title: '租金范围(日)',
align: 'center',
dataIndex: 'rentalRange',
},
{
title: '库存',
align: 'center',
dataIndex: 'stock',
},
{
title: '销量',
title: '创建时间',
align: 'center',
dataIndex: 'createTime',
},
{
title: '创建时间',
title: '状态',
align: 'center',
dataIndex: 'shelfStatus',
render: (text: number) => (text ? '上架' : '下架'),
},
{
title: '操作',
align: 'center',
width: '20%',
render: () => (
render: (_: any, record) => (
<>
<Button type='link'>编辑</Button>
<Button type='link'>详情</Button>
<Button type='link'>上架</Button>
<Button type='link'>下架</Button>
<Button type='link' danger>
<Button type='link' onClick={() => toRentEdit(record)}>
编辑
</Button>
<Button type='link' onClick={() => toRentDetail(record)}>
详情
</Button>
<Button
type='link'
disabled={!!record.shelfStatus}
onClick={() => batchOnShelfOrTakeDownRequest([record.id], 1)}
>
上架
</Button>
<Button
type='link'
disabled={!record.shelfStatus}
onClick={() => batchOnShelfOrTakeDownRequest([record.id], 0)}
>
下架
</Button>
<Button type='link' danger onClick={() => batchRemoveWareInfoRequest([record.id])}>
删除
</Button>
</>
),
},
];
const [tableData] = useState<any>([{ id: 1 }]);
const [tableData, setTableData] = useState<rentGoodsType>([]);
const [pagination, setPagination] = useState<PaginationProps & { totalCount: number }>({
pageNo: 1,
pageSize: 10,
totalCount: 0,
});
const [query, setQuery] = useState<rentGoodsParametersType>({
shelfStatus: undefined,
});
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
const onTabChange = (key: string) => {
pagination.pageNo = 1;
pagination.pageSize = 10;
setActiveTabKey(key);
query.shelfStatus = key === '1' ? undefined : key === '2' ? 1 : 0;
setQuery(query);
getRentGoodsList(query);
};
//租赁商品列表
const getRentGoodsList = (query?: rentGoodsParametersType) => {
RentManageAPI.getLeaseGoodsList({
pageNo: pagination.pageNo,
pageSize: pagination.pageSize,
...query,
}).then(({ result }) => {
pagination.totalCount = result.totalCount;
setPagination({ ...pagination });
setTableData(result.list || []);
});
};
//新增,编辑租赁商品
const addOrEditClick = () => {
navigate({ pathname: '/rentManage/rentGoods/add' });
};
//分页
const paginationChange = (pageNo: number, pageSize: number) => {
pagination.pageNo = pageNo;
pagination.pageSize = pageSize;
getRentGoodsList(query);
};
//筛选
const searchSuccess = (value: rentGoodsParametersType) => {
pagination.pageNo = 1;
pagination.pageSize = 10;
setQuery(value);
getRentGoodsList(value);
};
//获取类型列表
const getRentTypeList = () => {
RentManageAPI.getTypeList({ pageNo: 1, pageSize: 99999 }).then(({ result }) => {
if (result.list) {
setRentTypeSelectList(result.list.map((v) => ({ value: v.id, label: v.name })));
}
});
};
//品牌列表
const getRentMakeList = () => {
RentManageAPI.getListBrandInfo({ pageNo: 1, pageSize: 99999 }).then(({ result }) => {
if (result.list) {
const optionList = result.list.map((v) => ({ label: v.brandName, value: v.id }));
setBrandInfoList(optionList);
}
});
};
//跳转租赁商品编辑
const toRentEdit = (record: rentGoodsType[0]) => {
navigate({ pathname: '/rentManage/rentGoods/edit', search: `id=${record.id}` });
};
//跳转租赁详情
const toRentDetail = (record: rentGoodsType[0]) => {
navigate({ pathname: '/rentManage/rentGoods/detail', search: `id=${record.id}` });
};
//批量上下架操作
const batchOnShelfOrTakeDownClick = (status: number) => {
if (selectedRowKeys.length === 0) {
message.warning('请先选择租赁商品');
} else {
batchOnShelfOrTakeDownRequest(selectedRowKeys as number[], status);
}
};
//批量上下架请求
const batchOnShelfOrTakeDownRequest = (goodsIds: number[], status: number) => {
RentManageAPI.batchOnShelfOrTakeDown({ goodsIds, status }).then(({ code }) => {
if (code === '200') {
message.success(`${status ? '上架' : '下架'}成功`);
getRentGoodsList(query);
setSelectedRowKeys([]);
}
});
};
//批量删除操作
const batchRemoveWareInfoClick = () => {
if (selectedRowKeys.length === 0) {
message.warning('请先选择租赁商品');
} else {
batchRemoveWareInfoRequest(selectedRowKeys as number[]);
}
};
//批量删除请求
const batchRemoveWareInfoRequest = (ids: number[]) => {
Modal.confirm({
title: '提示',
content: `确认删除${ids.length > 1 ? '这些' : '该'}商品`,
onOk: () => {
RentManageAPI.batchRemoveWareInfo(ids).then(({ code }) => {
if (code === '200') {
if (ids.length === tableData.length && pagination.pageNo !== 1) {
pagination.pageNo -= 1;
}
getRentGoodsList(query);
message.success('删除成功');
}
});
},
});
};
//表格-选择
const onSelectChange = (newSelectedRowKeys: React.Key[]) => {
setSelectedRowKeys(newSelectedRowKeys);
};
useEffect(() => {
getRentGoodsList();
getRentTypeList();
getRentMakeList();
}, []);
return (
<div className='rent-list'>
......@@ -110,20 +292,50 @@ const RentList = () => {
新增商品
</Button>
}
searchData={searchSuccess}
/>
<Card tabList={tabList} activeTabKey={activeTabKey} onTabChange={onTabChange}>
<div className='table-operate' style={{ marginBottom: '10px' }}>
<Button type='primary' icon={<ArrowUpOutlined />} style={{ marginRight: '10px' }}>
<Button
type='primary'
icon={<ArrowUpOutlined />}
style={{ marginRight: '10px' }}
onClick={() => batchOnShelfOrTakeDownClick(1)}
>
批量上架
</Button>
<Button type='primary' icon={<ArrowDownOutlined />} style={{ marginRight: '10px' }}>
<Button
type='primary'
icon={<ArrowDownOutlined />}
style={{ marginRight: '10px' }}
onClick={() => batchOnShelfOrTakeDownClick(0)}
>
批量下架
</Button>
<Button type='primary' danger icon={<DeleteOutlined />}>
<Button
type='primary'
danger
icon={<DeleteOutlined />}
onClick={batchRemoveWareInfoClick}
>
批量删除
</Button>
</div>
<Table bordered columns={tableColumns} rowKey='id' dataSource={tableData} />
<Table
columns={tableColumns}
rowKey='id'
dataSource={tableData}
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} 条数据`,
}}
rowSelection={{ selectedRowKeys, onChange: onSelectChange }}
/>
</Card>
</div>
);
......
import { Cascader, Form, Input, message, Modal, ModalProps, Switch } from 'antd';
import { FC, useEffect } from 'react';
import districtData from '~/assets/json/district.json';
import { InterDataType, InterReqType } from '~/api/interface';
import { addressInsetType, addressListType } from '~/api/interface/systemManageType';
import { SystemManageAPI } from '~/api';
interface selfProps {
onOk: () => void;
onCancel: () => void;
currentAddressItem?: addressType[0] | undefined;
}
//新增地址参数类型
type addAddressParameterType = Exclude<InterReqType<addressInsetType>, undefined>;
//地址列表返回类型
type addressType = InterDataType<addressListType>;
const AddOrEditAddressModal: FC<ModalProps & selfProps> = ({
open,
onCancel,
onOk,
currentAddressItem,
}) => {
const [form] = Form.useForm<
Omit<addAddressParameterType, 'takeRegion' | 'type' | 'districtCode'> & {
takeRegion: string[];
type: boolean;
districtCode: number[];
}
>();
const handleOk = () => {
form.validateFields().then((values) => {
SystemManageAPI[currentAddressItem ? 'editAddress' : 'addressInset']({
...values,
districtCode: values.districtCode[2].toString(),
takeRegion: getDistrictName(values.districtCode),
type: values.type ? 1 : 0,
id: currentAddressItem ? currentAddressItem.id : undefined,
}).then(({ code }) => {
if (code === '200') {
message.success('新增地址成功');
form.resetFields();
onOk();
}
});
});
};
const handleCancel = () => {
onCancel();
};
//根据省市区code查询省市区名称
const getDistrictName = (codeArr: number[]) => {
const getFlatDistrictData = (districtData: any[]) => {
return districtData.reduce((pre: any, cur: any) => {
pre.push(cur);
if (cur.childInfo) {
pre.push(...getFlatDistrictData(cur.childInfo));
}
return pre;
}, []);
};
const flatDistrictData: any = getFlatDistrictData(districtData);
return codeArr.map((v) => flatDistrictData.find((i: any) => i.id === v)?.name).join('/');
};
useEffect(() => {
if (currentAddressItem) {
form.setFieldsValue({
takeName: currentAddressItem.takeName,
takePhone: currentAddressItem.takePhone,
districtCode: [
Number(currentAddressItem.districtCode.substring(0, 2) + '0000'),
Number(currentAddressItem.districtCode.substring(0, 4) + '00'),
Number(currentAddressItem.districtCode),
],
takeAddress: currentAddressItem.takeAddress,
type: !!currentAddressItem.type,
});
}
}, [currentAddressItem]);
return (
<Modal
open={open}
title={currentAddressItem ? '编辑地址' : '新增地址'}
onOk={handleOk}
onCancel={handleCancel}
>
<Form labelCol={{ span: 4 }} wrapperCol={{ span: 20 }} form={form}>
<Form.Item label='姓名' name='takeName' rules={[{ required: true, message: '请输入姓名' }]}>
<Input placeholder='请输入姓名' maxLength={30} />
</Form.Item>
<Form.Item
label='手机号'
name='takePhone'
rules={[
{ required: true, message: '请输入手机号' },
// 校验手机号
() => ({
validator(_, value) {
if (!value || /^1[3-9]\d{9}$/.test(value)) {
return Promise.resolve();
}
return Promise.reject('请输入正确的手机号');
},
}),
]}
>
<Input placeholder='请输入手机号' maxLength={11} />
</Form.Item>
<Form.Item
label='所在地区'
name='districtCode'
rules={[{ required: true, message: '请选择所在地区' }]}
>
<Cascader
placeholder='请选择所在地区'
options={districtData}
fieldNames={{ label: 'name', value: 'id', children: 'childInfo' }}
/>
</Form.Item>
<Form.Item
label='详细地址'
name='takeAddress'
rules={[{ required: true, message: '请输入详细地址' }]}
>
<Input.TextArea rows={4} showCount placeholder='请输入详细地址' maxLength={70} />
</Form.Item>
<Form.Item label='设为默认地址' name='type'>
<Switch />
</Form.Item>
</Form>
</Modal>
);
};
export default AddOrEditAddressModal;
import SearchBox from '~/components/search-box';
import { Button, message, Modal, Table } from 'antd';
import { PlusOutlined } from '@ant-design/icons';
import { ColumnsType } from 'antd/es/table';
import AddOrEditAddressModal from '~/pages/systemManage/addressManage/components/addOrEditAddressModal';
import { useEffect, useState } from 'react';
import { SystemManageAPI } from '~/api';
import { InterDataType } from '~/api/interface';
import { addressListType } from '~/api/interface/systemManageType';
//地址列表返回类型
type addressType = InterDataType<addressListType>;
const AddressManage = () => {
const tableColumns: ColumnsType<addressType[0]> = [
{
title: '姓名',
align: 'center',
dataIndex: 'takeName',
},
{
title: '电话',
align: 'center',
dataIndex: 'takePhone',
},
{
title: '所在地区',
align: 'center',
dataIndex: 'takeRegion',
},
{
title: '详细地址',
align: 'center',
dataIndex: 'takeAddress',
},
{
title: '状态',
align: 'center',
dataIndex: 'type',
render: (text: number) => (text ? '默认' : ''),
},
{
title: '操作',
align: 'center',
render: (_: any, record) => (
<>
<Button type='link' onClick={() => addOrEditAddressModalClick(record)}>
编辑
</Button>
<Button type='link' onClick={() => deleteAddressClick(record)}>
删除
</Button>
</>
),
},
];
const [addressList, setAddressList] = useState<addressType>([]);
const [addOrEditAddressModalShow, setAddOrEditAddressModalShow] = useState<boolean>(false);
const [currentAddressItem, setCurrentAddressItem] = useState<addressType[0]>();
const getAddressList = () => {
SystemManageAPI.getAddressList({}).then(({ result }) => {
setAddressList(result);
});
};
//新增,编辑地址
const addOrEditAddressModalClick = (record?: addressType[0]) => {
setCurrentAddressItem(record ? { ...record } : undefined);
setAddOrEditAddressModalShow(true);
};
const addOrEditAddressModalCancel = () => {
setAddOrEditAddressModalShow(false);
};
const addOrEditAddressModalOk = () => {
getAddressList();
setAddOrEditAddressModalShow(false);
};
//地址删除
const deleteAddressClick = (record: addressType[0]) => {
Modal.confirm({
title: '提示',
content: '确认删除该地址吗?',
onOk: () => {
SystemManageAPI.deleteAddress({ id: record.id }).then(({ code }) => {
if (code === '200') {
message.success('删除成功');
getAddressList();
}
});
},
});
};
useEffect(() => {
getAddressList();
}, []);
return (
<div className='address-manage'>
<SearchBox
child={
<Button
type='primary'
icon={<PlusOutlined />}
onClick={() => addOrEditAddressModalClick()}
>
新增地址
</Button>
}
/>
<Table bordered columns={tableColumns} dataSource={addressList} rowKey='id' />
{/*新增编辑地址*/}
<AddOrEditAddressModal
open={addOrEditAddressModalShow}
onCancel={addOrEditAddressModalCancel}
onOk={addOrEditAddressModalOk}
currentAddressItem={currentAddressItem}
/>
</div>
);
};
export default AddressManage;
......@@ -35,6 +35,7 @@ import {
BankOutlined,
VerifiedOutlined,
AccountBookOutlined,
EnvironmentOutlined,
} from '@ant-design/icons';
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
......@@ -98,7 +99,8 @@ const ServiceIntroduceView = React.lazy(
); //服务介绍
const RentListView = React.lazy(() => import('~/pages/rentManage/rentGoods/rentList')); //租赁列表
const RentAddOrEditView = React.lazy(() => import('~/pages/rentManage/rentGoods/rentAddOrEdit')); //租赁新增、编辑、详情
const RentAddOrEditView = React.lazy(() => import('~/pages/rentManage/rentGoods/rentAddOrEdit')); //租赁新增、编辑
const RentDetailView = React.lazy(() => import('~/pages/rentManage/rentGoods/rentDetail')); //租赁详情
const RentTypeView = React.lazy(() => import('~/pages/rentManage/rentType')); //租赁-类型管理
const RentMakeView = React.lazy(() => import('~/pages/rentManage/rentMake')); //租赁-品牌管理
const RentModeView = React.lazy(() => import('~/pages/rentManage/rentMode')); //租赁-型号管理
......@@ -106,7 +108,7 @@ const RentModeView = React.lazy(() => import('~/pages/rentManage/rentMode')); //
const MallGoodsView = React.lazy(() => import('~/pages/mallManage/mallGoods/goodsList')); //商城商品
const MallAddOrEditOrDetailView = React.lazy(
() => import('~/pages/mallManage/mallGoods/goodsAddOrEditOrDetail'),
); //商城商品新增、编辑、租赁商品详情
); //商城商品新增、编辑
const MallGoodsDetailsView = React.lazy(() => import('~/pages/mallManage/mallGoods/goodsDetails')); //商城商品(新)
const ProduceListView = React.lazy(() => import('~/pages/mallManage/produceManage/produceList')); //产品列表
......@@ -153,6 +155,7 @@ const CompanyDetailView = React.lazy(
import AccountLimit from '~/pages/systemManage/limitManage/roleList'; //账号权限
import LimitInfo from '~/pages/systemManage/limitManage/limitInfo';
import CustomListDetail from '~/pages/customManage/customList/detail';
const AddressManageView = React.lazy(() => import('~/pages/systemManage/addressManage'));
// const IndustryListView = React.lazy(() => import('~/pages/mallManage/industryManage/industryList')); //行业列表
// const IndustryDetailView = React.lazy(
......@@ -734,17 +737,17 @@ export const routerList: Array<RouteObjectType> = [
hidden: true,
},
},
// {
// path: '/rentManage/rentGoods/detail',
// element: withLoadingComponent(<RentAddOrEditView />),
// errorElement: <ErrorPage />,
// meta: {
// id: 10136,
// icon: <SmileOutlined />,
// title: '租赁商品详情',
// hidden: true,
// },
// },
{
path: '/rentManage/rentGoods/detail',
element: withLoadingComponent(<RentDetailView />),
errorElement: <ErrorPage />,
meta: {
id: 10176,
icon: <SmileOutlined />,
title: '租赁商品详情',
hidden: true,
},
},
{
path: '/rentManage/rentType',
element: withLoadingComponent(<RentTypeView />),
......@@ -1163,6 +1166,17 @@ export const routerList: Array<RouteObjectType> = [
hidden: true,
},
},
{
path: '/systemManage/addressManage',
element: withLoadingComponent(<AddressManageView />),
errorElement: <ErrorPage />,
meta: {
id: 1450,
title: '地址管理',
icon: <EnvironmentOutlined />,
develop: true,
},
},
],
},
];
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论