import prompt from '@ohos.prompt' import systemTime from '@ohos.systemDateTime'; import router from '@ohos.router'; import util from '@ohos.util'; import buffer from '@ohos.buffer'; import {testMarkRules,testAllitems,testRealExam,testUIAllitems,testKm2Items} from './dataTest/index' import { deepClone, getCurrentTime, stringToASC, string2Bytes, fillZero, Array2Byte, convertGpsCoord2 } from '../../common/utils/tools' import { examJudgeSetLogCallback, examJudgeBeginExam, examJudgeInit, examJudgeRealExam, examJudgeSetRealExamCallback, examJudgeSetPerformCallback, examJudgeEndExam } from './api/index' import { getTranslateSignals, getCarStatus, getCarStatusType, getCenterProjectStatus, getTestMarkRules, sendBlue, sendGreen } from './utils//judge-common' import {writeObjectOut,uploadExamProgressData} from '../../api/judge' import VoiceAnnounce from './utils/voice-announcements' import FileModel from './utils/file-model' import FilePhoto from './utils/file-photo' import JudgeTask from './utils/judge-task' import FileUtil from '../../common/utils/File' import {getMessageHeartbeat} from '../../common//utils//UdpJudge' const judgeTag = 'SURENJUN_JUDGE' export default class Judge{ constructor(judgeUI,fileLog) { this.serialIndex = 1; this.judgeUI = judgeUI this.fileLog = fileLog; //语音播放工具 this.avPlayer = new VoiceAnnounce(); //模型工具 this.fileModel = new FileModel(judgeUI.context); //文件工具 this.fileUtil = new FileUtil(judgeUI.context) this.judgeTask = new JudgeTask() const mediaTest= new FilePhoto(judgeUI.context); this.filePhoto = mediaTest this.kfArr = judgeUI.kfArr this.xmmcStr = ''; this.xmmcCode = ''; this.carztStr = ''; this.allKm2ItemsObj = {}; this.modelPath = 'models/model_enc' this.isTrajectoryOpen = true; this.trajectoryPath = '/logs/2024_01_24/2024_01_24_11_30_06_2210707689316_620502199005070478_马鸣五/judge_exam_data.txt'; this.isExam = !globalThis.singlePlay; const {projectsCenterObj} = judgeUI //科目三待修改 testKm2Items.forEach(item => { this.allKm2ItemsObj[item.code] = item; //考试项目存在 if(projectsCenterObj[item.code]){ this.allKm2ItemsObj[item.code] = { code:item.code, status:1 } } }) this.isEnd = false; } //开始评判 private async judging(callBack:Function){ const { getJudgeBeginData, getPlcData, fileLog, fileUtil, 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.注册日志回调完成') //相关评判初始化只做一次 if(!isJudgeInitBool){ let initInfo:any = '' if(isTrajectoryOpen){ initInfo = JSON.parse(strArr[0]) }else{ initInfo = await this.getJudgeInitData(); } await fileLog.setExamJudgeData(initInfo) const tempJudge = await examJudgeInit(initInfo); globalThis.isJudgeInitBool = true console.info(judgeTag,'4.评判初始化完成') }else{ const initInfo = await this.getJudgeInitData(); await fileLog.setExamJudgeData(initInfo) } 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) this.performInfo = info }) // 3.开始考试 let beginExamInfo if(isTrajectoryOpen){ beginExamInfo = JSON.parse(strArr[1]) }else{ beginExamInfo = await getJudgeBeginData() } await fileLog.setExamJudgeData(beginExamInfo) await examJudgeBeginExam(beginExamInfo); console.info(judgeTag,'6.开始考试注册完成') //实时plc数据信号 // let open = true; if(isTrajectoryOpen){ let num = 2; const judgeTimer = setInterval(async ()=>{ const msg = JSON.parse(strArr[num]); await fileLog.setExamJudgeData(msg) if(!msg){ console.info(judgeTag,'模拟数据考试结束') examJudgeEndExam(); globalThis.windowClass.setWindowSystemBarEnable(['navigation']) clearInterval(judgeTimer) return } // 4.过程数据 this.tempData = msg this.plcData= msg await examJudgeRealExam(msg) num++ },100) globalThis.judgeTimer = judgeTimer; return } globalThis.udpClient.onMessage(async (msg) => { console.info('plc信号',msg) const stachArr= msg.split(',') const {isEnd} = this; if (stachArr[0] != '#DN_GD' || isEnd) { return } const plcData = await getPlcData(msg); // 4.过程数据 await fileLog.setExamJudgeData(plcData) await examJudgeRealExam(plcData) const udpIndex = globalThis.udpIndex; if(udpIndex % 5 === 0){ const judgeUdp = globalThis.judgeUdp const bytes= await this.getMessageHeartbeat(); judgeUdp.send(bytes) } globalThis.udpIndex+=1 }) avPlayer.playAudio(['km2/ksks.WAV'],true) } public async onJudgeFn(fn:Function){ await this.judging(fn) } //处理评判过程回调 handleRealExam = async (strData,callBack) => { // console.log('过程数据:' + strData); let examData = JSON.parse(strData); const {getDqxmStr,getKfStr,judgeUI} = this; const {carzt,xmks,kf,event,xmjs,ksjs} = examData //获取项目结束、项目开始代码 const xmdm = event == 2 ? xmjs.xmdm : xmks.xmdm const xmxh = event == 2 ? xmjs.xmxh : xmks.xmxh; switch (event){ //项目开始 case 1: judgeUI.projectsObj[xmdm].type = '2'; const xmmcStr = judgeUI.projectsObj[xmdm].name; const xmmcCode = judgeUI.projectsObj[xmdm].projectCodeCenter; const xmmcSingleCode = judgeUI.projectsObj[xmdm].projectCode; this.allKm2ItemsObj[xmmcCode].status = 2; this.xmmcStr = xmmcStr; this.xmmcCode = xmmcCode; this.xmmcSingleCode = xmmcSingleCode this.xmdm = xmdm; this.xmxh = xmxh; break; //项目结束 case 2: judgeUI.projectsObj[xmdm].type = (xmjs.xmhg === 0 ? '4' : '3'); this.xmmcStr = '无'; this.xmmcCode = ''; this.xmmcSingleCode = 0; this.xmdm = ''; 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 }) this.judgeUI.totalScore += thisKf.score*1; break; //考车状态 case 4: this.carztStr = getCarStatus(carzt);break; //考试结束 case 5: this.ksjs = ksjs;break; default:;break; } const {xmmcStr,carztStr,kfArr} = this; await callBack({ //项目名称 考车状态 扣分arr xmmcStr, carztStr, kfArr }); const copyProjectsObj = this.judgeUI.projectsObj; //语音播报 this.goVoiceAnnounce(event,xmdm, this.kfArr,xmjs) judgeUI.projectsObj = deepClone(copyProjectsObj) } //更改考试状态 goVoiceAnnounce = async (event,xmdm,kf,xmjs) => { const projectsObj = this.judgeUI.projectsObj; const {beginProject,pointsDedute,endProject,avPlayer,uploadProgressPhoto,judgeTask,handEndExam} = this; const xmhg = xmjs.xmhg const kfLen = kf.length switch (event){ // 项目开始 case 1: avPlayer.playAudio([`km2/${projectsObj[xmdm].projectCodeCenter}.mp3`],true) //项目开始同步接口 await judgeTask.addTask(async ()=>{ console.info(judgeTag,'项目开始 start') await beginProject(xmdm) console.info(judgeTag,'上传照片 start') await uploadProgressPhoto(xmdm) }) break; // 项目结束 case 2: await judgeTask.addTask(async ()=>{ console.info(judgeTag,'项目结束123 start') await endProject(xmdm) }) break; // 扣分 case 3: console.info(judgeTag ,kf[kfLen -1].markcatalog); avPlayer.playAudio([`km2/${kf[kfLen -1].markcatalog}.mp3`]) await judgeTask.addTask(async ()=>{ console.info(judgeTag,'项目扣分 start') await pointsDedute(kf[kfLen -1].xmdm,kf[kfLen -1]) }) break; // 考车状态 case 4:break // 考试结束 case 5: clearInterval(globalThis.judgeTimer) await judgeTask.addTask(async ()=>{ console.info(judgeTag,'考试结束 start') await handEndExam() }) break } } //处理考试结束 public handEndExam = async ()=>{ const {isExam,judgeUI,endExam,avPlayer} = this; avPlayer.playAudio(['km2/exam_waiting.mp3'],true) this.isEnd = true const bytes = await this.getMessageHeartbeat(true); globalThis.judgeUdp.send(bytes) await examJudgeEndExam(); // sendBlue() globalThis.isJudge = false await endExam() } // 拍照 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 } } // 当前项目转换 getDqxmStr = (type) => { const projectsObj = this.judgeUI.projectsObj if(projectsObj){ if(projectsObj[type]){ return projectsObj[type].abbreviation }else{ return '通用评判' } } } // 扣分项目转换 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 } } // 项目开始接口同步 beginProject = async(ksxm) => { const carInfo = globalThis.carInfo; const { examSubject,plateNo } = carInfo; const {judgeUI,fileLog,getSbbm,xmxh} = this; const {lsh,idCard,serialNumber,projectsObj,ksdd,kslx} = 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, kchp:encodeURI(plateNo), ksdd:encodeURI(ksdd), ksxl:encodeURI(kslx) || '', //开始时间 kssj:time } } const code = await writeObjectOut(data) console.info(judgeTag,'项目开始 end') if(code === 2300007){ this.isJudgeDisConnect = true; } const isJudgeDisConnect = this.isJudgeDisConnect isJudgeDisConnect ? fileLog.setExamJudgeDisWuxiProgressData(data) : fileLog.setExamJudgeWuxiData(data) let toast = '' switch (code){ case 0:toast = '存在作弊嫌疑,已被取消或暂停考试';break; case -1:toast = '无考生身份比对信息';break; case -2:toast = '考试项目与考试安排信息不符';break; case -3:toast = '考试设备未备案';break; case -4:toast = '考试设备与考试项目不符';break; case -5:toast = '考试设备使用状态异常';break; case -6:toast = '考生考试车型与考试设备使用准驾车型范围不符';break; case -7:toast = '该考生存在作弊嫌疑,已被暂停/取消考试';break; case -8:toast = '项目开始时间不能小于科目开始时间';break; case -9:toast = '存在未结束的考试项目、不能开始新的项目考试!';break; case -10:toast = '科目三考车号牌不能为空';break; case -11:toast = '同一考车存在未结束考试,不能开始应用于新的考试';break; case -12:toast = '未找到考场记录';break; case -13:toast = '未找到考车信息';break; case -14:toast = '随机抽取考生的考车与当前考车不一致';break; default:toast = '';break; } if(toast){ prompt.showToast({ message: decodeURIComponent(toast), duration: 4000 }); } } // 项目结束接口同步 endProject = async(ksxm) =>{ const carInfo = globalThis.carInfo; const deviceNo = globalThis.deviceNo; const { examSubject,plateNo,carNo } = carInfo; const {judgeUI,fileLog,getSbxh,xmxh,getSbbm} = this; const {lsh,idCard,serialNumber,projectsObj,cdsbInfoObj,ksdd,kslx} = judgeUI const time = await getCurrentTime(); const project = projectsObj[ksxm] const sbxh = getSbbm(ksxm,xmxh) const data = { xtlb:'17', jkxlh:serialNumber, jkid:'17C55', drvexam:{ lsh, kskm:examSubject, // 身份证号码 sfzmhm:idCard, ksxm:project.projectCodeCenter, sbxh, //操作类型 1:正常 0:撤销该考试记录 czlx:'1', kchp:encodeURI(plateNo), ksdd:encodeURI(ksdd), ksxl:encodeURI(kslx) || '', //结束时间 jssj:time } } const code = await writeObjectOut(data) if(code === 2300007){ this.isJudgeDisConnect = true; } const isJudgeDisConnect = this.isJudgeDisConnect isJudgeDisConnect ? fileLog.setExamJudgeDisWuxiProgressData(data) : fileLog.setExamJudgeWuxiData(data) console.info(judgeTag,'项目结束 end') let toast = '' switch (code){ case -1:toast = '无当前考试项目开始信息';break; case -2:toast = '考生身份证明号码与考生预约信息不符';break; case -3:toast = '考试项目不正确';break; case -4:toast = '考试设备序号不正确!';break; case -5:toast = '考试项目结束时间写入错误';break; case -6:toast = '考生未进行身份认证';break; case -7:toast = '项目考试过程信息记录被非法篡改';break; case -8:toast = '每个考试项目中必须至少抓拍一张照片';break; case -12:toast = '未找到考场记录';break; case -13:toast = '未找到考车信息';break; case -15:toast = '考试过程信息必须由考车上传';break; case -90:toast = '考试项目已经结束、无需重传';break; case -91:toast = '实际道路考试,在完成科目考试时统一结束';break; } if(toast){ prompt.showToast({ message: decodeURIComponent(toast), duration: 4000 }); } } // 考试扣分 pointsDedute= async (ksxm,kf) => { const carInfo = globalThis.carInfo; const deviceNo = globalThis.deviceNo; const { examSubject,plateNo,carNo } = carInfo; const {judgeUI,getProjectInfo,fileLog} = this; const {lsh,idCard,serialNumber,ksdd} = judgeUI const time = await getCurrentTime(); const project = getProjectInfo(ksxm); const data = { //系统类别 xtlb:'17', //接口序列号 jkxlh:serialNumber, //接口标识 jkid:'17C53', drvexam:{ //流水号 lsh, //考试科目 kskm:examSubject, // 通用评判科二10000,科三30000 ksxm:project?project.projectCodeCenter:10000, kfxm:kf.markcatalog, kfxmmx:`${ksxm},${kf.markserial}`, // 身份证号码 sfzmhm:idCard, kchp:encodeURI(carInfo.plateNo), //1:自动 2:人工 kffs:1, ksdd:encodeURI(ksdd), //开始时间 kfsj:time } } const code = await writeObjectOut(data); if(code === 2300007){ this.isJudgeDisConnect = true; } const isJudgeDisConnect = this.isJudgeDisConnect isJudgeDisConnect ? fileLog.setExamJudgeDisWuxiProgressData(data) : fileLog.setExamJudgeWuxiData(data) console.info(judgeTag,'项目扣分 end') let toast = '' switch (code){ case 0:toast = '已存在同一时间的同一扣分记录';break case -1:toast = '无当前考试项目开始信息';break; case -2:toast = '扣分时间大于项目开始时间!';break; case -3:toast = '考试项目与扣分项不符';break; case -4:toast = '项目考试过程中,请传入当前考试项目代码';break; case -5:toast = '考生未进行身份认证';break; case -6:toast = '扣分时间写入错误';break; case -7:toast = '项目考试过程信息记录被非法篡改';break; case -12:toast = '未找到考场记录';break; case -13:toast = '未找到考车信息';break; case -15:toast = '考试过程信息必须由考车上传';break; default:toast = '';break } if(toast){ prompt.showToast({ message: decodeURIComponent(toast), duration: 4000 }); } } // 考试过程照片 uploadProgressPhoto = async (ksxm) => { const time = await getCurrentTime(); const {judgeUI,plcData,getPhoto,fileLog} = this; const photoBase64 = await getPhoto(); const carInfo = globalThis.carInfo; const { examSubject,plateNo,carNo } = carInfo; const {lsh,idCard,serialNumber,projectsObj,ksdd} = 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:encodeURIComponent(photoBase64), cs:Math.ceil(gps.sd * 1.852), ksdd:encodeURI(ksdd) } }; const code = await writeObjectOut(data); if(code === 2300007){ this.isJudgeDisConnect = true; } const isJudgeDisConnect = this.isJudgeDisConnect; let toast = ''; switch (code){ case -1:toast = '无当前科目考试信息';break; case -2:toast = '考生身份证明号码与考生预约信息不符';break; case -3:toast = '考试项目不正确';break; case -4:toast = '考试过程中拍摄照片数量少于3张!';break; case -5:toast = '考试项目不符合要求';break; case -6:toast = '存在未结束的考试项目!';break; } if(toast){ prompt.showToast({ message: decodeURIComponent(toast), duration: 4000 }); } fileLog.setExamJudgeWuxiData(data) console.info(judgeTag,'上传照片 end') } // 考试结束 public endExam = async (isManual?:Boolean) => { const carInfo = globalThis.carInfo; const deviceNo = globalThis.deviceNo; const { examSubject ,plateNo} = carInfo; const {judgeUI,fileLog,ksjs,getPhoto,uploadProgressData,uploadDisConnectData,avPlayer} = this; const {lsh,idCard,serialNumber,kssycs,totalScore} = judgeUI await uploadDisConnectData(); const time = await getCurrentTime(); const photoBase64 = await getPhoto(); const data = { xtlb:'17', jkxlh:serialNumber, jkid:'17C56', drvexam:{ //流水号 lsh, kchp:encodeURI(plateNo), kskm:examSubject, sfzmhm:idCard, //@ts-ignore zp:encodeURIComponent(photoBase64), jssj:time, kscj:(totalScore*1) > 0 ? totalScore : 0, kslc:(ksjs?.qjjl + ksjs?.dcjl) || 0, dwlc:'', } } const code = await writeObjectOut(data); let toast = ''; switch (code){ case -1:toast = '无当前科目考试信息';break; case -2:toast = '考生身份证明号码与考生预约信息不符';break; case -3:toast = '考试结束时间不正确';break; case -4:toast = '考试过程中拍摄照片数量少于3张!';break; case -5:toast = '考试项目不符合要求';break; case -6:toast = '存在未结束的考试项目!';break; case -7:toast = '传输的考试成绩非空';break; case -91:toast = '考试成绩计算不一致';break; case -91:toast = '日间考试已结束等待进行夜间考试';break; default: toast = '';break } console.info(judgeTag,'考试结束 end') if(!isManual){ if(totalScore < 80){ judgeUI.loadingPopupVisible = true if(kssycs == 1){ avPlayer.playAudio(['km2/unqualified_one.wav'],true) }else{ avPlayer.playAudio(['km2/unqualified_two.wav'],true) } }else{ avPlayer.playAudio(['km2/qualified.mp3'],true) } } console.info(judgeTag,`考试成绩:${totalScore}`) fileLog.setExamJudgeWuxiData(data) await uploadProgressData(); setTimeout(()=>{ router.back(); },3000) } // 断网数据补传 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') } // 获取评判初始化数据 getJudgeInitData = async () => { const {getModelData} = this const carInfo = globalThis.carInfo; const { examSubject,plateNo,carNo } = carInfo; const {fileLog} = this const judgeUI = this.judgeUI const {projectsObj,cdsbInfoObj,markRuleListObj,carType,carName} = judgeUI const initInfo = { kskm:examSubject*1, kchp:plateNo, kchm:carNo*1, kscx:carType, cxcode:'1', name:carName, carmodel:getModelData(`${carType}.txt`), allitems:Reflect.ownKeys(cdsbInfoObj).map(cdsbKey=>{ const cdsb = cdsbInfoObj[cdsbKey]; const {xmdm,xmxh,modelKey} = cdsb return { xmdm,xmxh,model:getModelData(`${modelKey}.txt`) } }), mark:Reflect.ownKeys(markRuleListObj).map(ruleKey=>(markRuleListObj[ruleKey])) || testMarkRules, sysset:judgeUI.judgeConfig, }; console.info(judgeTag,'3.获取评判初始化数据完成') return initInfo } // 消息心跳发送 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} = this; const {lsh,startHourTime,totalScore} = judgeUI; const examType = isExam?examSubject:0; const {sensor,gps} = tempData; const {zfxd,yfxd,shtd,ygd,jgd,skd,dh1,dh2,lhq,jsc,ssc,fsc,lb,mkg,aqd,ygq,cs,fdjzs} = sensor const {jd,wd, hxj, fyj, hbg,} = gps const translateProject = getTranslateProject(); const sbxh = getSbxh(xmdm,xmxh) const {carzt,dcjl,qjjl,dxjl,bxjl} = JSON.parse(performInfo); const asclshArr = stringToASC(lsh); //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, 0,0,0,0 ].concat(getCarStatusType(carzt)).concat([ ygq, sensor.wd, 0 ]) ) //@ts-ignore const translateJd = convertGpsCoord2(wd).toFixed(7) * Math.pow(10,7) //@ts-ignore const translateWd = convertGpsCoord2(jd).toFixed(7) * Math.pow(10,7) //@ts-ignore const translateProjects= translateProject.map(num => string2Bytes(num,8)[0]) const arr = [ //考生号 TODO 考试员号 asclshArr.map(lsh => string2Bytes(lsh,8)[0]), ascksyhArr.map(ksyh => string2Bytes(ksyh,8)[0]), //科目类型(0:未考试 1:科目二 2:科目三) + 考试开始时间 string2Bytes(`${examType}${startHourTime}`,4 * 8), // TODO 消息序号从1开始,0结束 string2Bytes(isEnd ? 0 : serialIndex,2 * 8), /*左向灯 右向灯 双跳灯 远光灯 近光灯 视宽灯 点火1 点火2 离合器 脚刹 手刹 副刹 喇叭 门开关 安全带 档位 车辆状态 雨刮器 雾灯 0*/ translateSignals, //速度 发动机转速 GPS纬度 GPS经度 主天线位置 //@ts-ignore string2Bytes(cs,2 * 8), string2Bytes(fdjzs / 60,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+90) * 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]) ] let tempArr = []; arr.forEach(itemArr =>{ tempArr = tempArr.concat(itemArr)}) this.serialIndex += 1; return Array2Byte(tempArr) } // 获取开始考试数据 getJudgeBeginData = async () => { const {code,name:examinerName} = globalThis.examinerInfo; const {isExam} = this; const judgeUI = this.judgeUI const {projects,carType,isDdxk,ddxkTime,projectsCenterObj,ddxkKsxmArr,ddxkKfArr} = judgeUI; const beginInfo = { ic:'', kgid:'012', kgxm:decodeURI(examinerName), exam:isExam?1:0, //生成的轨迹文件 track:'', xm:judgeUI.name, sex:0, kslsh:judgeUI.lsh, sfzmhm:judgeUI.idCard, ksyy:'', kscx:carType, kkcs:1, sfyk:0, ykkkcs:1, wayno:0, czlx:0, kskssj:await systemTime.getCurrentTime(), ksxm:projects.map(project=>{ return { xmdm:project.projectCode*1, xmxh:'', } }), //断点续考 ddxk:isDdxk ? 1 : 0, ddkssj:ddxkTime, ykxm:isDdxk?(ddxkKsxmArr?.map(projectCenterCode => (projectsCenterObj[projectCenterCode]?.projectCode)*1)):[], kfxm:isDdxk?(ddxkKfArr?.map(kf => { const [xmdm,kfdm] = kf.split(',') return { xmdm:xmdm*1, kfdm } })):[], yklc:0, special:[] } console.info(judgeTag,'5.获取开始考试数据完成') return beginInfo } // 获取plc数据 getPlcData = async (plc:string) => { const {fileLog} = this; await fileLog.setPlcProgressData(plc) const p = plc.split(',').map((val,key)=>{ if(key !== 27 && key !== 92){ //@ts-ignore return val*1 }else{ return val } }); let data:any = testRealExam; const time = await systemTime.getCurrentTime() const tempData = { sensor:{ //安全带 车门门开关 手刹 脚刹 副刹 离合器 喇叭 示宽灯 近光灯 远光灯 aqd:p[19], mkg:p[14], ssc:p[13], jsc:p[12], fsc:p[18], lhq:p[17], lb:p[4], skd:p[9], jgd:p[7], ygd:p[8], //左方向灯 右方向灯 双跳灯 雾灯 雨刮器 点火1 点火2 发动机转速 档位 车速 zfxd:p[2], yfxd:p[3], shtd:p[20],wd:p[10], ygq:p[11], dh1:p[5], dh2:p[6], fdjzs:p[25], dw:p[28], cs:p[23], //@ts-ignore 方向盘 fxp:p[27].split('_')[0]*1, //累计脉冲 溜车脉冲 超声波左后 超声波右后 超声波右前 超声波左前 座椅 仪表盘 后视镜 倒车镜 光照 雨量 ljmc:p[24], lcmc:0, csbzh:p[32], csbyh:p[30], csbyq:p[31], csbzq:p[29], zy:0, tbp:0, hsj:0, dcj:0, gx:0, yl:0 }, gps:{ //办卡类型 定位差分状态 bklx:p[56], dwzt:p[83], //@ts-ignore 角度差分状态 jdzt:p[92].split('-')[0]*1, //gps数据 //gps时间 经度 纬度 航向角 俯仰角 海拔高 高度差 速度 sj:time, jd:p[96], wd:p[95], hxj:p[90], fyj:p[91], hbg:p[85], gdc:p[86], sd:p[97], //龄期 经度因子 纬度因子 定位搜星数 age:p[87], jdyz:p[89], wdyz:p[88], dwsxs:p[84], //@ts-ignore 角度搜星数 jdsxs:p[92].split('-')[1]*1 }, gps2:data.gps, vision:data.vision, radar:data.radar, extend:{} } const gps = tempData.gps const timeStr = p[93] + '' + p[94]; const judgeSignal = [ // 车门 安全带 熄火 发动机启动 左转向 右转向 前照灯近灯 前照灯远灯 p[14], p[19], p[5], p[6], p[2], p[3], p[7], p[8], // 注车制动 行车制动 离合器 副制动 喇叭 雨刷 危险报警灯 示廓灯 系统未涉及的传感器信号 p[13], p[12], p[17], p[18], p[4], p[11], p[20], p[9], 0 ] const judgeAnotherSignal = [ // 低三挡位 左侧单边桥1 左侧单边桥2 右侧单边桥1 右侧单边桥2 雾灯 '000', '0', '0', '0', '0', p[10], // 桩杆全无信号 左后绕车 右后绕车 右前绕车 左前绕车 '000', '0', '0', '0', '0' ] const wuXiData = [ // 卫星时间 精度 纬度 高度 方位角 俯仰角 速度角 速度 横滚 卫星定位状态 卫星定位状态 '$KSXT', timeStr, gps.jd, gps.wd, gps.hbg, gps.hxj, gps.fyj, '' , gps.sd, '', gps.dwzt, gps.dwzt, //前天线可用星数 后天线可用星数 东向坐标位置 北向位置坐标 天向位置坐标 东向速度 北向速度 天向速度 '', '', '', '', '', '', '', '', //@ts-ignore 评判信号1 评判信号2 发动机转速 (judgeSignal.join('')*1).toString(16), (judgeAnotherSignal.join('')*1).toString(16) , p[25], '0xFFFFFFF' ] const wuXiDataStr = wuXiData.join(',') this.plcData= tempData await fileLog.setExamJudgeWuxiProgressData(wuXiDataStr) this.tempData = tempData this.plcStr = plc; globalThis.msgStr= plc return tempData } //获取场地序号 getSbxh = (ksxm,xmxh) => { const {judgeUI} = this; const {cdsbInfoObj,projectsObj} = judgeUI; const project = projectsObj[ksxm] 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} = judgeUI; const project = projectsObj[ksxm] if(project === undefined){ return '00000000' } const projectKey = `${ksxm}_${xmxh}`; const currentCdsb = cdsbInfoObj[projectKey] || {}; const sbxh = currentCdsb.sbbm || '00000000' return sbxh } // 中心所有项目转换 getTranslateProject = () => { const {allKm2ItemsObj} = this; const tempItems = testKm2Items.map(item=>{ const current = allKm2ItemsObj[item.code]; return { code:item.code, status:getCenterProjectStatus(current.status) } }) const len = Math.floor(tempItems.length / 4); const arr = []; for(let i = 0;i <= len;i++){ const temp = tempItems.slice( i*4 , (i+1)*4 ); let tempArr = temp.map(item => item.status) if(i === 4){ tempArr = tempArr.concat(['00','00']) } arr.push(tempArr.join('')); } return arr.map(numStr => parseInt(numStr,2)); } // 获取考试项目详情 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 } private judgeUI private fileLog private totalScore:number private folderPath:string private modelPath:string private avPlayer private carztStr:string private xmmcStr:string private xmmcCode:string private xmmcSingleCode:number private xmdm:string private xmxh:string private fileModel:FileModel private filePhoto:FilePhoto //是否是考试模式 private isExam:boolean //考试是否结束了 private isEnd:boolean //UDP服务序列号 private serialIndex:number private fileUtil:FileUtil private judgeTask:JudgeTask private tempData:any public plcStr:string private performInfo:any private ksjs:{ // 累计前进距离 qjjl:number, // 累计倒车距离 dcjl:number } private kfArr:{ //项目名称 xmmcStr:string, xmdm:string, //扣分描述 desc:string, //扣分 score:string //无锡所扣分代码 markcatalog:string markserial:string kfxh:string }[] private plcData:any private km2ItemsStatus:any[] //所有的科目二考试项目(大车&小车) private allKm2ItemsObj:any //当前科目二的考试项目 private currentKm2ItemsObj:any //本地轨迹回放地址 private trajectoryPath:string private isTrajectoryOpen:boolean; // 调代理接口是否断网了 private isJudgeDisConnect:boolean; }