From 32e275915167a96fb2e5c1078748ead227355239 Mon Sep 17 00:00:00 2001 From: zhuotianyuan Date: Tue, 30 Dec 2025 10:34:45 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=9B=B4=E6=96=B0=E8=AE=A2=E5=8D=95?= =?UTF-8?q?=E7=BB=9F=E8=AE=A1=E5=8A=9F=E8=83=BD=E5=92=8C=E7=9B=B8=E5=85=B3?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B=E5=AE=9A=E4=B9=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/Order/List/index.tsx | 33 +++-- src/pages/Statistics/Order/index.tsx | 30 +++- src/pages/Statistics/OrderSource/index.tsx | 23 ++- src/servers/api/typings.d.ts | 160 +++++++++++++++++++++ 4 files changed, 228 insertions(+), 18 deletions(-) diff --git a/src/pages/Order/List/index.tsx b/src/pages/Order/List/index.tsx index 277c55d..187f1cb 100644 --- a/src/pages/Order/List/index.tsx +++ b/src/pages/Order/List/index.tsx @@ -73,6 +73,7 @@ import { Tag, } from 'antd'; import React, { useMemo, useRef, useState } from 'react'; +import { request, useParams } from '@umijs/max'; import RelatedOrders from '../../Subscription/Orders/RelatedOrders'; const ListPage: React.FC = () => { @@ -490,19 +491,29 @@ const ListPage: React.FC = () => { // > // 批量导出 // , - { + console.log(selectedRowKeys); try { - const { success, message: errMsg } = - await ordercontrollerExportorder({ + const res = await request('/order/order/export', { + method: 'GET', + params: { ids: selectedRowKeys, - }); - if (!success) { - throw new Error(errMsg); + } + }); + if (res?.success && res?.data?.csv) { + const blob = new Blob([res.data.csv], { type: 'text/csv;charset=utf-8;' }); + const url = URL.createObjectURL(blob); + const a = document.createElement('a'); + a.href = url; + a.download = 'customers.csv'; + a.click(); + URL.revokeObjectURL(url); + } else { + message.error(res.message || '导出失败'); } - message.success('导出成功'); actionRef.current?.reload(); setSelectedRowKeys([]); } catch (error: any) { @@ -510,14 +521,10 @@ const ListPage: React.FC = () => { } }} > - - , + ]} request={async ({ date, ...param }: any) => { if (param.status === 'all') { diff --git a/src/pages/Statistics/Order/index.tsx b/src/pages/Statistics/Order/index.tsx index 8147e70..7190b67 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')); @@ -128,8 +130,22 @@ const ListPage: React.FC = () => { }); if (success) { const res = data?.sort(() => -1); - setXAxis(res?.map((v) => dayjs(v.order_date).format('YYYY-MM-DD'))); - setSeries([ + 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订单数', type: 'line', @@ -583,6 +599,16 @@ const ListPage: React.FC = () => { name="date" /> {/* */} + { data: data?.inactiveRes?.map((v) => v.new_user_count)?.sort((_) => -1), label: { show: true, + formatter: function (params) { + if (!params.value) return ''; + return Math.abs(params.value) + +'\n' + +Math.abs(data?.inactiveRes?.find((item) => item.order_month === params.name)?.new_user_total || 0); + }, + color: '#000000', }, emphasis: { focus: 'series', @@ -52,6 +59,13 @@ const ListPage: React.FC = () => { data: data?.inactiveRes?.map((v) => v.old_user_count)?.sort((_) => -1), label: { show: true, + formatter: function (params) { + if (!params.value) return ''; + return Math.abs(params.value) + +'\n' + +Math.abs(data?.inactiveRes?.find((item) => item.order_month === params.name)?.old_user_total || 0); + }, + color: '#000000', }, emphasis: { focus: 'series', @@ -69,9 +83,12 @@ const ListPage: React.FC = () => { show: true, formatter: function (params) { if (!params.value) return ''; - return Math.abs(params.value); - }, - color: '#fff', + return Math.abs(params.value) + +'\n'+ + +Math.abs(data?.res?.find((item) => item.order_month === params.name && + item.first_order_month_group === v)?.total || 0); + }, + color: '#000000', }, data: xAxisData.map((month) => { return ( diff --git a/src/servers/api/typings.d.ts b/src/servers/api/typings.d.ts index 45fdbd5..e60d33a 100644 --- a/src/servers/api/typings.d.ts +++ b/src/servers/api/typings.d.ts @@ -854,6 +854,7 @@ declare namespace API { purchaseType?: 'all' | 'first_purchase' | 'repeat_purchase'; orderType?: 'all' | 'cpc' | 'non_cpc'; brand?: 'all' | 'zyn' | 'yoone' | 'zolt'; + grouping?: 'day' | 'week' | 'month'; }; type OrderStatusCountDTO = { @@ -1573,6 +1574,10 @@ declare namespace API { search?: string; /** 过滤条件对象 */ where?: Record; + /** 创建时间后 */ + after?: string; + /** 创建时间前 */ + before?: string; /** 排序对象,例如 { "sku": "desc" } */ orderBy?: Record; siteId: number; @@ -1587,6 +1592,10 @@ declare namespace API { search?: string; /** 过滤条件对象 */ where?: Record; + /** 创建时间后 */ + after?: string; + /** 创建时间前 */ + before?: string; /** 排序对象,例如 { "sku": "desc" } */ orderBy?: Record; siteId: number; @@ -1601,6 +1610,10 @@ declare namespace API { search?: string; /** 过滤条件对象 */ where?: Record; + /** 创建时间后 */ + after?: string; + /** 创建时间前 */ + before?: string; /** 排序对象,例如 { "sku": "desc" } */ orderBy?: Record; siteId: number; @@ -1615,6 +1628,10 @@ declare namespace API { search?: string; /** 过滤条件对象 */ where?: Record; + /** 创建时间后 */ + after?: string; + /** 创建时间前 */ + before?: string; /** 排序对象,例如 { "sku": "desc" } */ orderBy?: Record; siteId: number; @@ -1629,6 +1646,10 @@ declare namespace API { search?: string; /** 过滤条件对象 */ where?: Record; + /** 创建时间后 */ + after?: string; + /** 创建时间前 */ + before?: string; /** 排序对象,例如 { "sku": "desc" } */ orderBy?: Record; siteId: number; @@ -1643,6 +1664,10 @@ declare namespace API { search?: string; /** 过滤条件对象 */ where?: Record; + /** 创建时间后 */ + after?: string; + /** 创建时间前 */ + before?: string; /** 排序对象,例如 { "sku": "desc" } */ orderBy?: Record; siteId: number; @@ -1657,6 +1682,10 @@ declare namespace API { search?: string; /** 过滤条件对象 */ where?: Record; + /** 创建时间后 */ + after?: string; + /** 创建时间前 */ + before?: string; /** 排序对象,例如 { "sku": "desc" } */ orderBy?: Record; customerId: number; @@ -1677,6 +1706,10 @@ declare namespace API { search?: string; /** 过滤条件对象 */ where?: Record; + /** 创建时间后 */ + after?: string; + /** 创建时间前 */ + before?: string; /** 排序对象,例如 { "sku": "desc" } */ orderBy?: Record; siteId: number; @@ -1695,6 +1728,10 @@ declare namespace API { search?: string; /** 过滤条件对象 */ where?: Record; + /** 创建时间后 */ + after?: string; + /** 创建时间前 */ + before?: string; /** 排序对象,例如 { "sku": "desc" } */ orderBy?: Record; siteId: number; @@ -1719,6 +1756,10 @@ declare namespace API { search?: string; /** 过滤条件对象 */ where?: Record; + /** 创建时间后 */ + after?: string; + /** 创建时间前 */ + before?: string; /** 排序对象,例如 { "sku": "desc" } */ orderBy?: Record; siteId: number; @@ -1738,6 +1779,10 @@ declare namespace API { search?: string; /** 过滤条件对象 */ where?: Record; + /** 创建时间后 */ + after?: string; + /** 创建时间前 */ + before?: string; /** 排序对象,例如 { "sku": "desc" } */ orderBy?: Record; siteId: number; @@ -1752,6 +1797,10 @@ declare namespace API { search?: string; /** 过滤条件对象 */ where?: Record; + /** 创建时间后 */ + after?: string; + /** 创建时间前 */ + before?: string; /** 排序对象,例如 { "sku": "desc" } */ orderBy?: Record; siteId: number; @@ -1766,6 +1815,10 @@ declare namespace API { search?: string; /** 过滤条件对象 */ where?: Record; + /** 创建时间后 */ + after?: string; + /** 创建时间前 */ + before?: string; /** 排序对象,例如 { "sku": "desc" } */ orderBy?: Record; siteId: number; @@ -1785,6 +1838,10 @@ declare namespace API { search?: string; /** 过滤条件对象 */ where?: Record; + /** 创建时间后 */ + after?: string; + /** 创建时间前 */ + before?: string; /** 排序对象,例如 { "sku": "desc" } */ orderBy?: Record; siteId: number; @@ -2239,6 +2296,8 @@ declare namespace API { email?: string; /** 电话 */ phone?: string; + /** 配送方式 */ + method_title?: string; }; type UnifiedCategoryDTO = { @@ -2248,6 +2307,19 @@ declare namespace API { name?: string; }; + type UnifiedCouponLineDTO = { + /** 优惠券项ID */ + id?: Record; + /** 优惠券项代码 */ + code?: string; + /** 优惠券项折扣 */ + discount?: string; + /** 优惠券项税额 */ + discount_tax?: string; + /** 优惠券项元数据 */ + meta_data?: any; + }; + type UnifiedCustomerDTO = { /** 客户ID */ id?: Record; @@ -2292,6 +2364,29 @@ declare namespace API { per_page?: number; /** 总页数 */ totalPages?: number; + /** 分页后的数据 */ + after?: string; + /** 分页前的数据 */ + before?: string; + }; + + type UnifiedFeeLineDTO = { + /** 费用项ID */ + id?: Record; + /** 费用项名称 */ + name?: string; + /** 税率类 */ + tax_class?: string; + /** 税率状态 */ + tax_status?: string; + /** 总金额 */ + total?: string; + /** 总税额 */ + total_tax?: string; + /** 税额详情 */ + taxes?: any; + /** 元数据 */ + meta_data?: any; }; type UnifiedImageDTO = { @@ -2333,6 +2428,10 @@ declare namespace API { per_page?: number; /** 总页数 */ totalPages?: number; + /** 分页后的数据 */ + after?: string; + /** 分页前的数据 */ + before?: string; }; type UnifiedOrderDTO = { @@ -2344,6 +2443,8 @@ declare namespace API { status?: string; /** 货币 */ currency?: string; + /** 货币符号 */ + currency_symbol?: string; /** 总金额 */ total?: string; /** 客户ID */ @@ -2352,6 +2453,8 @@ declare namespace API { customer_name?: string; /** 客户邮箱 */ email?: string; + /** 客户邮箱 */ + customer_email?: string; /** 订单项(具体的商品) */ line_items?: UnifiedOrderLineItemDTO[]; /** 销售项(兼容前端) */ @@ -2372,6 +2475,22 @@ declare namespace API { date_modified?: string; /** 原始数据 */ raw?: Record; + /** 配送方式 */ + shipping_lines?: UnifiedShippingLineDTO[]; + /** 费用项 */ + fee_lines?: UnifiedFeeLineDTO[]; + /** 优惠券项 */ + coupon_lines?: UnifiedCouponLineDTO[]; + /** 支付时间 */ + date_paid?: string; + /** 客户IP地址 */ + customer_ip_address?: string; + /** UTM来源 */ + utm_source?: string; + /** 设备类型 */ + device_type?: string; + /** 来源类型 */ + source_type?: string; }; type UnifiedOrderLineItemDTO = { @@ -2402,6 +2521,10 @@ declare namespace API { per_page?: number; /** 总页数 */ totalPages?: number; + /** 分页后的数据 */ + after?: string; + /** 分页前的数据 */ + before?: string; }; type UnifiedPaginationDTO = { @@ -2415,6 +2538,10 @@ declare namespace API { per_page?: number; /** 总页数 */ totalPages?: number; + /** 分页后的数据 */ + after?: string; + /** 分页前的数据 */ + before?: string; }; type UnifiedProductAttributeDTO = { @@ -2486,6 +2613,10 @@ declare namespace API { per_page?: number; /** 总页数 */ totalPages?: number; + /** 分页后的数据 */ + after?: string; + /** 分页前的数据 */ + before?: string; }; type UnifiedProductVariationDTO = { @@ -2541,6 +2672,10 @@ declare namespace API { per_page?: number; /** 总页数 */ totalPages?: number; + /** 分页后的数据 */ + after?: string; + /** 分页前的数据 */ + before?: string; }; type UnifiedSearchParamsDTO = { @@ -2552,10 +2687,31 @@ declare namespace API { search?: string; /** 过滤条件对象 */ where?: Record; + /** 创建时间后 */ + after?: string; + /** 创建时间前 */ + before?: string; /** 排序对象,例如 { "sku": "desc" } */ orderBy?: Record; }; + type UnifiedShippingLineDTO = { + /** 配送方式ID */ + id?: Record; + /** 配送方式名称 */ + method_title?: string; + /** 配送方式实例ID */ + method_id?: string; + /** 配送方式金额 */ + total?: string; + /** 配送方式税额 */ + total_tax?: string; + /** 配送方式税额详情 */ + taxes?: any; + /** 配送方式元数据 */ + meta_data?: any; + }; + type UnifiedSubscriptionDTO = { /** 订阅ID */ id?: Record; @@ -2592,6 +2748,10 @@ declare namespace API { per_page?: number; /** 总页数 */ totalPages?: number; + /** 分页后的数据 */ + after?: string; + /** 分页前的数据 */ + before?: string; }; type UnifiedTagDTO = {