From 700c4e3128600b2aa1d6a3e0baea4c53bc709ece Mon Sep 17 00:00:00 2001 From: linkeyu <798648091@qq.com> Date: Tue, 21 Jul 2026 15:44:08 +0800 Subject: [PATCH 1/3] =?UTF-8?q?feat(admin):=20=E9=A2=86=E5=88=B8=E6=98=8E?= =?UTF-8?q?=E7=BB=86=E5=B1=95=E7=A4=BA=E7=82=B9=E4=BD=8D=E5=88=86=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/(main)/coupon-data/page.tsx | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/app/(main)/coupon-data/page.tsx b/src/app/(main)/coupon-data/page.tsx index 3f0a696..362f76a 100644 --- a/src/app/(main)/coupon-data/page.tsx +++ b/src/app/(main)/coupon-data/page.tsx @@ -72,6 +72,8 @@ interface CouponDataRow { app_env: string | null; started_at: string; claimed_count: number | null; + point_success_count: number | null; + point_total_count: number | null; trace_url: string | null; ad_revenue_yuan: number | null; // 本次领券看的信息流广告预估收益(元);未填充为 null } @@ -495,17 +497,16 @@ export default function CouponDataPage() { title: '点位成功率', key: 'point_success_rate', width: 110, - render: (_: unknown, r: CouponDataRow) => ( - - {r.trace_url ? ( - - 查看明细 - - ) : ( - 待埋点 - )} - - ), + render: (_: unknown, r: CouponDataRow) => { + if (r.point_success_count == null || r.point_total_count == null || r.point_total_count <= 0) { + return -; + } + return ( + + {r.point_success_count}/{r.point_total_count} + + ); + }, }, { title: '广告收益', -- 2.52.0 From fd9c685723a8052c285666ca48383e2a6f82438f Mon Sep 17 00:00:00 2001 From: linkeyu <798648091@qq.com> Date: Tue, 21 Jul 2026 15:52:23 +0800 Subject: [PATCH 2/3] =?UTF-8?q?feat(admin):=20=E7=82=B9=E4=BD=8D=E5=88=86?= =?UTF-8?q?=E6=95=B0=E6=94=AF=E6=8C=81=E6=9F=A5=E7=9C=8B=E6=98=8E=E7=BB=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/(main)/coupon-data/page.tsx | 59 +++++++++++++++++++++++++++-- 1 file changed, 56 insertions(+), 3 deletions(-) diff --git a/src/app/(main)/coupon-data/page.tsx b/src/app/(main)/coupon-data/page.tsx index 362f76a..a3b3cb3 100644 --- a/src/app/(main)/coupon-data/page.tsx +++ b/src/app/(main)/coupon-data/page.tsx @@ -10,6 +10,7 @@ import { DatePicker, Divider, Input, + Popover, Row, Select, Space, @@ -74,6 +75,12 @@ interface CouponDataRow { claimed_count: number | null; point_success_count: number | null; point_total_count: number | null; + point_details: Array<{ + coupon_id: string; + coupon_name: string | null; + status: string; + reason: string | null; + }>; trace_url: string | null; ad_revenue_yuan: number | null; // 本次领券看的信息流广告预估收益(元);未填充为 null } @@ -118,6 +125,13 @@ const STATUS_TAG: Record = { abandoned: { color: 'orange', label: '中途退出' }, }; +const POINT_STATUS_TAG: Record = { + success: { color: 'success', label: '成功' }, + already_claimed: { color: 'processing', label: '已领' }, + failed: { color: 'error', label: '失败' }, + skipped: { color: 'default', label: '跳过' }, +}; + // ms → "1.5s"(空值显示 -) const fmtSec = (ms: number | null | undefined): string => ms == null ? '-' : `${(ms / 1000).toFixed(1)}s`; @@ -501,10 +515,49 @@ export default function CouponDataPage() { if (r.point_success_count == null || r.point_total_count == null || r.point_total_count <= 0) { return -; } + const score = `${r.point_success_count}/${r.point_total_count}`; + const details = r.point_details ?? []; return ( - - {r.point_success_count}/{r.point_total_count} - + + {details.length > 0 ? details.map((point, index) => { + const status = POINT_STATUS_TAG[point.status] ?? { + color: 'default', label: point.status, + }; + return ( +
+
+
+ {point.coupon_name || point.coupon_id} + {point.coupon_name ? ( +
{point.coupon_id}
+ ) : null} +
+ {status.label} +
+ {point.reason ? ( +
+ 原因:{point.reason} +
+ ) : null} +
+ ); + }) : 暂无点位明细} + + )} + > + +
); }, }, -- 2.52.0 From e47763375afbfb57981add9ab00f433fd05310ff Mon Sep 17 00:00:00 2001 From: linkeyu <798648091@qq.com> Date: Wed, 22 Jul 2026 11:20:59 +0800 Subject: [PATCH 3/3] =?UTF-8?q?perf(admin):=20=E7=82=B9=E5=87=BB=E5=90=8E?= =?UTF-8?q?=E5=8A=A0=E8=BD=BD=E9=A2=86=E5=88=B8=E7=82=B9=E4=BD=8D=E6=98=8E?= =?UTF-8?q?=E7=BB=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/(main)/coupon-data/page.tsx | 150 ++++++++++++++++++---------- 1 file changed, 95 insertions(+), 55 deletions(-) diff --git a/src/app/(main)/coupon-data/page.tsx b/src/app/(main)/coupon-data/page.tsx index a3b3cb3..f7c339c 100644 --- a/src/app/(main)/coupon-data/page.tsx +++ b/src/app/(main)/coupon-data/page.tsx @@ -14,6 +14,7 @@ import { Row, Select, Space, + Spin, Statistic, Table, Tag, @@ -75,15 +76,21 @@ interface CouponDataRow { claimed_count: number | null; point_success_count: number | null; point_total_count: number | null; - point_details: Array<{ - coupon_id: string; - coupon_name: string | null; - status: string; - reason: string | null; - }>; + // 兼容旧后端的内嵌明细;新后端不再返回,改为点击后按 trace 加载。 + point_details?: CouponPointDetail[]; trace_url: string | null; ad_revenue_yuan: number | null; // 本次领券看的信息流广告预估收益(元);未填充为 null } +interface CouponPointDetail { + coupon_id: string; + coupon_name: string | null; + status: string; + reason: string | null; +} +interface CouponPointDetailsOut { + trace_id: string; + items: CouponPointDetail[]; +} interface CouponDataReport { date_from: string; date_to: string; @@ -132,6 +139,87 @@ const POINT_STATUS_TAG: Record = { skipped: { color: 'default', label: '跳过' }, }; +function PointScorePopover({ row }: { row: CouponDataRow }) { + const { message } = App.useApp(); + const [details, setDetails] = useState(row.point_details ?? null); + const [loading, setLoading] = useState(false); + const [loadError, setLoadError] = useState(null); + + if (row.point_success_count == null || row.point_total_count == null || row.point_total_count <= 0) { + return -; + } + const score = `${row.point_success_count}/${row.point_total_count}`; + const loadDetails = async () => { + if (details !== null || loading) return; + setLoading(true); + setLoadError(null); + try { + const response = await api.get('/admin/api/coupon-data/point-details', { + params: { trace_id: row.trace_id }, + }); + setDetails(response.data.items); + } catch (error) { + const errorMessage = errMsg(error); + setLoadError(errorMessage); + message.error(errorMessage); + } finally { + setLoading(false); + } + }; + + return ( + { + if (open) void loadDetails(); + }} + content={( +
+ {loading || (details === null && loadError === null) ? ( + + ) : loadError ? ( + 明细加载失败,请关闭后重试 + ) : details && details.length > 0 ? details.map((point, index) => { + const status = POINT_STATUS_TAG[point.status] ?? { + color: 'default', label: point.status, + }; + return ( +
+
+
+ {point.coupon_name || point.coupon_id} + {point.coupon_name ? ( +
{point.coupon_id}
+ ) : null} +
+ {status.label} +
+ {point.reason ? ( +
+ 原因:{point.reason} +
+ ) : null} +
+ ); + }) : ( + 暂无点位明细 + )} +
+ )} + > + +
+ ); +} + // ms → "1.5s"(空值显示 -) const fmtSec = (ms: number | null | undefined): string => ms == null ? '-' : `${(ms / 1000).toFixed(1)}s`; @@ -511,55 +599,7 @@ export default function CouponDataPage() { title: '点位成功率', key: 'point_success_rate', width: 110, - render: (_: unknown, r: CouponDataRow) => { - if (r.point_success_count == null || r.point_total_count == null || r.point_total_count <= 0) { - return -; - } - const score = `${r.point_success_count}/${r.point_total_count}`; - const details = r.point_details ?? []; - return ( - - {details.length > 0 ? details.map((point, index) => { - const status = POINT_STATUS_TAG[point.status] ?? { - color: 'default', label: point.status, - }; - return ( -
-
-
- {point.coupon_name || point.coupon_id} - {point.coupon_name ? ( -
{point.coupon_id}
- ) : null} -
- {status.label} -
- {point.reason ? ( -
- 原因:{point.reason} -
- ) : null} -
- ); - }) : 暂无点位明细} - - )} - > - -
- ); - }, + render: (_: unknown, r: CouponDataRow) => , }, { title: '广告收益', -- 2.52.0