You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

92 lines
6.1 KiB

5 hours ago
# -*- coding: utf-8 -*-
"""从统一 demo 生成《验收步骤清单.md》:逐 tab 提取联测步骤(按钮 + 预期说明),结果列留白。"""
import io, re, sys, html, pathlib
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
ROOT = pathlib.Path(__file__).resolve().parent
t = (ROOT / 'demo' / 'index.html').read_text(encoding='utf-8')
TAB_META = {
'user': ('A7-1 用户管理', '用户列表 / 统计出参 / 移交全链路 / 时间戳'),
'sync': ('A7-1-2 同步任务(二期票01)', '任务化契约 / 分页倒序 / 详情五块 / 设置读写与边界 / lastSyncTime 切表'),
'role': ('A7-2 角色管理', '统计四计数 / 批量增量分配 / copy / 启停校验 / 内置保护'),
'res': ('A7-2 权限点管理', '引用清单 / 停启 roundtrip / 禁删两段'),
'push': ('A7-3 方案推送规则', '状态机全链(草稿/发布/64029/64030/copy/64027)'),
'dedup': ('A7-3 项目查重规则', '发布与引用计数 / 64031 两路 / 64030 / 64033'),
'projrule': ('A7-3 项目规则', 'current 5 区块聚合 / 分区保存 / 64036 比例校验'),
'pool': ('A7-3 线索规则·线索池', '三类异人成员 / 导出导入 / 列表 / 清理'),
'poolrule': ('A7-3-4 公海规则「绑定商机(数量)」(二期票03)', '部门专用规则发布 / boundOppCount 增量 / 默认兜底 / 清理'),
'glog': ('A7-4 日志管理(二期票02 · crm-log)', 'AOP 采集 / 操作·登录·批量日志 / 结果文件 / 权限口径'),
'seed': ('A7-5 字典种子验证', 'opp_stage 06/07 + opportunity_status 4 值'),
'dgroup': ('A7-5 数据字典·分组管理(v3 契约)', '新建/编辑/启停/删除/设默认值(仅二级项)'),
'ditem': ('A7-5 数据字典·字典项管理(v3 契约)', '无键值自动编码 / 组内名称唯一 63007 / 复合子项 / 63013 禁停'),
'dtree': ('A7-5 数据字典·两级树', '一级列表 + 行内二级展开'),
'dref': ('A7-5 数据字典·引用计数联测', '客户引用 +1 / 换引用迁移 / 引用项禁删 63009 / 归档保留计数'),
}
def strip(h):
h = re.sub(r'<[^>]+>', ' ', h)
return re.sub(r'\s+', ' ', html.unescape(h)).strip()
out = []
out.append('# A7 后台管理验收步骤清单(a7-acceptance · 15 页全分区)\n')
out.append('- **被测对象**:`demo/index.html`(15 tab 统一版)× 测试环境 `https://ai.itc.vip/crm-api`')
out.append('- **使用方法**:双击打开 demo → 页头「uid 登录」(默认管理员罗伟健)→ 按下表逐 tab 从上到下点每个步骤按钮 →')
out.append(' 输出框**绿色(✅/提示)= PASS**,**红色(失败 + code=)= 候选缺陷** → 结果列填 PASS / FAIL,FAIL 的按《验收结果汇总.md》格式记缺陷。')
out.append('- **纪律**:数字类断言(条数/计数)随库内数据浮动,以**相对变化**为准;每 tab 最后的「清理」步骤务必执行,不留演示数据。\n')
for tab, label in re.findall(r'<button data-tab="([^"]+)"[^>]*>([^<]+)</button>', t):
sec_m = re.search(r'<section id="tab-' + tab + r'"[^>]*>(.*?)</section>', t, re.S)
if not sec_m:
continue
sec = sec_m.group(1)
meta = TAB_META.get(tab, ('', ''))
out.append(f'\n---\n\n## {label}{tab})· {meta[0]}\n')
if meta[1]:
out.append(f'> 覆盖:{meta[1]}\n')
steps = re.findall(r'<div class="step"><b>([^<]*)</b>(.*?)</div>', sec, re.S)
if steps:
out.append('| 步骤 | 操作 | 说明 / 预期 | 结果(PASS/FAIL) | 备注 |')
out.append('|---|---|---|---|---|')
for num, body in steps:
btns = re.findall(r'<button[^>]*>([^<]+)</button>', body)
hints = re.findall(r'<span class="hint">(.*?)</span>', body, re.S)
desc = ''.join(strip(h) for h in hints) or ''
out.append(f'| {strip(num)} | {" / ".join(strip(b) for b in btns) or ""} | {desc} | | |')
else:
btns = []
for b in re.findall(r'<button[^>]*>([^<]+)</button>', sec):
x = strip(b)
if x and x not in btns:
btns.append(x)
out.append('本页为主界面操作(无联测步骤面板),对照原型逐控件核对:\n')
out.append('可操作入口:' + ''.join(btns))
out.append('\n| 操作 | 预期 | 结果(PASS/FAIL) | 备注 |')
out.append('|---|---|---|---|')
out.append('| 逐控件操作并观察列表/弹窗反馈 | 与原型 A7 对应页一致(弹窗字段、错误码文案、列表列头) | | |')
out.append('''
---
## 争议留白(待产品/负责人确认,本轮不作为缺陷)
- [ ] 数据共享 3 A7-2-3 backup 草稿箱等原型正式化未纳入盘点与验收
- [ ] 职务下拉值域来源OA title 去重 vs 字典分组挂账待拍板
- [ ] 角色管理处理使用人员弹窗当前参与商机数计数口径未拍板
- [ ] OpportunityPoolRule 列表所属战队等冗余列 UI 确认后补
- [ ] 幻影挂账 3 端点POST /depts/save/depts/delete/users/admin-role原型无入口保留运维用途
- [ ] 项目规则阶段提醒区块原型自注待补充
- [ ] 全局日志采集覆盖面 = 写侧POST先行不采查询GET登录日志仅采退出钩子debug/token 不走登录采集点
## 已知形态说明(不算缺陷)
- 同步任务两态容忍测试环境钉钉凭据不可达时任务以 all_failed 终态落行或长时间 running均为正常形态
- lastSyncTime 口径 = 同步任务表最新成功行 endTime无成功行时为空
- 操作/登录/批量日志行与同步任务行 = 审计数据留存不删其余演示数据一律 e2d- 前缀 + 步骤面板末步清理
''')
p = ROOT / '验收步骤清单.md'
p.write_text('\n'.join(out), encoding='utf-8')
print('OK ->', p)
print('tabs:', len(re.findall(r'<button data-tab=', t)), '| steps rows:', sum(len(re.findall(r'<div class="step">', m)) for m in re.findall(r'<section id="tab-[^"]*"[^>]*>(.*?)</section>', t, re.S)))