|
- import fs from 'node:fs';
- import crypto from 'node:crypto';
- import assert from 'node:assert/strict';
- import {login,call} from './role-permissions-live.mjs';
- const dir='reports/bridge-005-new-model-20260917';
- const prior='reports/bridge-005-authoring-20260916';
- const read=(p)=>JSON.parse(fs.readFileSync(p,'utf8'));
- const fixture=read(prior+'/pilot.json'),before=read(prior+'/original-assignments.json');
- const session=await login('root');
- const api=async endpoint=>{const r=await call('tran/v1/'+endpoint,session.accessToken);assert.equal(r.status,200);return r.data;};
- const originals=[];
- for(const id of ['86','87','88','89']){const current=await api('teaching/assignments/'+id);delete current.serverNow;delete before[id].serverNow;assert.deepEqual(current,before[id]);originals.push({id,code:current.code,versionId:current.contentVersionId,unchanged:true});}
- const scene=await api('content/projects/'+fixture.sceneId),training=await api('content/projects/'+fixture.trainingId),task=await api('teaching/assignments/'+fixture.taskId);
- assert.equal(task.status,'DRAFT');assert.equal(task.contentVersionId,training.project.publishedVersionId);
- assert.ok(training.currentVersion.dependencies.some(d=>d.targetVersionId===scene.project.publishedVersionId));
- const vehicle=scene.currentVersion.content.objects.find(o=>o.sourceName==='0916架桥车.glb');
- assert.ok(vehicle);assert.equal(vehicle.modelPartTargets.length,7);
- assert.equal(scene.currentVersion.content.environment.useModelFloor,true);
- assert.equal(scene.currentVersion.content.objects.some(o=>o.type==='scene-environment'),false);
- const asset=scene.currentVersion.assets.find(a=>a.code===vehicle.assetCode);
- const source=fs.readFileSync('../../模型/0916架桥车.glb');
- const installed=fs.readFileSync('../unreal_tran_web/public'+vehicle.resourceUrl);
- assert.deepEqual(installed,source);assert.equal(asset.sha256,crypto.createHash('sha256').update(source).digest('hex'));
- const steps=training.currentVersion.content.steps;
- assert.equal(steps.length,5);assert.equal(steps.flatMap(s=>s.action.mechanism.steps).length,6);
- for(const step of steps){assert.ok(vehicle.modelPartTargets.some(p=>p.interactionId===step.targetId&&p.sourceNodeName===step.targetRef.sourceNodeName));assert.ok(step.audio.narrationVideoAssetCode&&step.audio.narrationAssetCode);}
- const live=read(dir+'/runtime-final-lan.json'),regression=read(dir+'/original-005-regression.json');
- assert.equal(live.pass,true);assert.equal(regression.pass,true);
- const audit={pass:true,time:new Date().toISOString(),fixture,model:asset.storageUri,sha256:asset.sha256,targets:vehicle.modelPartTargets,originals,grounding:live.checks.find(c=>c.grounding)?.grounding,media:live.checks.find(c=>c.media)?.media,steps:5,operations:6};
- fs.writeFileSync(dir+'/audit.json',JSON.stringify(audit,null,2));
- fs.copyFileSync(prior+'/scene-editor.png',dir+'/scene-editor.png');fs.copyFileSync(prior+'/training-editor.png',dir+'/training-editor.png');
- fs.writeFileSync(dir+'/index.html',`<!doctype html><html lang="zh-CN"><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>005 新模型验收</title><style>body{font:16px/1.7 system-ui;color:#173f39;background:#f3f8f6;max-width:1200px;margin:32px auto;padding:0 24px}section{background:white;border:1px solid #d5e6df;border-radius:12px;padding:24px;margin:20px 0}img{width:100%;border-radius:8px}a{color:#087f70}li{margin:8px 0}</style><h1>005 新版架桥车:替换与完整流程验收</h1><p>${audit.time} · 本地与局域网 · 管理员教员预览</p><section><h2>结果</h2><p>已替换为 0916架桥车.glb,七个目标全部重新绑定。五步六个动作、真实鼠标拖拽、服务端预览校验、数字人视频与语音回退通过。前端构建和新模型几何测试通过。</p><p>新增场景资产保留了原运行中的平整作业区,移除重复的基础地面;车轮贴地检查通过。盖板沿新版铰链向外开启,互救手柄向上拨动。</p><p>验证任务 ${fixture.taskId} 保持草稿。原四个已发布任务的完整数据逐项对比一致,旧版 005 的完整流程回归通过。未切换原学员任务,未验证新增学员成绩。</p><ul><li><a href="http://127.0.0.1:6180/teaching/virtual-training/preview/${fixture.taskId}">打开新版 005 预览</a></li><li><a href="http://127.0.0.1:6180/content/scenes/${fixture.sceneId}/edit">场景制作</a>(发布版本 ${fixture.sceneVersionId})</li><li><a href="http://127.0.0.1:6180/content/training-projects/${fixture.trainingId}/legacy">训练编排</a>(发布版本 ${fixture.trainingVersionId})</li><li><a href="audit.json">模型、版本、贴地与原任务核对</a></li><li><a href="runtime-final-lan.json">局域网操作证据</a> / <a href="original-005-regression.json">原 005 回归</a></li></ul></section><section><h2>新版整车</h2><img src="task-116-initial.png"></section><section><h2>球阀操作</h2><img src="task-116-step-3.png"></section><section><h2>开盖与互救开关</h2><img src="task-116-step-5.png"></section><section><h2>场景制作与训练编排</h2><img src="scene-editor.png"><img src="training-editor.png"></section></html>`);
- console.log(JSON.stringify({pass:true,sceneVersion:fixture.sceneVersionId,trainingVersion:fixture.trainingVersionId,originalsUnchanged:true}));
|