Bladeren bron

docs: 经营驾驶舱设计(6 个 KPI + 趋势/排行/漏斗/结构)

liangzhao 2 weken geleden
bovenliggende
commit
ead0991fc1
1 gewijzigde bestanden met toevoegingen van 128 en 0 verwijderingen
  1. 128 0
      docs/superpowers/specs/2026-10-20-ops-cockpit-design.md

+ 128 - 0
docs/superpowers/specs/2026-10-20-ops-cockpit-design.md

@@ -0,0 +1,128 @@
+# 经营驾驶舱 · 设计文档
+
+- 日期:2026-10-20
+- 分支:`dev`
+- 状态:待评审
+- 范围:新增独立菜单「经营驾驶舱」,面向经营总览(不含履约、营销专块)
+
+## 1. 背景
+
+「店铺运营」现在是明细表 + 卡片,适合逐店核对,但不适合一眼看经营大盘。需要一屏看清:今天做了多少、比昨天好还是差、哪家店在拖后腿、转化在哪一环掉。
+
+数据源:上传的运营明细(平台导出全字段 + 人工统计表),已按「日期 + 门店」合并去重。
+
+## 2. 首屏内容
+
+```
+经营驾驶舱                         日期 [10.18] ~ [10.19]   学校 ▾   店铺 ▾
+┌──────────┬──────────┬──────────┬──────────┬───────────┬─────────┐
+│ 营业额    │ 有效订单  │ 客单价    │ 曝光人数  │ 进店转化率 │ 店铺评分 │
+│ 2,363.73 │    86    │  27.49   │  6,775   │   8.6%    │  4.62   │
+│ ↓ 7.2%   │  ↓12.8%  │  ↑ 6.5%  │  ↓16.1%  │  ↓0.4pp   │   —     │
+└──────────┴──────────┴──────────┴──────────┴───────────┴─────────┘
+┌────────────────────────────┬────────────────────────────┐
+│ 营业额 / 订单趋势(双轴)    │ 门店营业额 Top 10(横向条形) │
+├────────────────────────────┼────────────────────────────┤
+│ 转化漏斗 曝光→进店→下单      │ 收入结构:收入 / 支出 / 补贴  │
+└────────────────────────────┴────────────────────────────┘
+```
+
+## 3. 指标口径(实现必须统一,不允许前端各算各的)
+
+| 指标 | 口径 | 说明 |
+|---|---|---|
+| 营业额 | Σ 营业额 | 平台列「营业额」;人工表映射为 `revenue` |
+| 有效订单 | Σ 有效订单 | 整数 |
+| 客单价 | 营业额 ÷ 有效订单 | 订单为 0 时显示 `–` |
+| 曝光人数 | Σ 曝光人数 | |
+| 进店转化率 | Σ 进店人数 ÷ Σ 曝光人数 | **不是**各店转化率的算术平均 |
+| 店铺评分 | 评分 > 0 的门店取均值 | 未开业/无评分(0)不参与 |
+
+**环比**:所选区间 vs **紧邻的前一个等长区间**。
+
+- 金额/数量:(本期 − 上期) ÷ 上期 × 100%
+- 比率:本期 − 上期,单位 **pp**(百分点)
+- 上期为 0 或无数据:显示 `—`,不显示 ∞
+- 评分不做环比(评分是存量指标,短期对比意义不大)
+
+## 4. 四张图
+
+| 图 | 形式 | 数据 |
+|---|---|---|
+| 趋势 | 柱(营业额,左轴)+ 线(订单,右轴) | 按日聚合 |
+| 门店排行 | 横向条形 Top 10 | 所选区间营业额,带数值标签 |
+| 转化漏斗 | 漏斗图 | 曝光人数 → 进店人数 → 下单人数,标注各层转化率 |
+| 收入结构 | 堆叠柱 / 瀑布 | 收入、支出、活动补贴、商家活动成本(按日) |
+
+配色沿用现有主题:主色 `#ff6b35`,辅助灰 `#b8b2ad`,ECharts 已在仓库内。
+
+## 5. 交互
+
+- 顶部筛选:日期区间、学校多选、店铺多选(复用店铺运营的多选组件与状态)
+- 任一筛选变化 → 重新拉取聚合并重绘,KPI 与四张图同步
+- 图表点击:
+  - 门店排行点击某店 → 跳转「店铺运营」并预选该店(可选,二期)
+- 空态:无数据时显示「所选范围没有数据」+ 清空筛选按钮
+- 加载态:KPI 与图表显示骨架/占位,避免闪烁
+
+## 6. 接口
+
+新增 **`GET /api/ops/dashboard`**(服务端聚合,保证口径一致):
+
+```
+?from=20261018&to=20261019&schools=浙江工商大学桐庐校区&shops=537278859
+```
+
+响应:
+
+```json
+{
+  "from": "20261018", "to": "20261019",
+  "prev": { "from": "20261016", "to": "20261017" },
+  "kpis": {
+    "revenue":    { "value": 2363.73, "prev": 2544.1, "delta": -7.1, "unit": "money" },
+    "orders":     { "value": 86, "prev": 99, "delta": -13.1, "unit": "int" },
+    "avgTicket":  { "value": 27.49, "prev": 25.7, "delta": 7.0, "unit": "money" },
+    "exposure":   { "value": 6775, "prev": 8090, "delta": -16.3, "unit": "int" },
+    "conversion": { "value": 0.086, "prev": 0.09, "delta": -0.4, "unit": "pp" },
+    "rating":     { "value": 4.62, "prev": null, "delta": null, "unit": "num" }
+  },
+  "trend": [{ "date": "20261018", "revenue": 2363.73, "orders": 86 }],
+  "ranking": [{ "shopId": "...", "shopName": "...", "revenue": 750.7 }],
+  "funnel": { "exposure": 6775, "visit": 585, "order": 88 },
+  "structure": [{ "date": "20261018", "income": 2363.73, "expense": 747.46, "subsidy": 51.7 }]
+}
+```
+
+实现复用 `loadMergedRows()`(人工 + 平台合并),不动现有表结构。
+
+## 7. 页面
+
+- 菜单:经营分析组,新增「经营驾驶舱」,放在「店铺运营」之前
+- 视图标识 `cockpit`,`public/cockpit.js`,复用 `ops-multi` 组件样式
+- 图表用 ECharts(已有),自适应容器宽度,窗口 resize 重绘
+
+## 8. 边界
+
+| 场景 | 表现 |
+|---|---|
+| 无数据 | 空态提示 + 清空筛选 |
+| 只有 1 天数据 | 趋势图只有一根柱;环比显示 `—`(没有上期) |
+| 上期为 0 | 环比 `—`,不显示 ∞ |
+| 存储不可用 | 显示「数据暂不可用」+ 重试 |
+| 店铺/学校筛选为空 | 与店铺运营一致:提示至少选一个 |
+
+## 9. 测试
+
+- 单测:KPI 聚合(含 0 订单客单价、评分排除 0、转化率加权)、环比计算(正负、上期 0、无上期)
+- 接口:`/api/ops/dashboard` 空库 / 有数据 / 筛选组合
+- 冒烟:只读断言 `GET /api/ops/dashboard` 200
+- 手测:切日期、切学校、切店铺,KPI 与图表同步;窗口缩放不溢出
+
+## 10. 待办(评审通过后实施)
+
+- [ ] `GET /api/ops/dashboard` 聚合实现(复用 loadMergedRows)
+- [ ] 前端 `public/cockpit.js`:筛选、KPI 卡、趋势、排行、漏斗、结构图
+- [ ] `index.html` 菜单与视图骨架、`app.js` 注册、`style.css`
+- [ ] 测试脚本扩展 + smoke 断言
+- [ ] README 增补