feat(ui)+chore(docs): UI 补齐清单清空;数据可信销项与「卡」号清退

本笔含两组收尾工作(同一工作区内交错在 6 个共享文档/门禁配置里,
拆开会产生"文档声称的页数与树里黄金数不一致"的中间提交,故合为一笔):

一、UI 补齐(清单清空)
- 新建 6 个内容页模块:ui_page_accident / oper / alarm / start / yk
  复用 ui_w_records 共享组件(分页、空态"无记录"、按实例读盘缓存),
  记录层与五个写入点已由道F task-10 / 道G task-12 落地,本批只补页面;
  ui_page_runreport 为 13 行 2 页只读统计,四个数逐个挂范围标签
  (自电池周期 / 本次开机),boot_ready=0 显 "--" 不显 0。
- 数据面:ui_data_info_t 尾部追加 9 字段,ui_data_feed 用
  boot_stats_get() + iec104_serv_get_stats() 纯搬运;模拟器填确定值假数据
  (差异登记 docs/测试说明/模拟器差距清单.md §2.3 两行)。
- 接线:菜单树 6 叶绑 #page=,绑定叶 22→28、UI_PAGE_MAP_COUNT=28;
  字库 185→218 字 / 280→313 字形;双端注册 uvprojx +30、CMakeLists +6。
- 回归:内容页黄金 53→60(含 runreport_p2 真拍第 2 页),文本断言
  425 正向 / 36 反向;存量 53 张逐字节零漂移;记录 5 页各用独立空目录
  (模拟器把操作留痕写进 cwd 的 sim_oper.log,共用 tmp 会让空态拍不到)。

二、数据可信销项 + 「数据可信」任务卡号整族清退
- 删除已闭环的"已知电压注入验证"行与闭环结论块(证据在
  docs/硬件平台/ADC通道映射说明.md §8.1 与
  docs/测试说明/ADC前端注入验证流程.md §5~§7),§5 标识列改语义短语。
- 卡 0/0b/1~12 共 14 个号全仓 288 站点 / 56 文件清退成语义短语,
  代码注释、测试、门禁配置与文档一并改;换算表入 docs/编号规范.md §9.3。
  这一族是中文前缀,不进 check_ids 语料,刻意不入 id_aliases.json。

验证(实测)
- @build 0 错 0 警:Code=236456 RO=28124 RW=1876 ZI=137084;
  RAM +464 B(RW +304 / ZI +160),RW_IRAM1 62.2% / RW_CCM 87.9%,
  体积同码凭证与 RAM 台账已回填。
- check_menu_rows 8 状态 rc=0(池 5368/5448 常量未动);
  check_content_pages 60 页 rc=0;check_font_charset / registration /
  coding-standard / bom-drift / mojibake / doc-links --all / layer-deps /
  nested-comment 全 rc=0;check_ids --strict 无错误;主机单测
  ui_data 295 / boot_stats 21 / sys_log_mcu 141 / soe 32 / soe_store 27。

未做(不是遗漏)
- 六页真机判据(真记录翻页、掉电保持、清除后归零、boot_count 自增、
  拔 RTC 电池落 RESTARTED、IWDG 复位落 rst_cause、主站连一次 conn_up+1)
  已登记 docs/任务规划/登记簿.md §7;模拟器结构上照不到。
- docs/产品需求/产品需求设计文档.md 属另一条在飞改动,本笔不含;
  其中我已同步 6 处现状数字(28 叶 / 60 页 / 218 字),随该笔入库。
This commit is contained in:
2026-10-28 07:23:16 +08:00
parent 8f7c141a0b
commit 94b0d79026
113 changed files with 1934 additions and 615 deletions
+123 -2
View File
@@ -131,6 +131,27 @@ PAGES = [
("comm_reject", "ddddd ee uruuruuue e d e"), # CA 编到 0(< min=1)→ ENTER 拒退
("comm_wait", "ddddd ee uruuruuue e u e dd e"), # CA 1→2 提交 → 下移到保存行 ENTER:WAIT(+--comm-nopump)
("comm_ok", "ddddd ee uruuruuue e u e dd e"), # 同键序、pump 正常 → OK(脏位真被清)
# ── 接线道 task-6:记录 5 页 + 运行报告(六叶同一笔绑 #page= 注记)────────────────
# 键序 = 主界面第 7 项「记录查询」(6 下)→ e 进子框(进框后首项 SOE记录 即被选中)
# → 再按 n 下选到目标叶 → e 开页。实测下数与 node 号严格对应:
# 1=事故 34 / 2=操作 35 / 3=保护告警 36 / 4=保护启动 37 / 5=遥控 38 /
# 6=自检 39 / 7=运行 40 / 8=运行报告 41(与 Lead 交接口径同源,逐个键序实测过)。
# 这五页在**模拟器侧没有写入方**(sim_rec_count 对这些编号恒 0)→ 拍到的是空态判据:
# 伪行"无记录"落在第 0 行,而第 0 行正是选中行(白底黑字)→ 文本断言一律 inv=True
# (实测 inv=False 匹不上,这是 ui_content_page 选中带的实现事实,不是 bug)。
("accident", "dddddde d e"),
("oper", "dddddde dd e"),
("alarm", "dddddde ddd e"),
("start", "dddddde dddd e"),
("yk", "dddddde ddddd e"),
# 运行报告(node 41):12 行 / UI_LIST_ROWS=8 → 真 2 页。**四个数逐个挂范围标签**是判据
# (docs/任务规划/UI补齐.md §2「运行报告」行),所以两张都必须拍——首屏钉上电次数/
# 计数范围/复位原因/主站接入 + 范围标签"本次开机",第 2 页钉 104 另外三枚(发送帧数
# 128 / 发送失败 0 / 接收字节 4096)与页脚真实页码 2/2。四枚假数据值互不相同是刻意的:
# 行错位/串行只有"像素 + 逐行文本断言"两把尺子同时才照得出来(Lead 裁定 2026-10-28,
# 因此用例是 53+7=60 张,不是 53+6=59)。
("runreport", "dddddde dddddddd e"),
("runreport_p2", "dddddde dddddddd e dddddddd"), # 页内再 8 下 → 第 2 页(选中落 r0=发送帧数)
]
# 文本级断言表:页名 -> [(名称, 期望串, y 带, 是否反显)]
@@ -590,6 +611,72 @@ TEXTS = {
("r0名", "公共地址", (24, 38), False), ("r0值", "2", (24, 38), False),
("保存名", "保存", (52, 66), True), ("保存值", "OK", (52, 66), True), # 脏位被 pump 清 = 已落盘
],
# ── 接线道 task-6:记录 5 页(空态判据)+ 运行报告两页 ───────────────────────────
# 五个记录页只钉空态:模拟器侧这五个日志文件没有写入方,能钉的正是判据"空记录显示
# 无记录"(App/log/README.md §五类记录)。第 0 行 = 选中行(白底黑字)→ inv=True;
# 页脚钉"第 1 页,共 1 页"同时钉住分页数学(1 条伪行 = 1 页,不是 0 页也不是 2 页)。
"accident": [
("标题", "事故记录", (0, 24), False),
("r0空态", "无记录", (24, 38), True),
("页脚", "第 1 页,共 1 页", (140, 160), False),
],
"oper": [
("标题", "操作记录", (0, 24), False),
("r0空态", "无记录", (24, 38), True),
("页脚", "第 1 页,共 1 页", (140, 160), False),
],
"alarm": [
("标题", "保护告警", (0, 24), False),
("r0空态", "无记录", (24, 38), True),
("页脚", "第 1 页,共 1 页", (140, 160), False),
],
"start": [
("标题", "保护启动", (0, 24), False),
("r0空态", "无记录", (24, 38), True),
("页脚", "第 1 页,共 1 页", (140, 160), False),
],
"yk": [
("标题", "遥控记录", (0, 24), False),
("r0空态", "无记录", (24, 38), True),
("页脚", "第 1 页,共 1 页", (140, 160), False),
],
# 运行报告首屏 8 行。四个数各自挂范围标签是判据(上电次数=自电池周期、其余=本次开机),
# 所以**标签与值成对断言**:只钉值不钉标签,就等于把"终身次数"这种口径错画放过去。
# 值 = simulator/main.c 的确定假数据(boot_count 7 / rst_cause 4 上电复位 / conn_up 3 /
# uptime_s 0);四枚 104 数互不相同是刻意的,行错位在第 2 页那张里同样看得出来。
# 运行报告首屏 8 行(13 行 = 8 + 5 两页,Lead 2026-10-28 补「计数可信」行使四态可辨)。
# 四个数各自挂范围标签是判据(上电次数=自电池周期、其余=本次开机),所以**标签与值
# 成对断言**:只钉值不钉标签,等于把"终身次数"这种口径错画放过去。「延续」= 模拟器
# 假数据 boot_seq_state=2(CONTINUED),与 UNKNOWN 的 "--" 是两回事。
# 值 = simulator/main.c 的确定假数据(boot_count 7 / rst_cause 4 上电复位 / uptime_s 0)。
"runreport": [
("标题", "运行报告", (0, 24), False),
("r0名", "上电次数", (24, 38), True), ("r0值", "7", (24, 38), True),
("r1名", "计数范围", (38, 52), False), ("r1范围标签", "自电池周期", (38, 52), False),
("r2名", "计数可信", (52, 66), False), ("r2可信度", "延续", (52, 66), False),
("r3名", "计数写回", (66, 80), False), ("r3值", "正常", (66, 80), False),
("r4名", "复位原因", (80, 94), False), ("r4值", "上电复位", (80, 94), False),
("r5名", "复位范围", (94, 108), False), ("r5范围标签", "本次开机", (94, 108), False),
("r6名", "运行时长", (108, 122), False), ("r6值", "00:00:00", (108, 122), False),
("r7名", "时长范围", (122, 136), False), ("r7范围标签", "本次开机", (122, 136), False),
("页脚", "第 1 页,共 2 页", (140, 160), False),
],
# 运行报告第 2 页:104 另外三枚 + 统计范围标签 + 真实页码 2/2(分页数学的像素证据)
# 运行报告第 2 页(13 行 → 第 2 页 5 行):104 四枚 + 统计范围标签 + 真实页码 2/2。
# 选中行随翻页落在 r0(主站接入)→ inv=True;四枚值 3/128/0/4096 互不相同是刻意的,
# 行错位或分页窗口算错只有"像素 + 逐行文本"两把尺子同时才照得出来(Lead 裁定)。
"runreport_p2": [
("标题", "运行报告", (0, 24), False),
("r0名", "主站接入", (24, 38), True), ("r0值", "3", (24, 38), True),
("r1名", "发送帧数", (38, 52), False), ("r1值", "128", (38, 52), False),
("r2名", "发送失败", (52, 66), False), ("r2值", "0", (52, 66), False),
("r3名", "接收字节", (66, 80), False), ("r3值", "4096", (66, 80), False),
("r4名", "统计范围", (80, 94), False), ("r4范围标签", "本次开机", (80, 94), False),
("页脚", "第 2 页,共 2 页", (140, 160), False),
],
}
# 反向文本断言表:页名 -> [(名称, 期望**不出现**的串, y 带, 是否反显态)]
@@ -667,6 +754,26 @@ ABSENT = {
# 反过来正向断言"100"是没有意义的——它是"100V"甚至"10000V"的子串,
# 字形匹配器只保证 bbox 内干净、不检查词边界(实测在上一行的 10000V 上命中)
"sparam_edit": [("编辑态不打单位后缀", "100V", (38, 52), True)],
# ── 接线道 task-6:反向断言钉"分页不串行 / 记录源不串页"(同样不依赖参考图)──
# 运行报告两页互为反证:第 1 页不许出现只有第 2 页才有的行、反之亦然——分页窗口
# 一旦算错(比如 rows_per_page 与页脚页码不同源),只有一张图会露馅,这里两把都上。
# 五个记录页钉"空态页上不许出现别的页的时标串":SOE 页屏上有固定 3 条假记录,时标
# 2026-10-25(ui_w_soe 的显示假数据)。一旦有人图省事把记录页接到那份假数据上,
# 或把两端记录源映射表(simulator/main.c 的 s_sim_log_map 与 App/task/ui_task.c 的
# s_log_map)接错号,让这几页读到 SOE 的数据,屏上就会冒出这个时标——这条不依赖参考图就会响。
"runreport": [
("第 1 页不出现第 2 页的行", "发送帧数", (0, 160), False),
],
"runreport_p2": [
("第 2 页不出现第 1 页的行", "上电次数", (0, 160), False),
],
"accident": [("空态不串 SOE 假记录", "2026-10-25", (0, 160), False)],
"oper": [("空态不串 SOE 假记录", "2026-10-25", (0, 160), False)],
"alarm": [("空态不串 SOE 假记录", "2026-10-25", (0, 160), False)],
"start": [("空态不串 SOE 假记录", "2026-10-25", (0, 160), False)],
"yk": [("空态不串 SOE 假记录", "2026-10-25", (0, 160), False)],
}
W = H = 160
@@ -694,6 +801,16 @@ EXTRA = {
"comm_wait": ["--comm-nopump"],
}
# 接线道 task-6:记录 5 页在**各自独立的空目录**里跑(不共用回归的那个 tmp)。
# 诱因(实测,不是猜):模拟器把"人工操作留痕"镜像成了真记录——simulator/main.c 的
# sim_post_oper() 走 syslog_post(SYSLOG_OPER, ...) 落盘**当前工作目录**的 sim_oper.log;
# 而 60 页原本共用一个 tmp,clock_save / netcfg_save / sparam_save 这些"保存"态跑完之后
# sim_oper.log 已经攒了 3 条(192 B = 3×64 B)→ "操作记录"页读到的是真记录,
# 空态判据(第 0 行"无记录")根本拍不到。**判据本身没错,错在跑它的环境被前面的写路径
# 污染了**,所以给这 5 页各开一个空目录 = 现场"这些日志文件还不存在"的确定态;
# 其余 55 页环境一字不变(对存量 53 张黄金零影响,实测逐字节零漂移)。
FRESH_CWD = ("accident", "oper", "alarm", "start", "yk")
def run_sim(seq, out, cwd, extra=()):
"""在指定工作目录里跑一次无头截图。
@@ -867,8 +984,12 @@ def main():
# 1) 跑全部页面 + 文本级断言预检(先于像素比对/刷新:失败即中止,避免误刷参考)
shots = {}
for name, seq in PAGES:
shot = os.path.join(tmp, "shot_%s.bin" % name)
run_sim(seq, shot, tmp, EXTRA.get(name, ()))
cwd = tmp
if name in FRESH_CWD:
# 记录页的空态判据要求"日志文件此刻不存在",理由见 FRESH_CWD 上方说明
cwd = tempfile.mkdtemp(prefix="fresh_%s_" % name, dir=tmp)
shot = os.path.join(cwd, "shot_%s.bin" % name)
run_sim(seq, shot, cwd, EXTRA.get(name, ()))
shots[name] = open(shot, "rb").read()
n_pos = 0