import systemTime from '@ohos.systemDateTime'; import router from '@ohos.router'; import util from '@ohos.util'; import buffer from '@ohos.buffer'; import { testKm2Items,testKm3Items, testMarkRules } from './dataTest/index'; import { EXAMDATA, SOUND, KSJS } from './api/judgeSDK'; import VoiceAnnounce from './utils/voiceAnnouncements'; import FileModel from './utils/fileModel'; import FilePhoto from './utils/filePhoto'; import FileUtil from '../../common/utils/File'; import FileLog from './utils/fileLog'; import JudgeTask from './utils/judgeTask'; import { judgeConfig } from './utils/judgeConfig'; import { uploadExamProgressData, writeObjectOut } from '../../api/judge'; import UsbService from '../../common/service/usbService'; import { LANE,KF } from '../judgeSDK/api/judgeSDK.d'; import {saveStartRecordVideo,endRecordVideo} from '../../common/service/videoService' import { Array2Byte, convertGpsCoord2, deepClone, fillZero, getCurrentTime, string2Bytes, stringToASC } from '../../common/utils/tools'; import { getCarStatus, getCarStatusType, getDwStatusType, getCenterProjectStatus, getKmProjectVoice, getTranslateSignals, plcStrToJson, plcStrToWXJson, promptWxCode, senorToWXDataStr, getKmProjectCancelVoice } from './utils/judgeCommon'; import { examJudgeArtificialItem, examJudgeArtificialMark, examJudgeBeginExam, examJudgeEndExam, examJudgeInit, examJudgeSoundEnd, examJudgeRealExam, examJudgeSetLogCallback, examJudgeSetPerformCallback, examJudgeSetRealExamCallback, examCalcGpsDistance, examJudgeVersion } from './api/index'; const judgeTag = 'SURENJUN_JUDGE' import { getSyncData, upDateTableByArray } from '../../common/service/initable'; export default class Judge { constructor(judgeUI) { this.serialIndex = 1; this.judgeUI = judgeUI //语音播放工具 this.avPlayer = new VoiceAnnounce(); //模型工具 this.fileModel = new FileModel(judgeUI.context); //文件工具 this.fileUtil = new FileUtil(judgeUI.context) this.judgeTask = new JudgeTask() this.usbService = new UsbService(); this.filePhoto = new FilePhoto(judgeUI.context); this.kfArr = judgeUI.kfArr this.xmmcStr = ''; this.xmmcCode = ''; this.xmmcEndCode = undefined; this.carztStr = ''; this.testKmItems = {}; // 考试回放配置 const {isTrajectoryOpen,modelPath,trajectoryPath} = judgeConfig this.isTrajectoryOpen = isTrajectoryOpen; this.modelPath = modelPath; this.trajectoryPath = trajectoryPath; this.isExam = !this.judgeUI.singlePlay; const {projectsCenterObj,examSubject} = judgeUI; (examSubject ==2 ? testKm2Items : testKm3Items ).forEach(item => { const projectCenterObj = projectsCenterObj[item.code] this.testKmItems[item.code] = item; //考试项目存在 this.testKmItems[item.code] = { code: item.code, status: projectCenterObj === undefined ? 0 : ( projectCenterObj.isEnd ? 3 : 1 ) } }) console.info(judgeTag+'testKmItems',JSON.stringify(this.testKmItems)) this.isExamEnd = false; } public async onJudgeFn(fn: Function) { await this.judging(fn) } //开始评判 private async judging(callBack: Function) { const {judgeUI} = this; const { name, lsh, idCard,kssycs,manualMarkRules} = judgeUI; const fileLog = new FileLog(judgeUI.context); const filePath = await fileLog.initFileLogo({ name, lsh, idCard }); this.fileLog = fileLog; this.filePath = filePath; const {getJudgeBeginData,handleUdp,handDistance,fileUtil,handleTrajectoryUdp,isTrajectoryOpen,trajectoryPath,avPlayer} = this; const isJudgeInitBool = globalThis.isJudgeInitBool; let strArr = []; if (isTrajectoryOpen) { const folderPath = await this.fileUtil.initFolder(trajectoryPath); const str = await fileUtil.readFile(folderPath) strArr = str.split('\n') } //日志回调 console.info(judgeTag, '1.进入评判入口') await examJudgeSetLogCallback(3, async (level, info, len) => { console.log('评判日志:' + info) await fileLog.setExamJudgeLogData(info); }) console.info(judgeTag, '2.注册日志回调完成') let initInfo = isTrajectoryOpen ? JSON.parse(strArr[0]) : await this.getJudgeInitData(); await fileLog.setExamJudgeData(initInfo) //相关评判初始化只做一次 if (!isJudgeInitBool) { const tempJudge = await examJudgeInit(initInfo); globalThis.isJudgeInitBool = true console.info(judgeTag, '4.评判初始化完成') } globalThis.isJudge = true // 2.评判过程回调 await examJudgeSetRealExamCallback(async (strData, len) => { await fileLog.setExamJudgeCallbackData(strData) console.info('评判回调数据', strData) this.handleRealExam(strData, callBack) }) await examJudgeSetPerformCallback(async (info) => { console.info('评判实时数据', info) const performInfo = JSON.parse(info) this.performInfo = performInfo const jl = Math.floor((performInfo.qjjl + performInfo.dcjl) / 100); if(jl > this.judgeUI.examMileage){ this.checkExamIsEnd() } this.judgeUI.jl = jl //TODO 待优化 跨组件传值不生效 globalThis.laneData = performInfo.lane; }) // 3.开始考试 let beginExamInfo = isTrajectoryOpen ? { ...JSON.parse(strArr[1]), replay: 1, } : await getJudgeBeginData() await fileLog.setExamJudgeData(beginExamInfo) await examJudgeBeginExam(beginExamInfo); console.info(judgeTag, '6.开始考试注册完成') avPlayer.playAudio([globalThis.singlePlay ? 'voice/ksks.WAV' : 'voice/监管成功.mp3']) if(!globalThis.singlePlay){ this.videoData = await saveStartRecordVideo(`${name}_${kssycs}`) } const {examSubject,projectsObj} = this.judgeUI // if(examSubject == 3){ // //不做模拟灯光,需要做上车准备 =>(请上车准备) // if(projectsObj[41]?.type == 3 && projectsObj[1]?.type != 3){ // avPlayer.playAudio(['voice/上车准备.mp3']) // } // //不做模拟灯光,不做上车准备 =>(请起步,完成考试) // if(projectsObj[41]?.type == 3 && projectsObj[1]?.type == 3){ // avPlayer.playAudio(['voice/402001.mp3']) // } // } this.judgeUI.draw = true // 处理轨迹plc信息 if (isTrajectoryOpen) { handleTrajectoryUdp(strArr); return } // 处理实时udp里的plc信号 // globalThis.udpClient.closeMessage_1(); globalThis.udpClient.onMessage_1(async (msg) => { console.info('socketTag[PLC.UdpClient]', '收到udp回调数据') handleUdp(msg) const udpIndex = globalThis.udpIndex; if (udpIndex % 5 === 0) { handDistance(); } }); // this.checkExamIsEnd() //监听远程结束考试 globalThis.udpEvent.onEndExam(async ()=>{ this.checkExamIsEnd(true); }) console.info(judgeTag,JSON.stringify(manualMarkRules)) //监听远程扣分 globalThis.udpEvent.onKfExam(async (content)=>{ console.info('评判收到远程扣分项目内容' + JSON.stringify(content)) const { kfxh , directives } = content.data; console.info(judgeTag ,'评判收到远程扣分项目内容,扣分序号:' + `kfxh=>${kfxh}; directives=>${directives}`) //根据扣分序号找扣分代码 const currentKf = manualMarkRules.filter(mark => mark.kfxh == kfxh)[0]; console.info(judgeTag, '扣分项目:' + JSON.stringify(currentKf)) this.setJudgeMark(currentKf.itemno, currentKf.markserial, 2); globalThis.judgeUdp.confirmKf(directives , 1) }) } //实时计算gps经纬度距离 handDistance= async ()=>{ const {jd,wd,hxj,dwzt,jdzt} = this.tempData.gps; const tJD = convertGpsCoord2(jd) const tWD = convertGpsCoord2(wd) const {prevJd,prevWd} = this if(prevJd && dwzt == 4 && jdzt == 3){ const distance = await examCalcGpsDistance({ jd1:prevJd, wd1:prevWd, jd2:tJD, wd2:tWD, h:hxj || 1, }) //@ts-ignore globalThis.distanceClass?.setTimeData(((distance / 100).toFixed(2)) * 1) } this.prevJd = tJD; this.prevWd = tWD; } // 获取评判初始化数据 getJudgeInitData = async () => { const {getModelData,getKm3JudgeInitConfig} = this const carInfo = globalThis.carInfo; const { examSubject,plateNo,carId } = carInfo; const judgeUI = this.judgeUI const {projectsObj,itemInfoObj,markRuleListObj,carType,carName,systemparmArr,carinfoArr} = judgeUI const examType = examSubject == 2 ? 'km2' : 'km3' let allitems = []; if (examSubject == 2) { allitems = Reflect.ownKeys(itemInfoObj).map(cdsbKey => { const cdsb = itemInfoObj[cdsbKey]; const {xmdm,xmxh,modelKey} = cdsb return { xmdm, xmxh, model: getModelData(`${examType}/${modelKey}.txt`) } }) } //获取版本号 const sdkver = await examJudgeVersion(); const initInfo = { sdkver, appver:globalThis.version, kskm: examSubject * 1, kchp: plateNo, kchm: carId * 1, kscx: carType, cxcode: '1', name: carName, carmodel: getModelData(`${examType}/${carType}.txt`), allitems, iteminfo: [], systemparm: systemparmArr, mark: Reflect.ownKeys(markRuleListObj).map(ruleKey => (markRuleListObj[ruleKey])) || testMarkRules, sysset: judgeUI.judgeConfig, itemInfoObj, carlist:judgeUI.carlist, carinfo: carinfoArr, }; let km3Config = {} if (examSubject == 3) { km3Config = await getKm3JudgeInitConfig(); } // 获取科目三的评判配置 console.info(judgeTag, '3.获取评判初始化数据完成') return { ...initInfo, ...km3Config, } } // 获取开始考试数据 getJudgeBeginData = async () => { const {code,name:examinerName} = globalThis.examinerInfo; let currentParams: any = router.getParams(); const {sczb,kfdm} = currentParams; const {isExam} = this; const judgeUI = this.judgeUI const {projects,carType,kssycs,isDdxk,ddxkTime,projectsCenterObj,ddxkKsxmArr,ddxkKfArr,passingScore} = judgeUI; const beginInfo = { kgid: '012', kgxm: decodeURI(examinerName || ''), exam: isExam ? 1 : 0, //是否回放 replay: 0, //生成的轨迹文件 track: '', xm: judgeUI.name, sex: 0, kslsh: judgeUI.lsh, sfzmhm: judgeUI.idCard, ksyy: '', kscx: carType, kkcs: Number(kssycs) || 2 , sfyk: 0, ykkkcs: 1, wayno: judgeUI.wayno * 1, czlx: 0, kskssj: await systemTime.getCurrentTime(), passing:passingScore * 1, ksxm: projects.map(project => { return { xmdm: project.projectCode * 1, xmxh: '', } }), //断点续考 ddxk: isDdxk ? 1 : 0, ddkssj: ddxkTime || 0, ykxm: (ddxkKsxmArr?.map(projectCenterCode => (projectsCenterObj[projectCenterCode]?.projectCode) * 1)) || [], kfxm: isDdxk ? (ddxkKfArr?.map(kf => { const [xmdm, kfdm] = kf.split(',') return {xmdm: xmdm * 1,kfdm} })) : [], //TODO 已考里程待修改 yklc: 0, special: [], //TODO 科目三参数临时写死 sczb: (sczb === undefined || sczb == 0) ? 0 : 1, sczbkf: kfdm, dmndg: false, mfxx: false, mfxxn: false } console.info(judgeTag, '5.获取开始考试数据完成') return beginInfo } //处理评判过程回调 handleRealExam = async (strData, callBack) => { let examData: EXAMDATA = JSON.parse(strData); const {getDqxmStr,getKfStr,goJudgeVoice,setMndg,avPlayer,fileLog,judgeUI} = this; const {carzt,xmks,kf,event,xmjs,xmqx,ksjs,sound,mndg,lane,precast,nongps} = examData const param512 = (judgeUI.judgeConfigObj['512'] || '').split(','); //获取项目结束、项目开始代码 const xmdm = event == 2 ? xmjs.xmdm : xmks.xmdm const xmxh = event == 2 ? xmjs.xmxh : xmks.xmxh; const isManualProjectIn = this.artSubject3ProjectsCodesArr.includes(xmdm); const {examSubject,projects,judgeConfigObj} = this.judgeUI; const param611 = judgeConfigObj['611'] || ''; switch (event) { //项目开始 case 1: judgeUI.projectsObj[xmdm].type = '2'; if (isManualProjectIn) { //手动项目是否在进行中 this.judgeUI.isManualProjectIn = true } if (xmdm == 41 && examSubject == 3) { this.rmndg = 1 } this.judgeUI.currentXmdm = xmdm; const xmmcStr = judgeUI.projectsObj[xmdm].name; const xmmcCode = judgeUI.projectsObj[xmdm].projectCodeCenter; const xmmcSingleCode = judgeUI.projectsObj[xmdm].projectCode; this.testKmItems[xmmcCode].status = 2; this.xmmcStr = xmmcStr; this.xmmcCode = xmmcCode; this.xmmcSingleCode = xmmcSingleCode this.xmmcEndCode = xmmcCode this.xmdm = xmdm; this.xmxh = xmxh; this.judgeUI.isProjectIn = true break; //项目结束 case 2: { const xmmcCode = judgeUI.projectsObj[xmdm].projectCodeCenter; judgeUI.projectsObj[xmdm].type = (xmjs.xmhg === 0 ? '4' : '3'); //计算项目是否全部结束 this.judgeUI.isProjectIn = (Reflect.ownKeys(judgeUI.projectsObj).filter( projectKey => judgeUI.projectsObj[projectKey].type == '2').length ) > 0; if (isManualProjectIn) { this.judgeUI.isManualProjectIn = false } this.testKmItems[xmmcCode].status = 3; //统计必考项目数量 this.xmmcStr = '无'; this.xmmcCode = ''; this.xmdm = ''; this.judgeUI.currentXmdm = undefined; break; } //扣分 case 3: const thisKf = getKfStr(`${kf.xmdm}_${kf.kfdm}`) //扣分信息 this.kfArr.push({ //扣分项目名称 xmmcStr: getDqxmStr(kf.xmdm), xmdm: kf.xmdm, //扣分描述 desc: thisKf.desc, //扣分分数 score: thisKf.score, // 扣分无锡所代码 markcatalog: thisKf.markcatalog, markserial: thisKf.markserial, kfxh: thisKf.kfxh, //扣分类型 type: kf.type }) this.judgeUI.totalScore += thisKf.score * 1; if(kf.xmdm != 20){ const type = judgeUI.projectsObj[kf.xmdm].type; judgeUI.projectsObj[kf.xmdm].type = (type == 3 || type == 4) ? '4' : '5'; } break; //考车状态 case 4: this.carztStr = getCarStatus(carzt); break; //考试结束 case 5: this.ksjs = ksjs; await fileLog.setExamJudgeData({ method: 'examJudgeEndExam', }) break; //项目取消 case 6:{ console.info(judgeTag,'项目取消'); const {examSubject} = this.judgeUI const xmdm = xmqx.xmdm; const xmmcCode = judgeUI.projectsObj[xmdm].projectCodeCenter; const voiceCode = getKmProjectCancelVoice(examSubject,xmmcCode); // avPlayer.playAudio([`voice/${voiceCode}.mp3`],true) this.judgeUI.projectsObj[xmdm].type = '1'; this.testKmItems[xmmcCode].status = '1'; break; } //语音播放和提示 case 7: goJudgeVoice(sound) break; //模拟灯光事件 case 8: setMndg(mndg) break; //车道和路段变化 case 9: this.judgeUI.lane = lane this.lane = lane; break; //预进项目事件 case 10:{ const param611 = judgeConfigObj['611'] || ''; const [f,s] = param611.split('/') const {xmdm,xmxh} = precast; const xmmcCode = judgeUI.projectsObj[xmdm].projectCodeCenter; const xmmcSingleCode = judgeUI.projectsObj[xmdm].projectCode; // if(examSubject == 2 && ((xmdm == 0 && f == 1) || (xmdm == 1 && s == 1) || xmdm == 3)){ // //倒车入库/桩考/侧方停车 // avPlayer.playAudio([`voice/${xmmcCode}.mp3`],false) // } this.testKmItems[xmmcCode].status = 2; this.xmmcStr = xmmcStr; this.xmmcCode = xmmcCode; this.xmdm = xmdm; this.xmxh = xmxh; this.xmmcSingleCode = xmmcSingleCode; judgeUI.projectsObj[xmdm].type = '2'; } break; //差分事件 case 11:{ const {type}= nongps this.checkDwzt(type) } default: break; } const {xmmcStr,carztStr,kfArr} = this; await callBack({ //项目名称 考车状态 扣分arr xmmcStr, carztStr, kfArr }); //语音播报 this.goVoiceAnnounce(event, xmdm, this.kfArr, xmjs, ksjs,xmxh) //更新UI if (event == 1 || event == 2 || event == 3 || event == 6) { const copyProjectsObj = this.judgeUI.projectsObj; judgeUI.projectsObj = deepClone(copyProjectsObj); } } // 更改考试状态 goVoiceAnnounce = async (event, xmdm, kf, xmjs, ksjs,xmxh) => { const { beginProject, pointsDedute, endProject, avPlayer, uploadProgressPhoto, judgeTask, handEndExam, judgeUI, checkExamIsEnd, checkProjectIsStart, lane } = this; const {projectsObj,judgeConfigObj,examSubject,examMileage,jl,isAllProjectsEnd} = judgeUI; const kfLen = kf.length; //不报语音的项目列表 const ignoreVoiceCodeArr = (judgeConfigObj['312'] || '').split(',') const param611 = judgeConfigObj['611'] || ''; const param512 = (judgeConfigObj['512'] || '').split(','); const [f,s] = param611.split('/') switch (event) { // 项目开始 case 1: const code = projectsObj[xmdm].projectCodeCenter; const isEnd = projectsObj[xmdm].isEnd; const kmCode = getKmProjectVoice(code, 1, judgeConfigObj, lane,xmxh) // if (!ignoreVoiceCodeArr.includes(code)) { // if(examSubject == 2 && ((xmdm == 0 && f == 2) || (xmdm == 1 && s == 2) || xmdm == 3)){ // //倒出入库、桩考\进项目语音控制 // }else{ // kmCode && avPlayer.playAudio([`voice/${kmCode}.mp3`],true) // } // } setTimeout(()=>{if(param512[7] != 0){ clearTimeout(this.deductedPopShowTimer) this.judgeUI.isDeductedPopShow = true }},200) //项目已考不上传监管信息 if (!isEnd) { judgeTask.addTask(async () => { console.info(judgeTag, `项目开始-${xmdm}-${projectsObj[xmdm].name}`) await beginProject(xmdm) },{isDelay: true}) judgeTask.addTask(async () => { console.info(judgeTag, `项目-${xmdm}-上传照片 start`) await uploadProgressPhoto(xmdm) },{isDelay: true}) this.judgeUI.projectsObj[xmdm].isUpload = true; } break; // 项目结束 case 2:{ const endCode = projectsObj[xmdm].projectCodeCenter; const projectIsEnd = projectsObj[xmdm].isEnd; const endKmCode = getKmProjectVoice(endCode, 2, judgeConfigObj, lane,xmxh) // if (!ignoreVoiceCodeArr.includes(endCode) && examSubject == 3) { // endKmCode && avPlayer.playAudio([`voice/${endKmCode}.mp3`]) // } const isStart = await checkProjectIsStart(xmdm,1); if(isStart){ //项目结束了就不再生成数据 console.info(judgeTag + ' projectIsEnd =>',projectIsEnd) if (!projectIsEnd) { judgeTask.addTask(async () => { console.info(judgeTag, `项目结束-${xmdm}-${projectsObj[xmdm].name}`) await endProject(xmdm); this.xmmcSingleCode = 0; this.xmmcEndCode = undefined; }, {isDelay: true}) } } if(!this.judgeUI.isProjectIn){ this.deductedPopShowTimer = setTimeout(()=>{ this.judgeUI.isDeductedPopShow = false },(param512[5] || 0) * 1000) } judgeUI.projectsObj[xmdm].isEnd = true; break; } // 扣分 case 3: console.info('surenjun','扣分开始') //扣分时实时播报语音(0-否+1-是) const currentKf = kf[kfLen -1]; if (judgeConfig.kfVoiceOpen ||(examSubject == 2 && judgeConfigObj['618'] == '1') || (examSubject== 3&& judgeConfigObj['418'] == '1') ) { avPlayer.playAudio([`voice/${currentKf.markcatalog}.mp3`,`voice/mark_${Math.abs(currentKf.score)}.mp3`]) } const isStart = await checkProjectIsStart(currentKf.xmdm,2,currentKf); if(isStart){ await judgeTask.addTask(async () => { console.info(judgeTag, `项目扣分-${currentKf.markcatalog}-${currentKf.desc}`) await pointsDedute(currentKf.xmdm, currentKf) }, {isDelay: true}) } break; // 考车状态 case 4: break // 考试结束 case 5: console.info(judgeTag, '考试结束') judgeTask.addTask(async () => { console.info(judgeTag, '考试结束 start') globalThis.isJudge = false; await handEndExam(ksjs) }) clearInterval(globalThis.judgeTimer) break default: break } if (event == 2 || event == 3) { setTimeout(() => { this.judgeUI.kfArrScroller.scrollTo({ yOffset: 999999, xOffset: 0 }) },500) //统计必考项目完成数量 await this.setCountItems(); await checkExamIsEnd() } } // 检测扣分、结束项目时该项目是否开始 checkProjectIsStart = async(xmdm,currentType:1|2,kf?:KF) => { if(xmdm == 20){ return true } const {judgeTask,beginProject,pointsDedute,uploadProgressPhoto,endProject,checkExamIsEnd,totalScore} = this; const {projectsObj,passingScore:passingGrade} = this.judgeUI const {isUpload} = projectsObj[xmdm]; //如果项目没有开始 console.info('surenjun isUpload=>',isUpload) if(!isUpload){ console.info(judgeTag,'项目补传开始') //项目开始补传 judgeTask.addTask(async ()=>{await beginProject(xmdm)},{isDelay:true}) judgeTask.addTask(async ()=>{await uploadProgressPhoto(xmdm)},{isDelay:true}) this.judgeUI.projectsObj[xmdm].isUpload = true; //扣分补传 if(currentType == 2){ judgeTask.addTask(async ()=>{await pointsDedute(xmdm,kf)},{isDelay:true}) } //扣分补传判断是否合格 不合格补传项目结束 if(currentType == 1 || (currentType == 2 && totalScore < passingGrade)){ judgeTask.addTask(async ()=>{await endProject(xmdm)},{isDelay:true}) this.judgeUI.projectsObj[xmdm].isEnd = true; } judgeTask.addTask(async ()=>{ checkExamIsEnd() }) return false; }else{ return true } } // 项目开始接口同步 beginProject = async (ksxm) => { const carInfo = globalThis.carInfo; const { examSubject,plateNo } = carInfo; const {judgeUI,fileLog,getSbbm,xmxh,filePath} = this; const {lsh,idCard,serialNumber,projectsObj,ksdd,kslx,xldm} = judgeUI const time = await getCurrentTime(); const project = projectsObj[ksxm] const sbxh = getSbbm(ksxm, xmxh) const data = { //系统类别 接口序列号 接口标识 xtlb: '17', jkxlh: serialNumber, jkid: '17C52', drvexam: { // 考试科目 身份证号码 lsh, kskm: examSubject, sfzmhm: idCard, ksxm: project.projectCodeCenter, sbxh, ksxl:xldm, kchp: encodeURI(plateNo), // 开始时间 ksdd: encodeURI(ksdd), kslx: encodeURI(kslx) || '', kssj: time } } const {code} = await writeObjectOut(data,filePath) console.info(judgeTag, '项目开始 end') if (code === 2300007) { this.isJudgeDisConnect = true; } promptWxCode('17C52', code) } // 项目结束接口同步 endProject = async (ksxm) => { const carInfo = globalThis.carInfo; const deviceNo = globalThis.deviceNo; const { examSubject,plateNo,carNo } = carInfo; const {judgeUI,fileLog,getSbxh,xmxh,getSbbm,filePath} = this; const {lsh,idCard,serialNumber,projectsObj,cdsbInfoObj,ksdd,kslx,xldm,} = judgeUI const time = await getCurrentTime(); const project = projectsObj[ksxm] const sbxh = examSubject == 3 ? undefined : getSbbm(ksxm, xmxh) const data = { xtlb: '17', jkxlh: serialNumber, jkid: '17C55', drvexam: { lsh, kskm: examSubject, sfzmhm: idCard, ksxm: project.projectCodeCenter, sbxh, //TODO 操作类型 1:正常 0:撤销该考试记录 czlx: '1', ksxl:xldm, kchp: encodeURI(plateNo), ksdd: encodeURI(ksdd), kslx: encodeURI(kslx) || '', jssj: time } } const {code} = await writeObjectOut(data,filePath) if (code === 2300007) { this.isJudgeDisConnect = true; } console.info(judgeTag, '项目结束 end') promptWxCode('17C55', code) } // 考试扣分 pointsDedute = async (ksxm, kf) => { const carInfo = globalThis.carInfo; const deviceNo = globalThis.deviceNo; const { examSubject,plateNo,carNo } = carInfo; const {judgeUI,getProjectInfo,fileLog,xmmcSingleCode,xmmcEndCode,filePath} = this; const {lsh,idCard,serialNumber,ksdd,projectsObj} = judgeUI const time = await getCurrentTime(); const project = getProjectInfo(ksxm); //科目三夜间行驶.模拟灯光、上车准备出现通用评判,ksxm为当前进行的项目 const checkProjects = ['17', '41', '1']; //获取正在进行的项目 const inProjects = Reflect.ownKeys(projectsObj).filter(projectKey => projectsObj[projectKey].type == 2); let commonKsxm = ''; checkProjects.forEach(projectCode=>{ if(inProjects.includes(projectCode)){ commonKsxm = projectCode } }) const data = { xtlb: '17', jkxlh: serialNumber, jkid: '17C53', drvexam: { lsh, kskm: examSubject, ksxm: project == undefined ? (commonKsxm ? (projectsObj[commonKsxm].projectCodeCenter) : (examSubject == 3 ? 30000 : (xmmcEndCode == undefined ? 10000 : xmmcEndCode))) : project.projectCodeCenter , kfxm: kf.markcatalog, kfxmmx: `${ksxm},${kf.markserial}`, sfzmhm: idCard, kchp: encodeURI(carInfo.plateNo), //扣分方式 kffs: kf.type == 0 ? 1 : 2, ksdd: encodeURI(ksdd), kfsj: time } } console.info(judgeTag + 'ksxm=>',data.drvexam.ksxm) const {code} = await writeObjectOut(data,filePath); if (code === 2300007) { this.isJudgeDisConnect = true } console.info(judgeTag, '项目扣分 end') promptWxCode('17C53', code) } // 考试过程照片 uploadProgressPhoto = async (ksxm) => { const time = await getCurrentTime(); const {judgeUI,plcData,getPhoto,fileLog,filePath} = this; const photoBase64 = await getPhoto(); const carInfo = globalThis.carInfo; const { examSubject,plateNo,carNo } = carInfo; const {lsh,idCard,serialNumber,projectsObj,ksdd,judgeConfigObj} = judgeUI; const {sensor,gps} = plcData const project = projectsObj[ksxm] const data = { xtlb: '17', jkxlh: serialNumber, jkid: '17C54', drvexam: { lsh, kskm: examSubject, ksxm: project.projectCodeCenter, sfzmhm: idCard, kchp: encodeURI(plateNo), zpsj: time, //@ts-ignore zp: photoBase64, cs: Math.floor((judgeConfigObj['350'] == 0?gps.sd:sensor.cs) * 1.852), ksdd: encodeURI(ksdd) } }; const {code} = await writeObjectOut(data,filePath); if (code === 2300007) { this.isJudgeDisConnect = true } promptWxCode('17C54', code) console.info(judgeTag, '上传照片 end') } // 评判语音提示 goJudgeVoice = async (sound: SOUND) => { const {avPlayer,fileLog} = this; const {xmdm,code,type} = sound; console.info('surenjun code=>',JSON.stringify(code)) //判断是不是模拟灯光语音 if (type == 1) { avPlayer.playAudio([`voice/${code[0]}.mp3`], false, () => { examJudgeSoundEnd({ itemno: xmdm, code:code[0], type }) fileLog.setExamJudgeData({ method: 'examJudgeSoundEnd', itemno: xmdm, code:code[0], type, }) }) }else{ avPlayer.playAudio([`voice/${code[0]}.mp3`]) } } // 校验考试是否结束 checkExamIsEnd = async (isManual?: boolean) => { const {judgeUI,avPlayer,isExamEnd,isEndTip,ksjs} = this; const {isAllProjectsEnd,examSubject,singlePlay,totalScore,judgeConfigObj,passingScore,examMileage,jl} = judgeUI; if (isExamEnd) { return } //及格分 let passingGrade = passingScore if (isManual) { // 考试不合格 await examJudgeEndExam() this.isExamEnd = true this.isManual = true } else { const param302 = judgeConfigObj['302']; const param342 = judgeConfigObj['342']; const param512 = (judgeConfigObj['512'] || '').split(','); //单机模式 if (singlePlay) { console.info(judgeTag + ' isAllProjectsEnd => ',isAllProjectsEnd) if (isAllProjectsEnd && jl >= examMileage) { //成绩合格 if(totalScore >= passingGrade && !isEndTip) { if (examSubject == 3 && (param342 == 0 || param342 == 2) && (param302 != 6 || param302 != 7 || param302 != 8)) { if(param512[7] != 0){ clearTimeout(this.deductedPopShowTimer) avPlayer.playAudio(['voice/综合评判.mp3']) this.judgeUI.isDeductedPopShow = true this.judgeUI.defaultTabIndex = 1 this.isEndTip = true return } } else { await examJudgeEndExam() this.isExamEnd = true return } }else{ if(examSubject == 3 && (param302 == 4 || param302 == 5 || param302 == 7 || param302 == 8)){ await examJudgeEndExam() this.isExamEnd = true return } } await examJudgeEndExam() this.isExamEnd = true } } else { //成绩不合格 if (totalScore < passingGrade) { //科目三不合格报靠边停车 if(examSubject == 3 && param302 ==1){ avPlayer.playAudio([`voice/考试结束.mp3`]); return } await examJudgeEndExam() this.isExamEnd = true return } //成绩合格 if (isAllProjectsEnd && totalScore >= passingGrade && !isEndTip) { if(examSubject == 2){ await examJudgeEndExam() this.isExamEnd = true return } //考试里程判断 if(examSubject == 3 && jl < examMileage){ return } //考试合格自动退出 if(examSubject == 3 && (param302 == 4 || param302 == 7) || param302 == 8){ await examJudgeEndExam() this.isExamEnd = true return } if (examSubject == 3 && (param342 == 0 || param342 == 2) && (param302 != 6 || param302 != 7 || param302 != 8)) { if(param512[7] != 0){ clearTimeout(this.deductedPopShowTimer) this.judgeUI.isDeductedPopShow = false avPlayer.playAudio(['voice/综合评判.mp3']) this.judgeUI.isDeductedPopShow = true this.judgeUI.defaultTabIndex = 1 this.isEndTip = true } } else { await examJudgeEndExam() this.isExamEnd = true } } } } } // 处理考试结束 public handEndExam = async (ksjs: KSJS) => { this.judgeUI.loadingPopupVisible = true; this.judgeUI.endPopupVisible = false; this.judgeUI.isDeductedPopShow = false; const {qjjl,dcjl} = ksjs const {judgeUI,endExam,handleSEP,kfArr,avPlayer,judgeTask,isManual} = this; const {judgeConfigObj,examSubject,isAllProjectsEnd,totalScore,passingScore} = judgeUI; //计算考试分数 // this.judgeUI.totalScore = isAllProjectsEnd ? totalScore : 0; const singlePlay = globalThis.singlePlay const param302 = judgeConfigObj['302']; // globalThis.windowClass.setWindowSystemBarEnable(['navigation']) //自动退出待验证并且不合格 if (!isManual && examSubject == 3 && (param302 == 1 || (singlePlay && param302 == 2)) && totalScore < passingScore) { avPlayer.playAudio([`voice/考试结束.mp3`]) } //联网模式下手动结束的直接退出 if (!singlePlay && isManual && !isAllProjectsEnd) { avPlayer.playAudio(['voice/empty.mp3'], true, () => { router.back(); }) return } if (examSubject == 3) { const param302 = judgeConfigObj['302']; if (totalScore < passingScore) { //考试不合格;考试模式,自动退出; if (param302 == 4 || param302 == 5 || param302 == 7 || param302 == 8) { } } else { //考试合格 } } await handleSEP(306); avPlayer.playAudio(['voice/exam_waiting.mp3'], globalThis.singlePlay, async () => { try { if (!singlePlay) { const bytes = await this.getMessageHeartbeat(true); globalThis.judgeUdp.send(bytes) } await endExam() } catch (e) { console.info(judgeTag,JSON.stringify(e)) // setTimeout(() => { // // avPlayer.avPlayerStop(); // router.back(); // }, 3000) } }); } // 考试结束 public endExam = async (isManual?: Boolean) => { const carInfo = globalThis.carInfo; const singlePlay = globalThis.singlePlay const { examSubject ,plateNo} = carInfo; const {judgeUI,ksjs,getPhoto,uploadProgressData,uploadDisConnectData,avPlayer,kfArr,judgeTask,filePath} = this; const {lsh,idCard,serialNumber,kssycs,totalScore,judgeConfigObj,isAllProjectsEnd,passingScore} = judgeUI //TODO 断网考试结束补传 // await uploadDisConnectData(); const time = await getCurrentTime(); const photoBase64 = await getPhoto(); const {d1,d2,d3,d4,d5} = ksjs const data = { xtlb: '17', jkxlh: serialNumber, jkid: '17C56', drvexam: { lsh, kchp: encodeURI(plateNo), kskm: examSubject, sfzmhm: idCard, //@ts-ignore zp: photoBase64, jssj: time, kscj: (totalScore * 1) > 0 ? totalScore : 0, kslc: Math.ceil(((ksjs?.qjjl + ksjs?.dcjl) || 0) / 100), // 1,22;2,560;3,128;4,0;5,0; dwlc: [d1,d2,d3,d4,d5].map((d,index) => `${index+1},${Math.floor(d /100)}`).join(';'), } } const {code,keystr,message} = await writeObjectOut(data,filePath) ; promptWxCode('17C56', code) if(code != 1){ avPlayer.playAudio(['voice/监管失败.mp3']) this.isUdpEnd = true router.back(); return } console.info(judgeTag, '考试结束 end') const param302 = judgeConfigObj['302']; judgeUI.loadingPopupVisible = true; let currentKssycs =0; let voiceURL = '' if (examSubject == 2) { if (isAllProjectsEnd) { voiceURL = (totalScore < passingScore ? `voice/unqualified_${kssycs == 1 ? 'one' : 'two'}.wav` : 'voice/qualified.mp3') }else{ voiceURL = `voice/unqualified_${kssycs == 1 ? 'one' : 'two'}.wav` currentKssycs = kssycs == 1 ? 0 : 1 } switch (voiceURL){ case 'voice/unqualified_one.wav': currentKssycs = 0; break; case 'voice/unqualified_two.wav': currentKssycs = 1; break; case 'voice/qualified.mp3': currentKssycs = 0; break; } } if (examSubject == 3) { if (isAllProjectsEnd) { if (totalScore < passingScore) { voiceURL = `voice/${kssycs == 1 ? 'exam_no_pass_finish' : 'exam_no_pass'}.mp3` currentKssycs = kssycs == 1 ? 0 : 1 } else { voiceURL = 'voice/exam_pass.mp3' currentKssycs = 0 } } else { voiceURL = `voice/${kssycs == 1 ? 'exam_no_pass_finish' : 'exam_no_pass'}.mp3` currentKssycs = kssycs == 1 ? 0 : 1 } switch (voiceURL){ case 'voice/exam_no_pass_finish.mp3': currentKssycs = 0; break; case 'voice/exam_no_pass.mp3': currentKssycs = 1; break; case 'voice/exam_pass.mp3': currentKssycs = 0; break; } } const USER = await getSyncData('USER'); await upDateTableByArray('USER', [{ ...USER[0], kssycs:currentKssycs }]) console.info(judgeTag, `考试成绩:${totalScore}`) if(!singlePlay){ await endRecordVideo(this.videoData) await uploadProgressData(); } //语音播放扣分项 let score = 0; //结束考试时候是否播报一遍所有扣分 const param634 = judgeConfigObj['634']; if (kfArr.length && ((examSubject == 2 && param634 == 1) || examSubject == 3)) { avPlayer.playAudio([`voice/kfdesc.mp3`], false, () => { try { kfArr.forEach((kf, index) => { score += Math.abs(Number(kf.score)); //TODO 考试分数待替换 if (score <= (examSubject == 3 ? 10 : 20)) { if (kfArr.length - 1 === index) { avPlayer.playAudio([`voice/${kf.markcatalog}.mp3`, voiceURL], false, () => { this.isUdpEnd = true router.back(); }) throw new Error('End Loop') } avPlayer.playAudio([`voice/${kf.markcatalog}.mp3`]) } else { avPlayer.playAudio([`voice/${kf.markcatalog}.mp3`, voiceURL], false, () => { router.back(); }) throw new Error('End Loop') } }) } catch (e) { console.info(judgeTag,JSON.stringify(e)) } }) } else { avPlayer.playAudio([voiceURL], true, () => { setTimeout(() => { this.isUdpEnd = true router.back(); }, param302 == 8 ? 3000 : 0) }) } } // 当前项目转换 getDqxmStr = (type) => { const projectsObj = this.judgeUI.projectsObj return projectsObj[type]?.abbreviation || '通用评判' } // 扣分项目转换 getKfStr = (code) => { const markRuleListObj = this.judgeUI.markRuleListObj; const thisMark = markRuleListObj[code] return { desc: thisMark.markshow, score: thisMark.markreal, markcatalog: thisMark.markcatalog, markserial: thisMark.markserial, kfxh: thisMark.kfxh } } // 消息心跳发送 getMessageHeartbeat = async (isEnd?: Boolean) => { const carInfo = globalThis.carInfo; const { examSubject,plateNo,ksyh } = carInfo; const { judgeUI, isExam, serialIndex, tempData, xmmcCode, xmxh, xmmcSingleCode, xmdm, performInfo, kfArr, getTranslateProject, getSbxh, fileLog, } = this; const singlePlay = globalThis.singlePlay const {lsh,startHourTime,totalScore,examTime,judgeConfigObj} = judgeUI; const {fourInOneScreen:{gpsDigit}} = judgeConfig const examType = examSubject == 2?2:3 const {sensor,gps} = tempData; if(tempData.sensor === undefined){ return } const {zfxd,yfxd,shtd,ygd,jgd,skd,dh1,dh2,lhq,jsc,ssc,fsc,lb,mkg,aqd,ygq,cs,fdjzs,dw} = sensor const {jd,wd, hxj, fyj, hbg,sd} = gps; //过滤错误数据 if(jd == 0){ return } const translateProject = getTranslateProject(); const sbxh = getSbxh(xmdm, xmxh) const {carzt,dcjl,qjjl,dxjl,bxjl} = performInfo || {}; const asclshArr = stringToASC( fillZero((singlePlay ? (examSubject == 2 ? '0000000000000':'1111111111111') : lsh) || 0, 13) ); //13不足要补0 const ascksyhArr = stringToASC(fillZero(ksyh || 0, 13)) const ascsbxhArr = stringToASC(sbxh) const translateSignals = getTranslateSignals( [zfxd, yfxd, shtd, ygd, jgd, skd, dh1, dh2, lhq, jsc, ssc, fsc, lb, mkg, aqd].concat(getDwStatusType(dw)).concat(getCarStatusType(carzt)).concat([ygq, sensor.wd, 0]) ) //@ts-ignore const translateJd = convertGpsCoord2(wd).toFixed(gpsDigit) * Math.pow(10, gpsDigit); //@ts-ignore const translateWd = convertGpsCoord2(jd).toFixed(gpsDigit) * Math.pow(10, gpsDigit) //@ts-ignore const translateProjects = translateProject.map(numStr => string2Bytes(parseInt(numStr, 2), 8)[0]) //@ts-ignore let tempSd = ((judgeConfigObj['350'] ==0 ? sd : cs) * 1.852).toFixed(0) * 1 if(tempSd < 1){ tempSd = 0 } const arr = [ //考生号 asclshArr.map(lsh => string2Bytes(lsh, 8)[0]), //考试员号 ascksyhArr.map(ksyh => string2Bytes(ksyh, 8)[0]), //科目类型(0:未考试 1:科目二 2:科目三) + 考试开始时间 string2Bytes(`${examType}${globalThis.startHourTime || startHourTime}`, 4 * 8), // TODO 消息序号从1开始,0结束 string2Bytes(isEnd ? 0 : serialIndex, 2 * 8), /*左向灯 右向灯 双跳灯 远光灯 近光灯 视宽灯 点火1 点火2 离合器 脚刹 手刹 副刹 喇叭 门开关 安全带 档位 车辆状态 雨刮器 雾灯 0*/ translateSignals, //速度 发动机转速 GPS纬度 GPS经度 主天线位置 //@ts-ignore string2Bytes(tempSd * 100, 2 * 8), string2Bytes(fdjzs / 100, 8), string2Bytes(translateJd, 4 * 8), string2Bytes(translateWd, 4 * 8), string2Bytes(1, 8), //GPS东向距离 string2Bytes(dxjl < 0 ? (dxjl + 4294967296) : dxjl, 4 * 8), //GPS北向距离 string2Bytes(bxjl < 0 ? (bxjl + 4294967296) : bxjl, 4 * 8), //航向角 俯仰角 高程(海拔) string2Bytes((hxj) * 100, 2 * 8), string2Bytes(fyj * 100, 2 * 8), string2Bytes(hbg * 100, 4 * 8), //项目状态 parseInt('01010010',2) 二进制转成10进制 translateProjects, //当前项目编号 string2Bytes(xmmcSingleCode ? (xmmcSingleCode * 1 + 1) : 0, 8), //场地设备编号 ascsbxhArr.map(sbxh => string2Bytes(sbxh, 8)[0]), //本次考试行驶距离 string2Bytes(Math.floor((dcjl + qjjl) / 100), 2 * 8), //扣分 string2Bytes(100 - Math.abs(totalScore), 2 * 8), //扣分项数量 string2Bytes(kfArr.length, 8), //n个扣分序号 kfArr.map(kf => string2Bytes(kf.kfxh, 8)[0]), //TODO 牵引车第二gps精度、纬度 string2Bytes(0, 4 * 8), string2Bytes(0, 4 * 8), //TODO 牵引车第二航向角 string2Bytes(0, 2 * 8), //TODO 摩托压线 Byte[20], string2Bytes(0, 20 * 8), //考试用时 string2Bytes(examTime, 4 * 8), //TODO 项目用时 string2Bytes(fillZero(0,2), 2 * 8), //TODO 设备信号状态 string2Bytes(0, 4 * 8), ] let tempArr = []; arr.forEach(itemArr => { tempArr = tempArr.concat(itemArr) }) this.serialIndex += 1; fileLog.setFourAndOneLogData(`${lsh},${ksyh},${examType}${globalThis.startHourTime || startHourTime},`); fileLog.setFourAndOneLogDataBytes(tempArr.toString()); return Array2Byte(tempArr) } //获取场地序号 getSbxh = (ksxm, xmxh) => { const {judgeUI} = this; const {cdsbInfoObj,projectsObj} = judgeUI; const project = projectsObj[ksxm] if(project == 3){ return '0000000000' } if (project === undefined) { return '0000000000' } const projectType = project.sbxh; const projectKey = `${ksxm}_${xmxh}`; const currentCdsb = cdsbInfoObj[projectKey] || {}; const sbxh = currentCdsb.sbbh || '0000000000' return sbxh } getSbbm = (ksxm, xmxh) => { const {judgeUI} = this; const {cdsbInfoObj,projectsObj,examSubject} = judgeUI; const project = projectsObj[ksxm] //科目三不需要 if(examSubject == 3){ return undefined } if (project === undefined) { return '00000000' } const projectKey = `${ksxm}_${xmxh}`; const currentCdsb = cdsbInfoObj[projectKey] || {}; const sbxh = currentCdsb.sbbm || '00000000' return sbxh } // 中心所有项目转换 getTranslateProject = () => { const {examSubject} = this.judgeUI; const tempItems = (examSubject == 2 ? testKm2Items:testKm3Items).map(item => { const current = this.testKmItems[item.code]; return { code: item.code, status: getCenterProjectStatus(current.status) } }) const arr = []; for (let i = 0; i <= 4; i++) { const temp = tempItems.slice(i * 4, (i + 1) * 4); let tempArr = temp.map(item => item.status) if (i === 4) { tempArr = examSubject == 2 //bit36-bit39保留 ? tempArr.concat(['00', '00']) //bit30-bit39保留 : tempArr.concat(['00', '00','00']) } // if (i === 3 && examSubject == 3) { // tempArr = tempArr.concat(['00']) // } arr.push(tempArr.join('')); } return arr } // 获取考试项目详情 getProjectInfo = (projectCode) => { const judgeUI = this.judgeUI; return judgeUI.projectsObj[projectCode] } // 获取模型数据 getModelData = (modelName) => { const modelPath = this.modelPath const fileModel = this.fileModel; const modelData = fileModel.getModelContent(modelPath, modelName); return modelData } // 过程照片拍照 getPhoto = async (empty?: boolean) => { const singlePlay = globalThis.singlePlay //单机模式返回空照片 if (singlePlay) { return '' } else { const {filePhoto} = this; const photoBase64 = await filePhoto.getPhoto(); console.info(judgeTag, '拍照完成') return photoBase64 } } //人工操作项目 public setJudgeItem = async (itemno, type: 1 | 2) => { const {fileLog} = this; await examJudgeArtificialItem(itemno * 1, type); await fileLog.setExamJudgeData({ method: 'examJudgeArtificialItem', itemno: itemno * 1, type }) console.info(judgeTag, `人工评判${type == 1 ? '进入' : '取消'}项目-${itemno}`) } //人工扣分 public setJudgeMark = async (itemno, serial, type = 1) => { const {fileLog} = this await examJudgeArtificialMark(itemno * 1, serial, type); console.info(judgeTag, `进入人工扣分-${itemno}-${serial}`) await fileLog.setExamJudgeData({ method: 'examJudgeArtificialMark', itemno: itemno * 1, serial, type }) console.info(judgeTag, `人工扣分-${itemno}-${serial}`) } // 断网数据补传 uploadDisConnectData = async () => { const {isJudgeDisConnect,fileLog,fileUtil} = this; if (!isJudgeDisConnect) { return } const folderPath = fileLog.folderPath const examDataStr = await fileUtil.readFile(`${folderPath}/wuxi_dis_progress_data.txt`); const examDataArr = examDataStr.split('\n'); for (let examDataStr of examDataArr) { const examData = JSON.parse(examDataStr) const code = await writeObjectOut(examData); } } //上传无锡所过程数据 uploadProgressData = async () => { const {judgeUI,fileUtil,fileLog} = this; const {idCard,startFullTime} = judgeUI const carInfo = globalThis.carInfo; const {carId,examinationRoomId} = carInfo const folderPath = fileLog.folderPath const base64 = new util.Base64(); const time = await getCurrentTime(); const endTime = await getCurrentTime(1) let examDataBase64 //@ts-ignore //TODO try catch报错待优化 const examDataStr: string = await fileUtil.readFile(`${folderPath}/wuxi_progress_data.txt`); try { let tempBuff = buffer.alloc(examDataStr.length, examDataStr) let examData: Uint8Array = new Uint8Array(tempBuff.buffer) examDataBase64 = base64.encodeToStringSync(examData) } catch (e) { console.info(judgeTag, JSON.stringify(e)) } console.info(judgeTag, '过程数据文件上传 start') await uploadExamProgressData({ time, carId, examinationRoomId, examData: examDataBase64, type: 1, cardNo: idCard, examStartTime: startFullTime, examEndTime: endTime, }) console.info(judgeTag, '过程数据文件上传 end') } //获取科目三的评判初始化配置 getKm3JudgeInitConfig = async () => { const {judgeUI,getModelData} = this; const {mapPointArr,mapPointItemArr} = judgeUI; return { map_point: mapPointArr, map_point_item: mapPointItemArr, //科目三暂时为空 iteminfo: [], roads: getModelData('km3/Roads.txt'), sharps: getModelData('km3/Sharps.txt') } } // 处理udp plc信号 handleUdp = async (msg) => { console.info('plc信号', msg) const {fileLog,getPlcData,usbService,isUdpEnd,isExamEnd,judgeUI} = this const stachArr = msg.split(',') if (stachArr[0] != '#DN_GD' || isUdpEnd) { return } const plcData = await getPlcData(msg); // 4.过程数据 await fileLog.setExamJudgeData(plcData) //检测到有无锡所设备接入,需要发送特定的数据,供检测 if (usbService.isWXUSBDevice) { const str = await senorToWXDataStr(msg); usbService.sendUSB(str) } // this.judgeUI.isDwztRight = (plcData.gps.dwzt == 4 && plcData.gps.jdzt == 3); const param350 = judgeUI.judgeConfigObj['350'] //@ts-ignore this.judgeUI.sd = ((param350 == 0? plcData.gps.sd :plcData.sensor.cs) as number * 1.852).toFixed(0) + '' this.judgeUI.dw = (Math.floor(plcData.sensor.dw as number) || 0) + '' //TODO 暂时关闭差分检测异常 // await this.checkDwzt(plcData.gps.dwzt,plcData.gps.jdzt); if(!isExamEnd){ await examJudgeRealExam(plcData) } const udpIndex = globalThis.udpIndex; let [prevJd,preWd] = [0,0] if (udpIndex % 5 === 0 && !isUdpEnd) { const judgeUdp = globalThis.judgeUdp const bytes = await this.getMessageHeartbeat(isExamEnd); judgeUdp.send(bytes) } globalThis.udpIndex += 1 } // 处理特殊参数配置 handleSEP = async (code: number) => { const {judgeUI:{ judgeConfigObj },avPlayer} = this; const {examSubject} = globalThis.carInfo; switch (code) { //结束考试方式 case 306: if (judgeConfigObj[code] == 5) { //靠边停车 avPlayer.playAudio(['voice/406001.mp3']) } break; } } // 获取plc数据 getPlcData = async (plc: string) => { const {fileLog,mndgStr,rmndg} = this; await fileLog.setPlcProgressData(plc) //plc字符串转化成评判初始化数据 const tempData = await plcStrToJson(plc); //模拟灯光回放时刻 tempData.sensor.rmndg = rmndg; //模拟灯灯光灯光项目 tempData.sensor.mndg = mndgStr; //plc字符串转化成无锡所过程数据 const wuXiDataStr = await plcStrToWXJson(plc) this.plcData = tempData await fileLog.setExamJudgeWuxiProgressData(wuXiDataStr) this.tempData = tempData this.plcStr = plc; this.mndgStr = ''; this.rmndg = 0; globalThis.msgStr = plc return tempData } // 处理轨迹plc信号 handleTrajectoryUdp = async (strArr) => { const {fileLog,setJudgeItem,setJudgeMark,endExam} = this; let num = 2; const judgeTimer = setInterval(async () => { const msgStr = strArr[num]; if(msgStr == ''){ console.info(judgeTag, '模拟数据考试结束') // globalThis.windowClass.setWindowSystemBarEnable(['navigation']) clearInterval(judgeTimer) this.checkExamIsEnd(true) return } const msg = JSON.parse(strArr[num]); num++ // 4.过程数据 this.tempData = msg this.judgeUI.isDwztRight = (msg?.gps?.dwzt == 4 && msg?.gps?.jdzt == 3); this.judgeUI.sd = Math.floor(msg?.gps?.sd * 1.852) + ''; this.judgeUI.dw = Math.floor(msg?.sensor?.dw) + '' this.plcData = msg // this.judgeUI.isDwztRight = msg.gps.dwzt == 4; globalThis.msgStr = '' if (msg.method === 'examJudgeArtificialItem') { setJudgeItem(msg.itemno, msg.type) } if (msg.method === 'examJudgeArtificialMark') { setJudgeItem(msg.itemno, msg.serial) } await examJudgeRealExam(msg) const bytes = await this.getMessageHeartbeat(); bytes && globalThis.judgeUdp.send(bytes) }, 200) globalThis.judgeTimer = judgeTimer; } // 统计必考项目、所有项目、已考数量 setCountItems = async () => { const carInfo = globalThis.carInfo; const { examSubject} = carInfo; const {projectsObj} = this.judgeUI; //必考项目数量 必考项目已考数量 let projectNum = 0, endProjectsNum = 0; // 所有考试项目数量 项目已考项目数量 let allProjectNum = 0, allEndProjectsNum = 0; Reflect.ownKeys(projectsObj).forEach(projectKey => { const {type,isRequired} = projectsObj[projectKey]; allProjectNum += 1; if (type == 3 || type == 4) { allEndProjectsNum += 1; } if (isRequired) { projectNum += 1; if (type == 3 || type == 4) { endProjectsNum += 1; } } }) console.info(judgeTag,'项目状态projectsObj:' + JSON.stringify(projectsObj)); console.info(judgeTag,'所有考试项目数量:' + allProjectNum) console.info(judgeTag,'必考项目数量:' + projectNum) console.info(judgeTag,'必考项目已考数量:' + endProjectsNum) //必考项目除靠边停车是否全部完成 this.judgeUI.isRequiredProjectsEnd = (projectNum - endProjectsNum === 0) this.judgeUI.isAllProjectsEnd = (allProjectNum - allEndProjectsNum === 0) } // 模拟灯光 setMndg = async (mndgStr: string) => { this.mndgStr = mndgStr } // 检测差分状态 checkDwzt = async (type) => { const {avPlayer} = this; const judgeConfig = this.judgeUI.judgeConfig; switch (type){ case 0: this.judgeUI.isDwztRight = true; break; case 1: this.judgeUI.dwztErrorVisible = true; avPlayer.playAudio([`voice/差分状态异常.mp3`],true) setTimeout(()=>{ router.back() },3000) break; case 2: avPlayer.playAudio([`voice/差分状态异常.mp3`],true); break; case 3: this.judgeUI.dwztErrorVisible = true; avPlayer.playAudio([`voice/差分状态异常.mp3`],true); break; case 4: this.judgeUI.isDwztRight = false; //差分异常上报 break; } } public plcStr: string private judgeUI private fileLog private filePath private totalScore: number private prevJd: number = 0 private prevWd: number = 0 private dwztNum:number = 0 private folderPath: string private modelPath: string private avPlayer private carztStr: string private rmndg: 0 | 1 private mndgStr: string | undefined private xmmcStr: string private xmmcCode: string private xmmcSingleCode: number private xmmcEndCode?:number private xmdm: string | number private xmxh: string private fileModel: FileModel private filePhoto: FilePhoto private usbService: UsbService //是否是考试模式 private isExam: boolean //考试是否结束了 private isExamEnd: boolean // 是否发送udp private isUdpEnd: boolean = false //是否手动结束考试 private isManual: boolean //UDP服务序列号 private serialIndex: number private fileUtil: FileUtil private judgeTask: JudgeTask private tempData: any private performInfo: any private isEndTip:boolean = false; private deductedPopShowTimer:number = 0; private ksjs: { // 累计前进距离 qjjl: number, // 累计倒车距离 dcjl: number d1: number d2: number d3: number d4: number d5: number d6: number } private kfArr: { //项目名称 xmmcStr: string, xmdm: string | number, //扣分描述 desc: string, //扣分 score: string //无锡所扣分代码 markcatalog: string markserial: string kfxh: string type: 0| 1 | 2 }[] private km2ItemsStatus: any[] //所有的科目考试项目(大车&小车) private testKmItems: any private plcData: any //当前科目二的考试项目 private currentKm2ItemsObj: any //本地轨迹回放地址 private trajectoryPath: string private isTrajectoryOpen: boolean; // 调代理接口是否断网了 private isJudgeDisConnect: boolean; private artSubject3ProjectsCodesArr: number[] = [3, 9, 4, 10, 12, 11] private lane: LANE = { road: '', num: 0, count: 0 } private videoData:any }