跳转至

显示完整性改动前后对比(ui-delta.py)

位置:deploy/nfos/tools/ui-delta.py | 语言:python3 | 是否需要 root:否

工具性质:本地静态对比(只读两份 CSS;只写 --out 指定的文件) 运行前提:仓库检出必须在场(加载 apps/web/tests/lint-layout.py)。可从任意位置运行(工具自动向上找到含 deploy/nfos 的祖先目录) 部署状态:随仓库检出运行,不部署到 /opt/Cy/services/system.d/nfos/


用途

对「显示完整性」改动做前后对比,且做到工具版本无关。

源码 docstring 说明的动因(逐字引用):

为什么需要它:并发 agent 在我工作期间既改了 nf.css,也改了 tests/lint-layout.py。
拿“旧工具的结果”和“新工具的结果”对比是不成立的,所以这里:
  1) 用**同一份当前版** lint-layout.py 分别去量「基线备份 .bak-20260926-190842」与「当前 nf.css」;
  2) 另外用自带的纯正则模式计数(不依赖任何外部工具)交叉验证;
  3) 逐条检查“审计缺口”是否仍然存在(针对具体规则字符串做断言式检查)。

输出 4 块:

块 内容
摘要行 BASE <base 路径> / CUR <cur 路径> 各自的字节数与 sha16(sha256 前 16 位)
1. 纯正则模式计数 源码内 PATTERNS 共 17 条模式,先剥离 /* */ 注释再计数(表格列为 模式 / 改动前 / 改动后 / 增减);随后再打印一份含注释的原始计数“仅供查证”
2. lint-layout.py 对比 用同一份当前版 lint_layout 量两份 CSS(lint_css + lint_clip_ancestors),按规则名 R* 汇总 改动前 / 改动后 / 增减 与合计
3. 审计缺口逐条判定 源码内 GAPS 共 9 条(G1–G9),每条输出 已修 / 未修(后者若匹配“原写法仍在”正则会追加 (原写法仍在)),并打印该条的 判定式
4. 结尾追加区块标记 用 /\* ===== ([^\n]*?) ===== \*/ 提取 --cur 里所有追加区块标题

GAPS 的 9 条缺口(编号 + 说明逐字来自源码):

编号 缺口说明(源码逐字)
G1 .nf-nowrap 仍用省略号吃掉 store 订单号/商品名/自提点等“必须看全”字段
G2 .nf-code 是 white-space:pre(长 JSON/长 URL 只能横向拖)
G3 ui.js 给弹层写内联 width,窄屏盖掉媒体查询(弹层比视口宽,右侧在屏外)
G4 .nf-drawer 无 max-width 兜底(同上,内联 420px)
G5 .nf-search-results 无 max-height(absolute 浮层越出视口,页面滚不动)
G6 .nf-user-menu 无 max-height/overflow(同上)
G7 .nf-notify-list 固定 380px,矮窗口顶出屏幕
G8 折叠轨回归:.nf-side{min-width:240px} 未给 .collapsed 兜底(>1200px 手动折叠时侧栏压住正文)
G9 .nf-kv dd 只靠 word-break(无 overflow-wrap:anywhere)

典型场景

  • 改完 nf.css 后,给出“相对基线备份,17 个模式计数与 lint 规则命中各增减多少”的量化证据;
  • 回归核对:确认 G1–G9 的 9 条审计缺口确实从 未修 变成 已修,且没有把旧写法留在别处;
  • 复盘“改了 CSS 但视觉没变”的原因:对比 lint 命中数是否有变化,或某条缺口仍是 未修(原写法仍在)。

用法与参数

源码 docstring 给出的用法(逐字引用,.scratch/ 为升级前旧路径;本页按新位置书写,路径参数不变):

用法:
  python .scratch/ui-delta.py --base apps/web/index/css/nf.css.bak-20260926-190842 \
                              --cur  apps/web/index/css/nf.css --out .scratch/ui-delta.txt

参数来自 argparse.ArgumentParser():

参数 类型 默认值 说明
--base 字符串(文件路径) 无默认值(required=True) 改动前的基线文件(通常是 CSS 的 .bak-<时间戳> 备份)
--cur 字符串(文件路径) 无默认值(required=True) 改动后的当前文件
--out 字符串(文件路径) ''(空 = 写 stdout) 输出文件;给值时打印 written: <path> (<N> bytes)

无参数时的默认行为:没有默认行为 —— --base 与 --cur 都必填,缺失时 argparse 报错并以退出码 2 结束。

两个路径参数都按当前工作目录解析(源码不做仓库根拼接),推荐在仓库根执行并传相对路径。

示例

从仓库根目录执行(--base 请换成实际存在的基线备份文件名):

python deploy/nfos/tools/ui-delta.py `
  --base apps/web/index/css/nf.css.bak-20260926-190842 `
  --cur apps/web/index/css/nf.css `
  --out .scratch/ui-delta.txt

期望输出形态:

written: .scratch/ui-delta.txt (45678 bytes)

正文形如:

== 显示完整性:基线 vs 当前 ==
BASE apps/web/index/css/nf.css.bak-...        ... B  sha16=...
CUR  apps/web/index/css/nf.css                ... B  sha16=...

-- 1. 纯正则模式计数(不依赖任何工具版本;**注释已剥离**,...) --
  模式                                改动前    改动后      增减
  overflow:hidden                       12        9       -3
  ...
-- 2. lint-layout.py(**同一份当前版工具**量两份 css,公平对比) --
  规则       改动前    改动后      增减
  R1            5        2       -3
  合计         ...
-- 3. 审计缺口逐条判定(G=gap,见脚本内 GAPS) --
  G1   已修     .nf-nowrap 仍用省略号吃掉 ...
       判定式: \.nf-nowrap\s*\{[^}]*white-space\s*:\s*normal
  ...
-- 4. 结尾追加区块标记 --
  WEB-UI-CLIP-FIX BEGIN/END ...
情形 期望退出码
正常完成 0(源码未调用 sys.exit)
缺 --base / --cur 2(argparse 报错)
任一路径不存在 / --out 不可写 1(Python traceback)
lint-layout.py 缺失或 lint_css/lint_clip_ancestors 接口变更 1(importlib/AttributeError traceback)

注意:G1–G9 的判定结果不影响退出码 —— 出现 未修 也仍返回 0;判定要看正文第 3 块。

依赖与权限

  • 语言/版本:Python 3(#!/usr/bin/env python3)。
  • 第三方依赖:无,标准库 argparse / hashlib / importlib.util / io / os / re / sys。
  • 仓库依赖:必需 —— load_lint() 加载 <repo>/apps/web/tests/lint-layout.py,依赖其 lint_css / lint_clip_ancestors(第 2 块)。第 1、3、4 块是自带纯正则,不依赖外部工具。
  • 权限:不需要 root;不需要网络(纯离线);写权限仅用于 --out。

风险与注意事项

  • 只读两份 CSS,只写 --out:不修改 --base / --cur,不改任何仓库文件。不传 --out 时只写 stdout,不落盘。
  • --base 必须是真正的“改动前”文件:本工具不做自动备份、不做版本控制查询。传错文件(例如两份都是当前版)会得出“无变化”的假结论。
  • 第 3 块是正则断言,不是语义证明:已修 仅代表匹配到了源码内那条“已修判定式”。例如 G1 的判定式只要求 .nf-nowrap {...} 里出现 white-space: normal;若该声明被更靠后的规则覆盖,仍会判 已修。确切结论需配合 ui-keyrules.py 看最终生效声明。
  • 第 1 块与第 2 块口径不同:第 1 块剥注释后按 17 条正则计数;第 2 块走 lint-layout.py 的规则体系。两块不应互相校验,它们是交叉验证用的两条独立证据。
  • G5/G6/G7/G8/G9 在源码里 alive_rx 为 None,因此这些条目只会有 已修 / 未修 两种输出,不会追加“(原写法仍在)”。

回滚

本工具不部署到线上、不改线上系统;不改动任何被对比文件。

  • 产出/改动位置:仅 --out 指定的文件(例如 .scratch/ui-delta.txt)。
  • 清理方式:
Remove-Item -Force .scratch/ui-delta.txt
  • 基线文件(.bak-*)由使用者自己创建;本工具既不创建也不删除它。不给 --out 时无任何落盘物,无需清理;线上侧无需回滚。