Commit d4d42900 authored by 武广's avatar 武广

Merge branch 'master' of git.quantgroup.cn:ui/merchant-manage-ui into feature/right20220906

parents 9c4a5427 ec6e8de8
...@@ -91,6 +91,12 @@ export default { ...@@ -91,6 +91,12 @@ export default {
path: '/', path: '/',
component: './Admin', component: './Admin',
}, },
{
title: '商户管理后台',
path: '/orderManage/queryOrder',
name: 'queryOrder',
component: './orderManage/queryOrder',
},
{ {
title: '商户管理后台', title: '商户管理后台',
path: '/orderManage/pendingDeliveryOrder', path: '/orderManage/pendingDeliveryOrder',
......
import React, { useState } from 'react'; import React, { useState, useEffect } from 'react';
import { Map, Marker, ZoomControl, CityListControl } from 'react-bmapgl'; import { Map, Marker, ZoomControl, CityListControl } from 'react-bmapgl';
import { Modal, Input } from 'antd'; import { Modal, Input } from 'antd';
export default props => { export default props => {
const { visible, onSetPoint, onCancel, lngLat } = props; const { visible, onSetPoint, onCancel, lngLat, addrInfo } = props;
let defaultLnglat = { lng: 116.404449, lat: 39.914889 }; let defaultLnglat = { lng: 116.404449, lat: 39.914889 };
if (lngLat) { if (lngLat) {
defaultLnglat = lngLat; defaultLnglat = lngLat;
...@@ -27,6 +27,31 @@ export default props => { ...@@ -27,6 +27,31 @@ export default props => {
setLnglatText(`${e.latlng.lng},${e.latlng.lat}`); setLnglatText(`${e.latlng.lng},${e.latlng.lat}`);
}; };
// const translateCallback = obj => {
// console.log('obj :>> ', obj);
// setLnglat(obj.points[0]);
// };
const getPoint = () => {
// const convertor = new window.BMapGL.Convertor();
const myGeo = new window.BMapGL.Geocoder();
// 将地址解析结果显示在地图上,并调整地图视野
myGeo.getPoint(
addrInfo.address || '',
point => {
if (point) {
// convertor.translate([point], 1, 5, translateCallback);
setLnglat(point);
}
},
addrInfo.provice || '北京市',
);
};
useEffect(() => {
if (visible) getPoint();
}, [visible]);
return ( return (
<Modal <Modal
title="门店信息" title="门店信息"
......
...@@ -125,44 +125,52 @@ export default () => { ...@@ -125,44 +125,52 @@ export default () => {
width: 300, width: 300,
dataIndex: 'action', dataIndex: 'action',
fixed: 'right', fixed: 'right',
render: (_, r) => [ render: (_, r) => {
<Popconfirm const operations = [
title="确定允许退款?" <Popconfirm
onConfirm={() => refund(r)} title="确定允许退款?"
okText="确认" onConfirm={() => refund(r)}
cancelText="取消" okText="确认"
key="pop" cancelText="取消"
disabled={!r.showRefund} key="pop"
> disabled={!r.showRefund}
<Button key="link1" className="mr10 mt10" type="primary" disabled={!r.showRefund}> >
{r.showRefunded ? '已退款' : '允许退款'} <Button key="link1" className="mr10 mt10" type="primary" disabled={!r.showRefund}>
</Button> {r.showRefunded ? '已退款' : '允许退款'}
</Popconfirm>, </Button>
<Button </Popconfirm>,
key="link2" <Button
onClick={() => reject(r)} key="link2"
type="primary" onClick={() => reject(r)}
className="mr10 mt10" type="primary"
disabled={!r.showRefuse} className="mr10 mt10"
> disabled={!r.showRefuse}
驳回 >
</Button>, 驳回
<Button key="link3" onClick={() => viewDetail(r)} type="primary" className="mr10 mt10"> </Button>,
订单详情 <Button key="link3" onClick={() => viewDetail(r)} type="primary" className="mr10 mt10">
</Button>, 订单详情
<Button </Button>,
key="link4" <Button
onClick={() => handleCom(r)} key="link4"
type="primary" onClick={() => handleCom(r)}
className="mr10 mt10" type="primary"
disabled={!r.showLogistics} className="mr10 mt10"
> disabled={!r.showLogistics}
查看物流 >
</Button>, 查看物流
<Button className="mr10 mt10" type="primary" onClick={() => viewLog(r)}> </Button>,
查看记录 <Button className="mr10 mt10" type="primary" onClick={() => viewLog(r)}>
</Button>, 查看记录
], </Button>,
];
// 服务订单删除物流拦截
if (!['vip', 'self'].includes(r.supplierType)) {
operations.splice(3, 1);
}
return operations;
},
}, },
]; ];
return ( return (
......
...@@ -146,25 +146,33 @@ export default () => { ...@@ -146,25 +146,33 @@ export default () => {
dataIndex: 'action', dataIndex: 'action',
width: 250, width: 250,
fixed: 'right', fixed: 'right',
render: (val, r) => [ render: (val, r) => {
<Button key="link1" onClick={() => openAudit(r)} className="mr10" type="primary"> const operations = [
审核 <Button key="link1" onClick={() => openAudit(r)} className="mr10 mt10" type="primary">
</Button>, 审核
<Button </Button>,
disabled={r.serviceType !== 1 || (r.serviceType === 1 && r.intercept)} <Button
onClick={() => openLogistics(r)} disabled={r.serviceType !== 1 || (r.serviceType === 1 && r.intercept)}
className="mr10" onClick={() => openLogistics(r)}
type="primary" className="mr10 mt10"
> type="primary"
物流拦截 >
</Button>, 物流拦截
<Button className="mr10 mt10" key="link" onClick={() => viewDetail(r)} type="primary"> </Button>,
订单详情 <Button className="mr10 mt10" key="link" onClick={() => viewDetail(r)} type="primary">
</Button>, 订单详情
<Button type="primary" onClick={() => viewLog(r)}> </Button>,
查看记录 <Button className="mr10 mt10" type="primary" onClick={() => viewLog(r)}>
</Button>, 查看记录
], </Button>,
];
// 服务订单删除物流拦截
if (!['vip', 'self'].includes(r.supplierType)) {
operations.splice(1, 1);
}
return operations;
},
}, },
]; ];
return ( return (
......
...@@ -24,13 +24,17 @@ const StoreModal = props => { ...@@ -24,13 +24,17 @@ const StoreModal = props => {
const { const {
visible, visible,
onCancel, onCancel,
form: { getFieldDecorator, setFieldsValue, validateFields, resetFields }, form: { getFieldDecorator, setFieldsValue, getFieldsValue, validateFields, resetFields },
formInfo, formInfo,
} = props; } = props;
const [areaAddr, setAreaAddr] = useState([]); const [areaAddr, setAreaAddr] = useState([]);
const [visibleMap, setVisibleMap] = useState(false); const [visibleMap, setVisibleMap] = useState(false);
const [times, setTimes] = useState([{ name: 'time0' }]); const [times, setTimes] = useState([{ name: 'time0' }]);
const [formData, setFormData] = useState({}); const [formData, setFormData] = useState({});
const [mapInfo, setMapInfo] = useState({
provice: '',
address: '',
});
const divDom = useRef(); const divDom = useRef();
...@@ -82,7 +86,22 @@ const StoreModal = props => { ...@@ -82,7 +86,22 @@ const StoreModal = props => {
}; };
// 显示地图 // 显示地图
const openMap = v => setVisibleMap(v); const openMap = v => {
const values = getFieldsValue();
let provice = '北京市';
if (values.addr.length > 0) {
areaAddr.forEach(item => {
if (item.value === values.addr[0]) {
provice = item.label;
}
});
}
setMapInfo({
provice,
address: values.address,
});
setVisibleMap(v);
};
// 获取地址省 // 获取地址省
const getAreaAddr = async id => { const getAreaAddr = async id => {
...@@ -162,7 +181,7 @@ const StoreModal = props => { ...@@ -162,7 +181,7 @@ const StoreModal = props => {
}; };
useEffect(() => { useEffect(() => {
if (props.visible) { if (visible) {
resetFields(); resetFields();
const info = Object.assign({}, formInfo); const info = Object.assign({}, formInfo);
if (info && info.id) { if (info && info.id) {
...@@ -186,7 +205,9 @@ const StoreModal = props => { ...@@ -186,7 +205,9 @@ const StoreModal = props => {
setFormData(info); setFormData(info);
getLazyAddr(info); getLazyAddr(info);
} else { } else {
getAreaAddr(0); if (areaAddr.length < 1) {
getAreaAddr();
}
setFormData({}); setFormData({});
} }
} }
...@@ -197,6 +218,7 @@ const StoreModal = props => { ...@@ -197,6 +218,7 @@ const StoreModal = props => {
title="门店信息" title="门店信息"
visible={visible} visible={visible}
width="800px" width="800px"
maskClosable={false}
onOk={() => onSubmit()} onOk={() => onSubmit()}
onCancel={() => handleCancel()} onCancel={() => handleCancel()}
> >
...@@ -293,6 +315,7 @@ const StoreModal = props => { ...@@ -293,6 +315,7 @@ const StoreModal = props => {
</Form> </Form>
<MapModal <MapModal
visible={visibleMap} visible={visibleMap}
addrInfo={mapInfo}
onCancel={() => openMap(false)} onCancel={() => openMap(false)}
onSetPoint={e => onSetPoint(e)} onSetPoint={e => onSetPoint(e)}
></MapModal> ></MapModal>
......
...@@ -14,18 +14,8 @@ export default () => { ...@@ -14,18 +14,8 @@ export default () => {
const [pageNo, setPageNo] = useState(1); const [pageNo, setPageNo] = useState(1);
const [totalNum, setTotalNum] = useState(0); const [totalNum, setTotalNum] = useState(0);
const [pageSize, setPageSize] = useState(20); const [pageSize, setPageSize] = useState(20);
const table = useRef();
const refSearch = useRef(); const refSearch = useRef();
const divDom = useRef(); const divDom = useRef();
const onEnableState = async ({ id, state }) => {
const enable = +state === 1 ? 0 : 1;
const res = await apiEnableStore({ id, state: enable });
if (res === '0000') {
notification.success({ message: `已${state ? '禁用' : '启用'}` });
// eslint-disable-next-line no-unused-expressions
table.current?.reload?.();
}
};
const onCreate = () => { const onCreate = () => {
setStoreInfo({}); setStoreInfo({});
setVisible(true); setVisible(true);
...@@ -34,13 +24,6 @@ export default () => { ...@@ -34,13 +24,6 @@ export default () => {
setStoreInfo(info); setStoreInfo(info);
setVisible(true); setVisible(true);
}; };
const closeModal = isReload => {
if (isReload === true) {
// eslint-disable-next-line no-unused-expressions
table.current?.reload?.();
}
setVisible(false);
};
// 获取市区街道 // 获取市区街道
const loadData = async selectedOptions => { const loadData = async selectedOptions => {
...@@ -111,6 +94,21 @@ export default () => { ...@@ -111,6 +94,21 @@ export default () => {
} }
getList(params); getList(params);
}; };
const closeModal = isReload => {
if (isReload) {
onSearch(refSearch.current?.getFieldValue?.() || {});
}
setStoreInfo({});
setVisible(false);
};
const onEnableState = async ({ id, state }) => {
const enable = +state === 1 ? 0 : 1;
const res = await apiEnableStore({ id, state: enable });
if (res === '0000') {
notification.success({ message: `已${state ? '禁用' : '启用'}` });
onSearch(refSearch.current?.getFieldValue?.() || {});
}
};
const onReset = () => { const onReset = () => {
if (refSearch.current && refSearch.current.resetFields) { if (refSearch.current && refSearch.current.resetFields) {
...@@ -284,9 +282,7 @@ export default () => { ...@@ -284,9 +282,7 @@ export default () => {
columns={columns} columns={columns}
rowKey={record => record.id} rowKey={record => record.id}
pagination={false} pagination={false}
// className={styles.tabletop}
scroll={{ x: '100%' }} scroll={{ x: '100%' }}
// rowSelection={rowSelection}
/> />
{dataList && dataList.length && ( {dataList && dataList.length && (
<div className={style.pageBox}> <div className={style.pageBox}>
......
...@@ -8,6 +8,10 @@ ...@@ -8,6 +8,10 @@
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"
/> />
<title>量星球商户管理系统</title> <title>量星球商户管理系统</title>
<script
type="text/javascript"
src="https://api.map.baidu.com/api?v=3.0&ak=5gZyih0oAhiNdbbdPKTc9ZGYOwel8bYN&type=webgl"
></script>
<link rel="icon" href="/favicon.png" type="image/x-icon" /> <link rel="icon" href="/favicon.png" type="image/x-icon" />
</head> </head>
<body> <body>
......
...@@ -147,7 +147,7 @@ const LogisticsForm = props => { ...@@ -147,7 +147,7 @@ const LogisticsForm = props => {
message: '请填写物流单号!', message: '请填写物流单号!',
}, },
], ],
})(<Input placeholder="请填写物流单号" />)} })(<Input maxLength={30} placeholder="请填写物流单号" />)}
</FormItem> </FormItem>
<FormItem> <FormItem>
{getFieldDecorator(`${i}-serialNumber`, { {getFieldDecorator(`${i}-serialNumber`, {
......
import React, { useMemo } from 'react';
import { Spin, Empty } from 'antd';
import style from './index.less';
const CustomTable = props => {
const {
columns,
dataSource,
rowKey,
bordered,
eachRowHeadRender = null,
subDataField = null,
loading = null,
align = 'left',
} = props;
const colLength = columns.length;
const baseColumns = useMemo(() => columns, [columns]);
const baseDataSource = useMemo(() => dataSource, [dataSource]);
const ColElement = () =>
baseColumns.map((column, index) => {
const key = column.dataIndex || index.toString();
const styleWidth = column.width ? { width: column.width } : {};
return <col key={key} style={styleWidth}></col>;
});
/** @name thead内容 */
const TheadElement = () => (
<tr>
{baseColumns.map((column, index) => {
const key = column.dataIndex || index;
return <th key={key}>{column.title}</th>;
})}
</tr>
);
/** @name 获取td元素数据 */
const getTdElement = ({ dataSourceItem, dataSourceIndex, subData, subDataItem, subDataIndex }) =>
baseColumns.map((column, index) => {
const { render, dataIndex, align: itemAlign = null } = column;
const key = dataIndex || index;
// 子集不存在的属性去顶级查找
const currentData =
subDataItem && subDataItem[key] !== undefined ? subDataItem[key] : dataSourceItem[key];
let rowSpan = 1;
// 设置了自动合并 && 只设置第一条数据的值,其他的返回<></</>
if (column.rowSpanMode === 'auto' && subData) {
rowSpan = subData.length;
if (subDataIndex > 0) {
return <></>;
}
}
const renderParams = {
value: currentData,
record: dataSourceItem,
index: dataSourceIndex,
subRecord: subDataItem,
subIndex: subDataIndex,
};
return (
<td rowSpan={rowSpan} key={key} align={itemAlign || align}>
<div className={style['td-box']}>{render ? render(renderParams) : currentData}</div>
</td>
);
});
/** @name 每一行的头部自定义渲染 */
const EachRowHeadElement = dataSourceItem => (
<tr>
<td className={style['thead-render']} colSpan={colLength}>
{' '}
{eachRowHeadRender(dataSourceItem)}
</td>
</tr>
);
/** @name tbody内容 */
const TbodyElement = () =>
baseDataSource.map((dataSourceItem, dataSourceIndex) => {
const subData = subDataField ? dataSourceItem[subDataField] : dataSourceItem;
let tbodyElement = '';
if (Array.isArray(subData)) {
tbodyElement = subData.map((subDataItem, subDataIndex) => {
const key = subDataItem[rowKey] || subDataIndex.toString();
return (
<tr key={key}>
{getTdElement({
dataSourceItem,
dataSourceIndex,
subData,
subDataItem,
subDataIndex,
})}
</tr>
);
});
} else {
const key = subData[rowKey] || dataSourceIndex.toString();
tbodyElement = (
<tr key={key}>{getTdElement({ dataSourceItem, dataSourceIndex, subData })}</tr>
);
}
return (
<React.Fragment key={dataSourceIndex.toString()}>
{eachRowHeadRender ? (
<EachRowHeadElement key={dataSourceIndex.toString()} {...dataSourceItem} />
) : (
''
)}
{tbodyElement}
</React.Fragment>
);
});
const EmptyElement = () => {
if (!dataSource || dataSource.length === 0) {
return (
<div className={style['custom-table-empty']}>
<Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />
</div>
);
}
return <></>;
};
const memoTable = useMemo(
() => (
<table>
<colgroup>
<ColElement />
</colgroup>
<thead className={style['custom-table-thead']}>
<TheadElement />
</thead>
<tbody className={style['custom-table-tbody']}>
<TbodyElement />
</tbody>
</table>
),
[props.dataSource],
);
return (
<div className={`${style['custom-table']} ${bordered ? style['custom-table-bordered'] : ''}`}>
<Spin spinning={loading}>
{memoTable}
<EmptyElement />
</Spin>
</div>
);
};
export { CustomTable };
.custom-table {
width: 100%;
background: #fff;
table {
width: 100%;
}
}
.custom-table-thead {
background: #fafafa;
> tr > th {
padding: 16px 16px;
overflow-wrap: break-word;
}
}
.custom-table-tbody {
> tr > td {
padding: 16px 16px;
> .td-box {
word-break: break-all;
}
&.thead-render {
padding: 0;
}
}
}
// bordered
.custom-table-bordered {
> table,
.custom-table-tbody,
.custom-table-thead {
> tr > td,
> tr > th {
border: 1px solid #e8e8e8;
}
}
}
// empt
.custom-table-empty {
margin: 0 auto;
overflow: hidden;
text-align: center;
border: 1px solid #e8e8e8;
border-top: none;
}
import React, { useState, useEffect, forwardRef, useImperativeHandle } from 'react';
import { Modal, Table } from 'antd';
// import { queryOrderDetail } from '../../service';
import { COUPON_CODE_STATUS } from '../../const';
import style from './index.less';
const DetailModal = (props, ref) => {
const [visible, setVisible] = useState(false);
const modalProps = {
visible,
width: '1000px',
title: '订单详情',
footer: null,
onCancel: () => {
setVisible(false);
},
};
// const getDetail = async orderNo => {
// const params = {
// orderNo,
// };
// const res = await queryOrderDetail(params);
// console.log(res);
// };
/** @module 基本信息 */
const [baseInfo, setBaseInfo] = useState({});
/** @module 商品table */
const [goodData, setGoodData] = useState([]);
const goodColumns = [
{
title: '商品',
dataIndex: 'spuName',
width: 350,
render: (value, record) => {
const { primaryImage, skuSpec, spuId } = record;
return (
<div className={style['sku-info']}>
<img src={primaryImage} width="50px" height="50px" alt="" />
<div className={style['sku-info__box']}>
<p className={style['sku-info__box--name']}>{value}</p>
{/* <p className={style['sku-info__box--spec']}>规格:{skuSpec}</p>
<p className={style['sku-info__box--id']}>商品id: {spuId}</p> */}
</div>
</div>
);
},
},
{
title: '单价(元)',
dataIndex: 'supplyPrice',
width: 150,
},
{
title: '数量',
dataIndex: 'count',
width: 150,
},
{
title: '小计',
dataIndex: 'subTotal',
width: 150,
render: (value, record) => {
const { supplyPrice, count } = record;
return (supplyPrice * count).toFixed(2);
},
},
{
title: '售后状态',
width: 150,
dataIndex: 'afterServiceStatusDesc',
render: value => value || '-',
},
];
/** @module 券码 */
const [couponData, setCouponData] = useState([]);
const couponColumns = [
{
title: '券码',
width: 150,
render: (value, record, index) => `券码${index + 1}`,
},
{
title: '有效期',
dataIndex: 'useStartTime',
width: 350,
render: (value, record) => {
const { useEndTime } = record;
return `${value} - ${useEndTime}`;
},
},
{
title: '核销时间',
dataIndex: 'useTime',
width: 200,
render: value => value || '-',
},
{
title: '核销人',
dataIndex: 'usedByShopName',
width: 150,
render: value => value || '-',
},
{
title: '状态',
dataIndex: 'codeStatus',
width: 150,
render: value => COUPON_CODE_STATUS[value],
},
];
const open = record => {
console.log(record);
setVisible(true);
const {
skuVos,
couponCodeVos,
receiverName,
receiverMobile,
fullAddress,
orderNo,
orderTime,
payTime,
} = record;
setGoodData(skuVos);
setCouponData(couponCodeVos);
setBaseInfo({
receiverName,
receiverMobile,
fullAddress,
orderNo,
orderTime,
payTime,
});
// getDetail(orderNo);
};
useImperativeHandle(ref, () => ({
open,
}));
return (
<Modal {...modalProps}>
<div className={style['order-info']}>
<div className={style['order-info--item']}>
<div className={style['order-info--item__title']}>收货人信息</div>
<ul className={style['order-info--item__ul']}>
<li>姓名:{baseInfo.receiverName}</li>
<li>手机号:{baseInfo.receiverMobile}</li>
<li>地址:{baseInfo.fullAddress}</li>
</ul>
</div>
<div className={style['order-info--item']}>
<div className={style['order-info--item__title']}>订单信息</div>
<ul className={style['order-info--item__ul']}>
<li>订单号:{baseInfo.orderNo}</li>
<li>下单时间:{baseInfo.orderTime}</li>
<li>付款时间:{baseInfo.payTime}</li>
</ul>
</div>
</div>
{/* 商品 */}
<div className={style['good-table']}>
<Table
pagination={false}
rowKey="orderSkuId"
bordered
columns={goodColumns}
dataSource={goodData}
></Table>
</div>
{/* 券码 */}
<div className={style['coupon-table']}>
<Table pagination={false} bordered columns={couponColumns} dataSource={couponData}></Table>
</div>
</Modal>
);
};
export default forwardRef(DetailModal);
.order-info {
display: flex;
padding: 20px;
background: #fafafa;
&--item {
flex: 1;
&__title {
height: 40px;
font-weight: bold;
font-size: 16px;
}
&__ul {
margin: 0;
padding: 0;
font-size: 14px;
li {
line-height: 30px;
}
}
}
}
.sku-info {
display: flex;
.sku-info__box {
margin-left: 10px;
p {
margin: 0;
padding: 0;
}
&--spec {
color: #999;
}
&--id {
color: #999;
}
}
}
.good-table,
.coupon-table {
margin-top: 20px;
}
import React from 'react';
import { Form, Input, Select, DatePicker, Button, Space, notification } from 'antd';
import { sub } from 'date-fns';
import style from './index.less';
const { Option } = Select;
const { RangePicker } = DatePicker;
const SEARCH_TYPE = {
SELECT: 'select',
RANGE_PICKER: 'range_picker',
INPUT: 'input',
};
const FormSearch = props => {
const {
width = '100%',
form,
initialValues = {},
onFinish = () => {},
formConfig,
formOptions,
btnConfig,
} = props;
const FormItemBox = ({ bindKey, label, column, children, afterRender }) => {
const columnValue = column;
// if (afterRender) {
// columnValue = '';
// }
return (
<Form.Item
className={style['custom-form-item']}
column={columnValue}
name={bindKey}
label={label}
>
{children}
</Form.Item>
);
};
// 下拉框类型
const FormItemSelect = config => {
const {
bindKey,
options: configOptions = [],
originOptions = {},
afterRender = null,
afterOptions = {},
column,
} = config;
// 提取公共部分
const BaseSelectElement = () => (
<FormItemBox {...config}>
<Select name={bindKey} className={style['form-item-tag']} {...originOptions}>
{configOptions.map(option => (
<Option key={option.value} value={option.value}>
{option.name}
</Option>
))}
</Select>
</FormItemBox>
);
if (afterRender) {
return (
<>
{/* // <div className={style['custom-form-item-group']}> */}
<BaseSelectElement />
<FormItemBox column={column} {...afterOptions}>
{afterRender()}
</FormItemBox>
{/* // </div> */}
</>
);
}
return <BaseSelectElement />;
};
// 选择日期范围类型
const FormItemRangePicker = config => {
const { originOptions = {} } = config;
return (
<FormItemBox {...config}>
<RangePicker className={style['form-item-tag']} {...originOptions} />
</FormItemBox>
);
};
// 选择日期
// 多级联动
// 输入框类型
const FormItemInput = config => {
const { originOptions = {} } = config;
return (
<FormItemBox {...config}>
<Input className={style['form-item-tag']} {...originOptions} />
</FormItemBox>
);
};
// 表单内容元素
const FormItemElement = () =>
formConfig.map(config => {
const { type } = config;
switch (type) {
case SEARCH_TYPE.SELECT:
return <FormItemSelect key={config.bindKey} {...config} />;
case SEARCH_TYPE.RANGE_PICKER:
return <FormItemRangePicker key={config.bindKey} {...config} />;
case SEARCH_TYPE.INPUT:
return <FormItemInput key={config.bindKey} {...config} />;
default:
return <></>;
}
});
/**
* @module 按钮操作
*/
const FormItemButton = () => (
<Space size={10}>
{btnConfig.map(config => {
const { label, onClick = () => {}, type = 'primary', clickType = 'search' } = config;
const htmlType = clickType === 'reset' ? 'reset' : 'submit';
const callback = () => {
setTimeout(() => {
onClick({ type: clickType, params: form.getFieldValue() });
});
};
return (
<Button key={clickType} type={type} htmlType={htmlType} onClick={callback}>
{label}
</Button>
);
})}
</Space>
);
return (
<div className={style['form-search']}>
<Form
style={{ width }}
layout="inline"
form={form}
initialValues={initialValues}
onFinish={onFinish}
{...formOptions}
>
<FormItemElement></FormItemElement>
<Form.Item>
<FormItemButton></FormItemButton>
</Form.Item>
</Form>
</div>
);
};
export { FormSearch, SEARCH_TYPE };
.form-search {
padding: 15px;
background: #fff;
}
.custom-form-item {
min-width: 320px;
margin-bottom: 20px !important;
&[column='1'] {
width: 100%;
}
&[column='2'] {
width: calc(50% - 16px);
}
&[column='3'] {
width: calc(33.3333% - 32px);
}
&[column='4'] {
width: calc(25% - 48px);
}
&[column='5'] {
width: calc(20% - 54px);
}
}
.form-item-tag {
width: 100%;
}
// .custom-form-item-group {
// display: flex;
// }
import LogisticsForm from '../../../pendingDeliveryOrder/components/LogisticsForm';
const LogisticsFormModal = props => (
// eslint-disable-next-line react/react-in-jsx-scope
<LogisticsForm {...props} />
);
export default LogisticsFormModal;
// 搜索类型
export const ORDER_SEARCH_TYPE = [
{
value: 'orderNo',
name: '订单编号',
},
{
value: 'spuId',
name: '商品id',
},
{
value: 'channelOrderNo',
name: '外部订单',
},
{
value: 'receiverName',
name: '收货人姓名',
},
{
value: 'userMobile',
name: '买家手机号',
},
{
value: 'userMobile4',
name: '买家手机号后四位',
},
{
value: 'receiverMobile',
name: '收货人手机号',
},
{
value: 'receiverMobile4',
name: '收货人手机号后四位',
},
];
// 订单类型
export const ORDER_TYPE = [
{
value: '',
name: '全部',
},
{
value: 1,
name: '普通订单',
},
{
value: 4,
name: '服务订单',
},
];
// 订单状态
export const ORDER_STATUS = [
{
value: '',
name: '全部',
},
{
value: 1,
name: '未支付',
},
{
value: 2,
name: '待发货',
},
{
value: 3,
name: '已发货',
},
{
value: 4,
name: '已完成',
},
{
value: 5,
name: '已关闭',
},
];
export const COUPON_CODE_STATUS = {
1: '未使用',
2: '已使用',
3: '已退款',
};
import { Form, Tabs, Input, Button, Pagination } from 'antd';
import React, { useState, useEffect, useRef } from 'react';
import { PageHeaderWrapper } from '@ant-design/pro-layout';
import style from './index.less';
import { CustomTable } from './components/CustomTable/index';
import { FormSearch, SEARCH_TYPE } from './components/FormSearch/index';
import LogisticsForm from './components/LogisticsFormModel';
import DetailModal from './components/DetailModal/index';
import { queryOrderList, getGoods, getLogistics, queryExpress, queryToSend } from './service';
import { ORDER_SEARCH_TYPE, ORDER_TYPE, ORDER_STATUS } from './const';
const { TabPane } = Tabs;
const OrderList = ref => {
const [loading, setLoading] = useState(false);
const detailModalRef = useRef();
/** @module 发货弹框 */
// 物流公司数据
const [companys, setCompanys] = useState([]);
// 物流弹出框展示
const [LogisticsModalVisible, handleModalVisible] = useState(false);
// 订单下商品列表
const [skuList, setSkuList] = useState([]);
// 当前物流数据
const [LogisticsData, setLogisticsData] = useState([{}]);
/** @module 表格区域 */
const [tableData, setTableData] = useState([]);
const [dataTotal, setDataTotal] = useState(10);
const [pagination, setPagination] = useState({
pageSize: 20,
pageNo: 1,
});
/** @module 搜索区域 */
const [form] = Form.useForm();
/** @module 状态切换区域 */
const [currentOrderStatus, setCurrentOrderStatus] = useState('');
// 获取列表数据
const getOrderList = () => {
const {
orderSearch = 'orderNo',
orderSearchValue = '',
orderTime = [],
skuName = '',
productType = '',
orderStatus = '',
} = form.getFieldValue();
// 筛选同步订单状态tabs
const startTime = orderTime[0] ? orderTime[0].format('YYYY-MM-DD') : '';
const endTime = orderTime[1] ? orderTime[1].format('YYYY-MM-DD') : '';
const searchParams = {
[orderSearch]: orderSearchValue,
startTime,
endTime,
skuName,
productType,
orderStatus,
...pagination,
};
setLoading(true);
queryOrderList(searchParams).then(res => {
setLoading(false);
const { total, records } = res.data;
setDataTotal(total);
setTableData(records);
});
};
// 打开详情弹框
const openDetailModal = record => {
detailModalRef.current.open(record);
};
// 切换订单状态- 同步select和tabs
function orderStatusChange(value) {
setCurrentOrderStatus(String(value));
form.setFieldsValue({
orderStatus: Number(value) || '',
});
setPagination({
...pagination,
pageNo: 1,
});
}
// 重载
const reload = () => {
handleModalVisible(false);
getOrderList();
};
// 获取物流公司列表
const getCompanys = async () => {
const res = await queryExpress();
setCompanys(res);
};
// 分页操作
const onPageChange = (page, size) => {
const current = pagination.pageSize !== size ? 1 : page;
setPagination({
pageNo: current,
pageSize: size,
});
};
useEffect(() => {
getCompanys();
}, []);
useEffect(() => {
getOrderList();
}, [pagination]);
const baseStyle = {
style: {
// width: '250px',
},
};
const FormSearchProps = {
// width: '1200px',
form,
initialValues: {
orderSearch: 'orderNo',
orderStatus: '',
productType: '',
},
formOptions: {},
formConfig: [
{
type: SEARCH_TYPE.SELECT,
label: '订单搜索',
bindKey: 'orderSearch',
column: 5,
options: ORDER_SEARCH_TYPE,
originOptions: {
placeholder: '请选择',
...baseStyle,
},
afterRender: () => <Input style={{ width: '100%' }} type="text"></Input>,
afterOptions: {
bindKey: 'orderSearchValue',
},
},
{
type: SEARCH_TYPE.RANGE_PICKER,
label: '下单时间',
column: 5,
bindKey: 'orderTime',
originOptions: {
placeholder: ['请选择', '请选择'],
...baseStyle,
},
},
{
type: SEARCH_TYPE.INPUT,
label: '商品名称',
column: 5,
bindKey: 'skuName',
originOptions: {
placeholder: '请输入',
...baseStyle,
},
},
{
// 1-普通商品订单 2-虚拟商品订单 3-电子卡券 4-服务商品
type: SEARCH_TYPE.SELECT,
label: '订单类型',
column: 5,
bindKey: 'productType',
options: ORDER_TYPE,
originOptions: {
placeholder: '请选择',
...baseStyle,
},
},
{
type: SEARCH_TYPE.SELECT,
label: '订单状态',
column: 5,
bindKey: 'orderStatus',
options: ORDER_STATUS,
originOptions: {
placeholder: '请选择',
...baseStyle,
},
},
],
btnConfig: [
{
label: '筛选',
clickType: 'submit',
onClick: () => {
const { orderStatus } = form.getFieldValue();
orderStatusChange(orderStatus);
},
},
{
label: '重置',
type: '',
clickType: 'reset',
onClick: () => {
orderStatusChange('');
},
},
],
};
const columns = [
{
title: '商品',
dataIndex: 'spuName',
align: 'left',
width: 350,
render: ({ value, subRecord }) => {
const { primaryImage, skuSpec, spuId } = subRecord;
return (
<div className={style['sku-info']}>
<img src={primaryImage} width="50px" height="50px" alt="" />
<div className={style['sku-info__box']}>
<p className={style['sku-info__box--name']}>{value}</p>
<p className={style['sku-info__box--spec']}>规格:{skuSpec}</p>
<p className={style['sku-info__box--id']}>商品id: {spuId}</p>
</div>
</div>
);
},
},
{
title: '单位(元)/数量',
dataIndex: 'supplyPrice',
width: 150,
render: ({ value, subRecord }) => {
const { count } = subRecord;
return `${value}/${count}`;
},
},
{
title: '买家/收货人',
dataIndex: 'receiverName',
rowSpanMode: 'auto',
width: 150,
render: ({ value, record }) => `${value}/${record.receiverMobile}`,
},
{
title: '付款金额(元)',
dataIndex: 'supplyAmount',
width: 150,
},
{
title: '订单状态',
dataIndex: 'orderStatusDesc',
rowSpanMode: 'auto',
width: 150,
},
{
title: '配送方式',
dataIndex: 'deliveryType',
rowSpanMode: 'auto',
width: 150,
},
{
title: '售后',
dataIndex: 'afterSaleVos',
width: 220,
align: 'left',
render: ({ value }) => {
if (value && value.length) {
return value.map(item => (
<div className={style['after-status-box']}>
<div className={style.desc}>{item.afterServiceStatusDesc}</div>
<div className={style.blue}>{item.afterServiceNo}</div>
</div>
));
}
return <div align="center">-</div>;
},
},
{
title: '操作',
rowSpanMode: 'auto',
align: 'center',
width: 100,
render: ({ value, record, index, subRecord, subIndex }) => {
let text = '';
if ([12, 14].includes(record.orderStatus)) {
text = '发货';
}
if ([13].includes(record.orderStatus)) {
text = '修改物流';
}
// 服务订单不展示发货/修改物流
if (record.productType === 4) {
return <></>;
}
return (
<>
{text ? (
<Button
type="primary"
onClick={async () => {
const skuListData = await getGoods(record?.orderId);
let logisticsData = [{}];
setSkuList(skuListData);
const res = await getLogistics(record?.orderId);
logisticsData = res.map(item => ({
selectedGoods: item?.skus?.map(sku => sku?.orderSkuId),
selectedCompany: item.expressCompanyCode
? `${item?.expressCompanyCode}-${item?.expressCompanyName}`
: null,
orderNum: item?.deliveryNo,
}));
setLogisticsData(logisticsData);
handleModalVisible(true);
}}
>
{text}
</Button>
) : (
''
)}
</>
);
},
},
];
const tableProps = {
bordered: true,
columns,
rowKey: 'skuId',
align: 'center',
dataSource: tableData,
subDataField: 'skuVos',
loading,
};
return (
<PageHeaderWrapper>
<FormSearch {...FormSearchProps} />
<div className={style['tab-box']}>
<Tabs
activeKey={currentOrderStatus}
onChange={orderStatusChange}
size="large"
tabBarStyle={{ padding: '0 30px' }}
>
<TabPane key="" tab="全部"></TabPane>
<TabPane key={1} tab="未支付"></TabPane>
<TabPane key={2} tab="待发货"></TabPane>
<TabPane key={3} tab="已发货"></TabPane>
<TabPane key={4} tab="已完成"></TabPane>
<TabPane key={5} tab="已关闭"></TabPane>
</Tabs>
</div>
<div className={style['white-box']}>
<CustomTable
{...tableProps}
eachRowHeadRender={record => (
<div className={style['table-item-header']}>
<div className={style['table-item-header--info']}>
<span>订单编号:{record.orderNoStr}</span>
<span>下单时间:{record.orderTime}</span>
</div>
<a
onClick={() => {
openDetailModal(record);
}}
className={style['table-item-header--btn']}
>
查看详情
</a>
</div>
)}
></CustomTable>
{/* 分页 */}
{tableData.length ? (
<div className={style['table-pagination']}>
<Pagination
onChange={onPageChange}
total={dataTotal}
showTotal={(total, range) => `第${range[0]}-${range[1]}条 /总共${total}条`}
pageSize={pagination.pageSize}
current={pagination.pageNo}
/>
</div>
) : (
''
)}
</div>
<LogisticsForm
onSubmit={reload}
skuList={skuList}
companys={companys}
onCancel={() => handleModalVisible(false)}
modalVisible={LogisticsModalVisible}
value={LogisticsData}
/>
<DetailModal ref={detailModalRef} />
</PageHeaderWrapper>
);
};
export default OrderList;
.table-item-header {
display: flex;
padding: 0 20px;
line-height: 40px;
background-color: #f7f8f9;
&--info {
flex: 1;
span {
margin-right: 20px;
}
}
&--btn {
padding: 0 10px;
color: #61b0ff;
}
}
.white-box {
background-color: #fff;
}
.tab-box {
margin-top: 20px;
background-color: #fff;
}
.table-pagination {
margin-bottom: 30px;
padding: 20px 30px;
text-align: right;
}
.sku-info {
display: flex;
.sku-info__box {
margin-left: 10px;
p {
margin: 0;
padding: 0;
}
&--spec {
color: #999;
}
&--id {
color: #999;
}
}
}
.blue {
color: #61b0ff;
}
.after-status-box {
margin: 5px 0;
}
import { stringify } from 'querystring';
import _ from 'lodash';
import request from '@/utils/request';
import { saveAs } from 'file-saver';
import { format } from 'date-fns';
import config from '../../../../config/env.config';
// 查询订单列表
export async function queryOrderList(params) {
return request.post('/api/kdsp/queryOrderList', {
prefix: config.kdspApi,
data: params,
});
}
// 订单详情
export async function queryOrderDetail(params) {
return request.post('/api/kdsp/queryOrderDetail', {
prefix: config.kdspApi,
data: params,
});
}
// 待发货订单
export async function queryToSend(params) {
try {
const {
data: { current, records, total, size },
} = await request.post('/api/kdsp/op/mch-order/list-v2', {
prefix: config.kdspApi,
data: stringify(_.omitBy(params, v => !v)),
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
});
return {
current,
data: records.map(v => ({ ...v, logisticsStatus: `_${v.logisticsStatus}` })),
total,
pageSize: size,
};
} catch (error) {
return {};
}
}
// 发货/更新物流
export async function updateExpress(params) {
return request.post('/api/kdsp/op/mch-order/update-express-info', {
prefix: config.kdspApi,
data: params,
});
}
// 快递公司
export async function queryExpress() {
try {
const { data } = await request.get('/api/kdsp/op/express/list', {
prefix: config.kdspApi,
});
return data;
} catch (error) {
return {};
}
}
export async function getGoods(orderId) {
const { data } = await request.get(`/api/kdsp/op/mch-order/skus?orderId=${orderId}`, {
prefix: config.kdspApi,
});
return data;
}
export async function getLogistics(orderId) {
const { data } = await request.get(`/api/kdsp/op/mch-order/logistics-skus?orderId=${orderId}`, {
prefix: config.kdspApi,
});
return data;
}
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