Files
xiaotutongxue/scripts/check-manual.py
T
lovife 1f3c485ceb feat(role,scope)!: 角色与授权可配 + 需求收敛(4 角色 / 10 菜单 / 删两模块)
角色与授权(交接摘要 §一·三十五):
- 权限判定合并两个来源:内置角色按代码(BuiltinRole)、自定义角色按库
  (sys_role_permission)。实现放 module 层的 DbRoleGrantSource,security 只依赖
  接口 RoleGrantSource —— 否则角色服务要调 permissionChecker,两个包迟早成环
- 权限判定必须加缓存:此前是零 IO,而压测基线是"SQL 条数恒定"。缓存放 Redis,
  空结果也缓存(否则已删角色的 token 会把库打穿)、Redis 挂了退化成直读库、TTL 只兜底
- V18 建 sys_role.user_type(账号的 user_type 一直从角色反推,自定义角色不在代码映射里)
  与 sys_role_menu;8 个接口 + 错误码 40045;契约 119 -> 129
- 内置角色只读(权限码是前后端契约,做成可改 = 一次误操作就能把管理员锁在系统外);
  平台级能力两道防线(界面禁用 + 服务端 40301);防自锁;改完立即生效(写授权清缓存)
- RoleProvisioner 从"已存在就 continue"改成幂等回填 + 每日 03:20 定时任务 ——
  修的是"代码改了权限、已开通租户永远停在发放那一刻",这种漂移不报错也没测试会红
- scripts/e2e-m10-role.py 77/77

需求收敛(交接摘要 §一·三十六,本节的数字为准):
- 删副班主任 / 审核员两个内置角色(6 -> 4)、历史整理器(module/cleanup)、
  加入申请(module/join + 学生端 pages/join)、collect_task_org.deputy_user_ids 整列;
  审核范围三级回退 -> 两级,连带 6 个 mapper 的 LIKE '%,id,%' 分支
- V19 迁移处理存量:先解 sys_user_role 绑定再软删角色;账号只在"除这两个角色外没有
  别的角色"时才软删。必须迁而不能只删代码 —— 角色码删掉后 mergePermissions 返回空集,
  存量账号会"能登录、处处 40301",不抛异常不打日志
- 契约 129 -> 119、错误码 59 -> 54、权限码 30 -> 28、PC 菜单 12 -> 10、
  小程序页 10 -> 9、原型 32 -> 29 屏、E2E 39 -> 37 个(断言 1695 条)
- UserService.list 对不认识的角色码由"静默丢掉过滤条件"改成失败关闭
  (之前传个不存在的 roleCode 会返回全校账号,且看起来完全正常)
- 品牌元信息同步改名「深学在线」:pom 名称、/doc.html 标题、配置与启动类注释、
  存储自检探针内容;学生端 app 名与全局导航栏标题
2026-10-10 16:48:54 +08:00

91 lines
3.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- coding: utf-8 -*-
"""手册与代码的一致性检查(客服话术的可信度靠它)。
## 为什么要查这个
手册(`docs/10-用户手册与客服话术.md`)的价值**完全建立在
"手册里那句话 == 用户屏幕上那句话"**上 —— 客服照着它回答,
对不上就会开始自己编,那比没有手册更糟。
而**手册是文档、文案在代码里**:改一次代码文案,手册就静默失准,
且没有任何东西会红。这与"首页在说一件不真的事"(F-82)是同一类问题。
所以这里把它变成机械检查,与 `check-api-parity.py`(契约↔路由)、
`check-entity-columns.py`(实体↔DDL)并列 —— 都是"文档与代码是否还对得上"。
## 查两件事
1. 手册里引用的每个错误码(反引号包着的 5 位数)在 `ErrorCode.java` 里**确实存在**;
2. 手册里"客服会照着念"的那些提示文案在代码里**逐字存在**。
⚠️ 它**不检查**手册有没有漏掉新错误码 —— 那要靠人。
它拦的是"手册写了代码里没有的东西"(这会让客服查到一半卡住)。
跑法:python scripts/check-manual.py
"""
import io
import re
import sys
sys.stdout.reconfigure(encoding="utf-8")
manual = io.open('docs/10-用户手册与客服话术.md', encoding='utf-8').read()
codes_src = io.open('backend/xt-common/src/main/java/cn/tianbaotong/fill/common/api/'
'ErrorCode.java', encoding='utf-8').read()
# ① 码:三个捕获组 → 自己建索引
rows = re.findall(r'([A-Z_]+)\((\d{4,5}),\s*"([^"]*)"\)', codes_src)
declared_by_code = {code: (name, msg) for name, code, msg in rows}
print("ErrorCode 里声明了 %d 个码" % len(declared_by_code))
used = sorted(set(re.findall(r'`(\d{5})`', manual)))
print("手册引用了 %d 个码" % len(used))
bad = []
for c in used:
if c in declared_by_code:
name, msg = declared_by_code[c]
print(" ✓ %s %-24s %s" % (c, name, msg[:44]))
else:
bad.append(c)
print(" ✗ %s **ErrorCode 里没有这个码**" % c)
# ② 关键文案
# ⚠️ 2026-10 需求收敛:原列表里的「你已在名单中,请返回重新核验」与
# 「你已提交过申请,请耐心等待」两句属于**已删除的加入申请模块**
# (`module/join`,连同错误码 40037/40038/40039/40040/40042),
# 代码里已不存在 —— 因此从本清单移除,不要再加回来。
key_phrases = [
"没有找到你的信息,请核对后重试",
"操作过于频繁,请稍后再试",
"该信息已被登记",
"这份材料可能不是你的,请重新上传",
"已进入审核,需先撤回才能删材料",
"已通过终审,不可撤回",
"任务已截止、已归档或已暂停",
"驳回次数已达上限",
"存在不合格文件,禁止导出",
"你的材料被退回了",
"导出包已过期",
"这个学生还没扫码核对身份",
]
src_all = ""
import glob
for p in glob.glob('backend/**/*.java', recursive=True):
try:
src_all += io.open(p, encoding='utf-8').read()
except Exception:
pass
print("\n核对手册里引用的提示文案(%d 句):" % len(key_phrases))
missing = []
for ph in key_phrases:
if ph in src_all:
print(" ✓ %s" % ph)
else:
missing.append(ph)
print(" ✗ %s —— **代码里找不到这句**" % ph)
print("\n结果:错误的码 %d 个,找不到的文案 %d 句" % (len(bad), len(missing)))
sys.exit(1 if (bad or missing) else 0)