提交 a2746629 作者: 龚洪江

功能:租赁页面

...@@ -31,9 +31,12 @@ export type listBrandInfoType = InterItemFunction< ...@@ -31,9 +31,12 @@ export type listBrandInfoType = InterItemFunction<
>; >;
//租赁-型号-新增 //租赁-型号-新增
export type addRentModeType = InterFunction<{ modeName: string; productTypeId: number }, any>; export type addRentModeType = InterFunction<
{ modeName: string; productTypeId: number; brandInfoId: number; tag?: string },
any
>;
//租赁-型号-列表 //租赁-型号-列表
export type rentModeListType = InterItemFunction< export type rentModeListType = InterItemFunction<
{ brandInfoId?: number; productTypeId?: number }, { brandInfoId?: number; productTypeId?: number },
any { modeName: string; id: number; brandInfoId: number; productTypeId: number; tag: string }[]
>; >;
import SearchBox, { searchColumns } from '~/components/search-box';
import React, { useEffect, useRef, useState } from 'react';
import { useNavigate, useSearchParams } from 'react-router-dom';
import { Button, Card, Image, message, Modal, Table } from 'antd';
import {
ArrowDownOutlined,
ArrowUpOutlined,
DeleteOutlined,
PlusOutlined,
} from '@ant-design/icons';
import { ColumnsType } from 'antd/es/table';
import GoodsAPI from '~/api/modules/goodsAPI';
import { InterDataType, InterReqType, PaginationProps } from '~/api/interface';
import { listGoodsType } from '~/api/interface/goodsType';
import { CategoryManageAPI } from '~/api';
import { filterObjAttr } from '~/utils';
import qs from 'query-string';
//商品返回类型
type goodsType = InterDataType<listGoodsType>['list'];
//商品列表筛选类型
type goodsSearchParameters = Omit<InterReqType<listGoodsType>, 'goodsType'>;
const RentList = () => {
//筛选ref
const searchRef = useRef();
const navigate = useNavigate();
const [searchParams, setSearchParams] = useSearchParams();
const tabList = [
{
key: '1',
tab: '全部',
},
{
key: '2',
tab: '上架中',
},
{
key: '3',
tab: '仓库中',
},
];
const [activeTabKey, setActiveTabKey] = useState<string>('1');
const [searchColumns, setSearchColumns] = useState<searchColumns[]>([
{
label: '商品名称',
placeholder: '请输入商品名称',
name: 'goodsName',
type: 'input',
},
{
label: '所属目录',
placeholder: '请选择所属目录',
name: 'directoryId',
type: 'select',
options: [],
},
{
label: '创建时间',
placeholder: '请输入选择创建时间',
name: 'time',
type: 'rangePicker',
},
]);
const tableColumns: ColumnsType<goodsType[0]> = [
{
title: '序号',
align: 'center',
render: (_text: any, _record, index: number) =>
(pagination.pageNo - 1) * pagination.pageSize + index + 1,
},
{
title: '图片',
align: 'center',
dataIndex: 'imgUrl',
render: (text: string) => <Image src={text} width={50} height={50} />,
},
{ title: '商品名称', align: 'center', dataIndex: 'goodsName' },
{ title: '所属目录', align: 'center', dataIndex: 'directoryName' },
{ title: '创建时间', align: 'center', dataIndex: 'createTime' },
{
title: '状态',
align: 'center',
dataIndex: 'status',
render: (text: number) => (text ? '上架' : '下架'),
},
{
title: '操作',
align: 'center',
dataIndex: 'id',
render: (id: number) => (
<>
<Button type='link' onClick={() => toEditGoods(id)}>
编辑
</Button>
<Button type='link' onClick={() => toRentGoodsDetail(id)}>
详情
</Button>
</>
),
},
];
const [tableData, setTableData] = useState<goodsType>([]);
const [allRentGoods, setAllRentGoods] = useState<goodsType>([]);
const [loading, setLoading] = useState<boolean>(false);
//分页
const [pagination, setPagination] = useState<
PaginationProps & { totalCount: number; totalPage: number }
>({
pageNo: 1,
pageSize: 10,
totalCount: 0,
totalPage: 1,
});
//筛选
const [query, setQuery] = useState<goodsSearchParameters>({ status: undefined });
// 表格多选
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
const onTabChange = (key: string) => {
pagination.pageNo = 1;
pagination.pageSize = 10;
query.status = key === '1' ? undefined : key === '2' ? 1 : 0;
setSearchParams(
qs.stringify({
pageNo: 1,
pageSize: 10,
...query,
status: query.status === undefined ? 'all' : query.status,
}),
);
getGoodsList(query);
getGoodsList({ ...query, pageNo: 1, pageSize: 9999 }, true);
setQuery(query);
setActiveTabKey(key);
};
const paginationChange = (pageNo: number, pageSize: number) => {
pagination.pageSize = pageSize;
pagination.pageNo = pageNo;
setSearchParams(
qs.stringify({
pageNo: pageNo,
pageSize: pageSize,
...query,
status: query.status === undefined ? 'all' : query.status,
}),
);
getGoodsList(query);
getGoodsList({ ...query, pageNo: 1, pageSize: 9999 }, true);
};
//筛选
const searchSuccess = (data: any) => {
pagination.pageNo = 1;
pagination.pageSize = 10;
setQuery({ ...filterObjAttr(data, ['time']), status: query.status });
getGoodsList({ ...filterObjAttr(data, ['time']), status: query.status });
getGoodsList(
{ ...filterObjAttr(data, ['time']), status: query.status, pageNo: 1, pageSize: 9999 },
true,
);
setSearchParams(
qs.stringify({
pageNo: 1,
pageSize: 10,
...filterObjAttr(data, ['time']),
status: query.status === undefined ? 'all' : query.status,
}),
);
};
//商品列表
const getGoodsList = (query?: goodsSearchParameters, isAll?: boolean) => {
setLoading(true);
GoodsAPI.getGoodsList({
pageNo: pagination.pageNo,
pageSize: pagination.pageSize,
goodsType: 1,
...query,
}).then(({ result }) => {
setLoading(false);
if (isAll) {
setAllRentGoods(result.list || []);
} else {
setTableData(result.list || []);
pagination.totalCount = result.totalCount;
pagination.totalPage = result.totalPage;
setPagination(pagination);
}
});
};
//新增商品
const toAddRentGoods = () => {
navigate({ pathname: '/mallManage/rentGoods/add' });
};
//编辑商品
const toEditGoods = (id: number) => {
navigate({
pathname: '/mallManage/rentGoods/edit',
search: `id=${id}`,
});
};
//商品详情
const toRentGoodsDetail = (id: number) => {
navigate({
pathname: '/mallManage/rentGoods/detail',
search: `id=${id}&isDetail=1`,
});
};
// 表格多选事件
const onSelectChange = (newSelectedRowKeys: React.Key[]) => {
setSelectedRowKeys(newSelectedRowKeys);
};
//获取目录列表
const getDirectoryList = () => {
CategoryManageAPI.getDirectoryListClone({ type: 2 }).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('请先选择商品');
}
Modal.confirm({
title: '提示',
content: '删除后数据将会丢失,确定删除吗?',
onOk() {
GoodsAPI.batchRemoveWareInfo(selectedRowKeys as number[]).then(({ code }) => {
if (code === '200') {
if (pagination.pageNo !== 1 && tableData.length == 1) {
pagination.pageNo -= 1;
}
message.success('删除成功');
getGoodsList(query);
}
});
},
});
};
//上移
const upGoodsRentClick = () => {
if (selectedRowKeys.length === 0) {
message.warning('请选择商品');
} else if (selectedRowKeys.length > 1) {
message.warning('最多选择一个商品');
} else {
const index = tableData.findIndex((v) => v.id === selectedRowKeys[0]);
const allIndex = allRentGoods.findIndex((v) => v.id === selectedRowKeys[0]);
if (index === 0 && pagination.pageNo === 1) {
message.warning('位置已到最前列,无法上移');
} else {
const exReqData =
index === 0
? allRentGoods
.filter((_v, index) => index === allIndex - 1 || index === allIndex)
.map((v) => ({ id: v.id }))
: tableData
.filter((_v, i) => index - 1 === i || index === i)
.map((v) => ({ id: v.id }));
GoodsAPI.exchangeGoodsInfo({ firstId: exReqData[0].id, secondId: exReqData[1].id }).then(
({ code }) => {
if (code === '200') {
message.success('上移成功');
if (index === 0 && pagination.pageNo !== 1) {
pagination.pageNo -= 1;
setSearchParams(
qs.stringify({
pageNo: pagination.pageNo,
pageSize: pagination.pageSize,
...query,
status: query.status === undefined ? 'all' : query.status,
}),
);
}
getGoodsList(query);
getGoodsList({ ...query, pageNo: 1, pageSize: 9999 }, true);
}
},
);
}
}
};
//下移
const downRentGoodsClick = () => {
if (selectedRowKeys.length === 0) {
message.warning('请选择商品');
} else if (selectedRowKeys.length > 1) {
message.warning('最多选择一个商品');
} else {
const index = tableData.findIndex((v) => v.id === selectedRowKeys[0]);
const allIndex = allRentGoods.findIndex((v) => v.id === selectedRowKeys[0]);
if (index === tableData.length - 1 && pagination.pageNo === pagination.totalPage) {
message.warning('位置已到最后,无法下移');
} else {
const exReqData =
index === tableData.length - 1
? allRentGoods
.filter((_v, index) => index === allIndex + 1 || index === allIndex)
.map((v) => ({ id: v.id }))
: tableData
.filter((_v, i) => index + 1 === i || index === i)
.map((v) => ({ id: v.id }));
GoodsAPI.exchangeGoodsInfo({ firstId: exReqData[0].id, secondId: exReqData[1].id }).then(
({ code }) => {
if (code === '200') {
message.success('下移成功');
if (index === tableData.length - 1 && pagination.pageNo !== pagination.totalPage) {
pagination.pageNo += 1;
setSearchParams(
qs.stringify({
pageNo: pagination.pageNo,
pageSize: pagination.pageSize,
...query,
status: query.status === undefined ? 'all' : query.status,
}),
);
}
getGoodsList(query);
getGoodsList({ ...query, pageNo: 1, pageSize: 9999 }, true);
}
},
);
}
}
};
useEffect(() => {
getDirectoryList();
pagination.pageNo = Number(searchParams.get('pageNo') || 1);
pagination.pageSize = Number(searchParams.get('pageSize') || 10);
const queryObj = {
goodsName: searchParams.get('goodsName') || undefined,
directoryId: searchParams.get('directoryId')
? Number(searchParams.get('directoryId'))
: undefined,
startTime: searchParams.get('startTime') || undefined,
endTime: searchParams.get('endTime') || undefined,
status:
searchParams.get('status') === 'all' || searchParams.get('status') === null
? undefined
: Number(searchParams.get('status')),
};
getGoodsList(queryObj);
getGoodsList({ ...queryObj, pageSize: 9999, pageNo: 1 }, true);
setActiveTabKey(
searchParams.get('status') === 'all' || searchParams.get('status') === null
? '1'
: Number(searchParams.get('status')) === 1
? '2'
: '3',
);
(searchRef.current as any).getForm().setFieldsValue({
goodsName: searchParams.get('goodsName') || undefined,
directoryId: searchParams.get('directoryId')
? Number(searchParams.get('directoryId'))
: undefined,
time: searchParams.get('startTime')
? [searchParams.get('startTime'), searchParams.get('endTime')]
: undefined,
});
}, []);
return (
<div className='goods-list'>
<SearchBox
search={searchColumns}
child={
<Button type='primary' icon={<PlusOutlined />} onClick={toAddRentGoods}>
新增商品
</Button>
}
searchData={searchSuccess}
baseRef={searchRef}
/>
<Card tabList={tabList} activeTabKey={activeTabKey} onTabChange={onTabChange}>
<div className='header-operate' style={{ marginBottom: '10px' }}>
<Button
type='primary'
style={{ marginRight: '10px' }}
icon={<ArrowUpOutlined />}
onClick={upGoodsRentClick}
>
上移
</Button>
<Button
type='primary'
style={{ marginRight: '10px' }}
icon={<ArrowDownOutlined />}
onClick={downRentGoodsClick}
>
下移
</Button>
{activeTabKey !== '2' && (
<Button
type='primary'
style={{ marginRight: '10px' }}
icon={<ArrowUpOutlined />}
onClick={() => batchOnShelfOrTakeDown(1)}
>
上架
</Button>
)}
{activeTabKey !== '3' && (
<Button
type='primary'
style={{ marginRight: '10px' }}
icon={<ArrowDownOutlined />}
onClick={() => batchOnShelfOrTakeDown(0)}
>
下架
</Button>
)}
<Button danger icon={<DeleteOutlined />} onClick={deleteGoods}>
删除
</Button>
</div>
<Table
columns={tableColumns}
bordered
dataSource={tableData}
rowKey='id'
rowSelection={{
selectedRowKeys,
onChange: onSelectChange,
}}
loading={loading}
pagination={{
total: pagination.totalCount,
pageSize: pagination.pageSize,
current: pagination.pageNo,
showSizeChanger: true,
showQuickJumper: true,
onChange: (page: number, pageSize: number) => paginationChange(page, pageSize),
showTotal: (total, range) => `当前 ${range[0]}-${range[1]} 条记录 / 共 ${total} 条数据`,
}}
/>
</Card>
</div>
);
};
export default RentList;
.goods-info{
&-title{
font-size: 15px;
font-weight: bold;
line-height: 40px;
}
}
import { Form, Input, Radio } from 'antd';
import './index.scss';
const GoodsInfo = () => {
const qualityList = [
{
label: '全新',
value: 0,
},
{
label: '99新',
value: 1,
},
{
label: '95新',
value: 2,
},
{
label: '90新',
value: 3,
},
{
label: '80新',
value: 4,
},
];
return (
<div className='goods-info'>
<div className='goods-info-title'>商品信息</div>
<Form labelCol={{ span: 2 }} wrapperCol={{ span: 10 }}>
<Form.Item label='商品标题'>
<Input placeholder='请输入商品标题' />
</Form.Item>
<Form.Item label='商品卖点'>
<Input placeholder='请输入商品卖点' />
</Form.Item>
<Form.Item label='商品成新'>
<Radio.Group>
{qualityList.map((v, index) => (
<Radio value={v.value} key={index}>
{v.label}
</Radio>
))}
</Radio.Group>
</Form.Item>
<Form.Item label='商品状态'>
<Radio.Group>
<Radio value={1}>上架</Radio>
<Radio value={0}>下架</Radio>
</Radio.Group>
</Form.Item>
</Form>
</div>
);
};
export default GoodsInfo;
.rent-attr{
&-title{
font-size: 15px;
font-weight: bold;
line-height: 40px;
}
}
import './index.scss';
import { Button, Cascader, Form, Radio, Table } from 'antd';
import EditableCell from '~/components/EditableCell';
import { useState } from 'react';
import { MinusOutlined, PlusOutlined, UploadOutlined } from '@ant-design/icons';
import { Uploader } from '~/components/uploader';
import RichText from '~/components/richText';
type EditableTableProps = Parameters<typeof Table>[0];
type ColumnTypes = Exclude<EditableTableProps['columns'], undefined>;
const RentAttr = () => {
const typeList = [
{
label: '航拍无人机',
value: 1,
},
{
label: '行业无人机',
value: 2,
},
{
label: '挂载',
value: 3,
},
{
label: '配件',
value: 4,
},
];
const attrTableColumns: (ColumnTypes[number] & {
editable?: boolean;
dataIndex?: string;
inputType?: string;
rules?: any;
maxLength?: number;
})[] = [
{
title: '参数名称',
dataIndex: '',
editable: true,
align: 'center',
},
{
title: '参数值',
dataIndex: '',
editable: true,
align: 'center',
},
{
title: '操作',
dataIndex: '',
render: (_text: string, _record: any, index: number) => (
<>
{index === parameterTableData.length - 1 ? (
<Button
icon={<PlusOutlined />}
type='primary'
onClick={addParameterDataEvent}
style={{ marginRight: '10px' }}
></Button>
) : (
''
)}
{index ? (
<Button
type='primary'
icon={<MinusOutlined />}
onClick={deleteParameterDataEvent}
></Button>
) : (
''
)}
</>
),
},
];
const columns = attrTableColumns.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 [parameterTableData, setParameterTableData] = useState<any>([{ id: 1 }]);
//商品参数新增
const addParameterDataEvent = () => {
setParameterTableData([...parameterTableData, { id: parameterTableData.length + 1 }]);
};
//商品参数删除
const deleteParameterDataEvent = () => {};
return (
<div className='rent-attr'>
<div className='rent-attr-title'>商品属性</div>
<Form labelCol={{ span: 2 }} wrapperCol={{ span: 10 }}>
<Form.Item label='商品类型'>
<Radio.Group>
{typeList.map((v) => (
<Radio key={v.value} value={v.value}>
{v.label}
</Radio>
))}
</Radio.Group>
</Form.Item>
<Form.Item label='商品型号'>
<Cascader placeholder='请选择商品型号' />
</Form.Item>
<Form.Item label='商品参数'>
<Form>
<Table
columns={columns as ColumnTypes}
components={{
body: {
cell: EditableCell,
},
}}
dataSource={parameterTableData}
bordered
rowKey='id'
pagination={false}
></Table>
</Form>
</Form.Item>
<Form.Item label='商品图片'>
<Uploader fileUpload listType='picture-card'>
<UploadOutlined />
</Uploader>
</Form.Item>
<Form.Item label='商品视频'>
<Uploader fileUpload listType='picture-card'>
<UploadOutlined />
</Uploader>
</Form.Item>
<Form.Item label='商品详情页'>
<RichText richTextContent='' />
</Form.Item>
</Form>
</div>
);
};
export default RentAttr;
.rent-info{
&-title{
font-size: 15px;
font-weight: bold;
line-height: 40px;
}
}
import { Form, Select } from 'antd';
import './index.scss';
const RentInfo = () => {
return (
<div className='rent-info'>
<div className='rent-info-title'>租赁信息</div>
<Form labelCol={{ span: 2 }} wrapperCol={{ span: 10 }}>
<Form.Item label='最低租期'>
<Select placeholder='请选择租期'>
<Select.Option>11</Select.Option>
</Select>
</Form.Item>
<Form.Item label='最高租期'>
<Select placeholder='请选择租期'>
<Select.Option>11</Select.Option>
</Select>
</Form.Item>
</Form>
</div>
);
};
export default RentInfo;
.sku-info{
&-title{
font-size: 15px;
font-weight: bold;
line-height: 40px;
}
}
import './index.scss';
import { Button, Col, Row, Table } from 'antd';
import { PlusOutlined } from '@ant-design/icons';
import { ColumnsType } from 'antd/es/table/InternalTable';
const SkuInfo = () => {
const skuTableColumns: ColumnsType<any> = [
{
title: '版本',
align: 'center',
},
{
title: '是否缺货',
align: 'center',
},
{
title: '押金',
align: 'center',
},
];
return (
<div className='sku-info'>
<div className='sku-info-title'>价格库存信息</div>
<Row>
<Col span={1}></Col>
<Col span={22}>
<div>
<Button type='primary' icon={<PlusOutlined />} style={{ marginBottom: '10px' }}>
新增规格
</Button>
<Table bordered columns={skuTableColumns} />
</div>
</Col>
</Row>
</div>
);
};
export default SkuInfo;
import GoodsInfo from './components/goodsInfo';
import RentAttr from './components/rentAttr';
import RentInfo from './components/rentInfo';
import SkuInfo from './components/skuInfo';
const RentAddOrEdit = () => {
return (
<div className='rent-create-edit'>
{/*商品信息*/}
<GoodsInfo />
{/*商品属性*/}
<RentAttr />
{/*租赁信息*/}
<RentInfo />
{/*价格库存信息*/}
<SkuInfo />
</div>
);
};
export default RentAddOrEdit;
import BaseInfo from '~/components/goods/commonAddOrEdit/baseInfo';
import StockSku from '~/components/goods/commonAddOrEdit/stockSku';
import OtherInfo from '~/components/goods/commonAddOrEdit/otherInfo';
import GoodsIntroduce from '~/components/goods/commonAddOrEdit/goodsIntroduce';
import AddOrEditSkuModal from '~/components/goods/commonAddOrEdit/addOrEditSkuModal';
import { Button, message } from 'antd';
import { useNavigate, useSearchParams } from 'react-router-dom';
import './index.scss';
import { useEffect, useRef, useState } from 'react';
import { CategoryManageAPI } from '~/api';
import { InterDataType } from '~/api/interface';
import { categoryListType } from '~/api/interface/categoryManage';
import {
customizeEntity,
detailGoodsType,
skuUnitType,
specEntity,
} from '~/api/interface/goodsType';
import goodsAPI from '~/api/modules/goodsAPI';
import { filterObjAttr } from '~/utils';
import GoodsAPI from '~/api/modules/goodsAPI';
import { UploadFile } from 'antd/es/upload/interface';
//分类返回类型
type categoryType = InterDataType<categoryListType>['list'];
//产品-规格单位返回类型
type unitType = InterDataType<skuUnitType>;
//商品返回类型
type goodsDetailType = InterDataType<detailGoodsType>;
const GoodsAddOrEditOrDetail = () => {
const [searchParams] = useSearchParams();
//基本信息ref
const baseInfoRef = useRef<any>();
const navigate = useNavigate();
//当前目录
const [currentDesc, setCurrentDesc] = useState<number>(-1);
//分类
const [categoryList, setCategoryList] = useState<categoryType>([]);
//添加、编辑库存规格弹窗
const [addOrEditSkuModalShow, setAddOrEditSkuModalShow] = useState(false);
//库存规格数据
const [specData, setSpecData] = useState<specEntity[]>([]);
const [goodsSpecCopy, setGoodsSpecCopy] = useState<specEntity[]>([]);
//产品规格-单位
const [skuUnitList, setSkuUnitList] = useState<unitType>([]);
//其它服务
const [otherService, setOtherService] = useState<number[]>([]);
// 当前操作行数据
const [curtRowData, setCurtRowData] = useState<Partial<specEntity>>({});
//商品详情
const [goodsDetail, setGoodsDetail] = useState<goodsDetailType>();
//产品介绍
const [productIntroduce, setProductIntroduce] = useState<string>('');
//是否商品详情
const [isDetail, setIsDetail] = useState<boolean>(false);
//添加、编辑规格
const addOrEditSkuShowEvent = (record?: specEntity) => {
const baseInfoForm = baseInfoRef.current.baseInform;
setCurrentDesc(baseInfoForm.getFieldValue('directoryId') || -1);
if (!baseInfoForm.getFieldValue('directoryId')) {
return message.warning('请先选择目录');
}
if (record) {
setCurtRowData({ ...record });
}
setAddOrEditSkuModalShow(true);
};
//删除规格
const deleteSkuEvent = (record: specEntity) => {
const index = specData.findIndex((v) => v.id === record.id);
specData.splice(index, 1);
setSpecData([...specData]);
};
const addOrEditSkuModalCancel = () => {
setAddOrEditSkuModalShow(false);
setCurtRowData({});
};
const addOrEditSkuModalOk = (data: specEntity) => {
if (Object.keys(curtRowData).length != 0) {
const index: number = specData.findIndex((i) => i.id === data.id);
specData.splice(index, 1, data);
setSpecData([...specData]);
} else {
setSpecData([...specData, data]);
}
addOrEditSkuModalCancel();
};
//根据目录获取分类列表
const getCategoryList = (directoryId: number) => {
CategoryManageAPI.getCategoryList({ directoryId, type: 2, pageSize: 9999, pageNo: 1 }).then(
({ result }) => {
setCategoryList(result.list || []);
},
);
};
//产品-单位
const getSkuUnit = () => {
goodsAPI.getSkuUnit().then(({ result }) => {
setSkuUnitList(result || []);
});
};
//其它服务选择
const otherServiceSelect = (ids: number[]) => {
setOtherService(ids);
};
//获取产品详情
const getRichText = (html?: string) => {
setProductIntroduce(html || '');
};
//商品详情
const getGoodsDetail = (goodsInfoId: number) => {
GoodsAPI.getGoodsDetail({ goodsInfoId, type: 1, leaseTerm: 0 }).then(({ result }) => {
setGoodsDetail(result);
getCategoryList(result.directoryId);
const specList: specEntity[] = result.goodsSpec.reduce((pre: any, cur: specEntity) => {
// 自定义
if (cur.flag === 1) {
const cusList: customizeEntity[] =
cur.productSpecList &&
cur.productSpecList.reduce((preProd: any, curProd: customizeEntity, index: number) => {
const obj: UploadFile = {
uid: `img${index}`,
status: 'done',
url: curProd.specImage,
name: 'image',
};
preProd.push({ ...curProd, fileList: [obj] });
return preProd;
}, []);
cur.customizeInfo = cusList;
} else {
const specId: number[] =
result.directoryId === 2
? cur.industrySpecList &&
cur.industrySpecList.map((curIndu: any) => {
return {
mallSpecId: curIndu.industrySpecId,
specName: curIndu.specName,
partNo: curIndu.partNo,
id: curIndu.id,
};
})
: cur.productSpecList &&
cur.productSpecList.map((item: any) => {
return {
mallSpecId: item.productSpec,
specName: item.specName,
partNo: item.partNo,
id: item.id,
};
});
cur.specIds = specId;
}
pre.push({ ...cur, productName: cur.skuName });
return pre;
}, []);
setGoodsSpecCopy(result.goodsSpec);
setOtherService(result.otherService.map((v) => v.saleServiceId));
setSpecData(specList);
});
};
//保存
const saveSubmit = () => {
const baseInfoForm = baseInfoRef.current.baseInform;
baseInfoForm.validateFields().then((values: any) => {
if (specData.length === 0) {
return message.warning('清添加库存规格');
}
//主图
values.images = [
{
imgType: 0,
imgUrl: values.mainImg[0].url,
id: goodsDetail
? goodsDetail.images.some((i) => i.id === values.mainImg[0].id)
? values.mainImg[0].id
: undefined
: undefined,
},
];
//副图
if (values.subImg) {
values.images.push(
...values.subImg.map((v: any) => ({
imgType: 1,
imgUrl: v.url,
id: goodsDetail
? goodsDetail.images.some((i) => i.id === v.id)
? v.id
: undefined
: undefined,
})),
);
}
//分类
values.categoryByOne = values.masterTypeId[0];
values.categoryByTwo = values.masterTypeId[1] || undefined;
// 过滤对象属性
const goodsSpecVO: specEntity[] = specData.reduce((pre: any, cur: specEntity) => {
cur.customizeInfo = cur.customizeInfo?.reduce((cusPre: any, cusCur: customizeEntity) => {
const bol: boolean = goodsSpecCopy.some((i: specEntity) => {
return i.customizeInfo?.some((i: customizeEntity) => i.id === cusCur.id);
});
cusPre = [
...cusPre,
bol ? filterObjAttr(cusCur, ['fileList']) : filterObjAttr(cusCur, ['id', 'fileList']),
];
return cusPre;
}, []);
// 存在对象属性改变!
cur.specIds = cur.specIds?.reduce((preSpec: any, curSpec: any) => {
preSpec = [...preSpec, filterObjAttr(curSpec, ['specName', 'partNo'])];
return preSpec;
}, []);
// 是否新增
const isAdd: boolean = goodsSpecCopy.every((i: specEntity) => i.id != cur.id);
// 是否修改了某一条
const isEdit: boolean = goodsSpecCopy.every(
(i: specEntity) => i.categoryId != cur.categoryId,
);
pre = [
...pre,
!isAdd
? isEdit
? filterObjAttr(cur, ['industrySpecList', 'productSpecList', 'skuName', 'id'])
: filterObjAttr(cur, ['industrySpecList', 'productSpecList', 'skuName'])
: filterObjAttr(cur, ['id', 'skuName']),
];
return pre;
}, []);
goodsAPI[goodsDetail ? 'editGoods' : 'addGoods']({
...filterObjAttr(values, ['mainImg', 'subImg', 'video', 'masterTypeId', 'id', 'goodsDesc']),
productSpec: goodsSpecVO,
goodsType: 1,
goodsDetailVO: { goodsDesc: values.goodsDesc, productDesc: productIntroduce },
otherService: otherService,
id: goodsDetail ? goodsDetail.id : undefined,
}).then(({ code }) => {
if (code === '200') {
message.success(goodsDetail ? '编辑成功' : '新增成功');
navigate(-1);
}
});
});
};
//返回
const backRoute = () => {
navigate(-1);
};
useEffect(() => {
if (searchParams.get('id')) {
getGoodsDetail(Number(searchParams.get('id')));
}
setIsDetail(!!searchParams.get('isDetail'));
getSkuUnit();
}, []);
return (
<div className='goods-info'>
{/* 基本信息*/}
<BaseInfo
ref={baseInfoRef}
categoryList={categoryList}
getCategoryList={getCategoryList}
goodsDetail={goodsDetail}
isDetail={isDetail}
goodsType={1}
/>
{/* 库存规格*/}
<StockSku
addOrEditSku={addOrEditSkuShowEvent}
specData={specData}
skuUnitList={skuUnitList}
deleteSku={deleteSkuEvent}
isDetail={isDetail}
/>
{/*其它信息*/}
<OtherInfo
otherServiceSelect={otherServiceSelect}
goodsDetail={goodsDetail}
isDetail={isDetail}
/>
{/*产品介绍图*/}
<GoodsIntroduce getRichText={getRichText} goodsDetail={goodsDetail} isDetail={isDetail} />
{/*库存规格,添加、编辑弹窗*/}
<AddOrEditSkuModal
currentDesc={currentDesc}
open={addOrEditSkuModalShow}
handleCancel={addOrEditSkuModalCancel}
handleOk={addOrEditSkuModalOk}
skuUnitList={skuUnitList}
curtRowData={curtRowData}
goodsType={1}
/>
<div className='goods-info-operate'>
{!isDetail && (
<Button type='primary' onClick={saveSubmit}>
保存
</Button>
)}
<Button onClick={backRoute}>返回</Button>
</div>
</div>
);
};
export default GoodsAddOrEditOrDetail;
import SearchBox, { searchColumns } from '~/components/search-box'; import SearchBox, { searchColumns as searchColumnsType } from '~/components/search-box';
import React, { useEffect, useRef, useState } from 'react'; import { Button, Card, Table } from 'antd';
import { useNavigate, useSearchParams } from 'react-router-dom';
import { Button, Card, Image, message, Modal, Table } from 'antd';
import { import {
ArrowDownOutlined, ArrowDownOutlined,
ArrowUpOutlined, ArrowUpOutlined,
DeleteOutlined, DeleteOutlined,
PlusOutlined, PlusOutlined,
} from '@ant-design/icons'; } from '@ant-design/icons';
import { useState } from 'react';
import { ColumnsType } from 'antd/es/table'; import { ColumnsType } from 'antd/es/table';
import GoodsAPI from '~/api/modules/goodsAPI'; import { useNavigate } from 'react-router-dom';
import { InterDataType, InterReqType, PaginationProps } from '~/api/interface';
import { listGoodsType } from '~/api/interface/goodsType';
import { CategoryManageAPI } from '~/api';
import { filterObjAttr } from '~/utils';
import qs from 'query-string';
//商品返回类型
type goodsType = InterDataType<listGoodsType>['list'];
//商品列表筛选类型
type goodsSearchParameters = Omit<InterReqType<listGoodsType>, 'goodsType'>;
const RentList = () => { const RentList = () => {
//筛选ref
const searchRef = useRef();
const navigate = useNavigate(); const navigate = useNavigate();
const [searchParams, setSearchParams] = useSearchParams(); const searchColumns: searchColumnsType[] = [
{
label: '商品名称',
name: '',
type: 'input',
placeholder: '请输入商品名称',
},
{
label: '商品类型',
name: '',
type: 'select',
placeholder: '请选择商品类型',
options: [],
},
{
label: '商品品牌',
name: '',
type: 'select',
placeholder: '请选择商品品牌',
options: [],
},
];
const tabList = [ const tabList = [
{ {
key: '1', key: '1',
...@@ -40,416 +49,81 @@ const RentList = () => { ...@@ -40,416 +49,81 @@ const RentList = () => {
}, },
]; ];
const [activeTabKey, setActiveTabKey] = useState<string>('1'); const [activeTabKey, setActiveTabKey] = useState<string>('1');
const [searchColumns, setSearchColumns] = useState<searchColumns[]>([ const tableColumns: ColumnsType<any> = [
{ {
label: '商品名称', title: '商品名称',
placeholder: '请输入商品名称', align: 'center',
name: 'goodsName',
type: 'input',
}, },
{ {
label: '所属目录', title: '押金范围',
placeholder: '请选择所属目录', align: 'center',
name: 'directoryId',
type: 'select',
options: [],
}, },
{ {
label: '创建时间', title: '租金范围(日)',
placeholder: '请输入选择创建时间', align: 'center',
name: 'time',
type: 'rangePicker',
}, },
]);
const tableColumns: ColumnsType<goodsType[0]> = [
{ {
title: '序号', title: '库存',
align: 'center', align: 'center',
render: (_text: any, _record, index: number) =>
(pagination.pageNo - 1) * pagination.pageSize + index + 1,
}, },
{ {
title: '图片', title: '销量',
align: 'center', 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: '状态', title: '创建时间',
align: 'center', align: 'center',
dataIndex: 'status',
render: (text: number) => (text ? '上架' : '下架'),
}, },
{ {
title: '操作', title: '操作',
align: 'center', align: 'center',
dataIndex: 'id', width: '20%',
render: (id: number) => ( render: () => (
<> <>
<Button type='link' onClick={() => toEditGoods(id)}> <Button type='link'>编辑</Button>
编辑 <Button type='link'>详情</Button>
</Button> <Button type='link'>上架</Button>
<Button type='link' onClick={() => toRentGoodsDetail(id)}> <Button type='link'>下架</Button>
详情 <Button type='link' danger>
删除
</Button> </Button>
</> </>
), ),
}, },
]; ];
const [tableData, setTableData] = useState<goodsType>([]); const [tableData] = useState<any>([{ id: 1 }]);
const [allRentGoods, setAllRentGoods] = useState<goodsType>([]);
const [loading, setLoading] = useState<boolean>(false);
//分页
const [pagination, setPagination] = useState<
PaginationProps & { totalCount: number; totalPage: number }
>({
pageNo: 1,
pageSize: 10,
totalCount: 0,
totalPage: 1,
});
//筛选
const [query, setQuery] = useState<goodsSearchParameters>({ status: undefined });
// 表格多选
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
const onTabChange = (key: string) => { const onTabChange = (key: string) => {
pagination.pageNo = 1;
pagination.pageSize = 10;
query.status = key === '1' ? undefined : key === '2' ? 1 : 0;
setSearchParams(
qs.stringify({
pageNo: 1,
pageSize: 10,
...query,
status: query.status === undefined ? 'all' : query.status,
}),
);
getGoodsList(query);
getGoodsList({ ...query, pageNo: 1, pageSize: 9999 }, true);
setQuery(query);
setActiveTabKey(key); setActiveTabKey(key);
}; };
const paginationChange = (pageNo: number, pageSize: number) => { //新增,编辑租赁商品
pagination.pageSize = pageSize; const addOrEditClick = () => {
pagination.pageNo = pageNo;
setSearchParams(
qs.stringify({
pageNo: pageNo,
pageSize: pageSize,
...query,
status: query.status === undefined ? 'all' : query.status,
}),
);
getGoodsList(query);
getGoodsList({ ...query, pageNo: 1, pageSize: 9999 }, true);
};
//筛选
const searchSuccess = (data: any) => {
pagination.pageNo = 1;
pagination.pageSize = 10;
setQuery({ ...filterObjAttr(data, ['time']), status: query.status });
getGoodsList({ ...filterObjAttr(data, ['time']), status: query.status });
getGoodsList(
{ ...filterObjAttr(data, ['time']), status: query.status, pageNo: 1, pageSize: 9999 },
true,
);
setSearchParams(
qs.stringify({
pageNo: 1,
pageSize: 10,
...filterObjAttr(data, ['time']),
status: query.status === undefined ? 'all' : query.status,
}),
);
};
//商品列表
const getGoodsList = (query?: goodsSearchParameters, isAll?: boolean) => {
setLoading(true);
GoodsAPI.getGoodsList({
pageNo: pagination.pageNo,
pageSize: pagination.pageSize,
goodsType: 1,
...query,
}).then(({ result }) => {
setLoading(false);
if (isAll) {
setAllRentGoods(result.list || []);
} else {
setTableData(result.list || []);
pagination.totalCount = result.totalCount;
pagination.totalPage = result.totalPage;
setPagination(pagination);
}
});
};
//新增商品
const toAddRentGoods = () => {
navigate({ pathname: '/rentManage/rentGoods/add' }); navigate({ pathname: '/rentManage/rentGoods/add' });
}; };
//编辑商品
const toEditGoods = (id: number) => {
navigate({
pathname: '/rentManage/rentGoods/edit',
search: `id=${id}`,
});
};
//商品详情
const toRentGoodsDetail = (id: number) => {
navigate({
pathname: '/rentManage/rentGoods/detail',
search: `id=${id}&isDetail=1`,
});
};
// 表格多选事件
const onSelectChange = (newSelectedRowKeys: React.Key[]) => {
setSelectedRowKeys(newSelectedRowKeys);
};
//获取目录列表
const getDirectoryList = () => {
CategoryManageAPI.getDirectoryListClone({ type: 2 }).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('请先选择商品');
}
Modal.confirm({
title: '提示',
content: '删除后数据将会丢失,确定删除吗?',
onOk() {
GoodsAPI.batchRemoveWareInfo(selectedRowKeys as number[]).then(({ code }) => {
if (code === '200') {
if (pagination.pageNo !== 1 && tableData.length == 1) {
pagination.pageNo -= 1;
}
message.success('删除成功');
getGoodsList(query);
}
});
},
});
};
//上移
const upGoodsRentClick = () => {
if (selectedRowKeys.length === 0) {
message.warning('请选择商品');
} else if (selectedRowKeys.length > 1) {
message.warning('最多选择一个商品');
} else {
const index = tableData.findIndex((v) => v.id === selectedRowKeys[0]);
const allIndex = allRentGoods.findIndex((v) => v.id === selectedRowKeys[0]);
if (index === 0 && pagination.pageNo === 1) {
message.warning('位置已到最前列,无法上移');
} else {
const exReqData =
index === 0
? allRentGoods
.filter((_v, index) => index === allIndex - 1 || index === allIndex)
.map((v) => ({ id: v.id }))
: tableData
.filter((_v, i) => index - 1 === i || index === i)
.map((v) => ({ id: v.id }));
GoodsAPI.exchangeGoodsInfo({ firstId: exReqData[0].id, secondId: exReqData[1].id }).then(
({ code }) => {
if (code === '200') {
message.success('上移成功');
if (index === 0 && pagination.pageNo !== 1) {
pagination.pageNo -= 1;
setSearchParams(
qs.stringify({
pageNo: pagination.pageNo,
pageSize: pagination.pageSize,
...query,
status: query.status === undefined ? 'all' : query.status,
}),
);
}
getGoodsList(query);
getGoodsList({ ...query, pageNo: 1, pageSize: 9999 }, true);
}
},
);
}
}
};
//下移
const downRentGoodsClick = () => {
if (selectedRowKeys.length === 0) {
message.warning('请选择商品');
} else if (selectedRowKeys.length > 1) {
message.warning('最多选择一个商品');
} else {
const index = tableData.findIndex((v) => v.id === selectedRowKeys[0]);
const allIndex = allRentGoods.findIndex((v) => v.id === selectedRowKeys[0]);
if (index === tableData.length - 1 && pagination.pageNo === pagination.totalPage) {
message.warning('位置已到最后,无法下移');
} else {
const exReqData =
index === tableData.length - 1
? allRentGoods
.filter((_v, index) => index === allIndex + 1 || index === allIndex)
.map((v) => ({ id: v.id }))
: tableData
.filter((_v, i) => index + 1 === i || index === i)
.map((v) => ({ id: v.id }));
GoodsAPI.exchangeGoodsInfo({ firstId: exReqData[0].id, secondId: exReqData[1].id }).then(
({ code }) => {
if (code === '200') {
message.success('下移成功');
if (index === tableData.length - 1 && pagination.pageNo !== pagination.totalPage) {
pagination.pageNo += 1;
setSearchParams(
qs.stringify({
pageNo: pagination.pageNo,
pageSize: pagination.pageSize,
...query,
status: query.status === undefined ? 'all' : query.status,
}),
);
}
getGoodsList(query);
getGoodsList({ ...query, pageNo: 1, pageSize: 9999 }, true);
}
},
);
}
}
};
useEffect(() => {
getDirectoryList();
pagination.pageNo = Number(searchParams.get('pageNo') || 1);
pagination.pageSize = Number(searchParams.get('pageSize') || 10);
const queryObj = {
goodsName: searchParams.get('goodsName') || undefined,
directoryId: searchParams.get('directoryId')
? Number(searchParams.get('directoryId'))
: undefined,
startTime: searchParams.get('startTime') || undefined,
endTime: searchParams.get('endTime') || undefined,
status:
searchParams.get('status') === 'all' || searchParams.get('status') === null
? undefined
: Number(searchParams.get('status')),
};
getGoodsList(queryObj);
getGoodsList({ ...queryObj, pageSize: 9999, pageNo: 1 }, true);
setActiveTabKey(
searchParams.get('status') === 'all' || searchParams.get('status') === null
? '1'
: Number(searchParams.get('status')) === 1
? '2'
: '3',
);
(searchRef.current as any).getForm().setFieldsValue({
goodsName: searchParams.get('goodsName') || undefined,
directoryId: searchParams.get('directoryId')
? Number(searchParams.get('directoryId'))
: undefined,
time: searchParams.get('startTime')
? [searchParams.get('startTime'), searchParams.get('endTime')]
: undefined,
});
}, []);
return ( return (
<div className='goods-list'> <div className='rent-list'>
<SearchBox <SearchBox
search={searchColumns} search={searchColumns}
child={ child={
<Button type='primary' icon={<PlusOutlined />} onClick={toAddRentGoods}> <Button icon={<PlusOutlined />} type='primary' onClick={addOrEditClick}>
新增商品 新增商品
</Button> </Button>
} }
searchData={searchSuccess}
baseRef={searchRef}
/> />
<Card tabList={tabList} activeTabKey={activeTabKey} onTabChange={onTabChange}> <Card tabList={tabList} activeTabKey={activeTabKey} onTabChange={onTabChange}>
<div className='header-operate' style={{ marginBottom: '10px' }}> <div className='table-operate' style={{ marginBottom: '10px' }}>
<Button <Button type='primary' icon={<ArrowUpOutlined />} style={{ marginRight: '10px' }}>
type='primary' 批量上架
style={{ marginRight: '10px' }}
icon={<ArrowUpOutlined />}
onClick={upGoodsRentClick}
>
上移
</Button>
<Button
type='primary'
style={{ marginRight: '10px' }}
icon={<ArrowDownOutlined />}
onClick={downRentGoodsClick}
>
下移
</Button> </Button>
{activeTabKey !== '2' && ( <Button type='primary' icon={<ArrowDownOutlined />} style={{ marginRight: '10px' }}>
<Button 批量下架
type='primary'
style={{ marginRight: '10px' }}
icon={<ArrowUpOutlined />}
onClick={() => batchOnShelfOrTakeDown(1)}
>
上架
</Button> </Button>
)} <Button type='primary' danger icon={<DeleteOutlined />}>
{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 <Table bordered columns={tableColumns} rowKey='id' dataSource={tableData} />
columns={tableColumns}
bordered
dataSource={tableData}
rowKey='id'
rowSelection={{
selectedRowKeys,
onChange: onSelectChange,
}}
loading={loading}
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>
); );
......
...@@ -6,11 +6,14 @@ import { useEffect, useState } from 'react'; ...@@ -6,11 +6,14 @@ import { useEffect, useState } from 'react';
import { RentManageAPI } from '~/api'; import { RentManageAPI } from '~/api';
import { InterDataType, PaginationProps } from '~/api/interface'; import { InterDataType, PaginationProps } from '~/api/interface';
import { listBrandInfoType } from '~/api/interface/rentManageType'; import { listBrandInfoType } from '~/api/interface/rentManageType';
import { useNavigate } from 'react-router-dom';
//品牌列表返回类型 //品牌列表返回类型
type makeListType = InterDataType<listBrandInfoType>['list']; type makeListType = InterDataType<listBrandInfoType>['list'];
const RentMake = () => { const RentMake = () => {
const navigate = useNavigate();
const tableColumns: ColumnsType<makeListType[0]> = [ const tableColumns: ColumnsType<makeListType[0]> = [
{ {
title: '品牌名称', title: '品牌名称',
...@@ -30,7 +33,9 @@ const RentMake = () => { ...@@ -30,7 +33,9 @@ const RentMake = () => {
width: '15%', width: '15%',
render: (_: any, record) => ( render: (_: any, record) => (
<> <>
<Button type='link'>绑定型号</Button> <Button type='link' onClick={() => addRentModeClick(record)}>
新增型号
</Button>
<Button type='link' onClick={() => addOrEditRentMakeModalClick(record)}> <Button type='link' onClick={() => addOrEditRentMakeModalClick(record)}>
编辑 编辑
</Button> </Button>
...@@ -71,6 +76,14 @@ const RentMake = () => { ...@@ -71,6 +76,14 @@ const RentMake = () => {
getListBrandInfo(); getListBrandInfo();
setAddOrEditRentMakeModalShow(false); setAddOrEditRentMakeModalShow(false);
}; };
//品牌新增型号
const addRentModeClick = (record: makeListType[0]) => {
navigate({
pathname: '/rentManage/rentModel',
search: `brandInfoId=${record.id}&brandName=${record.brandName}`,
});
};
//分页 //分页
const paginationChange = (pageNo: number, pageSize: number) => { const paginationChange = (pageNo: number, pageSize: number) => {
pagination.pageNo = pageNo; pagination.pageNo = pageNo;
......
import { Form, Input, Modal, ModalProps, Select } from 'antd'; import { Button, Col, Form, Input, message, Modal, ModalProps, Row, Select } from 'antd';
import { FC, useEffect, useState } from 'react'; import { FC, useEffect, useState } from 'react';
import { InterDataType, InterReqType } from '~/api/interface'; import { InterDataType, InterReqType } from '~/api/interface';
import { addRentModeType, getTypeListType } from '~/api/interface/rentManageType'; import { addRentModeType, getTypeListType, rentModeListType } from '~/api/interface/rentManageType';
import { RentManageAPI } from '~/api'; import { RentManageAPI } from '~/api';
import { MinusOutlined, PlusOutlined } from '@ant-design/icons';
interface selfProps { interface selfProps {
onOk: () => void; onOk: () => void;
onCancel: () => void; onCancel: () => void;
brandInfoId: number;
rentTypeList: rentTypeListType;
currentRentMode: modeListType[0] | undefined;
} }
//型号新增参数类型 //型号新增参数类型
type addRentParameterType = Exclude<InterReqType<addRentModeType>, undefined>; type addRentParameterType = Exclude<InterReqType<addRentModeType>, undefined>;
//类型类别返回类型 //类型类别返回类型
type rentTypeListType = InterDataType<getTypeListType>['list']; type rentTypeListType = InterDataType<getTypeListType>['list'];
//型号返回类型
type modeListType = InterDataType<rentModeListType>['list'];
const AddOrEditRentModeModal: FC<ModalProps & selfProps> = ({ open, onOk, onCancel }) => { const AddOrEditRentModeModal: FC<ModalProps & selfProps> = ({
open,
onOk,
onCancel,
brandInfoId,
rentTypeList,
currentRentMode,
}) => {
const [form] = Form.useForm<addRentParameterType>(); const [form] = Form.useForm<addRentParameterType>();
const [rentTypeList, setRentTypeList] = useState<rentTypeListType>([]);
//标签数组
const [tagList, setTagList] = useState<{ id: number; tagName: string }[]>([
{ id: Math.random(), tagName: 'tag1' },
]);
const handleOk = () => { const handleOk = () => {
form.validateFields().then((values) => { form.validateFields().then((values: any) => {
RentManageAPI.addRentMode({ ...values }).then(({ code }) => { const covertTagList = tagList.reduce((pre: string[], cur) => {
const tagKeyItem: string | undefined = Object.keys(values).find(
(key: string) => key === cur.tagName,
);
if (tagKeyItem && values[tagKeyItem]) {
pre.push(values[tagKeyItem]);
}
return pre;
}, []);
RentManageAPI.addRentMode({
productTypeId: values.productTypeId,
modeName: values.modeName,
tag: covertTagList.length ? covertTagList.join(',') : undefined,
brandInfoId,
}).then(({ code }) => {
if (code === '200') { if (code === '200') {
message.success('新增成功');
form.resetFields(); form.resetFields();
onOk(); onOk();
} }
...@@ -32,20 +64,44 @@ const AddOrEditRentModeModal: FC<ModalProps & selfProps> = ({ open, onOk, onCanc ...@@ -32,20 +64,44 @@ const AddOrEditRentModeModal: FC<ModalProps & selfProps> = ({ open, onOk, onCanc
form.resetFields(); form.resetFields();
onCancel(); onCancel();
}; };
//获取类型列表
const getRentTypeList = () => { //新增标签
RentManageAPI.getTypeList({ pageNo: 1, pageSize: 99999 }).then(({ result }) => { const addTagClick = () => {
setRentTypeList(result.list || []); setTagList([...tagList, { id: Math.random(), tagName: `tag${tagList.length + 1}` }]);
}); };
//删除标签
const deleteTagClick = (index: number) => {
form.setFieldValue(tagList[index].tagName, undefined);
tagList.splice(index, 1);
setTagList([...tagList]);
}; };
useEffect(() => { useEffect(() => {
getRentTypeList(); if (currentRentMode) {
}, []); form.setFieldsValue({
productTypeId: currentRentMode.productTypeId,
modeName: currentRentMode.modeName,
...currentRentMode.tag?.split(',').reduce((pre: any, cur, currentIndex) => {
pre['tag' + (currentIndex + 1)] = cur;
return pre;
}, {}),
});
setTagList(
currentRentMode.tag
?.split(',')
.map((_v, index) => ({ id: Math.random(), tagName: `tag${index + 1}` })) || [],
);
}
}, [currentRentMode]);
return ( return (
<Modal open={open} onOk={handleOk} onCancel={handleCancel} title='新增型号'> <Modal
<Form form={form}> open={open}
onOk={handleOk}
onCancel={handleCancel}
title={currentRentMode ? '编辑型号' : '新增型号'}
>
<Form form={form} labelCol={{ span: 4 }} wrapperCol={{ span: 20 }}>
<Form.Item <Form.Item
label='所属类别' label='所属类别'
name='productTypeId' name='productTypeId'
...@@ -66,6 +122,42 @@ const AddOrEditRentModeModal: FC<ModalProps & selfProps> = ({ open, onOk, onCanc ...@@ -66,6 +122,42 @@ const AddOrEditRentModeModal: FC<ModalProps & selfProps> = ({ open, onOk, onCanc
> >
<Input placeholder='请输入型号名称' maxLength={30} /> <Input placeholder='请输入型号名称' maxLength={30} />
</Form.Item> </Form.Item>
{tagList.map((v, index) => (
<Row key={v.id}>
<Col span={20}>
<Form.Item
label={index ? '' : '标签'}
labelCol={{ span: 5 }}
wrapperCol={{ span: 19, offset: index ? 5 : 0 }}
name={v.tagName}
>
<Input placeholder='请输入标签名称' />
</Form.Item>
</Col>
<Col span={3} offset={1}>
{index === tagList.length - 1 ? (
<Button
type='primary'
icon={<PlusOutlined />}
style={{ marginRight: '5px' }}
onClick={addTagClick}
></Button>
) : (
''
)}
{index ? (
<Button
type='primary'
icon={<MinusOutlined />}
onClick={() => deleteTagClick(index)}
></Button>
) : (
''
)}
</Col>
</Row>
))}
</Form> </Form>
</Modal> </Modal>
); );
......
import SearchBox, { searchColumns as searchColumnsType } from '~/components/search-box'; import SearchBox, { searchColumns as searchColumnsType } from '~/components/search-box';
import { Button, Table } from 'antd'; import { Button, Modal, Table, Tag } from 'antd';
import { PlusOutlined } from '@ant-design/icons'; import { PlusOutlined } from '@ant-design/icons';
import { ColumnsType } from 'antd/es/table/InternalTable'; import { ColumnsType } from 'antd/es/table/InternalTable';
import AddOrEditRentModeModal from '~/pages/rentManage/rentMode/components/addOrEditRentModeModal'; import AddOrEditRentModeModal from '~/pages/rentManage/rentMode/components/addOrEditRentModeModal';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { RentManageAPI } from '~/api'; import { RentManageAPI } from '~/api';
import { PaginationProps } from '~/api/interface'; import { InterDataType, InterReqListType, PaginationProps } from '~/api/interface';
import { useSearchParams, useNavigate } from 'react-router-dom';
import { getTypeListType, rentModeListType } from '~/api/interface/rentManageType';
//类型类别返回类型
type rentTypeListType = InterDataType<getTypeListType>['list'];
//型号返回类型
type modeListType = InterDataType<rentModeListType>['list'];
//型号列表参数类型
type modeListParametersType = InterReqListType<rentModeListType>;
const RentMode = () => { const RentMode = () => {
const tableColumns: ColumnsType<any> = [ const [searchParams] = useSearchParams();
const navigate = useNavigate();
const [rentTypeList, setRentTypeList] = useState<rentTypeListType>([]);
const tableColumns: ColumnsType<modeListType[0]> = [
{ {
title: '型号名称', title: '型号名称',
align: 'center', align: 'center',
dataIndex: 'modeName',
}, },
{ {
title: '所属类型', title: '所属类型',
align: 'center', align: 'center',
}, dataIndex: 'productTypeId',
{ render: (text: number) => rentTypeList.find((v) => v.id === text)?.name || '',
title: '所属品牌',
align: 'center',
}, },
{ {
title: '标签', title: '标签',
align: 'center', align: 'center',
dataIndex: 'tag',
render: (text: string) => text?.split(',').map((v, index) => <Tag key={index}>{v}</Tag>),
}, },
{ {
title: '操作', title: '操作',
align: 'center', align: 'center',
width: '10%',
render: (_: any, record) => (
<>
<Button type='link' onClick={() => addOrEditRentModelClick(record)}>
编辑
</Button>
<Button type='link' onClick={() => deleteRentModelClick(record)}>
删除
</Button>
</>
),
}, },
]; ];
const searchColumns: searchColumnsType[] = [ const searchColumns: searchColumnsType[] = [
{ {
name: '', name: 'productTypeId',
label: '设备类型', label: '所属类型',
placeholder: '请选择设备类型', placeholder: '请选择所属类型',
type: 'select', type: 'select',
options: [], options: rentTypeList.map((v) => ({ id: v.id, name: v.name })),
}, },
]; ];
const [brandInfoId, setBrandInfoId] = useState<number>(-1);
const [addOrEditRentModelModalShow, setAddOrEditRentModelModalShow] = useState<boolean>(false); const [addOrEditRentModelModalShow, setAddOrEditRentModelModalShow] = useState<boolean>(false);
const [pagination, setPagination] = useState<PaginationProps & { totalCount: number }>({ const [pagination, setPagination] = useState<PaginationProps & { totalCount: number }>({
pageNo: 1, pageNo: 1,
pageSize: 10, pageSize: 10,
totalCount: 0, totalCount: 0,
}); });
const [tableData, setTableData] = useState<modeListType>([]);
const [query, setQuery] = useState<modeListParametersType>();
const [currentRentMode, setCurrentRentMode] = useState<modeListType[0]>();
//新增,编辑型号弹窗 //新增,编辑型号弹窗
const addOrEditRentModelClick = () => { const addOrEditRentModelClick = (record?: modeListType[0]) => {
setCurrentRentMode(record ? { ...record } : undefined);
setAddOrEditRentModelModalShow(true); setAddOrEditRentModelModalShow(true);
}; };
const addOrEditRentModelModalCancel = () => { const addOrEditRentModelModalCancel = () => {
setAddOrEditRentModelModalShow(false); setAddOrEditRentModelModalShow(false);
}; };
const addOrEditRentModelModalOk = () => { const addOrEditRentModelModalOk = () => {
setAddOrEditRentModelModalShow(true); setAddOrEditRentModelModalShow(false);
getModeList(brandInfoId, query);
}; };
//类型列表 //删除型号
const getModeList = () => { const deleteRentModelClick = (record: modeListType[0]) => {
Modal.confirm({
title: '提示',
content: '确认删除该型号?',
onOk: () => {},
});
};
//型号列表
const getModeList = (brandInfoId: number, query?: modeListParametersType) => {
RentManageAPI.getRentModeList({ RentManageAPI.getRentModeList({
pageNo: pagination.pageNo, pageNo: pagination.pageNo,
pageSize: pagination.pageSize, pageSize: pagination.pageSize,
brandInfoId,
...query,
}).then(({ result }) => { }).then(({ result }) => {
pagination.totalCount = result.totalCount; pagination.totalCount = result.totalCount;
setTableData(result.list || []);
setPagination({ ...pagination }); setPagination({ ...pagination });
}); });
}; };
//获取类型列表
const getRentTypeList = () => {
RentManageAPI.getTypeList({ pageNo: 1, pageSize: 99999 }).then(({ result }) => {
setRentTypeList(result.list || []);
searchColumns[0].options = (result.list || []).map((v) => ({ id: v.id, name: v.name }));
});
};
//返回
const backRoute = () => {
navigate(-1);
};
//分页
const paginationChange = (pageNo: number, pageSize: number) => {
pagination.pageNo = pageNo;
pagination.pageSize = pageSize;
getModeList(brandInfoId, query);
};
//筛选
const searchSuccess = (value: modeListParametersType) => {
pagination.pageSize = 10;
pagination.pageNo = 1;
setQuery(value);
getModeList(brandInfoId, value);
};
useEffect(() => { useEffect(() => {
getModeList(); getRentTypeList();
setBrandInfoId(Number(searchParams.get('brandInfoId')));
getModeList(Number(searchParams.get('brandInfoId')));
}, []); }, []);
return ( return (
<div className='rent-model'> <div className='rent-model'>
<SearchBox <SearchBox
search={searchColumns} search={searchColumns}
child={ child={
<Button type='primary' icon={<PlusOutlined />} onClick={addOrEditRentModelClick}> <>
<span style={{ marginRight: '10px', color: '#1677ff' }}>
当前品牌:{searchParams.get('brandName')}
</span>
<Button
type='primary'
icon={<PlusOutlined />}
onClick={() => addOrEditRentModelClick()}
>
新增型号 新增型号
</Button> </Button>
</>
}
otherChild={
<Button type='primary' onClick={backRoute}>
返回
</Button>
} }
searchData={searchSuccess}
/>
<Table
bordered
columns={tableColumns}
dataSource={tableData}
rowKey='id'
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} 条数据`,
}}
/> />
<Table bordered columns={tableColumns} />
<AddOrEditRentModeModal <AddOrEditRentModeModal
open={addOrEditRentModelModalShow} open={addOrEditRentModelModalShow}
onCancel={addOrEditRentModelModalCancel} onCancel={addOrEditRentModelModalCancel}
onOk={addOrEditRentModelModalOk} onOk={addOrEditRentModelModalOk}
brandInfoId={brandInfoId}
rentTypeList={rentTypeList}
currentRentMode={currentRentMode}
/> />
</div> </div>
); );
......
...@@ -98,9 +98,7 @@ const ServiceIntroduceView = React.lazy( ...@@ -98,9 +98,7 @@ const ServiceIntroduceView = React.lazy(
); //服务介绍 ); //服务介绍
const RentListView = React.lazy(() => import('~/pages/rentManage/rentGoods/rentList')); //租赁列表 const RentListView = React.lazy(() => import('~/pages/rentManage/rentGoods/rentList')); //租赁列表
const RentAddOrEditOrDetailView = React.lazy( const RentAddOrEditView = React.lazy(() => import('~/pages/rentManage/rentGoods/rentAddOrEdit')); //租赁新增、编辑、详情
() => import('~/pages/rentManage/rentGoods/rentAddOrEditOrDetail'),
); //租赁新增、编辑、详情
const RentTypeView = React.lazy(() => import('~/pages/rentManage/rentType')); //租赁-类型管理 const RentTypeView = React.lazy(() => import('~/pages/rentManage/rentType')); //租赁-类型管理
const RentMakeView = React.lazy(() => import('~/pages/rentManage/rentMake')); //租赁-品牌管理 const RentMakeView = React.lazy(() => import('~/pages/rentManage/rentMake')); //租赁-品牌管理
const RentModeView = React.lazy(() => import('~/pages/rentManage/rentMode')); //租赁-型号管理 const RentModeView = React.lazy(() => import('~/pages/rentManage/rentMode')); //租赁-型号管理
...@@ -716,7 +714,7 @@ export const routerList: Array<RouteObjectType> = [ ...@@ -716,7 +714,7 @@ export const routerList: Array<RouteObjectType> = [
}, },
{ {
path: '/rentManage/rentGoods/add', path: '/rentManage/rentGoods/add',
element: withLoadingComponent(<RentAddOrEditOrDetailView />), element: withLoadingComponent(<RentAddOrEditView />),
errorElement: <ErrorPage />, errorElement: <ErrorPage />,
meta: { meta: {
id: 10135, id: 10135,
...@@ -727,7 +725,7 @@ export const routerList: Array<RouteObjectType> = [ ...@@ -727,7 +725,7 @@ export const routerList: Array<RouteObjectType> = [
}, },
{ {
path: '/rentManage/rentGoods/edit', path: '/rentManage/rentGoods/edit',
element: withLoadingComponent(<RentAddOrEditOrDetailView />), element: withLoadingComponent(<RentAddOrEditView />),
errorElement: <ErrorPage />, errorElement: <ErrorPage />,
meta: { meta: {
id: 10136, id: 10136,
...@@ -736,17 +734,17 @@ export const routerList: Array<RouteObjectType> = [ ...@@ -736,17 +734,17 @@ export const routerList: Array<RouteObjectType> = [
hidden: true, hidden: true,
}, },
}, },
{ // {
path: '/rentManage/rentGoods/detail', // path: '/rentManage/rentGoods/detail',
element: withLoadingComponent(<RentAddOrEditOrDetailView />), // element: withLoadingComponent(<RentAddOrEditView />),
errorElement: <ErrorPage />, // errorElement: <ErrorPage />,
meta: { // meta: {
id: 10136, // id: 10136,
icon: <SmileOutlined />, // icon: <SmileOutlined />,
title: '租赁商品详情', // title: '租赁商品详情',
hidden: true, // hidden: true,
}, // },
}, // },
{ {
path: '/rentManage/rentType', path: '/rentManage/rentType',
element: withLoadingComponent(<RentTypeView />), element: withLoadingComponent(<RentTypeView />),
...@@ -776,8 +774,9 @@ export const routerList: Array<RouteObjectType> = [ ...@@ -776,8 +774,9 @@ export const routerList: Array<RouteObjectType> = [
meta: { meta: {
id: 10139, id: 10139,
icon: <SmileOutlined />, icon: <SmileOutlined />,
title: '型号管理', title: '品牌管理/型号',
develop: true, develop: true,
hidden: true,
}, },
}, },
], ],
...@@ -792,20 +791,9 @@ export const routerList: Array<RouteObjectType> = [ ...@@ -792,20 +791,9 @@ export const routerList: Array<RouteObjectType> = [
title: '分类管理', title: '分类管理',
}, },
children: [ children: [
{
path: '/categoryManage/jobServicesCategory/1',
element: withLoadingComponent(<CategoryManage />),
errorElement: <ErrorPage />,
meta: {
id: 1210,
title: '作业服务分类',
icon: <SendOutlined />,
},
},
// 作业服务分类(新)
// { // {
// path: '/categoryManage/serviceCategoryList', // path: '/categoryManage/jobServicesCategory/1',
// element: withLoadingComponent(<ServiceCategoryListView />), // element: withLoadingComponent(<CategoryManage />),
// errorElement: <ErrorPage />, // errorElement: <ErrorPage />,
// meta: { // meta: {
// id: 1210, // id: 1210,
...@@ -813,6 +801,17 @@ export const routerList: Array<RouteObjectType> = [ ...@@ -813,6 +801,17 @@ export const routerList: Array<RouteObjectType> = [
// icon: <SendOutlined />, // icon: <SendOutlined />,
// }, // },
// }, // },
// 作业服务分类(新)
{
path: '/categoryManage/serviceCategoryList',
element: withLoadingComponent(<ServiceCategoryListView />),
errorElement: <ErrorPage />,
meta: {
id: 1210,
title: '作业服务分类',
icon: <SendOutlined />,
},
},
{ {
path: '/categoryManage/jobServicesCategory/2', path: '/categoryManage/jobServicesCategory/2',
element: withLoadingComponent(<CategoryManage />), element: withLoadingComponent(<CategoryManage />),
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论