交付出件箱

← 返回出件箱

⚠️ 已被 v1.2 取代 —— 现行正本是 dual-cockpit-proposal-v1.2-20260819.md(v1.2 是在本文上做增量,本文各节仍然有效,可当详档查阅)。

双驾驶舱建设方案 v1.1 · A 展示屏 + B 管控屏

2026-08-19 · 在 v1.0(08-18)基础上补齐 5 个缺口,取代 v1.0,读这一份即可
沿用 08-15 调研定稿的 9 条口径规则与四大缺口结论,不新增任何统计口径
本版为纯文档,零代码改动;所有代码事实均本轮重新 grep 实证(证据见第二节)


〇、结论速览

结论:v1.0 定的方向全部成立,本版把 5 个"只给了一句话"的地方落成了可执行的表;最重要的一条是——A屏光点的数据链路本轮已逐段 grep 走通,从"等摸底才知道行不行"变成"代码层确定可行,摸底只是复核数量"。

# v1.0 的状态 v1.1 做了什么
1 A屏光点改用登录 IP,但"IP 从哪来"只有一句话 补第二节:五段链路逐段 grep 实证到 file:line,并挖出 5 条 v1.0 没写的硬约束
2 B屏"沿用 08-15 十二模块,不重复展开" 补第三节:12 模块 × 两屏 × 三层级 完整落位表
3 联动下钻——08-15 调研就标了"缺系统章节" 补第四节:下钻规则表(选中态、回退、跨模块联动)
4 "一套 API 两张皮"只有一句约定 补第五节:8 个接口清单(口径出处 + 刷新频率 + 两屏取数差异)
5 摸底 SQL 沿用 08-14 的 10 段 补第六节:按 D7 修订——1 段降级、1 段升级、新增 1 段直接产出 A屏地图长什么样
6 验收只有"性能三原则" 补第七节:11 项可执行验收清单

唯一仍卡住的事没变:摸底 SQL 要有生产库权限的同事跑,云机不连生产库。


一、现状盘点(08-19 接手时)

交付物 文件 状态
调研定稿(12 模块·九章) cockpit-research-20260815.md ✅ 正本,未动
单屏原型图 cockpit-mockup-20260815.html ✅ 08-18 真渲染修瑕全绿
A屏科技风原型 cockpit-a-mockup-20260818.html ✅ 已出,等长官看图
B屏深色管控原型 cockpit-b-mockup-20260818.html ✅ 已出,等长官看图
双屏方案 v1.0 dual-cockpit-proposal-20260818.md 🔄 被本版取代
摸底 SQL geo-cockpit-baseline-sql-20260814.md ⏸ 仍无人执行(08-14 至今)
双屏方案 v1.1 本文件 ✅ 本轮产出

二、A屏光点数据链路 · 本轮 grep 实证(v1.1 最大增量)

结论:链路五段全部走通,全是现成字段、零补录;生产反代的真实 IP 透传在代码层已经开着,v1.0 列为头号风险的"IP 全落内网"在代码层不成立。

2.1 五段链路(每段带物理出处)

# 环节 物理证据 结论
1 登录事件落表 app/models/audit.py:23 AuthAuditLog → 表 auth_audit_logs;event_type 有 CHECK 约束,5 类含 login_success ✅ 有事实表
2 事件带 IP app/models/audit.py:37 ip = Column(INET, nullable=True);login_attempts 同款 :74 ✅ 有 IP 列,但可空
3 机构端登录也落这张表 app/api/seat_auth.py:173 调 auth_service._write_audit(...);写入体 app/services/auth_service.py:498 ✅ 席位登录进审计(不只平台账号)
4 事件能映射到机构 auth_audit_logs.user_id → app/models/user.py:58 linked_org_id;CHECK 约束 user.py:142 强制 role='org_seat' 必有 linked_org_id(org_admin 见 :140,渠道 channel_id 见 :143) ✅ 机构/渠道归属确定,无需补录
5 IP 是真实公网 IP 取值 app/api/seat_auth.py:135 用 request.client.host;生产 uvicorn 带 --proxy-headers --forwarded-allow-ips *(deploy/Dockerfile.api:67),nginx 设 XFF(deploy/nginx/chat.tongban.love.conf:108-109);生产 compose 用的正是这份(deploy/docker-compose.prod.yml:78) ✅ 透传链路成立
— 落省份 ip2region 离线库 XdbSearchIP,云机实测 1.55ms/8 次 ✅ 现成

基线说明:以上行号取自本 worktree HEAD 8f92bd1b(2026-08-12),该分支落后 origin/test 641 个提交,行号在 test 上可能漂移,符号名不会。

2.2 本轮挖出的 5 条硬约束(v1.0 完全没写)

# 约束 物理证据 对大屏的影响
1 审计日志只留 6 个月,APScheduler 每天 02:00 清 app/models/audit.py:24 光点/登录趋势回溯窗口上限 6 个月;跨年同比不能靠这张表,得走结算域订单数据
2 审计写入是 best-effort,异常被 except 吞掉只打 warning app/services/auth_service.py:508-509 🔴 审计表的登录条数不是权威计数。KPI「今日活跃」必须走现有活跃口径(app/api/admin_activity.py,三源=seat_activity_log+auth_audit_logs,见 :4 文件头),不许大屏自己 COUNT 审计表——否则两处数字对不上
3 ip 列 nullable app/models/audit.py:37 光点必须显式处理 NULL:不画、且在"未定位"计数里体现(沿用已定规则第 6 条"未定位机构必须上屏")
4 事件类型无 logout app/models/audit.py:47-49 CHECK 只 5 类 印证 08-15「无在线状态」结论:在线人数做不了,只能做活跃四级
5 🔴 结算域审计表 audit_logs 生产账号只有 INSERT,没有 SELECT settlement/db/grants.sql:48 GRANT INSERT ON audit_logs TO settlement_rw;(:59-60 明确不转属主) B屏若要展示"谁处置了什么"的操作留痕,现在读不出来——需要单独开只读账号或视图。这是 v1.0 漏掉的工程前提,建议列为 D8 待拍板

2.3 结论调整

v1.0 的说法 v1.1 修正
§七「登录 IP 内网占比高 → 先修部署配置再上光点」是并列风险之一 代码+部署配置层已透传,这条从"待验风险"降为"跑数复核";仍要跑 SQL【2】,因为配置文件对 ≠ 生产实际生效(可能存在多层反代)
A屏 KPI「今日活跃」数据来源写「模块1 顶部指标子集」 明确=复用 admin_activity.py 现有口径,不自算(见约束 2)

三、12 模块 × 两屏 × 三层级 落位总表

结论:A屏只承载 12 模块中的 5 个(且都是"数字/形状"层),B屏 12 模块一个不少;差异全在"信息是否点名到人"。

# 模块(08-15 定稿原名) A屏 B屏地图/侧栏 B屏下钻面板 说明
1 顶部核心指标(6 项) ✅ 取 4 项做超大 KPI ✅ 6 项全留 — A屏取:在营机构/生效席位/今日活跃/本期续费完成率
2 中央地图(三层信息) ✅ 热力+光点,无标注无点色 ✅ 省级色块,点省份下钻 — D7 已定不采集坐标 → 两屏均无机构点位
3 渠道产能榜(TOP10) ✅ 降为 TOP5,轮播卡·左 ✅ TOP10 全留 — A屏三维度自动轮换,B屏手动切
4 审批实时列表 ❌ 不上屏 ✅ ✅ 名单+处置 含机构名,A屏脱敏原则排除
5 月度业务曲线(近 12 月·三线) ✅ 轮播卡·左(与模块3 交替) ✅ —
6 续费预警列表 ⚠️ 只给计数,轮播卡·右 ✅ 完整名单 ✅ 该机构席位批次明细 A屏永不出名单(D5 开关控制是否连计数也隐藏)
7 异常告警列表 ⚠️ 同上,异常数>0 红闪 ✅ ✅ 同上
8 席位增购排行榜 ❌ ✅ 右侧切换区 —
9 续费周期甘特图 ❌ ✅ 右侧切换区 ✅ 单机构甘特 echarts CustomChart
10 未来 12 个月到期分布 ❌ ✅ 右侧切换区 —
11 底部智能洞察带 ✅ 走马灯,最多两句 ✅ —
12 机构详情面板(弹层) ❌ A屏零交互,无弹层 — ✅ B屏专属
新 大区分布横条(七大区) ✅ 轮播卡·右(与预警交替) ✅ 地图上方筛选条 — v1.0 已把"环形"改横条(七类超分类色板 5 槽上限)

A屏上屏元素合计 5 类(KPI 4 个 / 地图 / 轮播卡左 / 轮播卡右 / 走马灯)——与 v1.0 §2.2 一致,本表只是把它对回了 12 模块编号。


四、联动下钻规则(08-15 调研标注的缺口,本版补齐)

结论:B屏只允许一个全局选中态(省份),下钻面板是唯一的"点名到人"出口;A屏零交互,本节完全不适用。

4.1 三级下钻路径

层级 入口 展示 退出
L0 全国 默认态 12 模块全国口径 —
L1 省份 点地图省份 / 点大区横条 侧栏模块 3/5/6/7/8/10 全部切到该省口径,标题追加「· 广东」;地图该省高亮描边 点空白 / 面包屑「全国」
L2 机构 在 L1 的预警列表 / 审批列表 / 省份机构清单里点某一行 模块 12 详情面板(弹层):机构基本信息 + 席位批次甘特 + 续费历史 + 处置按钮 关闭弹层,回到 L1

4.2 规则(避免"两套账")

规则 内容 为什么
单一选中态 全屏同时只有一个省份被选中;再点另一省=替换,不是叠加 多选会让"续费完成率"分母口径变模糊,违反"不新增口径"
顶部 KPI 不跟随 模块 1 六项永远是全国口径,下钻时不变,但加一行小字「当前筛选:广东」 KPI 是大屏定盘星,跟着变会让人以为全国数掉了
未定位机构 L0 计数上屏;L1 任何省份都不含它们;单独一个「未定位 N 家」入口直接进 L2 清单 已定规则第 6 条「未定位机构必须上屏,不隐藏」
无数据省份 用面板底色 #0F2137,不进热力渐变,可点(进 L1 显示空态) 与"0 家"区分,避免最浅档被误读成 0
处置动作 只在 L2 面板内,L1 列表不放按钮 防误操作;也让 B屏投屏模式只需屏蔽 L2 即可全脱敏
A屏 本节全部不适用(零交互、无弹层、无面包屑) v1.0 §2.3

五、数据接口清单(一套 API 两张皮)

结论:8 个接口,A屏用其中 4 个且都是 B屏的子集;口径全部指向现有实现,接口层只做聚合不做新算法。

⚠️ 接口路径为建议命名,当前代码中不存在(已 git ls-files 核对);口径出处列才是现有物理代码。

# 接口(建议) 供给 口径出处(现有代码) 刷新 A屏 B屏
1 GET /cockpit/kpi 模块 1 六项 活跃口径 app/api/admin_activity.py;席位/订单 settlement/backend/app/models/settlement.py:510,584 30s ✅ 取 4 项 ✅ 全 6 项
2 GET /cockpit/geo/heat 地图省份热力 同 1 的活跃口径 + 省→大区映射(本期新建) 5min ✅ ✅
3 GET /cockpit/geo/pings?since= 登录光点(增量) auth_audit_logs(event_type='login_success', ip) + ip2region 15s ✅ 可选开关
4 GET /cockpit/insights 模块 11 洞察带 由 1/2/6/7 结果二次生成,无独立查询 5min ✅ ✅
5 GET /cockpit/channels/ranking?dim= 模块 3、8 Channel settlement.py:86;席位批次 :584 5min ❌ ✅
6 GET /cockpit/trend/monthly 模块 5、10 StoreServiceOrder settlement.py:510 5min ❌ ✅
7 GET /cockpit/alerts?type= 模块 4、6、7 席位到期 settlement.py:584-613 60s ❌(只取 count,走接口 1) ✅
8 GET /cockpit/org/{id} 模块 12 详情面板 同 5/6/7 + 甘特 按需 ❌ ✅

5.1 三条工程约定

约定 内容
口径零分叉 A屏不允许有 B屏没有的字段;接口 1 返回 6 项,A屏自己只渲染 4 项
权限 A屏用只读展示账号,服务端白名单只放行接口 1/2/3/4,且响应中不含机构名/IP 明文;不靠前端"不显示"
渠道隔离 B屏渠道账号复用结算侧现成实现 settlement/backend/app/auth/zhaoyang_permissions.py:293-315(服务端按 sub 反查 channel_id,不信任客户端声明)

六、摸底 SQL 修订(按 D7 + 本轮实证)

结论:原 10 段有 1 段降级、1 段升级、需新增 1 段;新增的那段跑完就直接知道 A屏地图长什么样,建议排第一。

段 原用途 v1.1 处置 理由
【1】机构地址覆盖率 判"可定位率"三档 🔽 降为选修 D7 已定不采集坐标,判据作废;仍可跑,为将来"地址地理编码"增强路径留底数
【2】登录 IP 真实性体检 判是否要先修反代 🔼 升为第一优先 本轮已证代码层透传开着(2.1 第 5 段),此查询变成"验证配置真的生效"的唯一手段
【3】谁在登录 下钻面板给谁看 保留 —
【4】渠道维度分布 + 登录留存多久 渠道卡数据基础 保留,留存部分可跳过 留存已由代码确定 = 6 个月(audit.py:24)
【5】销售额三口径 主口径选哪个 保留 —
【6】经营数据时间跨度 趋势能回溯多久 保留 与【4】留存不同源:这查订单表,不受 6 月清理影响
【7】席位到期分布 预警负载 保留 —
【8】未激活/永久席位 续费分母 保留 —
【9】续费与流失历史 曲线/甘特回溯 保留 —
【10】待审批积压 审批列表参数 保留 —
【11】新增 A屏地图预演 🆕 新增,建议排第一 见下

6.1 新增第【11】段(建议)

用途:把 A屏地图"提前跑出来"——近 7 日 login_success 按机构去重后按省聚合,直接看出热力图有几个省亮、多少条 IP 为空、多少落私网。

-- 【11】A屏地图预演 · 近7日登录事件的机构覆盖与 IP 可用性
-- 只读;不含 ip2region 解析(需应用层),先看原始可用性
SELECT
  COUNT(*)                                                   AS 登录成功事件数,
  COUNT(DISTINCT u.linked_org_id)                            AS 覆盖机构数,
  COUNT(*) FILTER (WHERE a.ip IS NULL)                       AS IP为空条数,
  COUNT(*) FILTER (WHERE a.ip << '10.0.0.0/8'::inet
                      OR a.ip << '172.16.0.0/12'::inet
                      OR a.ip << '192.168.0.0/16'::inet
                      OR a.ip << '127.0.0.0/8'::inet)        AS 私网IP条数,
  COUNT(DISTINCT a.ip)                                       AS 去重IP数
FROM auth_audit_logs a
JOIN users u ON u.id = a.user_id
WHERE a.event_type = 'login_success'
  AND a.created_at > now() - interval '7 days'
  AND u.linked_org_id IS NOT NULL;

怎么读:

结果 判断
覆盖机构数 ≥ 在营机构数 × 30% A屏地图有内容,光点方案直接做
私网IP条数 / 总数 > 20% 反代配置在生产未真正生效,先修部署再上光点(与 SQL【2】互为印证)
IP为空条数占比高 光点会稀疏,需在图例注明"仅统计可定位登录"
覆盖机构数 很低 不是数据问题是业务问题(机构本身登录少),此时地图价值有限,热力改用「近 30 日」口径

七、验收清单(11 项,可执行)

结论:性能三条 + 视觉三条 + 数据五条;每条都能跑出个数字,不靠"看着还行"。

# 类别 验收项 判定
1 性能 投屏机 1080p 连续 30 分钟 帧率 ≥30fps,内存无上涨趋势
2 性能 动效只用 transform/opacity DevTools 无 layout thrash
3 性能 数据刷新与动画解耦 echarts setOption 增量合并,刷新不整屏重绘
4 视觉 echarts 不出大屏目录 grep -rln "echarts" web/app --include=*.tsx \| grep -v "/cockpit/" \| wc -l = 0
5 视觉 无全量 barrel import grep -rn "from ['\"]echarts['\"]" web/app web/components \| wc -l = 0;对照组 echarts/core > 0
6 视觉 大屏 echarts chunk gzip < 200 KB(贴 next build First Load JS)
7 数据 两屏 KPI 逐项对比 A屏 4 个数字 = B屏对应 4 个,不允许有 1 的差
8 数据 大屏活跃数 vs 现有活跃页 同一时刻取数,数字一致(证明复用口径没自算)
9 数据 省份合计 34 省热力值合计 + 未定位数 = 全国总数
10 数据 光点 NULL/私网处理 抽查:ip IS NULL 的登录事件在图上 0 个点,且计入"未定位"
11 权限 A屏展示账号越权 直接请求接口 5/6/7/8 → 403;接口 1-4 响应体 grep 不到机构名与 IP

八、待拍板决策点(含新增 D8)

# 决策 状态
D1 B屏地图续费状态点色 ✅ 随 D7 了结(无点位无点色,状态放下钻清单徽章)
D2 深色科技风两屏统一 推荐统一(一套令牌,B屏只换皮不减密度)
D3 A屏是否显示机构名 推荐不显示
D4 深色令牌 v1 色板 推荐按 v1.0 第五节定稿(已过色觉/对比度机器校验)
D5 A屏预警/异常计数是否对外显示 推荐做成开关,默认隐藏
D6 A屏热力口径:今日 or 近 7 日活跃 推荐近 7 日(B屏维持今日不变)
D7 是否采集机构坐标 ✅ 已定(08-18 长官拍板):不采集
D8 B屏是否展示结算域操作留痕 🆕 新增待拍板。现状:audit_logs 生产账号无 SELECT 权限(settlement/db/grants.sql:48)。要展示需单开只读账号或视图(属主不转、不做 schema 迁移)。若本期不做,B屏「谁处置了什么」这一栏直接不上

九、下一步(顺序不能换)

序 事项 谁做 阻塞谁
1 长官看 A/B 两张原型图 + 拍 D2–D6、D8 长官 全部
2 跑摸底 SQL(先跑新增第【11】段和第【2】段) 有生产库权限的同事 地图口径与光点是否成立
3 视 2 的结果决定:光点直接做 / 先修反代 / 热力改 30 日口径 主会话出结论页 实施

云机不连生产库,第 2 项云机做不了,这一条从 08-14 挂到今天没变。


本方案纯文档,零代码改动。第二节全部结论均为本轮(2026-08-19)在 worktree HEAD 8f92bd1b 上重新 grep 实证,含对照组自证;行号在 origin/test 上可能漂移,符号名不会。数据类数字(机构数、覆盖率等)一律未实测,需摸底 SQL 出结果。
云机环境 · 非验收证据。