No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.
 
 
 
 

34 líneas
5.2 KiB

  1. import fs from 'node:fs';
  2. import crypto from 'node:crypto';
  3. import assert from 'node:assert/strict';
  4. import {login,call} from './role-permissions-live.mjs';
  5. const dir='reports/bridge-005-new-model-20260917';
  6. const prior='reports/bridge-005-authoring-20260916';
  7. const read=(p)=>JSON.parse(fs.readFileSync(p,'utf8'));
  8. const fixture=read(prior+'/pilot.json'),before=read(prior+'/original-assignments.json');
  9. const session=await login('root');
  10. const api=async endpoint=>{const r=await call('tran/v1/'+endpoint,session.accessToken);assert.equal(r.status,200);return r.data;};
  11. const originals=[];
  12. 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});}
  13. const scene=await api('content/projects/'+fixture.sceneId),training=await api('content/projects/'+fixture.trainingId),task=await api('teaching/assignments/'+fixture.taskId);
  14. assert.equal(task.status,'DRAFT');assert.equal(task.contentVersionId,training.project.publishedVersionId);
  15. assert.ok(training.currentVersion.dependencies.some(d=>d.targetVersionId===scene.project.publishedVersionId));
  16. const vehicle=scene.currentVersion.content.objects.find(o=>o.sourceName==='0916架桥车.glb');
  17. assert.ok(vehicle);assert.equal(vehicle.modelPartTargets.length,7);
  18. assert.equal(scene.currentVersion.content.environment.useModelFloor,true);
  19. assert.equal(scene.currentVersion.content.objects.some(o=>o.type==='scene-environment'),false);
  20. const asset=scene.currentVersion.assets.find(a=>a.code===vehicle.assetCode);
  21. const source=fs.readFileSync('../../模型/0916架桥车.glb');
  22. const installed=fs.readFileSync('../unreal_tran_web/public'+vehicle.resourceUrl);
  23. assert.deepEqual(installed,source);assert.equal(asset.sha256,crypto.createHash('sha256').update(source).digest('hex'));
  24. const steps=training.currentVersion.content.steps;
  25. assert.equal(steps.length,5);assert.equal(steps.flatMap(s=>s.action.mechanism.steps).length,6);
  26. 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);}
  27. const live=read(dir+'/runtime-final-lan.json'),regression=read(dir+'/original-005-regression.json');
  28. assert.equal(live.pass,true);assert.equal(regression.pass,true);
  29. 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};
  30. fs.writeFileSync(dir+'/audit.json',JSON.stringify(audit,null,2));
  31. fs.copyFileSync(prior+'/scene-editor.png',dir+'/scene-editor.png');fs.copyFileSync(prior+'/training-editor.png',dir+'/training-editor.png');
  32. 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>`);
  33. console.log(JSON.stringify({pass:true,sceneVersion:fixture.sceneVersionId,trainingVersion:fixture.trainingVersionId,originalsUnchanged:true}));