forked from yoone/WEB
280 lines
6.7 KiB
TypeScript
280 lines
6.7 KiB
TypeScript
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
|
|
|
import {
|
|
statisticscontrollerGetinativeusersbymonth,
|
|
statisticscontrollerGetordersorce,
|
|
} from '@/servers/api/statistics';
|
|
import {
|
|
ActionType,
|
|
PageContainer,
|
|
ProColumns,
|
|
ProTable,
|
|
} from '@ant-design/pro-components';
|
|
import { Space, Tag } from 'antd';
|
|
import dayjs from 'dayjs';
|
|
import ReactECharts from 'echarts-for-react';
|
|
import { HistoryOrder } from '../Order';
|
|
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)
|
|
.sort((a, b) => a.localeCompare(b));
|
|
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;
|