Files
mini-openclaw-v2/scripts/test_prescreen_panel.cjs
qiaoqichaoandClaude Code 985e2f6a53 feat(v2): S1d 最薄界面——工作台内的材料集合导入面板
T02 收尾子卡。挂在既有 /xingbang-workbench「材料与问题」页内,**不新建路由**,
复用 workspace.css 既有 class(无新增样式表)。

- src/components/xingbang/ImportBatchPanel.tsx:登记清单 → 逐项上传 → 重试/取消 →
  冲突并列展示与裁定。浏览器端用 crypto.subtle 算 sha256 生成清单(服务端仍重算核对)
- src/lib/prescreen.ts:错误信封解包 + 契约类型(**手工对齐**,OpenAPI→TS 生成链
  未建设,已在文件头标注为临时)+ 服务端状态标签
- page.tsx 仅三处小改:导入面板、挂载面板、request() 改用 messageOf
  (兼容信封与既有 detail 的 string/array/object 三种形态,不丢既有信息量)

面向用户的诚实性约束(有源码守卫锁定):明确写出"未上传或未确认的文件不会进入
项目事实""不会按上传先后覆盖""不会自动挑一个";空批次用既有空状态,不绘制虚构行;
面板不含任何审批概率。

验证:
- npx tsc --noEmit 通过;npm run build 通过
- 新增 scripts/test_prescreen_panel.cjs(10 条源码守卫),已加入 verify.py 用例
- scripts/verify.py 10/10 PASS(exit 0)

**未验证**:面板未经浏览器端到端验证。它依赖客户端数据加载,SSR HTML 不含它,
且本项目没有浏览器自动化依赖。目前只有类型检查、构建与源码断言三层证据。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-29 18:14:14 +08:00

59 lines
3.4 KiB
JavaScript
Raw Permalink 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.
/**
* S1d 界面源码守卫。
*
* 这是**源码断言**,不是浏览器端到端测试(docs/v2/06-validation.md §2 已明确
* 现有 UI 脚本的性质)。它锁住的是可机械核对的约束:不新建路由、复用既有样式、
* 上传必须带批次标识、冲突裁定必须留痕、不得展示任何审批概率。
*/
const assert = require("node:assert/strict");
const fs = require("node:fs");
const path = require("node:path");
const root = path.resolve(__dirname, "..");
const read = (file) => fs.readFileSync(path.join(root, file), "utf8");
const panel = read("src/components/xingbang/ImportBatchPanel.tsx");
const workbench = read("src/app/xingbang-workbench/page.tsx");
const lib = read("src/lib/prescreen.ts");
// 1. 挂载在既有工作台内,不新建路由(docs/v2/04-ui-spec.md §1:不恢复已合并的旧页面)
assert.match(workbench, /import ImportBatchPanel from "@\/components\/xingbang\/ImportBatchPanel"/, "工作台应导入导入面板");
assert.match(workbench, /<ImportBatchPanel /, "工作台应渲染导入面板");
for (const banned of ["prescreen", "import-batch", "material-import"]) {
assert.ok(!fs.existsSync(path.join(root, "src/app", banned)), `不得为 S1 新建路由目录 src/app/${banned}`);
}
// 2. 复用既有样式,不新增样式表
assert.ok(!/^import .*\.css";/m.test(panel), "面板应复用 workspace.css 既有 class,不新增样式表");
// 3. 上传必须带批次标识(否则服务端无法回写条目状态)
assert.match(panel, /form\.append\("batch_id", batch\.id\)/, "上传必须提交 batch_id");
assert.match(panel, /form\.append\("item_id", itemId\)/, "上传必须提交 item_id");
// 4. 冲突裁定必须显式选择 + 填写说明,且未填说明时按钮禁用
assert.match(panel, /resolution_note: note/, "裁定必须提交 resolution_note");
assert.match(panel, /selected_evidence_ids: \[evidenceId\]/, "裁定必须显式选择来源");
assert.match(panel, /disabled=\{busy \|\| !note\.trim\(\)\}/, "未填裁定说明时不得可提交");
// 5. 必须向用户说明"未确认不入事实"与"冲突不覆盖"(BR-01 / BR-23 的用户可见面)
assert.match(panel, /未上传或未确认的文件不会进入项目事实/, "必须说明未确认不入事实");
assert.match(panel, /不会按上传先后覆盖/, "必须说明冲突不按上传先后覆盖");
assert.match(panel, /不会自动挑一个/, "必须说明系统不会自动挑选冲突来源");
// 6. 不得展示任何审批概率(BR-12 / AC-12:未校准即无概率)
assert.ok(!/通过率|probability|概率环/.test(panel), "S1 面板不得展示任何审批概率");
assert.ok(!/通过率|probability/.test(lib), "S1 客户端不得引入概率字段");
// 7. 不得在前端编造判定结果:值必须来自服务端字段
assert.ok(!/value:\s*["']?\d/.test(panel), "面板不得硬编码业务数值");
// 8. 客户端必须同时吃下两种错误形状,且不丢既有 detail 的信息量
assert.match(lib, /data\?\.error/, "客户端必须能解包统一错误信封");
assert.match(lib, /JSON\.stringify\(detail\)/, "既有 detail 数组形态不得丢信息");
// 9. 空状态不得绘制虚构行(UI Spec §3)
assert.match(panel, /ra-empty/, "空批次应使用既有空状态样式");
assert.match(panel, /尚无导入批次/, "空批次应给出明确的空状态文案");
console.log("prescreen-panel-ui: PASS");