# 离线复核工作区

工作区提供测量记录、记录核查、人工核查、复核报告、修订对比、批量与交付、草稿七个视图。界面使用
MoonBit 核心完成解析与计算；浏览器负责选择文件、编辑文本、展示结果和保存草稿。
内置示例均为合成数据，结果只涉及靶病灶。

## 启动

在仓库根目录执行：

```sh
python scripts/build_browser.py
```

构建结果位于 `_build/browser/`。需要用本地 HTTP 服务打开，浏览器通常不允许从
`file:` 地址载入 ES 模块。各平台均可在仓库根目录运行：

```sh
python scripts/serve_browser.py --directory . --port 8765
```

随后打开 `http://127.0.0.1:8765/_build/browser/`。也可只服务构建目录：

```sh
python scripts/serve_browser.py --directory _build/browser --port 8765
```

后一命令对应 `http://127.0.0.1:8765/`。启动脚本只监听本机，固定 `.js` / `.mjs` 的
JavaScript 文件类型，避免 Windows 系统映射影响模块加载。发布候选浏览器包内也附带同一脚本。

所有运行资源都来自本地构建目录，没有在线字体、CDN 或远程计算服务。页面的
`connect-src 'none'` 限制主动网络连接。草稿与本地服务的来源地址关联，更换端口、
浏览器或用户配置后，不会自动共享同一份本机草稿。可通过草稿文件转移进度。

## 从测量到报告

在“查看合成示例”或导入窗口中，可选择多靶随访、缺测、采集标识变化、修订影响，
以及单靶入门模板。完整四例直接使用仓库中的合成输入，在构建时随本地模块打包。
“修订影响”会同时载入原始对照版本，可直接到“修订对比”中查看后续影响。

1. 点击“导入记录”，选择同一研究的 JSON 配置与 CSV 随访文件；也可先查看合成示例。
2. 在“测量记录”中编辑观察。基线资料按需展开；随访筛选只改变显示范围，不改变顺序或参与计算的记录。
3. 到“记录核查”查看待修正项和人工核查项。定位按钮会返回对应单元格或原始文件。
4. 检查通过后生成报告。界面展示靶病灶分类分布、总和趋势和参照值；完整报告保留每次测量与逐条件计算依据。
5. 按需导出输入、五种格式的报告，或准备摘要与完整证据打印视图。

CSV 的引号、换行和多行说明由现有 MoonBit 解析器处理。表格中的直径保持文本值，
不会四舍五入或把缺失值写成零。编辑会同步更新原始 JSON/CSV；保留内容与顺序，
不保证原文件的缩进、引号风格或换行编码保持不变。

格式可读但临床记录有误时，表格会保留有问题的值供修正。JSON 语法/字段类型，或
CSV 引号、表头、列数有误时，原文仍会保留，可以直接编辑后更新表格。人工核查项
与待修正项分开显示；NE 可以来自有效输入，不会被改成解析错误。

修改输入、恢复草稿或切换报告语言后，之前的报告和打印视图会立即撤下。重新生成后，
导出、趋势和打印均使用当前记录。异步读文件或生成输入标识期间发生的新修改，也不会
被旧操作的结果覆盖。

## 整次随访录入与管理

当前记录通过格式与结构检查后，可在“随访观察”中点击“新增随访”，填写编号、日期和
采集标识。先点击“检查随访信息”预览，再确认新增。工作区会按基线病灶逐项建立
“未测量”观察，直径和说明留空；请根据本次读片结果补充，不会自动沿用上次测量。

筛选到某次随访后，点击“管理随访”，可统一修改本次全部观察的编号、日期与采集标识。
测量值、观察状态与读片者说明保持原样。也可选择“移除此随访…”，检查移除范围后显式确认。
编号须唯一，日期保持现有顺序；工作区不会自动调整或排序。人工核查提示仍会保留。

“撤销修改”和“重做修改”适用于当前输入的表格、原文及整次操作。同一字段内连续输入
合并为一步，离开字段后重新计步；撤销后产生新修改会清除重做分支。恢复输入后需重新生成
报告，先前报告与交接预览不会重新启用。对照版本、语言和人工核查记录各自独立管理。

历史只存于页面内存，最多保留 40 步、总计 8 MiB 的输入快照；超限时释放较早记录。
刷新页面或重新载入示例、文件、草稿、会话、批量记录或交接包会重置历史，不能跨研究撤销。
需要跨会话保留时仍需显式保存或导出。原始文本保留与格式细节见[编辑契约](input-editing.md)。

### 按靶病灶录入本次观察

筛选到需要补充的随访，点击“录入本次观察”。窗口按基线顺序展示各靶病灶、器官组、
病灶类型和基线尺寸。已测量时填写直径，无法评价时填写原因；其余状态不保存直径或原因。
切换状态后，不适用的旧内容不会写入，检查预览会列出原观察与新观察，确认后再保存。

本次存在遗漏的基线病灶时，也会列为“未测量”，便于明确补充；不会复制其他随访的测量。
所有病灶一起通过核心检查后才会应用，超精度、缺少原因等问题会阻止保存。保存后可一步
撤销或重做，其他随访及研究 JSON 原文保持不变。编辑表单或更换随访会撤回旧预览。

## 保存与恢复

右上角“保存草稿”只在点击时写入本机，不会自动保存。草稿可包含尚未通过检查的输入。
刷新或再次打开页面后，在“草稿”中点击恢复。清除操作仅删除本工作区的专用草稿键，
不修改当前正在编辑的记录，也不清空其他网站或应用的数据。

草稿文件使用独立的版本化 JSON 容器，保留研究原文、CSV 原文、报告语言和保存时间。
容器必须完整且版本受支持，才会替换当前输入；损坏或不兼容的文件会给出提示，当前
记录和报告保持不变。载入有效容器后，内容仍要经过原有的记录核查。

草稿保存在浏览器的本地存储中，并非加密的病例管理系统。工作区示例和验收均使用
合成记录；实际使用者需自行管理设备、浏览器配置与文件的访问范围。

## 对照版本与修订影响

在“修订对比”中点击“设为对照版本”，可固定当前通过结构检查的原始输入。
继续在“测量记录”中修改，再点击“比较当前记录”，即可查看按随访与病灶编号对齐的
测量变化，以及后续总和、此前最低值、最低值来源和靶病灶分类受到的影响。
对照版本不会跟随表格修改。重新设置或清除对照由显式操作完成。

两侧都独立检查，任何一侧存在结构问题时不输出部分对比；研究标识、基线、采集
配置或有序靶病灶集合不同也不能比较。合法的 NE 保留其复核语义。空差异表示未发现
核心测量或评价变化，原文排版差异可能仍使输入标识不同。当前记录或语言修改后，
旧对比及导出入口立即撤回，需重新比较。对比可导出 JSON、Markdown 或 HTML。

导入另一份记录或普通草稿会清除对照版本，避免把不同记录意外组合。修订合成示例
会显式配套载入原始多靶记录作为对照。

## 保存与恢复复核会话

“导出复核会话”保存对照与当前两组研究 JSON / CSV 原文、报告语言和 UTC 保存时间。
尚未完成或尚未通过检查的文本也可保留；没有对照版本时 `before` 为 `null`。
会话不会保存可被误用的旧计算结果，载入后需重新比较或生成报告。

会话 v1 的 `kind` 为 `lesion-followup-session`。除 `sha256` 外，规范载荷按
`schema_version`、`kind`、`saved_at`、`language`、`before`、`current` 的顺序构造；
每组原文按 `study_json`、`followup_csv` 排列，使用 JavaScript `JSON.stringify` 的紧凑
编码，取其 UTF-8 字节的 SHA-256。载入时先检查全部字段与摘要，再替换工作区内容。
摘要核对内容完整性，不认证文件作者或来源。它与报告包的原始文件字节摘要用途不同。

损坏、未知版本、字段异常或摘要不符的文件保留当前记录和已生成结果。异步读取或
生成会话期间若记录已被编辑，该操作会停止应用旧内容。会话通过文件显式导出和导入，
本机草稿仍只保存当前记录；需要跨次保存对照关系时，应导出复核会话。

## 记录人工核查过程

在“人工核查”中点击“开始当前核查”，可基于当前通过结构检查的输入建立提示清单。
逐项标记已查看，填写核查备注，并在“本轮复核说明”记录依据、未决问题或交接信息。
可筛选全部、待核查或已查看。没有自动提示时仍可保存本轮说明，不会凭空生成核查项。

“已查看”只记录查看情况，不会移除原始提示、修复缺测、改变 NE 或其他靶病灶分类，
也不代表问题已解决。临床复核报告仍保留完整的核心提示与计算依据。

核查进度在点击“保存核查进度”后写入单独的本机副本。测量草稿与复核会话需分别保存。
刷新后先载入对应的原始输入，再点击“恢复本机核查”。也可导出核查 JSON，通过文件恢复。
容器、摘要、原始输入标识和核心提示均匹配后才会应用；损坏或不匹配的文件不覆盖现有内容。
清除本机副本不会删除页面内的记录，也不影响测量草稿。

修改原始输入后，旧核查记录保留为只读版本，可导出 JSON 备份；不能将它导出为当前输入的
复核说明。重新开始会为当前输入建立新的待核查清单；恢复完全相同的原文也可重新启用原记录。
切换报告语言不改变输入对应关系。输入标识使用原文，包括其排版和换行表示。

“导出复核说明 HTML”及“导出 Markdown”保存独立的人工核查说明，包含输入标识、全部原提示、
已查看与待核查状态、备注及时间。它与临床复核报告分别交付，不写入原有五文件报告包。
导出语言沿用“复核报告”的语言选择。格式、资源限制和完整性摘要契约见[核查记录说明](review-notes.md)。

## 完整交接与恢复

“批量与交付”顶部提供单份完整交接入口。当前输入通过检查后，点击“导出完整交接 ZIP”，
即可将两版原始输入、报告语言和五文件报告包一起保存。存在匹配的人工核查记录时，可选择
一并保存查看状态和备注；未勾选则明确不包含。交接包包含原始资料，应按原有资料权限保管。

接收时选择完整交接 ZIP，点击“检查交接包”。工作区会核对外层文件清单、会话及备注摘要，
验证原有报告包，并从当前输入重新生成全部五份报告文件进行比对。拼接了不同输入、缺件、
篡改或重算不一致的包会被拒绝，当前工作区保持原状。这里只预览核对后的元数据，不执行
收到的 HTML。对照原文会保留；未完成的对照需要在载入后另行核查和比较。

检查完成后，可先确认研究编号、基线、随访数、提示数、对照版本及人工核查进度，再点击
“载入已核对记录”。载入会同时替换页面的两版输入、报告语言和核查记录；包内没有备注时，
原页面的内存核查记录会清除。本机测量草稿和已保存的核查副本不会自动改写，需显式保存。
报告与修订结果在载入后重新生成。更换文件，或在预览后编辑输入、对照、语言、备注，都会
撤回旧载入入口，需重新检查。单纯核查文件不会自动覆盖正在进行的工作。

完整交接包与原有五文件报告 ZIP、批量报告 ZIP 不同。下方“核查收到的报告包”仍用于原有
报告格式；完整交接包应从顶部入口接收。结构与完整性契约见[交接格式说明](handoff.md)。

## 批量复核与报告交付

在“批量与交付”中选择从本工作区导出的复核会话 JSON，设置本批报告语言，再点击
“开始批量复核”。每批 1–20 份，每份最多 2 MiB。这些是浏览器资源限制，不是医学规则。
文件按选择顺序使用 `case-001` 等独立编号，同名文件也不会合并或覆盖。

每份会话先核对容器和 SHA-256，再复核其 `current` 输入。合法 NE 和人工核查提示仍可
生成报告；容器损坏、临床输入不合规或读取失败会独立列出，不阻断后续记录。对照版本
随会话保留，批量处理不自动执行修订比较。点击“打开记录”会显式载入该会话的两版原文，
并使用本批报告语言，可继续修正或比较。不会自动覆盖本机草稿。批量结果与当前编辑器
分别保留；修改单份记录不改写已经处理的批次。更换文件或重新运行会撤回上次批量输出。

成功记录可下载独立报告 ZIP；整批 ZIP 包含原有 MoonBit 渲染的 `index.json` / `index.html`
及每个成功编号下的五文件报告包。失败记录只进入索引。全部失败时仍可导出 JSON 索引。
解压整批 ZIP 后可打开 `index.html` 进入报告。单份“复核报告”生成后也可直接下载报告 ZIP；
编辑后旧报告入口会撤回。ZIP 使用未压缩存储、UTF-8 名称、CRC32 及固定时间，不引入库依赖。

在“核查收到的报告包”中选择单份或整批 ZIP。文件只在内存中读取，不展开到磁盘，
也不执行导入 HTML。单份五文件可位于根目录或同一目录；整批在根目录放导航索引，
每个报告目录分别核查。目录中的清单、固定四项报告、字节长度、SHA-256 与核心元数据
检查均复用 MoonBit `verify_bundle`，各目录分别给出结果。未知文件、缺件、损坏或不兼容
清单会拒绝。整批索引仅用于导航，不在单份清单的校验范围内。

支持 stored 与 DEFLATE（含数据描述记录）ZIP，要求 UTF-8 文件内容，非 ASCII 名称也须
使用 UTF-8 标志。不支持加密、分卷、ZIP64 或符号链接。归档最多 64 MiB、128 项、20 份
报告；单项解压最多 16 MiB，总解压最多 64 MiB，流式解压超过声明大小即停止。路径中的
绝对路径、父目录、反斜线、控制字符及 Windows 保留名称被拒绝，重复名称和大小写冲突也
会拒绝。DEFLATE 需要浏览器支持 `DecompressionStream("deflate-raw")`，否则提示使用 stored ZIP。

完整性检查不认证作者或文件来源，不代替临床评价，也不重新证明报告中的每项医学分类。
浏览器导出的原始输入摘要指传入字符串的 UTF-8 字节；初次文件读取时已丢失的 BOM 或
无效编码不能恢复。核查 ZIP 不修改当前测量记录、草稿或修订对照。

## 查找观察与核查入口

随访观察表支持按病灶、器官、日期、状态及读片者说明搜索，可与随访选择组合使用。
多个关键词用空格分隔，需同时匹配；搜索忽略大小写及全角字符差异，不修改原始编号。
下方显示匹配条数，没有结果时可点击“清除筛选”。筛选仅影响表格显示，报告仍包含全部随访。
重新载入、撤销或应用整次录入后，搜索条件重置。

有效输入的记录核查与人工核查提示提供“录入本次观察”入口，自动选中对应随访，
并聚焦相关病灶的直径、原因或状态。基线靶病灶缺少观察行时，表单仍以“未测量”展示。
打开表单不会标记提示已查看，也不会修改备注；保存前仍需检查并确认预览。
输入变化后，原版本核查记录只供查阅，录入入口停用。结构性错误继续通过“前往对应记录”修正。

## 打印与追溯

“摘要打印”和“完整证据打印”在页面内打开预览，无需弹窗或外部页面。
确认后使用打印按钮，或按 Ctrl+P；也可下载独立打印 HTML 后使用浏览器打印。

两种布局使用相同的研究编号、基线日期和当前输入 SHA-256 标识。标识是研究原文与
CSV 原文组成的有序字符串数组经 JSON 编码后的 UTF-8 字节摘要；它用于对应这次输入，
与报告包中原始文件字节摘要的表示方式不同。摘要屏幕视图可以跳转到同次完整证据，
打印稿保留研究信息和标识，便于与完整稿逐项对照。

布局按 A4、12 mm 页边距设计。摘要仅打印随访汇总；完整稿包括趋势、测量台账、
原始观察、计算条件和范围说明。长表格允许分页并重复表头；长说明可换行，SVG 在页宽内缩放。
操作区和编辑控件不进入打印内容。不同浏览器或打印机可能使用不同字体与分页策略，
打印前仍可在系统预览中确认纸张与缩放设置。

## 设计与验收

信息结构参考了 [Linear 项目工作区](https://linear.app/docs/projects) 的分区与上下文组织，
以及 [Stripe 的界面设计指南](https://docs.stripe.com/stripe-apps/design) 对主要操作、详情视图
和一致组件的处理方式。导航、图标、样式与文案均在本仓库实现，没有引入第三方运行依赖。

自动验收命令为 `python scripts/acceptance.py`。除原有四后端核心测试与 CLI 对比外，
还覆盖编辑后导出重读、多行 Unicode CSV、无效值保留、草稿版本、输入标识独立校验、
打印证据链接和 36 次随访的长记录。浏览器与分页检查记录见 [验收说明](acceptance.md)。
