diff --git a/.umirc.ts b/.umirc.ts index 5d47237..4889d7d 100644 --- a/.umirc.ts +++ b/.umirc.ts @@ -134,9 +134,14 @@ export default defineConfig({ }, { name: '数据分析列表', - path: '/customer/statistic', - component: './Customer/Statistic', + path: '/customer/statistic/list', + component: './Customer/StatisticList', }, + // { + // name: '客户统计', + // path: '/customer/statistic/home', + // component: './Customer/Statistic', + // } ], }, { diff --git a/package.json b/package.json index 7ceb5ad..f05ffb3 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,8 @@ "@ant-design/charts": "^2.2.6", "@ant-design/icons": "^5.0.1", "@ant-design/pro-components": "^2.4.4", + "@cubejs-client/core": "^1.6.4", + "@cubejs-client/react": "^1.6.4", "@fingerprintjs/fingerprintjs": "^4.6.2", "@monaco-editor/react": "^4.7.0", "@tinymce/tinymce-react": "^6.3.0", diff --git a/src/pages/Customer/Statistic/index.tsx b/src/pages/Customer/Statistic/index.tsx index 09d098d..e69de29 100644 --- a/src/pages/Customer/Statistic/index.tsx +++ b/src/pages/Customer/Statistic/index.tsx @@ -1,289 +0,0 @@ -import { HistoryOrder } from '@/pages/Statistics/Order'; -import { - customercontrollerAddtag, - customercontrollerDeltag, - customercontrollerGetcustomerlist, - customercontrollerGettags, - customercontrollerSetrate, -} from '@/servers/api/customer'; -import { - ActionType, - ModalForm, - PageContainer, - ProColumns, - ProFormSelect, - ProTable, -} from '@ant-design/pro-components'; -import { App, Button, Rate, Space, Tag } from 'antd'; -import dayjs from 'dayjs'; -import { useRef, useState } from 'react'; - -const ListPage: React.FC = () => { - const actionRef = useRef(); - const { message } = App.useApp(); - 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: '等级', - hideInSearch: true, - render: (_, record) => { - if (!record.yoone_orders || !record.yoone_total) return '-'; - if (Number(record.yoone_orders) === 1 && Number(record.yoone_total) > 0) - return 'B'; - return '-'; - }, - }, - { - title: '评星', - dataIndex: 'rate', - width: 200, - render: (_, record) => { - return ( - { - try { - const { success, message: msg } = - await customercontrollerSetrate({ - id: record.customerId, - rate: val, - }); - if (success) { - message.success(msg); - actionRef.current?.reload(); - } - } catch (e) { - message.error(e.message); - } - }} - value={record.rate} - /> - ); - }, - }, - { - title: '联系电话', - dataIndex: 'phone', - hideInSearch: true, - render: (_, record) => record?.billing.phone || record?.shipping.phone, - }, - { - title: '账单地址', - dataIndex: 'billing', - render: (_, record) => - JSON.stringify(record?.billing || record?.shipping), - }, - { - title: '标签', - dataIndex: 'tags', - render: (_, record) => { - return ( - - {(record.tags || []).map((tag) => { - return ( - { - const { success, message: msg } = - await customercontrollerDeltag({ - email: record.email, - tag, - }); - return false; - }} - > - {tag} - - ); - })} - - ); - }, - }, - { - title: '操作', - dataIndex: 'option', - valueType: 'option', - fixed: 'right', - render: (_, record) => { - return ( - - - - - ); - }, - }, - ]; - return ( - - { - 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} - /> - - ); -}; - -export const AddTag: React.FC<{ - email: string; - tags?: string[]; - tableRef: React.MutableRefObject; -}> = ({ email, tags, tableRef }) => { - const { message } = App.useApp(); - const [tagList, setTagList] = useState([]); - - return ( - 修改标签} - width={800} - modalProps={{ - destroyOnHidden: true, - }} - submitter={false} - > - { - 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); - }, - }} - > - - ); -}; - -export default ListPage; diff --git a/src/pages/Customer/StatisticList/index.tsx b/src/pages/Customer/StatisticList/index.tsx new file mode 100644 index 0000000..09d098d --- /dev/null +++ b/src/pages/Customer/StatisticList/index.tsx @@ -0,0 +1,289 @@ +import { HistoryOrder } from '@/pages/Statistics/Order'; +import { + customercontrollerAddtag, + customercontrollerDeltag, + customercontrollerGetcustomerlist, + customercontrollerGettags, + customercontrollerSetrate, +} from '@/servers/api/customer'; +import { + ActionType, + ModalForm, + PageContainer, + ProColumns, + ProFormSelect, + ProTable, +} from '@ant-design/pro-components'; +import { App, Button, Rate, Space, Tag } from 'antd'; +import dayjs from 'dayjs'; +import { useRef, useState } from 'react'; + +const ListPage: React.FC = () => { + const actionRef = useRef(); + const { message } = App.useApp(); + 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: '等级', + hideInSearch: true, + render: (_, record) => { + if (!record.yoone_orders || !record.yoone_total) return '-'; + if (Number(record.yoone_orders) === 1 && Number(record.yoone_total) > 0) + return 'B'; + return '-'; + }, + }, + { + title: '评星', + dataIndex: 'rate', + width: 200, + render: (_, record) => { + return ( + { + try { + const { success, message: msg } = + await customercontrollerSetrate({ + id: record.customerId, + rate: val, + }); + if (success) { + message.success(msg); + actionRef.current?.reload(); + } + } catch (e) { + message.error(e.message); + } + }} + value={record.rate} + /> + ); + }, + }, + { + title: '联系电话', + dataIndex: 'phone', + hideInSearch: true, + render: (_, record) => record?.billing.phone || record?.shipping.phone, + }, + { + title: '账单地址', + dataIndex: 'billing', + render: (_, record) => + JSON.stringify(record?.billing || record?.shipping), + }, + { + title: '标签', + dataIndex: 'tags', + render: (_, record) => { + return ( + + {(record.tags || []).map((tag) => { + return ( + { + const { success, message: msg } = + await customercontrollerDeltag({ + email: record.email, + tag, + }); + return false; + }} + > + {tag} + + ); + })} + + ); + }, + }, + { + title: '操作', + dataIndex: 'option', + valueType: 'option', + fixed: 'right', + render: (_, record) => { + return ( + + + + + ); + }, + }, + ]; + return ( + + { + 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} + /> + + ); +}; + +export const AddTag: React.FC<{ + email: string; + tags?: string[]; + tableRef: React.MutableRefObject; +}> = ({ email, tags, tableRef }) => { + const { message } = App.useApp(); + const [tagList, setTagList] = useState([]); + + return ( + 修改标签} + width={800} + modalProps={{ + destroyOnHidden: true, + }} + submitter={false} + > + { + 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); + }, + }} + > + + ); +}; + +export default ListPage; diff --git a/src/pages/Site/Shop/Layout.tsx b/src/pages/Site/Shop/Layout.tsx index af3f651..3ca0cc0 100644 --- a/src/pages/Site/Shop/Layout.tsx +++ b/src/pages/Site/Shop/Layout.tsx @@ -95,7 +95,7 @@ const ShopLayout: React.FC = () => {