{ "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": 73, "fail": 5, "unitTests": 20, "artifactChecks": [ { "name": "PDF 四页可解析且每页含文本", "status": "PASS", "detail": "4 pages" }, { "name": "OFD ZIP 完整、入口和 XML 可解析", "status": "PASS", "detail": "9 XML files; 未使用第三方 OFD 阅读器认证" }, { "name": "离线 ZIP 完整", "status": "PASS", "detail": "16 files" }, { "name": "离线脚本没有 Vite 开发缓存引用", "status": "PASS", "detail": "" }, { "name": "离线狐狸和卡车 GLB 结构及动画保留", "status": "PASS", "detail": "导出按现有逻辑轻量化,卡车从 369980 缩至 318276 字节;非原文件逐字节复制。实际渲染和动画另由浏览器验证。" }, { "name": "离线包含本地 Three.js 和解码器", "status": "PASS", "detail": "" } ], "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" ] ], "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 已达标。" ] ], "proposals": [ [ "A:编辑与正式内容闭环(优先)", "保留现有编辑器,将列表、工程保存、模板/模型/场景选择、权限和版本操作对接现有 content 接口。服务端为数据真值;明确迁移本地工程和 IndexedDB 文件,不能静默覆盖。发布时提交 OFD 和离线 ZIP,并遵循现有可选审核设置。", "验收:新建→编辑→刷新/换浏览器→发布→旧版本不变→撤回;正式数据库与界面一致,其他账号按权限可见。" ], [ "B:教学阅读闭环", "衔接现有教学指导书、阅读记录和反馈接口;补齐个人笔记、收藏、学习进度与统计。离线笔记是否回传及冲突处理需要与在线范围一起定。", "验收:教员发布→学员阅读→记录/笔记/反馈保存→教员统计可查询;账号隔离生效。" ], [ "C:对外接口真实联调", "将当前本地契约自检与真实 HTTP 接口对齐,文档标明真实路径、参数、错误及授权;沿用现有平台认证机制,不新增密钥文件或独立服务。", "验收:从独立客户端调用,读取/修改/反馈真实工程,未授权请求被拒绝。" ] ], "runs": [ { "phase": "create", "checks": [ { "name": "通过界面从空白模板创建指导书", "status": "PASS", "detail": "" }, { "name": "创建调用正式内容接口", "status": "FAIL", "detail": "当前页面使用浏览器本地工程库" }, { "name": "新建工程出现在正式后端列表", "status": "FAIL", "detail": "" } ], "errors": [], "requests": [] }, { "phase": "edit", "checks": [ { "name": "步骤标题、说明、工具、安全、验收编辑保存", "status": "PASS", "detail": "" }, { "name": "刷新后恢复已保存的本地内容", "status": "PASS", "detail": "" }, { "name": "新增步骤后保存", "status": "PASS", "detail": "" }, { "name": "正文续页和复制页面保存", "status": "PASS", "detail": "" }, { "name": "撤销复制恢复页数", "status": "PASS", "detail": "" }, { "name": "重做复制恢复页数", "status": "PASS", "detail": "" }, { "name": "导入真实 Fox.glb 文件并登记本地资源", "status": "PASS", "detail": "" } ], "errors": [], "requests": [] }, { "phase": "reader", "checks": [ { "name": "查看角色的正文编辑控件禁用", "status": "PASS", "detail": "" }, { "name": "查看角色可以使用导出菜单", "status": "PASS", "detail": "" }, { "name": "查看角色可以使用页码和缩放", "status": "PASS", "detail": "" }, { "name": "只读用户实际导出 OFD 且不修改工程", "status": "PASS", "detail": "" } ], "errors": [], "requests": [] }, { "phase": "missing", "checks": [ { "name": "访问不存在的指导书不会自动新建", "status": "PASS", "detail": "" } ], "errors": [], "requests": [] }, { "phase": "content", "checks": [ { "name": "公式与说明保存", "status": "PASS", "detail": "" }, { "name": "发布保存本地正式版本", "status": "PASS", "detail": "" } ], "errors": [], "requests": [] }, { "phase": "revision", "checks": [ { "name": "修订不改变旧的正式版本快照", "status": "PASS", "detail": "" }, { "name": "工程 JSON 导入恢复步骤与资源关联", "status": "PASS", "detail": "" }, { "name": "狐狸动画真实改变渲染帧", "status": "PASS", "detail": "" }, { "name": "狐狸截取当前角度保存纸面图片", "status": "PASS", "detail": "" }, { "name": "卡车动画真实改变渲染帧", "status": "PASS", "detail": "" }, { "name": "卡车截取当前角度保存纸面图片", "status": "PASS", "detail": "" }, { "name": "新修订再次发布并留存历史版本", "status": "PASS", "detail": "" }, { "name": "撤回本地正式版本", "status": "PASS", "detail": "" } ], "errors": [], "requests": [] }, { "phase": "templates", "checks": [ { "name": "四类模板列表", "status": "PASS", "detail": "" }, { "name": "模板 1 静态版式预览", "status": "PASS", "detail": "" }, { "name": "模板 1 动态目录切换", "status": "PASS", "detail": "" }, { "name": "模板下载 pdf", "status": "PASS", "detail": "" }, { "name": "模板下载 ofd", "status": "PASS", "detail": "" }, { "name": "模板 2 静态版式预览", "status": "PASS", "detail": "" }, { "name": "模板 2 动态目录切换", "status": "PASS", "detail": "" }, { "name": "模板 3 静态版式预览", "status": "PASS", "detail": "" }, { "name": "模板 3 动态目录切换", "status": "PASS", "detail": "" }, { "name": "模板 4 静态版式预览", "status": "PASS", "detail": "" }, { "name": "模板 4 动态目录切换", "status": "PASS", "detail": "" }, { "name": "选用模板真正生成章节步骤", "status": "PASS", "detail": "" }, { "name": "新文档不混入演示版本和反馈", "status": "PASS", "detail": "" }, { "name": "新文档不混入其他装备参数与来源", "status": "PASS", "detail": "" }, { "name": "列表默认按创建时间倒序", "status": "PASS", "detail": "" } ], "errors": [], "requests": [] }, { "phase": "layout", "checks": [ { "name": "插入表格、填写单元格、合并拆分与边框保存", "status": "PASS", "detail": "" }, { "name": "插入正文自由块后保存", "status": "PASS", "detail": "" }, { "name": "二维框标注保存", "status": "PASS", "detail": "" }, { "name": "动态阅读检索步骤", "status": "PASS", "detail": "" }, { "name": "表格、自由块、二维标注重开后保留", "status": "PASS", "detail": "" }, { "name": "列表按编号检索", "status": "PASS", "detail": "" }, { "name": "重置恢复创建时间排序", "status": "PASS", "detail": "" } ], "errors": [], "requests": [] }, { "phase": "api", "checks": [ { "name": "对外接口展示九个操作", "status": "PASS", "detail": "" }, { "name": "本地接口调度 list-projects 返回成功", "status": "PASS", "detail": "200\nGET /api/ofd/projects\n10 ms\n{\n \"success\": true,\n \"data\": {\n \"total\": 3," }, { "name": "本地接口调度 get-project 返回成功", "status": "PASS", "detail": "200\nGET /api/ofd/projects/OFD-mtub76ed-01\n8 ms\n{\n \"success\": true,\n \"data\": {\n" }, { "name": "本地接口调度 update-step 返回成功", "status": "PASS", "detail": "200\nPUT /api/ofd/projects/OFD-mtub76ed-01/steps/step-01\n26 ms\n{\n \"success\": tru" }, { "name": "本地接口调度 register-resource 返回成功", "status": "PASS", "detail": "201\nPOST /api/ofd/projects/OFD-mtub76ed-01/resources\n35 ms\n{\n \"success\": true,\n" }, { "name": "本地接口调度 collect-resources 返回成功", "status": "PASS", "detail": "201\nPOST /api/ofd/projects/OFD-mtub76ed-01/collect\n44 ms\n{\n \"success\": true,\n " }, { "name": "本地接口调度 inspect 返回成功", "status": "PASS", "detail": "200\nPOST /api/ofd/projects/OFD-mtub76ed-01/inspect\n9 ms\n{\n \"success\": true,\n \"" }, { "name": "本地接口调度 delivery-manifest 返回成功", "status": "PASS", "detail": "200\nPOST /api/ofd/projects/OFD-mtub76ed-01/delivery-manifest\n6 ms\n{\n \"success\":" }, { "name": "本地接口调度 submit-feedback 返回成功", "status": "PASS", "detail": "201\nPOST /api/ofd/projects/OFD-mtub76ed-01/feedback\n25 ms\n{\n \"success\": true,\n " }, { "name": "接口面板未发送真实 HTTP 业务请求", "status": "PASS", "detail": "这里通过本地函数调度,需要接入正式 API 才可外部调用" } ], "errors": [], "requests": [] }, { "phase": "offline", "checks": [ { "name": "离线包章节步骤可以阅读与切换", "status": "PASS", "detail": "" }, { "name": "离线模型 1 动画可播放", "status": "PASS", "detail": "" }, { "name": "离线模型 1 观察操作可执行", "status": "PASS", "detail": "" }, { "name": "离线模型 2 动画可播放", "status": "PASS", "detail": "" }, { "name": "离线模型 2 观察操作可执行", "status": "PASS", "detail": "" }, { "name": "断开公网和业务服务后没有外部依赖请求", "status": "PASS", "detail": "" }, { "name": "离线个人批注与收藏入口", "status": "FAIL", "detail": "当前离线阅读器未提供原始需求中的个人笔记、收藏和学习进度回传" } ], "errors": [], "requests": [] }, { "phase": "final-document", "checks": [ { "name": "狐狸按实际尺寸取景后保存", "status": "PASS", "detail": "" }, { "name": "卡车按实际尺寸取景后保存", "status": "PASS", "detail": "" }, { "name": "两个模型的取景图片重开后保留", "status": "PASS", "detail": "" } ], "errors": [], "requests": [] }, { "phase": "export", "checks": [ { "name": "导出 project 下载文件", "status": "PASS", "detail": "" }, { "name": "导出 requirement 下载文件", "status": "PASS", "detail": "" }, { "name": "导出 plan 下载文件", "status": "PASS", "detail": "" }, { "name": "导出 pdf 下载文件", "status": "PASS", "detail": "" }, { "name": "导出 ofd 下载文件", "status": "PASS", "detail": "" }, { "name": "导出 offline 下载文件", "status": "PASS", "detail": "" } ], "errors": [], "requests": [] }, { "phase": "resources", "checks": [ { "name": "导入本地视频并在原生播放器实际播放", "status": "PASS", "detail": "" }, { "name": "视频当前帧海报保存到步骤", "status": "PASS", "detail": "" }, { "name": "非法工程 JSON 被拒绝且原工程保留", "status": "PASS", "detail": "" }, { "name": "编制工程同步到正式内容库", "status": "FAIL", "detail": "实测仅写入浏览器本地库;正式内容库查询 HTTP 200" }, { "name": "编制发布结果进入教学指导书列表", "status": "FAIL", "detail": "教学查询 HTTP 200" } ], "errors": [], "requests": [] } ] }