1896 lines
		
	
	
		
			60 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			1896 lines
		
	
	
		
			60 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| 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, KSJS, SOUND } 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 { KF, LANE } from '../judgeSDK/api/judgeSDK.d';
 | ||
| import { endRecordVideo, saveStartRecordVideo } from '../../common/service/videoService';
 | ||
| import {
 | ||
|   Array2Byte,
 | ||
|   convertGpsCoord2,
 | ||
|   deepClone,
 | ||
|   fillZero,
 | ||
|   getCurrentTime,
 | ||
|   string2Bytes,
 | ||
|   stringToASC
 | ||
| } from '../../common/utils/tools';
 | ||
| 
 | ||
| import {
 | ||
|   getCarStatus,
 | ||
|   getCarStatusType,
 | ||
|   getCenterProjectStatus,
 | ||
|   getDwStatusType,
 | ||
|   getKmProjectCancelVoice,
 | ||
|   getKmProjectVoice,
 | ||
|   getTranslateSignals,
 | ||
|   plcStrToJson,
 | ||
|   plcStrToWXJson,
 | ||
|   promptWxCode,
 | ||
|   senorToWXDataStr
 | ||
| } from './utils/judgeCommon';
 | ||
| 
 | ||
| import {
 | ||
|   examCalcGpsDistance,
 | ||
|   examJudgeArtificialItem,
 | ||
|   examJudgeArtificialMark,
 | ||
|   examJudgeBeginExam,
 | ||
|   examJudgeEndExam,
 | ||
|   examJudgeInit,
 | ||
|   examJudgeRealExam,
 | ||
|   examJudgeSetLogCallback,
 | ||
|   examJudgeSetPerformCallback,
 | ||
|   examJudgeSetRealExamCallback,
 | ||
|   examJudgeSoundEnd,
 | ||
|   examJudgeVersion
 | ||
| } from './api/index';
 | ||
| import { getSyncData, upDateTableByArray } from '../../common/service/initable';
 | ||
| import promptAction from '@ohos.promptAction';
 | ||
| 
 | ||
| const judgeTag = 'SURENJUN_JUDGE'
 | ||
| 
 | ||
| export default class Judge {
 | ||
|   // 过程照片拍照
 | ||
|   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')
 | ||
| 
 | ||
|     try {
 | ||
|       await uploadExamProgressData({
 | ||
|         time,
 | ||
|         carId,
 | ||
|         examinationRoomId,
 | ||
|         examData: examDataBase64,
 | ||
|         type: 1,
 | ||
|         cardNo: idCard,
 | ||
|         examStartTime: startFullTime,
 | ||
|         examEndTime: endTime,
 | ||
|       })
 | ||
|     } catch (e) {
 | ||
|       console.info(judgeTag, '过程数据文件上传失败:' + JSON.stringify(e))
 | ||
|     }
 | ||
|     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')
 | ||
|     }
 | ||
|   }
 | ||
|   // 处理特殊参数配置
 | ||
|   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;
 | ||
|     }
 | ||
|   }
 | ||
|   public plcStr: string
 | ||
|   private judgeUI
 | ||
|   // 检测扣分、结束项目时该项目是否开始
 | ||
|   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
 | ||
|     }
 | ||
|   }
 | ||
|   // 处理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
 | ||
|   }
 | ||
|   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
 | ||
|   // 模拟灯光
 | ||
|   setMndg = async (mndgStr: string) => {
 | ||
|     this.mndgStr = mndgStr
 | ||
|   }
 | ||
|   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
 | ||
|   //实时计算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;
 | ||
|   }
 | ||
|   private performInfo: any
 | ||
|   private isEndTip: boolean = false;
 | ||
|   private deductedPopShowTimer: number = 0;
 | ||
|   // 校验考试是否结束
 | ||
|   // 校验考试是否结束
 | ||
|   checkExamIsEnd =
 | ||
|     async (isManual?: boolean) => {
 | ||
|       const {judgeUI,avPlayer,isExamEnd,isEndTip,ksjs} = this;
 | ||
|       const {isAllProjectsEnd,examSubject,singlePlay,totalScore,judgeConfigObj,passingScore,examMileage,jl} = judgeUI;
 | ||
|       const param302 = judgeConfigObj['302'];
 | ||
|       if (isExamEnd) {
 | ||
|         return
 | ||
|       }
 | ||
|       //及格分
 | ||
|       let passingGrade = passingScore
 | ||
|       if (isManual) {
 | ||
|         // 考试不合格
 | ||
|         await examJudgeEndExam()
 | ||
|         this.isExamEnd = true
 | ||
|         this.isManual = true
 | ||
|       } else {
 | ||
|         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) {
 | ||
|               if (param302 == 1) {
 | ||
|                 avPlayer.playAudio([`voice/考试结束.mp3`]);
 | ||
|               } else if (param302 == 0) {
 | ||
|                 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
 | ||
|             }
 | ||
|           }
 | ||
|         }
 | ||
|       }
 | ||
|     }
 | ||
|   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
 | ||
|   // 获取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, '模拟数据考试结束')
 | ||
|         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;
 | ||
|   }
 | ||
|   //当前科目二的考试项目
 | ||
|   private currentKm2ItemsObj: any
 | ||
|   //本地轨迹回放地址
 | ||
|   private trajectoryPath: string
 | ||
|   private isTrajectoryOpen: boolean;
 | ||
|   // 调代理接口是否断网了
 | ||
|   private isJudgeDisConnect: boolean;
 | ||
|   // 项目开始接口同步
 | ||
|   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 this.sendWriteObjectOut(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 this.sendWriteObjectOut(data, filePath)
 | ||
|     if (code === 2300007) {
 | ||
|       this.isJudgeDisConnect = true;
 | ||
|     }
 | ||
|     console.info(judgeTag, '项目结束 end')
 | ||
|     promptWxCode('17C55', 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 this.sendWriteObjectOut(data, filePath);
 | ||
|     if (code === 2300007) {
 | ||
|       this.isJudgeDisConnect = true
 | ||
|     }
 | ||
|     promptWxCode('17C54', code)
 | ||
|     console.info(judgeTag, '上传照片 end')
 | ||
|   }
 | ||
|   private artSubject3ProjectsCodesArr: number[] = [3, 9, 4, 10, 12, 11]
 | ||
|   private lane: LANE = {
 | ||
|     road: '', num: 0, count: 0
 | ||
|   }
 | ||
|   private videoData: any
 | ||
|   private disConnectNum: number = 0;
 | ||
| 
 | ||
|   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;
 | ||
|   }
 | ||
| 
 | ||
|   //调用监管接口
 | ||
|   sendWriteObjectOut = async (data, filePath) => {
 | ||
|     const temp = await writeObjectOut(data, filePath);
 | ||
|     console.log("wzj", JSON.stringify(temp))
 | ||
|     if (this.disConnectNum == 0) {
 | ||
|       console.log("wzj", "第一次发送", JSON.stringify(data))
 | ||
|     }
 | ||
|     if (this.disConnectNum < 5 && this.disConnectNum > 0) {
 | ||
|       console.log("wzj", "第" + this.disConnectNum + "次重新发送", JSON.stringify(data))
 | ||
|     }
 | ||
|     if (
 | ||
|     //后台连接中心异常
 | ||
|       temp.code == -1 || temp.code == 0 ||
 | ||
|         //断网&网络超时次数计算
 | ||
|         temp.code == 2300007 || temp.code == 2300028) {
 | ||
|       this.disConnectNum += 1;
 | ||
|       if (this.disConnectNum < 5) {
 | ||
|         if (temp.code == 2300028) {
 | ||
|           await new Promise(resolve => setTimeout(resolve, 1000)); // 延迟1秒
 | ||
|         }
 | ||
|         return await this.sendWriteObjectOut(data, filePath)
 | ||
|       }
 | ||
|     }
 | ||
| 
 | ||
|     if (this.disConnectNum >= 5) {
 | ||
|       console.info('surenjun', '123')
 | ||
|       this.judgeUI.errorMsg = '当前的考试过程信息网络传输异常,程序点击确认将重启!';
 | ||
|       this.judgeUI.disConnectErrorOpen = true
 | ||
|     }
 | ||
| 
 | ||
|     this.disConnectNum = 0
 | ||
|     return temp
 | ||
|   }
 | ||
| 
 | ||
|   public async onJudgeFn(fn: Function) {
 | ||
|     await this.judging(fn)
 | ||
|   }
 | ||
| 
 | ||
|   // 获取评判初始化数据
 | ||
|   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,
 | ||
|       zeng: 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,
 | ||
|       closeAllFiles
 | ||
|     } = 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, '考试结束')
 | ||
|       //关闭录像
 | ||
|         if (!globalThis.singlePlay) {
 | ||
|           await endRecordVideo(this.videoData)
 | ||
|         }
 | ||
|         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()
 | ||
|     }
 | ||
|   }
 | ||
| 
 | ||
|   // 考试扣分
 | ||
|   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 this.sendWriteObjectOut(data, filePath);
 | ||
|     if (code == 2300007) {
 | ||
|       this.isJudgeDisConnect = true
 | ||
|     }
 | ||
|     console.info(judgeTag, '项目扣分 end')
 | ||
|     promptWxCode('17C53', code)
 | ||
|   }
 | ||
| 
 | ||
|   // 评判语音提示
 | ||
|   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 {
 | ||
|       //收到综合评判语音时,显示综合评判弹窗
 | ||
|       if (code[0] == 'zhpp') {
 | ||
|         clearTimeout(this.deductedPopShowTimer)
 | ||
|         this.judgeUI.isDeductedPopShow = true
 | ||
|         this.judgeUI.defaultTabIndex = 1
 | ||
|         this.isEndTip = true
 | ||
|       }
 | ||
|       avPlayer.playAudio([`voice/${code[0]}.mp3`])
 | ||
|     }
 | ||
|   }
 | ||
| 
 | ||
|   // 处理考试结束
 | ||
|   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, closeAllFiles } = this;
 | ||
|     const { judgeConfigObj, examSubject, isAllProjectsEnd, totalScore, passingScore } = judgeUI;
 | ||
|     //计算考试分数
 | ||
|     // this.judgeUI.totalScore = isAllProjectsEnd ? totalScore : 0;
 | ||
|     const singlePlay = globalThis.singlePlay
 | ||
|     const param302 = judgeConfigObj['302'];
 | ||
| 
 | ||
|     //自动退出待验证并且不合格
 | ||
|     if (!isManual && examSubject == 3 && (param302 == 1 || (singlePlay && param302 == 2)) &&
 | ||
|       totalScore < passingScore) {
 | ||
|       avPlayer.playAudio([`voice/考试结束.mp3`])
 | ||
|     }
 | ||
|     //联网模式下:项目没有做完、当前分数大于及格分;手动结束直接退出
 | ||
|     if (!singlePlay && isManual && !isAllProjectsEnd && totalScore >= passingScore) {
 | ||
|       avPlayer.playAudio(['voice/empty.mp3'], true, () => {
 | ||
|         this.isUdpEnd = true;
 | ||
|         closeAllFiles()
 | ||
|         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)
 | ||
|         }
 | ||
|       } catch (e) {
 | ||
|         console.info(judgeTag, JSON.stringify(e))
 | ||
|       }
 | ||
|       await endExam()
 | ||
|     });
 | ||
| 
 | ||
|   }
 | ||
| 
 | ||
|   // 考试结束
 | ||
|   public endExam = async (isManual?: Boolean) => {
 | ||
|     const carInfo = globalThis.carInfo;
 | ||
|     const singlePlay = globalThis.singlePlay
 | ||
|     const { examSubject, plateNo } = carInfo;
 | ||
|     const {
 | ||
|       judgeUI,
 | ||
|       ksjs,
 | ||
|       getPhoto,
 | ||
|       avPlayer,
 | ||
|       kfArr,
 | ||
|       filePath,
 | ||
|       closeAllFiles
 | ||
|     } = this;
 | ||
|     const { lsh, idCard, serialNumber, kssycs, totalScore, judgeConfigObj, isAllProjectsEnd, passingScore } = judgeUI
 | ||
|     //TODO 断网考试结束补传
 | ||
|     // await uploadDisConnectData();
 | ||
|     try {
 | ||
|       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(';'),
 | ||
|         }
 | ||
|       }
 | ||
|       let backTimeOut = setTimeout(() => {
 | ||
|         router.back()
 | ||
|       }, 90 * 1000)
 | ||
|       const { code, keystr, message } = await this.sendWriteObjectOut(data, filePath);
 | ||
|       promptWxCode('17C56', code)
 | ||
| 
 | ||
|       if (code != 1) {
 | ||
|         avPlayer.playAudio(['voice/监管失败.mp3'])
 | ||
|         this.judgeUI.errorMsg = decodeURIComponent(message)
 | ||
| 
 | ||
|         if (code == 2300028 || code == 2300007) {
 | ||
|           this.judgeUI.errorMsg = '当前的考试过程信息监管审核未通过,程序将退出!'
 | ||
|         }
 | ||
|         this.isUdpEnd = true;
 | ||
|         closeAllFiles()
 | ||
|         this.judgeUI.loadingPopupVisible = false;
 | ||
|         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 uploadProgressData();
 | ||
|       }
 | ||
|       clearTimeout(backTimeOut)
 | ||
|       //语音播放扣分项
 | ||
|       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;
 | ||
|                     closeAllFiles()
 | ||
|                     router.back();
 | ||
|                   })
 | ||
|                   throw new Error('End Loop')
 | ||
|                 }
 | ||
|                 avPlayer.playAudio([`voice/${kf.markcatalog}.mp3`])
 | ||
|               } else {
 | ||
|                 avPlayer.playAudio([`voice/${kf.markcatalog}.mp3`, voiceURL], false, () => {
 | ||
|                   this.isUdpEnd = true;
 | ||
|                   closeAllFiles()
 | ||
|                   router.back();
 | ||
|                 })
 | ||
|                 throw new Error('End Loop')
 | ||
|               }
 | ||
|             })
 | ||
|           } catch (e) {
 | ||
|             console.info(judgeTag, JSON.stringify(e))
 | ||
|           }
 | ||
|         })
 | ||
|       } else {
 | ||
|         avPlayer.playAudio([voiceURL], true, () => {
 | ||
|           setTimeout(() => {
 | ||
|             this.isUdpEnd = true
 | ||
|             closeAllFiles()
 | ||
|             router.back();
 | ||
|           }, param302 == 8 ? 3000 : 0)
 | ||
|         })
 | ||
|       }
 | ||
| 
 | ||
|     } catch (e) {
 | ||
|       promptAction.showToast({
 | ||
|         message: "考试结束异常,请尝试重新结束",
 | ||
|         duration: 3000
 | ||
|       })
 | ||
|       judgeUI.loadingPopupVisible = false
 | ||
|     }
 | ||
| 
 | ||
|   }
 | ||
| 
 | ||
|   // 当前项目转换
 | ||
|   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
 | ||
|   }
 | ||
| 
 | ||
|   // 统计必考项目、所有项目、已考数量
 | ||
|   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)
 | ||
|   }
 | ||
| 
 | ||
|   // 检测差分状态
 | ||
|   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;
 | ||
|     }
 | ||
|   }
 | ||
| 
 | ||
|   closeAllFiles = () => {
 | ||
|     setTimeout(() => {
 | ||
|       this.fileLog.closeAllFiles()
 | ||
|     }, 1000)
 | ||
|   }
 | ||
| 
 | ||
|   //开始评判
 | ||
|   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)
 | ||
|     })
 | ||
|     this.checkExamIsEnd();
 | ||
| 
 | ||
|   }
 | ||
| } |