管理端:设计系统 v2 收敛 + 修复漏斗卡恒为 0 的响应式缺陷

## 一、设计系统收敛

- theme/index.css 重写为 token 底座:品牌三级、语义五组、文字四级、
  边框/背景/圆角/阴影/动效/热区/排版刻度
- 修复 Element Plus 派生色阶残留:--el-color-*-light-N 是 SCSS 编译期静态生成,
  只覆盖基色不会带动它们 —— 数据统计页实测 133 处元素仍在用 EP 默认调色板
  (其中主色蓝 8 处)。已按 mix(#fff,base,N*10%) / mix(#000,base,20%) 补全全部档位
- 新增 src/theme/tokens.ts:模板里 :style 需拼 8 位 hex(color + '15'),用不了 var(),
  故以 TS 常量镜像色值;守卫会双向校验它与 index.css 同名取值一致
- 24 个 .vue 收敛:硬编码色值 97 处/67 种 → 0;越界字号 88 处(最低 9px)→ 0;
  非法字重 650×6 → 0;触摸目标 17 处 <44px → 全部 ≥44px
- 对比度:text-tertiary 3.54:1、warning 2.33:1、coral 作文字 3.14:1 → 全部 ≥4.5:1
- 新增守卫 ui-tests/admin-design-tokens.mjs(含 WCAG 对比度实算)

## 二、修复既有功能性缺陷:数据统计页漏斗卡与安全卡恒显示 0

- 现象:同一张卡片里,上方漏斗数字全是 0,下方汇总表却是 12846/9217/8462/3812,
  界面自相矛盾
- 根因:funnelStages / matchStages / safetyCards 是普通数组(const x = [...]),
  loadFunnel() 直接改元素属性,模板读的却是同一个数组 —— 非响应式写入不触发重渲染。
  同页凡走 ref 的值(汇总表、V11 区块)全部正常,规律清晰
- 修法(按根因):三个集合改为 computed() 从既有 ref 派生,卡片与汇总表因此同源,
  结构上不可能再出现「同一份数据的两处展示对不上」;另把 loadFunnel() 内遮蔽
  颜色助手的局部变量 const token 改名 authToken
- 该缺陷无 TS/lint/构建报错,前 18 个守卫全绿也抓不到 —— 只有真跑起来看渲染结果才暴露
- 新增守卫 ui-tests/admin-reactivity-contracts.mjs:
  ①非响应式状态(普通声明 + 被当状态写 + 出现在模板里;未被写过的静态常量清单合法)
  ②数据统计页同源契约 ③颜色助手遮蔽

## 验证

- UI 契约门禁 20/20 PASS(MIN_GUARDS 18→20)
- 负向注入 3 例全部 FAIL(exit 1),还原后复跑 exit 0(证明守卫有判别力)
- vue-tsc --noEmit exit 0
- vite build 成功(17.74s)
- 渲染态实测(Edge 无头 + CDP 读渲染后 DOM,同一 mock、同一路由,只差代码):
  修复前漏斗卡/安全卡全 0、比率全 '-' → 修复后 12846/9217/8462/3812/
  48210/51236/7420/4380/1926/1284,安全卡 17/214/23/9

交付物:artifacts/admin-design-v2-preview.html
This commit is contained in:
WorkBuddy
2026-09-23 01:06:57 +08:00
parent 269adf1fed
commit 631e3000d3
20 changed files with 1765 additions and 381 deletions
+9 -1
View File
@@ -31,10 +31,18 @@ const UI_TESTS_DIR = resolve(root, 'ui-tests')
// wxss-component-selector-contracts(组件 wxss 用了标签/ID/属性选择器);
// 17 → 18:新增 miniapp-api-client-behavior(**唯一一组行为断言**:桩掉 wx.request,
// 真跑 api.js,验证成功/失败/幂等键释放/收尾容错 4 组行为)。
// 18 → 19:新增 admin-design-tokens(管理端设计 token 守卫:未定义 token / 硬编码色值 /
// 字号下限 / 非法字重 / EP 调色板残留 / **对比度实算** —— 最后一项是此前
// 完全无人把关的一类,且人工目视很难覆盖 24 个页面)。
// 19 → 20:新增 admin-reactivity-contracts(管理端响应式契约:**非响应式状态**——
// 普通 `const x = [...]` 被直接改元素且绑到 v-for 时,改动了但渲染不更新,
// 界面显示陈旧/默认值。2026-09-23 实测数据统计页漏斗卡恒为 0 即此因。
// 该缺陷无 TS/lint/构建报错,前 19 个守卫全绿也抓不到,只有真跑起来看渲染
// 结果才暴露 → 必须由源码结构断言接管)。
// 新增/删减守卫时同步修改本默认值。
// 可用环境变量 UI_GUARDS_MIN 覆盖 —— 唯一目的是让「数量下限」这条分支本身可被自检
// (`UI_GUARDS_MIN=99 node scripts/run-ui-contracts.mjs` 必须拒绝报绿)。
const MIN_GUARDS = Number(process.env.UI_GUARDS_MIN ?? 18)
const MIN_GUARDS = Number(process.env.UI_GUARDS_MIN ?? 20)
const cliArgs = process.argv.slice(2)
const explicit = cliArgs.length > 0