Commit cd134bc7 authored by shida.liu's avatar shida.liu

feat: 为审计新增的页面,无实际用处

parent a3bb5b11
......@@ -304,6 +304,24 @@ export default {
{
component: './404',
},
{
title: '商户管理后台-POP商品管理-待发货订单',
path: '/popOrderManage/popPendingDeliveryOrder',
name: 'popPendingDeliveryOrder',
component: './PopOrderManage/pendingDeliveryOrder',
},
{
title: '商户管理后台-POP商品管理-已发货订单',
path: '/popOrderManage/popDeliveryOrder',
name: 'popDeliveryOrder',
component: './PopOrderManage/deliveryOrder',
},
{
title: '商户管理后台-POP商品管理-批量发货',
path: '/popOrderManage/popBatchDelivery',
name: 'popBatchDeliveryOrder',
component: './PopOrderManage/batchDelivery',
},
],
},
{
......
......@@ -34,6 +34,24 @@ export const BATCH_DELIVERY = {
EDITABLE: '020502', // 新增/修改
};
// POP待发货订单-(应付审计的,没有实际用处)
export const POP_PENDING_DELIVERY_ORDER = {
LIST: '0203011',
EDITABLE: '0203021',
};
// POP已发货订单-(应付审计的,没有实际用处)
export const POP_DELIVERY_ORDER = {
LIST: '0204011',
EDITABLE: '0204021',
};
// POP批量发货-(应付审计的,没有实际用处)
export const POP_BATCH_DELIVERY = {
LIST: '0205011',
EDITABLE: '0205021', // 新增/修改
};
// 订单查询
export const QUERY_ORDER = {
LIST: '020601', // 订单查询列表
......
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 { connect } from 'dva';
import { BATCH_DELIVERY } from '@/../config/permission.config';
import {
queryToBatchSend,
uploadFile,
downTemplate,
downUploadeOrder,
} from '../pendingDeliveryOrder/service';
const TableList = props => {
const actionRef = useRef(null);
const { permissions } = props;
const canEditable = permissions[BATCH_DELIVERY.EDITABLE];
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={{
marginRight: '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>,
];
if (!canEditable) {
exportBtn.splice(0, 1);
}
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();
// eslint-disable-next-line no-unused-expressions
form?.submit();
}}
>
{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 connect(({ menu }) => ({
permissions: menu.permissions,
}))(TableList);
import React from 'react';
import { Table } from 'antd';
import style from './style.less';
const GoodsRemark = props => {
const columns = [
{
title: '商品',
dataIndex: 'skuName',
width: 350,
render: (value, record) => {
const { skuName, imageUrl } = record;
return (
<div className={style.popoverGoods}>
<img src={imageUrl} alt="" className={style['popoverGoods-img']} />
<span>{skuName}</span>
</div>
);
},
},
{
title: '备注',
dataIndex: 'content',
width: 150,
},
{
title: '操作时间',
dataIndex: 'time',
width: 150,
},
];
return (
<div>
<Table columns={columns} dataSource={props.dataSource} pagination={false} />
</div>
);
};
export default GoodsRemark;
.popoverGoods {
display: flex;
align-items: center;
&-img {
width: 50px;
height: 50px;
margin-right: 10px;
}
}
import React from 'react';
import DeliverOrder from '../pendingDeliveryOrder';
// 已发货type:2;待发货type: 1
const TableList = () => <DeliverOrder type={2} />;
export default TableList;
import { Form } from '@ant-design/compatible';
import '@ant-design/compatible/assets/index.css';
import { Modal, notification, Input } from 'antd';
import React, { useState } from 'react';
import { apiDelayDeliverGoods } from '../service';
const UpdateStock = props => {
const { getFieldDecorator, validateFields, resetFields } = props.form;
const valueInfo = {};
const [loading, setLoading] = useState(false);
const submit = async () => {
validateFields(async (err, { remark }) => {
if (err) return;
setLoading(true);
const params = {
orderIds: [props.orderId],
operationType: 5,
remark,
};
console.log('params :>> ', params);
const res = await apiDelayDeliverGoods(params);
if (res?.businessCode === '0000') {
notification.success({ message: '提交成功!' });
props.onCancel('success');
resetFields();
}
setLoading(false);
});
};
const onCancel = () => {
props.onCancel();
resetFields();
};
const formItemLayout = {
labelCol: {
span: 7,
},
wrapperCol: {
span: 15,
},
};
return (
<Modal
title="异常订单报备"
visible={props.visible}
okButtonProps={{ loading }}
onCancel={onCancel}
onOk={submit}
width={500}
>
<Form {...formItemLayout}>
<Form.Item label="异常原因:">
{getFieldDecorator('remark', {
rules: [{ required: true, message: '请输入异常原因!' }],
initialValue: valueInfo.remark,
})(<Input.TextArea maxLength={30} showCount />)}
</Form.Item>
</Form>
</Modal>
);
};
export default Form.create()(UpdateStock);
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 } from 'antd';
const LogisticsCom = props => {
const { modalVisible, onCancel } = props;
const [result, setResult] = useState({});
useEffect(() => {
setResult(props.value);
});
return (
<Modal
destroyOnClose
title={`${
result?.expressCompanyName
? `${result?.expressCompanyName}-${result?.deliveryNo}`
: '物流信息'
}`}
visible={modalVisible}
onCancel={() => onCancel()}
onOk={() => onCancel()}
afterClose={() => setResult({})}
bodyStyle={{ maxHeight: '600px', minHeight: '200px', overflow: 'auto' }}
footer={[]}
>
{result?.detailList?.length ? (
<Timeline>
{result?.detailList?.map((item, index) => (
// eslint-disable-next-line react/no-array-index-key
<Timeline.Item color={index > 0 ? 'gray' : 'blue'} key={index}>
<p>{item.desc}</p>
<p>{item.time}</p>
</Timeline.Item>
))}
</Timeline>
) : (
'暂无物流信息'
)}
</Modal>
);
};
export default LogisticsCom;
import React, { useState, useEffect } from 'react';
import { MinusCircleOutlined, PlusCircleOutlined } from '@ant-design/icons';
import { Form } from '@ant-design/compatible';
import '@ant-design/compatible/assets/index.css';
import { Modal, Select, Input, Card, notification } from 'antd';
import style from '../index.less';
import { apiDeliveriesAdd } from '../service';
const FormItem = Form.Item;
const { Option } = Select;
const LogisticsForm = props => {
const { modalVisible, onCancel, company = [], skuList, onSubmit } = props;
const { getFieldDecorator } = props.form;
const [result, setResult] = useState(() => props.value);
const formData = async (formDataList, fieldsValue, suffixes) => {
// 数据聚合
suffixes.forEach(suffixe => {
const formObj = {};
// eslint-disable-next-line no-restricted-syntax
for (const key in fieldsValue) {
if (key.startsWith(suffixe)) {
formObj[key.split('-')[1]] = fieldsValue[key];
}
}
formDataList.push(formObj);
});
// 参数整合
const resultData = [];
formDataList.forEach(data => {
data.selectedGoods.forEach(orderSkuId => {
resultData.push({
orderSkuId,
expressCompanyCode: data.selectedCompany.split('-')[0],
expressCompanyName: data.selectedCompany.split('-')[1],
deliveryNo: data.orderNum,
serialNumber: data.serialNumber || '',
});
});
});
// 校验重复商品
let orderSkuIds = [];
formDataList.forEach(data => {
orderSkuIds = [...orderSkuIds, ...data.selectedGoods];
});
if (orderSkuIds.length !== Array.from(new Set(orderSkuIds)).length) {
notification.error({ message: '商品选择重复!' });
return;
}
if (skuList.length !== orderSkuIds.length) {
notification.error({ message: '该订单下的所有商品必须设置物流信息!' });
return;
}
await apiDeliveriesAdd(resultData);
onSubmit();
};
const handleSubmit = () => {
props.form.validateFields((err, fieldsValue) => {
const suffixes = [];
const formDataList = [];
if (err) return;
Object.keys(fieldsValue).forEach(key => {
const suffixe = key.split('-')[0];
if (!suffixes.includes(suffixe)) suffixes.push(suffixe);
});
formData(formDataList, fieldsValue, suffixes);
});
};
const addForm = () => {
setResult([...result, {}]);
};
const rmForm = () => {
if (result.length === 1) return;
setResult(result.slice(0, result.length - 1));
};
useEffect(() => {
setResult(props.value);
}, props.value);
return (
<Modal
destroyOnClose
title="物流操作确认"
visible={modalVisible}
onCancel={() => onCancel()}
onOk={handleSubmit}
afterClose={() => setResult([{}])}
>
<Form>
{result &&
result.length &&
result.map((v, i) => (
// eslint-disable-next-line react/no-array-index-key
<Card key={i}>
<FormItem>
{getFieldDecorator(`${i}-selectedGoods`, {
initialValue: v.selectedGoods,
rules: [
{
required: true,
message: '请选择该订单下的商品!',
},
],
})(
<Select mode="multiple" placeholder="请选择该订单下的商品">
{skuList.map(item => (
<Option value={item.orderSkuId} key={item.orderSkuId}>
{item.skuName + (item.skuAttr || '')}
</Option>
))}
</Select>,
)}
</FormItem>
<FormItem>
{getFieldDecorator(`${i}-selectedCompany`, {
initialValue: v.selectedCompany,
rules: [
{
required: true,
message: '请选择物流公司!',
},
],
})(
<Select showSearch placeholder="请选择物流公司">
{company?.map(item => (
<Option
value={`${item.expressCompanyCode}-${item.expressCompanyName}`}
key={item.expressCompanyCode}
>
{item.expressCompanyName}
</Option>
)) || []}
</Select>,
)}
</FormItem>
<FormItem>
{getFieldDecorator(`${i}-orderNum`, {
initialValue: v.orderNum,
rules: [
{
required: true,
message: '请填写物流单号!',
},
],
})(<Input maxLength={30} placeholder="请填写物流单号" />)}
</FormItem>
<FormItem>
{getFieldDecorator(`${i}-serialNumber`, {
initialValue: v.serialNumber,
rules: [
{
pattern: new RegExp(/^[0-9a-zA-Z-_]{6,32}$/, 'g'),
message: '序列号格式不正确!',
},
],
})(<Input placeholder="请填写序列号" />)}
</FormItem>
</Card>
))}
<div className={style.logistics}>
<PlusCircleOutlined className={style.logisticsIcon} onClick={addForm} />
<MinusCircleOutlined className={style.logisticsIcon} onClick={rmForm} />
</div>
</Form>
</Modal>
);
};
export default Form.create()(LogisticsForm);
.sku-list-module {
margin-bottom: 20px;
padding: 10px 20px;
border: 1px solid #f2f2f2;
&__index {
margin-bottom: 5px;
font-weight: 700;
font-size: 14px;
}
}
.sku-list-box {
padding-bottom: 10px;
.sku-list {
display: flex;
// padding-bottom: 19px;
&__goods-name {
flex: 1;
margin-bottom: 0 !important;
}
&__goods-count {
width: 100px;
margin-bottom: 5px !important;
}
}
}
.operation {
font-size: 24px;
text-align: center;
> * {
margin: 0 10px;
}
}
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;
This diff is collapsed.
@import '~antd/es/style/themes/default.less';
.protable {
:global {
.tableContent {
display: flex;
align-items: center;
// height: 60px;
min-height: 60px;
padding: 0 12px;
}
.border {
border-bottom: 1px solid #e8e8e8;
}
.subContent {
flex: 1;
padding: 12px;
overflow: hidden;
line-height: 36px;
white-space: nowrap;
text-overflow: ellipsis;
}
.expressList {
display: flex;
flex-direction: column;
width: calc(100% + 24px);
height: 100%;
margin: -12px;
}
tbody .colStyle {
padding: 0;
}
.ant-popover-title {
max-width: 300px;
overflow: hidden;
}
}
}
.tabpane {
:global {
.ant-tabs-content {
min-height: 200px;
max-height: 700px;
overflow: auto;
}
}
}
.btnWarning {
background-color: rgb(247, 143, 74) !important;
border-color: rgb(247, 143, 74) !important;
}
.btnWarning:hover,
.btnWarning:focus {
background-color: rgb(253, 168, 111) !important;
border-color: rgb(253, 168, 111) !important;
}
.tableList {
.tableListOperator {
margin-bottom: 16px;
button {
margin-right: 8px;
}
}
}
.tableListForm {
:global {
.ant-form-item {
display: flex;
margin-right: 0;
margin-bottom: 15px;
> .ant-form-item-label {
width: auto;
padding-right: 8px;
line-height: 32px;
}
.ant-form-item-control {
line-height: 32px;
}
}
.ant-form-item-control-wrapper {
flex: 1;
}
}
.submitButtons {
display: block;
margin-bottom: 24px;
white-space: nowrap;
}
}
.button {
margin-right: 10px;
}
.buttonWrap {
margin: 10px 0 15px 0;
button {
margin-right: 10px;
}
}
.subContent {
height: 400px;
overflow: auto;
}
.wrapCont {
overflow: hidden;
}
.treeCont {
float: left;
width: 20%;
overflow: auto;
}
.tableCont {
float: right;
width: 78%;
}
.logistics {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 30px;
margin-top: 24px;
}
.logisticsIcon {
font-size: 25px;
&:first-child {
margin-right: 10px;
}
}
.notice-btn {
max-width: 120px;
margin: 0 auto;
text-align: center;
button {
margin: 5px 0;
}
}
// 催发货图标
.urge-box {
white-space: nowrap;
}
.urge {
display: inline-block;
width: 36px;
height: 17px;
margin-left: 5px;
color: #ff1515;
font-size: 12px;
line-height: 16px;
text-align: center;
border: 1px solid #ff1515;
border-radius: 18px;
cursor: pointer;
}
.popover-notice-box {
max-height: 300px;
margin-right: -15px;
padding-right: 15px;
overflow: auto;
}
.popover-notice {
max-width: 400px;
line-height: 32px;
word-break: break-all;
}
import * as api from './service';
const tableDate = [{}];
const Model = {
namespace: 'popPendingDeliveryOrder',
state: {
tableData: [],
typeList: [],
organizationList: [],
},
effects: {
*getSubjectList({ payload }, { call, put }) {
yield put({
type: 'saveData',
payload: {
tableData: tableDate,
},
});
// const response = yield call(api.subjectList, payload);
// if (response.code === 2000) {
// yield put({
// type: 'saveData',
// payload: {
// tableData: response.data,
// },
// });
// }
},
*subjectTypeList({ payload }, { call, put }) {
// const response = yield call(api.subjectTypeList, payload);
// if (response.code === 2000) {
// yield put({
// type: 'saveData',
// payload: {
// typeList: response.data,
// },
// });
// }
},
*organizationList({ payload }, { call, put }) {
// const response = yield call(api.organizationList, payload);
// if (response.code === 2000) {
// yield put({
// type: 'saveData',
// payload: {
// organizationList: response.data,
// },
// });
// }
},
},
reducers: {
saveData(state, action) {
const data = action.payload;
return { ...state, ...data };
},
},
};
export default Model;
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 queryToSend(params) {
try {
const {
data: { current, records, total, size },
} = await request.post('/api/merchants/orders/list', {
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 queryExpress() {
try {
const { data } = await request.get('/api/merchants/companies/list', {
prefix: config.kdspApi,
});
return data;
} catch (error) {
return {};
}
}
export async function getGoods(orderId) {
const { data } = await request.get(`/api/merchants/orders/skus/list?orderId=${orderId}`, {
prefix: config.kdspApi,
});
return data;
}
export async function uploadFile(file) {
const params = new FormData();
params.append('file', file);
const data = await request.post('/api/merchants/orders/deliveries/batches/import', {
data: params,
prefix: config.kdspApi,
});
return data;
}
export function downTemplate() {
window.location.href = 'https://sc-img.q-gp.com/orders/templates/batch_deliveriesV2.xlsx';
}
export async function downOrder(params) {
const data = await request.post('/api/merchants/orders/export', {
data: stringify(_.omitBy(params, v => !v)),
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
prefix: config.kdspApi,
responseType: 'arrayBuffer',
});
const blob = new Blob([data]);
saveAs(blob, `商户订单列表-${format(new Date(), 'yyyyMMddHHmmss')}.xlsx`);
}
// 批量发货订单
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/merchants/deliveries/batchlist', {
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/merchants/deliveries/batchexport', {
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`);
}
// 延迟发货
export function apiDelayDeliverGoods(data) {
return request.post('/api/merchants/orders/logs/add', {
data,
prefix: config.kdspApi,
});
}
/**
* 多物流发货-查询多物流订单信息
* @param {*} params
* @returns
* @see http://yapi.quantgroups.com/project/389/interface/api/45840
*/
export function apiQueryOrderInfo(params) {
return request.get('/api/merchants/orders/deliveries/packages/detail', {
params,
prefix: config.kdspApi,
});
}
/**
* 多物流发货-新建发货/更新发货信息
* @param {*} data
* @returns
* @see http://yapi.quantgroups.com/project/389/interface/api/45816
*/
export function apiDeliveriesAdd(data) {
return request.post('/api/merchants/orders/deliveries/add', {
data,
prefix: config.kdspApi,
});
}
export function apiDeliveriesEdit(data) {
return request.post('/api/merchants/orders/deliveries/edit', {
data,
prefix: config.kdspApi,
});
}
/**
* 多物流发货-查询物流轨迹
* @see http://yapi.quantgroups.com/project/389/interface/api/46120
*/
export function apiDeliveriesTraceList(data) {
return request.post('/api/merchants/deliveries/traces/list', {
data: stringify(data),
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
prefix: config.kdspApi,
});
}
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