选中正式项目,进入模型编辑路由。
已验证 · 报告生成:2026/9/6 16:34:35(北京时间)。源码已接通、合同测试和真实浏览器验证分别记录;没有断言关联的功能仍为待验证。
“已实现/本轮修复”是源码状态;绿色“已验证”要求独立证据。过程截图与测试总数不能自动把 103 个功能全部变成通过。
从参考资料提取通用能力
原始两份 PDF 共 11 页已由主代理完整渲染并视觉阅读。原始诉求集中在部件选择、操作步骤、交互反馈和结果追踪。本轮以狐狸、牛奶卡车等轻量模型验证部件选择、流程编排、交互反馈和结果保存。
维修训练内容设计.pdf · 电器控制系统故障维修脚本.pdf。报告仅链接原文,不复制全文或整页图片。
| 资料能力 | 本轮可观察结果 | 矩阵追踪 |
|---|---|---|
| 部件级选择与操作 | 整体与部件区分;树、视口和属性联动;操作后可保存重开。 | selection.scope / selection.sync / property.* |
| 动作流程 | 时间轴关键帧、曲线插值、蓝图顺序和真假分支有实际执行结果。 | timeline.* / curve.* / blueprint.* |
| 交互反馈 | 点击/双击/自动事件、高亮、文字提示、停止和错误反馈与对象匹配。 | blueprint.click / double-click / auto / highlight / message |
| 结果追踪 | 模型版本、封面、引用和本次运行结果有证据;明确运行日志不是教学成绩或审计。 | publish.* / feedback.* / project.conflict |
确认用户实际使用的执行入口
传 projectId / api=1,注入权限与未保存确认。
承载 legacy-model-editor/editor.html。
main.js + timeline.js + blueprint.js,经 stage 构建。
受控资产、项目版本、保存和发布。
当前默认入口由 content.ts 和 LegacyModelEditorView.vue 确定,stage-legacy-model-editor.mjs 将真实原型源码打入静态资源。备用 DigitalTwinEditor.js 不是本轮默认入口。
覆盖顶部工具、场景树/资源库、三维视口、对象属性/组件说明、时间轴、曲线、蓝图、发布面板、运行日志和快捷键。代码中保留但没有可达按钮的“训练场景 JSON 导入”不计为用户可达功能。
明确保存、运行与验证的边界
工程数据闭环
对象变换/材质/自定义字段、时间轴/蓝图和环境稳定引用必须能保存、重开、撤销及 JSON 往返。临时 blob 只用于渲染,服务端资产标识用于持久化。
导入、截图、保存与发布期间保留互斥和乐观锁;失败不得用成功消息掩盖,也不得发布半绑定资源。
界面与业务范围
网格、线框、PBR、透视和展开布局属于当前视图选项,未跨刷新保存不作为缺陷。运行日志属于本次运行记录,不等同审计和教学成绩。
现有组件新增是名称标记;现有离线 HTML 是步骤演示;下游自动执行模型动作须另行确认。
全功能覆盖矩阵
每行列出实际执行入口、实现状态、边界、对应修复及独立验证要求。静态功能清单 · 带证据的矩阵 JSON · 修复前基线与实施记录。
只读模型的搜索、原生动画选择与键盘预览
权限桥误把查看控件的键盘交互当成内容编辑,导致只读用户不能在搜索框输入、切换原生动画或按 Enter 进入预览。
按实际查看控件放行键盘输入/选择/激活;模型编辑、内容上传/保存/发布仍依对应权限阻断。
真实 DOM 权限桥 14/14 通过;最终完整19条E2E全部通过,其中管理员用例验证真实键盘搜索、原生动画切换与Enter播放/暂停,期间没有内容写请求,直接创建接口返回403。
源码 · 聚焦测试Auth / Tran 连接有效性检查增加时限与空闲保活
数据库连接健康检查可能在驱动网络读取上长时间阻塞,拖住借用连接的请求;不能据此把每个历史503都逐条归因为此缺陷。
两个模块统一使用有时限的 SELECT 1 健康检查,默认临时网络时限 2 秒;检查结束恢复原连接超时,开启空闲检查和保活。已有普通业务 SQL 超时策略不变。
实际 Kingbase 驱动隔离探针:正常检查 12ms,原0ms和原7000ms网络超时均恢复;隔离网络黑洞约2010ms抛出 SocketTimeoutException 并关闭连接。探针不是整个平台可用性测试,后端打包和全量E2E结果另记。
源码 · 另一模块源码 · 验证证据曲线轨道与分量控件的可读性
曲线轨道改为按钮后遗漏背景和边框样式,显示为灰底灰字;分量下拉沿用浏览器默认样式并与数值标签重叠。
补齐整宽暗色轨道按钮、主副文字与选中/悬停/键盘焦点样式;分量下拉使用暗色样式并定位右上。仅修改曲线面板CSS。
最终浏览器轮次重新操作轨道、关键帧、五种插值和分量选择并截图;可视效果以最终22与28号截图核对。
源码 · 验证证据工程与数据
| 功能 / 真实执行路径 | 实现状态 | 闭环与边界 | 本轮对应修复 | 测试证据 / 验收要求 |
|---|---|---|---|---|
新建工程project.newLegacyModelEditorView.vue:118 · createNewProject | 本轮修复 | 宿主创建新项目 ID 并跳转;新建不是清空并覆盖当前工程。 | 新建复用正式 create API;创建失败或取消保留原工程。 | 已验证新建工程取消及失败保留输入;成功创建新ID且不覆盖当前模型 · e2e+api验收要求与证据范围新建前后 ID 不同,原工程内容/版本不被覆盖;取消不发创建请求。 |
导入装备 GLBproject.import-glbmain.js:1264 · importModelFile | 已有实现 | 只支持单文件 GLB;上传→登记→解析→最终保存。 | 延续导入 busy/失败阻断及稳定资产校验。 | 已验证受控模型与外部环境 GLB 上传、JSON 往返和刷新重开 · e2e+api验收要求与证据范围选择轻量 GLB,真实模型可见;刷新仍加载同一资产。e2e+api:真实上传、注册、保存、JSON重导入、刷新后的实际网格和原生动画目录;未断言下游场景执行动画。 |
导入工程 JSONproject.import-jsonmain.js:2863 · importProjectFile | 本轮修复 | 导入到当前工程,不创建副本;受控引用必须属于当前可用资产。JSON 不含 GLB 字节。 | 导入前 materialize 稳定资产引用。 | 已验证受控模型与外部环境 GLB 上传、JSON 往返和刷新重开 · e2e+api非法 JSON 与未登记 blob 引用导入失败时保留当前文档 · e2e+api验收要求与证据范围同项目导出后再导入,材质/动画/环境不丢;无效或跨项目缺失引用报错。e2e+api:真实上传、注册、保存、JSON重导入、刷新后的实际网格和原生动画目录;未断言下游场景执行动画。 |
手动保存 / Ctrl+Sproject.savemain.js:2748 · saveProject | 已有实现 | 同一工程保存内容和当前视口封面;成功以 API 响应为准。 | 保留队列、版本保护和封面失败回退。 | 已验证受控模型与外部环境 GLB 上传、JSON 往返和刷新重开 · e2e+api保存请求超时和 409 保留恢复副本,解除故障后可重试 · e2e+api对象名称、变换、PBR、属性与扩展标记保存重开;撤销重做 · e2e+api验收要求与证据范围保存真实 PUT 成功,刷新字段不丢;重复点击不交错。e2e+api:真实上传、注册、保存、JSON重导入、刷新后的实际网格和原生动画目录;未断言下游场景执行动画。 e2e+api:真实页面保存及真实服务端重试;失败由浏览器定向注入 timedout/409,非宣称自然发生的服务故障。 e2e+api:真实属性输入/材质参数/标签、保存与刷新;变换只验数值输入,不代替三维 gizmo 拖动。 |
30 秒自动保存project.autosavemain.js:2122 · bindShellEvents | 已有实现 | 自动保存工程内容;不反复截图更新封面,恢复稿待确认期间暂停。 | 导入/封面保存期间阻断重入。 | 已验证补充视口与工作区:鼠标镜头、聚焦、面板、预览导航、日志与自动保存 · e2e+api验收要求与证据范围修改后等待自动保存并刷新;忙碌时不提交半成品。e2e+api:真实鼠标镜头操作;聚焦只验证相机目标;真实30秒自动保存,无测试加速定时器;统计内存估值未当作性能结论。 |
修改工程名project.namemain.js:457 · projectNameInput | 已有实现 | 输入→失焦/Enter→保存;当前模型工程名。 | 无本轮专门改动。 | 已验证补充视口与工作区:鼠标镜头、聚焦、面板、预览导航、日志与自动保存 · e2e+api验收要求与证据范围改名保存后列表和重新打开一致。e2e+api:真实鼠标镜头操作;聚焦只验证相机目标;真实30秒自动保存,无测试加速定时器;统计内存估值未当作性能结论。 |
另存项目 JSONproject.export-jsonmain.js:2883 · saveProjectAs | 已有实现 | 下载工程 JSON;不是另建服务端项目,也不内嵌 GLB 文件。 | 稳定资产引用保留,临时 blob 地址清除。 | 已验证受控模型与外部环境 GLB 上传、JSON 往返和刷新重开 · e2e+api验收要求与证据范围下载文件可解析,包含轨道/蓝图/自定义字段,配套资源可重新解析。e2e+api:真实上传、注册、保存、JSON重导入、刷新后的实际网格和原生动画目录;未断言下游场景执行动画。 |
撤销 / Ctrl+Zproject.undomain.js:160 · class HistoryStack | 本轮修复 | 最多 60 个历史快照;不是数据库版本回滚。 | 异步互斥,失败不移动索引,托管 GLB 快照重新解析。 | 已验证对象名称、变换、PBR、属性与扩展标记保存重开;撤销重做 · e2e+api蓝图真实节点库与端口拖线:七种参数、内部边复制/剪切、撤销重做及保存 · e2e+runtime-readhistory retains 60 states, truncates redo after edits and ignores duplicate snapshots · unithistory serializes async restores and leaves index unchanged when restoration fails · unitmanaged-GLB history downloads the snapshot stable reference before restoring, without rewriting it · unit验收要求与证据范围属性/曲线修改撤销;连续点击不并发;下载失败索引与修改保留。e2e+api:真实属性输入/材质参数/标签、保存与刷新;变换只验数值输入,不代替三维 gizmo 拖动。 e2e+runtime-read:节点库点选添加及实际拖动/接线/执行;不把点选当成节点拖入,不把适应画布当成鼠标平移缩放全部已验。 unit:60 个快照上限、重复状态忽略及新编辑截断 redo 分支。 unit:异步互斥、下载失败不移动索引,解除锁后可继续操作。 unit:受控 GLB 快照先物化再恢复,不把临时 URL 写回快照。 |
重做 / Ctrl+Yproject.redomain.js:160 · class HistoryStack | 本轮修复 | 撤销后重做;产生新编辑时清掉旧 redo 分支。 | 与撤销共用异步恢复保护。 | 已验证对象名称、变换、PBR、属性与扩展标记保存重开;撤销重做 · e2e+api蓝图真实节点库与端口拖线:七种参数、内部边复制/剪切、撤销重做及保存 · e2e+runtime-readhistory retains 60 states, truncates redo after edits and ignores duplicate snapshots · unithistory serializes async restores and leaves index unchanged when restoration fails · unitmanaged-GLB history downloads the snapshot stable reference before restoring, without rewriting it · unit验收要求与证据范围重做恢复相同字段及姿态,不回放无效分支。e2e+api:真实属性输入/材质参数/标签、保存与刷新;变换只验数值输入,不代替三维 gizmo 拖动。 e2e+runtime-read:节点库点选添加及实际拖动/接线/执行;不把点选当成节点拖入,不把适应画布当成鼠标平移缩放全部已验。 unit:60 个快照上限、重复状态忽略及新编辑截断 redo 分支。 unit:异步互斥、下载失败不移动索引,解除锁后可继续操作。 unit:受控 GLB 快照先物化再恢复,不把临时 URL 写回快照。 |
异常恢复副本project.recoverymain.js:2554 · reconcileApiRecovery | 本轮修复 | 同版本恢复稿需用户确认;旧版本隔离/下载,不静默覆盖服务器。 | 恢复稿重新解析受控资源;指纹忽略对象键顺序,避免已保存页面刷新误生恢复稿。 | 已验证真实未保存稿同版本恢复并显式保存;旧版本恢复稿下载隔离保留 · e2e+apibeforeunload recovery does not create a draft for key order alone, but preserves real unsaved changes · unit验收要求与证据范围同版本恢复可见;旧版本保留/下载;主动保存前不自动 PUT。e2e+api:通过真实beforeunload创建未保存稿;同版恢复后仅显式保存落库;旧版只下载隔离,不自动覆盖服务端。丢弃/跨标签竞态另由既有恢复合同测试覆盖。 unit:同语义对象键顺序不产生假恢复稿;真正修改仍保留。不包含全部恢复/隔离/下载 UI 分支。 |
保存/发布版本冲突project.conflictmodel-content-api.js:1025 · queueSave | 已有实现 | 409 阻断;恢复稿保留。 | 发布封面队列同样遵守冲突保护。 | 已验证保存请求超时和 409 保留恢复副本,解除故障后可重试 · e2e+apiAPI conflict leaves publication failed and releases the cover guard · unit验收要求与证据范围定向模拟 409,无后续发布请求,不误报成功。e2e+api:真实页面保存及真实服务端重试;失败由浏览器定向注入 timedout/409,非宣称自然发生的服务故障。 unit:409 分支不误报已发布并释放 busy 标记;模拟 API。 |
查看/编辑/新增/发布权限project.permissionslegacy-iframe-permissions.ts:32 · installLegacyModelPermissions | 本轮修复 | 按 content.model.* 权限,不按 teacher/admin 身份推断写权限;只读仍能搜索、选择原生动画和键盘激活预览。 | 新建接真实 create 能力;只发布可发布已保存版本;修复查看控件键盘事件误拦截。 | 已验证管理员只读权限:编辑、新建、导入、保存发布均不可越权 · e2e+api验收要求与证据范围只读查看操作可用且无内容写请求;不可编辑/保存;publisher 不上传/PUT,正常发布已有版本。e2e+api:管理员只读UI、真实键盘搜索、原生片段切换与Enter播放/暂停、预览无内容写请求及创建403;纯publisher无需update的发布流程由独立权限合同回归补充。 |
离开/切角色未保存确认project.leaveLegacyModelEditorView.vue:147 · confirmLeave | 已有实现 | 取消留在当前页;保存失败不得离开;上传/保存/发布忙时保留状态。 | 新建也复用现有未保存确认。 | 已验证补充环境与树:内置三环境保存重开、节点计数与折叠展开 · e2e+api未保存离开:关闭确认保留工作、保存失败留在原页、重试保存后离开 · e2e+api验收要求与证据范围取消、放弃、保存失败与 busy 分别验证,没有误清 dirty。e2e+api:真实切换、保存和刷新三种环境;树计数与展开折叠;装备车库保存后返回列表不误报未保存。树220行上限仍属已说明边界。 |
资源库与场景树
| 功能 / 真实执行路径 | 实现状态 | 闭环与边界 | 本轮对应修复 | 测试证据 / 验收要求 |
|---|---|---|---|---|
资源库浏览 / 选择装备resource.catalogmain.js:1383 · renderAssets | 本轮修复 | 切换装备可能应用其基准时间轴/蓝图;不是把第二个主装备追加进当前模型。 | 修复单节点选择器误用导致启动报错;忙碌期间禁止切换资源。 | 已验证补充资源库:搜索清空、真实卡片切换与刷新保留 · e2e+apiresource catalog startup renders all model/environment cards and binds every action with a real DOM · unit验收要求与证据范围完整资源库 DOM 初始化、卡片事件、空目录启动正常;切换实际几何可见,保存后资源一致。e2e+api:真实搜索与资源卡片点击、服务端保存、刷新后原模型网格;副本独立登记待清理。 unit:真实 DOM 渲染、卡片绑定、空目录及 busy 保护;不包含 GLB 网络加载。 |
资源搜索resource.searchmain.js:1467 · applyAssetSearch | 已有实现 | 按资源名称/关键词过滤现有目录,不搜索服务器全站。 | 无本轮专门改动。 | 已验证补充资源库:搜索清空、真实卡片切换与刷新保留 · e2e+api验收要求与证据范围关键字命中、空结果与清空恢复。e2e+api:真实搜索与资源卡片点击、服务端保存、刷新后原模型网格;副本独立登记待清理。 |
内置车间 / 野外 / 装备车库environment.builtinmain.js:789 · resetEnvironmentPlaceholder | 已有实现 | 车间/野外为程序化环境;车库为随包 GLB。 | 保留真实 GLB 和占位环境来源区别。 | 已验证补充环境与树:内置三环境保存重开、节点计数与折叠展开 · e2e+api验收要求与证据范围三种切换与重新打开可重现相应环境。e2e+api:真实切换、保存和刷新三种环境;树计数与展开折叠;装备车库保存后返回列表不误报未保存。树220行上限仍属已说明边界。 |
导入外部车间 / 野外 GLBenvironment.externalmain.js:1028 · loadEnvironmentSceneFile | 本轮修复 | 一个环境根;受控 MODEL_FILE 资产 metadata.usage=environment,与主装备独立。 | 上传、最终保存、JSON 与刷新恢复稳定引用;失败阻断半提交。 | 已验证受控模型与外部环境 GLB 上传、JSON 往返和刷新重开 · e2e+api验收要求与证据范围小 GLB 上传后主装备不被替换;环境刷新仍可见且资产引用一致。e2e+api:真实上传、注册、保存、JSON重导入、刷新后的实际网格和原生动画目录;未断言下游场景执行动画。 |
模型加载进度 / 失败 / 重试resource.loadingLegacyModelEditorView.vue:33 · installLegacyModelIframeLoadingScope | 已有实现 | 局部加载状态;错误短提示,中性失败状态可重试。 | 复用前轮加载范围与错误消息修复。 | 已验证受控 GLB 下载失败阻止编辑,重试成功;发布预检开关无写入且拒绝错误资源 JSON · e2e+api验收要求与证据范围资源失败不无限转圈;重试恢复;无凭据泄露。e2e+api:真实受控下载定向503→中性失败与禁止编辑→解除故障后UI重试成功;预检面板开关不写项目,错误资源JSON在替换当前模型之前被拒绝。服务端发布时code/URI一致性拒绝由ContentProjectServiceTest合同回归覆盖,未把面板绿标代替服务端校验。 |
场景树节点与计数tree.browsemain.js:1925 · buildSceneTree | 现有边界 | 树行上限 220;统计节点总数不等于当前展开行数。 | 无本轮容量重构。 | 已验证补充环境与树:内置三环境保存重开、节点计数与折叠展开 · e2e+api验收要求与证据范围模型/环境节点可达,计数说明不当作全部节点已经逐项验收。e2e+api:真实切换、保存和刷新三种环境;树计数与展开折叠;装备车库保存后返回列表不误报未保存。树220行上限仍属已说明边界。 |
节点展开 / 折叠tree.expandmain.js:1925 · buildSceneTree | 已有实现 | 当前界面浏览状态;无须持久化展开布局。 | 无本轮专门改动。 | 已验证补充环境与树:内置三环境保存重开、节点计数与折叠展开 · e2e+api验收要求与证据范围展开和折叠子级不修改模型对象。e2e+api:真实切换、保存和刷新三种环境;树计数与展开折叠;装备车库保存后返回列表不误报未保存。树220行上限仍属已说明边界。 |
场景树搜索tree.searchmain.js:1925 · buildSceneTree | 已有实现 | 搜索当前载入对象,不新增/删除对象。 | 无本轮专门改动。 | 已验证场景树搜索、可见性、选择、视口工具、原生动画与截图 · e2e验收要求与证据范围搜索节点后选中正确对象,清空恢复树。e2e:树搜索、对象隐藏刷新、轮廓及视图开关、原生动画和PNG下载。移动/旋转/缩放只切换模式,真实gizmo拖动仍需补验;聚焦未做几何断言。 |
显示 / 隐藏对象tree.visibilitymain.js:1925 · buildSceneTree | 本轮修复 | 对象 visible 保存;隐藏祖先的子对象不接受射线拾取。 | 拾取与高亮统一检查祖先可见性。 | 已验证场景树搜索、可见性、选择、视口工具、原生动画与截图 · e2evisible child under a hidden ancestor cannot be picked or highlighted; trigger aliases include ancestors · unit验收要求与证据范围隐藏父级后不能点到子级,保存重开仍隐藏。e2e:树搜索、对象隐藏刷新、轮廓及视图开关、原生动画和PNG下载。移动/旋转/缩放只切换模式,真实gizmo拖动仍需补验;聚焦未做几何断言。 unit:共用可见性和祖先别名函数;鼠标事件另由 E2E 验证。 |
整体 / 部件级选择selection.scopemain.js:1938 · setSelectionScope | 已有实现 | 整体作用主装备根;部件作用实际节点。 | 保留当前选择层级合同。 | 已验证补充视口与工作区:鼠标镜头、聚焦、面板、预览导航、日志与自动保存 · e2e+api验收要求与证据范围点击可见 mesh,整体/部件切换选择目标不同。e2e+api:真实鼠标镜头操作;聚焦只验证相机目标;真实30秒自动保存,无测试加速定时器;统计内存估值未当作性能结论。 |
树 / 视口 / 属性选择联动selection.syncmain.js:1947 · selectObject | 本轮修复 | 显示实际对象并更新辅助框;环境也是可编辑对象。 | 关闭轮廓后重选不恢复辅助框。 | 已验证场景树搜索、可见性、选择、视口工具、原生动画与截图 · e2e验收要求与证据范围三处名称/对象 ID 一致,重选后轮廓状态保持。e2e:树搜索、对象隐藏刷新、轮廓及视图开关、原生动画和PNG下载。移动/旋转/缩放只切换模式,真实gizmo拖动仍需补验;聚焦未做几何断言。 |
三维视图与操作
| 功能 / 真实执行路径 | 实现状态 | 闭环与边界 | 本轮对应修复 | 测试证据 / 验收要求 |
|---|---|---|---|---|
鼠标旋转 / 平移 / 缩放视角view.orbitmain.js:2 · OrbitControls | 已有实现 | 当前三维相机;不是模型变换。 | 无本轮专门改动。 | 已验证补充视口与工作区:鼠标镜头、聚焦、面板、预览导航、日志与自动保存 · e2e+api验收要求与证据范围鼠标操作改变镜头但不改变对象局部坐标。e2e+api:真实鼠标镜头操作;聚焦只验证相机目标;真实30秒自动保存,无测试加速定时器;统计内存估值未当作性能结论。 |
聚焦选中 / Fview.focusmain.js:2272 · fitCamera | 已有实现 | 按当前对象包围盒定位相机。 | 无本轮专门改动。 | 已验证补充视口与工作区:鼠标镜头、聚焦、面板、预览导航、日志与自动保存 · e2e+api验收要求与证据范围小模型/部件聚焦后仍可见,不被裁剪。e2e+api:真实鼠标镜头操作;聚焦只验证相机目标;真实30秒自动保存,无测试加速定时器;统计内存估值未当作性能结论。 |
移动工具 / Wview.movemain.js:2234 · setTransformMode | 本轮修复 | 拖拽编辑对象局部位置,保存后重开一致。 | 动画姿态下更新基值只扣实际偏移。 | 已验证真实三维移动、旋转、缩放手柄拖动及撤销重做保存重开 · e2e+runtime-readback验收要求与证据范围移动后保存、刷新及动画再播放不漂移。 |
旋转工具 / Eview.rotatemain.js:2234 · setTransformMode | 本轮修复 | 对象旋转;与当前时间轴旋转叠加需要一致。 | 统一动画基值处理。 | 已验证真实三维移动、旋转、缩放手柄拖动及撤销重做保存重开 · e2e+runtime-readback验收要求与证据范围旋转后保存/撤销/重做姿态一致。 |
缩放工具 / Rview.scalemain.js:2234 · setTransformMode | 已有实现 | 对象缩放持久化;时间轴没有缩放轨道 UI。 | 无新增缩放动画能力。 | 已验证真实三维移动、旋转、缩放手柄拖动及撤销重做保存重开 · e2e+runtime-readback验收要求与证据范围对象缩放保存和重开正确。 |
网格开关view.gridmain.js:2283 · toggleGrid | 已有实现 | 临时视图选项,不要求写入工程。 | 非持久化不计保存缺陷。 | 已验证场景树搜索、可见性、选择、视口工具、原生动画与截图 · e2e验收要求与证据范围开关只影响辅助网格,不改变模型。e2e:树搜索、对象隐藏刷新、轮廓及视图开关、原生动画和PNG下载。移动/旋转/缩放只切换模式,真实gizmo拖动仍需补验;聚焦未做几何断言。 |
PBR 光照开关view.pbrmain.js:2236 · handleView | 已有实现 | 当前照明预览选项;不是批量材质编辑。 | 非持久化不计保存缺陷。 | 已验证场景树搜索、可见性、选择、视口工具、原生动画与截图 · e2e验收要求与证据范围开关改变显示,物体材质字段不被覆盖。e2e:树搜索、对象隐藏刷新、轮廓及视图开关、原生动画和PNG下载。移动/旋转/缩放只切换模式,真实gizmo拖动仍需补验;聚焦未做几何断言。 |
线框开关view.wireframemain.js:2236 · handleView | 已有实现 | 当前视图选项;不承诺保存到工程。 | 非持久化不计保存缺陷。 | 已验证场景树搜索、可见性、选择、视口工具、原生动画与截图 · e2e验收要求与证据范围线框开关恢复正常着色。e2e:树搜索、对象隐藏刷新、轮廓及视图开关、原生动画和PNG下载。移动/旋转/缩放只切换模式,真实gizmo拖动仍需补验;聚焦未做几何断言。 |
选中轮廓开关view.outlinemain.js:2236 · handleView | 本轮修复 | 当前会话偏好,进出预览后保持;不要求跨重载存储。 | 重选时不重新泄露轮廓。 | 已验证场景树搜索、可见性、选择、视口工具、原生动画与截图 · e2e验收要求与证据范围关闭→重选→预览→退出,轮廓仍关闭。e2e:树搜索、对象隐藏刷新、轮廓及视图开关、原生动画和PNG下载。移动/旋转/缩放只切换模式,真实gizmo拖动仍需补验;聚焦未做几何断言。 |
透视视角按钮view.perspectivemain.js:2236 · handleView | 现有边界 | 重置透视观察角度;当前没有正交视角菜单。 | 不把临时视图状态当作保存缺陷。 | 已验证场景树搜索、可见性、选择、视口工具、原生动画与截图 · e2e验收要求与证据范围点击后相机和聚焦目标正常。e2e:树搜索、对象隐藏刷新、轮廓及视图开关、原生动画和PNG下载。移动/旋转/缩放只切换模式,真实gizmo拖动仍需补验;聚焦未做几何断言。 |
下载视口截图view.snapshotmain.js:3092 · downloadSnapshot | 已有实现 | 当前 canvas PNG,可包含编辑辅助元素;保存封面是独立截图流程。 | 无本轮专门改动。 | 已验证场景树搜索、可见性、选择、视口工具、原生动画与截图 · e2e验收要求与证据范围PNG 下载可打开,内容与当前视口对应。e2e:树搜索、对象隐藏刷新、轮廓及视图开关、原生动画和PNG下载。移动/旋转/缩放只切换模式,真实gizmo拖动仍需补验;聚焦未做几何断言。 |
底部页签 / Tab / 面板高度view.panelsmain.js:2215 · switchBottomMode | 已有实现 | 时间轴、蓝图、曲线、日志切换;拖分割条只调整当前工作区。 | 曲线入口接真实数据。 | 已验证补充视口与工作区:鼠标镜头、聚焦、面板、预览导航、日志与自动保存 · e2e+api验收要求与证据范围各页签显示正确内容,调整高度后画布正确 resize。e2e+api:真实鼠标镜头操作;聚焦只验证相机目标;真实30秒自动保存,无测试加速定时器;统计内存估值未当作性能结论。 |
进入 / 退出运行预览view.previewmain.js:2284 · togglePreview | 本轮修复 | 真实当前三维场景;隐藏辅助工具,退出不丢编辑状态。 | 进入显式派发 auto;退出停止运行并恢复轮廓策略。 | 已验证已保存蓝图:条件出口与目标匹配 runtime 检查,真实模型单击/双击/进入预览自动触发 · e2e场景树搜索、可见性、选择、视口工具、原生动画与截图 · e2e验收要求与证据范围进入/退出与 Esc,三维仍可见,无辅助框泄漏。e2e:执行使用正式模型编辑器的真实模型/时间轴/高亮/提示 handler;不等同于学员端任务下发。 e2e:树搜索、对象隐藏刷新、轮廓及视图开关、原生动画和PNG下载。移动/旋转/缩放只切换模式,真实gizmo拖动仍需补验;聚焦未做几何断言。 |
预览播放 / 前后导航view.preview-stepmain.js:2122 · bindShellEvents | 现有边界 | 播放运行蓝图;前后按钮当前按时间轴 ±2 秒,不是按业务工序跳转。 | 无新增业务工序导航。 | 已验证补充视口与工作区:鼠标镜头、聚焦、面板、预览导航、日志与自动保存 · e2e+api验收要求与证据范围播放触发真实流程;前后跳时与时间轴一致。e2e+api:真实鼠标镜头操作;聚焦只验证相机目标;真实30秒自动保存,无测试加速定时器;统计内存估值未当作性能结论。 |
对象属性与扩展标记
| 功能 / 真实执行路径 | 实现状态 | 闭环与边界 | 本轮对应修复 | 测试证据 / 验收要求 |
|---|---|---|---|---|
对象名称property.namemain.js:1996 · bindInspectorEvents | 已有实现 | 修改当前节点名,标识保持稳定。 | 无本轮专门改动。 | 已验证对象名称、变换、PBR、属性与扩展标记保存重开;撤销重做 · e2e+api验收要求与证据范围树和属性同步,保存重开名称保留。e2e+api:真实属性输入/材质参数/标签、保存与刷新;变换只验数值输入,不代替三维 gizmo 拖动。 |
对象标识 / 状态说明property.identitymain.js:1958 · renderInspector | 本轮修复 | 标识只读;可见性含祖先状态,阴影取实际castShadow;编辑能力由宿主权限注入。 | 不再固定显示“可见/投射阴影”,补宿主可编辑状态钩子。 | 已验证补充视口与工作区:鼠标镜头、聚焦、面板、预览导航、日志与自动保存 · e2e+apiinspector state tags reflect ancestor visibility and actual shadow flags, with a host editability hook · unit验收要求与证据范围标识不可编辑;选中对象、隐藏状态、阴影及只读权限标签一致。e2e+api:真实鼠标镜头操作;聚焦只验证相机目标;真实30秒自动保存,无测试加速定时器;统计内存估值未当作性能结论。 unit:真实属性 DOM 显示隐藏/阴影状态,并提供宿主权限标签 hook;不伪称此单测完成会话鉴权。 |
位置 XYZ 数值property.positionmain.js:1996 · bindInspectorEvents | 本轮修复 | 局部坐标;动画当前帧下编辑也能生成正确基值。 | 中性姿态与实际应用偏移统一。 | 已验证对象名称、变换、PBR、属性与扩展标记保存重开;撤销重做 · e2e+api验收要求与证据范围三个轴编辑、保存重开、动画回放一致。e2e+api:真实属性输入/材质参数/标签、保存与刷新;变换只验数值输入,不代替三维 gizmo 拖动。 |
旋转 XYZ 数值property.rotationmain.js:1996 · bindInspectorEvents | 本轮修复 | 输入角度转弧度存储,显示角度。 | 多轨旋转基值不重复扣除。 | 已验证对象名称、变换、PBR、属性与扩展标记保存重开;撤销重做 · e2e+api验收要求与证据范围度数显示与存储/播放的弧度一致。e2e+api:真实属性输入/材质参数/标签、保存与刷新;变换只验数值输入,不代替三维 gizmo 拖动。 |
缩放 XYZ 数值property.scalemain.js:1996 · bindInspectorEvents | 已有实现 | 对象当前缩放,不添加新的缩放轨道。 | 无本轮专门改动。 | 已验证对象名称、变换、PBR、属性与扩展标记保存重开;撤销重做 · e2e+api验收要求与证据范围非均匀缩放可保存和重开。e2e+api:真实属性输入/材质参数/标签、保存与刷新;变换只验数值输入,不代替三维 gizmo 拖动。 |
材质基础色property.colormain.js:1996 · bindInspectorEvents | 现有边界 | 只编辑当前对象第一个材质槽;共享材质可能影响共享该实例的网格。 | 界面明确材质槽 1/N。 | 已验证对象名称、变换、PBR、属性与扩展标记保存重开;撤销重做 · e2e+api验收要求与证据范围颜色修改、保存重开对应当前槽;不宣称所有槽可编辑。e2e+api:真实属性输入/材质参数/标签、保存与刷新;变换只验数值输入,不代替三维 gizmo 拖动。 |
材质金属度property.metalnessmain.js:1996 · bindInspectorEvents | 现有边界 | 当前首槽 PBR 参数 0~1。 | 标明材质槽范围。 | 已验证对象名称、变换、PBR、属性与扩展标记保存重开;撤销重做 · e2e+api验收要求与证据范围拖动参数有效,保存重开值一致。e2e+api:真实属性输入/材质参数/标签、保存与刷新;变换只验数值输入,不代替三维 gizmo 拖动。 |
材质粗糙度property.roughnessmain.js:1996 · bindInspectorEvents | 现有边界 | 当前首槽 PBR 参数 0~1。 | 标明材质槽范围。 | 已验证对象名称、变换、PBR、属性与扩展标记保存重开;撤销重做 · e2e+api验收要求与证据范围参数与当前槽持久化一致。e2e+api:真实属性输入/材质参数/标签、保存与刷新;变换只验数值输入,不代替三维 gizmo 拖动。 |
材质透明度property.opacitymain.js:1996 · bindInspectorEvents | 现有边界 | 当前首槽;联动 transparent/depthWrite。 | 保留实际透明度保存字段。 | 已验证对象名称、变换、PBR、属性与扩展标记保存重开;撤销重做 · e2e+api验收要求与证据范围透明效果与重开结果一致。e2e+api:真实属性输入/材质参数/标签、保存与刷新;变换只验数值输入,不代替三维 gizmo 拖动。 |
自定义资源编码property.codemain.js:1996 · bindInspectorEvents | 本轮修复 | 对象 customProperties.resourceCode,不是服务器资产主键。 | 输入真正回写、保存、恢复及撤销。 | 已验证对象名称、变换、PBR、属性与扩展标记保存重开;撤销重做 · e2e+apicustom properties and extension labels survive actual capture, project JSON and object restore · unit验收要求与证据范围编辑、清空、重选、JSON 往返、刷新均一致。e2e+api:真实属性输入/材质参数/标签、保存与刷新;变换只验数值输入,不代替三维 gizmo 拖动。 unit:真实对象 capture、normalization、JSON 与 restore 往返;清空和撤销到未存在字段状态。 |
自定义运行状态property.statusmain.js:1996 · bindInspectorEvents | 本轮修复 | NORMAL/SERVICE 标签,不会发起真实设备控制。 | 真正写回对象,首次变更可撤销。 | 已验证对象名称、变换、PBR、属性与扩展标记保存重开;撤销重做 · e2e+apicustom properties and extension labels survive actual capture, project JSON and object restore · unit验收要求与证据范围两状态切换及刷新保留。e2e+api:真实属性输入/材质参数/标签、保存与刷新;变换只验数值输入,不代替三维 gizmo 拖动。 unit:真实对象 capture、normalization、JSON 与 restore 往返;清空和撤销到未存在字段状态。 |
流程绑定说明property.bindingmain.js:1958 · renderInspector | 现有边界 | 只读显示模板/时间轴名称,不是教学任务的设备或物联网绑定。 | 无本轮业务绑定改造。 | 已验证补充视口与工作区:鼠标镜头、聚焦、面板、预览导航、日志与自动保存 · e2e+api验收要求与证据范围只读,不将其当作任务绑定操作验收。e2e+api:真实鼠标镜头操作;聚焦只验证相机目标;真实30秒自动保存,无测试加速定时器;统计内存估值未当作性能结论。 |
组件页内置能力说明component.inspectmain.js:1975 · renderComponents | 现有边界 | 变换、场景节点、渲染等派生说明,没有通用组件启停系统。 | 区分内置说明与自定义标记。 | 已验证补充视口与工作区:鼠标镜头、聚焦、面板、预览导航、日志与自动保存 · e2e+api验收要求与证据范围显示与对象类型一致,不虚报可执行组件配置。e2e+api:真实鼠标镜头操作;聚焦只验证相机目标;真实30秒自动保存,无测试加速定时器;统计内存估值未当作性能结论。 |
添加扩展标记component.tagmain.js:1975 · renderComponents | 本轮澄清 | 只保存名称标签;没有脚本、启停、运行时行为。 | 从“添加组件”改为“扩展标记,仅保存标签”。 | 已验证对象名称、变换、PBR、属性与扩展标记保存重开;撤销重做 · e2e+apicustom properties and extension labels survive actual capture, project JSON and object restore · unit验收要求与证据范围新增标签保存/重开;不得声称已启用新行为。e2e+api:真实属性输入/材质参数/标签、保存与刷新;变换只验数值输入,不代替三维 gizmo 拖动。 unit:真实对象 capture、normalization、JSON 与 restore 往返;清空和撤销到未存在字段状态。 |
时间轴与曲线
| 功能 / 真实执行路径 | 实现状态 | 闭环与边界 | 本轮对应修复 | 测试证据 / 验收要求 |
|---|---|---|---|---|
播放 / 暂停 / Spacetimeline.playtimeline.js:393 · play() | 已有实现 | 播放当前编辑时间轴;原生 GLB 动画单独控制。 | 停止清理与时间同步由本轮补强。 | 已验证时间轴真实控件:轨道/关键帧/播放与曲线 5 插值,保存后重新加载一致 · e2e+runtime-read验收要求与证据范围播放进度/真实对象姿态变化,暂停停在当前帧。e2e+runtime-read:真实控件和指针操作,运行时读取数值校验;curve.axis仅切换无数值独立断言,timeline.seek播放头与Alt吸附未在本例覆盖。 |
停止timeline.stoptimeline.js:429 · stop() | 已有实现 | 停止并回到起始时间,按起始帧应用动画。 | 无本轮语义扩展。 | 已验证时间轴真实控件:轨道/关键帧/播放与曲线 5 插值,保存后重新加载一致 · e2e+runtime-read验收要求与证据范围按钮停止后不再自行前进。e2e+runtime-read:真实控件和指针操作,运行时读取数值校验;curve.axis仅切换无数值独立断言,timeline.seek播放头与Alt吸附未在本例覆盖。 |
循环开关timeline.looptimeline.js:198 · #bindEvents | 本轮修复 | 循环设置随 timeline 保存;不循环到达终点只完成一次。 | 循环变更进入历史/dirty。 | 已验证时间轴真实控件:轨道/关键帧/播放与曲线 5 插值,保存后重新加载一致 · e2e+runtime-read验收要求与证据范围开关、保存重开、到末尾/循环边界正确。e2e+runtime-read:真实控件和指针操作,运行时读取数值校验;curve.axis仅切换无数值独立断言,timeline.seek播放头与Alt吸附未在本例覆盖。 |
上一 / 下一关键帧timeline.key-navtimeline.js:232 · #onClick | 已有实现 | 按时间轴关键帧时间定位。 | 无本轮专门改动。 | 已验证时间轴真实控件:轨道/关键帧/播放与曲线 5 插值,保存后重新加载一致 · e2e+runtime-read验收要求与证据范围多个轨道时跳到正确相邻关键时刻。e2e+runtime-read:真实控件和指针操作,运行时读取数值校验;curve.axis仅切换无数值独立断言,timeline.seek播放头与Alt吸附未在本例覆盖。 |
拖播放头 / 点击刻度timeline.seektimeline.js:263 · #onPointerDown | 本轮修复 | 实时求值当前帧;键盘左右移动一帧,Shift 移动一秒。 | 拖动补发 timechange,解绑指针监听。 | 已验证补充时间轴与蓝图工具:刻度/按键/记录/分量、基准匹配、节点搜索拖入与画布平移 · e2e+runtime-read验收要求与证据范围时间码、曲线和视口姿态同步。e2e+runtime-read:真实模型编辑参数/基准轨道生成验收,不构成装备操作或维修指导。桥梁原工程94仅GET和copy。 |
添加轨道timeline.add-tracktimeline.js:471 · addTrack( | 已有实现 | 当前主装备节点的变换轨道。 | 无新增轨道类型。 | 已验证时间轴真实控件:轨道/关键帧/播放与曲线 5 插值,保存后重新加载一致 · e2e+runtime-read验收要求与证据范围增加后可绑定节点并保存。e2e+runtime-read:真实控件和指针操作,运行时读取数值校验;curve.axis仅切换无数值独立断言,timeline.seek播放头与Alt吸附未在本例覆盖。 |
删除轨道timeline.remove-tracktimeline.js:495 · removeTrack( | 本轮修复 | 删除后不再保留该轨道施加的旧姿态。 | 宿主恢复此前作用的属性基值。 | 已验证时间轴真实控件:轨道/关键帧/播放与曲线 5 插值,保存后重新加载一致 · e2e+runtime-read验收要求与证据范围删除即时复原,再保存/重开一致。e2e+runtime-read:真实控件和指针操作,运行时读取数值校验;curve.axis仅切换无数值独立断言,timeline.seek播放头与Alt吸附未在本例覆盖。 |
修改轨道目标节点timeline.targettimeline.js:506 · updateSelectedTrack | 本轮修复 | 用稳定对象标识绑定,不靠同名第一项。 | 重绑清理旧目标的应用姿态。 | 已验证时间轴真实控件:轨道/关键帧/播放与曲线 5 插值,保存后重新加载一致 · e2e+runtime-readchanging a binding resets the former target and keeps manual transform edits as base · unit验收要求与证据范围从 A 改为 B,A 复原,B 播放。e2e+runtime-read:真实控件和指针操作,运行时读取数值校验;curve.axis仅切换无数值独立断言,timeline.seek播放头与Alt吸附未在本例覆盖。 unit:轨道重绑后旧目标复位,手动变换成为新基值;不假称鼠标拖动已验。 |
选择位置 / 旋转属性timeline.propertytimeline.js:506 · updateSelectedTrack | 已有实现 | 位置 XYZ 向量、旋转 X/Y/Z;没有缩放轨道 UI。 | 保留当前实际能力。 | 已验证时间轴真实控件:轨道/关键帧/播放与曲线 5 插值,保存后重新加载一致 · e2e+runtime-read验收要求与证据范围属性切换后关键帧类型和播放一致。e2e+runtime-read:真实控件和指针操作,运行时读取数值校验;curve.axis仅切换无数值独立断言,timeline.seek播放头与Alt吸附未在本例覆盖。 |
轨道静音timeline.mutetimeline.js:232 · #onClick | 本轮修复 | 仅忽略当前轨道,不关闭其他轨道。 | 不再停留旧姿态或保存时重复扣值。 | 已验证时间轴真实控件:轨道/关键帧/播放与曲线 5 插值,保存后重新加载一致 · e2e+runtime-read验收要求与证据范围静音/恢复后实际姿态与重开一致。e2e+runtime-read:真实控件和指针操作,运行时读取数值校验;curve.axis仅切换无数值独立断言,timeline.seek播放头与Alt吸附未在本例覆盖。 |
记录当前姿态关键帧timeline.recordmain.js:2276 · addKeyframeFromSelection | 本轮修复 | 记录相对对象基值的当前值。 | 与多轨实际应用/保存采用同一基值。 | 已验证补充时间轴与蓝图工具:刻度/按键/记录/分量、基准匹配、节点搜索拖入与画布平移 · e2e+runtime-read验收要求与证据范围操作对象后记录,回放命中相同姿态。e2e+runtime-read:真实模型编辑参数/基准轨道生成验收,不构成装备操作或维修指导。桥梁原工程94仅GET和copy。 |
双击新增关键帧timeline.add-keytimeline.js:255 · #onDoubleClick | 已有实现 | 在轨道对应时刻创建/更新关键帧。 | 时间碰撞保留当前编辑帧。 | 已验证时间轴真实控件:轨道/关键帧/播放与曲线 5 插值,保存后重新加载一致 · e2e+runtime-read验收要求与证据范围新增后节点可选,时间/数值可保存。e2e+runtime-read:真实控件和指针操作,运行时读取数值校验;curve.axis仅切换无数值独立断言,timeline.seek播放头与Alt吸附未在本例覆盖。 |
删除关键帧 / Deletetimeline.delete-keytimeline.js:584 · deleteSelected | 已有实现 | 删除选中的关键帧;输入框编辑时不截获删除键。 | 删除和监听清理回归。 | 已验证时间轴真实控件:轨道/关键帧/播放与曲线 5 插值,保存后重新加载一致 · e2e+runtime-read验收要求与证据范围删除后曲线和播放变化,撤销可恢复。e2e+runtime-read:真实控件和指针操作,运行时读取数值校验;curve.axis仅切换无数值独立断言,timeline.seek播放头与Alt吸附未在本例覆盖。 |
关键帧拖动 / Alt 取消吸附timeline.drag-keytimeline.js:263 · #onPointerDown | 本轮修复 | 默认 1/30 秒吸附;重叠时合并,保留正在编辑帧。 | 拖动时间同步,碰撞处理确定。 | 已验证时间轴真实控件:轨道/关键帧/播放与曲线 5 插值,保存后重新加载一致 · e2e+runtime-read验收要求与证据范围拖动/重叠/Alt 行为和保存后时间正确。e2e+runtime-read:真实控件和指针操作,运行时读取数值校验;curve.axis仅切换无数值独立断言,timeline.seek播放头与Alt吸附未在本例覆盖。 |
时间轴缩放timeline.zoomtimeline.js:451 · setZoom | 已有实现 | 显示缩放随 timeline 记录;不改变时长/关键帧数值。 | 无本轮专门改动。 | 已验证时间轴真实控件:轨道/关键帧/播放与曲线 5 插值,保存后重新加载一致 · e2e+runtime-read验收要求与证据范围缩放不改变动作内容。e2e+runtime-read:真实控件和指针操作,运行时读取数值校验;curve.axis仅切换无数值独立断言,timeline.seek播放头与Alt吸附未在本例覆盖。 |
多轨组合与保存基值timeline.multitrackmodel-editor-state.js:12 · applyEditorTimelinePose | 本轮修复 | 不同属性组合;同对象同属性最后有效轨道生效。 | 求值、手工编辑基值、序列化一致。 | 已验证multiple tracks on one property use last effective value; capture subtracts it only once · unitchanging a binding resets the former target and keeps manual transform edits as base · unit验收要求与证据范围两轨同属性、静音、删轨、重绑、重开无漂移。unit:调用实际 apply/capture/update 基值方法;验证同属性最后有效轨道、静音/删除后中性姿态,偏移只扣一次。 unit:轨道重绑后旧目标复位,手动变换成为新基值;不假称鼠标拖动已验。 |
载入装备基准动作timeline.baselinemain.js:3058 · loadBaselineAnimation | 现有边界 | 匹配部件后直接替换当前时间轴/蓝图;当前没有单独确认框,不是任意维修流程自动生成。 | 保持当前装备限定;无匹配只提示,不改工程。 | 已验证补充时间轴与蓝图工具:刻度/按键/记录/分量、基准匹配、节点搜索拖入与画布平移 · e2e+runtime-read验收要求与证据范围匹配时载入/保存/重开;无匹配时保留原数据并给出提示。e2e+runtime-read:真实模型编辑参数/基准轨道生成验收,不构成装备操作或维修指导。桥梁原工程94仅GET和copy。 |
GLB 原生动画选择 / 播放timeline.nativemain.js:1715 · selectNativeAnimation | 已有实现 | 真实 GLB 自带片段;保存选择索引,不是蓝图 clip 字段。 | 无片段时禁用。 | 已验证场景树搜索、可见性、选择、视口工具、原生动画与截图 · e2e验收要求与证据范围狐狸实际动画播放/暂停,选择保存后重开一致。e2e:树搜索、对象隐藏刷新、轮廓及视图开关、原生动画和PNG下载。移动/旋转/缩放只切换模式,真实gizmo拖动仍需补验;聚焦未做几何断言。 |
曲线选择轨道 / 关键帧timeline.curvemodel-curve-editor.js:5 · class ModelCurveEditor | 本轮修复 | 曲线与时间轴共用一份轨道和关键帧数据。 | 移除固定 SVG 假数据。 | 已验证时间轴真实控件:轨道/关键帧/播放与曲线 5 插值,保存后重新加载一致 · e2e+runtime-readcurve edits real scalar key values, time and interpolation, persisting through document reload · unit验收要求与证据范围实际轨道名和点数匹配时间轴,点击同步当前帧。e2e+runtime-read:真实控件和指针操作,运行时读取数值校验;curve.axis仅切换无数值独立断言,timeline.seek播放头与Alt吸附未在本例覆盖。 unit:真实曲线控件与 TimelineEditor,标量编辑与文档往返。 |
曲线编辑时间curve.timemodel-curve-editor.js:30 · change(input) | 本轮修复 | 更新实际 key.time,约束在时间轴时长内。 | 调用 timeline.updateKeyframe 并保持编辑目标。 | 已验证时间轴真实控件:轨道/关键帧/播放与曲线 5 插值,保存后重新加载一致 · e2e+runtime-readcurve edits real scalar key values, time and interpolation, persisting through document reload · unit验收要求与证据范围改时间后重排、撤销、JSON 往返一致。e2e+runtime-read:真实控件和指针操作,运行时读取数值校验;curve.axis仅切换无数值独立断言,timeline.seek播放头与Alt吸附未在本例覆盖。 unit:真实曲线控件与 TimelineEditor,标量编辑与文档往返。 |
曲线编辑标量 / XYZ 数值curve.valuemodel-curve-editor.js:30 · change(input) | 本轮修复 | 修改实际关键帧值,向量编辑保留其他分量。 | 无效空值拒绝提交。 | 已验证时间轴真实控件:轨道/关键帧/播放与曲线 5 插值,保存后重新加载一致 · e2e+runtime-readcurve edits real scalar key values, time and interpolation, persisting through document reload · unitcurve vector editing preserves other components and selected track; invalid values do not mutate · unit验收要求与证据范围标量和向量都驱动真实姿态并保存。e2e+runtime-read:真实控件和指针操作,运行时读取数值校验;curve.axis仅切换无数值独立断言,timeline.seek播放头与Alt吸附未在本例覆盖。 unit:真实曲线控件与 TimelineEditor,标量编辑与文档往返。 unit:向量其它分量保留,当前轨道、非法值保护;不包含显示轴切换或可视像素验收。 |
曲线插值curve.easingmodel-curve-editor.js:30 · change(input) | 本轮修复 | 支持线性、平滑、缓入、缓出、阶梯;没有 Bezier 切线 UI。 | 阶梯插值与已有下游时间轴求值一致。 | 已验证时间轴真实控件:轨道/关键帧/播放与曲线 5 插值,保存后重新加载一致 · e2e+runtime-readcurve edits real scalar key values, time and interpolation, persisting through document reload · unit验收要求与证据范围修改插值改变中间帧,重开保留。e2e+runtime-read:真实控件和指针操作,运行时读取数值校验;curve.axis仅切换无数值独立断言,timeline.seek播放头与Alt吸附未在本例覆盖。 unit:真实曲线控件与 TimelineEditor,标量编辑与文档往返。 |
曲线 XYZ 分量显示curve.axismodel-curve-editor.js:30 · change(input) | 已有实现 | 改变图上显示分量,不改另外两轴的数据。 | 当前实际向量轨道才出现。 | 已验证补充时间轴与蓝图工具:刻度/按键/记录/分量、基准匹配、节点搜索拖入与画布平移 · e2e+runtime-read验收要求与证据范围切分量显示不同曲线,数值不被改写。e2e+runtime-read:真实模型编辑参数/基准轨道生成验收,不构成装备操作或维修指导。桥梁原工程94仅GET和copy。 |
蓝图与交互反馈
| 功能 / 真实执行路径 | 实现状态 | 闭环与边界 | 本轮对应修复 | 测试证据 / 验收要求 |
|---|---|---|---|---|
节点库搜索 / 拖入节点blueprint.paletteblueprint.js:287 · _renderPalette | 已有实现 | 当前七类节点:触发、时间轴、等待、高亮、提示、条件、完成。 | 不新增任意脚本节点。 | 已验证补充时间轴与蓝图工具:刻度/按键/记录/分量、基准匹配、节点搜索拖入与画布平移 · e2e+runtime-read验收要求与证据范围搜索、拖入后节点类型和参数可保存。e2e+runtime-read:真实模型编辑参数/基准轨道生成验收,不构成装备操作或维修指导。桥梁原工程94仅GET和copy。 |
添加节点按钮blueprint.addblueprint.js:257 · _bind() | 已有实现 | 工具栏默认添加提示节点;其他类型来自节点库。 | 无本轮专门改动。 | 已验证补充时间轴与蓝图工具:刻度/按键/记录/分量、基准匹配、节点搜索拖入与画布平移 · e2e+runtime-read验收要求与证据范围新增进入画布、历史与 JSON。e2e+runtime-read:真实模型编辑参数/基准轨道生成验收,不构成装备操作或维修指导。桥梁原工程94仅GET和copy。 |
节点标题 / 参数编辑blueprint.parametersblueprint.js:431 · _renderInspector | 已有实现 | 按节点类型提供数字、文字、枚举、复选框。 | 保留数值边界与真实数据写回。 | 已验证蓝图真实节点库与端口拖线:七种参数、内部边复制/剪切、撤销重做及保存 · e2e+runtime-read验收要求与证据范围改参数与标题后重开保留。e2e+runtime-read:节点库点选添加及实际拖动/接线/执行;不把点选当成节点拖入,不把适应画布当成鼠标平移缩放全部已验。 |
节点拖动 / 多选框选blueprint.moveblueprint.js:566 · _onViewportPointerDown | 已有实现 | 节点布局随蓝图 JSON 保存。 | 无本轮专门改动。 | 已验证蓝图真实节点库与端口拖线:七种参数、内部边复制/剪切、撤销重做及保存 · e2e+runtime-read验收要求与证据范围多选移动位置正确,撤销恢复。e2e+runtime-read:节点库点选添加及实际拖动/接线/执行;不把点选当成节点拖入,不把适应画布当成鼠标平移缩放全部已验。 |
连接 / 替换 / 删除执行线blueprint.connectblueprint.js:767 · connect( | 本轮修复 | 单输出重连替换;允许多个来源汇聚同一输入。 | 不再清掉同一输入的其他合法来源。 | 已验证蓝图真实节点库与端口拖线:七种参数、内部边复制/剪切、撤销重做及保存 · e2e+runtime-read验收要求与证据范围true/false 汇聚保留两条,替换输出只影响该线。e2e+runtime-read:节点库点选添加及实际拖动/接线/执行;不把点选当成节点拖入,不把适应画布当成鼠标平移缩放全部已验。 |
删除节点 / 连线blueprint.deleteblueprint.js:786 · deleteSelection | 已有实现 | 删除节点一并清理相关边。 | 复制/剪切使用同一图数据合同。 | 已验证蓝图真实节点库与端口拖线:七种参数、内部边复制/剪切、撤销重做及保存 · e2e+runtime-read验收要求与证据范围无悬空边;撤销恢复完整图。e2e+runtime-read:节点库点选添加及实际拖动/接线/执行;不把点选当成节点拖入,不把适应画布当成鼠标平移缩放全部已验。 |
复制 / 剪切 / 粘贴blueprint.copyblueprint.js:714 · copySelection | 本轮修复 | Ctrl/Cmd+C/X/V;复制选区内部边,不复制指向外部的边。 | 新节点 ID 和内部连线同步生成,阻止快捷键冒泡。 | 已验证蓝图真实节点库与端口拖线:七种参数、内部边复制/剪切、撤销重做及保存 · e2e+runtime-read验收要求与证据范围副本内部连接正确,不误删外部对象。e2e+runtime-read:节点库点选添加及实际拖动/接线/执行;不把点选当成节点拖入,不把适应画布当成鼠标平移缩放全部已验。 |
平移 / 缩放 / 适应画布blueprint.canvasblueprint.js:801 · frameAll | 已有实现 | 蓝图画布浏览;不是三维相机。 | 无本轮专门改动。 | 已验证补充时间轴与蓝图工具:刻度/按键/记录/分量、基准匹配、节点搜索拖入与画布平移 · e2e+runtime-read验收要求与证据范围滚轮、Space 拖动和适应可见全部节点。e2e+runtime-read:真实模型编辑参数/基准轨道生成验收,不构成装备操作或维修指导。桥梁原工程94仅GET和copy。 |
运行 / F5blueprint.runblueprint.js:871 · async run( | 本轮修复 | 在当前模型编辑器驱动真实场景;有 200 步循环上限。 | 条件与等待流程回归。 | 已验证蓝图真实节点库与端口拖线:七种参数、内部边复制/剪切、撤销重做及保存 · e2e+runtime-read验收要求与证据范围执行高亮、动作、反馈;循环图可终止不挂死。e2e+runtime-read:节点库点选添加及实际拖动/接线/执行;不把点选当成节点拖入,不把适应画布当成鼠标平移缩放全部已验。 |
停止运行blueprint.stopblueprint.js:997 · stop( | 本轮修复 | 停止中断挂起等待,旧运行不覆盖新运行状态。 | AbortSignal 贯穿宿主动作与高亮清理。 | 已验证蓝图真实节点库与端口拖线:七种参数、内部边复制/剪切、撤销重做及保存 · e2e+runtime-read验收要求与证据范围等待/动画中停止及时退出,无迟到完成提示。e2e+runtime-read:节点库点选添加及实际拖动/接线/执行;不把点选当成节点拖入,不把适应画布当成鼠标平移缩放全部已验。 |
重置执行blueprint.resetblueprint.js:1014 · resetExecution | 已有实现 | 复位执行状态、时间轴和高亮;保留蓝图编辑内容。 | 高亮恢复原材质。 | 已验证蓝图真实节点库与端口拖线:七种参数、内部边复制/剪切、撤销重做及保存 · e2e+runtime-read验收要求与证据范围运行后重置,进度归零且节点图不丢。e2e+runtime-read:节点库点选添加及实际拖动/接线/执行;不把点选当成节点拖入,不把适应画布当成鼠标平移缩放全部已验。 |
点击触发目标blueprint.clickblueprint.js:933 · async trigger( | 本轮修复 | 匹配事件和目标 ID/名称/祖先别名;空目标可通配。 | 不再点击 B 触发 A。 | 已验证已保存蓝图:条件出口与目标匹配 runtime 检查,真实模型单击/双击/进入预览自动触发 · e2e验收要求与证据范围两个不同目标分别点击,只运行匹配分支。e2e:执行使用正式模型编辑器的真实模型/时间轴/高亮/提示 handler;不等同于学员端任务下发。 |
双击触发目标blueprint.double-clickmain.js:2256 · pickObject | 本轮修复 | 双击独立派发 double-click,与单击区分。 | 增加真实视口双击派发并抑制待发单击。 | 已验证已保存蓝图:条件出口与目标匹配 runtime 检查,真实模型单击/双击/进入预览自动触发 · e2e验收要求与证据范围双击只触发目标的双击分支。e2e:执行使用正式模型编辑器的真实模型/时间轴/高亮/提示 handler;不等同于学员端任务下发。 |
自动触发blueprint.automain.js:2284 · togglePreview | 本轮修复 | 仅进入预览显式派发 auto,不把每次单击当 auto。 | 事件匹配与进入预览联动。 | 已验证已保存蓝图:条件出口与目标匹配 runtime 检查,真实模型单击/双击/进入预览自动触发 · e2e验收要求与证据范围进入预览触发一次,普通点击不重放自动分支。e2e:执行使用正式模型编辑器的真实模型/时间轴/高亮/提示 handler;不等同于学员端任务下发。 |
播放时间轴节点blueprint.timelinemain.js:2024 · playTimelineForBlueprint | 本轮修复 | 播放当前唯一时间轴,动作名称仅描述;支持起始时间、速度、等待。 | 起始末帧不反跳零,终止可取消。 | 已验证蓝图真实节点库与端口拖线:七种参数、内部边复制/剪切、撤销重做及保存 · e2e+runtime-read验收要求与证据范围起始时间和速度实际生效,等待与不等待分支正确。e2e+runtime-read:节点库点选添加及实际拖动/接线/执行;不把点选当成节点拖入,不把适应画布当成鼠标平移缩放全部已验。 |
等待节点blueprint.waitblueprint.js:1 · NODE_TYPES | 已有实现 | 指定毫秒等待;可被停止取消。 | 异步停止及时结束。 | 已验证蓝图真实节点库与端口拖线:七种参数、内部边复制/剪切、撤销重做及保存 · e2e+runtime-read验收要求与证据范围等待期间停止不会继续执行后续节点。e2e+runtime-read:节点库点选添加及实际拖动/接线/执行;不把点选当成节点拖入,不把适应画布当成鼠标平移缩放全部已验。 |
高亮节点 / 呼吸效果blueprint.highlightmain.js:2052 · highlightPart | 本轮修复 | 准确命中可见对象;同名歧义要求标识;没有可高亮材质则报错。 | 拒绝错误整机回退,真实呼吸效果,保存忽略临时高亮。 | 已验证蓝图真实节点库与端口拖线:七种参数、内部边复制/剪切、撤销重做及保存 · e2e+runtime-readvisible child under a hidden ancestor cannot be picked or highlighted; trigger aliases include ancestors · unithighlight rejects missing/hidden targets and transient colors never enter a saved project · unit验收要求与证据范围目标正确、找不到报错、结束恢复、保存不永久染色。e2e+runtime-read:节点库点选添加及实际拖动/接线/执行;不把点选当成节点拖入,不把适应画布当成鼠标平移缩放全部已验。 unit:共用可见性和祖先别名函数;鼠标事件另由 E2E 验证。 unit:目标不存在/隐藏报错,执行时暂态发光颜色不进入保存文档,结束恢复原材质。 |
操作提示节点blueprint.messagemain.js:2099 · showTeachingMessage | 现有边界 | 显示标题/文本,可点击关闭或约 1.8/2.5 秒自动继续;不是强制人员确认。 | 不将其当作业务审核/签名。 | 已验证蓝图真实节点库与端口拖线:七种参数、内部边复制/剪切、撤销重做及保存 · e2e+runtime-read验收要求与证据范围文本出现、关闭和停止不留弹层。e2e+runtime-read:节点库点选添加及实际拖动/接线/执行;不把点选当成节点拖入,不把适应画布当成鼠标平移缩放全部已验。 |
条件判断节点blueprint.conditionmain.js:2095 · evaluateBlueprintCondition | 本轮修复 | 当前运行变量、嵌套字段、truthy/布尔/数字比较。 | false 没有出口不走 true,字符串布尔正确解析。 | 已验证已保存蓝图:条件出口与目标匹配 runtime 检查,真实模型单击/双击/进入预览自动触发 · runtimeboolean, numeric and nested blueprint conditions select their true/false branches · unit验收要求与证据范围真假分支分别验证,缺出口不误执行。unit:布尔、数字、truthy 与嵌套路径值解析。 |
流程完成节点blueprint.finishmain.js:1075 · initEditors | 已有实现 | 本次预览结果/进度提示,不写教学任务成绩。 | 保持本次运行反馈边界。 | 已验证蓝图真实节点库与端口拖线:七种参数、内部边复制/剪切、撤销重做及保存 · e2e+runtime-read验收要求与证据范围成功/完成提示与实际执行结果一致。e2e+runtime-read:节点库点选添加及实际拖动/接线/执行;不把点选当成节点拖入,不把适应画布当成鼠标平移缩放全部已验。 |
发布、交付与运行信息
| 功能 / 真实执行路径 | 实现状态 | 闭环与边界 | 本轮对应修复 | 测试证据 / 验收要求 |
|---|---|---|---|---|
生成 / 发布检查面板publish.preflightmain.js:2978 · togglePublishPanel | 现有边界 | 本地主要检查资源引用存在及轨道/节点数量,不执行完整蓝图可达性、终止性或业务校验;服务端发布校验最终生效。 | 发布目标与离线交付能力明确。 | 已验证受控 GLB 下载失败阻止编辑,重试成功;发布预检开关无写入且拒绝错误资源 JSON · e2e+api验收要求与证据范围可打开关闭;不完整工程不能凭界面绿标绕过服务端。e2e+api:真实受控下载定向503→中性失败与禁止编辑→解除故障后UI重试成功;预检面板开关不写项目,错误资源JSON在替换当前模型之前被拒绝。服务端发布时code/URI一致性拒绝由ContentProjectServiceTest合同回归覆盖,未把面板绿标代替服务端校验。 |
发布到场景资源库publish.apimain.js:2897 · publishToSceneLibrary | 本轮修复 | 先保存当前工程再发布固定版本;纯 publisher 发布已保存版本。 | 整个保存/发布队列互斥,失败不发后续发布。 | 已验证直接发布同步截图封面、固定版本目录与真实离线步骤 HTML · e2e+apiAPI publish supplies current cover, blocks duplicate publication and reports preserved old cover once · unitAPI conflict leaves publication failed and releases the cover guard · unit验收要求与证据范围发布版本/模型资产/列表状态一致,保存失败不发布。e2e+api:目录可取得固定发布版本及同版封面;HTML已真实打开并确认演示边界,未声明下游动画执行或完整离线三维运行。 unit:实际发布宿主方法传封面、重入阻断和上传失败只提示一次;模拟 API,不是实际服务响应。 unit:409 分支不误报已发布并释放 busy 标记;模拟 API。 |
发布时当前三维截图封面publish.covermain.js:2897 · publishToSceneLibrary | 本轮修复 | JPEG 当前视口;截图或上传失败可保留旧封面并明确提示。 | 与手动保存共用封面链路,409 阻断。 | 已验证直接发布同步截图封面、固定版本目录与真实离线步骤 HTML · e2e+apiAPI publish supplies current cover, blocks duplicate publication and reports preserved old cover once · unitAPI conflict leaves publication failed and releases the cover guard · unit验收要求与证据范围真实封面图对应当前模型;上传失败提示一次,旧图保留。e2e+api:目录可取得固定发布版本及同版封面;HTML已真实打开并确认演示边界,未声明下游动画执行或完整离线三维运行。 unit:实际发布宿主方法传封面、重入阻断和上传失败只提示一次;模拟 API,不是实际服务响应。 unit:409 分支不误报已发布并释放 busy 标记;模拟 API。 |
导出步骤演示 HTMLpublish.htmlmain.js:3011 · exportStandaloneHtml | 本轮澄清 | 工程数据、静态截图和步骤演示;不包含 GLB、不执行真实三维交互。 | 生成面板和按钮移除完整离线运行的误导。 | 已验证直接发布同步截图封面、固定版本目录与真实离线步骤 HTML · e2e+api验收要求与证据范围下载可打开、步骤导航可用,醒目标明不含三维模型。e2e+api:目录可取得固定发布版本及同版封面;HTML已真实打开并确认演示边界,未声明下游动画执行或完整离线三维运行。 |
下游读取模型固定版本publish.downstreammodel-content-api.js:1159 · publishDocument | 现有边界 | 已发布模型作为资源引用;下游自动执行模型 timeline/blueprint 尚无统一运行桥接。 | 本轮不将资源加载成功等同动作自动运行成功。 | 已验证直接发布同步截图封面、固定版本目录与真实离线步骤 HTML · e2e+api验收要求与证据范围固定引用/可见性单独测;自动动作执行列为待确认范围。e2e+api:目录可取得固定发布版本及同版封面;HTML已真实打开并确认演示边界,未声明下游动画执行或完整离线三维运行。 |
运行日志feedback.logmain.js:3116 · log(message | 已有实现 | 本次内存运行日志,最多 160 条;不是服务端审计日志。 | 错误信息转义,保留清晰运行结果。 | 已验证补充视口与工作区:鼠标镜头、聚焦、面板、预览导航、日志与自动保存 · e2e+api验收要求与证据范围选中/运行/保存产生相应日志,不要求刷新保留。e2e+api:真实鼠标镜头操作;聚焦只验证相机目标;真实30秒自动保存,无测试加速定时器;统计内存估值未当作性能结论。 |
节点 / 三角面 / FPS 等状态feedback.statsmain.js:3094 · updateStats | 现有边界 | 节点与三角面统计、当前 FPS;内存为估算值,不是精确浏览器内存剖析。 | 无本轮性能仪表重构。 | 已验证补充视口与工作区:鼠标镜头、聚焦、面板、预览导航、日志与自动保存 · e2e+api验收要求与证据范围载入模型后统计有合理变化,状态不作为性能验收数据。e2e+api:真实鼠标镜头操作;聚焦只验证相机目标;真实30秒自动保存,无测试加速定时器;统计内存估值未当作性能结论。 |
成功 / 错误短消息feedback.toastmain.js:3117 · toast(message | 已有实现 | 瞬时反馈;保存/发布成功以接口完成为准。 | 封面失败不伪报全部成功。 | 已验证保存请求超时和 409 保留恢复副本,解除故障后可重试 · e2e+apiAPI publish supplies current cover, blocks duplicate publication and reports preserved old cover once · unit验收要求与证据范围失败出现一次明确提示,自动消失,不形成重复常驻错误条。e2e+api:真实页面保存及真实服务端重试;失败由浏览器定向注入 timedout/409,非宣称自然发生的服务故障。 unit:实际发布宿主方法传封面、重入阻断和上传失败只提示一次;模拟 API,不是实际服务响应。 |
执行结果与证据分层
浏览器 E2E
19/19 项通过 · 已验证 · Playwright 原始结果
| 用例 | 结果 | 耗时 / 失败原因 |
|---|---|---|
| 受控模型与外部环境 GLB 上传、JSON 往返和刷新重开 | 已验证 | 14.6 秒 |
| 非法 JSON 与未登记 blob 引用导入失败时保留当前文档 | 已验证 | 6.0 秒 |
| 保存请求超时和 409 保留恢复副本,解除故障后可重试 | 已验证 | 9.7 秒 |
| 直接发布同步截图封面、固定版本目录与真实离线步骤 HTML | 已验证 | 7.9 秒 |
| 时间轴真实控件:轨道/关键帧/播放与曲线 5 插值,保存后重新加载一致 | 已验证 | 11.8 秒 |
| 补充时间轴与蓝图工具:刻度/按键/记录/分量、基准匹配、节点搜索拖入与画布平移 | 已验证 | 20.1 秒 |
| 蓝图真实节点库与端口拖线:七种参数、内部边复制/剪切、撤销重做及保存 | 已验证 | 14.1 秒 |
| 已保存蓝图:条件出口与目标匹配 runtime 检查,真实模型单击/双击/进入预览自动触发 | 已验证 | 13.1 秒 |
| 对象名称、变换、PBR、属性与扩展标记保存重开;撤销重做 | 已验证 | 8.4 秒 |
| 场景树搜索、可见性、选择、视口工具、原生动画与截图 | 已验证 | 15.4 秒 |
| 新建工程取消及失败保留输入;成功创建新ID且不覆盖当前模型 | 已验证 | 10.5 秒 |
| 管理员只读权限:编辑、新建、导入、保存发布均不可越权 | 已验证 | 4.7 秒 |
| 真实三维移动、旋转、缩放手柄拖动及撤销重做保存重开 | 已验证 | 9.4 秒 |
| 未保存离开:关闭确认保留工作、保存失败留在原页、重试保存后离开 | 已验证 | 9.5 秒 |
| 补充资源库:搜索清空、真实卡片切换与刷新保留 | 已验证 | 8.5 秒 |
| 补充环境与树:内置三环境保存重开、节点计数与折叠展开 | 已验证 | 22.8 秒 |
| 补充视口与工作区:鼠标镜头、聚焦、面板、预览导航、日志与自动保存 | 已验证 | 34.9 秒 |
| 真实未保存稿同版本恢复并显式保存;旧版本恢复稿下载隔离保留 | 已验证 | 12.5 秒 |
| 受控 GLB 下载失败阻止编辑,重试成功;发布预检开关无写入且拒绝错误资源 JSON | 已验证 | 9.8 秒 |
通过浏览器定向注入的 409/503 等异常仅验证失败处理,不代表开发服务真实发生该故障。UI 点击、脚本调用运行时和纯 API 检查按各用例证据说明区分。
保留首轮失败与定向重跑事实
仅保留安全的次数、名称、时间及源文件哈希;不复制请求正文、会话、错误上下文或私有运行日志。历史轮次不替代当前 results.json,定向2/2不等同全量19/19。 安全迭代记录
| 历史轮次 | 原始结果 | 解释范围 |
|---|---|---|
| 全量首轮 | 17/19 通过 · 该轮失败 | 两例均已完成保存并返回列表,末尾测试辅助GET项目详情返回503;分别定位 interaction:114 与 navigation:142。 |
| 首次鉴权诊断定向重跑 | 0/2 通过 · 该轮失败 | 此轮才在登录阶段超时,业务操作未开始;不与首轮末尾GET详情503混为同一发生阶段。 |
| 后续定向重跑 | 2/2 通过 · 该轮通过 | 只证明这两条在此次运行通过,不能把首轮17/19改写为19/19。 |
| 修复与曲线配色更新后的最终完整轮 | 19/19 通过 · 该轮通过 | 保留原始失败,不以随后同名证据覆盖。 |
已修复 Auth/Tran 数据库连接健康检查可能无界阻塞的问题,并完成实际 Kingbase 驱动隔离黑洞探针(约2010ms释放关闭);最终双模块构建和完整E2E另行记录。该探针不能证明历史每一次503均已逐条与该原因建立因果关联。
完成修复后另跑完整19条,使用新的完整results.json、对应时段证据/附件、最终validation及artifact检查;旧失败保留在本历史记录。
真实 API / 运行时断言
逐份读取 evidence/*.json。文件存在本身不代表通过;每份证据须注明断言结果和覆盖的 featureIds。
evidence/30-assets-roundtrip.json 已验证
{
"time": "2026-09-06T08:20:27.495Z",
"data": {
"status": "PASS",
"kind": "e2e+api",
"testTitle": "受控模型与外部环境 GLB 上传、JSON 往返和刷新重开",
"featureIds": [
"project.import-glb",
"environment.external",
"project.import-json",
"project.export-json",
"project.save"
],
"projectId": "226",
"mainCode": "MODEL_MTPJKFPW_09-FOX",
"environmentCode": "ENV_MODEL_MTPJKH7H_01-BOX",
"mainUri": "fsvc://unreal-tran/model/2026/09/06/b85bd2722c4e133e61469c9f413380f0.glb",
"environmentUri": "fsvc://unreal-tran/model/2026/09/06/9bd7351f3ee917431354690f44a449b5.glb",
"modelMeshes": 1,
"environmentMeshes": 1,
"nativeClips": 3,
"environmentPosition": [
6,
0,
-7
],
"environmentScale": [
0.15,
0.15,
0.15
],
"result": "PASS",
"scope": "真实上传、注册、保存、JSON重导入、刷新后的实际网格和原生动画目录;未断言下游场景执行动画。"
}
}evidence/31-invalid-import.json 已验证
{
"time": "2026-09-06T08:20:33.535Z",
"data": {
"status": "PASS",
"kind": "e2e+api",
"testTitle": "非法 JSON 与未登记 blob 引用导入失败时保留当前文档",
"featureIds": [
"project.import-json"
],
"projectId": "227",
"result": "PASS",
"cases": [
"JSON语法错误",
"无受控资源编号/地址的跨页面blob引用"
],
"retainedVersion": 1
}
}evidence/32-save-failure-recovery.json 已验证
{
"time": "2026-09-06T08:20:43.214Z",
"data": {
"status": "PASS",
"kind": "e2e+api",
"testTitle": "保存请求超时和 409 保留恢复副本,解除故障后可重试",
"featureIds": [
"project.conflict",
"project.save",
"feedback.toast"
],
"projectId": "228",
"result": "PASS",
"intercepted": [
{
"mode": "timedout",
"method": "PUT",
"projectId": "228"
},
{
"mode": "409",
"method": "PUT",
"projectId": "228"
}
],
"scope": "真实页面保存及真实服务端重试;失败由浏览器定向注入 timedout/409,非宣称自然发生的服务故障。"
}
}evidence/34-publish-fixed-version.json 已验证
{
"time": "2026-09-06T08:20:51.047Z",
"data": {
"status": "PASS",
"kind": "e2e+api",
"testTitle": "直接发布同步截图封面、固定版本目录与真实离线步骤 HTML",
"featureIds": [
"publish.api",
"publish.cover",
"publish.html",
"publish.downstream"
],
"projectId": "229",
"result": "PASS",
"versionId": "283",
"coverUri": "fsvc://unreal-tran/image/2026/09/06/14ab7b4e1e7a9d21f13f3504cb8b89ae.jpg",
"priorCoverUri": "fsvc://unreal-tran/image/2026/09/05/c09a49efd4423dcf8ccbc46b46d1e209.jpg",
"mainCode": "MODEL_MTO6V5W6_09-FOX",
"scope": "目录可取得固定发布版本及同版封面;HTML已真实打开并确认演示边界,未声明下游动画执行或完整离线三维运行。"
}
}evidence/41-resource-search-switch.json 已验证
{
"time": "2026-09-06T08:22:56.960Z",
"data": {
"status": "PASS",
"kind": "e2e+api",
"testTitle": "补充资源库:搜索清空、真实卡片切换与刷新保留",
"featureIds": [
"resource.search",
"resource.catalog"
],
"projectId": "235",
"original": {
"id": "imported-model_mto6v5w6_09-fox",
"name": "09-Fox",
"code": "MODEL_MTO6V5W6_09-FOX"
},
"boxId": "imported-model_mtpjnqqk_01-box",
"restored": {
"id": "imported-model_mto6v5w6_09-fox",
"code": "MODEL_MTO6V5W6_09-FOX",
"meshes": 1
},
"scope": "真实搜索与资源卡片点击、服务端保存、刷新后原模型网格;副本独立登记待清理。"
}
}evidence/43-builtin-environments-tree.json 已验证
{
"time": "2026-09-06T08:23:19.759Z",
"data": {
"status": "PASS",
"kind": "e2e+api",
"testTitle": "补充环境与树:内置三环境保存重开、节点计数与折叠展开",
"featureIds": [
"environment.builtin",
"tree.browse",
"tree.expand",
"project.leave"
],
"projectId": "236",
"snapshots": [
{
"type": "workshop",
"mode": "placeholder",
"sourceKind": "placeholder",
"nodes": 48,
"meshes": 45,
"id": "ee302132-152c-4575-a2ec-0a56b4820079",
"shownRows": 76,
"totalNodes": 76
},
{
"type": "outdoor",
"mode": "placeholder",
"sourceKind": "placeholder",
"nodes": 70,
"meshes": 65,
"id": "bf88db35-635d-4012-8df6-dd41382e624f",
"shownRows": 98,
"totalNodes": 98
},
{
"type": "depot",
"mode": "placeholder",
"sourceKind": "builtin-gltf",
"nodes": 41,
"meshes": 32,
"id": "cebab0bb-6910-4dff-b846-9978adcb3450",
"shownRows": 69,
"totalNodes": 69
}
],
"depotSavedLeave": {
"promptedForUnsavedChanges": false,
"version": 5
},
"scope": "真实切换、保存和刷新三种环境;树计数与展开折叠;装备车库保存后返回列表不误报未保存。树220行上限仍属已说明边界。"
}
}evidence/46-navigation-panels-autosave.json 已验证
{
"time": "2026-09-06T08:23:54.656Z",
"data": {
"status": "PASS",
"kind": "e2e+api",
"testTitle": "补充视口与工作区:鼠标镜头、聚焦、面板、预览导航、日志与自动保存",
"featureIds": [
"project.name",
"project.autosave",
"view.orbit",
"view.focus",
"view.panels",
"view.preview-step",
"feedback.log",
"feedback.stats",
"property.identity",
"property.binding",
"selection.scope",
"component.inspect"
],
"projectId": "237",
"focused": {
"position": [
11.153569378931522,
8.526809324389628,
13.922975975299929
],
"target": [
0.01518877997232826,
2.4006999949620704,
2.266009371254541e-7
],
"distance": 18.853169271563605
},
"rotated": {
"position": [
1.7511663652214757,
6.181727848275404,
18.38837160033089
],
"target": [
0.01518877997232826,
2.4006999949620704,
2.266009371254541e-7
],
"distance": 18.853169271563594
},
"panned": {
"position": [
-5.273341581654527,
5.082450786888863,
17.990688935160133
],
"target": [
-0.5866856170824521,
2.73698783970429,
-0.11942014831462
],
"distance": 18.85316927156359
},
"focusTargetScreen": [
-5.177525136316571e-19,
-1.227265217497261e-16,
0.9980999049952497
],
"panelModes": [
"timeline",
"blueprint",
"curve",
"console"
],
"logCount": 8,
"stats": {
"objects": "98 节点 / 66 网格",
"triangles": "1,438",
"fps": "54"
},
"scope": "真实鼠标镜头操作;聚焦只验证相机目标;真实30秒自动保存,无测试加速定时器;统计内存估值未当作性能结论。"
}
}evidence/51-gizmos.json 已验证
{
"time": "2026-09-06T08:22:38.815Z",
"data": {
"status": "PASS",
"kind": "e2e+runtime-readback",
"testTitle": "真实三维移动、旋转、缩放手柄拖动及撤销重做保存重开",
"featureIds": [
"view.move",
"view.rotate",
"view.scale"
],
"projectId": "233",
"changes": [
{
"mode": "translate",
"before": [
0,
0,
0
],
"after": [
0.7257266613731312,
0,
0
]
},
{
"mode": "rotate",
"before": [
0,
0,
0
],
"after": [
-1.194547194225429,
0,
0
]
},
{
"mode": "scale",
"before": [
1,
1,
1
],
"after": [
0.30167729043770014,
1,
1
]
}
],
"reopened": {
"position": [
0.7257266613731312,
0,
0
],
"rotation": [
-1.194547194225429,
0,
0
],
"scale": [
0.30167729043770014,
1,
1
]
}
}
}evidence/52-leave.json 已验证
{
"time": "2026-09-06T08:22:48.155Z",
"data": {
"status": "PASS",
"kind": "e2e+api",
"testTitle": "未保存离开:关闭确认保留工作、保存失败留在原页、重试保存后离开",
"featureIds": [
"project.leave"
],
"projectId": "234",
"closeKeptDraft": true,
"failureKeptDraft": true,
"retriedSavePersisted": true
}
}evidence/60-project-recovery.json 已验证
{
"time": "2026-09-06T08:24:07.184Z",
"data": {
"status": "PASS",
"kind": "e2e+api",
"testTitle": "真实未保存稿同版本恢复并显式保存;旧版本恢复稿下载隔离保留",
"featureIds": [
"project.recovery"
],
"projectId": "238",
"sameVersion": 1,
"explicitSaveVersion": 2,
"concurrentVersion": 3,
"retainedFilename": "recovery-238-isolated.json",
"scope": "通过真实beforeunload创建未保存稿;同版恢复后仅显式保存落库;旧版只下载隔离,不自动覆盖服务端。丢弃/跨标签竞态另由既有恢复合同测试覆盖。"
}
}evidence/63-loading-publish-preflight.json 已验证
{
"time": "2026-09-06T08:24:17.025Z",
"data": {
"status": "PASS",
"kind": "e2e+api",
"testTitle": "受控 GLB 下载失败阻止编辑,重试成功;发布预检开关无写入且拒绝错误资源 JSON",
"featureIds": [
"resource.loading",
"publish.preflight"
],
"projectId": "239",
"failedDownloads": 1,
"retainedVersion": 1,
"scope": "真实受控下载定向503→中性失败与禁止编辑→解除故障后UI重试成功;预检面板开关不写项目,错误资源JSON在替换当前模型之前被拒绝。服务端发布时code/URI一致性拒绝由ContentProjectServiceTest合同回归覆盖,未把面板绿标代替服务端校验。"
}
}evidence/new-project.json 已验证
{
"time": "2026-09-06T08:22:24.723Z",
"data": {
"status": "PASS",
"kind": "e2e+api",
"testTitle": "新建工程取消及失败保留输入;成功创建新ID且不覆盖当前模型",
"featureIds": [
"project.new"
],
"oldId": "168",
"newId": "232",
"cancelPreserved": true,
"failureRetainedName": true,
"originalVersion": 17,
"sourceUnchanged": true
}
}evidence/permissions.json 已验证
{
"time": "2026-09-06T08:22:29.489Z",
"data": {
"status": "PASS",
"kind": "e2e+api",
"testTitle": "管理员只读权限:编辑、新建、导入、保存发布均不可越权",
"featureIds": [
"project.permissions"
],
"scope": "管理员只读UI、真实键盘搜索、原生片段切换与Enter播放/暂停、预览无内容写请求及创建403;纯publisher无需update的发布流程由独立权限合同回归补充。",
"readonlyUi": true,
"readonlySearch": true,
"nativeClipChanged": true,
"keyboardPreview": true,
"previewWriteRequests": 0,
"createStatus": 403
}
}evidence/properties.json 已验证
{
"time": "2026-09-06T08:21:58.738Z",
"data": {
"status": "PASS",
"kind": "e2e+api",
"testTitle": "对象名称、变换、PBR、属性与扩展标记保存重开;撤销重做",
"featureIds": [
"property.name",
"property.position",
"property.rotation",
"property.scale",
"property.color",
"property.metalness",
"property.roughness",
"property.opacity",
"property.code",
"property.status",
"component.tag",
"project.undo",
"project.redo",
"project.save"
],
"scope": "真实属性输入/材质参数/标签、保存与刷新;变换只验数值输入,不代替三维 gizmo 拖动。",
"state": {
"id": "model-imported-model_mto6v5w6_09-fox-26",
"position": [
1.25,
0,
0
],
"rotation": [
0,
0.2617993877991494,
0
],
"scale": [
1,
1,
1.1
],
"customProperties": {
"resourceCode": "CLOSURE-FOX-001",
"operatingStatus": "SERVICE"
},
"customComponents": [
"扩展标记 1",
"扩展标记 2",
"扩展标记 3",
"扩展标记 4",
"扩展标记 5"
]
},
"serverVersion": 15,
"persisted": true
}
}evidence/truck-blueprint-events.json 已验证
{
"time": "2026-09-06T08:21:50.227Z",
"data": {
"status": "PASS",
"kind": "e2e",
"testTitle": "已保存蓝图:条件出口与目标匹配 runtime 检查,真实模型单击/双击/进入预览自动触发",
"featureIds": [
"blueprint.click",
"blueprint.double-click",
"blueprint.auto",
"view.preview"
],
"projectId": "169",
"runtimeSupplement": {
"status": "PASS",
"kind": "runtime",
"featureIds": [
"blueprint.condition"
],
"branches": {
"falseBranch": {
"result": true,
"visitedFinish": false,
"logs": [
{
"time": "16:21:41",
"message": "开始执行 · 闭环-条件判断",
"level": "run",
"nodeId": "node-mtpjlz9t-p124m"
},
{
"time": "16:21:41",
"message": "执行节点:闭环-条件判断",
"level": "run",
"nodeId": "node-mtpjlz9t-p124m"
},
{
"time": "16:21:41",
"message": "条件结果:否 / FALSE",
"level": "warning",
"nodeId": "node-mtpjlz9t-p124m"
},
{
"time": "16:21:41",
"message": "节点“闭环-条件判断”没有后续连线,流程结束",
"level": "warning",
"nodeId": "node-mtpjlz9t-p124m"
},
{
"time": "16:21:41",
"message": "蓝图执行完成 · 1 个节点",
"level": "success",
"nodeId": null
}
]
},
"trueBranch": {
"result": true,
"visitedFinish": true,
"logs": [
{
"time": "16:21:41",
"message": "开始执行 · 闭环-条件判断",
"level": "run",
"nodeId": "node-mtpjlz9t-p124m"
},
{
"time": "16:21:41",
"message": "执行节点:闭环-条件判断",
"level": "run",
"nodeId": "node-mtpjlz9t-p124m"
},
{
"time": "16:21:41",
"message": "条件结果:是 / TRUE",
"level": "success",
"nodeId": "node-mtpjlz9t-p124m"
},
{
"time": "16:21:41",
"message": "执行节点:闭环-流程完成",
"level": "run",
"nodeId": "node-mtpjlznf-cxlzk"
},
{
"time": "16:21:41",
"message": "蓝图执行完成 · 2 个节点",
"level": "success",
"nodeId": null
}
]
}
},
"mismatch": {
"result": false,
"started": false
}
},
"browserEvents": [
{
"event": "click",
"starts": 1,
"finished": true,
"source": "真实 renderer canvas 指针事件",
"logs": [
{
"time": "16:21:42",
"message": "运行状态已重置",
"level": "system",
"nodeId": null
},
{
"time": "16:21:42",
"message": "开始执行 · 闭环-点击触发",
"level": "run",
"nodeId": "node-mtpjlx7c-sgcyx"
},
{
"time": "16:21:42",
"message": "执行节点:闭环-点击触发",
"level": "run",
"nodeId": "node-mtpjlx7c-sgcyx"
},
{
"time": "16:21:42",
"message": "执行节点:闭环-播放时间轴",
"level": "run",
"nodeId": "node-mtpjlxj9-y3g3v"
},
{
"time": "16:21:42",
"message": "执行节点:闭环-等待",
"level": "run",
"nodeId": "node-mtpjlxxe-ond97"
},
{
"time": "16:21:42",
"message": "执行节点:闭环-高亮部件",
"level": "run",
"nodeId": "node-mtpjlyci-4c5oi"
},
{
"time": "16:21:42",
"message": "执行节点:闭环-操作提示",
"level": "run",
"nodeId": "node-mtpjlyuw-164xj"
},
{
"time": "16:21:43",
"message": "执行节点:闭环-条件判断",
"level": "run",
"nodeId": "node-mtpjlz9t-p124m"
},
{
"time": "16:21:43",
"message": "条件结果:是 / TRUE",
"level": "success",
"nodeId": "node-mtpjlz9t-p124m"
},
{
"time": "16:21:43",
"message": "执行节点:闭环-流程完成",
"level": "run",
"nodeId": "node-mtpjlznf-cxlzk"
},
{
"time": "16:21:43",
"message": "蓝图执行完成 · 7 个节点",
"level": "success",
"nodeId": null
}
]
},
{
"event": "double-click",
"starts": 1,
"finished": true,
"source": "真实 renderer canvas 指针事件",
"logs": [
{
"time": "16:21:43",
"message": "运行状态已重置",
"level": "system",
"nodeId": null
},
{
"time": "16:21:44",
"message": "开始执行 · 闭环-点击触发",
"level": "run",
"nodeId": "node-mtpjlx7c-sgcyx"
},
{
"time": "16:21:44",
"message": "执行节点:闭环-点击触发",
"level": "run",
"nodeId": "node-mtpjlx7c-sgcyx"
},
{
"time": "16:21:44",
"message": "执行节点:闭环-播放时间轴",
"level": "run",
"nodeId": "node-mtpjlxj9-y3g3v"
},
{
"time": "16:21:44",
"message": "执行节点:闭环-等待",
"level": "run",
"nodeId": "node-mtpjlxxe-ond97"
},
{
"time": "16:21:44",
"message": "执行节点:闭环-高亮部件",
"level": "run",
"nodeId": "node-mtpjlyci-4c5oi"
},
{
"time": "16:21:44",
"message": "执行节点:闭环-操作提示",
"level": "run",
"nodeId": "node-mtpjlyuw-164xj"
},
{
"time": "16:21:45",
"message": "执行节点:闭环-条件判断",
"level": "run",
"nodeId": "node-mtpjlz9t-p124m"
},
{
"time": "16:21:45",
"message": "条件结果:是 / TRUE",
"level": "success",
"nodeId": "node-mtpjlz9t-p124m"
},
{
"time": "16:21:45",
"message": "执行节点:闭环-流程完成",
"level": "run",
"nodeId": "node-mtpjlznf-cxlzk"
},
{
"time": "16:21:45",
"message": "蓝图执行完成 · 7 个节点",
"level": "success",
"nodeId": null
}
]
},
{
"event": "auto",
"starts": 1,
"finished": true,
"source": "真实点击进入预览",
"logs": [
{
"time": "16:21:45",
"message": "运行状态已重置",
"level": "system",
"nodeId": null
},
{
"time": "16:21:45",
"message": "开始执行 · 闭环-点击触发",
"level": "run",
"nodeId": "node-mtpjlx7c-sgcyx"
},
{
"time": "16:21:45",
"message": "执行节点:闭环-点击触发",
"level": "run",
"nodeId": "node-mtpjlx7c-sgcyx"
},
{
"time": "16:21:45",
"message": "执行节点:闭环-播放时间轴",
"level": "run",
"nodeId": "node-mtpjlxj9-y3g3v"
},
{
"time": "16:21:45",
"message": "执行节点:闭环-等待",
"level": "run",
"nodeId": "node-mtpjlxxe-ond97"
},
{
"time": "16:21:45",
"message": "执行节点:闭环-高亮部件",
"level": "run",
"nodeId": "node-mtpjlyci-4c5oi"
},
{
"time": "16:21:46",
"message": "执行节点:闭环-操作提示",
"level": "run",
"nodeId": "node-mtpjlyuw-164xj"
},
{
"time": "16:21:46",
"message": "执行节点:闭环-条件判断",
"level": "run",
"nodeId": "node-mtpjlz9t-p124m"
},
{
"time": "16:21:46",
"message": "条件结果:是 / TRUE",
"level": "success",
"nodeId": "node-mtpjlz9t-p124m"
},
{
"time": "16:21:46",
"message": "执行节点:闭环-流程完成",
"level": "run",
"nodeId": "node-mtpjlznf-cxlzk"
},
{
"time": "16:21:46",
"message": "蓝图执行完成 · 7 个节点",
"level": "success",
"nodeId": null
}
]
}
],
"persistedNodeCount": 7,
"persistedEdgeCount": 6,
"scope": "执行使用正式模型编辑器的真实模型/时间轴/高亮/提示 handler;不等同于学员端任务下发。"
}
}evidence/truck-blueprint-tool-supplement.json 已验证
{
"time": "2026-09-06T08:21:23.003Z",
"data": {
"status": "PASS",
"kind": "e2e+runtime-read",
"testTitle": "补充时间轴与蓝图工具:刻度/按键/记录/分量、基准匹配、节点搜索拖入与画布平移",
"featureIds": [
"timeline.seek",
"timeline.record",
"timeline.baseline",
"curve.axis",
"blueprint.palette",
"blueprint.add",
"blueprint.canvas"
],
"projectIds": [
"230",
"231"
],
"pose": {
"time": 0.9666666666666666,
"value": [
2.4166666666666665,
-0.9666666666666666,
0
],
"actual": [
2.4166666666666665,
-0.9666666666666666,
0
],
"base": [
0,
0,
0
]
},
"recorded": {
"id": "key-u60x1lh",
"time": 0.9666666666666666,
"value": [
2.4166666666666665,
-0.9666666666666666,
0
],
"easing": "easeInOut"
},
"curveAxis": {
"xAndYPathsDiffer": true,
"values": [
5,
-2,
0
]
},
"noMatchPreserved": true,
"baseline": {
"name": "闭环工具补充-基准匹配-mtpjlmiy",
"timeline": {
"version": 1,
"duration": 12,
"currentTime": 0,
"loop": true,
"zoom": 1,
"tracks": [
{
"id": "bridge-front-outrigger-drop",
"name": "前支腿下落支撑",
"targetId": "bridge-front-outrigger",
"property": "position",
"color": "#ffd166",
"muted": false,
"keyframes": [
{
"id": "bfo-k0",
"time": 0,
"value": [
0,
0,
0
],
"easing": "easeInOut"
},
{
"id": "bfo-k1",
"time": 2.4,
"value": [
0,
-0.45,
0
],
"easing": "easeInOut"
},
{
"id": "bfo-k2",
"time": 10,
"value": [
0,
-0.45,
0
],
"easing": "linear"
},
{
"id": "bfo-k3",
"time": 12,
"value": [
0,
0,
0
],
"easing": "easeInOut"
}
]
},
{
"id": "bridge-rear-outrigger-drop",
"name": "后支腿下落支撑",
"targetId": "bridge-rear-outrigger",
"property": "position",
"color": "#f4a261",
"muted": false,
"keyframes": [
{
"id": "bro-k0",
"time": 0,
"value": [
0,
0,
0
],
"easing": "easeInOut"
},
{
"id": "bro-k1",
"time": 2.2,
"value": [
0,
-0.19,
0
],
"easing": "easeInOut"
},
{
"id": "bro-k2",
"time": 10,
"value": [
0,
-0.19,
0
],
"easing": "linear"
},
{
"id": "bro-k3",
"time": 12,
"value": [
0,
0,
0
],
"easing": "easeInOut"
}
]
},
{
"id": "bridge-rear-support-drop",
"name": "后支座下落支撑",
"targetId": "bridge-rear-support",
"property": "position",
"color": "#e76f51",
"muted": false,
"keyframes": [
{
"id": "brs-k0",
"time": 0,
"value": [
0,
0,
0
],
"easing": "easeInOut"
},
{
"id": "brs-k1",
"time": 0.4,
"value": [
0,
0,
0
],
"easing": "easeInOut"
},
{
"id": "brs-k2",
"time": 2.6,
"value": [
0,
-0.25,
0
],
"easing": "easeInOut"
},
{
"id": "brs-k3",
"time": 10.2,
"value": [
0,
-0.25,
0
],
"easing": "linear"
},
{
"id": "brs-k4",
"time": 12,
"value": [
0,
0,
0
],
"easing": "easeInOut"
}
]
},
{
"id": "bridge-gantry-slew",
"name": "回转门架回转",
"targetId": "bridge-gantry",
"property": "rotation.y",
"color": "#2a9d8f",
"muted": false,
"keyframes": [
{
"id": "bgs-k0",
"time": 0,
"value": 0,
"easing": "easeInOut"
},
{
"id": "bgs-k1",
"time": 2.2,
"value": 0,
"easing": "easeInOut"
},
{
"id": "bgs-k2",
"time": 4.8,
"value": 0.24,
"easing": "easeInOut"
},
{
"id": "bgs-k3",
"time": 8.6,
"value": 0.24,
"easing": "linear"
},
{
"id": "bgs-k4",
"time": 11.4,
"value": 0,
"easing": "easeInOut"
},
{
"id": "bgs-k5",
"time": 12,
"value": 0,
"easing": "easeInOut"
}
]
},
{
"id": "bridge-gantry-upper-luffing",
"name": "门架上臂变幅",
"targetId": "bridge-gantry-upper",
"property": "rotation.x",
"color": "#8a68e8",
"muted": false,
"keyframes": [
{
"id": "bgu-k0",
"time": 0,
"value": 0,
"easing": "easeInOut"
},
{
"id": "bgu-k1",
"time": 3,
"value": 0,
"easing": "easeInOut"
},
{
"id": "bgu-k2",
"time": 5.4,
"value": -0.22,
"easing": "easeInOut"
},
{
"id": "bgu-k3",
"time": 8.8,
"value": -0.22,
"easing": "linear"
},
{
"id": "bgu-k4",
"time": 11.2,
"value": 0,
"easing": "easeInOut"
},
{
"id": "bgu-k5",
"time": 12,
"value": 0,
"easing": "easeInOut"
}
]
},
{
"id": "bridge-erection-frame-luffing",
"name": "后架设架起落(抬头 → 落桥)",
"targetId": "bridge-erection-frame",
"property": "rotation.x",
"color": "#4cc9f0",
"muted": false,
"keyframes": [
{
"id": "bef-k0",
"time": 0,
"value": 0,
"easing": "easeInOut"
},
{
"id": "bef-k1",
"time": 3.6,
"value": 0,
"easing": "easeInOut"
},
{
"id": "bef-k2",
"time": 5,
"value": -0.07,
"easing": "easeInOut"
},
{
"id": "bef-k3",
"time": 7.8,
"value": 0.2,
"easing": "easeInOut"
},
{
"id": "bef-k4",
"time": 9.8,
"value": 0.2,
"easing": "linear"
},
{
"id": "bef-k5",
"time": 11.6,
"value": 0,
"easing": "easeInOut"
},
{
"id": "bef-k6",
"time": 12,
"value": 0,
"easing": "easeInOut"
}
]
},
{
"id": "bridge-luffing-cylinder-follow",
"name": "变幅缸随动",
"targetId": "bridge-luffing-cylinder",
"property": "rotation.x",
"color": "#90be6d",
"muted": false,
"keyframes": [
{
"id": "blc-k0",
"time": 0,
"value": 0,
"easing": "easeInOut"
},
{
"id": "blc-k1",
"time": 3.6,
"value": 0,
"easing": "easeInOut"
},
{
"id": "blc-k2",
"time": 5,
"value": -0.03,
"easing": "easeInOut"
},
{
"id": "blc-k3",
"time": 7.8,
"value": 0.09,
"easing": "easeInOut"
},
{
"id": "blc-k4",
"time": 9.8,
"value": 0.09,
"easing": "linear"
},
{
"id": "blc-k5",
"time": 11.6,
"value": 0,
"easing": "easeInOut"
},
{
"id": "blc-k6",
"time": 12,
"value": 0,
"easing": "easeInOut"
}
]
},
{
"id": "bridge-carriage-travel",
"name": "移动架沿滑道后行",
"targetId": "bridge-carriage",
"property": "position",
"color": "#32b8e6",
"muted": false,
"keyframes": [
{
"id": "bct-k0",
"time": 0,
"value": [
0,
0,
0
],
"easing": "easeInOut"
},
{
"id": "bct-k1",
"time": 5.4,
"value": [
0,
0,
0
],
"easing": "easeInOut"
},
{
"id": "bct-k2",
"time": 8.4,
"value": [
0,
0,
-0.42
],
"easing": "easeInOut"
},
{
"id": "bct-k3",
"time": 10,
"value": [
0,
0,
-0.42
],
"easing": "linear"
},
{
"id": "bct-k4",
"time": 12,
"value": [
0,
0,
0
],
"easing": "easeInOut"
}
]
},
{
"id": "bridge-launch-pinion-drive",
"name": "导梁销齿轮驱动",
"targetId": "bridge-launch-pinion",
"property": "rotation.x",
"color": "#f9c74f",
"muted": false,
"keyframes": [
{
"id": "blp-k0",
"time": 0,
"value": 0,
"easing": "linear"
},
{
"id": "blp-k1",
"time": 5.4,
"value": 0,
"easing": "linear"
},
{
"id": "blp-k2",
"time": 8.4,
"value": 5.2,
"easing": "linear"
},
{
"id": "blp-k3",
"time": 10,
"value": 5.2,
"easing": "linear"
},
{
"id": "blp-k4",
"time": 12,
"value": 0,
"easing": "linear"
}
]
},
{
"id": "bridge-front-cradle-luffing",
"name": "前托架抬头",
"targetId": "bridge-front-cradle",
"property": "rotation.x",
"color": "#ff9f2f",
"muted": false,
"keyframes": [
{
"id": "bfc-k0",
"time": 0,
"value": 0,
"easing": "easeInOut"
},
{
"id": "bfc-k1",
"time": 6.8,
"value": 0,
"easing": "easeInOut"
},
{
"id": "bfc-k2",
"time": 9,
"value": 0.12,
"easing": "easeInOut"
},
{
"id": "bfc-k3",
"time": 10.4,
"value": 0.12,
"easing": "linear"
},
{
"id": "bfc-k4",
"time": 11.8,
"value": 0,
"easing": "easeInOut"
},
{
"id": "bfc-k5",
"time": 12,
"value": 0,
"easing": "easeInOut"
}
]
},
{
"id": "bridge-front-pusher-extend",
"name": "前推送装置送桥",
"targetId": "bridge-front-pusher",
"property": "position",
"color": "#ef476f",
"muted": false,
"keyframes": [
{
"id": "bfp-k0",
"time": 0,
"value": [
0,
0,
0
],
"easing": "easeInOut"
},
{
"id": "bfp-k1",
"time": 7.2,
"value": [
0,
0,
0
],
"easing": "easeInOut"
},
{
"id": "bfp-k2",
"time": 9.4,
"value": [
0,
0,
0.34
],
"easing": "easeInOut"
},
{
"id": "bfp-k3",
"time": 10.6,
"value": [
0,
0,
0.34
],
"easing": "linear"
},
{
"id": "bfp-k4",
"time": 12,
"value": [
0,
0,
0
],
"easing": "easeInOut"
}
]
},
{
"id": "bridge-feed-pinion-drive",
"name": "前推送销齿轮驱动",
"targetId": "bridge-feed-pinion",
"property": "rotation.x",
"color": "#c77dff",
"muted": false,
"keyframes": [
{
"id": "bfd-k0",
"time": 0,
"value": 0,
"easing": "linear"
},
{
"id": "bfd-k1",
"time": 7.2,
"value": 0,
"easing": "linear"
},
{
"id": "bfd-k2",
"time": 9.4,
"value": 4,
"easing": "linear"
},
{
"id": "bfd-k3",
"time": 10.6,
"value": 4,
"easing": "linear"
},
{
"id": "bfd-k4",
"time": 12,
"value": 0,
"easing": "linear"
}
]
}
]
},
"resolved": true
},
"addedNode": {
"id": "node-mtpjlj3c-n13gc",
"type": "message",
"title": "操作提示",
"x": 440,
"y": 160,
"params": {
"title": "操作提示",
"text": "请观察铲斗与动臂的联动过程",
"level": "info"
}
},
"draggedNode": {
"id": "node-mtpjlj9e-sko2s",
"type": "wait",
"title": "等待",
"x": -40,
"y": -170,
"params": {
"duration": 600
}
},
"canvasPreservedGraph": true,
"scope": "真实模型编辑参数/基准轨道生成验收,不构成装备操作或维修指导。桥梁原工程94仅GET和copy。"
}
}evidence/truck-blueprint-ui.json 已验证
{
"time": "2026-09-06T08:21:37.144Z",
"data": {
"status": "PASS",
"kind": "e2e+runtime-read",
"testTitle": "蓝图真实节点库与端口拖线:七种参数、内部边复制/剪切、撤销重做及保存",
"featureIds": [
"blueprint.parameters",
"blueprint.move",
"blueprint.connect",
"blueprint.delete",
"blueprint.copy",
"blueprint.run",
"blueprint.stop",
"blueprint.reset",
"blueprint.timeline",
"blueprint.wait",
"blueprint.highlight",
"blueprint.message",
"blueprint.finish",
"project.undo",
"project.redo"
],
"scope": "节点库点选添加及实际拖动/接线/执行;不把点选当成节点拖入,不把适应画布当成鼠标平移缩放全部已验。",
"projectId": "169",
"graph": {
"nodes": [
{
"id": "node-mtpjlx7c-sgcyx",
"type": "trigger-click",
"title": "闭环-点击触发",
"x": 160,
"y": -120,
"params": {
"event": "click",
"target": "model-imported-model_mto6wi6k_08-cesiummilktruck-3"
}
},
{
"id": "node-mtpjlxj9-y3g3v",
"type": "play-timeline",
"title": "闭环-播放时间轴",
"x": 420,
"y": -120,
"params": {
"clip": "牛奶卡车曲线联动",
"from": 8,
"speed": 2,
"waitForEnd": true
}
},
{
"id": "node-mtpjlxxe-ond97",
"type": "wait",
"title": "闭环-等待",
"x": 680,
"y": -120,
"params": {
"duration": 100
}
},
{
"id": "node-mtpjlyci-4c5oi",
"type": "highlight",
"title": "闭环-高亮部件",
"x": 160,
"y": 70,
"params": {
"target": "model-imported-model_mto6wi6k_08-cesiummilktruck-3",
"color": "#ff8800",
"pulse": false
}
},
{
"id": "node-mtpjlyuw-164xj",
"type": "message",
"title": "闭环-操作提示",
"x": 420,
"y": 70,
"params": {
"title": "卡车模型闭环提示",
"text": "检查真实目标高亮、时间轴完成和条件出口。",
"level": "success"
}
},
{
"id": "node-mtpjlz9t-p124m",
"type": "condition",
"title": "闭环-条件判断",
"x": 680,
"y": 70,
"params": {
"variable": "timelineComplete",
"operator": "==",
"value": true
}
},
{
"id": "node-mtpjlznf-cxlzk",
"type": "finish",
"title": "闭环-流程完成",
"x": 420,
"y": 260,
"params": {
"result": "success",
"text": "牛奶卡车蓝图验证完成"
}
}
],
"edges": [
{
"id": "edge-mtpjm04u-tt0qb",
"from": {
"node": "node-mtpjlx7c-sgcyx",
"port": "then"
},
"to": {
"node": "node-mtpjlxj9-y3g3v",
"port": "in"
}
},
{
"id": "edge-mtpjm0bc-mnf7c",
"from": {
"node": "node-mtpjlxj9-y3g3v",
"port": "then"
},
"to": {
"node": "node-mtpjlxxe-ond97",
"port": "in"
}
},
{
"id": "edge-mtpjm0gx-mu6ys",
"from": {
"node": "node-mtpjlxxe-ond97",
"port": "then"
},
"to": {
"node": "node-mtpjlyci-4c5oi",
"port": "in"
}
},
{
"id": "edge-mtpjm0nr-y06n7",
"from": {
"node": "node-mtpjlyci-4c5oi",
"port": "then"
},
"to": {
"node": "node-mtpjlyuw-164xj",
"port": "in"
}
},
{
"id": "edge-mtpjm0ts-px732",
"from": {
"node": "node-mtpjlyuw-164xj",
"port": "then"
},
"to": {
"node": "node-mtpjlz9t-p124m",
"port": "in"
}
},
{
"id": "edge-mtpjm0zf-sa3h2",
"from": {
"node": "node-mtpjlz9t-p124m",
"port": "true"
},
"to": {
"node": "node-mtpjlznf-cxlzk",
"port": "in"
}
}
],
"running": false,
"logs": [
{
"time": "16:21:35",
"message": "运行状态已重置",
"level": "system",
"nodeId": null
}
]
},
"completedLog": [
{
"time": "16:21:25",
"message": "蓝图编辑器就绪 · 7 类节点已加载",
"level": "system",
"nodeId": null
},
{
"time": "16:21:33",
"message": "开始执行 · 闭环-点击触发",
"level": "run",
"nodeId": "node-mtpjlx7c-sgcyx"
},
{
"time": "16:21:33",
"message": "执行节点:闭环-点击触发",
"level": "run",
"nodeId": "node-mtpjlx7c-sgcyx"
},
{
"time": "16:21:33",
"message": "执行节点:闭环-播放时间轴",
"level": "run",
"nodeId": "node-mtpjlxj9-y3g3v"
},
{
"time": "16:21:33",
"message": "执行节点:闭环-等待",
"level": "run",
"nodeId": "node-mtpjlxxe-ond97"
},
{
"time": "16:21:33",
"message": "执行节点:闭环-高亮部件",
"level": "run",
"nodeId": "node-mtpjlyci-4c5oi"
},
{
"time": "16:21:34",
"message": "执行节点:闭环-操作提示",
"level": "run",
"nodeId": "node-mtpjlyuw-164xj"
},
{
"time": "16:21:35",
"message": "执行节点:闭环-条件判断",
"level": "run",
"nodeId": "node-mtpjlz9t-p124m"
},
{
"time": "16:21:35",
"message": "条件结果:是 / TRUE",
"level": "success",
"nodeId": "node-mtpjlz9t-p124m"
},
{
"time": "16:21:35",
"message": "执行节点:闭环-流程完成",
"level": "run",
"nodeId": "node-mtpjlznf-cxlzk"
},
{
"time": "16:21:35",
"message": "蓝图执行完成 · 7 个节点",
"level": "success",
"nodeId": null
}
],
"actions": "真实节点库/参数控件/端口拖线/复制剪切粘贴/删除/撤销重做/运行停止重置/保存",
"boundaries": "200 步循环保护由独立 Node 回归覆盖;本浏览器流程不注入假图或替换执行 handler。"
}
}evidence/truck-timeline-curve.json 已验证
{
"time": "2026-09-06T08:21:02.898Z",
"data": {
"status": "PASS",
"kind": "e2e+runtime-read",
"testTitle": "时间轴真实控件:轨道/关键帧/播放与曲线 5 插值,保存后重新加载一致",
"featureIds": [
"timeline.play",
"timeline.stop",
"timeline.loop",
"timeline.key-nav",
"timeline.add-track",
"timeline.remove-track",
"timeline.target",
"timeline.property",
"timeline.mute",
"timeline.add-key",
"timeline.delete-key",
"timeline.drag-key",
"timeline.zoom",
"timeline.curve",
"curve.time",
"curve.value",
"curve.easing"
],
"scope": "真实控件和指针操作,运行时读取数值校验;curve.axis仅切换无数值独立断言,timeline.seek播放头与Alt吸附未在本例覆盖。",
"projectId": "169",
"actions": "真实 DOM 轨道/帧增删、关键帧指针拖移、播放控件、曲线输入和保存重开",
"restored": {
"id": "track-0-che4ljm",
"name": "新轨道 6",
"targetId": "interaction-5f7e4bee",
"property": "position",
"color": "#ffb22e",
"muted": false,
"keyframes": [
{
"id": "key-0-0-mi1ztwf",
"time": 0,
"value": [
0,
0,
0
],
"easing": "easeInOut"
},
{
"id": "key-zi8i3f7",
"time": 2,
"value": [
5,
0,
0
],
"easing": "easeInOut"
},
{
"id": "key-0-1-2lnk2wi",
"time": 8,
"value": [
0,
0,
0
],
"easing": "easeInOut"
}
]
},
"interpolationSamples": {
"linear": 1.25,
"easeInOut": 0.625,
"easeIn": 0.3125,
"easeOut": 2.1875,
"step": 0
},
"excluded": [
"未新增 solo 能力",
"未将原生 GLB 动画片段当成多条编辑时间轴"
]
}
}evidence/viewport.json 已验证
{
"time": "2026-09-06T08:22:14.169Z",
"data": {
"status": "PASS",
"kind": "e2e",
"testTitle": "场景树搜索、可见性、选择、视口工具、原生动画与截图",
"featureIds": [
"tree.search",
"tree.visibility",
"selection.sync",
"view.grid",
"view.pbr",
"view.wireframe",
"view.outline",
"view.perspective",
"view.preview",
"view.snapshot",
"timeline.native"
],
"scope": "树搜索、对象隐藏刷新、轮廓及视图开关、原生动画和PNG下载。移动/旋转/缩放只切换模式,真实gizmo拖动仍需补验;聚焦未做几何断言。",
"clips": 3,
"nativeClipPersisted": true,
"hiddenObjectPersisted": true,
"snapshot": "装备模型编辑工具_1788682931740.png"
}
}构建、聚焦单测与版本检查
完整验证记录。单测/合同测试不并入真实 E2E 数量。
{
"time": "2026-09-06T08:28:23.891Z",
"status": "PASS",
"e2eComplete": true,
"checks": [
{
"name": "装备模型编辑回归",
"command": "node --test (8 model editor test files)",
"tests": 54,
"status": "PASS",
"failures": 0,
"exitCode": 0
},
{
"name": "权限桥新建、脏状态和只读键盘回归",
"command": "node --test tools/content-permissions.test.mjs",
"tests": 14,
"status": "PASS",
"failures": 0,
"exitCode": 0
},
{
"name": "报告证据归属与附件校验回归",
"command": "node --test tools/model-editor-report-evidence.test.mjs",
"tests": 7,
"status": "PASS",
"failures": 0,
"exitCode": 0
},
{
"name": "实际 Kingbase 驱动正常检查与隔离网络无响应验证",
"command": "KingbaseValidationProbe (isolated loopback TCP proxy, SELECT 1 only)",
"evidence": "data/kingbase-validation-probe-result.json",
"tests": 3,
"status": "PASS",
"failures": 0,
"exitCode": 0
},
{
"name": "Auth / Tran 完整构建与测试",
"command": "mvn -pl ut_auth,ut_tran -am package",
"tests": 476,
"moduleTests": [
120,
356
],
"status": "PASS",
"failures": 0,
"exitCode": 0
},
{
"name": "Web 构建和 iframe 产物一致性",
"command": "pnpm run build",
"warning": "既有大包体积提示;构建及10项public/dist哈希校验通过",
"status": "PASS",
"failures": 0,
"exitCode": 0
},
{
"name": "6 E2E specs strict TypeScript",
"command": "tsc --noEmit --strict (closure specs, helper, config)",
"status": "PASS",
"failures": 0,
"exitCode": 0
}
],
"coverage": [
{
"title": "resource catalog startup renders all model/environment cards and binds every action with a real DOM",
"featureIds": [
"resource.catalog"
],
"scope": "真实 DOM 渲染、卡片绑定、空目录及 busy 保护;不包含 GLB 网络加载。",
"status": "PASS",
"kind": "unit",
"testFile": "unreal_tran/tests/model-main-closure.test.mjs"
},
{
"title": "curve edits real scalar key values, time and interpolation, persisting through document reload",
"featureIds": [
"timeline.curve",
"curve.time",
"curve.value",
"curve.easing"
],
"scope": "真实曲线控件与 TimelineEditor,标量编辑与文档往返。",
"status": "PASS",
"kind": "unit",
"testFile": "unreal_tran/tests/model-main-closure.test.mjs"
},
{
"title": "curve vector editing preserves other components and selected track; invalid values do not mutate",
"featureIds": [
"curve.value"
],
"scope": "向量其它分量保留,当前轨道、非法值保护;不包含显示轴切换或可视像素验收。",
"status": "PASS",
"kind": "unit",
"testFile": "unreal_tran/tests/model-main-closure.test.mjs"
},
{
"title": "multiple tracks on one property use last effective value; capture subtracts it only once",
"featureIds": [
"timeline.multitrack"
],
"scope": "调用实际 apply/capture/update 基值方法;验证同属性最后有效轨道、静音/删除后中性姿态,偏移只扣一次。",
"status": "PASS",
"kind": "unit",
"testFile": "unreal_tran/tests/model-main-closure.test.mjs"
},
{
"title": "changing a binding resets the former target and keeps manual transform edits as base",
"featureIds": [
"timeline.multitrack",
"timeline.target"
],
"scope": "轨道重绑后旧目标复位,手动变换成为新基值;不假称鼠标拖动已验。",
"status": "PASS",
"kind": "unit",
"testFile": "unreal_tran/tests/model-main-closure.test.mjs"
},
{
"title": "custom properties and extension labels survive actual capture, project JSON and object restore",
"featureIds": [
"property.code",
"property.status",
"component.tag"
],
"scope": "真实对象 capture、normalization、JSON 与 restore 往返;清空和撤销到未存在字段状态。",
"status": "PASS",
"kind": "unit",
"testFile": "unreal_tran/tests/model-main-closure.test.mjs"
},
{
"title": "boolean, numeric and nested blueprint conditions select their true/false branches",
"featureIds": [
"blueprint.condition"
],
"scope": "布尔、数字、truthy 与嵌套路径值解析。",
"status": "PASS",
"kind": "unit",
"testFile": "unreal_tran/tests/model-main-closure.test.mjs"
},
{
"title": "visible child under a hidden ancestor cannot be picked or highlighted; trigger aliases include ancestors",
"featureIds": [
"tree.visibility",
"blueprint.highlight"
],
"scope": "共用可见性和祖先别名函数;鼠标事件另由 E2E 验证。",
"status": "PASS",
"kind": "unit",
"testFile": "unreal_tran/tests/model-main-closure.test.mjs"
},
{
"title": "inspector state tags reflect ancestor visibility and actual shadow flags, with a host editability hook",
"featureIds": [
"property.identity"
],
"scope": "真实属性 DOM 显示隐藏/阴影状态,并提供宿主权限标签 hook;不伪称此单测完成会话鉴权。",
"status": "PASS",
"kind": "unit",
"testFile": "unreal_tran/tests/model-main-closure.test.mjs"
},
{
"title": "history retains 60 states, truncates redo after edits and ignores duplicate snapshots",
"featureIds": [
"project.undo",
"project.redo"
],
"scope": "60 个快照上限、重复状态忽略及新编辑截断 redo 分支。",
"status": "PASS",
"kind": "unit",
"testFile": "unreal_tran/tests/model-main-closure.test.mjs"
},
{
"title": "history serializes async restores and leaves index unchanged when restoration fails",
"featureIds": [
"project.undo",
"project.redo"
],
"scope": "异步互斥、下载失败不移动索引,解除锁后可继续操作。",
"status": "PASS",
"kind": "unit",
"testFile": "unreal_tran/tests/model-main-closure.test.mjs"
},
{
"title": "managed-GLB history downloads the snapshot stable reference before restoring, without rewriting it",
"featureIds": [
"project.undo",
"project.redo"
],
"scope": "受控 GLB 快照先物化再恢复,不把临时 URL 写回快照。",
"status": "PASS",
"kind": "unit",
"testFile": "unreal_tran/tests/model-main-closure.test.mjs"
},
{
"title": "beforeunload recovery does not create a draft for key order alone, but preserves real unsaved changes",
"featureIds": [
"project.recovery"
],
"scope": "同语义对象键顺序不产生假恢复稿;真正修改仍保留。不包含全部恢复/隔离/下载 UI 分支。",
"status": "PASS",
"kind": "unit",
"testFile": "unreal_tran/tests/model-main-closure.test.mjs"
},
{
"title": "highlight rejects missing/hidden targets and transient colors never enter a saved project",
"featureIds": [
"blueprint.highlight"
],
"scope": "目标不存在/隐藏报错,执行时暂态发光颜色不进入保存文档,结束恢复原材质。",
"status": "PASS",
"kind": "unit",
"testFile": "unreal_tran/tests/model-main-closure.test.mjs"
},
{
"title": "API publish supplies current cover, blocks duplicate publication and reports preserved old cover once",
"featureIds": [
"publish.api",
"publish.cover",
"feedback.toast"
],
"scope": "实际发布宿主方法传封面、重入阻断和上传失败只提示一次;模拟 API,不是实际服务响应。",
"status": "PASS",
"kind": "unit",
"testFile": "unreal_tran/tests/model-main-closure.test.mjs"
},
{
"title": "API conflict leaves publication failed and releases the cover guard",
"featureIds": [
"project.conflict",
"publish.api",
"publish.cover"
],
"scope": "409 分支不误报已发布并释放 busy 标记;模拟 API。",
"status": "PASS",
"kind": "unit",
"testFile": "unreal_tran/tests/model-main-closure.test.mjs"
}
],
"runtime": {
"authSha256": "95b8487ca6a1d970387214b027ee9c1d34ae0d1d5c988574c024805d8bb61d9b",
"tranSha256": "e9528d739d6d817ebf7c5b9a34302195156b1543663066f5484c86c594c6e729",
"builtEqualsRunning": true,
"fileService": "开发进程撤销旧17180转发覆盖,恢复已配置远端文件服务"
},
"previousWorkPushed": {
"api": "71df00dffa39a8f49a4f0654969a3014c2f78f67",
"web": "3f39e2c94df9cdadf3545ae14bf0df41f2c37bf1",
"e2e": "b3d4ce8ffd8144090c18c8a28f5ca824170042c8"
}
}测试数据保留与清理
{
"time": "2026-09-06T08:27:13.581Z",
"status": "PASS",
"originals": [
{
"id": "157",
"name": "实测模型-狐狸动画-已验证-20260905",
"version": 15,
"unchanged": true
},
{
"id": "156",
"name": "实测模型-牛奶卡车-已验证-20260905",
"version": 20,
"unchanged": true
},
{
"id": "94",
"name": "桥梁架设装备整机模型",
"version": 253,
"unchanged": true
}
],
"projects": [
{
"id": "168",
"alreadyAbsent": true
},
{
"id": "169",
"alreadyAbsent": true
},
{
"id": "170",
"alreadyAbsent": true
},
{
"id": "171",
"alreadyAbsent": true
},
{
"id": "172",
"alreadyAbsent": true
},
{
"id": "173",
"alreadyAbsent": true
},
{
"id": "174",
"alreadyAbsent": true
},
{
"id": "175",
"alreadyAbsent": true
},
{
"id": "176",
"alreadyAbsent": true
},
{
"id": "177",
"alreadyAbsent": true
},
{
"id": "178",
"alreadyAbsent": true
},
{
"id": "179",
"alreadyAbsent": true
},
{
"id": "180",
"alreadyAbsent": true
},
{
"id": "181",
"alreadyAbsent": true
},
{
"id": "182",
"alreadyAbsent": true
},
{
"id": "183",
"name": "闭环导航名称-183",
"withdrawn": false,
"removed": true
},
{
"id": "184",
"name": "闭环验收-资源往返-mtph19ll",
"withdrawn": false,
"removed": true
},
{
"id": "185",
"name": "闭环验收-三维手柄-1788678747289",
"withdrawn": false,
"removed": true
},
{
"id": "186",
"name": "闭环验收-离开保护-1788678780620",
"withdrawn": false,
"removed": true
},
{
"id": "187",
"name": "闭环验收-恢复副本-mtph6hw8",
"withdrawn": false,
"removed": true
},
{
"id": "188",
"name": "闭环验收-加载与预检-mtph6ubj",
"withdrawn": false,
"removed": true
},
{
"id": "189",
"name": "闭环验收-三维手柄-1788678838243",
"withdrawn": false,
"removed": true
},
{
"id": "190",
"name": "闭环验收-离开保护-1788678850196",
"withdrawn": false,
"removed": true
},
{
"id": "191",
"name": "闭环工具补充-卡车控件-mtpha049",
"withdrawn": false,
"removed": true
},
{
"id": "192",
"name": "闭环工具补充-卡车控件-mtphbg8t",
"withdrawn": false,
"removed": true
},
{
"id": "193",
"name": "闭环工具补充-基准匹配-mtphbpqq",
"withdrawn": false,
"removed": true
},
{
"id": "194",
"name": "闭环工具补充-卡车控件-mtphfk1m",
"withdrawn": false,
"removed": true
},
{
"id": "195",
"name": "闭环工具补充-基准匹配-mtphfu32",
"withdrawn": false,
"removed": true
},
{
"id": "196",
"name": "闭环验收-资源往返-mtphjhoi",
"withdrawn": false,
"removed": true
},
{
"id": "197",
"name": "闭环验收-拒绝非法资源-mtphjv5x",
"withdrawn": false,
"removed": true
},
{
"id": "198",
"name": "闭环验收-保存失败恢复-mtphk0kk",
"withdrawn": false,
"removed": true
},
{
"id": "199",
"name": "闭环验收-发布封面版本-mtphk960",
"withdrawn": true,
"removed": true
},
{
"id": "200",
"name": "闭环工具补充-卡车控件-mtphkrbz",
"withdrawn": false,
"removed": true
},
{
"id": "201",
"name": "闭环工具补充-基准匹配-mtphkzlj",
"withdrawn": false,
"removed": true
},
{
"id": "202",
"name": "闭环新建-1788679561949",
"withdrawn": false,
"removed": true
},
{
"id": "203",
"name": "闭环验收-三维手柄-1788679613072",
"withdrawn": false,
"removed": true
},
{
"id": "204",
"name": "闭环验收-离开保护-1788679623529",
"withdrawn": false,
"removed": true
},
{
"id": "205",
"name": "闭环补充-资源库-mtphobxb",
"withdrawn": false,
"removed": true
},
{
"id": "206",
"name": "闭环补充-内置环境-mtphomov",
"withdrawn": false,
"removed": true
},
{
"id": "207",
"name": "闭环导航名称-207",
"withdrawn": false,
"removed": true
},
{
"id": "208",
"name": "闭环验收-恢复副本-mtphpz7v",
"withdrawn": false,
"removed": true
},
{
"id": "209",
"name": "闭环验收-加载与预检-mtphq9y1",
"withdrawn": false,
"removed": true
},
{
"id": "210",
"name": "闭环验收-离开保护-1788681347476",
"withdrawn": false,
"removed": true
},
{
"id": "211",
"name": "闭环补充-内置环境-mtpip60q",
"withdrawn": false,
"removed": true
},
{
"id": "212",
"name": "闭环验收-资源往返-mtpjbnl2",
"withdrawn": false,
"removed": true
},
{
"id": "213",
"name": "闭环验收-拒绝非法资源-mtpjbyqo",
"withdrawn": false,
"removed": true
},
{
"id": "214",
"name": "闭环验收-保存失败恢复-mtpjc2vu",
"withdrawn": false,
"removed": true
},
{
"id": "215",
"name": "闭环验收-发布封面版本-mtpjcafv",
"withdrawn": true,
"removed": true
},
{
"id": "216",
"name": "闭环工具补充-卡车控件-mtpjcof8",
"withdrawn": false,
"removed": true
},
{
"id": "217",
"name": "闭环工具补充-基准匹配-mtpjcvxe",
"withdrawn": false,
"removed": true
},
{
"id": "218",
"name": "闭环新建-1788682528069",
"withdrawn": false,
"removed": true
},
{
"id": "219",
"name": "闭环验收-三维手柄-1788682536810",
"withdrawn": false,
"removed": true
},
{
"id": "220",
"name": "闭环验收-离开保护-1788682545004",
"withdrawn": false,
"removed": true
},
{
"id": "221",
"name": "闭环补充-资源库-mtpjesgj",
"withdrawn": false,
"removed": true
},
{
"id": "222",
"name": "闭环补充-内置环境-mtpjezfi",
"withdrawn": false,
"removed": true
},
{
"id": "223",
"name": "闭环导航名称-223",
"withdrawn": false,
"removed": true
},
{
"id": "224",
"name": "闭环验收-恢复副本-mtpjg6y2",
"withdrawn": false,
"removed": true
},
{
"id": "225",
"name": "闭环验收-加载与预检-mtpjgfnd",
"withdrawn": false,
"removed": true
},
{
"id": "226",
"name": "闭环验收-资源往返-mtpjkcpq",
"withdrawn": false,
"removed": true
},
{
"id": "227",
"name": "闭环验收-拒绝非法资源-mtpjko7g",
"withdrawn": false,
"removed": true
},
{
"id": "228",
"name": "闭环验收-保存失败恢复-mtpjkshn",
"withdrawn": false,
"removed": true
},
{
"id": "229",
"name": "闭环验收-发布封面版本-mtpjkzt1",
"withdrawn": true,
"removed": true
},
{
"id": "230",
"name": "闭环工具补充-卡车控件-mtpjlf69",
"withdrawn": false,
"removed": true
},
{
"id": "231",
"name": "闭环工具补充-基准匹配-mtpjlmiy",
"withdrawn": false,
"removed": true
},
{
"id": "232",
"name": "闭环新建-1788682938712",
"withdrawn": false,
"removed": true
},
{
"id": "233",
"name": "闭环验收-三维手柄-1788682951454",
"withdrawn": false,
"removed": true
},
{
"id": "234",
"name": "闭环验收-离开保护-1788682960426",
"withdrawn": false,
"removed": true
},
{
"id": "235",
"name": "闭环补充-资源库-mtpjnoh9",
"withdrawn": false,
"removed": true
},
{
"id": "236",
"name": "闭环补充-内置环境-mtpjnv0t",
"withdrawn": false,
"removed": true
},
{
"id": "237",
"name": "闭环导航名称-237",
"withdrawn": false,
"removed": true
},
{
"id": "238",
"name": "闭环验收-恢复副本-mtpjp3nr",
"withdrawn": false,
"removed": true
},
{
"id": "239",
"name": "闭环验收-加载与预检-mtpjpdaj",
"withdrawn": false,
"removed": true
}
]
}交付物凭据与附件检查
最终扫描通过 · 脱敏扫描结果
四个仓库相对 HEAD 的变动/新增文件与本轮完整报告;真实本地账号密码精确匹配、可解码 JWT、ZIP/Playwright 内嵌报告逐项解压扫描及 PNG 文本元数据。输出不包含任何命中值或附近正文。
扫描 104 份文本、122 张图片的文本元数据及 1 个归档;图片正文不以文本扫描代替视觉 QA。
检查范围、历史常量排除与限制
{
"time": "2026-09-06T08:33:57.163137+00:00",
"status": "PASS",
"secretScan": "PASS",
"phase": "final",
"finalArtifactScan": true,
"scope": "四个仓库相对 HEAD 的变动/新增文件与本轮完整报告;真实本地账号密码精确匹配、可解码 JWT、ZIP/Playwright 内嵌报告逐项解压扫描及 PNG 文本元数据。输出不包含任何命中值或附近正文。",
"baselinePolicy": "只排除 HEAD 已存在且邻近至少64字符完全一致的普通源码/固定库字符串(统一CRLF/LF);新哈希模型bundle另允许至少25个邻近词元在仅归一化压缩变量名后完全一致,且命中须为更长固定常量的子串、不能是完整密码值。唯一经本轮复核的配置例外是 ut_auth/src/main/resources/application.yml 的 bootstrap-admin-password 环境变量默认项:文件、键、整行须与 HEAD 完全相同,且新旧文件各只出现一次;改值、改变量名、复制到其他文件或新增同一行均仍失败。其他真实凭据赋值与ZIP内元数据不作排除。Playwright静态库对比HEAD上一轮报告壳。",
"limitations": [
"图片仅扫描可读元数据,不执行OCR;图像正文由浏览器报告视觉QA核对。",
"只扫描本轮交付范围,不声称已审计整个历史仓库。",
"初查通过不代表最终结果文件已完成,最终需 --final 再执行。"
],
"selfChecks": {
"status": "PASS",
"tests": 15
},
"repositoryHeads": {
"unreal_tran": "d16184acf1686bb4a6ad44949d0587c5373ffbde",
"unreal_tran_web": "3f39e2c94df9cdadf3545ae14bf0df41f2c37bf1",
"unreal_tran_api": "71df00dffa39a8f49a4f0654969a3014c2f78f67",
"ute2e": "b3d4ce8ffd8144090c18c8a28f5ca824170042c8"
},
"changedFileCounts": {
"unreal_tran": 14,
"unreal_tran_web": 8,
"unreal_tran_api": 15,
"ute2e": 184
},
"deletedFileCounts": {
"unreal_tran": 0,
"unreal_tran_web": 2,
"unreal_tran_api": 0,
"ute2e": 0
},
"textArtifactsScanned": 104,
"pngMetadataFilesScanned": 122,
"archives": [
{
"file": "ute2e/reports/model-editor-closure-20260906/playwright/index.html!embedded-report-1.zip",
"entries": 7,
"textEntries": 7
}
],
"finalInputs": {
"results.json": true,
"validation.json": true,
"cleanup.json": true,
"playwright/index.html": true
},
"finalInputSha256": {
"results.json": "f37013658c8c38a5ec5993e636a30ad57eee9d3bcc119650c929952de8d556e9",
"validation.json": "6e0e87d0df73061bc8549d3405f03731fecf077d7425f52eeed45008f7d09959",
"cleanup.json": "ab2776afa143d9937651daa8fa18b531a3fb84c703f5f5b0918930e78c76eb26",
"playwright/index.html": "92dcca3fe570530bde973b9e09199c064fc2b343bb6f8a21b67fb3c72b8949ed"
},
"unchangedBaselineExclusions": [
{
"file": "unreal_tran_api/ut_auth/src/main/resources/application.yml",
"baseline": "unreal_tran_api/HEAD:ut_auth/src/main/resources/application.yml",
"occurrences": 1
},
{
"file": "unreal_tran_api/wiki/11-内容制作模块.md",
"baseline": "unreal_tran_api/HEAD:wiki/11-内容制作模块.md",
"occurrences": 17
},
{
"file": "unreal_tran_web/public/legacy-model-editor/assets/editor-BAqfQ3VC.js",
"baseline": "unreal_tran_web/HEAD:public/legacy-model-editor/assets/editor-CunHwJSa.js",
"occurrences": 1
},
{
"file": "ute2e/reports/model-editor-closure-20260906/playwright/index.html",
"baseline": "ute2e/HEAD:reports/role-permissions-20260906/playwright/index.html",
"occurrences": 1
}
],
"unscannedBinaryFiles": [],
"findings": []
}较大调整的具体范围
以下能力超出现有小范围修复。本轮保留入口并明确现状;确认范围后才能据此另行实现和验收。
真正的组件运行系统
- 当前行为
- “组件”页目前是内置能力说明;新增项只保存扩展标记名称,没有启停、参数执行或生命周期。
- 拟实现的可观察行为
- 用户新增一种行为组件,配置参数后能在当前模型和约定下游环境执行;停用后立即停止,重开后按保存状态恢复。
- 建议确认的实施范围
- 先定义有限组件目录、参数 schema、权限与版本;实现初始化/更新/销毁及错误隔离。不要直接开放任意脚本。
- 验收条件
- 每种批准组件可添加、编辑、启停、删除、保存重开;重复载入不重复绑定事件;失败组件不阻断其他对象,运行结果可定位。
完整三维离线运行包
- 当前行为
- 现有 HTML 是嵌入静态截图与工程数据的步骤演示,可离线查看;没有 GLB 字节和完整三维运行时。
- 拟实现的可观察行为
- 断网电脑打开交付包,真实模型/材质/原生动画/编辑时间轴与交互节点可以运行,且不依赖服务端 blob URL。
- 建议确认的实施范围
- 明确交付形式(目录/ZIP或单文件)、体积约束、资产授权和三维依赖;打包全部受控资产、运行时和相对资源清单。
- 验收条件
- 清缓存断网运行;模型和环境完整可见,动作/分支/高亮可交互;资源缺失明确报错;包内清单/哈希与发布版本一致。
下游场景 / 训练自动执行模型动画与蓝图
- 当前行为
- 发布模型可供下游按固定版本引用;不同下游已有局部动画能力,但没有统一的模型 timeline/blueprint 自动执行桥接。加载成功不等于动作已自动执行。
- 拟实现的可观察行为
- 在场景或训练放入模型实例后,按明确触发策略启动该发布版本的时间轴/蓝图;多个实例互不干扰。
- 建议确认的实施范围
- 统一实例目标命名空间、事件总线、生命周期和停止规则;明确自动播放、用户触发与训练步骤触发优先级,以及错误/完成结果回传。
- 验收条件
- 两个同模型实例分别触发不串台;锁定发布版本;停止/切步骤/卸载无迟到动作;真实对象姿态、分支和结果回传均有 E2E 证据。
41 张截图 · 点击放大
截图来自实际目录;首次加载、过程画面和最终结果按图注说明,不把空场景或加载遮罩当作模型可见证据。

通过真实属性控件编辑并保存;新增内容是可持久化的名称标记,不代表组件运行行为已经实现。
01-components-saved.png
重新加载服务端工程后核对对象名称、变换、首个材质槽、自定义字段和扩展标记;不是仅核对保存提示。
02-properties-reopened.png
真实狐狸模型在编辑器预览视口显示。临时网格、线框、透视等视图选项与模型数据保存分开验收。
03-fox-preview.png
定向注入创建请求失败,核对原工程保留及新建表单可重试;该画面不表示开发服务自然发生故障。
04-new-retry-dialog.png
新建走真实创建接口并进入新项目 ID,原模型工程没有被清空覆盖。
05-new-separate-project.png
使用本轮实际权限会话检查只读控件及接口拒绝;平台角色名称本身不授予内容写权限。
06-readonly-permissions.png
真实轨道增删、目标绑定、播放停止、静音和关键帧操作。当前截图停在零秒;它不表示原生 GLB 动画已经变成多条可编辑时间轴。
21-truck-timeline-controls.png
将卡车车身部件关键帧 X 改为 5 验证曲线与真实视口联动,因此车身与轮子暂时分离;这是测试姿态,不是模型加载丢失。
22-truck-curve-value-five.png
节点通过节点库创建,参数使用实际控件编辑,端口通过指针拖线连接;蓝图图数据随后保存重开核对。
23-truck-blueprint-seven-nodes.png
编辑器真实 handler 驱动时间轴、等待、高亮与提示节点;不是替换 handler 的演示截图。
24-truck-blueprint-real-message.png
用例检查节点顺序、条件出口和完成事件;右侧日志只记录当前运行,不等同服务端审计或教学成绩。
25-truck-blueprint-completed-log.png
对已由 UI 创建的图调用运行时接口检查 true/false 与不匹配目标;这张图标记为运行时证据,不能当成纯鼠标 UI 覆盖。
26-truck-condition-branches-runtime.png
真实点击进入预览后派发 auto,校验只启动一次;不代表下游场景或训练会自动运行模型蓝图。
27-truck-preview-auto.png
在真实可见网格像素上单击,校验只启动一次且流程完成;没有伪造 trigger 事件。
27-truck-preview-click.png
通过 renderer canvas 双击命中真实模型,校验事件匹配与单次执行;避免单击误启动双击/自动触发器。
27-truck-preview-double-click.png
在独立卡车副本中设置关键帧 X=5、Y=-2,切换曲线显示分量并比较曲线路径,确认切换视图不修改关键帧数据。车身偏移是特意设置的测试姿态。
28-curve-axis-y-negative.png
通过时间刻度点击/拖动、左右与 Shift 按键定位时间,再用实际关键帧按钮记录当前偏移,核对时间码、关键帧和持久化内容。
29-timeline-seek-record.png
狐狸是主模型,旁边方盒是轻量环境 GLB;两者使用独立受控资产引用,刷新后均有真实网格。当前镜头较远,资产身份以随附 API 断言核对。
30-assets-environment-reopened.png
搜索并清空节点库,通过 HTML5 拖放添加节点,核对工具栏默认添加、画布滚轮缩放/平移/适应操作没有意外改变节点图。
30-blueprint-palette-canvas.png
在独立匹配装备副本载入基准动作,核对轨道目标存在、项目名称保留、保存刷新后时间轴一致;不匹配卡车分支另外验证原时间轴未被覆盖。仅验证通用编辑数据,不制作实际维修流程。
31-bridge-baseline-reopened.png
非法 JSON 或无有效受控引用的导入被拒绝;核对原模型与工程内容仍在,没有以默认模型静默替换。
31-invalid-import-keeps-model.png
通过定向注入 409 验证保存失败分支及恢复数据,不将失败提示本身当成成功保存。
32-save-conflict-keeps-recovery.png
恢复正常请求后点击真实保存。右上红色 409 提示来自上一故障注入步骤,截图时尚在自动消退周期内;本次重试成功由当前 PUT 响应和保存后的刷新断言确认。失败后的旧上传票据不得被误复用。
33-save-retry-success.png
发布接口、保存版本和受控封面资产一起核对;封面来自当前三维视口。下载后的下游资源验证不等于下游自动执行蓝图。
34-published-current-cover.png
打开真实导出文件检查步骤演示内容。此文件不含完整三维模型和资源,完整三维离线包列为待确认范围。
35-offline-step-demo-actual-file.png
输入命中关键字、无匹配关键字,再清空搜索,断言卡片数量与空结果状态;仅搜索当前目录。
41-resource-search-restored.png
在独立副本导入小方盒,再点回原狐狸卡片;保存刷新后核对原资产 ID、code 与真实网格,不改原模型数据。
42-resource-card-switch-reopened.png
真实切换内置车间、保存和刷新后核对环境类型与网格;树计数、折叠和展开同时验证。
43-builtin-workshop-reopened.png
真实切换内置野外、保存和刷新后核对环境类型与网格;程序化环境不冒称外部 GLB。
44-builtin-outdoor-reopened.png
真实加载随包车库 GLB,保存刷新后检查 builtin-gltf 来源与网格;树总数与当前展开行数分开统计。
45-builtin-depot-reopened.png
通过真实按钮验证下一步推进两秒、上一步回零,并用 Escape 返回编辑;预览步进不是创建新的业务步骤。
46-preview-navigation.png
自定义编码修改后没有点击保存,等待实际 30 秒自动 PUT;刷新确认名称与编码保留。下方日志为本次加载运行日志,FPS 与显存只作状态展示。
47-navigation-autosave-log.png
为了验证真实平移、旋转与缩放手柄,特意把狐狸旋转至侧立并缩小 X 轴;画面中的侧立和压扁属于测试姿态,不是加载变形。定位只读投影,没有脚本写姿态;随后撤销/重做、保存刷新核对。
51-transform-gizmos.png
关闭确认框保留修改;定向注入保存 503 后仍留在原页,解除异常后重试保存才离开,最终 API 核对数据。
52-leave-save-failure.png
先在实际属性控件修改,再刷新触发 beforeunload 恢复稿;没有预先注入 localStorage 假快照。此时服务端版本未变化。
60-same-version-real-recovery.png
点击恢复后编辑器保留需显式保存状态;实际点击保存才更新服务端版本,恢复名称与原受控模型一致。
61-recovered-draft-explicitly-saved.png
在独立副本模拟另一个编辑器保存;旧稿不显示覆盖恢复按钮,只下载并隔离保留,服务端较新内容未被覆盖。
62-stale-version-recovery-protection.png
定向注入资源下载 503,中性加载失败界面保留重试入口,保存与发布均禁用;空白视口不作为模型加载成功。
63-controlled-glb-download-failed.png
解除下载故障后点击宿主重试,iframe 重新载入并出现真实模型网格;没有以默认占位模型绕过失败。
64-controlled-glb-retry-loaded.png
打开和关闭预检面板不会写入项目;错误受控资产引用的 JSON 在替换模型前被拒绝。面板绿标不能替代服务端发布校验。
65-publish-preflight-readonly.png
车库环境保存后使用正式宿主导航返回列表,确认不会因旧版规范化器把 depot 误改成 outdoor 而产生虚假的未保存提示;实际修改仍受离开保护。
66-depot-saved-return-list.png