Commit d0a905f0 authored by FE-安焕焕's avatar FE-安焕焕 👣

优化功能

parent 651d3bf1
...@@ -97,6 +97,11 @@ export default { ...@@ -97,6 +97,11 @@ export default {
name: 'deliveryOrder', name: 'deliveryOrder',
component: './orderManage/deliveryOrder', component: './orderManage/deliveryOrder',
}, },
{
path: '/orderManage/batchDelivery',
name: 'batchDeliveryOrder',
component: './orderManage/batchDelivery',
},
{ {
component: './404', component: './404',
}, },
......
...@@ -3,13 +3,13 @@ const isProduction = process.env.NODE_ENV === 'production'; ...@@ -3,13 +3,13 @@ const isProduction = process.env.NODE_ENV === 'production';
let envAPi = { let envAPi = {
api: '//backstms-vcc2.liangkebang.net', api: '//backstms-vcc2.liangkebang.net',
// kdspApi: '//yapi.quantgroups.com/mock/351', // kdspApi: '//yapi.quantgroups.com/mock/351',
// kdspApi: '//192.168.28.66:80', kdspApi: 'http://192.168.28.172:8042',
kdspApi: 'https://kdsp-op-vcc2.liangkebang.net', // kdspApi: 'https://kdsp-op-vcc2.liangkebang.net',
}; };
let prodApi = { let prodApi = {
api: '//backstms.q-gp.com', api: '//backstms.q-gp.com',
kdspApi: '//kdsp-operation.q-gp.com', kdspApi: '//kdsp-op.q-gp.com',
}; };
let exportApi; let exportApi;
......
...@@ -47,7 +47,18 @@ const MenuModel = { ...@@ -47,7 +47,18 @@ const MenuModel = {
return value; return value;
}; };
const menuData = initializationData(payload); const menuData = initializationData(payload);
return { ...state, menuData}; menuData[0].children.push({
children: [],
icon: null,
id: 'b3831ed2-5be8-4dab-a9b4-0965de8a0a5d',
name: '批量发货',
path: '/orderManage/batchDelivery',
picture: null,
type: { name: '菜单', value: 3 },
uri: '/orderManage/batchDelivery',
});
return { ...state, menuData };
}, },
}, },
}; };
......
import { Button, Upload, notification } from 'antd';
import React, { useRef } from 'react';
import { PageHeaderWrapper } from '@ant-design/pro-layout';
import ProTable from '@ant-design/pro-table';
import {
queryToBatchSend,
uploadFile,
downTemplate,
downUploadeOrder,
} from '../pendingDeliveryOrder/service';
const TableList = () => {
const actionRef = useRef();
const columns = [
{
title: '批次号',
dataIndex: 'batchNo',
key: 'batchNo',
align: 'center',
},
{
title: '时间',
key: 'dateTimeRange',
dataIndex: 'createdAtRange',
valueType: 'dateTimeRange',
width: 300,
hideInTable: true,
initialValue: [],
align: 'center',
},
{
title: '操作时间',
dataIndex: 'createdAt',
key: 'createdAt',
hideInSearch: true,
align: 'center',
},
{
title: '操作人',
dataIndex: 'userName',
key: 'userName',
hideInSearch: true,
width: 120,
align: 'center',
},
{
title: '发货单数',
dataIndex: 'totalNum',
key: 'totalNum',
hideInSearch: true,
width: 120,
align: 'center',
},
{
title: '成功发货单数',
dataIndex: 'succNum',
key: 'succNum',
hideInSearch: true,
width: 120,
align: 'center',
},
{
title: '状态',
dataIndex: 'status',
key: 'status',
width: 120,
align: 'center',
filters: [],
valueEnum: {
0: { text: '全部失败' },
1: { text: '全部成功' },
2: { text: '部分成功' },
99: { text: '全部' },
},
initialValue: 1,
},
{
title: '操作',
dataIndex: 'option',
key: 'option',
valueType: 'option',
align: 'center',
render: (_, record) => (
<React.Fragment>
<Button
type="primary"
style={{
marginRight: '10px',
}}
onClick={async () => {
downUploadeOrder({ batchNo: record.batchNo, status: 2 });
}}
>
导出全部数据
</Button>
{record.status === 1 ? (
''
) : (
<Button
type="primary"
style={{
marginRottom: '10px',
}}
onClick={() => {
downUploadeOrder({ batchNo: record.batchNo, status: 0 });
}}
>
导出失败数据
</Button>
)}
</React.Fragment>
),
},
];
const reload = () => {
if (actionRef.current) {
actionRef.current.reload();
}
};
const uploadProps = {
name: 'file',
async customRequest(info) {
const result = await uploadFile(info.file);
if (result.businessCode === '0000') {
reload();
notification.success({ message: '导入成功' });
}
},
accept: '.xlsx',
showUploadList: false,
};
const searchRender = ({ searchText, resetText }, { form }) => {
const exportBtn = [
<Upload {...uploadProps}>
<Button type="primary" style={{ marginRight: '10px' }} key="export">
批量发货
</Button>
</Upload>,
<Button
type="primary"
key="exportTemplate"
onClick={downTemplate}
style={{ marginRight: '10px' }}
>
模板下载
</Button>,
];
return [
<Button
key="search"
type="primary"
style={{ marginRight: '10px' }}
onClick={() => {
// eslint-disable-next-line no-unused-expressions
form?.submit();
}}
>
{searchText}
</Button>,
<Button
key="rest"
style={{ marginRight: '10px' }}
onClick={() => {
// eslint-disable-next-line no-unused-expressions
form?.resetFields();
}}
>
{resetText}
</Button>,
[...exportBtn],
];
};
return (
<PageHeaderWrapper>
<ProTable
actionRef={actionRef}
request={params => queryToBatchSend({ ...params })}
columns={columns}
rowKey={r => r.batchNo}
search={{
collapsed: false,
optionRender: searchRender,
}}
bordered
scroll={{ x: 1500 }}
/>
</PageHeaderWrapper>
);
};
export default TableList;
import React from 'react';
const Image = ({ width, url }) => <img width={width} src={url} alt="" />;
export default Image;
/* eslint-disable no-restricted-syntax */
/* eslint-disable guard-for-in */
import React, { useState, useEffect } from 'react';
import { Modal, Timeline, Tabs } from 'antd';
import style from '../index.less';
import { getLogisticsInfo } from '../service';
const { TabPane } = Tabs;
const LogisticsCom = props => {
const { modalVisible, onCancel } = props;
const [result, setResult] = useState({});
const getInfo = async (companyCode, logisticsNo) => {
const data = await getLogisticsInfo(companyCode, logisticsNo);
return data;
};
useEffect(() => {
setResult(props.value);
});
const callback = async key => {
const params = key.split('+');
if (result[params[1]]?.detailList) {
return;
}
const data = getInfo(params[0], params[1]);
result[params[1]].detailList = data?.logisticsList?.[0]?.detailList ?? [];
};
const render = () => {
const dom = [];
// eslint-disable-next-line guard-for-in
// eslint-disable-next-line no-restricted-syntax
for (const key in result) {
const value = result[key];
dom.push(
<TabPane
className={style.tabpane}
tab={value?.expressCompanyName + value?.deliveryNo}
key={`${value?.expressCompanyCode} + ${key}`}
tabBarStyle={{ height: '200px' }}
>
{value?.detailList?.length ? (
<Timeline>
{value?.detailList?.map((item, index) => (
<Timeline.Item color={index > 0 ? 'gray' : 'blue'}>
<p>{item.desc}</p>
<p>{item.logisticsTime}</p>
</Timeline.Item>
))}
</Timeline>
) : (
'暂无物流信息'
)}
</TabPane>,
);
}
return dom;
};
return (
<Modal
destroyOnClose
title="企业物流信息"
visible={modalVisible}
onCancel={() => onCancel()}
onOk={() => onCancel()}
afterClose={() => setResult({})}
bodyStyle={{ maxHeight: '600px', minHeight: '200px', overflow: 'auto' }}
>
<Tabs defaultActiveKey="1" onChange={callback}>
{render()}
</Tabs>
</Modal>
);
};
export default LogisticsCom;
import React from 'react';
import { Popover } from 'antd';
import Image from './Image';
const PopoverDom = ({ name, url }) => {
const content = <Image width={300} url={url} />;
return (
<Popover content={content} title={name}>
{Image({ width: 50, url })}
</Popover>
);
};
export default PopoverDom;
import { Button, Upload, notification } from 'antd'; import { Button } from 'antd';
import React, { useState, useEffect, useRef } from 'react'; import React, { useState, useEffect, useRef } from 'react';
import { PageHeaderWrapper } from '@ant-design/pro-layout'; import { PageHeaderWrapper } from '@ant-design/pro-layout';
import ProTable from '@ant-design/pro-table'; import ProTable from '@ant-design/pro-table';
import { FormInstance } from 'antd/lib/form'; import { FormInstance } from 'antd/lib/form';
import LogisticsForm from './components/LogisticsForm'; import LogisticsForm from './components/LogisticsForm';
import style from './styles.less'; import style from './styles.less';
import PopoverDom from './components/PreviewImage';
import LogisticsCom from './components/LogisticsCom';
import { import {
queryToSend, queryToSend,
queryExpress, queryExpress,
getGoods, getGoods,
uploadFile,
getLogistics, getLogistics,
downTemplate,
downOrder, downOrder,
getLogisticsInfo,
} from './service'; } from './service';
const TableList = props => { const TableList = props => {
...@@ -21,6 +22,8 @@ const TableList = props => { ...@@ -21,6 +22,8 @@ const TableList = props => {
const [skuList, setSkuList] = useState([]); const [skuList, setSkuList] = useState([]);
const [LogisticsData, setLogisticsData] = useState([{}]); const [LogisticsData, setLogisticsData] = useState([{}]);
const [ShowUpdateBtn] = useState([2, 5]); const [ShowUpdateBtn] = useState([2, 5]);
const [LogisticsComList, setLogisticsComList] = useState({});
const [LogisticsComModalVisible, handleComModalVisible] = useState(false);
const actionRef = useRef(); const actionRef = useRef();
const ref = useRef(FormInstance); const ref = useRef(FormInstance);
...@@ -32,9 +35,29 @@ const TableList = props => { ...@@ -32,9 +35,29 @@ const TableList = props => {
index < record?.mchOrderSkuVoList?.length - 1 ? 'border' : null, index < record?.mchOrderSkuVoList?.length - 1 ? 'border' : null,
].join(' ')} ].join(' ')}
> >
{key === 'skuName' ? <PopoverDom name={item[key]} url={item.imageUrl} /> : ''}
{item[key]} {item[key]}
</p> </p>
)); ));
const handleCom = async record => {
const tempObj = {};
// eslint-disable-next-line no-unused-expressions
record?.mchOrderSkuVoList?.forEach(item => {
if (!(item.deliveryNo in tempObj)) {
tempObj[item.deliveryNo] = {
deliveryNo: item.deliveryNo,
expressCompanyCode: item.expressCompanyCode,
expressCompanyName: item.expressCompanyName,
};
}
});
const keys = Object.keys(tempObj);
const firstObj = tempObj[keys[0]];
const data = await getLogisticsInfo(firstObj?.expressCompanyCode, firstObj?.deliveryNo);
tempObj[keys[0]].detailList = data?.logisticsList?.[0]?.detailList || [];
setLogisticsComList(tempObj);
handleComModalVisible(true);
};
const columns = [ const columns = [
{ {
title: '订单ID', title: '订单ID',
...@@ -58,36 +81,6 @@ const TableList = props => { ...@@ -58,36 +81,6 @@ const TableList = props => {
hideInSearch: true, hideInSearch: true,
width: 200, width: 200,
}, },
{
title: '收货人手机',
dataIndex: 'receiverPhone',
key: 'receiverPhone',
order: 4,
width: 150,
},
{
title: '收货人姓名',
dataIndex: 'receiverName',
key: 'receiverName',
order: 3,
width: 120,
},
{
title: '收货地址',
dataIndex: 'fullAddress',
key: 'fullAddress',
hideInSearch: true,
width: 350,
},
{
title: '商品自编码',
dataIndex: 'thirdSpuNo',
key: 'thirdSpuNo',
width: 120,
hideInSearch: true,
className: 'colStyle',
render: (_, record) => renderContent(record, 'thirdSpuNo'),
},
{ {
title: '商品名称', title: '商品名称',
dataIndex: 'skuName', dataIndex: 'skuName',
...@@ -115,6 +108,37 @@ const TableList = props => { ...@@ -115,6 +108,37 @@ const TableList = props => {
hideInSearch: true, hideInSearch: true,
render: (_, record) => renderContent(record, 'count'), render: (_, record) => renderContent(record, 'count'),
}, },
{
title: '商品自编码',
dataIndex: 'thirdSpuNo',
key: 'thirdSpuNo',
width: 120,
hideInSearch: true,
className: 'colStyle',
render: (_, record) => renderContent(record, 'thirdSpuNo'),
},
{
title: '收货人手机',
dataIndex: 'receiverPhone',
key: 'receiverPhone',
order: 4,
width: 150,
},
{
title: '收货人姓名',
dataIndex: 'receiverName',
key: 'receiverName',
order: 3,
width: 120,
},
{
title: '收货地址',
dataIndex: 'fullAddress',
key: 'fullAddress',
hideInSearch: true,
width: 350,
},
{ {
title: '物流公司', title: '物流公司',
dataIndex: 'expressCompanyName', dataIndex: 'expressCompanyName',
...@@ -193,11 +217,25 @@ const TableList = props => { ...@@ -193,11 +217,25 @@ const TableList = props => {
{props.type === 2 ? '更新物流信息' : '填写物流信息'} {props.type === 2 ? '更新物流信息' : '填写物流信息'}
</Button> </Button>
)} )}
{props.type === 2 ? (
<Button
type="primary"
style={{
marginBottom: '10px',
}}
onClick={() => {
handleCom(record);
}}
>
查询物流信息
</Button>
) : (
''
)}
</React.Fragment> </React.Fragment>
), ),
}, },
]; ];
const reload = () => { const reload = () => {
handleModalVisible(false); handleModalVisible(false);
if (actionRef.current) { if (actionRef.current) {
...@@ -212,17 +250,6 @@ const TableList = props => { ...@@ -212,17 +250,6 @@ const TableList = props => {
}; };
getCompanys(); getCompanys();
}, []); }, []);
const uploadProps = {
name: 'file',
async customRequest(info) {
const result = await uploadFile(info.file);
if (result.businessCode === '0000') {
notification.success({ message: '导入成功' });
}
},
accept: '.xlsx',
showUploadList: false,
};
const queryToSendFn = params => { const queryToSendFn = params => {
const transformedParam = { const transformedParam = {
...@@ -234,47 +261,30 @@ const TableList = props => { ...@@ -234,47 +261,30 @@ const TableList = props => {
}; };
return queryToSend(transformedParam); return queryToSend(transformedParam);
}; };
const searchRender = ({ searchText, resetText }, { form }) => { const searchRender = ({ searchText, resetText }, { form }) => [
const exportBtn = [ <Button
<Upload {...uploadProps}> key="search"
<Button type="primary" style={{ marginRight: '10px' }} key="export"> type="primary"
导入 style={{ marginRight: '10px' }}
</Button> onClick={() => {
</Upload>, // eslint-disable-next-line no-unused-expressions
<Button form?.submit();
type="primary" }}
key="exportTemplate" >
onClick={downTemplate} {searchText}
style={{ marginRight: '10px' }} </Button>,
> <Button
导入模板下载 key="rest"
</Button>, style={{ marginRight: '10px' }}
]; onClick={() => {
return [ // eslint-disable-next-line no-unused-expressions
<Button form?.resetFields();
key="search" }}
type="primary" >
style={{ marginRight: '10px' }} {resetText}
onClick={() => { </Button>,
// eslint-disable-next-line no-unused-expressions // props.type === 2 ? null : [...exportBtn],
form?.submit(); ];
}}
>
{searchText}
</Button>,
<Button
key="rest"
style={{ marginRight: '10px' }}
onClick={() => {
// eslint-disable-next-line no-unused-expressions
form?.resetFields();
}}
>
{resetText}
</Button>,
props.type === 2 ? null : [...exportBtn],
];
};
const toolBarRenderFn = () => [ const toolBarRenderFn = () => [
<Button <Button
...@@ -314,6 +324,12 @@ const TableList = props => { ...@@ -314,6 +324,12 @@ const TableList = props => {
modalVisible={LogisticsModalVisible} modalVisible={LogisticsModalVisible}
value={LogisticsData} value={LogisticsData}
/> />
<LogisticsCom
onSubmit={reload}
onCancel={() => handleComModalVisible(false)}
modalVisible={LogisticsComModalVisible}
value={LogisticsComList}
/>
</PageHeaderWrapper> </PageHeaderWrapper>
); );
}; };
......
...@@ -76,3 +76,56 @@ export async function downOrder(params) { ...@@ -76,3 +76,56 @@ export async function downOrder(params) {
const blob = new Blob([data]); const blob = new Blob([data]);
saveAs(blob, `商户订单列表-${format(new Date(), 'yyyyMMddHHmmss')}.xlsx`); saveAs(blob, `商户订单列表-${format(new Date(), 'yyyyMMddHHmmss')}.xlsx`);
} }
export async function getLogisticsInfo(companyCode, logisticsNo) {
const { data } = await request.get(
`/api/kdsp/op/logistics/kd100/track-list?companyCode=${companyCode}&logisticsNo=${logisticsNo}`,
{
prefix: config.kdspApi,
},
);
return data;
}
// 批量发货订单
export async function queryToBatchSend(params) {
const transformedParam = {
pageNo: params.current,
pageSize: params.pageSize || 20,
startTime: params.dateTimeRange?.[0],
endTime: params.dateTimeRange?.[1],
status: params?.status ?? 99,
batchNo: params.batchNo,
};
const {
data: { current, records, total, size },
} = await request.get('/api/kdsp/op/mch-order/delivery-batch-list', {
prefix: config.kdspApi,
params: _.omitBy(transformedParam, v => !v),
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
});
return {
current,
data: records.map(v => ({ ...v })),
total,
pageSize: size,
};
}
export async function downUploadeOrder(params) {
const data = await request.get('/api/kdsp/op/mch-order/delivery-batch-order-downLoad', {
params,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
prefix: config.kdspApi,
responseType: 'arrayBuffer',
});
const blob = new Blob([data]);
const status = {
0: '失败数据',
1: '成功数据',
2: '全部数据',
};
saveAs(blob, `批量发货-${status[params.status]}-${format(new Date(), 'yyyyMMddHHmmss')}.xlsx`);
}
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
:global { :global {
.tableContent { .tableContent {
display: flex; display: flex;
align-items: flex-end; align-items: center;
height: 60px; height: 60px;
padding: 16px; padding: 16px;
} }
...@@ -12,5 +12,18 @@ ...@@ -12,5 +12,18 @@
tbody .colStyle { tbody .colStyle {
padding: 0; padding: 0;
} }
.ant-popover-title {
max-width: 300px;
overflow: hidden;
}
}
}
.tabpane {
:global {
.ant-tabs-content {
min-height: 200px;
max-height: 700px;
overflow: auto;
}
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment