Переглянути джерело

feat: admin business dashboard panel (orders/WAU/paid-rate/churn-rate)

- 新增 数据看板 tab:8 核心指标(注册/DAU/WAU/MAU/付费率/订单/GMV)
- 12 周 WAU 趋势柱状图 + 付费转化漏斗 + 指标明细表(退款率/退订率/留存/ARPU)
- 口径说明:预充值模式退订率=账号注销率
DoTouch Dev 2 тижнів тому
батько
коміт
9908382f0e

+ 2 - 2
.omo/run-continuation/ses_0229f653bffedHZYFR3ILxjlpg.json

@@ -1,10 +1,10 @@
 {
   "sessionID": "ses_0229f653bffedHZYFR3ILxjlpg",
-  "updatedAt": "2026-08-08T18:03:23.168Z",
+  "updatedAt": "2026-08-08T18:12:58.698Z",
   "sources": {
     "background-task": {
       "state": "idle",
-      "updatedAt": "2026-08-08T18:03:23.168Z"
+      "updatedAt": "2026-08-08T18:12:58.698Z"
     }
   }
 }

+ 3 - 0
apps/web/src/components/admin/AdminPanels.tsx

@@ -7,6 +7,7 @@ import { useAdminTab } from './AdminShell';
 import { ModelsPanel } from './panels/ModelsPanel';
 import { OrdersPanel } from './panels/OrdersPanel';
 import { OverviewPanel } from './panels/OverviewPanel';
+import { DashboardPanel } from './panels/DashboardPanel';
 import { QuotasPanel } from './panels/QuotasPanel';
 import { SettingsPanel } from './panels/SettingsPanel';
 import { UsersPanel } from './panels/UsersPanel';
@@ -15,6 +16,8 @@ export function AdminPanels() {
   const { tab } = useAdminTab();
 
   switch (tab) {
+    case 'dashboard':
+      return <DashboardPanel />;
     case 'users':
       return <UsersPanel />;
     case 'models':

+ 2 - 1
apps/web/src/components/admin/AdminShell.tsx

@@ -8,7 +8,7 @@ import Link from 'next/link';
 import { createContext, useContext, useState, type ReactNode } from 'react';
 import { BrandLogo } from '@/components/BrandLogo';
 
-export type AdminTab = 'overview' | 'users' | 'models' | 'orders' | 'quotas' | 'settings';
+export type AdminTab = 'overview' | 'dashboard' | 'users' | 'models' | 'orders' | 'quotas' | 'settings';
 
 type AdminTabContextValue = {
   tab: AdminTab;
@@ -26,6 +26,7 @@ export function useAdminTab(): AdminTabContextValue {
 // 侧边栏导航项(图标 + 标题 + 副标题)
 const NAV_ITEMS: ReadonlyArray<{ id: AdminTab; icon: string; title: string; sub: string }> = [
   { id: 'overview', icon: '📊', title: '运营概览', sub: 'DoTouch.AI 平台数据 · 2026-08-08' },
+  { id: 'dashboard', icon: '📈', title: '数据看板', sub: '业务与运营指标 · 订单/活跃/付费' },
   { id: 'users', icon: '👥', title: '用户管理', sub: '账号查询 · 封禁与提权' },
   { id: 'models', icon: '🧠', title: '模型管理', sub: '236 个上游模型 · 定价与上架' },
   { id: 'orders', icon: '💸', title: '交易流水', sub: '充值 · 用量扣费 · 退款' },

+ 162 - 0
apps/web/src/components/admin/panels/DashboardPanel.tsx

@@ -0,0 +1,162 @@
+/**
+ * 数据看板面板 - 业务与运营指标(订单 / 活跃 / 付费 / 留存)
+ * 静态演示数据:核心指标卡 + 12 周 WAU 趋势 + 转化漏斗 + 指标明细表
+ */
+'use client';
+
+import { Notice, SectionTitle } from '../ui';
+
+/** 核心指标(本周值 + 环比) */
+const kpis = [
+  { label: '注册用户', value: '1,284', delta: '+37', up: true },
+  { label: '日活 DAU', value: '186', delta: '+4.2%', up: true },
+  { label: '周活 WAU', value: '412', delta: '+6.8%', up: true },
+  { label: '月活 MAU', value: '893', delta: '+11.3%', up: true },
+  { label: '付费用户', value: '305', delta: '+21', up: true },
+  { label: '付费率', value: '23.8%', delta: '+1.6pp', up: true },
+  { label: '本周订单', value: '892', delta: '+9.4%', up: true },
+  { label: '本周 GMV', value: '$1,290', delta: '+12.1%', up: true },
+];
+
+/** 12 周 WAU 趋势(柱状图) */
+const wauBars = [
+  { label: 'W1', height: 42 },
+  { label: 'W2', height: 46 },
+  { label: 'W3', height: 45 },
+  { label: 'W4', height: 52 },
+  { label: 'W5', height: 50 },
+  { label: 'W6', height: 58 },
+  { label: 'W7', height: 55 },
+  { label: 'W8', height: 63 },
+  { label: 'W9', height: 61 },
+  { label: 'W10', height: 70 },
+  { label: 'W11', height: 68 },
+  { label: 'W12', height: 78 },
+];
+
+/** 转化漏斗:注册 → 充值 → 首次调用 → 周活跃 */
+const funnel = [
+  { label: '注册用户', value: '1,284', pct: 100, color: 'bg-brand-purple' },
+  { label: '完成充值', value: '486', pct: 38, color: 'bg-brand-purple' },
+  { label: '首次调用 API', value: '412', pct: 32, color: 'bg-brand-purple' },
+  { label: '本周活跃(WAU)', value: '412', pct: 32, color: 'bg-brand-green' },
+  { label: '复购用户(≥2 次充值)', value: '203', pct: 16, color: 'bg-brand-green' },
+];
+
+/** 指标明细(本周 vs 上周 + 环比) */
+const metricRows = [
+  { name: '新增注册', week: 37, last: 31, delta: '+19.4%', trend: 'up' },
+  { name: '新增付费用户', week: 21, last: 16, delta: '+31.3%', trend: 'up' },
+  { name: '客单价(ARPU/付费)', week: '$4.23', last: '$3.98', delta: '+6.3%', trend: 'up' },
+  { name: '订单数(充值笔数)', week: 892, last: 815, delta: '+9.4%', trend: 'up' },
+  { name: '退款率', week: '1.2%', last: '1.5%', delta: '-0.3pp', trend: 'down' },
+  { name: '退订率(账号注销)', week: '0.8%', last: '0.9%', delta: '-0.1pp', trend: 'down' },
+  { name: '30 日留存率', week: '34.2%', last: '31.8%', delta: '+2.4pp', trend: 'up' },
+  { name: '平均每日请求/活跃用户', week: '31.2', last: '29.4', delta: '+6.1%', trend: 'up' },
+];
+
+export function DashboardPanel() {
+  return (
+    <div>
+      {/* 核心指标卡 */}
+      <div className="grid gap-4 [grid-template-columns:repeat(auto-fit,minmax(190px,1fr))]">
+        {kpis.map((k) => (
+          <div key={k.label} className="rounded-[14px] border border-white/[0.08] bg-brand-card p-5">
+            <div className="text-xs text-brand-muted">{k.label}</div>
+            <div className="mt-1.5 text-[22px] font-extrabold">{k.value}</div>
+            <div className={`mt-1 text-[11.5px] ${k.up ? 'text-brand-green-l' : 'text-[#FF6B6B]'}`}>
+              {k.delta} 环比上周
+            </div>
+          </div>
+        ))}
+      </div>
+
+      {/* 12 周 WAU 趋势 */}
+      <SectionTitle>周活跃用户(WAU)趋势 · 近 12 周</SectionTitle>
+      <div className="rounded-[14px] border border-white/[0.08] bg-brand-card p-5">
+        <div className="flex h-[150px] items-end gap-2 px-2">
+          {wauBars.map((bar) => (
+            <div key={bar.label} className="flex flex-1 flex-col items-center gap-1.5">
+              <div
+                className="min-h-[6px] w-[70%] max-w-[34px] rounded-b-sm rounded-t-md bg-gradient-to-b from-brand-purple to-[rgba(124,92,255,.25)]"
+                style={{ height: `${bar.height}%` }}
+              />
+              <span className="text-[10.5px] text-brand-muted">{bar.label}</span>
+            </div>
+          ))}
+        </div>
+      </div>
+
+      {/* 转化漏斗 */}
+      <SectionTitle>付费转化漏斗(本月)</SectionTitle>
+      <div className="rounded-[14px] border border-white/[0.08] bg-brand-card p-5">
+        <div className="flex flex-col gap-2.5">
+          {funnel.map((f) => (
+            <div key={f.label} className="flex items-center gap-3">
+              <div className="w-32 shrink-0 text-[12.5px] text-brand-muted">{f.label}</div>
+              <div className="h-7 flex-1 overflow-hidden rounded-md bg-brand-card2">
+                <div
+                  className={`flex h-full items-center rounded-md px-2 text-[12px] font-semibold text-brand-text ${f.color}`}
+                  style={{ width: `${f.pct}%` }}
+                >
+                  {f.value}
+                </div>
+              </div>
+              <div className="w-11 shrink-0 text-right text-[11.5px] text-brand-muted">
+                {f.pct}%
+              </div>
+            </div>
+          ))}
+        </div>
+      </div>
+
+      {/* 指标明细表 */}
+      <SectionTitle>运营指标明细 · 本周 vs 上周</SectionTitle>
+      <div className="overflow-x-auto rounded-[14px] border border-white/[0.08] bg-brand-card">
+        <table className="w-full min-w-[640px] border-collapse">
+          <thead>
+            <tr>
+              {['指标', '本周', '上周', '环比', '趋势'].map((h) => (
+                <th
+                  key={h}
+                  className="whitespace-nowrap bg-[rgba(124,92,255,.12)] px-4 py-[13px] text-left text-[12.5px] tracking-[0.4px] text-brand-purple-l"
+                >
+                  {h}
+                </th>
+              ))}
+            </tr>
+          </thead>
+          <tbody>
+            {metricRows.map((row) => (
+              <tr key={row.name} className="group">
+                <td className="border-t border-white/[0.08] px-4 py-[13px] text-sm font-semibold">
+                  {row.name}
+                </td>
+                <td className="border-t border-white/[0.08] px-4 py-[13px] font-mono text-[13px]">
+                  {row.week}
+                </td>
+                <td className="border-t border-white/[0.08] px-4 py-[13px] font-mono text-[13px] text-brand-muted">
+                  {row.last}
+                </td>
+                <td className="border-t border-white/[0.08] px-4 py-[13px] font-mono text-[13px]">
+                  {row.delta}
+                </td>
+                <td className="border-t border-white/[0.08] px-4 py-[13px] text-[13px]">
+                  {row.trend === 'up' ? (
+                    <span className="text-brand-green-l">▲ 上升</span>
+                  ) : (
+                    <span className="text-[#5FF5C3]">▼ 下降(向好)</span>
+                  )}
+                </td>
+              </tr>
+            ))}
+          </tbody>
+        </table>
+      </div>
+
+      <Notice className="mt-4">
+        📌 口径说明:当前为「仅预充值」模式(无订阅),「退订率」按账号注销率计;「退款率」为充值订单退款占比。订阅模式上线后新增退订统计。
+      </Notice>
+    </div>
+  );
+}

Різницю між файлами не показано, бо вона завелика
+ 0 - 0
apps/web/tsconfig.tsbuildinfo


Деякі файли не було показано, через те що забагато файлів було змінено