feat(HEL-546): 数据中枢 A/B/C 三方向落地为可用页面

- 基于第七版稳定基线(be647bb)重构 admin 前端为模块化架构:
  tokens.css(设计token唯一来源) + shared.css(公共组件) + core.js(状态/API/事件总线/轮询/路由)
  + main.js(入口) + layouts/{flowline,ledger,strata}.{css,js}(三方向独立布局)
  + layouts/shared.js(三方向共用数据视图与操作绑定)
- 三个页面(A装配线/B值班台账/C地层剖面)通过 ?layout= 查询参数独立可达、可刷新、可前进后退导航,
  共享登录态、真实后端数据(overview/sources/jobs/batches/datasets/audit)、错误处理与主题
- 六大板块(总览/数据源/调度任务/盘后发布/数据集/审计)在三个方向均可查看与操作(探测/触发/回滚/补数)
- 修正健康状态语义:CircuitBreaker closed/half_open/open 与适配器 ok/error/empty/unconfigured/unknown
  统一归一化为 ok/warn/error/unconfigured/unknown 供三方向一致展示
- 事件驱动动效:A 水平接力光梭、B 行级高亮+实时调用跑马灯、C 纵向贯穿光点+分层标记;
  统一使用 transform/opacity/WAAPI,避免 transition:all,支持 prefers-reduced-motion 静态降级
- 修复响应式布局在 1024/1280 断点因 CSS Grid 默认 min-width:auto 被内部宽表格撑爆轨道的问题
- 修复布局切换/前进后退时残留 setTimeout 回调在 unmount 后访问 null root 导致的报错(mounted 标志位+
  safeTimeout+统一清理定时器)
- 自测:Playwright 全断点(1440/1280/1024)x 双主题矩阵截图、90 次连续布局切换+前进后退压力测试无报错、
  探测/触发/回滚danger操作流程验证、reduced-motion 验证;后端 pytest 全量 133 用例通过,无回归
- 未改动:登录/鉴权契约、后端 API、'问天'冻结区、生产数据/权限

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
总工
2026-09-13 16:28:50 +08:00
co-authored by Cursor multica-agent
parent be647bbaba
commit 011ecc0d1a
14 changed files with 1915 additions and 1666 deletions
+136
View File
@@ -0,0 +1,136 @@
/* xiaobai-datahub 数据中枢后台 —— A/B/C 三方向共用组件层
只依赖 tokens.css 的变量;三个布局文件(flowline.css / ledger.css / strata.css
只写各自独有的排布,不得重复定义这里已有的颜色/组件规则。 */
* { box-sizing: border-box; }
html, body { margin: 0; height: 100%; }
body {
background: var(--bg0); color: var(--t1); font-family: var(--font-cn);
font-size: var(--fs-body); -webkit-font-smoothing: antialiased;
}
.num, .mono { font-variant-numeric: tabular-nums; font-feature-settings: "tnum"; }
.mono { font-family: var(--font-mono); }
.muted { color: var(--t3); }
.error, .fail { color: var(--error); }
.ok { color: var(--alive); }
.warn { color: var(--act); }
button { font-family: var(--font-cn); cursor: pointer; }
/* ---------- 区段标签:mono 小字大写,是整套系统的刻度尺 ---------- */
.sec-label {
font-family: var(--font-mono); font-size: var(--fs-label); letter-spacing: .14em;
text-transform: uppercase; color: var(--t3);
}
/* ---------- 卡片:只靠底色阶梯和 1px 发丝线分层 ---------- */
.card { background: var(--bg1); border: 1px solid var(--line); border-radius: var(--r-card); }
/* ---------- 状态 chip ---------- */
.chip {
display: inline-flex; align-items: center; gap: 5px; font-size: var(--fs-small);
line-height: 1; padding: 4px 8px; border-radius: var(--r-chip); border: 1px solid var(--line);
color: var(--t2); white-space: nowrap;
}
.chip::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor; flex: none; }
.chip.ok { color: var(--alive); background: var(--alive-soft); border-color: transparent; }
.chip.err { color: var(--error); background: var(--error-soft); border-color: transparent; }
.chip.warn { color: var(--act); background: var(--act-soft); border-color: transparent; }
.chip.unknown { color: var(--unknown); }
.chip.unconfigured { color: var(--unconfigured); border-style: dashed; background: transparent; }
.chip.info { color: var(--action); background: var(--action-soft); border-color: transparent; }
/* ---------- 双灯:LINK=链路健康(低亮常亮),ACT=真实活动(事件时短闪) ---------- */
.lamp { width: 7px; height: 7px; border-radius: 50%; display: inline-block; flex: none; transition: background var(--dur-fast) var(--ease-out); }
.lamp.link.on { background: var(--alive); box-shadow: 0 0 6px rgba(60,203,154,.55); }
.lamp.link.off { background: var(--bg3); }
.lamp.link.err { background: var(--error); box-shadow: 0 0 6px rgba(229,83,75,.55); }
.lamp.act { background: var(--bg3); }
.lamp.act.on { background: var(--act); box-shadow: 0 0 7px rgba(240,167,60,.8); }
.lamp.act.on.err { background: var(--error); box-shadow: 0 0 7px rgba(229,83,75,.8); }
.lamp-tag { font-family: var(--font-mono); font-size: 9px; color: var(--t3); letter-spacing: .08em; }
/* ---------- 按钮:蓝色只给"可操作" ---------- */
.btn {
font-family: var(--font-cn); font-size: var(--fs-small); color: var(--action);
background: var(--action-soft); border: 1px solid transparent; border-radius: var(--r-chip);
padding: 5px 12px; cursor: pointer; transition: background var(--dur-fast) var(--ease-out), transform var(--dur-fast) var(--ease-out);
}
.btn:hover { background: var(--action); color: #fff; }
.btn:active { transform: translateY(1px); }
.btn:disabled { opacity: .5; cursor: not-allowed; }
.btn.ghost { background: transparent; border-color: var(--line); color: var(--t2); }
.btn.ghost:hover { border-color: var(--action); color: var(--action); background: transparent; }
.btn.ghost.active { border-color: var(--action); color: var(--action); background: var(--action-soft); }
.btn.danger { color: var(--error); background: var(--error-soft); }
.btn.danger:hover { background: var(--error); color: #fff; }
.btn.mini { padding: 3px 8px; font-size: 11px; }
/* ---------- 表格 ---------- */
table.grid { width: 100%; border-collapse: collapse; font-size: var(--fs-small); }
table.grid th {
text-align: left; font-weight: 500; color: var(--t3); font-size: 11px;
padding: 6px 10px; border-bottom: 1px solid var(--line); white-space: nowrap;
}
table.grid td { padding: 6px 10px; color: var(--t2); border-bottom: 1px solid var(--line-soft); white-space: nowrap; }
table.grid td.k { color: var(--t1); }
table.grid tr:last-child td { border-bottom: none; }
/* ---------- 登录 / 改密(三页共用,跟布局无关) ---------- */
.auth-panel {
max-width: 420px; margin: 12vh auto; padding: 30px 32px; border-radius: 14px;
background: var(--glass); border: 1px solid var(--line); backdrop-filter: blur(14px);
box-shadow: var(--shadow-pop);
}
.auth-panel h1 { margin: 0 0 6px; font-size: 21px; }
.auth-panel label { display: block; margin: 12px 0; font-size: 13px; color: var(--t2); }
.auth-panel input {
width: 100%; margin-top: 6px; padding: 9px 11px; border: 1px solid var(--line); border-radius: 8px;
background: var(--bg2); color: var(--t1); font-family: var(--font-cn);
}
.auth-panel input:focus { outline: 2px solid var(--action); outline-offset: 1px; }
.auth-panel .badge-sim { display: inline-block; margin-bottom: 10px; font-size: 11px; padding: 3px 10px; border-radius: 999px; letter-spacing: .1em; color: var(--act); border: 1px solid var(--act); opacity: .85; }
.auth-panel button[type="submit"] {
background: var(--action); color: #fff; border: 0; border-radius: 8px; padding: 8px 16px; font-size: 13px;
}
/* ---------- 顶栏:品牌 + 交易日 + 阶段 + A/B/C 切换 + 全局控制 ---------- */
#topbar {
height: 48px; display: flex; align-items: center; gap: 12px; padding: 0 16px;
border-bottom: 1px solid var(--line); background: var(--bg1); position: sticky; top: 0; z-index: 20;
}
#topbar .title { font-size: 15px; font-weight: 600; color: var(--t1); white-space: nowrap; }
#topbar .title em { font-style: normal; color: var(--action); }
#topbar .vdiv { width: 1px; height: 16px; background: var(--line); flex: none; }
#topbar .tdate { font-size: 13px; color: var(--t2); white-space: nowrap; }
#topbar .spacer { flex: 1; }
#topbar .who { font-size: 12px; color: var(--t2); white-space: nowrap; }
/* A/B/C 切换:一直可见,写清中文名称,当前页状态明确 */
#layoutSwitch {
display: flex; align-items: center; gap: 2px; padding: 3px; border-radius: 8px;
background: var(--bg2); border: 1px solid var(--line); flex: none;
}
#layoutSwitch button {
font-family: var(--font-cn); font-size: 12.5px; color: var(--t2); background: transparent;
border: 0; border-radius: 6px; padding: 6px 11px; white-space: nowrap;
transition: background var(--dur-ui) var(--ease-out), color var(--dur-ui) var(--ease-out);
}
#layoutSwitch button .k { font-family: var(--font-mono); font-weight: 700; margin-right: 5px; opacity: .7; }
#layoutSwitch button[aria-current="page"] {
background: var(--action); color: #fff; box-shadow: var(--shadow-pop);
}
#layoutSwitch button[aria-current="page"] .k { opacity: 1; }
#layoutSwitch button:not([aria-current="page"]):hover { background: var(--bg3); color: var(--t1); }
/* ---------- 主内容容器 ---------- */
#page-root { min-height: calc(100vh - 48px); background: var(--bg0); }
.page-shell { padding: var(--sp4); max-width: 1584px; margin: 0 auto; }
/* 三方向表格容器统一命名以 Table 结尾:窄列/1024 档宁可局部横向滚动,
也不可撑破外层 grid/flex 轨道导致整页错位。 */
[id$="Table"] { overflow-x: auto; }
/* ---------- reduced-motion 全局兜底:不留半成品动效 ---------- */
@media (prefers-reduced-motion: reduce) {
* { animation-duration: .001ms !important; animation-iteration-count: 1 !important; transition-duration: .001ms !important; }
}
html.reduced * { animation-duration: .001ms !important; transition-duration: .001ms !important; }