import fs from 'node:fs'; import assert from 'node:assert/strict'; import {login,call} from './role-permissions-live.mjs'; import {scripts} from '../../unreal_tran_web/src/features/virtual-training-scripts/definition.js'; const dir='reports/bridge-006-six-steps-20260921';fs.mkdirSync(dir,{recursive:true}); const signed=await login('root'); const api=async(path,data,method)=>{const r=await call('tran/v1/'+path,signed.accessToken,data,method);assert.equal(r.status,200,path+': '+r.message);return r.data;}; const backup=(name,value)=>{const file=dir+'/'+name+'.json';if(!fs.existsSync(file))fs.writeFileSync(file,JSON.stringify(value,null,2));}; let task=await api('teaching/assignments/87'),project=await api('content/projects/'+task.contentProjectId); assert.equal(task.code,'TASK-VIRTUAL-006');assert.ok(['4','5'].includes(task.definitionSnapshot.runtime.scriptVersion)); backup('before-task',task);backup('before-project',project); for(const id of [86,88,89,116])backup('unchanged-'+id,await api('teaching/assignments/'+id)); const previous=JSON.parse(fs.readFileSync(dir+'/before-task.json')); const script=scripts.find(s=>s.code===task.code); if(task.definitionSnapshot.runtime.scriptVersion!=='5'){ const runs=await api('teaching/runs?assignmentId=87&size=100'); assert.equal(runs.total,0,'Do not withdraw a task with existing learner runs'); if(project.currentVersion.content.runtime.scriptVersion!=='5'){ assert.equal(project.currentVersion.id,project.project.publishedVersionId,'Do not overwrite an unrelated unpublished draft'); const content=structuredClone(project.currentVersion.content); assert.equal(content.steps.length,7);assert.equal(content.steps[6].action.targetId,'bridge-normal-control'); content.steps=content.steps.slice(0,6); content.steps.forEach((step,index)=>{step.assessment.weight=script.definition.steps[index].assessment.weight;}); content.runtime.scriptVersion='5'; content.scenario.operableParts=[...new Set(content.steps.flatMap(step=>step.action.mechanism.steps.map(op=>op.targetId)))]; project=await api('content/projects/'+project.project.id,{...project.project,content,assets:project.currentVersion.assets,dependencies:project.currentVersion.dependencies,version:project.project.version,changeSummary:'006调整为六步:移除正常作业概括项及示意手柄,保留完成说明;评分权重合计100%,保留旧版本与讲解资源'},'PUT'); } if(project.project.publishedVersionId!==project.currentVersion.id)project=await api('content/projects/'+project.project.id+'/publish',{version:project.project.version}); if(task.status==='PUBLISHED')task=await api('teaching/assignments/87/withdraw',{version:task.version,reason:'按确认后的训练范围移除第七步,更新六步内容版本'}); assert.ok(['DRAFT','WITHDRAWN'].includes(task.status)); task=await api('teaching/assignments/87',{...task,contentVersionId:project.project.publishedVersionId,version:task.version},'PUT'); task=await api('teaching/assignments/87/publish',{version:task.version}); } assert.equal(task.status,'PUBLISHED');assert.equal(task.definitionSnapshot.runtime.scriptVersion,'5');assert.equal(task.definitionSnapshot.steps.length,6); for(let i=0;i<6;i++){ const before=structuredClone(previous.definitionSnapshot.steps[i]),after=structuredClone(task.definitionSnapshot.steps[i]); delete before.assessment.weight;delete after.assessment.weight;assert.deepEqual(after,before,'Only scoring weights change for retained steps'); } assert.equal(Math.round(task.definitionSnapshot.steps.reduce((sum,step)=>sum+step.assessment.weight,0)*100),10000); assert.deepEqual(task.members,previous.members); for(const id of [86,88,89,116]){ const before=JSON.parse(fs.readFileSync(dir+'/unchanged-'+id+'.json')),after=await api('teaching/assignments/'+id); assert.deepEqual(after.definitionSnapshot,before.definitionSnapshot);assert.equal(after.contentVersionId,before.contentVersionId); } fs.writeFileSync(dir+'/after-task.json',JSON.stringify(task,null,2)); fs.writeFileSync(dir+'/migration.json',JSON.stringify({pass:true,id:task.id,oldContentVersion:previous.contentVersionId,newContentVersion:task.contentVersionId,steps:6,scoreWeight:100,runCount:task.runCount,unchangedTasks:[86,88,89,116]},null,2)); console.log('006 six-step content version',task.contentVersionId);