forked from yoone/WEB
1003 lines
29 KiB
TypeScript
1003 lines
29 KiB
TypeScript
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 {
|
|
statisticscontrollerGetorderbydate,
|
|
statisticscontrollerGetorderbyemail,
|
|
statisticscontrollerGetorderstatistics,
|
|
} from '@/servers/api/statistics';
|
|
import { formatSource } from '@/utils/format';
|
|
import {
|
|
ActionType,
|
|
ModalForm,
|
|
PageContainer,
|
|
ProForm,
|
|
ProFormDateRangePicker,
|
|
ProFormSelect,
|
|
ProTable,
|
|
} from '@ant-design/pro-components';
|
|
import { Button, Space, Tag } from 'antd';
|
|
import dayjs from 'dayjs';
|
|
import ReactECharts from 'echarts-for-react';
|
|
import { useEffect, useMemo, useRef, useState } from 'react';
|
|
|
|
const highlightText = (text: string, keyword: string) => {
|
|
if (!keyword) return text;
|
|
const parts = text.split(new RegExp(`(${keyword})`, 'gi'));
|
|
return parts.map((part, index) =>
|
|
part.toLowerCase() === keyword.toLowerCase() ? (
|
|
<span key={index} style={{ color: 'red', fontWeight: 'bold' }}>
|
|
{part}
|
|
</span>
|
|
) : (
|
|
part
|
|
),
|
|
);
|
|
};
|
|
|
|
const ListPage: React.FC = () => {
|
|
const [xAxis, setXAxis] = useState([]);
|
|
const [series, setSeries] = useState<any[]>([]);
|
|
const [selectedDate, setSelectedDate] = useState(null);
|
|
|
|
const option = useMemo(
|
|
() => ({
|
|
tooltip: {
|
|
trigger: 'axis',
|
|
formatter: function (params) {
|
|
const xValue = params[0].axisValue;
|
|
const items = params.map((item) => {
|
|
return `<span style="display: inline-block;width: 250px">${item.marker} ${item.seriesName}: ${item.value}</span>`;
|
|
});
|
|
|
|
// 每4个一行
|
|
const rows = [];
|
|
for (let i = 0; i < items.length; i += 4) {
|
|
rows.push(items.slice(i, i + 4).join(''));
|
|
}
|
|
|
|
return (
|
|
`<div>${xValue} ${
|
|
['周日', '周一', '周二', '周三', '周四', '周五', '周六'][
|
|
dayjs(xValue).day()
|
|
]
|
|
}</div>` + rows.join('<br/>')
|
|
);
|
|
},
|
|
},
|
|
legend: {
|
|
data: ['订单数', '总金额', '平均金额', '盒数'],
|
|
},
|
|
grid: {
|
|
left: '3%',
|
|
right: '4%',
|
|
bottom: '3%',
|
|
containLabel: true,
|
|
},
|
|
xAxis: {
|
|
type: 'category',
|
|
boundaryGap: false,
|
|
data: xAxis,
|
|
},
|
|
yAxis: [
|
|
{
|
|
type: 'value',
|
|
name: '订单数',
|
|
position: 'left',
|
|
},
|
|
{
|
|
type: 'value',
|
|
name: '总金额',
|
|
position: 'right',
|
|
offset: 60,
|
|
},
|
|
{
|
|
type: 'value',
|
|
name: '平均金额',
|
|
position: 'right',
|
|
},
|
|
{
|
|
type: 'value',
|
|
name: '盒数',
|
|
position: 'left',
|
|
offset: 60,
|
|
},
|
|
],
|
|
series,
|
|
}),
|
|
[xAxis, series],
|
|
);
|
|
|
|
return (
|
|
<PageContainer ghost>
|
|
<ProForm
|
|
layout="inline"
|
|
onFinish={async (values) => {
|
|
setXAxis([]);
|
|
setSeries([]);
|
|
setSelectedDate(null);
|
|
// setKeyword(values?.keyword || '');
|
|
const { date, ...params } = values;
|
|
const [startDate, endDate] = date;
|
|
const { data, success } =
|
|
await statisticscontrollerGetorderstatistics({
|
|
startDate,
|
|
endDate,
|
|
...params,
|
|
});
|
|
if (success) {
|
|
const res = data?.sort(() => -1);
|
|
setXAxis(res?.map((v) => dayjs(v.order_date).format('YYYY-MM-DD')));
|
|
setSeries([
|
|
{
|
|
name: 'TOGO CPC订单数',
|
|
type: 'line',
|
|
data: res?.map((v) => v.togo_cpc_orders),
|
|
},
|
|
{
|
|
name: 'TOGO 非CPC订单数',
|
|
type: 'line',
|
|
data: res?.map((v) => v.non_togo_cpc_orders),
|
|
},
|
|
{
|
|
name: 'CAN CPC订单数',
|
|
type: 'line',
|
|
data: res?.map((v) => v.can_cpc_orders),
|
|
},
|
|
{
|
|
name: 'CAN 非CPC订单数',
|
|
type: 'line',
|
|
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订单数',
|
|
type: 'line',
|
|
data: res?.map((v) => v.cpc_orders),
|
|
},
|
|
{
|
|
name: 'ZYN CPC订单数',
|
|
type: 'line',
|
|
data: res?.map((v) => v.zyn_orders),
|
|
},
|
|
{
|
|
name: 'YOONE CPC订单数',
|
|
type: 'line',
|
|
data: res?.map((v) => v.yoone_orders),
|
|
},
|
|
{
|
|
name: 'ZEX CPC订单数',
|
|
type: 'line',
|
|
data: res?.map((v) => v.zex_orders),
|
|
},
|
|
{
|
|
name: 'CPC金额',
|
|
type: 'line',
|
|
yAxisIndex: 1,
|
|
data: res?.map((v) => v.cpc_total),
|
|
},
|
|
{
|
|
name: 'ZYN CPC金额',
|
|
type: 'line',
|
|
yAxisIndex: 1,
|
|
data: res?.map((v) => v.zyn_total),
|
|
},
|
|
{
|
|
name: 'YOONE CPC金额',
|
|
type: 'line',
|
|
yAxisIndex: 1,
|
|
data: res?.map((v) => v.yoone_total),
|
|
},
|
|
{
|
|
name: 'ZEX CPC金额',
|
|
type: 'line',
|
|
yAxisIndex: 1,
|
|
data: res?.map((v) => v.zex_total),
|
|
},
|
|
{
|
|
name: '非CPC订单数',
|
|
type: 'line',
|
|
data: res?.map((v) => v.non_cpc_orders),
|
|
},
|
|
{
|
|
name: 'ZYN 非CPC订单数',
|
|
type: 'line',
|
|
data: res?.map((v) => v.non_zyn_orders),
|
|
},
|
|
{
|
|
name: 'YOONE 非CPC订单数',
|
|
type: 'line',
|
|
data: res?.map((v) => v.non_yoone_orders),
|
|
},
|
|
{
|
|
name: 'ZEX 非CPC订单数',
|
|
type: 'line',
|
|
data: res?.map((v) => v.non_zex_orders),
|
|
},
|
|
{
|
|
name: '非CPC金额',
|
|
type: 'line',
|
|
yAxisIndex: 1,
|
|
data: res?.map((v) => v.non_cpc_total),
|
|
},
|
|
{
|
|
name: 'ZYN 非CPC金额',
|
|
type: 'line',
|
|
yAxisIndex: 1,
|
|
data: res?.map((v) => v.non_zyn_total),
|
|
},
|
|
{
|
|
name: 'YOONE 非CPC金额',
|
|
type: 'line',
|
|
yAxisIndex: 1,
|
|
data: res?.map((v) => v.non_yoone_total),
|
|
},
|
|
{
|
|
name: 'ZEX 非CPC金额',
|
|
type: 'line',
|
|
yAxisIndex: 1,
|
|
data: res?.map((v) => v.non_zex_total),
|
|
},
|
|
{
|
|
name: 'ZYN 盒数金额',
|
|
type: 'line',
|
|
yAxisIndex: 1,
|
|
data: res?.map((v) => v.zyn_amount),
|
|
},
|
|
{
|
|
name: 'ZYN 盒数',
|
|
type: 'line',
|
|
yAxisIndex: 3,
|
|
data: res?.map((v) => v.zyn_quantity),
|
|
},
|
|
{
|
|
name: 'ZYN CPC盒数',
|
|
type: 'line',
|
|
yAxisIndex: 3,
|
|
data: res?.map((v) => v.cpc_zyn_quantity),
|
|
},
|
|
{
|
|
name: 'ZYN 非CPC盒数',
|
|
type: 'line',
|
|
yAxisIndex: 3,
|
|
data: res?.map((v) => v.non_cpc_zyn_quantity),
|
|
},
|
|
{
|
|
name: 'YOONE 盒数金额',
|
|
type: 'line',
|
|
yAxisIndex: 1,
|
|
data: res?.map((v) => v.yoone_amount),
|
|
},
|
|
{
|
|
name: 'YOONE 盒数',
|
|
type: 'line',
|
|
yAxisIndex: 3,
|
|
data: res?.map((v) => v.yoone_quantity),
|
|
},
|
|
{
|
|
name: 'YOONE CPC盒数',
|
|
type: 'line',
|
|
yAxisIndex: 3,
|
|
data: res?.map((v) => v.cpc_yoone_quantity),
|
|
},
|
|
{
|
|
name: 'YOONE 非CPC盒数',
|
|
type: 'line',
|
|
yAxisIndex: 3,
|
|
data: res?.map((v) => v.non_cpc_yoone_quantity),
|
|
},
|
|
{
|
|
name: 'YOONE套装金额',
|
|
type: 'line',
|
|
yAxisIndex: 1,
|
|
data: res?.map((v) => v.yoone_G_amount),
|
|
},
|
|
{
|
|
name: 'YOONE套装盒数',
|
|
type: 'line',
|
|
yAxisIndex: 3,
|
|
data: res?.map((v) => v.yoone_G_quantity),
|
|
},
|
|
{
|
|
name: 'YOONE套装CPC盒数',
|
|
type: 'line',
|
|
yAxisIndex: 3,
|
|
data: res?.map((v) => v.cpc_yoone_G_quantity),
|
|
},
|
|
{
|
|
name: 'YOONE套装非CPC盒数',
|
|
type: 'line',
|
|
yAxisIndex: 3,
|
|
data: res?.map((v) => v.non_cpc_yoone_G_quantity),
|
|
},
|
|
{
|
|
name: 'YOONE单盒金额',
|
|
type: 'line',
|
|
yAxisIndex: 1,
|
|
data: res?.map((v) => v.yoone_S_amount),
|
|
},
|
|
{
|
|
name: 'YOONE单盒盒数',
|
|
type: 'line',
|
|
yAxisIndex: 3,
|
|
data: res?.map((v) => v.yoone_S_quantity),
|
|
},
|
|
{
|
|
name: 'YOONE单盒CPC盒数',
|
|
type: 'line',
|
|
yAxisIndex: 3,
|
|
data: res?.map((v) => v.cpc_yoone_S_quantity),
|
|
},
|
|
{
|
|
name: 'YOONE单盒非CPC盒数',
|
|
type: 'line',
|
|
yAxisIndex: 3,
|
|
data: res?.map((v) => v.non_cpc_yoone_S_quantity),
|
|
},
|
|
{
|
|
name: 'YOONE 3MG 盒数金额',
|
|
type: 'line',
|
|
yAxisIndex: 1,
|
|
data: res?.map((v) => v.yoone_3_amount),
|
|
},
|
|
{
|
|
name: 'YOONE 3MG 盒数',
|
|
type: 'line',
|
|
yAxisIndex: 3,
|
|
data: res?.map((v) => v.yoone_3_quantity),
|
|
},
|
|
{
|
|
name: 'YOONE 3MG CPC盒数',
|
|
type: 'line',
|
|
yAxisIndex: 3,
|
|
data: res?.map((v) => v.cpc_yoone_3_quantity),
|
|
},
|
|
{
|
|
name: 'YOONE 3MG 非CPC盒数',
|
|
type: 'line',
|
|
yAxisIndex: 3,
|
|
data: res?.map((v) => v.non_cpc_yoone_3_quantity),
|
|
},
|
|
{
|
|
name: 'YOONE 6MG 盒数金额',
|
|
type: 'line',
|
|
yAxisIndex: 1,
|
|
data: res?.map((v) => v.yoone_6_amount),
|
|
},
|
|
{
|
|
name: 'YOONE 6MG 盒数',
|
|
type: 'line',
|
|
yAxisIndex: 3,
|
|
data: res?.map((v) => v.yoone_6_quantity),
|
|
},
|
|
{
|
|
name: 'YOONE 6MG CPC盒数',
|
|
type: 'line',
|
|
yAxisIndex: 3,
|
|
data: res?.map((v) => v.cpc_yoone_6_quantity),
|
|
},
|
|
{
|
|
name: 'YOONE 6MG 非CPC盒数',
|
|
type: 'line',
|
|
yAxisIndex: 3,
|
|
data: res?.map((v) => v.non_cpc_yoone_6_quantity),
|
|
},
|
|
{
|
|
name: 'YOONE 9MG 盒数金额',
|
|
type: 'line',
|
|
yAxisIndex: 1,
|
|
data: res?.map((v) => v.yoone_9_amount),
|
|
},
|
|
{
|
|
name: 'YOONE 9MG 盒数',
|
|
type: 'line',
|
|
yAxisIndex: 3,
|
|
data: res?.map((v) => v.yoone_9_quantity),
|
|
},
|
|
{
|
|
name: 'YOONE 9MG CPC盒数',
|
|
type: 'line',
|
|
yAxisIndex: 3,
|
|
data: res?.map((v) => v.cpc_yoone_9_quantity),
|
|
},
|
|
{
|
|
name: 'YOONE 9MG 非CPC盒数',
|
|
type: 'line',
|
|
yAxisIndex: 3,
|
|
data: res?.map((v) => v.non_cpc_yoone_9_quantity),
|
|
},
|
|
{
|
|
name: 'YOONE 12MG 盒数金额',
|
|
type: 'line',
|
|
yAxisIndex: 1,
|
|
data: res?.map((v) => v.yoone_12_amount),
|
|
},
|
|
{
|
|
name: 'YOONE 12MG 盒数',
|
|
type: 'line',
|
|
yAxisIndex: 3,
|
|
data: res?.map((v) => v.yoone_12_quantity),
|
|
},
|
|
{
|
|
name: 'YOONE 12MG CPC盒数',
|
|
type: 'line',
|
|
yAxisIndex: 3,
|
|
data: res?.map((v) => v.cpc_yoone_12_quantity),
|
|
},
|
|
{
|
|
name: 'YOONE 12MG 非CPC盒数',
|
|
type: 'line',
|
|
yAxisIndex: 3,
|
|
data: res?.map((v) => v.non_cpc_yoone_12_quantity),
|
|
},
|
|
{
|
|
name: 'YOONE 15MG 盒数金额',
|
|
type: 'line',
|
|
yAxisIndex: 1,
|
|
data: res?.map((v) => v.yoone_15_amount),
|
|
},
|
|
{
|
|
name: 'YOONE 15MG 盒数',
|
|
type: 'line',
|
|
yAxisIndex: 3,
|
|
data: res?.map((v) => v.yoone_15_quantity),
|
|
},
|
|
{
|
|
name: 'YOONE 15MG CPC盒数',
|
|
type: 'line',
|
|
yAxisIndex: 3,
|
|
data: res?.map((v) => v.cpc_yoone_15_quantity),
|
|
},
|
|
{
|
|
name: 'YOONE 15MG 非CPC盒数',
|
|
type: 'line',
|
|
yAxisIndex: 3,
|
|
data: res?.map((v) => v.non_cpc_yoone_15_quantity),
|
|
},
|
|
{
|
|
name: 'ZEX 盒数金额',
|
|
type: 'line',
|
|
yAxisIndex: 1,
|
|
data: res?.map((v) => v.zex_amount),
|
|
},
|
|
{
|
|
name: 'ZEX 盒数',
|
|
type: 'line',
|
|
yAxisIndex: 3,
|
|
data: res?.map((v) => v.zex_quantity),
|
|
},
|
|
{
|
|
name: 'ZEX CPC盒数',
|
|
type: 'line',
|
|
yAxisIndex: 3,
|
|
data: res?.map((v) => v.cpc_zex_quantity),
|
|
},
|
|
{
|
|
name: 'ZEX 非CPC盒数',
|
|
type: 'line',
|
|
yAxisIndex: 3,
|
|
data: res?.map((v) => v.non_cpc_zex_quantity),
|
|
},
|
|
{
|
|
name: '订单数',
|
|
type: 'line',
|
|
data: res?.map((v) => v.total_orders),
|
|
},
|
|
{
|
|
name: 'TOGO订单数',
|
|
type: 'line',
|
|
data: res?.map((v) => v.togo_total_orders),
|
|
},
|
|
{
|
|
name: 'CAN订单数',
|
|
type: 'line',
|
|
data: res?.map((v) => v.can_total_orders),
|
|
},
|
|
{
|
|
name: '总金额',
|
|
type: 'line',
|
|
yAxisIndex: 1,
|
|
data: res?.map((v) => v.total_amount),
|
|
},
|
|
{
|
|
name: 'TOGO总金额',
|
|
type: 'line',
|
|
yAxisIndex: 1,
|
|
data: res?.map((v) => v.togo_total_amount),
|
|
},
|
|
{
|
|
name: 'CAN总金额',
|
|
type: 'line',
|
|
yAxisIndex: 1,
|
|
data: res?.map((v) => v.can_total_amount),
|
|
},
|
|
{
|
|
name: '平均金额',
|
|
type: 'line',
|
|
yAxisIndex: 2,
|
|
data: res?.map((v) => v.avg_total_amount),
|
|
},
|
|
{
|
|
name: 'TOGO平均金额',
|
|
type: 'line',
|
|
yAxisIndex: 2,
|
|
data: res?.map((v) => v.avg_togo_total_amount),
|
|
},
|
|
{
|
|
name: 'CAN平均金额',
|
|
type: 'line',
|
|
yAxisIndex: 2,
|
|
data: res?.map((v) => v.avg_can_total_amount),
|
|
},
|
|
]);
|
|
}
|
|
}}
|
|
>
|
|
<ProFormDateRangePicker
|
|
label="日期"
|
|
rules={[{ required: true, message: '请选择日期' }]}
|
|
name="date"
|
|
/>
|
|
{/* <ProFormText label="关键词" name="keyword" /> */}
|
|
<ProFormSelect
|
|
label="站点"
|
|
name="siteId"
|
|
request={async () => {
|
|
const { data = [] } = await sitecontrollerAll();
|
|
return data.map((item) => ({
|
|
label: item.name,
|
|
value: item.id,
|
|
}));
|
|
}}
|
|
/>
|
|
{/* <ProFormSelect
|
|
label="类型"
|
|
name="purchaseType"
|
|
valueEnum={{
|
|
first_purchase: '首购',
|
|
repeat_purchase: '复购',
|
|
}}
|
|
/>
|
|
<ProFormSelect
|
|
label="来源"
|
|
name="orderType"
|
|
valueEnum={{
|
|
cpc: '广告',
|
|
non_cpc: '非广告',
|
|
}}
|
|
/>
|
|
<ProFormSelect
|
|
label="品牌"
|
|
name="brand"
|
|
valueEnum={{
|
|
zyn: 'ZYN',
|
|
zex: 'ZEX',
|
|
yoone: 'YOONE',
|
|
}}
|
|
/> */}
|
|
</ProForm>
|
|
{series?.length ? (
|
|
<ReactECharts
|
|
style={{ height: 450 }}
|
|
option={option}
|
|
onEvents={{
|
|
click: (params) => {
|
|
if (params.componentType === 'series') {
|
|
setSelectedDate(params.name);
|
|
}
|
|
},
|
|
}}
|
|
/>
|
|
) : (
|
|
<></>
|
|
)}
|
|
<DailyOrders selectedDate={selectedDate} />
|
|
</PageContainer>
|
|
);
|
|
};
|
|
|
|
const DailyOrders: React.FC<{
|
|
selectedDate;
|
|
}> = ({ selectedDate }) => {
|
|
const [orders, setOrders] = useState([]);
|
|
const actionRef = useRef<ActionType>();
|
|
useEffect(() => {
|
|
if (!selectedDate) {
|
|
setOrders([]);
|
|
return;
|
|
}
|
|
statisticscontrollerGetorderbydate({
|
|
date: selectedDate,
|
|
}).then(({ data, success }) => {
|
|
if (success) {
|
|
setOrders(data);
|
|
}
|
|
});
|
|
}, [selectedDate]);
|
|
|
|
const handleTableChange = (pagination, filters, sorter) => {
|
|
// 获取排序字段和排序方式
|
|
const { field, order } = sorter || {};
|
|
|
|
if (field && order) {
|
|
const sortedData = [...orders].sort((a, b) => {
|
|
if (['total', 'order_count', 'total_spent'].includes(field)) {
|
|
const valA = Number(a[field]);
|
|
const valB = Number(b[field]);
|
|
if (isNaN(valA)) return 1;
|
|
if (isNaN(valB)) return -1;
|
|
if (order === 'ascend') {
|
|
return valA - valB;
|
|
}
|
|
return valB - valA;
|
|
}
|
|
if (order === 'ascend') {
|
|
return a[field] > b[field] ? 1 : -1;
|
|
}
|
|
return a[field] < b[field] ? 1 : -1;
|
|
});
|
|
|
|
setOrders(sortedData);
|
|
}
|
|
};
|
|
|
|
if (!selectedDate) return <></>;
|
|
return (
|
|
<ProTable
|
|
search={false}
|
|
columns={[
|
|
{
|
|
title: '订单号',
|
|
dataIndex: 'externalOrderId',
|
|
},
|
|
{
|
|
title: '客户邮箱',
|
|
dataIndex: 'customer_email',
|
|
},
|
|
{
|
|
title: '站点',
|
|
dataIndex: 'siteId',
|
|
valueType: 'select',
|
|
request: async () => {
|
|
const { data = [] } = await sitecontrollerAll();
|
|
return data.map((item) => ({
|
|
label: item.name,
|
|
value: item.id,
|
|
}));
|
|
},
|
|
},
|
|
{
|
|
title: '首单时间',
|
|
dataIndex: 'first_purchase_date',
|
|
valueType: 'dateTime',
|
|
sorter: true,
|
|
},
|
|
{
|
|
title: '尾单时间',
|
|
dataIndex: 'last_purchase_date',
|
|
valueType: 'dateTime',
|
|
sorter: true,
|
|
},
|
|
{
|
|
title: '支付时间',
|
|
dataIndex: 'date_paid',
|
|
valueType: 'dateTime',
|
|
sorter: true,
|
|
},
|
|
{
|
|
title: '订单金额',
|
|
dataIndex: 'total',
|
|
sorter: true,
|
|
},
|
|
{
|
|
title: '总订单数',
|
|
dataIndex: 'order_count',
|
|
sorter: true,
|
|
},
|
|
{
|
|
title: '总订单金额',
|
|
dataIndex: 'total_spent',
|
|
sorter: true,
|
|
},
|
|
{
|
|
title: '订单类型',
|
|
dataIndex: 'purchase_type',
|
|
sorter: true,
|
|
render: (_, record) => {
|
|
if (record.purchase_type === 'first_purchase') return '首单';
|
|
return '复购单';
|
|
},
|
|
filters: [
|
|
{ text: '首单', value: 'first_purchase' },
|
|
{ text: '复购单', value: 'repeat_purchase' },
|
|
],
|
|
onFilter: (value, record) => {
|
|
return record.purchase_type === value;
|
|
},
|
|
},
|
|
{
|
|
title: '状态',
|
|
dataIndex: 'orderStatus',
|
|
hideInSearch: true,
|
|
valueType: 'select',
|
|
valueEnum: ORDER_STATUS_ENUM,
|
|
sorter: true,
|
|
},
|
|
{
|
|
title: '来源',
|
|
hideInSearch: true,
|
|
sorter: true,
|
|
render: (_, record) =>
|
|
formatSource(record.source_type, record.utm_source),
|
|
filters: [
|
|
{ text: 'google广告', value: 'source' },
|
|
{ text: 'google搜索', value: 'organic' },
|
|
{ text: '直达', value: 'direct' },
|
|
{ text: '其他', value: 'other' },
|
|
],
|
|
onFilter: (value, record) => {
|
|
if (value === 'source') {
|
|
return (
|
|
record.source_type === 'utm' && record.utm_source === 'google'
|
|
);
|
|
}
|
|
if (value === 'organic') {
|
|
return (
|
|
record.source_type === 'organic' &&
|
|
record.utm_source === 'google'
|
|
);
|
|
}
|
|
if (value === 'direct') {
|
|
return record.source_type === 'typein';
|
|
}
|
|
if (value === '其他') {
|
|
return !['utm', 'organic', 'typein'].includes(record.source_type);
|
|
}
|
|
},
|
|
},
|
|
{
|
|
title: '订单内容',
|
|
dataIndex: 'orderItems',
|
|
render: (_, record) => {
|
|
return (
|
|
<div>
|
|
{record.orderItems?.map((item) => (
|
|
// <div>{highlightText(item.name, keyword)}</div>
|
|
<div>{item.name}</div>
|
|
))}
|
|
</div>
|
|
);
|
|
},
|
|
filters: [
|
|
{ text: 'ZYN', value: 'zyn' },
|
|
{ text: 'YOONE', value: 'yoone' },
|
|
{ text: 'ZEX', value: 'zex' },
|
|
],
|
|
onFilter: (value, record) => {
|
|
return record.orderItems?.some((v) =>
|
|
v?.name?.toLowerCase().includes(value),
|
|
);
|
|
},
|
|
},
|
|
{
|
|
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: 'action',
|
|
valueType: 'option',
|
|
render: (_, record) => {
|
|
return (
|
|
<Space>
|
|
<AddTag
|
|
email={record.customer_email}
|
|
tags={record.tags}
|
|
tableRef={actionRef}
|
|
/>
|
|
<HistoryOrder
|
|
email={record.customer_email}
|
|
tags={record.tags}
|
|
tableRef={actionRef}
|
|
/>
|
|
</Space>
|
|
);
|
|
},
|
|
},
|
|
]}
|
|
dataSource={orders}
|
|
onChange={handleTableChange}
|
|
/>
|
|
);
|
|
};
|
|
|
|
export const HistoryOrder: React.FC<{
|
|
email: string;
|
|
tags?: string[];
|
|
tableRef: React.MutableRefObject<ActionType | undefined>;
|
|
}> = ({ email, tags, tableRef }) => {
|
|
const actionRef = useRef<ActionType>();
|
|
return (
|
|
<ModalForm
|
|
title={`历史订单${email}`}
|
|
trigger={<Button type="primary">历史订单</Button>}
|
|
modalProps={{ destroyOnHidden: true, footer: null }}
|
|
width="80vw"
|
|
submitter={false}
|
|
>
|
|
<ProTable
|
|
search={false}
|
|
columns={[
|
|
{
|
|
title: '订单号',
|
|
dataIndex: 'externalOrderId',
|
|
},
|
|
{
|
|
title: '客户邮箱',
|
|
dataIndex: 'customer_email',
|
|
},
|
|
{
|
|
title: '站点',
|
|
dataIndex: 'siteId',
|
|
valueType: 'select',
|
|
request: async () => {
|
|
const { data = [] } = await sitecontrollerAll();
|
|
return data.map((item) => ({
|
|
label: item.name,
|
|
value: item.id,
|
|
}));
|
|
},
|
|
},
|
|
{
|
|
title: '支付时间',
|
|
dataIndex: 'date_paid',
|
|
valueType: 'dateTime',
|
|
},
|
|
{
|
|
title: '订单金额',
|
|
dataIndex: 'total',
|
|
},
|
|
{
|
|
title: '状态',
|
|
dataIndex: 'orderStatus',
|
|
hideInSearch: true,
|
|
valueType: 'select',
|
|
valueEnum: ORDER_STATUS_ENUM,
|
|
},
|
|
{
|
|
title: '来源',
|
|
hideInSearch: true,
|
|
render: (_, record) =>
|
|
formatSource(record.source_type, record.utm_source),
|
|
},
|
|
{
|
|
title: '订单内容',
|
|
dataIndex: 'orderItems',
|
|
render: (_, record) => {
|
|
return (
|
|
<div>
|
|
{record.orderItems?.map((item) => (
|
|
<div>
|
|
${item.total} : {item.name} * {item.quantity}
|
|
</div>
|
|
))}
|
|
</div>
|
|
);
|
|
},
|
|
},
|
|
{
|
|
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 () => {
|
|
const { data, success } = await statisticscontrollerGetorderbyemail({
|
|
email,
|
|
});
|
|
return {
|
|
data,
|
|
success,
|
|
};
|
|
}}
|
|
toolBarRender={() => [
|
|
<AddTag email={email} tags={tags} tableRef={actionRef} />,
|
|
]}
|
|
/>
|
|
</ModalForm>
|
|
);
|
|
};
|
|
|
|
export default ListPage;
|