import fs from 'node:fs' import path from 'node:path' const root = path.resolve('reports/guide-closure-20260910') const phases = ['create','edit','reader','missing','content','revision','templates','layout','api','offline','final-document','export','resources'] const runs = phases.map(phase => ({ phase, ...JSON.parse(fs.readFileSync(path.join(root, `${phase}.json`), 'utf8')) })) const checks = runs.flatMap(run => run.checks.map(check => ({ phase:run.phase, ...check }))) const artifacts = JSON.parse(fs.readFileSync(path.join(root, 'artifact-validation.json'), 'utf8')) const fixes = [ ['不存在的工程地址自动新建', 'runtime.ts', '不存在 ID 明确报错,返回列表选择,避免查看操作创建脏数据。', 'missing'], ['列表默认排序及重置', 'GuideProjectList.vue / content-lists.js', '统一按创建时间倒序;更新旧工程不应改变默认顺序。', 'templates / layout'], ['只读用户无法选择导出和阅读控件', 'ofd-v4.js', '放行导出格式、页码、缩放、搜索等阅读控件;OFD 导出不再尝试保存草稿。', 'reader'], ['狐狸三维视口被环境雾完全遮住', 'ofd-viewport.js', '单模型加载清除车间雾;加载场景仍使用场景自身环境配置。', 'revision / offline'], ['默认模型相机距离不适配真实模型尺寸', 'ofd-document.js', '缺省相机走自动取景,保留用户明确保存的相机位置。已有显式相机不批量覆盖。', 'final-document / regression'], ['新建继承演示工程版本、反馈和装备参数', 'ofd-v4.js', '新工程清空演示业务记录、零件、技术参数与来源文件;模板章节按原模板生成。', 'templates'], ['开发环境导出的离线三维包加载失败', 'ofd-offline-runtime-assets.js', '打包 Three.js 和解码器原始源码,消除 Vite 改写后的开发路径。', 'offline / artifact-validation'], ['长标题、公式间距与动画秒数版式', 'ofd-layout.js', '缺省长标题自适应,公式后增加必要间距,动画时间保留两位小数。', 'PDF 四页目视 / regression'], ['反馈示例固定引用不存在的步骤', 'ofd-v4.js', '默认反馈示例使用当前工程的实际步骤,避免新建工程执行示例直接 404。', 'api:submit-feedback 201'], ] // 通过只表示这里写明的观察范围,不代表正式业务链路验收。 const coverage = [ ['列表','列表加载、编号搜索、重置、创建时间排序','本地通过','templates / layout','编辑旧记录后的多记录排序组合未单独量化。'], ['列表','项目详情、状态、版本入口','部分覆盖','代码审查 + publish 截图','统计是本地数据,不能作为教学统计。'], ['列表','删除及所有批量/权限组合','待补验证','代码审查','未删除用户工程;未对每一种授权组合做全矩阵测试。'], ['创建','空白向导、基本信息、建档','本地通过','create','正式后台不存在该新工程。'], ['创建','四类模板静态/动态预览','本地通过','templates','实际逐个打开并切换目录。'], ['创建','模板 PDF、OFD 下载和选模板创建','本地通过','templates','下载实测第一类;新建实测第四类(4 章 9 步)。'], ['创建','模板来源与平台模板管理联动','待确认改造','静态 OFD_CONTENT_TEMPLATES','当前不是后台模板库。'], ['创建','演示历史、反馈、参数隔离','修复通过','templates','仅修复新建,不清理用户既有文档。'], ['分析规划','资料来源、需求规格、构建计划导出','部分覆盖','02-planning / export','Markdown 下载已测;专业内容自动分析质量未验收。'], ['分析规划','多装备、多层级、关键步骤覆盖','待业务验收','原始 DOCX 对照','狐狸、卡车为功能夹具,不能证明真实维修覆盖率。'], ['编辑','步骤属性、保存、刷新重开','本地通过','edit','仅在同一测试浏览器项目空间持久化。'], ['编辑','新步骤、续页、复制、撤销重做','本地通过','edit','章节及步骤所有拖动组合未穷举。'], ['编辑','表格单元格、合并拆分、边框','本地通过','layout','填写后重开检查;未对所有样式排列组合做测试。'], ['编辑','自由文本块、矩形标注','本地通过','layout','自由排版允许用户自行移动重叠;未自动约束所有自由布局。'], ['编辑','公式输入、说明、关联区排版','修复通过','content / regression / PDF','两个公式回归与实际 PDF 检查。'], ['编辑','字体、纸张、页眉页脚、所有标注形状','部分覆盖','属性面板巡检与源码','不是每个属性都做了写入、重开、导出三重验证。'], ['资源','本地 GLB 导入、绑定步骤','本地通过','edit / revision','09-Fox.glb、08-CesiumMilkTruck.glb。'], ['资源','后台模型制作/场景制作资源选择','待确认改造','本地 platformModels / 场景目录','不能声称使用了之前在服务端创建的两个场景。'], ['资源','单模型显示、取景、截图、动画','修复通过','revision / final-document','实际图像和帧差验证,截图保存后重开保留。'], ['资源','本地视频导入、播放、截帧保存','本地通过','resources','使用 2 秒测试视频;不代表真实维修内容验证。'], ['资源','音频、资料包、损坏模型、存储配额','待补验证','导入代码审查','未对全部格式和存储异常做实际测试。'], ['资源','模型热点、部件聚焦、三维与步骤语义关联','部分覆盖','属性面板 + 离线观察操作','专业热点与真实装备语义尚需专项验证。'], ['预览','静态版式、动态步骤搜索与跳转','本地通过','layout / templates','在线预览位于本地编辑器。'], ['预览','播放、暂停/重播、观察控制','本地通过','revision / offline','两模型动画帧改变;离线观察按钮逐个执行。'], ['权限','管理员只读、导出不修改文档','修复通过','reader(实际 admin 会话)','编辑使用 root;未把三角色全接口授权矩阵当作已验证。'], ['权限','账号间工程隔离、数据范围','待确认改造','共享本地存储命名空间','正式数据应以现有后台权限和用户范围为准。'], ['发布','预检清单、草稿预览、发布面板','本地通过','08-preflight / 09-publish-panel','预检通过不等于后端发布成功。'], ['发布','发布、修订、旧快照、新版本、撤回','本地通过','content / revision','现状均为本地生命周期;没有实际发送后台发布请求。'], ['发布','后台版本、OFD/离线交付物原子发布','待确认改造','ContentProjectService','后台已要求 GUIDE 的 OFD + OFFLINE_HTML ZIP;现有页面未串联。'], ['发布','审核策略','代码确认','ContentProjectService GUIDE 分支','审核按现有配置可选;不引入强制审核新规则。'], ['导入导出','工程 JSON、导入恢复、非法 JSON','本地通过','revision / resources','JSON 不是完整资产备份;模型字节仍在 IndexedDB。'], ['导入导出','实际 PDF 下载及四页版式','修复通过','final-pdf-page-1 至 4','中文、目录、模型图、公式目视检查;字体存在替代。'], ['导入导出','实际 OFD ZIP/XML','本地通过','artifact-validation','未用第三方原生 OFD 阅读器验证标准一致性或签章。'], ['导入导出','离线 ZIP、GLB 轻量化、运行时','修复通过','offline / artifact-validation','卡车导出按已有逻辑压缩;结构与动画保留,非原字节复制。'], ['离线','断开公网/业务服务后本地启动阅读','本地通过','offline','Windows + Node.js 本地静态服务;没有依赖外站的请求。'], ['离线','手机尺寸、麒麟、真实移动设备','部分覆盖','23-offline-mobile','390×844 可显示,按钮换行与三维取景仍偏拥挤;未测实机、麒麟。'], ['教学','学员指导书列表、正式阅读内容','待确认改造','正式内容查询 + teaching 接口查询','不能从本地发布进入正式教学阅读。'], ['教学','收藏、个人笔记、检索、进度','待确认改造','原始需求与离线入口核对','离线缺个人笔记/收藏入口;需与在线用户身份及进度方案一并实现。'], ['教学','学习统计、报表、训练/考试联动','待确认改造','后端 teaching/guides 与原始需求','未因后台存在接口而判为全链路通过。'], ['接口','九个本地契约操作与反馈样例','修复通过','api / revision','八个本地请求逐个执行;生命周期通过发布 UI 单独实测。'], ['接口','第三方 HTTP 调用、鉴权、正式反馈','待确认改造','api:零真实业务 HTTP 请求','显示 /api/ofd 不代表服务端真实提供该接口。'], ['质量','构建、单元回归、浏览器异常','通过','build 及 20 项测试','选定最终 E2E 阶段无 pageerror;不包含早期定位脚本失败。'], ['质量','三主题、键盘、长文档、并发和性能指标','待补验证','本轮边界','未验证所有组合;不能宣称 <1s / ≥25fps / ≥99% / ≤10s 已达标。'], ] const proposals = [ ['A:编辑与正式内容闭环(优先)','保留现有编辑器,将列表、工程保存、模板/模型/场景选择、权限和版本操作对接现有 content 接口。服务端为数据真值;明确迁移本地工程和 IndexedDB 文件,不能静默覆盖。发布时提交 OFD 和离线 ZIP,并遵循现有可选审核设置。','验收:新建→编辑→刷新/换浏览器→发布→旧版本不变→撤回;正式数据库与界面一致,其他账号按权限可见。'], ['B:教学阅读闭环','衔接现有教学指导书、阅读记录和反馈接口;补齐个人笔记、收藏、学习进度与统计。离线笔记是否回传及冲突处理需要与在线范围一起定。','验收:教员发布→学员阅读→记录/笔记/反馈保存→教员统计可查询;账号隔离生效。'], ['C:对外接口真实联调','将当前本地契约自检与真实 HTTP 接口对齐,文档标明真实路径、参数、错误及授权;沿用现有平台认证机制,不新增密钥文件或独立服务。','验收:从独立客户端调用,读取/修改/反馈真实工程,未授权请求被拒绝。'], ] const pictures = [ ['19-list-created-order.png','新建模板工程与创建时间排序'],['01-create-wizard.png','空白创建向导'],['02-planning.png','资料与规划'],['17-template-preview.png','模板结构预览'], ['27-final-fox.png','狐狸真实模型显示与取景'],['28-final-truck.png','卡车真实模型显示与取景'],['29-video-poster.png','视频播放与当前帧海报'],['30-invalid-import.png','非法工程导入保留原文档'], ['24-table-edit.png','表格编辑测试(自由块为测试内容)'],['25-markup.png','矩形标注'],['26-interactive-search.png','动态阅读搜索'],['16-withdrawn.png','本地版本撤回'], ['20-api-local.png','接口自检:实际仍为本地调度'],['21-offline-reading.png','离线步骤阅读'],['22-offline-model-0.png','离线狐狸三维'],['22-offline-model-1.png','离线卡车三维'],['23-offline-mobile.png','手机尺寸观察:仍有拥挤'], ...[1,2,3,4].map(n=>[`final-pdf-page-${n}.png`,`最终 PDF 第 ${n} 页`]), ] const summary = {date:'2026-09-10',conclusion:'未完全闭环;本地编辑与导出路径完成修复验证,正式内容、教学和对外 HTTP 接入待确认',environment:{web:'http://127.0.0.1:6180',gateway:6100,browser:'Edge headless / Playwright',viewport:'1920×1080;390×844 观察',accounts:'root 编辑、admin 只读(不含凭据)'},pass:checks.filter(c=>c.status==='PASS').length,fail:checks.filter(c=>c.status==='FAIL').length,unitTests:20,artifactChecks:artifacts.checks,fixes,coverage,proposals,runs} fs.writeFileSync(path.join(root,'summary.json'),JSON.stringify(summary,null,2)) const esc = s => String(s??'').replace(/[&<>"']/g,c=>({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c])) const table = (heads,rows) => `
${heads.map(x=>``).join('')}${rows.map(row=>`${row.map(x=>``).join('')}`).join('')}
${esc(x)}
${esc(x)}
` const html=`作业指导闭环检查 · 20260910

作业指导模块:闭环检查与修复报告

2026-09-10 · 资料 → 原型 → 设计 → 开发 → 测试

结论:未完全闭环。本地编制、三维/视频预览与导出已完成本轮验证;实际页面仍保存到浏览器本地库,尚未连通正式内容发布、教学阅读及对外 HTTP 接口。不能以本地“已发布”认定全系统发布成功。

${summary.pass} 项 E2E 断言通过${summary.fail} 项需求断言未满足20 项回归通过6 项交付物检查通过构建通过

未满足的 5 项中,4 项重复印证正式内容/教学链路缺失,1 项为离线个人笔记和收藏入口缺失。通过项含“确认现状”的断言,不能直接换算为产品完成率。

1. 资料、原型与设计核对

原始依据:文档/桥梁装备“数字车间”资源建设需求参数.docx。覆盖内容分析规划、标准模板、排版与媒体关联、PDF/离线交付、版本更新、教学阅读、个人记录、反馈和统计。未将未阅读的其他 PDF 算作本轮依据。

正式路由经 LegacyGuidePageView.vue → runtime.ts → ofd-v4.js 托管原型。工程存储为带命名空间的本地 ContentListStore(seed:false),资源字节在 IndexedDB;模板和平台资源选择仍使用本地实现。后台已有 content projects、guide templates、teaching guides 接口,现状是前后两条实现未衔接。

测试创建了空白狐狸文档和模板卡车文档;狐狸文档中加入卡车作为第二个模型步骤,对两种模型验证导出与离线阅读。由于服务端场景资源没有接通,本轮直接导入本地 GLB,不能声称走通了之前正式创建的狐狸/卡车场景引用。

小修保持原交互和文档结构;不重建编辑器、不新增独立服务、不改 DDL。本轮不提交 Git。

2. 开发修复

${table(['问题','文件','处理','验证'],fixes)}

3. 全模块功能覆盖与边界

按功能入口建立 ${coverage.length} 项检查矩阵。“部分覆盖”和“待补验证”明确保留,不表示已跑过所有按钮与组合。

${table(['范围','功能点','结论','证据','边界'],coverage)}

4. 需要确认的较大调整

建议按 A → B → C 实施,复用现有后端和编辑器。以下尚未实施,避免在本次 bugfix 中静默改变存储、权限和发布规则。

${table(['范围','具体实施','验收闭环'],proposals)}

另有后续验证项:移动窄屏按钮与取景拥挤、完整主题/键盘矩阵、原生 OFD 阅读器、麒麟、长文档与性能压力测试。真实装备内容覆盖率及专业维修正确性需业务资料与实际装备验收。

5. 交付文件与复核方法

下载实测 PDF · 下载 OFD · 下载离线 ZIP · 下载工程 JSON · 需求规格 · 构建计划 · 完整 JSON 报告

离线 ZIP 完整解压后用其 Windows 启动脚本运行,需要已有 Node.js,通过本机 HTTP 打开,不能直接 file://。运行时和两个 GLB 均在包内,无公网或业务 API 依赖。OFD 已检查 ZIP/XML,PDF 四页已渲染核对;未宣称第三方 OFD 认证,PDF 字体跨平台一致性未验证。

测试数据保留在隔离的自动化浏览器空间,不在用户日常浏览器或服务端列表中。工程 JSON 含资源引用,不含所有模型原字节,导入编辑时需重新选择本地素材;离线 ZIP 是可独立复核的阅读交付物。下载内容使用测试文字,不能用于实际维修操作。

${table(['交付物检查','结果','说明'],artifacts.checks.map(c=>[c.name,c.status,c.detail]))}

6. 实际截图

点击查看原图。截图用于证明对应操作,含测试自由文本/标注的页面不作为最终排版模板。

${pictures.map(([file,title])=>`
${esc(title)}
${esc(title)}
`).join('')}

7. 测试明细

环境:Windows、Edge headless、Playwright,1920×1080;前端 6180,经 Gateway 6100;root 编辑、admin 只读。离线包通过隔离的 18766 本地静态服务运行并阻断其他主机请求。未将浏览器登录凭据写入报告。

命令:node tools/guide-closure-live.mjs <phase>(多阶段顺序执行,不能并发共享浏览器状态);python tools/guide-artifact-check.pynode --test scripts/guide-legacy-closure.test.mjs;现有 5 个 guide 测试脚本(17 项);pnpm run build(含 vue-tsc 和构建后校验)。新旧单元测试共 20 项通过,构建完成,仅既有 chunk size 提示。

早期脚本定位失败、重复运行造成的选择器歧义、Playwright storageState 无法恢复 Blob 原型,都未作为产品缺陷统计;实际模型测试通过界面重新导入,再在同一上下文刷新验证持久化。原始中间记录保留用于追溯,最终统计只采用下面选定阶段。

${table(['阶段','断言','结果','说明'],checks.map(c=>[c.phase,c.name,c.status,c.detail]))}

最终选定阶段 pageerror 总数:${runs.reduce((n,r)=>n+r.errors.length,0)}。真实 HTTP 业务写请求为零是尚未接入的证据,而不是接口性能验证。

` fs.writeFileSync(path.join(root,'index.html'),html) console.log(JSON.stringify({pass:summary.pass,fail:summary.fail,coverage:coverage.length,screenshots:pictures.length}))