管理端 · admin-web 20/20 契约门禁通过

管理端设计系统 v2 改造对照

用与小程端相同的收敛手法,把 admin-web(Vue3 + Element Plus)的样式统一到一套 token 上:颜色、字号、字重、触摸目标、对比度,并补上 Element Plus 派生色阶联动。

范围:24 个 .vue 中的 style 块 + src/theme/index.css(重写为底座)+ 新增 src/theme/tokens.ts(TS 侧色值镜像)。另含复验中咬出并修复的 1 个既有功能性缺陷(见第六节)。

0硬编码色值(原 97 处 / 67 种)
0越界字号(原 88 处,最低 9px)
0EP 默认调色板残留(数据统计页原 133 处)
4 / 4页面实测无 <11px 文本
20 / 20UI 契约门禁(新增 1 个响应式守卫)
1复验咬出并已修复的既有缺陷

一、修复的缺陷类别(附实测数字)

类别改造前(实测)改造后证据来源
Element Plus 派生色阶残留light-3/5/7/8/9、dark-2 及 success/warning/danger/info 的 light-N 全是 EP 默认值;数据统计页实测 133 处元素仍在使用 EP 默认调色板(其中主色蓝 8 处、success 14、danger 10、warning 8、info 92)全部档位按品牌基调重算;4 个页面实测 0 处渲染态 CDP 实测
硬编码色值97 处 / 67 种色值0守卫
硬编码字号88 处;其中 20 处 ≤11px(最低 9px,工作台实测 9px×27 / 10px×42)0 处越界;实测最低 11px守卫 + 渲染态
非法字重6 处 650(缺字重平台会回退,渲染不一致)0;仅用 400/500/600/700守卫 + 渲染态
对比度不达标text-tertiary #888 3.54:1、warning #E59A32 2.33:1、coral #F45F68 作文字 3.14:1全部 ≥4.5:1(11 组实算判定)守卫(WCAG 实算)
触摸目标偏小17 处 <44px全部 ≥44px守卫
依赖 UA 默认字号浏览器对 <small> 默认 font-size: smaller(0.833em),父级 11px→实际 9.17px、12px→10px统一继承父级字号 + 关键处显式声明,实测 ≥11px本轮渲染态新发现

二、核心 token 对照

Element Plus 的 --el-color-*-light-N 是 SCSS 编译期静态生成的:只改 --el-color-primary 不会带动它们,残留下来的就是 EP 默认蓝。

token改造前改造后说明
--el-color-primary#f45f68(只覆盖了基色)#C84A53实心底 + 白字 4.60:1
--el-color-primary-light-3#79bbff ← EP 默认蓝#d98087按 mix(#fff,base,30%) 重算
--el-color-primary-light-5#a0cfff ← EP 默认蓝#e4a5a9mix(#fff,base,50%)
--el-color-primary-light-7#c6e2ff ← EP 默认蓝#efc9cbmix(#fff,base,70%)
--el-color-primary-light-8#d9ecff ← EP 默认蓝#f4dbddmix(#fff,base,80%)
--el-color-primary-light-9#ecf5ff ← EP 默认蓝#faedeemix(#fff,base,90%)
--el-color-primary-dark-2#337ecc ← EP 默认蓝#a03b42mix(#000,base,20%)
--el-color-info#909399#656C79info 语义是「中性/未知」,保持灰调
--color-text-tertiary#888888(3.54:1)#676E7B白底 5.13:1 / 浅底 4.74:1
--admin-coral-strong(未定义)#C0414A深一档,专供白底文字 5.13:1
--admin-coral-solid(未定义)#C84A53实心底 + 白字 4.60:1
--tap-min(未定义)44px触摸目标下限
--font-size-base(未定义)14px正文基准

三、字号与字重收敛(工作台渲染态实测)

维度改造前改造后
字号分布 9px×27 · 10px×42 · 11px×35 · 12px×22 · 13px×9 · 14px×123 · 15px×3 · 16px×29 · 17px×73 · 20px×6 · 21px×6 · 22px×1 · 27px×1 · 30px×13 · 31px×3 11px×90 · 12px×37 · 13px×9 · 14px×123 · 15px×3 · 16px×102 · 20px×13 · 24px×1 · 28px×16
字重分布400 / 500 / 600 / 650×6 / 700仅 400 / 500 / 600 / 700
层级倒挂指标数字 30px > 页面标题 24px(数字比标题更抢眼)标题 24px / 指标 24px / 区块 20px,层级归位

字号刻度收敛为:micro 11 / xs 12 / sm 13 / base 14 / md 15 / lg 16 / xl 18 / 2xl 20 / 3xl 24 / 4xl 28 / 5xl 32 / display 38。

四、1440×900 目视对照

系统自带 Edge(Chromium 内核)无头截图,视口 1440×900、缩放 1x,页面数据来自本地 mock。 已目视核对工作台与数据统计的前后对照;登录页与申诉管理页未逐张细看,请人工过目。 数值层面另以「计算样式实测 + 守卫断言」为准。

提示:本节截图的「改造后」列取自已修复漏斗缺陷的产物, 故数据统计页的漏斗卡显示的是真实数字;修复前后的专项对照见第六节。

登录页 品牌视觉与表单密度

登录页 改造前
改造前
登录页 改造后
改造后

工作台 指标卡 / 待办 / 活动列表 / 漏斗

工作台 改造前
改造前
工作台 改造后
改造后

申诉管理 统计卡 + 列表 + 弹窗触发器

申诉管理 改造前
改造前
申诉管理 改造后
改造后

数据统计 漏斗阶段色 / 表格 / 标签(EP 默认色重灾区)

数据统计 改造前
改造前
数据统计 改造后
改造后

五、验证结果

项目结果命令 / 方式
UI 契约门禁(全量)20 / 20 PASS,0 失败,10.4snode scripts/run-ui-contracts.mjs
新增守卫 admin-design-tokensPASS:未定义 token 0 / 硬编码色值 0 / 越界字号 0 / 非法字重 0 / 对比度 11 组实算 / tokens.ts↔index.css 20 项一致node ui-tests/admin-design-tokens.mjs
新增守卫 admin-reactivity-contractsPASS:扫描 24 个 .vue、23 个 v-for 绑定点 → 非响应式状态 0、颜色助手遮蔽 0(静态常量清单 3 处正确豁免)node ui-tests/admin-reactivity-contracts.mjs
守卫判别力(负向注入 · 设计守卫)抽掉 .scene-footer small 的 font-size → 守卫 FAIL(exit 1),3b 计数 1注入 → 复测 → 还原
守卫判别力(负向注入 · 响应式守卫)3 例注入全部咬住(exit 1):①普通数组+直接改元素+v-for ②汇总表改硬编码数字(同源契约)③颜色助手被同名局部变量遮蔽;还原后复跑 exit 0node .workbuddy/neg-inject-admin.mjs
漏斗缺陷修复(行为验证)同一 mock、同一路由,只差代码:修复前漏斗卡/安全卡 全 0、比率全 - → 修复后 12846 / 9217 / 8462 / 3812 / 48210 / 51236 / 7420 / 4380 / 1926 / 1284,安全卡 17 / 214 / 23 / 9Edge 无头 + CDP 读渲染后 DOM 文本
类型检查exit 0,无错误vue-tsc --noEmit
生产构建成功,17.74svite build
渲染态实测(CDP)登录 / 工作台 / 申诉 / 数据统计 4 页:EP 默认色 0 处、<11px 文本 0 处、字重仅 400/500/600/700Edge 无头 + CDP 取计算样式

六、复验中咬出并已修复的既有缺陷

数据统计页:漏斗卡片与安全卡片恒显示 0 —— 已修复 + 已加守卫

现象:同一张卡片里,上方的漏斗数字全是 0,下方「累计注册 / 实名用户 / 审核通过 / 7日活跃」的汇总表却是真实数字(12846 / 9217 / 8462 / 3812),界面自相矛盾。

根因:这三组曾是普通数组,loadFunnel() 直接改元素属性,而模板读的就是同一个数组 —— 非响应式写入不触发重渲染,Vue 看不到变化:

const funnelStages = [ { value: 0, ... } ]  // 普通数组
funnelStages[0].value = userData.totalRegistered // 直接改元素 → 渲染不更新

定位依据(渲染态实测,同一 mock、同一路由,只差代码)

取值来源是否响应式修复前渲染修复后渲染
funnelStats.totalRegistered 等(汇总表)是(ref)正常 12846 / 9217 / 8462 / 3812正常
漏斗卡 10 张(funnelStages / matchStages)否(普通数组)全 012846 / 9217 / 8462 / 3812 / 48210 / 51236 / 7420 / 4380 / 1926 / 1284
安全卡 4 张(safetyCards)否(普通数组)全 017 / 214 / 23 / 9
比率(funnel-rate)否全 -71.7% / 65.9% / 29.7% / 106.3% / 15.4% / 9.1% / 2.7%

已排除环境因素:CDP 抓取页面运行期 控制台错误 0 条、网络失败 0 条, 且 汇总表在同一页渲染出了 12846 ⇒ 数据确实已到达前端,纯粹是响应式问题。 改造前的构建产物表现完全相同 ⇒ 该缺陷先于本次改动存在,不是本次收敛引入的回归。

修法(按根因而非最小改动):三个集合改为 computed() 从既有 ref 派生, 卡片与汇总表因此同源 —— 结构上不可能再出现「同一份数据的两处展示对不上」。 另把 loadFunnel() 里遮蔽颜色助手的局部变量 const token 改名 authToken。

为何前 19 个守卫全绿也没发现它:既有守卫都是源码结构断言,而这一段代码完全合法 —— 无 TS 报错、无 lint 报错、构建通过。只有真跑起来看渲染结果才暴露。 故新增 ui-tests/admin-reactivity-contracts.mjs: ①非响应式状态(普通声明 + 被当状态写 + 出现在模板里 → 失败;未被写过的静态常量清单合法,按「是否被写」区分) ②数据统计页同源契约(卡片与汇总表必须取自同一变量、端点不得被删) ③颜色助手遮蔽。已用负向注入证明判别力:3 例注入全部 FAIL(exit 1),还原后复跑 PASS。

漏斗缺陷修复对照 数据统计页 · 同为设计 v2,只差这一处修复,mock 数据完全相同

修复前
修复前:漏斗卡 0 / 0 / 0 / 0 / 0 / 0 / 0 / 0 / 0 / 0,安全卡 0 / 0 / 0 / 0
修复后
修复后:12846 / 9217 / 8462 / 3812 / 48210 / 51236 / 7420 / 4380 / 1926 / 1284,安全卡 17 / 214 / 23 / 9

七、边界与未验证项(请人工确认)