diff --git a/.umirc.ts b/.umirc.ts index 0e17571..2a69ec8 100644 --- a/.umirc.ts +++ b/.umirc.ts @@ -1,10 +1,10 @@ import { defineConfig } from '@umijs/max'; +import { codeInspectorPlugin } from 'code-inspector-plugin'; const isDev = process.env.NODE_ENV === 'development'; const UMI_APP_API_URL = isDev ? 'http://localhost:7001' : 'https://api.yoone.ca'; -import { codeInspectorPlugin } from 'code-inspector-plugin'; export default defineConfig({ hash: true, @@ -23,7 +23,7 @@ export default defineConfig({ config.plugin('code-inspector-plugin').use( codeInspectorPlugin({ bundler: 'webpack', - }) + }), ); }, routes: [ @@ -44,17 +44,17 @@ export default defineConfig({ ], }, { - name: '站点管理', - path: '/site', - access: 'canSeeSite', - routes: [ - { - name: '站点列表', - path: '/site/list', - component: './Site/List', - }, - ], - }, + name: '站点管理', + path: '/site', + access: 'canSeeSite', + routes: [ + { + name: '站点列表', + path: '/site/list', + component: './Site/List', + }, + ], + }, { name: '商品管理', path: '/product', diff --git a/README.md b/README.md index 7c7ac02..0164b5e 100644 --- a/README.md +++ b/README.md @@ -1,2 +1 @@ # WEB - diff --git a/src/access.ts b/src/access.ts index c6d252a..1f6dfcd 100644 --- a/src/access.ts +++ b/src/access.ts @@ -1,15 +1,39 @@ export default (initialState: any) => { const isSuper = initialState?.user?.isSuper ?? false; const isAdmin = initialState?.user?.Admin ?? false; - const canSeeOrganiza = (isSuper || isAdmin) || (initialState?.user?.permissions?.includes('organiza') ?? false); - const canSeeProduct = (isSuper || isAdmin) || (initialState?.user?.permissions?.includes('product') ?? false); - const canSeeStock = (isSuper || isAdmin) || (initialState?.user?.permissions?.includes('stock') ?? false); - const canSeeOrder = (isSuper || isAdmin) || - ((initialState?.user?.permissions?.includes('order') ?? false) || (initialState?.user?.permissions?.includes('order-10-days') ?? false)); - const canSeeCustomer = (isSuper || isAdmin) || (initialState?.user?.permissions?.includes('customer') ?? false); - const canSeeLogistics = (isSuper || isAdmin) || (initialState?.user?.permissions?.includes('logistics') ?? false); - const canSeeStatistics = (isSuper || isAdmin) || (initialState?.user?.permissions?.includes('statistics') ?? false); - const canSeeSite = (isSuper || isAdmin) || (initialState?.user?.permissions?.includes('site') ?? false); + const canSeeOrganiza = + isSuper || + isAdmin || + (initialState?.user?.permissions?.includes('organiza') ?? false); + const canSeeProduct = + isSuper || + isAdmin || + (initialState?.user?.permissions?.includes('product') ?? false); + const canSeeStock = + isSuper || + isAdmin || + (initialState?.user?.permissions?.includes('stock') ?? false); + const canSeeOrder = + isSuper || + isAdmin || + (initialState?.user?.permissions?.includes('order') ?? false) || + (initialState?.user?.permissions?.includes('order-10-days') ?? false); + const canSeeCustomer = + isSuper || + isAdmin || + (initialState?.user?.permissions?.includes('customer') ?? false); + const canSeeLogistics = + isSuper || + isAdmin || + (initialState?.user?.permissions?.includes('logistics') ?? false); + const canSeeStatistics = + isSuper || + isAdmin || + (initialState?.user?.permissions?.includes('statistics') ?? false); + const canSeeSite = + isSuper || + isAdmin || + (initialState?.user?.permissions?.includes('site') ?? false); return { canSeeOrganiza, diff --git a/src/constants/index.ts b/src/constants/index.ts index d0708c5..a2e78b4 100644 --- a/src/constants/index.ts +++ b/src/constants/index.ts @@ -116,5 +116,5 @@ export const ORDER_STATUS_ENUM: ProSchemaValueEnumObj = { refund_cancelled: { text: '已取消退款', status: 'refund_cancelled', - } + }, }; diff --git a/src/hooks/useDeviceFingerprint.ts b/src/hooks/useDeviceFingerprint.ts index b31dee2..991644e 100644 --- a/src/hooks/useDeviceFingerprint.ts +++ b/src/hooks/useDeviceFingerprint.ts @@ -1,5 +1,5 @@ -import { useEffect, useState } from 'react'; import FingerprintJS from '@fingerprintjs/fingerprintjs'; +import { useEffect, useState } from 'react'; /** * Hook: 获取设备指纹(visitorId) diff --git a/src/pages/Customer/List/index.tsx b/src/pages/Customer/List/index.tsx index e9c8b03..d0ca5e0 100644 --- a/src/pages/Customer/List/index.tsx +++ b/src/pages/Customer/List/index.tsx @@ -39,9 +39,9 @@ const ListPage: React.FC = () => { { title: '客户编号', dataIndex: 'customerId', - render: (_, record) => { - if(!record.customerId) return '-'; - return String(record.customerId).padStart(6,0) + render: (_, record) => { + if (!record.customerId) return '-'; + return String(record.customerId).padStart(6, 0); }, sorter: true, }, @@ -95,31 +95,37 @@ const ListPage: React.FC = () => { 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 '-' - } + 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} /> + 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} + /> + ); }, }, { diff --git a/src/pages/Login/index.tsx b/src/pages/Login/index.tsx index 14f3722..e557530 100644 --- a/src/pages/Login/index.tsx +++ b/src/pages/Login/index.tsx @@ -1,3 +1,4 @@ +import { useDeviceFingerprint } from '@/hooks/useDeviceFingerprint'; import { usercontrollerGetuser, usercontrollerLogin } from '@/servers/api/user'; import { LockOutlined, UserOutlined } from '@ant-design/icons'; import { @@ -7,7 +8,6 @@ import { } from '@ant-design/pro-components'; import { history, useModel } from '@umijs/max'; import { App, theme } from 'antd'; -import {useDeviceFingerprint} from '@/hooks/useDeviceFingerprint'; import { useState } from 'react'; const Page = () => { @@ -15,28 +15,32 @@ const Page = () => { const { token } = theme.useToken(); const { message } = App.useApp(); const deviceId = useDeviceFingerprint(); - const [ isAuth, setIsAuth ] = useState(false) + const [isAuth, setIsAuth] = useState(false); - console.log(deviceId) ; + console.log(deviceId); const onFinish = async (values: { username: string; password: string }) => { try { - const { data, success, code, message: msg } = await usercontrollerLogin({...values, deviceId}); + const { + data, + success, + code, + message: msg, + } = await usercontrollerLogin({ ...values, deviceId }); if (success) { message.success('登录成功'); localStorage.setItem('token', data?.token as string); const { data: user } = await usercontrollerGetuser(); setInitialState({ user }); history.push('/'); - return + return; } - if(code === 10001){ - message.info("验证码已发送至管理邮箱") + if (code === 10001) { + message.info('验证码已发送至管理邮箱'); setIsAuth(true); return; } message.error(msg); - } catch { message.error('登录失败'); } @@ -100,16 +104,17 @@ const Page = () => { }, ]} /> - { - isAuth? + {isAuth ? ( :<> - } + /> + ) : ( + <> + )} {/*
{ const actionRef = useRef(); @@ -69,7 +71,9 @@ const ListPage: React.FC = () => { { try { - await navigator.clipboard.writeText(record.return_tracking_number); + await navigator.clipboard.writeText( + record.return_tracking_number, + ); message.success('复制成功!'); } catch (err) { message.error('复制失败!'); @@ -106,7 +110,9 @@ const ListPage: React.FC = () => { disabled={isLoading} onClick={async () => { setIsLoading(true); - const { data } = await logisticscontrollerGetshipmentlabel({shipmentId:record.id}); + const { data } = await logisticscontrollerGetshipmentlabel({ + shipmentId: record.id, + }); const content = data.content; printPDF([content]); setIsLoading(false); @@ -120,7 +126,9 @@ const ListPage: React.FC = () => { disabled={isLoading} onClick={async () => { setIsLoading(true); - const res = await logisticscontrollerUpdateshipmentstate({shipmentId:record.id}); + const res = await logisticscontrollerUpdateshipmentstate({ + shipmentId: record.id, + }); console.log('res', res); setIsLoading(false); @@ -137,7 +145,7 @@ const ListPage: React.FC = () => { try { setIsLoading(true); const { success, message: errMsg } = - await logisticscontrollerDeleteshipment({id:record.id}); + await logisticscontrollerDeleteshipment({ id: record.id }); if (!success) { throw new Error(errMsg); } diff --git a/src/pages/Logistics/Services/index.tsx b/src/pages/Logistics/Services/index.tsx index f88e995..db49b12 100644 --- a/src/pages/Logistics/Services/index.tsx +++ b/src/pages/Logistics/Services/index.tsx @@ -1,6 +1,5 @@ import { logisticscontrollerGetservicelist, - logisticscontrollerSyncservices, logisticscontrollerToggleactive, } from '@/servers/api/logistics'; import { @@ -10,7 +9,7 @@ import { ProFormSwitch, ProTable, } from '@ant-design/pro-components'; -import { App, Button } from 'antd'; +import { App } from 'antd'; import { useRef } from 'react'; const ListPage: React.FC = () => { diff --git a/src/pages/Order/Items/index.tsx b/src/pages/Order/Items/index.tsx index 945ddbf..0929852 100644 --- a/src/pages/Order/Items/index.tsx +++ b/src/pages/Order/Items/index.tsx @@ -1,11 +1,15 @@ -import React, { useRef } from 'react'; -import { PageContainer } from '@ant-design/pro-layout'; -import type { ProColumns, ActionType, ProTableProps } from '@ant-design/pro-components'; -import { ProTable } from '@ant-design/pro-components'; -import { App } from 'antd'; -import dayjs from 'dayjs'; import { ordercontrollerGetordersales } from '@/servers/api/order'; import { sitecontrollerAll } from '@/servers/api/site'; +import type { + ActionType, + ProColumns, + ProTableProps, +} from '@ant-design/pro-components'; +import { ProTable } from '@ant-design/pro-components'; +import { PageContainer } from '@ant-design/pro-layout'; +import { App } from 'antd'; +import dayjs from 'dayjs'; +import React, { useRef } from 'react'; // 列表行数据结构(订单商品聚合) interface OrderItemAggRow { @@ -87,7 +91,10 @@ const OrderItemsPage: React.FC = () => { request: async () => { // 拉取站点列表(后台 /site/all) const { data = [] } = await sitecontrollerAll(); - return (data || []).map((item: any) => ({ label: item.siteName, value: item.id })); + return (data || []).map((item: any) => ({ + label: item.siteName, + value: item.id, + })); }, }, { @@ -104,7 +111,9 @@ const OrderItemsPage: React.FC = () => { ]; // 表格请求方法:调用 /order/getOrderSales 接口并设置 isSource=true 获取订单项聚合 - const request: ProTableProps['request'] = async (params:any) => { + const request: ProTableProps['request'] = async ( + params: any, + ) => { try { const { current = 1, pageSize = 10, siteId, name } = params as any; const [startDate, endDate] = (params as any).dateRange || []; @@ -115,7 +124,9 @@ const OrderItemsPage: React.FC = () => { siteId, name, isSource: true as any, - startDate: startDate ? (dayjs(startDate).toISOString() as any) : undefined, + startDate: startDate + ? (dayjs(startDate).toISOString() as any) + : undefined, endDate: endDate ? (dayjs(endDate).toISOString() as any) : undefined, } as any); const { success, data, message: errMsg } = resp as any; @@ -132,10 +143,12 @@ const OrderItemsPage: React.FC = () => { }; return ( - + actionRef={actionRef} - rowKey={(r) => `${r.externalProductId}-${r.externalVariationId}-${r.name}`} + rowKey={(r) => + `${r.externalProductId}-${r.externalVariationId}-${r.name}` + } columns={columns} request={request} pagination={{ showSizeChanger: true }} @@ -146,4 +159,4 @@ const OrderItemsPage: React.FC = () => { ); }; -export default OrderItemsPage; \ No newline at end of file +export default OrderItemsPage; diff --git a/src/pages/Order/List/index.tsx b/src/pages/Order/List/index.tsx index c45abaf..af56bd3 100644 --- a/src/pages/Order/List/index.tsx +++ b/src/pages/Order/List/index.tsx @@ -1,16 +1,13 @@ import styles from '../../../style/order-list.css'; import InternationalPhoneInput from '@/components/InternationalPhoneInput'; -import { HistoryOrder } from '@/pages/Statistics/Order'; import { ORDER_STATUS_ENUM } from '@/constants'; +import { HistoryOrder } from '@/pages/Statistics/Order'; import { logisticscontrollerCreateshipment, - logisticscontrollerGetshipmentfee, logisticscontrollerDelshipment, - logisticscontrollerGetpaymentmethods, - logisticscontrollerGetratelist, + logisticscontrollerGetshipmentfee, logisticscontrollerGetshippingaddresslist, - // logisticscontrollerGetshipmentlabel, } from '@/servers/api/logistics'; import { ordercontrollerCancelorder, @@ -27,9 +24,9 @@ import { ordercontrollerUpdateorderitems, } from '@/servers/api/order'; import { productcontrollerSearchproducts } from '@/servers/api/product'; -import { wpproductcontrollerSearchproducts } from '@/servers/api/wpProduct'; import { sitecontrollerAll } from '@/servers/api/site'; import { stockcontrollerGetallstockpoints } from '@/servers/api/stock'; +import { wpproductcontrollerSearchproducts } from '@/servers/api/wpProduct'; import { formatShipmentState, formatSource } from '@/utils/format'; import { CodeSandboxOutlined, @@ -65,7 +62,6 @@ import { Button, Card, Col, - Descriptions, Divider, Drawer, Dropdown, @@ -79,10 +75,8 @@ import { TabsProps, Tag, } from 'antd'; -import Item from 'antd/es/list/Item'; -import RelatedOrders from '../../Subscription/Orders/RelatedOrders'; import React, { useMemo, useRef, useState } from 'react'; -import { printPDF } from '@/utils/util'; +import RelatedOrders from '../../Subscription/Orders/RelatedOrders'; const ListPage: React.FC = () => { const actionRef = useRef(); @@ -129,14 +123,13 @@ const ListPage: React.FC = () => { label: '已申请退款', }, { - key: 'refund_approved', - label: "已退款", + label: '已退款', // label: '退款申请已通过', }, { key: 'refund_cancelled', - label: "已完成" + label: '已完成', // label: '已取消退款', }, // { @@ -167,21 +160,32 @@ const ListPage: React.FC = () => { dataIndex: 'id', hideInSearch: true, }, + { + title: '订单ID', + dataIndex: 'externalOrderId', + }, { title: '日期', dataIndex: 'date', hideInTable: true, valueType: 'dateRange', }, - + { title: '订阅', dataIndex: 'isSubscription', hideInSearch: true, render: (_, record) => { - const related = Array.isArray((record as any)?.related) ? (record as any).related : []; - const isSub = related.some((it) => it?.externalSubscriptionId || it?.billing_period || it?.line_items); - return {isSub ? '是' : '否'}; + const related = Array.isArray((record as any)?.related) + ? (record as any).related + : []; + const isSub = related.some( + (it) => + it?.externalSubscriptionId || it?.billing_period || it?.line_items, + ); + return ( + {isSub ? '是' : '否'} + ); }, }, { @@ -235,7 +239,7 @@ const ListPage: React.FC = () => { dataIndex: 'billing_phone', render: (_, record) => record.shipping?.phone || record.billing?.phone, }, - { + { title: '换货次数', dataIndex: 'exchange_frequency', hideInSearch: true, @@ -306,7 +310,11 @@ const ListPage: React.FC = () => { record.orderStatus, ) ? ( <> - + ) : ( @@ -359,11 +367,12 @@ const ListPage: React.FC = () => { }, { key: 'history', - label: + label: ( , + /> + ), }, { key: 'note', @@ -436,7 +445,9 @@ const ListPage: React.FC = () => { actionRef={actionRef} rowKey="id" rowClassName={(record) => { - return record.id === activeLine ? styles['selected-line-order-protable'] : ''; + return record.id === activeLine + ? styles['selected-line-order-protable'] + : ''; }} toolBarRender={() => [ , @@ -525,7 +536,7 @@ const Detail: React.FC<{ tableRef: React.MutableRefObject; orderId: number; record: API.Order; - setActiveLine: Function + setActiveLine: Function; }> = ({ tableRef, orderId, record, setActiveLine }) => { const [visiable, setVisiable] = useState(false); const { message } = App.useApp(); @@ -557,10 +568,14 @@ const Detail: React.FC<{ return ( <> - @@ -577,29 +592,29 @@ const Detail: React.FC<{ ) ? [] : [ - , - , - ]), + }} + > + 同步订单 + , + ]), // ...(['processing', 'pending_reshipment'].includes(record.orderStatus) // ? [ // , @@ -618,136 +633,136 @@ const Detail: React.FC<{ 'pending_refund', ].includes(record.orderStatus) ? [ - , - { - try { - const { success, message: errMsg } = - await ordercontrollerChangestatus( - { - id: record.id, - }, - { - status: 'after_sale_pending', - }, - ); - if (!success) { - throw new Error(errMsg); + , + { + try { + const { success, message: errMsg } = + await ordercontrollerChangestatus( + { + id: record.id, + }, + { + status: 'after_sale_pending', + }, + ); + if (!success) { + throw new Error(errMsg); + } + tableRef.current?.reload(); + } catch (error: any) { + message.error(error.message); } - tableRef.current?.reload(); - } catch (error: any) { - message.error(error.message); - } - }} - > - - , - ] + }} + > + + , + ] : []), ...(record.orderStatus === 'after_sale_pending' ? [ - , - { - try { - const { success, message: errMsg } = - await ordercontrollerCancelorder({ - id: record.id, - }); - if (!success) { - throw new Error(errMsg); - } - tableRef.current?.reload(); - } catch (error: any) { - message.error(error.message); - } - }} - > - - , - , - { - try { - const { success, message: errMsg } = - await ordercontrollerRefundorder({ - id: record.id, - }); - if (!success) { - throw new Error(errMsg); - } - tableRef.current?.reload(); - } catch (error: any) { - message.error(error.message); - } - }} - > - - , - , - { - try { - const { success, message: errMsg } = - await ordercontrollerCompletedorder({ - id: record.id, - }); - if (!success) { - throw new Error(errMsg); - } - tableRef.current?.reload(); - } catch (error: any) { - message.error(error.message); - } - }} - > - - , - , - { - try { - const { success, message: errMsg } = - await ordercontrollerChangestatus( - { + , + { + try { + const { success, message: errMsg } = + await ordercontrollerCancelorder({ id: record.id, - }, - { - status: 'pending_reshipment', - }, - ); - if (!success) { - throw new Error(errMsg); + }); + if (!success) { + throw new Error(errMsg); + } + tableRef.current?.reload(); + } catch (error: any) { + message.error(error.message); } - tableRef.current?.reload(); - } catch (error: any) { - message.error(error.message); - } - }} - > - - , - ] + }} + > + + , + , + { + try { + const { success, message: errMsg } = + await ordercontrollerRefundorder({ + id: record.id, + }); + if (!success) { + throw new Error(errMsg); + } + tableRef.current?.reload(); + } catch (error: any) { + message.error(error.message); + } + }} + > + + , + , + { + try { + const { success, message: errMsg } = + await ordercontrollerCompletedorder({ + id: record.id, + }); + if (!success) { + throw new Error(errMsg); + } + tableRef.current?.reload(); + } catch (error: any) { + message.error(error.message); + } + }} + > + + , + , + { + try { + const { success, message: errMsg } = + await ordercontrollerChangestatus( + { + id: record.id, + }, + { + status: 'pending_reshipment', + }, + ); + if (!success) { + throw new Error(errMsg); + } + tableRef.current?.reload(); + } catch (error: any) { + message.error(error.message); + } + }} + > + + , + ] : []), ]} > @@ -781,7 +796,9 @@ const Detail: React.FC<{ /> - { return (
@@ -790,7 +807,8 @@ const Detail: React.FC<{
); - }} /> + }} + /> @@ -902,7 +920,7 @@ const Detail: React.FC<{
    {record?.items?.map((item: any) => (
  • - {item.name}:{item.quantity} + {item.name}:{item.quantity}
  • ))}
@@ -910,13 +928,13 @@ const Detail: React.FC<{ }} /> {/* 显示 related order */} - { - return ; - }} -/> + { + return ; + }} + /> {/* 订单内容 */} { - return ( - - ) + return ; }} /> { - try { - const { success, message: errMsg } = - await logisticscontrollerDelshipment({ - id: v.id, - }); - if (!success) { - throw new Error(errMsg); + { + try { + const { success, message: errMsg } = + await logisticscontrollerDelshipment({ + id: v.id, + }); + if (!success) { + throw new Error(errMsg); + } + tableRef.current?.reload(); + initRequest(); + } catch (error: any) { + message.error(error.message); } - tableRef.current?.reload(); - initRequest(); - } catch (error: any) { - message.error(error.message); - } - }} - > - - 取消运单 - , - ] + }} + > + + 取消运单 + , + ] : [] } > @@ -1194,7 +1207,8 @@ const Shipping: React.FC<{ }, }} trigger={ - @@ -1972,7 +2011,6 @@ const SalesChange: React.FC<{ }> = ({ id, detailRef }) => { const formRef = useRef(); - return ( { - let idx = acc.findIndex((v: any) => v.productId === cur.productId); - if (idx === -1) { - acc.push(cur); - } else { - acc[idx].quantity += cur.quantity; - } - return acc; - }, + data.sales = data.sales?.reduce( + (acc: API.OrderSale[], cur: API.OrderSale) => { + let idx = acc.findIndex((v: any) => v.productId === cur.productId); + if (idx === -1) { + acc.push(cur); + } else { + acc[idx].quantity += cur.quantity; + } + return acc; + }, [], ); - // setOptions( // data.sales?.map((item) => ({ // label: item.name, // value: item.sku, // })) || [], // ); - return { ...data}; + return { ...data }; }} onFinish={async (formData: any) => { const { sales } = formData; - const res = await ordercontrollerUpdateorderitems({ orderId: id }, sales); + const res = await ordercontrollerUpdateorderitems( + { orderId: id }, + sales, + ); if (!res.success) { message.error(`更新货物信息失败: ${res.message}`); return false; } - message.success('更新成功') + message.success('更新成功'); detailRef?.current?.reload(); return true; }} > - + - { try { const { data } = await wpproductcontrollerSearchproducts({ name: keyWords, }); - return ( - data?.map((item) => { - return { - label: `${item.name}`, - value: item?.sku, - }; - }) - ); + return data?.map((item) => { + return { + label: `${item.name}`, + value: item?.sku, + }; + }); } catch (error) { return []; } @@ -2076,17 +2111,11 @@ const SalesChange: React.FC<{ precision: 0, }} /> - - + - - { @@ -2094,14 +2123,12 @@ const SalesChange: React.FC<{ const { data } = await productcontrollerSearchproducts({ name: keyWords, }); - return ( - data?.map((item) => { - return { - label: `${item.name} - ${item.nameCn}`, - value: item?.sku, - }; - }) - ); + return data?.map((item) => { + return { + label: `${item.name} - ${item.nameCn}`, + value: item?.sku, + }; + }); } catch (error) { return []; } @@ -2131,7 +2158,7 @@ const SalesChange: React.FC<{ ); -} +}; const CreateOrder: React.FC<{ tableRef?: React.MutableRefObject; diff --git a/src/pages/Product/List/index.tsx b/src/pages/Product/List/index.tsx index b7cf731..2370ac2 100644 --- a/src/pages/Product/List/index.tsx +++ b/src/pages/Product/List/index.tsx @@ -26,24 +26,31 @@ const NameCn: React.FC<{ id: number; value: string; tableRef: React.MutableRefObject; -}> = ({value,tableRef, id}) => { +}> = ({ value, tableRef, id }) => { const { message } = App.useApp(); const [editable, setEditable] = React.useState(false); - if (!editable) return
setEditable(true)}>{value||'-'}
; - return { - 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() - }} /> -} + if (!editable) + return
setEditable(true)}>{value || '-'}
; + return ( + { + 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 actionRef = useRef(); @@ -56,10 +63,10 @@ const List: React.FC = () => { { title: '中文名', dataIndex: 'nameCn', - render: (_, record) => { + render: (_, record) => { return ( - ) + ); }, }, { @@ -148,7 +155,7 @@ const List: React.FC = () => { success, }; }} - columns={columns} + columns={columns} editable={{ type: 'single', onSave: async (key, record, originRow) => { diff --git a/src/pages/Product/WpList/index.tsx b/src/pages/Product/WpList/index.tsx index 17f304e..2b32c80 100644 --- a/src/pages/Product/WpList/index.tsx +++ b/src/pages/Product/WpList/index.tsx @@ -262,9 +262,9 @@ const UpdateStatus: React.FC<{ { id: initialValues.id, }, - { + { status, - stock_status + stock_status, }, ); if (!success) { @@ -285,7 +285,7 @@ const UpdateStatus: React.FC<{ name="status" valueEnum={PRODUCT_STATUS_ENUM} /> - ; values: API.WpProductDTO; diff --git a/src/pages/Site/List/index.tsx b/src/pages/Site/List/index.tsx index 40ad842..b6a9507 100644 --- a/src/pages/Site/List/index.tsx +++ b/src/pages/Site/List/index.tsx @@ -1,8 +1,16 @@ -import React, { useEffect, useRef, useState } from 'react'; -import { ActionType, ProColumns, ProTable, ProFormInstance } from '@ant-design/pro-components'; -import { DrawerForm, ProFormText, ProFormSelect, ProFormSwitch } from '@ant-design/pro-components'; -import { Button, message, Popconfirm, Space, Tag } from 'antd'; +import { + ActionType, + DrawerForm, + ProColumns, + ProFormInstance, + ProFormSelect, + ProFormSwitch, + ProFormText, + ProTable, +} from '@ant-design/pro-components'; import { request } from '@umijs/max'; +import { Button, message, Popconfirm, Space, Tag } from 'antd'; +import React, { useEffect, useRef, useState } from 'react'; // 站点数据项类型(前端不包含密钥字段,后端列表不返回密钥) interface SiteItem { @@ -58,10 +66,21 @@ const SiteList: React.FC = () => { // 表格列定义 const columns: ProColumns[] = [ - { title: 'ID', dataIndex: 'id', width: 80, sorter: true, hideInSearch: true }, + { + title: 'ID', + dataIndex: 'id', + width: 80, + sorter: true, + hideInSearch: true, + }, { title: '站点名称', dataIndex: 'siteName', width: 220 }, { title: 'API 地址', dataIndex: 'apiUrl', width: 280, hideInSearch: true }, - { title: 'SKU 前缀', dataIndex: 'skuPrefix', width: 160, hideInSearch: true }, + { + title: 'SKU 前缀', + dataIndex: 'skuPrefix', + width: 160, + hideInSearch: true, + }, { title: '平台', dataIndex: 'type', @@ -101,7 +120,9 @@ const SiteList: React.FC = () => { { try { await request(`/site/disable/${row.id}`, { @@ -159,7 +180,9 @@ const SiteList: React.FC = () => { ...(values.siteName ? { siteName: values.siteName } : {}), ...(values.apiUrl ? { apiUrl: values.apiUrl } : {}), ...(values.type ? { type: values.type } : {}), - ...(typeof values.isDisabled === 'boolean' ? { isDisabled: values.isDisabled } : {}), + ...(typeof values.isDisabled === 'boolean' + ? { isDisabled: values.isDisabled } + : {}), ...(values.skuPrefix ? { skuPrefix: values.skuPrefix } : {}), }; // 仅当输入了新密钥时才提交,未输入则保持原本值 @@ -169,7 +192,10 @@ const SiteList: React.FC = () => { if (values.consumerSecret && values.consumerSecret.trim()) { payload.consumerSecret = values.consumerSecret.trim(); } - await request(`/site/update/${editing.id}`, { method: 'PUT', data: payload }); + await request(`/site/update/${editing.id}`, { + method: 'PUT', + data: payload, + }); } else { // 新增站点时要求填写 consumerKey 和 consumerSecret if (!values.consumerKey || !values.consumerSecret) { @@ -227,9 +253,18 @@ const SiteList: React.FC = () => { onFinish={handleSubmit} > {/* 站点名称,必填 */} - + {/* API 地址,可选 */} - + {/* 平台类型选择 */} { /> {/* 是否禁用 */} - + {/* WooCommerce REST consumer key;新增必填,编辑不填则保持原值 */} - + {/* WooCommerce REST consumer secret;新增必填,编辑不填则保持原值 */} - + ); }; -export default SiteList; \ No newline at end of file +export default SiteList; diff --git a/src/pages/Statistics/Order/index.tsx b/src/pages/Statistics/Order/index.tsx index 1e86906..bf6fbb7 100644 --- a/src/pages/Statistics/Order/index.tsx +++ b/src/pages/Statistics/Order/index.tsx @@ -21,7 +21,9 @@ import { Button, Space, Tag } from 'antd'; import dayjs from 'dayjs'; import ReactECharts from 'echarts-for-react'; import { useEffect, useMemo, useRef, useState } from 'react'; +import weekOfYear from 'dayjs/plugin/weekOfYear'; +dayjs.extend(weekOfYear); const highlightText = (text: string, keyword: string) => { if (!keyword) return text; const parts = text.split(new RegExp(`(${keyword})`, 'gi')); @@ -58,10 +60,9 @@ const ListPage: React.FC = () => { } return ( - `
${xValue} ${ - ['周日', '周一', '周二', '周三', '周四', '周五', '周六'][ - dayjs(xValue).day() - ] + `
${xValue} ${['周日', '周一', '周二', '周三', '周四', '周五', '周六'][ + dayjs(xValue).day() + ] }
` + rows.join('
') ); }, @@ -128,7 +129,22 @@ const ListPage: React.FC = () => { }); if (success) { const res = data?.sort(() => -1); - setXAxis(res?.map((v) => dayjs(v.order_date).format('YYYY-MM-DD'))); + const formatMap = { + month: 'YYYY-MM', + week: 'YYYY年第WW周', + day: 'YYYY-MM-DD', + }; + const format = formatMap[params.grouping] || 'YYYY-MM-DD'; + + if (params.grouping === 'week') { + setXAxis(res?.map((v) => { + const [year, week] = v.order_date.split('-'); + return `${year}年第${week}周`; + })); + } else { + setXAxis(res?.map((v) => dayjs(v.order_date).format(format))); + } + setSeries([ { name: 'TOGO CPC订单数', @@ -583,6 +599,16 @@ const ListPage: React.FC = () => { name="date" /> {/* */} + { + const [data, setData] = useState({}); - const [data, setData] = useState({}); + useEffect(() => { + statisticscontrollerGetordersorce().then(({ data, success }) => { + if (success) setData(data); + }); + }, []); - 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([]) - const actionRef = useRef(); - const columns: ProColumns[] = [ + 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 = [ { - 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; + name: '新客户', + type: 'bar', + data: data?.inactiveRes?.map((v) => v.new_user_count)?.sort((_) => -1), + label: { + show: true, }, - }, - { - 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 ( - - {(record.tags || []).map((tag) => { - return ( - { - const { success, message: msg } = - await customercontrollerDeltag({ - email: record.email, - tag, - }); - return false; - }} - > - {tag} - - ); - })} - - ); + formatter: function (params) { + if (!params.value) return ''; + return Math.abs(params.value) + '人'; }, + emphasis: { + focus: 'series', + }, + xAxisIndex: 0, + yAxisIndex: 0, }, { - title: '操作', - dataIndex: 'option', - valueType: 'option', - render: (_, record) => { - return ( - - ); + 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( - - { - if (params.componentType === 'series') { - setTableData([]) - const {success, data} = await statisticscontrollerGetinativeusersbymonth({ - month: params.name - }) - if(success) setTableData(data) - } - }, - }} - /> - { - tableData?.length ? - - :<> - - } - - ) -} + 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]); -export default ListPage; \ No newline at end of file + const [tableData, setTableData] = useState([]); + const actionRef = useRef(); + 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 ( + + {(record.tags || []).map((tag) => { + return ( + { + const { success, message: msg } = + await customercontrollerDeltag({ + email: record.email, + tag, + }); + return false; + }} + > + {tag} + + ); + })} + + ); + }, + }, + { + title: '操作', + dataIndex: 'option', + valueType: 'option', + render: (_, record) => { + return ( + + ); + }, + }, + ]; + return ( + + { + if (params.componentType === 'series') { + setTableData([]); + const { success, data } = + await statisticscontrollerGetinativeusersbymonth({ + month: params.name, + }); + if (success) setTableData(data); + } + }, + }} + /> + {tableData?.length ? ( + + ) : ( + <> + )} + + ); +}; + +export default ListPage; diff --git a/src/pages/Statistics/Sales/index.tsx b/src/pages/Statistics/Sales/index.tsx index e39a415..96eab1b 100644 --- a/src/pages/Statistics/Sales/index.tsx +++ b/src/pages/Statistics/Sales/index.tsx @@ -223,14 +223,17 @@ const ListPage: React.FC = () => { (yooneTotal.yoone12Quantity || 0) + (yooneTotal.yoone15Quantity || 0) + (yooneTotal.yoone18Quantity || 0) + - (yooneTotal.zexQuantity || 0) - } + (yooneTotal.zexQuantity || 0)}
YOONE 3MG: {yooneTotal.yoone3Quantity || 0}
YOONE 6MG: {yooneTotal.yoone6Quantity || 0}
YOONE 9MG: {yooneTotal.yoone9Quantity || 0}
YOONE 12MG新: {yooneTotal.yoone12QuantityNew || 0}
-
YOONE 12MG白: {(yooneTotal.yoone12Quantity || 0) - (yooneTotal.yoone12QuantityNew || 0)}
+
+ YOONE 12MG白:{' '} + {(yooneTotal.yoone12Quantity || 0) - + (yooneTotal.yoone12QuantityNew || 0)} +
YOONE 15MG: {yooneTotal.yoone15Quantity || 0}
YOONE 18MG: {yooneTotal.yoone18Quantity || 0}
ZEX: {yooneTotal.zexQuantity || 0}
diff --git a/src/pages/Stock/PurchaseOrder/index.tsx b/src/pages/Stock/PurchaseOrder/index.tsx index 066ba35..5a00cd1 100644 --- a/src/pages/Stock/PurchaseOrder/index.tsx +++ b/src/pages/Stock/PurchaseOrder/index.tsx @@ -427,9 +427,7 @@ const UpdateForm: React.FC<{ {({ items }) => { - return ( - '数量:' + items?.reduce((acc, cur) => acc + cur.quantity, 0) - ); + return '数量:' + items?.reduce((acc, cur) => acc + cur.quantity, 0); }} @@ -459,7 +457,7 @@ const UpdateForm: React.FC<{ return ( data?.map((item) => { return { - label: `${item.name} - ${item.nameCn}`, + label: `${item.name} - ${item.nameCn}`, value: item.sku, }; }) || [] @@ -624,7 +622,7 @@ const DetailForm: React.FC<{ return ( data?.map((item) => { return { - label: `${item.name} - ${item.nameCn}`, + label: `${item.name} - ${item.nameCn}`, value: item.sku, }; }) || [] diff --git a/src/pages/Stock/Record/index.tsx b/src/pages/Stock/Record/index.tsx index 48a5e88..5ece148 100644 --- a/src/pages/Stock/Record/index.tsx +++ b/src/pages/Stock/Record/index.tsx @@ -31,12 +31,12 @@ const ListPage: React.FC = () => { dataIndex: 'operationType', valueType: 'select', valueEnum: { - 'in': { - text: '入库' + in: { + text: '入库', + }, + out: { + text: '出库', }, - "out": { - text: '出库' - } }, }, { diff --git a/src/pages/Stock/Transfer/index.tsx b/src/pages/Stock/Transfer/index.tsx index a5b7a57..ee8b01b 100644 --- a/src/pages/Stock/Transfer/index.tsx +++ b/src/pages/Stock/Transfer/index.tsx @@ -207,7 +207,7 @@ const CreateForm: React.FC<{ drawerProps={{ destroyOnHidden: true, }} - onFinish={async ({orderNumber,...values}) => { + onFinish={async ({ orderNumber, ...values }) => { try { const { success, message: errMsg } = await stockcontrollerCreatetransfer(values); @@ -272,24 +272,38 @@ const CreateForm: React.FC<{ rules={[{ required: true, message: '请选择源目标仓库' }]} /> - { - 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, - }, - }), - ), - }) - }}>引用} /> + { + 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, + }, + }), + ), + }); + }} + > + 引用 + + } + /> {({ items }) => { - return '数量:' + (items?.reduce?.((acc, cur) => acc + cur.quantity, 0)||0); + return ( + '数量:' + + (items?.reduce?.((acc, cur) => acc + cur.quantity, 0) || 0) + ); }} { return { - label: `${item.name} - ${item.nameCn}`, + label: `${item.name} - ${item.nameCn}`, value: item.sku, }; }) || [] diff --git a/src/pages/Subscription/List/index.tsx b/src/pages/Subscription/List/index.tsx index d1ac189..184d578 100644 --- a/src/pages/Subscription/List/index.tsx +++ b/src/pages/Subscription/List/index.tsx @@ -1,4 +1,8 @@ -import React, { useRef, useState } from 'react'; +import { sitecontrollerAll } from '@/servers/api/site'; +import { + subscriptioncontrollerList, + subscriptioncontrollerSync, +} from '@/servers/api/subscription'; import { ActionType, DrawerForm, @@ -7,14 +11,10 @@ import { ProFormSelect, ProTable, } from '@ant-design/pro-components'; -import { App, Button, Tag, Drawer, List } from 'antd'; +import { App, Button, Drawer, List, Tag } from 'antd'; import dayjs from 'dayjs'; +import React, { useRef, useState } from 'react'; import { request } from 'umi'; -import { - subscriptioncontrollerList, - subscriptioncontrollerSync, -} from '@/servers/api/subscription'; -import { sitecontrollerAll } from '@/servers/api/site'; /** * 订阅状态枚举(用于筛选与展示) @@ -77,7 +77,11 @@ const ListPage: React.FC = () => { valueEnum: SUBSCRIPTION_STATUS_ENUM, // 以 Tag 形式展示,更易辨识 render: (_, row) => - row?.status ? {SUBSCRIPTION_STATUS_ENUM[row.status]?.text || row.status} : '-', + row?.status ? ( + {SUBSCRIPTION_STATUS_ENUM[row.status]?.text || row.status} + ) : ( + '-' + ), width: 120, }, { @@ -152,9 +156,9 @@ const ListPage: React.FC = () => { const { success, data, message: errMsg } = resp as any; if (!success) throw new Error(errMsg || '获取失败'); // 仅保留与父订单号完全一致的订单(避免模糊匹配误入) - const candidates: any[] = (Array.isArray(data) ? data : []).filter( - (c: any) => String(c?.externalOrderId) === parentNumber - ); + const candidates: any[] = ( + Array.isArray(data) ? data : [] + ).filter((c: any) => String(c?.externalOrderId) === parentNumber); // 拉取详情,补充状态、金额、时间 const details = [] as any[]; for (const c of candidates) { @@ -230,14 +234,22 @@ const ListPage: React.FC = () => {
- {item?.date_created ? dayjs(item.date_created).format('YYYY-MM-DD HH:mm') : '-'} + + {item?.date_created + ? dayjs(item.date_created).format('YYYY-MM-DD HH:mm') + : '-'} + {item?.status || '-'} {item?.currency_symbol || ''} - {typeof item?.total === 'number' ? item.total.toFixed(2) : item?.total ?? '-'} + {typeof item?.total === 'number' + ? item.total.toFixed(2) + : item?.total ?? '-'}
@@ -274,7 +286,9 @@ const SyncForm: React.FC<{ */ onFinish={async (values) => { try { - const { success, message: errMsg } = await subscriptioncontrollerSync(values); + const { success, message: errMsg } = await subscriptioncontrollerSync( + values, + ); if (!success) { throw new Error(errMsg); } diff --git a/src/pages/Subscription/Orders/OrderDetailDrawer.tsx b/src/pages/Subscription/Orders/OrderDetailDrawer.tsx index eabbbb3..23dd234 100644 --- a/src/pages/Subscription/Orders/OrderDetailDrawer.tsx +++ b/src/pages/Subscription/Orders/OrderDetailDrawer.tsx @@ -1,31 +1,21 @@ -import React, { useEffect, useRef, useState } from 'react'; -import { - App, - Button, - Card, - Divider, - Drawer, - Empty, - Popconfirm, - Space, - Tag, -} from 'antd'; -import { ActionType, ProDescriptions } from '@ant-design/pro-components'; import { CopyOutlined, DeleteFilled } from '@ant-design/icons'; +import { ActionType, ProDescriptions } from '@ant-design/pro-components'; +import { App, Button, Card, Divider, Drawer, Empty, Popconfirm } from 'antd'; +import React, { useEffect, useRef } from 'react'; // 服务器 API 引用(保持与原 index.tsx 一致) +import { logisticscontrollerDelshipment } from '@/servers/api/logistics'; import { ordercontrollerChangestatus, ordercontrollerGetorderdetail, ordercontrollerSyncorderbyid, } from '@/servers/api/order'; -import { logisticscontrollerDelshipment } from '@/servers/api/logistics'; import { sitecontrollerAll } from '@/servers/api/site'; // 工具与子组件 +import { ORDER_STATUS_ENUM } from '@/constants'; import { formatShipmentState, formatSource } from '@/utils/format'; import RelatedOrders from './RelatedOrders'; -import { ORDER_STATUS_ENUM } from '@/constants'; // 为保持原文件结构简单,此处从 index.tsx 引入的子组件仍由原文件导出或保持原状 // 若后续需要彻底解耦,可将 OrderNote / Shipping / SalesChange 也独立到文件 @@ -35,13 +25,13 @@ type OrderRecord = API.Order; interface OrderDetailDrawerProps { tableRef: React.MutableRefObject; // 列表刷新引用 - orderId: number; // 订单主键 ID - record: OrderRecord; // 订单行记录 - open: boolean; // 是否打开抽屉 - onClose: () => void; // 关闭抽屉回调 - setActiveLine: (id: number) => void; // 高亮当前行 - OrderNoteComponent: React.ComponentType; // 备注组件(从外部注入) - SalesChangeComponent: React.ComponentType; // 换货组件(从外部注入) + orderId: number; // 订单主键 ID + record: OrderRecord; // 订单行记录 + open: boolean; // 是否打开抽屉 + onClose: () => void; // 关闭抽屉回调 + setActiveLine: (id: number) => void; // 高亮当前行 + OrderNoteComponent: React.ComponentType; // 备注组件(从外部注入) + SalesChangeComponent: React.ComponentType; // 换货组件(从外部注入) } const OrderDetailDrawer: React.FC = ({ @@ -59,14 +49,18 @@ const OrderDetailDrawer: React.FC = ({ // 加载详情数据(与 index.tsx 中完全保持一致) const initRequest = async () => { - const { data, success }: API.OrderDetailRes = await ordercontrollerGetorderdetail({ orderId }); + const { data, success }: API.OrderDetailRes = + await ordercontrollerGetorderdetail({ orderId }); if (!success || !data) return { data: {} } as any; - data.sales = data.sales?.reduce((acc: API.OrderSale[], cur: API.OrderSale) => { - const idx = acc.findIndex((v: any) => v.productId === cur.productId); - if (idx === -1) acc.push(cur); - else acc[idx].quantity += cur.quantity; - return acc; - }, []); + data.sales = data.sales?.reduce( + (acc: API.OrderSale[], cur: API.OrderSale) => { + const idx = acc.findIndex((v: any) => v.productId === cur.productId); + if (idx === -1) acc.push(cur); + else acc[idx].quantity += cur.quantity; + return acc; + }, + [], + ); return { data } as any; }; @@ -220,108 +214,273 @@ const OrderDetailDrawer: React.FC = ({ : []), ]} > - - { - const { data = [] } = await sitecontrollerAll(); - return data.map((item) => ({ label: item.siteName, value: item.id })); - }} /> - - + + { + const { data = [] } = await sitecontrollerAll(); + return data.map((item) => ({ + label: item.siteName, + value: item.id, + })); + }} + /> + + - ( -
{r?.shipping?.phone || r?.billing?.phone || '-'}
- )} /> + ( +
+ {r?.shipping?.phone || r?.billing?.phone || '-'} +
+ )} + /> - formatSource(r.source_type, r.utm_source)} /> - - - - ( -
-
company:{r?.shipping?.company || r?.billing?.company || '-'}
-
first_name:{r?.shipping?.first_name || r?.billing?.first_name || '-'}
-
last_name:{r?.shipping?.last_name || r?.billing?.last_name || '-'}
-
country:{r?.shipping?.country || r?.billing?.country || '-'}
-
state:{r?.shipping?.state || r?.billing?.state || '-'}
-
city:{r?.shipping?.city || r?.billing?.city || '-'}
-
postcode:{r?.shipping?.postcode || r?.billing?.postcode || '-'}
-
phone:{r?.shipping?.phone || r?.billing?.phone || '-'}
-
address_1:{r?.shipping?.address_1 || r?.billing?.address_1 || '-'}
-
- )} /> - ( -
    - {(r?.items || []).map((item: any) => ( -
  • {item.name}:{item.quantity}
  • - ))} -
- )} /> - ( - - )} /> - ( -
    - {(r?.sales || []).map((item: any) => ( -
  • {item.name}:{item.quantity}
  • - ))} -
- )} /> - ( - - )} /> - { - if (!r.notes || r.notes.length === 0) return (); - return ( -
- {r.notes.map((note: any) => ( -
-
- {note.username} - {note.createdAt} + formatSource(r.source_type, r.utm_source)} + /> + + + + ( +
+
+ company: + + {r?.shipping?.company || r?.billing?.company || '-'} + +
+
+ first_name: + + {r?.shipping?.first_name || r?.billing?.first_name || '-'} + +
+
+ last_name: + + {r?.shipping?.last_name || r?.billing?.last_name || '-'} + +
+
+ country: + + {r?.shipping?.country || r?.billing?.country || '-'} + +
+
+ state: + {r?.shipping?.state || r?.billing?.state || '-'} +
+
+ city:{r?.shipping?.city || r?.billing?.city || '-'} +
+
+ postcode: + + {r?.shipping?.postcode || r?.billing?.postcode || '-'} + +
+
+ phone: + {r?.shipping?.phone || r?.billing?.phone || '-'} +
+
+ address_1: + + {r?.shipping?.address_1 || r?.billing?.address_1 || '-'} + +
+
+ )} + /> + ( +
    + {(r?.items || []).map((item: any) => ( +
  • + {item.name}:{item.quantity} +
  • + ))} +
+ )} + /> + } + /> + ( +
    + {(r?.sales || []).map((item: any) => ( +
  • + {item.name}:{item.quantity} +
  • + ))} +
+ )} + /> + ( + + )} + /> + { + if (!r.notes || r.notes.length === 0) + return ; + return ( +
+ {r.notes.map((note: any) => ( +
+
+ {note.username} + {note.createdAt} +
+
{note.content}
-
{note.content}
-
- ))} -
- ); - }} /> - { - if (!r.shipment || r.shipment.length === 0) return (); - return ( -
- {r.shipment.map((v: any) => ( - - {v.tracking_provider} - {v.primary_tracking_number} - { - try { await navigator.clipboard.writeText(v.tracking_url); message.success('复制成功!'); } - catch { message.error('复制失败!'); } - }} /> - } - actions={ (v.state === 'waiting-for-scheduling' || v.state === 'waiting-for-transit') ? [ - { - try { const { success, message: errMsg } = await logisticscontrollerDelshipment({ id: v.id }); if (!success) throw new Error(errMsg); tableRef.current?.reload(); ref.current?.reload?.(); } - catch (error: any) { message.error(error.message); } - }}> - 取消运单 - - ] : [] } - > -
订单号: {Array.isArray(v?.orderIds) ? v.orderIds.join(',') : '-'}
- {Array.isArray(v?.items) && v.items.map((item: any) => ( -
{item.name}: {item.quantity}
- ))} -
- ))} -
- ); - }} /> + ))} +
+ ); + }} + /> + { + if (!r.shipment || r.shipment.length === 0) + return ; + return ( +
+ {r.shipment.map((v: any) => ( + + {v.tracking_provider} + {v.primary_tracking_number} + { + try { + await navigator.clipboard.writeText( + v.tracking_url, + ); + message.success('复制成功!'); + } catch { + message.error('复制失败!'); + } + }} + /> + + } + actions={ + v.state === 'waiting-for-scheduling' || + v.state === 'waiting-for-transit' + ? [ + { + try { + const { success, message: errMsg } = + await logisticscontrollerDelshipment({ + id: v.id, + }); + if (!success) throw new Error(errMsg); + tableRef.current?.reload(); + ref.current?.reload?.(); + } catch (error: any) { + message.error(error.message); + } + }} + > + + 取消运单 + , + ] + : [] + } + > +
+ 订单号:{' '} + {Array.isArray(v?.orderIds) ? v.orderIds.join(',') : '-'} +
+ {Array.isArray(v?.items) && + v.items.map((item: any) => ( +
+ {item.name}: {item.quantity} +
+ ))} +
+ ))} +
+ ); + }} + /> ); }; -export default OrderDetailDrawer; \ No newline at end of file +export default OrderDetailDrawer; diff --git a/src/pages/Subscription/Orders/RelatedOrders.tsx b/src/pages/Subscription/Orders/RelatedOrders.tsx index 5b06530..6600dd3 100644 --- a/src/pages/Subscription/Orders/RelatedOrders.tsx +++ b/src/pages/Subscription/Orders/RelatedOrders.tsx @@ -1,7 +1,7 @@ -import React from 'react'; import { Empty, Tag } from 'antd'; import dayjs from 'dayjs'; import relativeTime from 'dayjs/plugin/relativeTime'; +import React from 'react'; dayjs.extend(relativeTime); @@ -12,17 +12,36 @@ dayjs.extend(relativeTime); */ const RelatedOrders: React.FC<{ data?: any[] }> = ({ data = [] }) => { const rows = (Array.isArray(data) ? data : []).map((it: any) => { - const isSubscription = !!it?.externalSubscriptionId || !!it?.billing_period || !!it?.line_items; - const number = isSubscription ? `#${it?.externalSubscriptionId || it?.id}` : `#${it?.externalOrderId || it?.id}`; + const isSubscription = + !!it?.externalSubscriptionId || !!it?.billing_period || !!it?.line_items; + const number = isSubscription + ? `#${it?.externalSubscriptionId || it?.id}` + : `#${it?.externalOrderId || it?.id}`; const relationship = isSubscription ? 'Subscription' : 'Order'; - const dateRaw = it?.start_date || it?.date_created || it?.createdAt || it?.updatedAt; + const dateRaw = + it?.start_date || it?.date_created || it?.createdAt || it?.updatedAt; const dateText = dateRaw ? dayjs(dateRaw).fromNow() : '-'; const status = (isSubscription ? it?.status : it?.orderStatus) || '-'; const statusLower = String(status).toLowerCase(); - const color = statusLower === 'active' ? 'green' : statusLower === 'cancelled' ? 'red' : 'default'; + const color = + statusLower === 'active' + ? 'green' + : statusLower === 'cancelled' + ? 'red' + : 'default'; const totalNum = Number(it?.total || 0); - const totalText = isSubscription ? `$${totalNum.toFixed(2)} / ${it?.billing_period || 'period'}` : `$${totalNum.toFixed(2)}`; - return { key: `${isSubscription ? 'sub' : 'order'}-${it?.id}`, number, relationship, dateText, status, color, totalText }; + const totalText = isSubscription + ? `$${totalNum.toFixed(2)} / ${it?.billing_period || 'period'}` + : `$${totalNum.toFixed(2)}`; + return { + key: `${isSubscription ? 'sub' : 'order'}-${it?.id}`, + number, + relationship, + dateText, + status, + color, + totalText, + }; }); if (rows.length === 0) return ; @@ -30,7 +49,14 @@ const RelatedOrders: React.FC<{ data?: any[] }> = ({ data = [] }) => { return (
{/* 表头(英文文案,符合国际化默认英文的要求) */} -
+
订单编号
关系
日期
@@ -39,11 +65,23 @@ const RelatedOrders: React.FC<{ data?: any[] }> = ({ data = [] }) => {
{rows.map((r) => ( -
- +
+
{r.relationship}
{r.dateText}
-
{r.status}
+
+ {r.status} +
{r.totalText}
))} diff --git a/src/pages/Subscription/Orders/index.tsx b/src/pages/Subscription/Orders/index.tsx index bc4a9bb..f3a6514 100644 --- a/src/pages/Subscription/Orders/index.tsx +++ b/src/pages/Subscription/Orders/index.tsx @@ -1,12 +1,16 @@ -import React, { useRef, useState } from 'react'; -import { PageContainer } from '@ant-design/pro-layout'; -import type { ProColumns, ActionType, ProTableProps } from '@ant-design/pro-components'; -import { ProTable } from '@ant-design/pro-components'; -import { App, Tag, Button } from 'antd'; -import dayjs from 'dayjs'; import { ordercontrollerGetorders } from '@/servers/api/order'; -import OrderDetailDrawer from './OrderDetailDrawer'; import { sitecontrollerAll } from '@/servers/api/site'; +import type { + ActionType, + ProColumns, + ProTableProps, +} from '@ant-design/pro-components'; +import { ProTable } from '@ant-design/pro-components'; +import { PageContainer } from '@ant-design/pro-layout'; +import { App, Button, Tag } from 'antd'; +import dayjs from 'dayjs'; +import React, { useRef, useState } from 'react'; +import OrderDetailDrawer from './OrderDetailDrawer'; interface OrderItemRow { id: number; @@ -43,7 +47,10 @@ const OrdersPage: React.FC = () => { valueType: 'select', request: async () => { const { data = [] } = await sitecontrollerAll(); - return (data || []).map((item: any) => ({ label: item.siteName, value: item.id })); + return (data || []).map((item: any) => ({ + label: item.siteName, + value: item.id, + })); }, }, { @@ -51,7 +58,10 @@ const OrdersPage: React.FC = () => { dataIndex: 'date_created', width: 180, hideInSearch: true, - render: (_, row) => (row?.date_created ? dayjs(row.date_created).format('YYYY-MM-DD HH:mm') : '-'), + render: (_, row) => + row?.date_created + ? dayjs(row.date_created).format('YYYY-MM-DD HH:mm') + : '-', }, { title: '邮箱', @@ -109,7 +119,14 @@ const OrdersPage: React.FC = () => { const request: ProTableProps['request'] = async (params) => { try { - const { current = 1, pageSize = 10, siteId, keyword, customer_email, payment_method } = params as any; + const { + current = 1, + pageSize = 10, + siteId, + keyword, + customer_email, + payment_method, + } = params as any; const [startDate, endDate] = (params as any).dateRange || []; const resp = await ordercontrollerGetorders({ current, @@ -119,7 +136,9 @@ const OrdersPage: React.FC = () => { customer_email, payment_method, isSubscriptionOnly: true as any, - startDate: startDate ? (dayjs(startDate).toISOString() as any) : undefined, + startDate: startDate + ? (dayjs(startDate).toISOString() as any) + : undefined, endDate: endDate ? (dayjs(endDate).toISOString() as any) : undefined, } as any); const { success, data, message: errMsg } = resp as any; @@ -136,10 +155,10 @@ const OrdersPage: React.FC = () => { }; return ( - + actionRef={actionRef} - rowKey='id' + rowKey="id" columns={columns} request={request} pagination={{ showSizeChanger: true }} diff --git a/src/pages/Track/index.tsx b/src/pages/Track/index.tsx index ed45b43..3f06a50 100644 --- a/src/pages/Track/index.tsx +++ b/src/pages/Track/index.tsx @@ -1,6 +1,6 @@ import { + logisticscontrollerGetlistbyorderid, logisticscontrollerGetorderlist, - logisticscontrollerGetlistbyorderid } from '@/servers/api/logistics'; import { SearchOutlined } from '@ant-design/icons'; import { PageContainer, ProFormSelect } from '@ant-design/pro-components'; @@ -16,8 +16,9 @@ const TrackPage: React.FC = () => { debounceTime={500} request={async ({ keyWords }) => { if (!keyWords || keyWords.length < 3) return []; - const { data: trackList } = - await logisticscontrollerGetorderlist({ number: keyWords }); + const { data: trackList } = await logisticscontrollerGetorderlist({ + number: keyWords, + }); return trackList?.map((v) => { return { label: v.siteName + ' ' + v.externalOrderId, @@ -29,8 +30,8 @@ const TrackPage: React.FC = () => { prefix: '订单号', async onChange(value: string) { setId(value); - setData({}) - + setData({}); + const { data } = await logisticscontrollerGetlistbyorderid({ id, }); @@ -53,32 +54,34 @@ const TrackPage: React.FC = () => { ), }} /> - { - data?.item ? + {data?.item ? ( +
-
-

原订单内容

- {data?.item?.map((item) => ( -
- {item.name} * {item.quantity} -
- ))} -
-
: <> - } - { - data?.saleItem ? +

原订单内容

+ {data?.item?.map((item) => ( +
+ {item.name} * {item.quantity} +
+ ))} +
+
+ ) : ( + <> + )} + {data?.saleItem ? ( +
-
-

订单内容

- {data?.saleItem?.map((item) => ( -
- {item.name} * {item.quantity} -
- ))} -
-
: <> - } +

订单内容

+ {data?.saleItem?.map((item) => ( +
+ {item.name} * {item.quantity} +
+ ))} +
+
+ ) : ( + <> + )} ); }; diff --git a/src/style/order-list.css b/src/style/order-list.css index f43dc6a..ca3f1c3 100644 --- a/src/style/order-list.css +++ b/src/style/order-list.css @@ -1,3 +1,3 @@ .selected-line-order-protable { - background-color: #add8e6; -} \ No newline at end of file + background-color: #add8e6; +} diff --git a/src/utils/format.ts b/src/utils/format.ts index af4f65e..0363eda 100644 --- a/src/utils/format.ts +++ b/src/utils/format.ts @@ -95,8 +95,8 @@ export function formatUniuniShipmentState(state: string) { '230': 'RETURN TO SENDER WAREHOUSE', '231': 'FAILED_DELIVERY_RETRY1', '232': 'FAILED_DELIVERY_RETRY2', - '255': 'Gateway_To_Gateway_Transit' - } + '255': 'Gateway_To_Gateway_Transit', + }; if (state in UNIUNI_STATUS_ENUM) { return UNIUNI_STATUS_ENUM[state]; } else { diff --git a/src/utils/util.ts b/src/utils/util.ts index 5e7b0a2..a7736fc 100644 --- a/src/utils/util.ts +++ b/src/utils/util.ts @@ -23,4 +23,4 @@ export async function printPDF(urls: string[]) { } next(); -} \ No newline at end of file +}