forked from yoone/WEB
1
0
Fork 0

客户列表

This commit is contained in:
cll 2025-07-19 11:54:10 +08:00
parent 354812c7c4
commit b5d05bfc65
27 changed files with 1165 additions and 122 deletions

View File

@ -80,12 +80,12 @@ export default defineConfig({
component: './Stock/Warehouse', component: './Stock/Warehouse',
}, },
{ {
name: '入库管理', name: '采购管理',
path: '/stock/purchaseOrder', path: '/stock/purchaseOrder',
component: './Stock/PurchaseOrder', component: './Stock/PurchaseOrder',
}, },
{ {
name: '调拨管理', name: '发货管理',
path: '/stock/transfer', path: '/stock/transfer',
component: './Stock/Transfer', component: './Stock/Transfer',
}, },
@ -106,6 +106,23 @@ export default defineConfig({
path: '/order/list', path: '/order/list',
component: './Order/List', component: './Order/List',
}, },
{
name: '待发货产品',
path: '/order/item',
component: './Order/PendingItems',
},
],
},
{
name: '客户管理',
path: '/customer',
access: 'canSeeAdmin',
routes: [
{
name: '客户列表',
path: '/customer/list',
component: './Customer/List',
},
], ],
}, },
// { // {
@ -145,6 +162,12 @@ export default defineConfig({
component: './Statistics/Order', component: './Statistics/Order',
access: 'canSeeSuper', access: 'canSeeSuper',
}, },
{
name: '订单来源',
path: '/statistics/orderSource',
component: './Statistics/OrderSource',
access: 'canSeeSuper',
},
{ {
name: '客户统计', name: '客户统计',
path: '/statistics/customer', path: '/statistics/customer',

View File

@ -22,8 +22,10 @@
"dayjs": "^1.11.9", "dayjs": "^1.11.9",
"echarts": "^5.6.0", "echarts": "^5.6.0",
"echarts-for-react": "^3.0.2", "echarts-for-react": "^3.0.2",
"file-saver": "^2.0.5",
"print-js": "^1.6.0", "print-js": "^1.6.0",
"react-phone-input-2": "^2.15.1" "react-phone-input-2": "^2.15.1",
"xlsx": "^0.18.5"
}, },
"devDependencies": { "devDependencies": {
"@types/react": "^18.0.33", "@types/react": "^18.0.33",

View File

@ -0,0 +1,247 @@
import { HistoryOrder } from '@/pages/Statistics/Order';
import {
customercontrollerAddtag,
customercontrollerDeltag,
customercontrollerGetcustomerlist,
customercontrollerGettags,
} from '@/servers/api/customer';
import {
ActionType,
ModalForm,
PageContainer,
ProColumns,
ProFormSelect,
ProTable,
} from '@ant-design/pro-components';
import { App, Button, Space, Tag } from 'antd';
import dayjs from 'dayjs';
import { useRef, useState } from 'react';
const ListPage: React.FC = () => {
const actionRef = useRef<ActionType>();
const columns: ProColumns[] = [
{
title: '用户名',
dataIndex: 'username',
hideInSearch: true,
render: (_, record) => {
if (record.billing.first_name || record.billing.last_name)
return record.billing.first_name + ' ' + record.billing.last_name;
return record.shipping.first_name + ' ' + record.shipping.last_name;
},
},
{
title: '邮箱',
dataIndex: 'email',
},
{
title: '客户编号',
dataIndex: 'customerId',
render: (_, record) => {
if(!record.customerId) return '-';
return String(record.customerId).padStart(6,0)
},
sorter: true,
},
{
title: '首单时间',
dataIndex: 'first_purchase_date',
valueType: 'dateMonth',
sorter: true,
render: (_, record) =>
record.first_purchase_date
? dayjs(record.first_purchase_date).format('YYYY-MM-DD HH:mm:ss')
: '-',
// search: {
// transform: (value: string) => {
// return { month: value };
// },
// },
},
{
title: '尾单时间',
hideInSearch: true,
dataIndex: 'last_purchase_date',
valueType: 'dateTime',
sorter: true,
},
{
title: '订单数',
dataIndex: 'orders',
hideInSearch: true,
sorter: true,
},
{
title: '金额',
dataIndex: 'total',
hideInSearch: true,
sorter: true,
},
{
title: 'YOONE订单数',
dataIndex: 'yoone_orders',
hideInSearch: true,
sorter: true,
},
{
title: 'YOONE金额',
dataIndex: 'yoone_total',
hideInSearch: true,
sorter: true,
},
{
title: 'state',
dataIndex: 'state',
render: (_, record) => record?.billing.state || record?.shipping.state,
},
{
title: 'city',
dataIndex: 'city',
hideInSearch: true,
render: (_, record) => record?.billing.city || record?.shipping.city,
},
{
title: '标签',
dataIndex: 'tags',
render: (_, record) => {
return (
<Space>
{(record.tags || []).map((tag) => {
return (
<Tag
key={tag}
closable
onClose={async () => {
const { success, message: msg } =
await customercontrollerDeltag({
email: record.email,
tag,
});
return false;
}}
>
{tag}
</Tag>
);
})}
</Space>
);
},
},
{
title: '操作',
dataIndex: 'option',
valueType: 'option',
render: (_, record) => {
return (
<Space>
<AddTag
email={record.email}
tags={record.tags}
tableRef={actionRef}
/>
<HistoryOrder
email={record.email}
tags={record.tags}
tableRef={actionRef}
/>
</Space>
);
},
},
];
return (
<PageContainer ghost>
<ProTable
headerTitle="查询表格"
actionRef={actionRef}
rowKey="id"
request={async (params, sorter) => {
const key = Object.keys(sorter)[0];
const { data, success } = await customercontrollerGetcustomerlist({
...params,
...(key ? { sorterKey: key, sorterValue: sorter[key] } : {}),
});
return {
total: data?.total || 0,
data: data?.items || [],
success,
};
}}
columns={columns}
/>
</PageContainer>
);
};
export const AddTag: React.FC<{
email: string;
tags?: string[];
tableRef: React.MutableRefObject<ActionType | undefined>;
}> = ({ email, tags, tableRef }) => {
const { message } = App.useApp();
const [tagList, setTagList] = useState<string[]>([]);
return (
<ModalForm
title={`修改标签 - ${email}`}
trigger={<Button></Button>}
width={800}
modalProps={{
destroyOnHidden: true,
}}
submitter={false}
>
<ProFormSelect
mode="tags"
allowClear
name="tag"
label="标签"
request={async () => {
const { data, success } = await customercontrollerGettags();
if (!success) return [];
setTagList(tags || []);
return data
.filter((tag) => {
return !(tags || []).includes(tag);
})
.map((tag) => ({ label: tag, value: tag }));
}}
fieldProps={{
value: tagList, // 当前值
onChange: async (newValue) => {
const added = newValue.filter((x) => !tagList.includes(x));
const removed = tagList.filter((x) => !newValue.includes(x));
if (added.length) {
const { success, message: msg } = await customercontrollerAddtag({
email,
tag: added[0],
});
if (!success) {
message.error(msg);
return;
}
}
if (removed.length) {
const { success, message: msg } = await customercontrollerDeltag({
email,
tag: removed[0],
});
if (!success) {
message.error(msg);
return;
}
}
tableRef?.current?.reload();
setTagList(newValue);
},
}}
></ProFormSelect>
</ModalForm>
);
};
export default ListPage;

View File

@ -154,7 +154,7 @@ const CreateForm: React.FC<{
} }
autoFocusFirstInput autoFocusFirstInput
drawerProps={{ drawerProps={{
destroyOnClose: true, destroyOnHidden: true,
}} }}
onFinish={async (values) => { onFinish={async (values) => {
const { contact, ...params } = values; const { contact, ...params } = values;
@ -284,7 +284,7 @@ const UpdateForm: React.FC<{
} }
autoFocusFirstInput autoFocusFirstInput
drawerProps={{ drawerProps={{
destroyOnClose: true, destroyOnHidden: true,
}} }}
onFinish={async (values) => { onFinish={async (values) => {
const { contact, ...params } = values; const { contact, ...params } = values;

View File

@ -423,7 +423,7 @@ const SyncForm: React.FC<{
} }
autoFocusFirstInput autoFocusFirstInput
drawerProps={{ drawerProps={{
destroyOnClose: true, destroyOnHidden: true,
}} }}
onFinish={async (values) => { onFinish={async (values) => {
try { try {
@ -501,7 +501,7 @@ const Detail: React.FC<{
<Drawer <Drawer
title="订单详情" title="订单详情"
open={visiable} open={visiable}
destroyOnClose destroyOnHidden
size="large" size="large"
onClose={() => setVisiable(false)} onClose={() => setVisiable(false)}
footer={[ footer={[
@ -1036,7 +1036,7 @@ const Shipping: React.FC<{
size="large" size="large"
width="80vw" width="80vw"
modalProps={{ modalProps={{
destroyOnClose: true, destroyOnHidden: true,
styles: { styles: {
body: { maxHeight: '65vh', overflowY: 'auto', overflowX: 'hidden' }, body: { maxHeight: '65vh', overflowY: 'auto', overflowX: 'hidden' },
}, },
@ -1265,7 +1265,7 @@ const Shipping: React.FC<{
<ProFormSelect <ProFormSelect
params={{ options }} params={{ options }}
request={async ({ keyWords, options }) => { request={async ({ keyWords, options }) => {
if (!keyWords || keyWords.length < 3) return options; if (!keyWords || keyWords.length < 2) return options;
try { try {
const { data } = await productcontrollerSearchproducts({ const { data } = await productcontrollerSearchproducts({
name: keyWords, name: keyWords,
@ -1273,7 +1273,7 @@ const Shipping: React.FC<{
return ( return (
data?.map((item) => { data?.map((item) => {
return { return {
label: item?.name, label: `${item.name} - ${item.nameCn}`,
value: item?.sku, value: item?.sku,
}; };
}) || options }) || options
@ -1802,7 +1802,7 @@ const CreateOrder: React.FC<{
size="large" size="large"
width="80vw" width="80vw"
modalProps={{ modalProps={{
destroyOnClose: true, destroyOnHidden: true,
styles: { styles: {
body: { maxHeight: '65vh', overflowY: 'auto', overflowX: 'hidden' }, body: { maxHeight: '65vh', overflowY: 'auto', overflowX: 'hidden' },
}, },
@ -1844,7 +1844,7 @@ const CreateOrder: React.FC<{
<ProForm.Group> <ProForm.Group>
<ProFormSelect <ProFormSelect
request={async ({ keyWords, options }) => { request={async ({ keyWords, options }) => {
if (!keyWords || keyWords.length < 3) return options; if (!keyWords || keyWords.length < 2) return options;
try { try {
const { data } = await productcontrollerSearchproducts({ const { data } = await productcontrollerSearchproducts({
name: keyWords, name: keyWords,
@ -1852,7 +1852,7 @@ const CreateOrder: React.FC<{
return ( return (
data?.map((item) => { data?.map((item) => {
return { return {
label: item?.name, label: `${item.name} - ${item.nameCn}`,
value: item?.sku, value: item?.sku,
}; };
}) || options }) || options
@ -2011,7 +2011,7 @@ const AddressPicker: React.FC<{
<ModalForm <ModalForm
title="选择地址" title="选择地址"
trigger={<Button type="primary"></Button>} trigger={<Button type="primary"></Button>}
modalProps={{ destroyOnClose: true }} modalProps={{ destroyOnHidden: true }}
onFinish={async () => { onFinish={async () => {
if (!selectedRow) { if (!selectedRow) {
message.error('请选择地址'); message.error('请选择地址');

View File

@ -0,0 +1,100 @@
import { ordercontrollerPengdingitems } from '@/servers/api/order';
import { stockcontrollerGetallstockpoints } from '@/servers/api/stock';
import {
ActionType,
PageContainer,
ProColumns,
ProTable,
} from '@ant-design/pro-components';
import { App, Button } from 'antd';
import { saveAs } from 'file-saver';
import { useEffect, useRef, useState } from 'react';
import * as XLSX from 'xlsx';
const ListPage: React.FC = () => {
const { message } = App.useApp();
const actionRef = useRef<ActionType>();
const [points, setPoints] = useState<API.StockPoint[]>([]);
useEffect(() => {
stockcontrollerGetallstockpoints().then(({ data }) => {
setPoints(data as API.StockPoint[]);
});
}, []);
const columns: ProColumns<API.StockDTO>[] = [
{
title: '产品名称',
dataIndex: 'name',
hideInSearch: true,
},
{
title: '数量',
dataIndex: 'quantity',
hideInSearch: true,
},
{
title: '订单号',
dataIndex: 'numbers',
hideInSearch: true,
width: 800,
render: (_, record) => {
return record?.numbers?.join?.('、');
},
},
];
return (
<PageContainer ghost>
<ProTable<API.StockDTO>
headerTitle="查询表格"
actionRef={actionRef}
rowKey="id"
request={async (params) => {
const { data, success } = await ordercontrollerPengdingitems(params);
return {
total: data?.total || 0,
data: data?.items || [],
success,
};
}}
columns={columns}
toolBarRender={() => [
<Button
type="primary"
onClick={async () => {
const { data, success } = await ordercontrollerPengdingitems({
current: 1,
pageSize: 20000,
});
if (!success) return;
// 表头
const headers = ['产品名', '数量', '订单号'];
// 数据行
const rows = (data?.items || []).map((item) => {
return [item.name, item.quantity, item.numbers?.join('、')];
});
// 导出
const sheet = XLSX.utils.aoa_to_sheet([headers, ...rows]);
const book = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(book, sheet, '待发产品');
const buffer = XLSX.write(book, {
bookType: 'xlsx',
type: 'array',
});
const blob = new Blob([buffer], {
type: 'application/octet-stream',
});
saveAs(blob, '待发产品.xlsx');
}}
>
</Button>,
]}
/>
</PageContainer>
);
};
export default ListPage;

View File

@ -84,7 +84,7 @@ const CreateForm: React.FC<{
} }
autoFocusFirstInput autoFocusFirstInput
drawerProps={{ drawerProps={{
destroyOnClose: true, destroyOnHidden: true,
}} }}
onFinish={async (values) => { onFinish={async (values) => {
try { try {

View File

@ -122,7 +122,7 @@ const CreateForm: React.FC<{
} }
autoFocusFirstInput autoFocusFirstInput
drawerProps={{ drawerProps={{
destroyOnClose: true, destroyOnHidden: true,
}} }}
onFinish={async (values) => { onFinish={async (values) => {
try { try {
@ -174,7 +174,7 @@ const UpdateForm: React.FC<{
} }
autoFocusFirstInput autoFocusFirstInput
drawerProps={{ drawerProps={{
destroyOnClose: true, destroyOnHidden: true,
}} }}
onFinish={async (values) => { onFinish={async (values) => {
try { try {

View File

@ -120,7 +120,7 @@ const CreateForm: React.FC<{
} }
autoFocusFirstInput autoFocusFirstInput
drawerProps={{ drawerProps={{
destroyOnClose: true, destroyOnHidden: true,
}} }}
onFinish={async (values) => { onFinish={async (values) => {
try { try {
@ -172,7 +172,7 @@ const UpdateForm: React.FC<{
} }
autoFocusFirstInput autoFocusFirstInput
drawerProps={{ drawerProps={{
destroyOnClose: true, destroyOnHidden: true,
}} }}
onFinish={async (values) => { onFinish={async (values) => {
try { try {

View File

@ -5,6 +5,7 @@ import {
productcontrollerGetflavorsall, productcontrollerGetflavorsall,
productcontrollerGetproductlist, productcontrollerGetproductlist,
productcontrollerGetstrengthall, productcontrollerGetstrengthall,
productcontrollerUpdateproductnamecn,
} from '@/servers/api/product'; } from '@/servers/api/product';
import { PlusOutlined } from '@ant-design/icons'; import { PlusOutlined } from '@ant-design/icons';
import { import {
@ -21,6 +22,28 @@ import {
import { App, Button, Popconfirm } from 'antd'; import { App, Button, Popconfirm } from 'antd';
import React, { useRef } from 'react'; import React, { useRef } from 'react';
const NameCn: React.FC<{
id: number;
value: string;
tableRef: React.MutableRefObject<ActionType | undefined>;
}> = ({value,tableRef, id}) => {
const { message } = App.useApp();
const [editable, setEditable] = React.useState<boolean>(false);
if (!editable) return <div onClick={() => setEditable(true)}>{value||'-'}</div>;
return <ProFormText fieldProps={{autoFocus:true}} initialValue={value} onBlur={async(e) => {
if(!e.target.value) return setEditable(false)
const { success, message: errMsg } =
await productcontrollerUpdateproductnamecn({
id,
nameCn: e.target.value,
})
setEditable(false)
if (!success) {
return message.error(errMsg)
}
tableRef?.current?.reload()
}} />
}
const List: React.FC = () => { const List: React.FC = () => {
const actionRef = useRef<ActionType>(); const actionRef = useRef<ActionType>();
@ -30,6 +53,15 @@ const List: React.FC = () => {
title: '名称', title: '名称',
dataIndex: 'name', dataIndex: 'name',
}, },
{
title: '中文名',
dataIndex: 'nameCn',
render: (_, record) => {
return (
<NameCn value={record.nameCn} id={record.id} tableRef={actionRef} />
)
},
},
{ {
title: '产品描述', title: '产品描述',
dataIndex: 'description', dataIndex: 'description',
@ -117,6 +149,12 @@ const List: React.FC = () => {
}; };
}} }}
columns={columns} columns={columns}
editable={{
type: 'single',
onSave: async (key, record, originRow) => {
console.log('保存数据:', record);
},
}}
rowSelection={{ rowSelection={{
onChange: (_, selectedRows) => setSelectedRows(selectedRows), onChange: (_, selectedRows) => setSelectedRows(selectedRows),
}} }}
@ -140,7 +178,7 @@ const CreateForm: React.FC<{
} }
autoFocusFirstInput autoFocusFirstInput
drawerProps={{ drawerProps={{
destroyOnClose: true, destroyOnHidden: true,
}} }}
onFinish={async (values) => { onFinish={async (values) => {
try { try {

View File

@ -118,7 +118,7 @@ const CreateForm: React.FC<{
} }
autoFocusFirstInput autoFocusFirstInput
drawerProps={{ drawerProps={{
destroyOnClose: true, destroyOnHidden: true,
}} }}
onFinish={async (values) => { onFinish={async (values) => {
try { try {
@ -170,7 +170,7 @@ const CreateForm: React.FC<{
// } // }
// autoFocusFirstInput // autoFocusFirstInput
// drawerProps={{ // drawerProps={{
// destroyOnClose: true, // destroyOnHidden: true,
// }} // }}
// onFinish={async (values) => { // onFinish={async (values) => {
// try { // try {

View File

@ -196,7 +196,7 @@ const SyncForm: React.FC<{
} }
autoFocusFirstInput autoFocusFirstInput
drawerProps={{ drawerProps={{
destroyOnClose: true, destroyOnHidden: true,
}} }}
onFinish={async (values) => { onFinish={async (values) => {
try { try {
@ -249,7 +249,7 @@ const UpdateForm: React.FC<{
} }
autoFocusFirstInput autoFocusFirstInput
drawerProps={{ drawerProps={{
destroyOnClose: true, destroyOnHidden: true,
}} }}
onFinish={async (values) => { onFinish={async (values) => {
const { siteId, ...params } = values; const { siteId, ...params } = values;
@ -339,7 +339,7 @@ const UpdateVaritation: React.FC<{
} }
autoFocusFirstInput autoFocusFirstInput
drawerProps={{ drawerProps={{
destroyOnClose: true, destroyOnHidden: true,
}} }}
onFinish={async (values) => { onFinish={async (values) => {
const { ...params } = values; const { ...params } = values;
@ -434,7 +434,7 @@ const SetComponent: React.FC<{
} }
autoFocusFirstInput autoFocusFirstInput
drawerProps={{ drawerProps={{
destroyOnClose: true, destroyOnHidden: true,
}} }}
onFinish={async ({ constitution }) => { onFinish={async ({ constitution }) => {
try { try {

View File

@ -1,4 +1,6 @@
import { ORDER_STATUS_ENUM } from '@/constants'; import { ORDER_STATUS_ENUM } from '@/constants';
import { AddTag } from '@/pages/Customer/List';
import { customercontrollerDeltag } from '@/servers/api/customer';
import { sitecontrollerAll } from '@/servers/api/site'; import { sitecontrollerAll } from '@/servers/api/site';
import { import {
statisticscontrollerGetorderbydate, statisticscontrollerGetorderbydate,
@ -7,6 +9,7 @@ import {
} from '@/servers/api/statistics'; } from '@/servers/api/statistics';
import { formatSource } from '@/utils/format'; import { formatSource } from '@/utils/format';
import { import {
ActionType,
ModalForm, ModalForm,
PageContainer, PageContainer,
ProForm, ProForm,
@ -14,10 +17,10 @@ import {
ProFormSelect, ProFormSelect,
ProTable, ProTable,
} from '@ant-design/pro-components'; } from '@ant-design/pro-components';
import { Button } from 'antd'; import { Button, Space, Tag } from 'antd';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import ReactECharts from 'echarts-for-react'; import ReactECharts from 'echarts-for-react';
import { useEffect, useMemo, useState } from 'react'; import { useEffect, useMemo, useRef, useState } from 'react';
const highlightText = (text: string, keyword: string) => { const highlightText = (text: string, keyword: string) => {
if (!keyword) return text; if (!keyword) return text;
@ -43,6 +46,7 @@ const ListPage: React.FC = () => {
tooltip: { tooltip: {
trigger: 'axis', trigger: 'axis',
formatter: function (params) { formatter: function (params) {
const xValue = params[0].axisValue;
const items = params.map((item) => { const items = params.map((item) => {
return `<span style="display: inline-block;width: 250px">${item.marker} ${item.seriesName}: ${item.value}</span>`; return `<span style="display: inline-block;width: 250px">${item.marker} ${item.seriesName}: ${item.value}</span>`;
}); });
@ -53,7 +57,13 @@ const ListPage: React.FC = () => {
rows.push(items.slice(i, i + 4).join('')); rows.push(items.slice(i, i + 4).join(''));
} }
return rows.join('<br/>'); return (
`<div>${xValue} ${
['周日', '周一', '周二', '周三', '周四', '周五', '周六'][
dayjs(xValue).day()
]
}</div>` + rows.join('<br/>')
);
}, },
}, },
legend: { legend: {
@ -120,28 +130,6 @@ const ListPage: React.FC = () => {
const res = data?.sort(() => -1); const res = data?.sort(() => -1);
setXAxis(res?.map((v) => dayjs(v.order_date).format('YYYY-MM-DD'))); setXAxis(res?.map((v) => dayjs(v.order_date).format('YYYY-MM-DD')));
setSeries([ setSeries([
{
name: '首购订单数',
type: 'line',
data: res?.map((v) => v.first_purchase_orders),
},
{
name: '首购金额',
type: 'line',
yAxisIndex: 1,
data: res?.map((v) => v.first_purchase_total),
},
{
name: '复购订单数',
type: 'line',
data: res?.map((v) => v.repeat_purchase_orders),
},
{
name: '复购金额',
type: 'line',
yAxisIndex: 1,
data: res?.map((v) => v.repeat_purchase_total),
},
{ {
name: 'TOGO CPC订单数', name: 'TOGO CPC订单数',
type: 'line', type: 'line',
@ -162,6 +150,50 @@ const ListPage: React.FC = () => {
type: 'line', type: 'line',
data: res?.map((v) => v.non_can_cpc_orders), data: res?.map((v) => v.non_can_cpc_orders),
}, },
{
name: '直达订单数',
type: 'line',
data: res?.map((v) => v.direct_orders),
},
{
name: '直达金额',
type: 'line',
yAxisIndex: 1,
data: res?.map((v) => v.direct_total),
},
{
name: '首购订单数',
type: 'line',
data: res?.map((v) => v.first_purchase_orders),
},
{
name: '首购金额',
type: 'line',
yAxisIndex: 1,
data: res?.map((v) => v.first_purchase_total),
},
{
name: 'organic订单数',
type: 'line',
data: res?.map((v) => v.organic_orders),
},
{
name: 'organic金额',
type: 'line',
yAxisIndex: 1,
data: res?.map((v) => v.organic_total),
},
{
name: '复购订单数',
type: 'line',
data: res?.map((v) => v.repeat_purchase_orders),
},
{
name: '复购金额',
type: 'line',
yAxisIndex: 1,
data: res?.map((v) => v.repeat_purchase_total),
},
{ {
name: 'CPC订单数', name: 'CPC订单数',
type: 'line', type: 'line',
@ -612,6 +644,7 @@ const DailyOrders: React.FC<{
selectedDate; selectedDate;
}> = ({ selectedDate }) => { }> = ({ selectedDate }) => {
const [orders, setOrders] = useState([]); const [orders, setOrders] = useState([]);
const actionRef = useRef<ActionType>();
useEffect(() => { useEffect(() => {
if (!selectedDate) { if (!selectedDate) {
setOrders([]); setOrders([]);
@ -683,6 +716,12 @@ const DailyOrders: React.FC<{
valueType: 'dateTime', valueType: 'dateTime',
sorter: true, sorter: true,
}, },
{
title: '尾单时间',
dataIndex: 'last_purchase_date',
valueType: 'dateTime',
sorter: true,
},
{ {
title: '支付时间', title: '支付时间',
dataIndex: 'date_paid', dataIndex: 'date_paid',
@ -784,12 +823,53 @@ const DailyOrders: React.FC<{
); );
}, },
}, },
{
title: '标签',
dataIndex: 'tags',
render: (_, record) => {
return (
<Space>
{(record.tags || []).map((tag) => {
return (
<Tag
key={tag}
closable
onClose={async () => {
const { success, message: msg } =
await customercontrollerDeltag({
email: record.email,
tag,
});
return false;
}}
>
{tag}
</Tag>
);
})}
</Space>
);
},
},
{ {
title: '操作', title: '操作',
dataIndex: 'action', dataIndex: 'action',
valueType: 'option', valueType: 'option',
render: (_, record) => { render: (_, record) => {
return <HistoryOrder email={record.customer_email} />; return (
<Space>
<AddTag
email={record.customer_email}
tags={record.tags}
tableRef={actionRef}
/>
<HistoryOrder
email={record.customer_email}
tags={record.tags}
tableRef={actionRef}
/>
</Space>
);
}, },
}, },
]} ]}
@ -799,15 +879,19 @@ const DailyOrders: React.FC<{
); );
}; };
const HistoryOrder: React.FC<{ export const HistoryOrder: React.FC<{
email: string; email: string;
}> = ({ email }) => { tags?: string[];
tableRef: React.MutableRefObject<ActionType | undefined>;
}> = ({ email, tags, tableRef }) => {
const actionRef = useRef<ActionType>();
return ( return (
<ModalForm <ModalForm
title={`历史订单${email}`} title={`历史订单${email}`}
trigger={<Button type="primary"></Button>} trigger={<Button type="primary"></Button>}
modalProps={{ destroyOnClose: true, footer: null }} modalProps={{ destroyOnHidden: true, footer: null }}
width="80vw" width="80vw"
submitter={false}
> >
<ProTable <ProTable
search={false} search={false}
@ -869,6 +953,34 @@ const HistoryOrder: React.FC<{
); );
}, },
}, },
{
title: '标签',
dataIndex: 'tags',
render: (_, record) => {
return (
<Space>
{(record.tags || []).map((tag) => {
return (
<Tag
key={tag}
// closable
onClose={async () => {
const { success, message: msg } =
await customercontrollerDeltag({
email,
tag,
});
return false;
}}
>
{tag}
</Tag>
);
})}
</Space>
);
},
},
]} ]}
request={async () => { request={async () => {
const { data, success } = await statisticscontrollerGetorderbyemail({ const { data, success } = await statisticscontrollerGetorderbyemail({
@ -879,6 +991,9 @@ const HistoryOrder: React.FC<{
success, success,
}; };
}} }}
toolBarRender={() => [
<AddTag email={email} tags={tags} tableRef={actionRef} />,
]}
/> />
</ModalForm> </ModalForm>
); );

View File

@ -0,0 +1,257 @@
import React, { useEffect, useState, useMemo, useRef } from "react"
import {
ActionType,
PageContainer, ProColumns, ProTable,
} from '@ant-design/pro-components';
import { statisticscontrollerGetordersorce, statisticscontrollerGetinativeusersbymonth } from "@/servers/api/statistics";
import ReactECharts from 'echarts-for-react';
import { App, Button, Space, Tag } from 'antd';
import { HistoryOrder } from "../Order";
import dayjs from 'dayjs';
const ListPage: React.FC = () => {
const [data, setData] = useState({});
useEffect(() => {
statisticscontrollerGetordersorce().then(({ data, success }) => {
if(success) setData(data)
});
}, []);
const option = useMemo(() => {
if(!data.inactiveRes) return {}
const xAxisData = data?.inactiveRes?.map(v=> v.order_month)?.sort(_=>-1)
const arr = data?.res?.map(v=>v.first_order_month_group)
const uniqueArr = arr.filter((item, index) => arr.indexOf(item) === index)
const series = [
{
name: '新客户',
type: 'bar',
data: data?.inactiveRes?.map(v=> v.new_user_count)?.sort(_=>-1),
label: {
show: true,
},
emphasis: {
focus: 'series'
},
xAxisIndex: 0,
yAxisIndex: 0,
},
{
name: '老客户',
type: 'bar',
data: data?.inactiveRes?.map(v=> v.old_user_count)?.sort(_=>-1),
label: {
show: true,
},
emphasis: {
focus: 'series'
},
xAxisIndex: 0,
yAxisIndex: 0,
},
...uniqueArr?.map(v => {
data?.res?.filter(item => item.order_month === v)
return {
name: v,
type: "bar",
stack: "total",
label: {
"show": true,
formatter: function(params) {
if(!params.value) return ''
return Math.abs(params.value)
},
color: '#fff'
},
"data": xAxisData.map(month => {
return (data?.res?.find(item => item.order_month === month && item.first_order_month_group === v)?.order_count || 0)
}),
xAxisIndex: 0,
yAxisIndex: 0,
}
}),
{
name: '未复购客户',
type: 'bar',
data: data?.inactiveRes?.map(v=> -v.inactive_user_count)?.sort(_=>-1),
stack: "total",
label: {
show: true,
},
emphasis: {
focus: 'series'
},
xAxisIndex: 1,
yAxisIndex: 1,
barWidth: "60%",
itemStyle: {
color: '#f44336'
}
},
]
return {
grid: [
{ top: '10%', height: '70%' },
{ bottom: '10%', height: '10%' }
],
legend: {
selectedMode: false
},
xAxis: [{
type: 'category',
data: xAxisData,
gridIndex: 0,
},{
type: 'category',
data: xAxisData,
gridIndex: 1,
}],
yAxis: [{
type: 'value',
gridIndex: 0,
},{
type: 'value',
gridIndex: 1,
}],
series,
}
}, [data])
const [tableData, setTableData] = useState<any[]>([])
const actionRef = useRef<ActionType>();
const columns: ProColumns[] = [
{
title: '用户名',
dataIndex: 'username',
hideInSearch: true,
render: (_, record) => {
if (record.billing.first_name || record.billing.last_name)
return record.billing.first_name + ' ' + record.billing.last_name;
return record.shipping.first_name + ' ' + record.shipping.last_name;
},
},
{
title: '邮箱',
dataIndex: 'email',
},
{
title: '首单时间',
dataIndex: 'first_purchase_date',
valueType: 'dateMonth',
sorter: true,
render: (_, record) =>
record.first_purchase_date
? dayjs(record.first_purchase_date).format('YYYY-MM-DD HH:mm:ss')
: '-',
},
{
title: '尾单时间',
hideInSearch: true,
dataIndex: 'last_purchase_date',
valueType: 'dateTime',
sorter: true,
},
{
title: '订单数',
dataIndex: 'orders',
hideInSearch: true,
sorter: true,
},
{
title: '金额',
dataIndex: 'total',
hideInSearch: true,
sorter: true,
},
{
title: 'state',
dataIndex: 'state',
render: (_, record) => record?.billing.state || record?.shipping.state,
},
{
title: 'city',
dataIndex: 'city',
hideInSearch: true,
render: (_, record) => record?.billing.city || record?.shipping.city,
},
{
title: '标签',
dataIndex: 'tags',
render: (_, record) => {
return (
<Space>
{(record.tags || []).map((tag) => {
return (
<Tag
key={tag}
closable
onClose={async () => {
const { success, message: msg } =
await customercontrollerDeltag({
email: record.email,
tag,
});
return false;
}}
>
{tag}
</Tag>
);
})}
</Space>
);
},
},
{
title: '操作',
dataIndex: 'option',
valueType: 'option',
render: (_, record) => {
return (
<HistoryOrder
email={record.email}
tags={record.tags}
tableRef={actionRef}
/>
);
},
},
];
return(
<PageContainer ghost>
<ReactECharts
option={option}
style={{ height: 1050 }}
onEvents={{
click: async (params) => {
if (params.componentType === 'series') {
setTableData([])
const {success, data} = await statisticscontrollerGetinativeusersbymonth({
month: params.name
})
if(success) setTableData(data)
}
},
}}
/>
{
tableData?.length ?
<ProTable
search={false}
headerTitle="查询表格"
actionRef={actionRef}
rowKey="id"
dataSource={tableData}
columns={columns}
/>
:<></>
}
</PageContainer>
)
}
export default ListPage;

View File

@ -7,11 +7,15 @@ import {
ProFormSwitch, ProFormSwitch,
ProTable, ProTable,
} from '@ant-design/pro-components'; } from '@ant-design/pro-components';
import { Button } from 'antd';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { saveAs } from 'file-saver';
import { useRef, useState } from 'react'; import { useRef, useState } from 'react';
import * as XLSX from 'xlsx';
const ListPage: React.FC = () => { const ListPage: React.FC = () => {
const actionRef = useRef<ActionType>(); const actionRef = useRef<ActionType>();
const formRef = useRef();
const [total, setTotal] = useState(0); const [total, setTotal] = useState(0);
const [isSource, setIsSource] = useState(false); const [isSource, setIsSource] = useState(false);
const [yooneTotal, setYooneTotal] = useState({}); const [yooneTotal, setYooneTotal] = useState({});
@ -106,6 +110,7 @@ const ListPage: React.FC = () => {
<ProTable <ProTable
headerTitle="查询表格" headerTitle="查询表格"
actionRef={actionRef} actionRef={actionRef}
formRef={formRef}
rowKey="id" rowKey="id"
params={{ isSource }} params={{ isSource }}
form={{ form={{
@ -145,6 +150,43 @@ const ListPage: React.FC = () => {
dateFormatter="number" dateFormatter="number"
footer={() => `总计: ${total}`} footer={() => `总计: ${total}`}
toolBarRender={() => [ toolBarRender={() => [
<Button
type="primary"
onClick={async () => {
const { dateRange, param } = formRef.current?.getFieldsValue();
const [startDate, endDate] = dateRange.values();
const { data, success } = await ordercontrollerGetordersales({
startDate: dayjs(startDate).valueOf(),
endDate: dayjs(endDate).valueOf(),
...param,
current: 1,
pageSize: 20000,
});
if (!success) return;
// 表头
const headers = ['产品名', '数量'];
// 数据行
const rows = (data?.items || []).map((item) => {
return [item.name, item.totalQuantity];
});
// 导出
const sheet = XLSX.utils.aoa_to_sheet([headers, ...rows]);
const book = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(book, sheet, '销售');
const buffer = XLSX.write(book, {
bookType: 'xlsx',
type: 'array',
});
const blob = new Blob([buffer], {
type: 'application/octet-stream',
});
saveAs(blob, '销售.xlsx');
}}
>
</Button>,
<ProFormSwitch <ProFormSwitch
label="原产品" label="原产品"
fieldProps={{ fieldProps={{

View File

@ -8,8 +8,10 @@ import {
ProColumns, ProColumns,
ProTable, ProTable,
} from '@ant-design/pro-components'; } from '@ant-design/pro-components';
import { App } from 'antd'; import { App, Button } from 'antd';
import { saveAs } from 'file-saver';
import { useEffect, useRef, useState } from 'react'; import { useEffect, useRef, useState } from 'react';
import * as XLSX from 'xlsx';
const ListPage: React.FC = () => { const ListPage: React.FC = () => {
const { message } = App.useApp(); const { message } = App.useApp();
@ -25,6 +27,11 @@ const ListPage: React.FC = () => {
title: '产品名称', title: '产品名称',
dataIndex: 'productName', dataIndex: 'productName',
}, },
{
title: '中文名',
dataIndex: 'productNameCn',
hideInSearch: true,
},
{ {
title: 'SKU', title: 'SKU',
dataIndex: 'productSku', dataIndex: 'productSku',
@ -76,7 +83,44 @@ const ListPage: React.FC = () => {
}; };
}} }}
columns={columns} columns={columns}
// toolBarRender={() => [<CreateForm tableRef={actionRef} />]} toolBarRender={() => [
<Button
type="primary"
onClick={async () => {
const { data, success } = await stockcontrollerGetstocks({
current: 1,
pageSize: 20000,
});
if (!success) return;
// 表头
const headers = ['产品名', 'SKU', ...points.map((p) => p.name)];
// 数据行
const rows = (data?.items || []).map((item) => {
const stockMap = new Map(
item.stockPoint.map((sp) => [sp.id, sp.quantity]),
);
const stockRow = points.map((p) => stockMap.get(p.id) || 0);
return [item.productName, item.productSku, ...stockRow];
});
// 导出
const sheet = XLSX.utils.aoa_to_sheet([headers, ...rows]);
const book = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(book, sheet, '库存');
const buffer = XLSX.write(book, {
bookType: 'xlsx',
type: 'array',
});
const blob = new Blob([buffer], {
type: 'application/octet-stream',
});
saveAs(blob, '库存.xlsx');
}}
>
</Button>,
]}
/> />
</PageContainer> </PageContainer>
); );

View File

@ -57,6 +57,7 @@ const PurchaseOrderPage: React.FC = () => {
title: '数量', title: '数量',
hideInSearch: true, hideInSearch: true,
render(_, record) { render(_, record) {
if (!record.items) return 0;
return record.items.reduce((cur, next) => { return record.items.reduce((cur, next) => {
return cur + next.quantity; return cur + next.quantity;
}, 0); }, 0);
@ -187,7 +188,7 @@ const CreateForm: React.FC<{
autoFocusFirstInput autoFocusFirstInput
layout="vertical" layout="vertical"
drawerProps={{ drawerProps={{
destroyOnClose: true, destroyOnHidden: true,
}} }}
onFinish={async (values) => { onFinish={async (values) => {
try { try {
@ -267,7 +268,7 @@ const CreateForm: React.FC<{
<div key={idx}> <div key={idx}>
<ProFormSelect <ProFormSelect
request={async ({ keyWords }) => { request={async ({ keyWords }) => {
if (keyWords.length < 3) return []; if (keyWords.length < 2) return [];
try { try {
const { data } = await productcontrollerSearchproducts({ const { data } = await productcontrollerSearchproducts({
name: keyWords, name: keyWords,
@ -275,7 +276,7 @@ const CreateForm: React.FC<{
return ( return (
data?.map((item) => { data?.map((item) => {
return { return {
label: item.name, label: `${item.name} - ${item.nameCn}`,
value: item.sku, value: item.sku,
}; };
}) || [] }) || []
@ -365,7 +366,7 @@ const UpdateForm: React.FC<{
} }
autoFocusFirstInput autoFocusFirstInput
drawerProps={{ drawerProps={{
destroyOnClose: true, destroyOnHidden: true,
}} }}
onFinish={async (values) => { onFinish={async (values) => {
try { try {
@ -450,7 +451,7 @@ const UpdateForm: React.FC<{
<div key={idx}> <div key={idx}>
<ProFormSelect <ProFormSelect
request={async ({ keyWords }) => { request={async ({ keyWords }) => {
if (keyWords.length < 3) return []; if (keyWords.length < 2) return [];
try { try {
const { data } = await productcontrollerSearchproducts({ const { data } = await productcontrollerSearchproducts({
name: keyWords, name: keyWords,
@ -458,7 +459,7 @@ const UpdateForm: React.FC<{
return ( return (
data?.map((item) => { data?.map((item) => {
return { return {
label: item.name, label: `${item.name} - ${item.nameCn}`,
value: item.sku, value: item.sku,
}; };
}) || [] }) || []
@ -544,7 +545,7 @@ const DetailForm: React.FC<{
trigger={<Button type="primary"></Button>} trigger={<Button type="primary"></Button>}
autoFocusFirstInput autoFocusFirstInput
drawerProps={{ drawerProps={{
destroyOnClose: true, destroyOnHidden: true,
}} }}
readonly={true} readonly={true}
layout="vertical" layout="vertical"
@ -614,7 +615,7 @@ const DetailForm: React.FC<{
<ProForm.Group> <ProForm.Group>
<ProFormSelect <ProFormSelect
request={async ({ keyWords }) => { request={async ({ keyWords }) => {
if (keyWords.length < 3) return []; if (keyWords.length < 2) return [];
try { try {
const { data } = await productcontrollerSearchproducts({ const { data } = await productcontrollerSearchproducts({
name: keyWords, name: keyWords,
@ -622,7 +623,7 @@ const DetailForm: React.FC<{
return ( return (
data?.map((item) => { data?.map((item) => {
return { return {
label: item.name, label: `${item.name} - ${item.nameCn}`,
value: item.sku, value: item.sku,
}; };
}) || [] }) || []

View File

@ -3,6 +3,7 @@ import {
stockcontrollerCanceltransfer, stockcontrollerCanceltransfer,
stockcontrollerCreatetransfer, stockcontrollerCreatetransfer,
stockcontrollerGetallstockpoints, stockcontrollerGetallstockpoints,
stockcontrollerGetpurchaseorder,
stockcontrollerGettransfers, stockcontrollerGettransfers,
stockcontrollerLosttransfer, stockcontrollerLosttransfer,
stockcontrollerReceivetransfer, stockcontrollerReceivetransfer,
@ -60,7 +61,7 @@ const TransferPage: React.FC = () => {
title: '数量', title: '数量',
hideInSearch: true, hideInSearch: true,
render(_, record) { render(_, record) {
return record.items.reduce((cur, next) => { return record?.items?.reduce?.((cur, next) => {
return cur + next.quantity; return cur + next.quantity;
}, 0); }, 0);
}, },
@ -204,11 +205,10 @@ const CreateForm: React.FC<{
autoFocusFirstInput autoFocusFirstInput
layout="vertical" layout="vertical"
drawerProps={{ drawerProps={{
destroyOnClose: true, destroyOnHidden: true,
}} }}
onFinish={async (values) => { onFinish={async ({orderNumber,...values}) => {
try { try {
console.log(values);
const { success, message: errMsg } = const { success, message: errMsg } =
await stockcontrollerCreatetransfer(values); await stockcontrollerCreatetransfer(values);
if (!success) { if (!success) {
@ -272,9 +272,24 @@ const CreateForm: React.FC<{
rules={[{ required: true, message: '请选择源目标仓库' }]} rules={[{ required: true, message: '请选择源目标仓库' }]}
/> />
<ProFormTextArea name="note" label="备注" /> <ProFormTextArea name="note" label="备注" />
<ProFormText name={'orderNumber'} addonAfter={<Button onClick={async () => {
const orderNumber = await form.getFieldValue('orderNumber')
const { data } = await stockcontrollerGetpurchaseorder({orderNumber})
form.setFieldsValue({
items: data?.map(
(item: { productName: string; productSku: string }) => ({
...item,
productSku: {
label: item.productName,
value: item.productSku,
},
}),
),
})
}}></Button>} />
<ProFormDependency name={['items']}> <ProFormDependency name={['items']}>
{({ items }) => { {({ items }) => {
return '数量:' + items?.reduce((acc, cur) => acc + cur.quantity, 0); return '数量:' + (items?.reduce?.((acc, cur) => acc + cur.quantity, 0)||0);
}} }}
</ProFormDependency> </ProFormDependency>
<ProFormList <ProFormList
@ -297,7 +312,7 @@ const CreateForm: React.FC<{
<div key={idx}> <div key={idx}>
<ProFormSelect <ProFormSelect
request={async ({ keyWords }) => { request={async ({ keyWords }) => {
if (keyWords.length < 3) return []; if (keyWords.length < 2) return [];
try { try {
const { data } = await productcontrollerSearchproducts({ const { data } = await productcontrollerSearchproducts({
name: keyWords, name: keyWords,
@ -305,7 +320,7 @@ const CreateForm: React.FC<{
return ( return (
data?.map((item) => { data?.map((item) => {
return { return {
label: item.name, label: `${item.name} - ${item.nameCn}`,
value: item.sku, value: item.sku,
}; };
}) || [] }) || []
@ -382,7 +397,7 @@ const UpdateForm: React.FC<{
} }
autoFocusFirstInput autoFocusFirstInput
drawerProps={{ drawerProps={{
destroyOnClose: true, destroyOnHidden: true,
}} }}
onFinish={async (values) => { onFinish={async (values) => {
try { try {
@ -450,7 +465,7 @@ const UpdateForm: React.FC<{
<ProFormTextArea name="note" label="备注" /> <ProFormTextArea name="note" label="备注" />
<ProFormDependency name={['items']}> <ProFormDependency name={['items']}>
{({ items }) => { {({ items }) => {
return '数量:' + items?.reduce((acc, cur) => acc + cur.quantity, 0); return '数量:' + items?.reduce?.((acc, cur) => acc + cur.quantity, 0);
}} }}
</ProFormDependency> </ProFormDependency>
<ProFormList <ProFormList
@ -473,7 +488,7 @@ const UpdateForm: React.FC<{
<div key={idx}> <div key={idx}>
<ProFormSelect <ProFormSelect
request={async ({ keyWords }) => { request={async ({ keyWords }) => {
if (keyWords.length < 3) return []; if (keyWords.length < 2) return [];
try { try {
const { data } = await productcontrollerSearchproducts({ const { data } = await productcontrollerSearchproducts({
name: keyWords, name: keyWords,
@ -481,7 +496,7 @@ const UpdateForm: React.FC<{
return ( return (
data?.map((item) => { data?.map((item) => {
return { return {
label: item.name, label: `${item.name} - ${item.nameCn}`,
value: item.sku, value: item.sku,
}; };
}) || [] }) || []
@ -553,7 +568,7 @@ const DetailForm: React.FC<{
trigger={<Button type="primary"></Button>} trigger={<Button type="primary"></Button>}
autoFocusFirstInput autoFocusFirstInput
drawerProps={{ drawerProps={{
destroyOnClose: true, destroyOnHidden: true,
}} }}
readonly={true} readonly={true}
layout="vertical" layout="vertical"
@ -630,7 +645,7 @@ const DetailForm: React.FC<{
<ProForm.Group> <ProForm.Group>
<ProFormSelect <ProFormSelect
request={async ({ keyWords }) => { request={async ({ keyWords }) => {
if (keyWords.length < 3) return []; if (keyWords.length < 2) return [];
try { try {
const { data } = await productcontrollerSearchproducts({ const { data } = await productcontrollerSearchproducts({
name: keyWords, name: keyWords,
@ -638,7 +653,7 @@ const DetailForm: React.FC<{
return ( return (
data?.map((item) => { data?.map((item) => {
return { return {
label: item.name, label: `${item.name} - ${item.nameCn}`,
value: item.sku, value: item.sku,
}; };
}) || [] }) || []

View File

@ -114,7 +114,7 @@ const CreateForm: React.FC<{
} }
autoFocusFirstInput autoFocusFirstInput
drawerProps={{ drawerProps={{
destroyOnClose: true, destroyOnHidden: true,
}} }}
onFinish={async (values) => { onFinish={async (values) => {
try { try {
@ -182,7 +182,7 @@ const UpdateForm: React.FC<{
} }
autoFocusFirstInput autoFocusFirstInput
drawerProps={{ drawerProps={{
destroyOnClose: true, destroyOnHidden: true,
}} }}
onFinish={async (values) => { onFinish={async (values) => {
try { try {

View File

@ -4,7 +4,6 @@ import {
} from '@/servers/api/logistics'; } from '@/servers/api/logistics';
import { SearchOutlined } from '@ant-design/icons'; import { SearchOutlined } from '@ant-design/icons';
import { PageContainer, ProFormSelect } from '@ant-design/pro-components'; import { PageContainer, ProFormSelect } from '@ant-design/pro-components';
import { Col, Row } from 'antd';
import { useState } from 'react'; import { useState } from 'react';
const TrackPage: React.FC = () => { const TrackPage: React.FC = () => {
@ -19,21 +18,15 @@ const TrackPage: React.FC = () => {
if (!keyWords || keyWords.length < 3) return []; if (!keyWords || keyWords.length < 3) return [];
const { data: trackList } = const { data: trackList } =
await logisticscontrollerGettrackingnumber({ number: keyWords }); await logisticscontrollerGettrackingnumber({ number: keyWords });
return trackList?.map( return trackList?.map((v) => {
(v: { return {
tracking_provider: string; label: v.siteName + ' ' + v.externalOrderId,
primary_tracking_number: string; value: v.id,
id: string; };
}) => { });
return {
label: v.tracking_provider + ' ' + v.primary_tracking_number,
value: v.id,
};
},
);
}} }}
fieldProps={{ fieldProps={{
prefix: '追踪号', prefix: '订单号',
onChange(value: string) { onChange(value: string) {
setId(value); setId(value);
}, },
@ -53,28 +46,22 @@ const TrackPage: React.FC = () => {
), ),
}} }}
/> />
<Row> <div>
<Col span={24}></Col> {data.map((item) => (
<Col span={18}></Col> <div>
<Col span={6}></Col> <h4>
{data?.orderItem?.map((v: any) => ( {item.name} * {item.quantity}
<> </h4>
<Col span={18}>{v.name}</Col> <div style={{ paddingLeft: 20, color: 'blue' }}>
<Col span={6}>{v.quantity}</Col> {item.constitution.map((v) => (
</> <div>
{v.name} * {v.quantity * item.quantity}
</div>
))}
</div>
</div>
))} ))}
</Row> </div>
<Row style={{ marginTop: '30px' }}>
<Col span={18}></Col>
<Col span={6}></Col>
{data?.shipmentItem?.map((v: any) => (
<>
<Col span={18}>{v.name}</Col>
<Col span={6}>{v.quantity}</Col>
</>
))}
</Row>
</PageContainer> </PageContainer>
); );
}; };

View File

@ -0,0 +1,58 @@
// @ts-ignore
/* eslint-disable */
import { request } from 'umi';
/** 此处后端没有提供注释 GET /customer/list */
export async function customercontrollerGetcustomerlist(
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
params: API.customercontrollerGetcustomerlistParams,
options?: { [key: string]: any },
) {
return request<any>('/customer/list', {
method: 'GET',
params: {
...params,
},
...(options || {}),
});
}
/** 此处后端没有提供注释 POST /customer/tag/add */
export async function customercontrollerAddtag(
body: API.CustomerTagDTO,
options?: { [key: string]: any },
) {
return request<API.BooleanRes>('/customer/tag/add', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
data: body,
...(options || {}),
});
}
/** 此处后端没有提供注释 DELETE /customer/tag/del */
export async function customercontrollerDeltag(
body: API.CustomerTagDTO,
options?: { [key: string]: any },
) {
return request<API.BooleanRes>('/customer/tag/del', {
method: 'DELETE',
headers: {
'Content-Type': 'application/json',
},
data: body,
...(options || {}),
});
}
/** 此处后端没有提供注释 GET /customer/tags */
export async function customercontrollerGettags(options?: {
[key: string]: any;
}) {
return request<any>('/customer/tags', {
method: 'GET',
...(options || {}),
});
}

View File

@ -2,6 +2,7 @@
/* eslint-disable */ /* eslint-disable */
// API 更新时间: // API 更新时间:
// API 唯一标识: // API 唯一标识:
import * as customer from './customer';
import * as logistics from './logistics'; import * as logistics from './logistics';
import * as order from './order'; import * as order from './order';
import * as product from './product'; import * as product from './product';
@ -12,6 +13,7 @@ import * as user from './user';
import * as webhook from './webhook'; import * as webhook from './webhook';
import * as wpProduct from './wpProduct'; import * as wpProduct from './wpProduct';
export default { export default {
customer,
logistics, logistics,
order, order,
product, product,

View File

@ -133,6 +133,21 @@ export async function ordercontrollerCreateorder(
}); });
} }
/** 此处后端没有提供注释 POST /order/order/pengding/items */
export async function ordercontrollerPengdingitems(
body: Record<string, any>,
options?: { [key: string]: any },
) {
return request<any>('/order/order/pengding/items', {
method: 'POST',
headers: {
'Content-Type': 'text/plain',
},
data: body,
...(options || {}),
});
}
/** 此处后端没有提供注释 POST /order/order/refund/${param0} */ /** 此处后端没有提供注释 POST /order/order/refund/${param0} */
export async function ordercontrollerRefundorder( export async function ordercontrollerRefundorder(
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象) // 叠加生成的Param类型 (非body参数swagger默认没有生成对象)

View File

@ -327,3 +327,17 @@ export async function productcontrollerGetstrengthall(options?: {
...(options || {}), ...(options || {}),
}); });
} }
/** 此处后端没有提供注释 PUT /productupdateNameCn/${param1}/${param0} */
export async function productcontrollerUpdateproductnamecn(
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
params: API.productcontrollerUpdateproductnamecnParams,
options?: { [key: string]: any },
) {
const { nameCn: param0, id: param1, ...queryParams } = params;
return request<API.ProductRes>(`/productupdateNameCn/${param1}/${param0}`, {
method: 'PUT',
params: { ...queryParams },
...(options || {}),
});
}

View File

@ -17,6 +17,21 @@ export async function statisticscontrollerGetcustomerorders(
}); });
} }
/** 此处后端没有提供注释 GET /statistics/inactiveUsersByMonth */
export async function statisticscontrollerGetinativeusersbymonth(
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
params: API.statisticscontrollerGetinativeusersbymonthParams,
options?: { [key: string]: any },
) {
return request<any>('/statistics/inactiveUsersByMonth', {
method: 'GET',
params: {
...params,
},
...(options || {}),
});
}
/** 此处后端没有提供注释 POST /statistics/order */ /** 此处后端没有提供注释 POST /statistics/order */
export async function statisticscontrollerGetorderstatistics( export async function statisticscontrollerGetorderstatistics(
body: API.OrderStatisticsParams, body: API.OrderStatisticsParams,
@ -62,6 +77,16 @@ export async function statisticscontrollerGetorderbyemail(
}); });
} }
/** 此处后端没有提供注释 GET /statistics/orderSource */
export async function statisticscontrollerGetordersorce(options?: {
[key: string]: any;
}) {
return request<any>('/statistics/orderSource', {
method: 'GET',
...(options || {}),
});
}
/** 此处后端没有提供注释 POST /statistics/restocking */ /** 此处后端没有提供注释 POST /statistics/restocking */
export async function statisticscontrollerRestocking( export async function statisticscontrollerRestocking(
body: Record<string, any>, body: Record<string, any>,

View File

@ -122,6 +122,20 @@ export async function stockcontrollerDelpurchaseorder(
}); });
} }
/** 此处后端没有提供注释 GET /stock/purchase-order/${param0} */
export async function stockcontrollerGetpurchaseorder(
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
params: API.stockcontrollerGetpurchaseorderParams,
options?: { [key: string]: any },
) {
const { orderNumber: param0, ...queryParams } = params;
return request<API.BooleanRes>(`/stock/purchase-order/${param0}`, {
method: 'GET',
params: { ...queryParams },
...(options || {}),
});
}
/** 此处后端没有提供注释 PUT /stock/receiveTransfer/${param0} */ /** 此处后端没有提供注释 PUT /stock/receiveTransfer/${param0} */
export async function stockcontrollerUpdatetransfer( export async function stockcontrollerUpdatetransfer(
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象) // 叠加生成的Param类型 (非body参数swagger默认没有生成对象)

View File

@ -67,10 +67,11 @@ declare namespace API {
name: string; name: string;
/** 产品描述 */ /** 产品描述 */
description?: string; description?: string;
/** sku */
sku?: string;
/** 分类 ID */ /** 分类 ID */
categoryId?: number; categoryId?: number;
strengthId?: number;
flavorsId?: number;
humidity?: string;
}; };
type CreatePurchaseOrderDTO = { type CreatePurchaseOrderDTO = {
@ -100,6 +101,22 @@ declare namespace API {
unit?: string; unit?: string;
}; };
type customercontrollerGetcustomerlistParams = {
current?: string;
pageSize?: string;
email?: string;
tags?: string;
sorterKey?: string;
sorterValue?: string;
state?: string;
first_purchase_date?: string;
};
type CustomerTagDTO = {
email?: string;
tag?: string;
};
type Date = { type Date = {
year?: string; year?: string;
month?: string; month?: string;
@ -552,12 +569,14 @@ declare namespace API {
id: number; id: number;
/** 产品名称 */ /** 产品名称 */
name: string; name: string;
nameCn?: string;
/** 产品描述 */ /** 产品描述 */
description?: string; description?: string;
/** 分类 ID */ /** 分类 ID */
categoryId?: number; categoryId?: number;
flavorsId?: number; flavorsId?: number;
strengthId?: number; strengthId?: number;
humidity?: string;
/** sku */ /** sku */
sku?: string; sku?: string;
/** 创建时间 */ /** 创建时间 */
@ -658,6 +677,11 @@ declare namespace API {
id: number; id: number;
}; };
type productcontrollerUpdateproductnamecnParams = {
nameCn: string;
id: number;
};
type productcontrollerUpdateproductParams = { type productcontrollerUpdateproductParams = {
id: number; id: number;
}; };
@ -765,6 +789,17 @@ declare namespace API {
name?: string; name?: string;
}; };
type QueryCustomerListDTO = {
current?: string;
pageSize?: string;
email?: string;
tags?: string;
sorterKey?: string;
sorterValue?: string;
state?: string;
first_purchase_date?: string;
};
type QueryFlavorsDTO = { type QueryFlavorsDTO = {
/** 页码 */ /** 页码 */
current?: number; current?: number;
@ -1027,6 +1062,10 @@ declare namespace API {
sku?: string; sku?: string;
}; };
type statisticscontrollerGetinativeusersbymonthParams = {
month?: string;
};
type stockcontrollerCanceltransferParams = { type stockcontrollerCanceltransferParams = {
id: number; id: number;
}; };
@ -1039,6 +1078,10 @@ declare namespace API {
id: number; id: number;
}; };
type stockcontrollerGetpurchaseorderParams = {
orderNumber: string;
};
type stockcontrollerGetpurchaseordersParams = { type stockcontrollerGetpurchaseordersParams = {
/** 页码 */ /** 页码 */
current?: number; current?: number;
@ -1261,10 +1304,11 @@ declare namespace API {
name?: string; name?: string;
/** 产品描述 */ /** 产品描述 */
description?: string; description?: string;
/** sku */
sku?: string;
/** 分类 ID */ /** 分类 ID */
categoryId?: number; categoryId?: number;
strengthId?: number;
flavorsId?: number;
humidity?: string;
}; };
type UpdatePurchaseOrderDTO = { type UpdatePurchaseOrderDTO = {