diff --git a/.cursor/skills/assistant-doc-sync/sync-log.md b/.cursor/skills/assistant-doc-sync/sync-log.md index a623623..28f6602 100644 --- a/.cursor/skills/assistant-doc-sync/sync-log.md +++ b/.cursor/skills/assistant-doc-sync/sync-log.md @@ -6,6 +6,10 @@ --- +## 2026-04-28 + +- 玩值继续落地:wz-admin ScreenViewPage 接 GET /api/screen/data/dashboard(失败回退展示值),wanzhiAdmin.ts 新增 etchScreenDashboardStats;开发文档/玩值/进度-看板.md、2026-04-28-日志.md、项目索引玩值 已同步 + ## 2026-04-27 - 玩值三端迁移完成度会议:纪要 `meeting/2026-04-27_三端迁移完成度与文档同步.md`;`开发文档/玩值/进度-看板.md`、`三端对齐项目清单.md`、`2026-04-27-日志.md`;项目索引玩值、meeting README、团队+玩值三角色+开发助理 evolution;**结论**:新三端主迁移完成,与 old 全矩阵 1:1 为持续对齐 diff --git a/new/wz-admin/src/api/wanzhiAdmin.ts b/new/wz-admin/src/api/wanzhiAdmin.ts index 04a1baf..c687ed2 100644 --- a/new/wz-admin/src/api/wanzhiAdmin.ts +++ b/new/wz-admin/src/api/wanzhiAdmin.ts @@ -44,6 +44,17 @@ export type FinancePayload = { withdraws?: unknown[] } +export type ScreenDashboardStats = { + totalUsers?: number + totalStreamers?: number + totalOrders?: number + totalRevenue?: number + todayNewUsers?: number + todayOrders?: number + activeStreamers?: number + pendingPawns?: number +} + export async function fetchDashboard(): Promise { const r = await get>(`${WZ}/dashboard`) return r.success && r.data ? r.data : null @@ -208,6 +219,13 @@ export async function fetchPointCard(id: string): Promise { + const r = await get>('/api/screen/data/dashboard') + if (!r.success || !r.data || !r.data.stats) return null + return r.data.stats +} + /** GET /api/screen/config — 根级 JSON,无 success 包裹 */ export async function screenConfigGet(): Promise> { return get>('/api/screen/config') diff --git a/new/wz-admin/src/pages/ScreenViewPage.tsx b/new/wz-admin/src/pages/ScreenViewPage.tsx index e4d2d44..c088e64 100644 --- a/new/wz-admin/src/pages/ScreenViewPage.tsx +++ b/new/wz-admin/src/pages/ScreenViewPage.tsx @@ -1,20 +1,87 @@ -import type { ReactNode } from 'react' +import { useEffect, useMemo, useState, type ReactNode } from 'react' import { Link } from 'react-router-dom' import { TrendingUp, Users, Radio, Wallet, Activity } from 'lucide-react' import MockSparkline from '@/components/screen/MockSparkline' +import { fetchScreenDashboardStats, type ScreenDashboardStats } from '@/api/wanzhiAdmin' +import { adminUseApi } from '@/config/adminUseApi' + +const DEFAULT_STATS: Required = { + totalUsers: 460000, + totalStreamers: 201, + totalOrders: 12480, + totalRevenue: 4130000, + todayNewUsers: 126, + todayOrders: 92, + activeStreamers: 48, + pendingPawns: 17, +} /** * 玩值数据大屏视图:指标条 + 双折线区段参考 old `app/admin/screen/_components` 中 Dashboard/Growth 布局; * 完整地图/投资卡等仍保留在 old(依赖 Next dynamic、Leaflet、DashboardContext)。 */ export default function ScreenViewPage() { + const [stats, setStats] = useState>(DEFAULT_STATS) + const [loading, setLoading] = useState(adminUseApi()) + const [loadErr, setLoadErr] = useState(null) + + useEffect(() => { + if (!adminUseApi()) { + setLoading(false) + setLoadErr(null) + setStats(DEFAULT_STATS) + return + } + let mounted = true + const run = async () => { + setLoading(true) + setLoadErr(null) + try { + const data = await fetchScreenDashboardStats() + if (!mounted) return + if (!data) { + setLoadErr('大屏接口返回为空,已回退展示数据') + setStats(DEFAULT_STATS) + } else { + setStats({ + totalUsers: data.totalUsers ?? DEFAULT_STATS.totalUsers, + totalStreamers: data.totalStreamers ?? DEFAULT_STATS.totalStreamers, + totalOrders: data.totalOrders ?? DEFAULT_STATS.totalOrders, + totalRevenue: data.totalRevenue ?? DEFAULT_STATS.totalRevenue, + todayNewUsers: data.todayNewUsers ?? DEFAULT_STATS.todayNewUsers, + todayOrders: data.todayOrders ?? DEFAULT_STATS.todayOrders, + activeStreamers: data.activeStreamers ?? DEFAULT_STATS.activeStreamers, + pendingPawns: data.pendingPawns ?? DEFAULT_STATS.pendingPawns, + }) + } + } catch { + if (!mounted) return + setLoadErr('读取 /api/screen/data/dashboard 失败,已回退展示数据') + setStats(DEFAULT_STATS) + } finally { + if (mounted) setLoading(false) + } + } + void run() + return () => { + mounted = false + } + }, []) + + const monthGrowth = useMemo(() => { + if (!stats.totalUsers) return '0.0' + return ((stats.todayNewUsers / stats.totalUsers) * 100 * 30).toFixed(1) + }, [stats.todayNewUsers, stats.totalUsers]) + return ( -
-
+
+

玩值电竞 · 数据大屏

-

增量迁入:指标 + MockSparkline(old GrowthChart 概念)· 地图组件仍用 old 全量页

+

+ {adminUseApi() ? '已接 /api/screen/data/dashboard(失败自动回退)' : '本地展示模式(VITE_ADMIN_USE_API=false)'} · 地图组件仍用 old 全量页 +

- } label="私域粉丝(展示)" value="46.0 万" /> - } label="电竞明星" value="201" /> - } label="单用户价值(元)" value="413" /> - } label="环比增长(mock)" value="+6.7%" /> + } label="私域用户总量" value={num(stats.totalUsers)} /> + } label="电竞明星" value={num(stats.totalStreamers)} /> + } label="充值流水(元)" value={money(stats.totalRevenue)} /> + } label="月增估算(%)" value={`+${monthGrowth}`} /> +
+
+ {loading ? '正在加载大屏统计...' : loadErr ? loadErr : '统计数据来源:wz-api /api/screen/data/dashboard'}
- +
@@ -63,3 +152,11 @@ function Metric({ icon, label, value }: { icon: ReactNode; label: string; value:
) } + +function num(v: number): string { + return v.toLocaleString() +} + +function money(v: number): string { + return `¥${Math.round(v).toLocaleString()}` +}