Compare commits
	
		
			2 Commits
		
	
	
		
			658fbed783
			...
			ee4d54e8d7
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | ee4d54e8d7 | ||
|  | d6a5c9fdba | 
| @ -71,3 +71,5 @@ export const StartExamTag = '[StartExam]' | ||||
| 
 | ||||
| //人脸对比 | ||||
| export const FaceCompareTag = '[FaceCompare]'; | ||||
| //过程数据处理 | ||||
| export const ProcessDataTag = '[ProcessData]'; | ||||
| @ -63,7 +63,7 @@ export enum ProcessDataEnumType { | ||||
|   JudgeExamData = "2", | ||||
|   //judge_log_data | ||||
|   JudgeLogData = "3", | ||||
|   //   judge_progress_callback_data | ||||
|   //judge_progress_callback_data | ||||
|   JudgeProgressCallbackData = "4", | ||||
|   //plc_data | ||||
|   PlcData = "5", | ||||
|  | ||||
| @ -189,7 +189,7 @@ struct Index { | ||||
|     dConsole.log("test1111") | ||||
|     await GetDeviceInfo(this.context) | ||||
|     this.carInfo = await GetCarInfo() | ||||
|     this.carInfo = AppStorage.get<CarInfoType>('carInfo')! | ||||
|     AppStorage.setOrCreate<CarInfoType>("carInfo", this.carInfo) | ||||
|     this.deviceId = this.carInfo.carNo || "" | ||||
|     await SetCurrentTime() | ||||
|     this.timeInfo = AppStorage.get<TimeSynchronizationRspBody>('timeInfo')! | ||||
|  | ||||
| @ -48,7 +48,7 @@ export async function GetCarInfo(): Promise<CarInfoType> { | ||||
|     deviceNo: AppStorage.get<string>('deviceNo') || "" | ||||
|   }; | ||||
|   let res: ApiResponseType = await obtainCarExamInfo(params) | ||||
|   dConsole.log("获取到的车辆信息", res) | ||||
|   dConsole.log("90", res) | ||||
|   if (res.obtainCarExamInfoRsp && res.obtainCarExamInfoRsp.body) { | ||||
|     const carInfo: ObtainCarExamInfoRspBody = res?.obtainCarExamInfoRsp?.body! | ||||
|     carInfo.plateNo = decodeURIComponent(carInfo.plateNo) | ||||
|  | ||||
| @ -396,7 +396,6 @@ struct JudgePage { | ||||
|         Reflect.set(this.projectsObj, 1, project_1) | ||||
|       } | ||||
|       Reflect.set(this.judgeConfigObj, sys.v_no!, value) | ||||
|       dConsole.log("寻找", this.judgeConfigObj) | ||||
|     }); | ||||
|     this.judgeConfig = syssetJudgeConfigArr; | ||||
|   } | ||||
|  | ||||
| @ -1,7 +1,9 @@ | ||||
| import { | ||||
|   JudgeConfigObjKmItems, | ||||
|   JudgeKSJS, | ||||
|   JudgePerformInfo, | ||||
|   JudgeUI, | ||||
|   LANE, | ||||
|   MarkRule, | ||||
|   PLCType, | ||||
|   ProcessDataEnumType, | ||||
| @ -22,6 +24,10 @@ import { PlcStrToJson, PlcStrToWXJson } from './utils' | ||||
| import { JudgeEndFn } from './JudgeEnd' | ||||
| 
 | ||||
| export default class JudgeBusiness { | ||||
|   public mndgStr: string | undefined | ||||
|   public lane: LANE = { | ||||
|     road: '', num: 0, count: 0 | ||||
|   } | ||||
|   public fileUtil: FileUtils | ||||
|   public avPlayer?: VoiceAnnounce | ||||
|   public performInfo?: JudgePerformInfo | ||||
| @ -31,7 +37,7 @@ export default class JudgeBusiness { | ||||
|   public isEndTip: boolean = false; | ||||
|   //是否手动结束考试 | ||||
|   public isManual: boolean = false | ||||
|   public deductedPopShowTimer: number = 0; | ||||
|   public deductedPopShowTimer: number = -1; | ||||
|   public videoData?: RecordHandleType | ||||
|   //是否是考试模式 | ||||
|   public isExam: boolean | ||||
| @ -48,12 +54,12 @@ export default class JudgeBusiness { | ||||
|   public xmxh: string = "" | ||||
|   public kfArr?: MarkRule[] | ||||
|   public carztStr: string | ||||
|   public ksjs?: JudgeKSJS | ||||
|   public plcData?: PLCType | ||||
|   private judgeUI: JudgeUI | ||||
|   private tempData?: PLCType | ||||
|   private plcData?: PLCType | ||||
|   // 是否发送udp | ||||
|   private isUdpEnd: boolean = false | ||||
|   private mndgStr: string | undefined | ||||
| 
 | ||||
|   constructor(judgeUI: JudgeUI) { | ||||
|     this.judgeUI = judgeUI | ||||
|  | ||||
| @ -1,9 +1,20 @@ | ||||
| import { JudgeTag } from '../../config'; | ||||
| import { JudgeCallBackData, JudgeUI, KmItem, MarkRule, ProcessDataEnumType, ProjectInfo } from '../../model'; | ||||
| import { | ||||
|   JudgeCallBackData, | ||||
|   JudgeConfigObj, | ||||
|   JudgeSound, | ||||
|   JudgeUI, | ||||
|   KmItem, | ||||
|   MarkRule, | ||||
|   ProcessDataEnumType, | ||||
|   ProjectInfo | ||||
| } from '../../model'; | ||||
| import { dConsole } from '../../utils/LogWorker'; | ||||
| import VoiceAnnounce from '../judgeSDK/utils/voiceAnnouncements'; | ||||
| import JudgeBusiness from './JudgeBusiness'; | ||||
| import { examJudgeArtificialItem } from './JudgeSDKUtils'; | ||||
| import { CurrentProjectConversion, DeductionProjectConversion } from './utils'; | ||||
| import { examJudgeArtificialItem, examJudgeSoundEnd } from './JudgeSDKUtils'; | ||||
| import { ProjectStart, UploadProgressPhoto } from './ProcessDataProcessing'; | ||||
| import { CurrentProjectConversion, DeductionProjectConversion, DetectingDifferences, GetCarStatus } from './utils'; | ||||
| 
 | ||||
| export const JudgingFn = async (strData: string, callBack: Function, judgeUI: JudgeUI, that: JudgeBusiness) => { | ||||
|   let examData: JudgeCallBackData = JSON.parse(strData); | ||||
| @ -26,13 +37,10 @@ export const JudgingFn = async (strData: string, callBack: Function, judgeUI: Ju | ||||
|   const isManualProjectIn = artSubject3ProjectsCodesArr.includes(xmdm); | ||||
|   const examSubject = judgeUI.examSubject | ||||
|   const judgeConfigObj = judgeUI.judgeConfigObj | ||||
|   let project: ProjectInfo = Reflect.get(judgeUI.projectsObj, xmdm) | ||||
|   const xmmcCode = project.projectCodeCenter || ""; | ||||
|   const kmItem: KmItem = Reflect.get(that.kmItems, xmmcCode) | ||||
| 
 | ||||
|   switch (event) { | ||||
|   //   项目开始 | ||||
|     case 1: | ||||
|     case 1: { | ||||
|       const project: ProjectInfo = Reflect.get(judgeUI.projectsObj, xmdm) | ||||
|       project.type = '2'; | ||||
|       if (isManualProjectIn) { | ||||
|         //手动项目是否在进行中 | ||||
| @ -44,6 +52,8 @@ export const JudgingFn = async (strData: string, callBack: Function, judgeUI: Ju | ||||
|       judgeUI.currentXmdm = xmdm; | ||||
|       const xmmcStr = project.name || ""; | ||||
|       const xmmcSingleCode = project.projectCode || ""; | ||||
|       const xmmcCode = project.projectCodeCenter || ""; | ||||
|       const kmItem: KmItem = Reflect.get(that.kmItems, xmmcCode) | ||||
|       kmItem.status = 2; | ||||
|       that.xmmcStr = xmmcStr; | ||||
|       that.xmmcCode = xmmcCode; | ||||
| @ -55,8 +65,11 @@ export const JudgingFn = async (strData: string, callBack: Function, judgeUI: Ju | ||||
|       Reflect.set(judgeUI.projectsObj, xmdm, project) | ||||
|       Reflect.set(that.kmItems, xmmcCode || 0, kmItem) | ||||
|       break; | ||||
|     } | ||||
|   //   项目结束 | ||||
|     case 2: | ||||
|     case 2: { | ||||
|       const project: ProjectInfo = Reflect.get(judgeUI.projectsObj, xmdm) | ||||
|       const xmmcCode = project.projectCodeCenter || ""; | ||||
|       project.type = (xmjs.xmhg === 0 ? '4' : '3') | ||||
|       //计算项目是否全部结束 | ||||
|       judgeUI.isProjectIn = (Reflect.ownKeys(judgeUI.projectsObj).filter((projectKey) => { | ||||
| @ -66,6 +79,7 @@ export const JudgingFn = async (strData: string, callBack: Function, judgeUI: Ju | ||||
|       if (isManualProjectIn) { | ||||
|         judgeUI.isManualProjectIn = false | ||||
|       } | ||||
|       const kmItem: KmItem = Reflect.get(that.kmItems, xmmcCode) | ||||
|       kmItem.status = 3; | ||||
|       //统计必考项目数量 | ||||
|       that.xmmcStr = '无'; | ||||
| @ -75,8 +89,9 @@ export const JudgingFn = async (strData: string, callBack: Function, judgeUI: Ju | ||||
|       Reflect.set(judgeUI.projectsObj, xmdm, project) | ||||
|       Reflect.set(that.kmItems, xmmcCode, kmItem) | ||||
|       break; | ||||
|     } | ||||
|   //   扣分 | ||||
|     case 3: | ||||
|     case 3: { | ||||
|       const thisKf = DeductionProjectConversion(`${kf.xmdm}_${kf.kfdm}`, judgeUI.markRuleListObj) | ||||
|       const kfObj: MarkRule = { | ||||
|         //扣分项目名称 | ||||
| @ -104,32 +119,77 @@ export const JudgingFn = async (strData: string, callBack: Function, judgeUI: Ju | ||||
|         Reflect.set(judgeUI.projectsObj, kf.xmdm, project) | ||||
|       } | ||||
|       break; | ||||
|     } | ||||
|   // 考试状态 | ||||
|     case 4: | ||||
|     case 4: { | ||||
|       that.carztStr = GetCarStatus(carzt); | ||||
|       break; | ||||
|     } | ||||
|   //   考试结束 | ||||
|     case 5: | ||||
|     case 5: { | ||||
|       that.ksjs = ksjs; | ||||
|       // await fileLog?.setExamJudgeData(JSON.stringify({ | ||||
|       //   method: 'examJudgeEndExam' | ||||
|       // })) | ||||
|       dConsole.writeProcessData(ProcessDataEnumType.JudgeExamData, JSON.stringify({ | ||||
|         method: 'examJudgeEndExam' | ||||
|       })) | ||||
|       break; | ||||
|     } | ||||
|   //   项目取消 | ||||
|     case 6: | ||||
|     case 6: { | ||||
|       dConsole.info(JudgeTag, '项目取消'); | ||||
|       const xmdm = xmqx.xmdm; | ||||
|       const project: ProjectInfo = Reflect.get(judgeUI.projectsObj, xmdm) | ||||
|       const xmmcCode = project.projectCodeCenter || ""; | ||||
|       project.type = '1' | ||||
|       const kmItem: KmItem = Reflect.get(that.kmItems, xmmcCode) | ||||
|       Reflect.set(judgeUI.projectsObj, xmdm, project) | ||||
|       kmItem.status = 1 | ||||
|       Reflect.set(that.kmItems, xmmcCode, kmItem) | ||||
|       break; | ||||
|     } | ||||
|   //   语音播报和提示 | ||||
|     case 7: | ||||
|     case 7: { | ||||
|       goJudgeVoice(sound, that.avPlayer) | ||||
|       break; | ||||
|     } | ||||
|   //   模拟灯光事件 | ||||
|     case 8: | ||||
|     case 8: { | ||||
|       that.mndgStr = mndg | ||||
|       break; | ||||
|     } | ||||
|   //   车道和路段变化 | ||||
|     case 9: | ||||
|     case 9: { | ||||
|       judgeUI.lane = lane | ||||
|       that.lane = lane; | ||||
|       break; | ||||
|     } | ||||
|   //   预进项目事件 | ||||
|     case 10: | ||||
|       break; | ||||
|     case 10: { | ||||
|       const xmdm = precast.xmdm | ||||
|       const xmxh = precast.xmxh | ||||
|       const project: ProjectInfo = Reflect.get(judgeUI.projectsObj, xmdm) | ||||
|       const xmmcCode: string = judgeUI.projectsObj[xmdm].projectCodeCenter; | ||||
|       const xmmcSingleCode: string = judgeUI.projectsObj[xmdm].projectCode; | ||||
|       const kmItem: KmItem = Reflect.get(that.kmItems, xmmcCode) | ||||
|       const xmmcStr = project?.name || ""; | ||||
|       kmItem.status = 2; | ||||
|       Reflect.set(that.kmItems, xmmcCode, project) | ||||
|       that.xmmcStr = xmmcStr || ""; | ||||
|       that.xmmcCode = xmmcCode || ""; | ||||
|       that.xmdm = xmdm; | ||||
|       that.xmxh = xmxh; | ||||
|       that.xmmcSingleCode = xmmcSingleCode || ""; | ||||
|       project.type = '2'; | ||||
|       Reflect.set(judgeUI.projectsObj, xmdm, project) | ||||
|     } | ||||
|   //   差分事件 | ||||
|     case 11: | ||||
|     case 11: { | ||||
|       DetectingDifferences(nongps.type, that.avPlayer) | ||||
|       break; | ||||
|     } | ||||
|     default: | ||||
|       83 | ||||
|       break; | ||||
|   } | ||||
|   await callBack({ | ||||
| @ -139,7 +199,25 @@ export const JudgingFn = async (strData: string, callBack: Function, judgeUI: Ju | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| // | ||||
| const goJudgeVoice = async (sound: JudgeSound, avPlayer: VoiceAnnounce) => { | ||||
|   dConsole.info('surenjun code=>', JSON.stringify(sound.code)) | ||||
|   //判断是不是模拟灯光语音 | ||||
|   if (sound.type == 1) { | ||||
|     avPlayer?.playAudio([`voice/${sound.code[0]}.mp3`], false, () => { | ||||
|       examJudgeSoundEnd({ | ||||
|         xmdm: sound.xmdm, code: sound.code[0], type: sound.type | ||||
|       }) | ||||
|       dConsole.writeProcessData(ProcessDataEnumType.JudgeExamData, JSON.stringify({ | ||||
|         method: 'examJudgeSoundEnd', | ||||
|         itemno: sound.xmdm, | ||||
|         code: sound.code[0], | ||||
|         type: sound.type, | ||||
|       })) | ||||
|     }) | ||||
|   } else { | ||||
|     avPlayer?.playAudio([`voice/${sound.code[0]}.mp3`]) | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| export const SetJudgeItem = async (itemno: string, type: 1 | 2) => { | ||||
| @ -152,3 +230,47 @@ export const SetJudgeItem = async (itemno: string, type: 1 | 2) => { | ||||
|   dConsole.writeProcessData(ProcessDataEnumType.JudgeExamData, str) | ||||
|   dConsole.info(JudgeTag, `人工评判${type == 1 ? '进入' : '取消'}项目-${itemno}`) | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * 改变考试状态 | ||||
|  * old goVoiceAnnounce | ||||
|  * @param event | ||||
|  * @param xmdm | ||||
|  * @param kf | ||||
|  * @param judgeUI | ||||
|  * @param that | ||||
|  */ | ||||
| const changeExamStatus = async (event: number, xmdm: number, kf: MarkRule[], judgeUI: JudgeUI, that: JudgeBusiness) => { | ||||
|   switch (event) { | ||||
|     case 1: { | ||||
|       const param512: JudgeConfigObj = (Reflect.get(judgeUI.judgeConfigObj, '512') || '').split(','); | ||||
|       const project: ProjectInfo = Reflect.get(judgeUI.projectsObj, xmdm) | ||||
|       setTimeout(() => { | ||||
|         if (Reflect.get(param512, 7) != 0) { | ||||
|           clearTimeout(that.deductedPopShowTimer) | ||||
|           judgeUI.isDeductedPopShow = true | ||||
|         } | ||||
|       }, 200) | ||||
|       if (!project.isEnd) { | ||||
|         // that.judgeTask.addTask(async () => { | ||||
|         //   dConsole.info(JudgeTag, `项目开始-${xmdm}-${project.name}`) | ||||
|         //   await beginProject(xmdm) | ||||
|         // }, { | ||||
|         //   isDelay: true | ||||
|         // }) | ||||
|         ProjectStart(xmdm, that.xmxh, judgeUI) | ||||
|         // that.judgeTask.addTask(async () => { | ||||
|         //   dConsole.info(JudgeTag, `项目-${xmdm}-上传照片 start`) | ||||
|         //   await uploadProgressPhoto(xmdm) | ||||
|         // }, { | ||||
|         //   isDelay: true | ||||
|         // }) | ||||
|         UploadProgressPhoto(xmdm, that.plcData, judgeUI) | ||||
|       } | ||||
|       break; | ||||
|     } | ||||
|     case 2: { | ||||
|       break; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| @ -1,28 +0,0 @@ | ||||
| import { testKm2Items, testKm3Items } from '../../mock'; | ||||
| import { JudgeConfigObjKmItems, ProjectInfo, ProjectInfos } from '../../model'; | ||||
| 
 | ||||
| class judgeVariable { | ||||
|   public rmndg: 0 | 1 = 0 | ||||
|   public kmItems: JudgeConfigObjKmItems = {} | ||||
|   public xmmcStr: string = "" | ||||
|   public xmmcEndCode?: string = "" | ||||
|   public xmxh: string = "" | ||||
|   public status: string = "开始" | ||||
| 
 | ||||
|   constructor() { | ||||
| 
 | ||||
|   } | ||||
| 
 | ||||
|   public initKmItems(examSubject: string, projectsCenterObj: ProjectInfos) { | ||||
|     (examSubject == '2' ? testKm2Items : testKm3Items).forEach(item => { | ||||
|       const projectCenterObj: ProjectInfo = Reflect.get(projectsCenterObj, item.code) | ||||
|       Reflect.set(this.kmItems, item.code, { | ||||
|         code: item.code, | ||||
|         status: projectCenterObj === undefined ? 0 : (projectCenterObj.isEnd ? 3 : 1) | ||||
|       }) | ||||
|     }) | ||||
| 
 | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| export const JudgeVariable = new judgeVariable(); | ||||
							
								
								
									
										187
									
								
								entry/src/main/ets/pages/Judge/ProcessDataProcessing.ets
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										187
									
								
								entry/src/main/ets/pages/Judge/ProcessDataProcessing.ets
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,187 @@ | ||||
| /** | ||||
|  * 过程数据处理 | ||||
|  */ | ||||
| import { ProcessDataTag } from '../../config'; | ||||
| import { | ||||
|   CarInfoType, | ||||
|   CDSBInfo, | ||||
|   CDSBInfos, | ||||
|   DrvexamType, | ||||
|   JudgeUI, | ||||
|   MarkRule, | ||||
|   PLCType, | ||||
|   ProjectInfo, | ||||
|   RegulatoryInterfaceParams | ||||
| } from '../../model'; | ||||
| import { GetPhotoBase64 } from '../../utils/Common'; | ||||
| import dayTs from '../../utils/Date'; | ||||
| import { dConsole } from '../../utils/LogWorker'; | ||||
| import { ProcessDataTaskPoolInstance } from './ProcessDataTaskPool'; | ||||
| 
 | ||||
| /** | ||||
|  * beginProject 项目开始 | ||||
|  */ | ||||
| export const ProjectStart = (ksxm: number, xmxh: string, judgeUI: JudgeUI) => { | ||||
|   const carInfo = AppStorage.get<CarInfoType>('carInfo'); | ||||
|   const project: ProjectInfo = Reflect.get(judgeUI.projectsObj, ksxm) | ||||
|   const sbxh = getSBXH(ksxm, xmxh, judgeUI.cdsbInfoObj, judgeUI.projectsObj, carInfo.examSubject); | ||||
|   const drvexam: DrvexamType = { | ||||
|     lsh: judgeUI.lsh, | ||||
|     kskm: carInfo?.examSubject || "2", | ||||
|     sfzmhm: judgeUI.idCard, | ||||
|     ksxm: project.projectCodeCenter, | ||||
|     sbxh, | ||||
|     ksxl: judgeUI.xldm, | ||||
|     kchp: encodeURI(carInfo?.plateNo || ""), | ||||
|     ksdd: encodeURI(judgeUI.ksdd), | ||||
|     kslx: encodeURI(judgeUI.kslx) || '', | ||||
|     kssj: dayTs().format("YYYY-MM-DD HH:mm:ss") | ||||
|   } | ||||
|   const data: RegulatoryInterfaceParams = { | ||||
|     //系统类别   接口序列号             接口标识 | ||||
|     xtlb: '17', | ||||
|     jkxlh: judgeUI.serialNumber, | ||||
|     jkid: '17C52', | ||||
|     drvexam | ||||
|   } | ||||
|   dConsole.log(ProcessDataTag, "项目开始数据处理", data) | ||||
|   ProcessDataTaskPoolInstance.addTask(data) | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * uploadProgressPhoto 上传过程照片 | ||||
|  */ | ||||
| export const UploadProgressPhoto = async (ksxm: number, plcData: PLCType, judgeUI: JudgeUI) => { | ||||
|   const photoBase64 = await GetPhotoBase64(judgeUI.context); | ||||
|   const carInfo = AppStorage.get<CarInfoType>('carInfo'); | ||||
|   const project: ProjectInfo = Reflect.get(judgeUI.projectsObj, ksxm) | ||||
|   const judgeConfig_305: number = Reflect.get(judgeUI.judgeConfigObj, '305') | ||||
|   const drvexam: DrvexamType = { | ||||
|     lsh: judgeUI.lsh, | ||||
|     kskm: carInfo?.examSubject || "2", | ||||
|     ksxm: project.projectCodeCenter, | ||||
|     sfzmhm: judgeUI.idCard, | ||||
|     kchp: encodeURI(carInfo?.plateNo || ""), | ||||
|     zpsj: dayTs().format("YYYY-MM-DD HH:mm:ss"), | ||||
|     zp: photoBase64, | ||||
|     cs: Math.floor((judgeConfig_305 == 0 ? (plcData?.gps?.sd || 0) : (plcData?.sensor?.cs || 0)) * 1.852), | ||||
|     ksdd: encodeURI(judgeUI.ksdd) | ||||
|   } | ||||
|   const data: RegulatoryInterfaceParams = { | ||||
|     xtlb: '17', | ||||
|     jkxlh: judgeUI.serialNumber, | ||||
|     jkid: '17C54', | ||||
|     drvexam | ||||
|   }; | ||||
|   dConsole.log(ProcessDataTag, "上传过程照片数据处理", data); | ||||
|   ProcessDataTaskPoolInstance.addTask(data) | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * pointsDedute 扣分补传 | ||||
|  */ | ||||
| export const DeductPoints = (ksxm: number, kf: MarkRule, xmmcEndCode: string, judgeUI: JudgeUI) => { | ||||
|   const carInfo = AppStorage.get<CarInfoType>('carInfo')!; | ||||
|   const examSubject = carInfo.examSubject | ||||
|   const lsh = judgeUI.lsh | ||||
|   const idCard = judgeUI.idCard | ||||
|   const serialNumber = judgeUI.serialNumber | ||||
|   const ksdd = judgeUI.ksdd | ||||
|   const projectsObj: object = judgeUI.projectsObj | ||||
|   const project: ProjectInfo = Reflect.get(judgeUI.projectsObj, ksxm) | ||||
|   //科目三夜间行驶.模拟灯光、上车准备出现通用评判,ksxm为当前进行的项目 | ||||
|   const checkProjects = ['17', '41', '1']; | ||||
|   //获取正在进行的项目 | ||||
|   const inProjects = Reflect.ownKeys(projectsObj).filter(projectKey => { | ||||
|     const project: ProjectInfo = Reflect.get(projectsObj, projectKey) | ||||
|     return project.type == '2' | ||||
|   }); | ||||
|   let commonKsxm = ''; | ||||
|   checkProjects.forEach(projectCode => { | ||||
|     if (inProjects.includes(projectCode)) { | ||||
|       commonKsxm = projectCode | ||||
|     } | ||||
|   }) | ||||
|   let ksxmD: string; | ||||
|   if (!project) { | ||||
|     if (commonKsxm) { | ||||
|       ksxmD = Reflect.get(projectsObj, commonKsxm).projectCodeCenter; | ||||
|     } else { | ||||
|       if (examSubject == '3') { | ||||
|         ksxmD = '30000'; | ||||
|       } else { | ||||
|         ksxmD = (xmmcEndCode == undefined ? '10000' : xmmcEndCode); | ||||
|       } | ||||
|     } | ||||
|   } else { | ||||
|     ksxmD = project?.projectCodeCenter || ""; | ||||
|   } | ||||
|   const drvexam: DrvexamType = { | ||||
|     lsh, | ||||
|     kskm: examSubject, | ||||
|     ksxm: ksxmD, | ||||
|     kfxm: kf.markcatalog, | ||||
|     kfxmmx: `${ksxm},${kf.markserial}`, | ||||
|     sfzmhm: idCard, | ||||
|     kchp: encodeURI(carInfo?.plateNo || ""), | ||||
|     //扣分方式 | ||||
|     kffs: kf.type == 0 ? 1 : 2, | ||||
|     ksdd: encodeURI(ksdd), | ||||
|     kfsj: dayTs().format("YYYY-MM-DD HH:mm:ss"), | ||||
|   } | ||||
|   const data: RegulatoryInterfaceParams = { | ||||
|     xtlb: '17', | ||||
|     jkxlh: serialNumber, | ||||
|     jkid: '17C53', | ||||
|     drvexam | ||||
|   } | ||||
|   dConsole.log(ProcessDataTag, "扣分上传数据", data) | ||||
|   ProcessDataTaskPoolInstance.addTask(data) | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * endProject 结束项目 | ||||
|  */ | ||||
| export const ProjectEnd = (ksxm: number, xmxh: string, judgeUI: JudgeUI) => { | ||||
|   const carInfo = AppStorage.get<CarInfoType>('carInfo'); | ||||
|   const project: ProjectInfo = Reflect.get(judgeUI.projectsObj, ksxm) | ||||
|   const sbxh = carInfo.examSubject == '3' ? undefined : getSBXH(ksxm, xmxh, judgeUI.cdsbInfoObj, judgeUI.projectsObj, carInfo.examSubject); | ||||
|   const drvexam: DrvexamType = { | ||||
|     lsh: judgeUI.lsh, | ||||
|     kskm: carInfo?.examSubject || "2", | ||||
|     sfzmhm: judgeUI.idCard, | ||||
|     ksxm: project.projectCodeCenter, | ||||
|     sbxh, | ||||
|     //TODO 操作类型 1:正常 0:撤销该考试记录 | ||||
|     czlx: '1', | ||||
|     ksxl: judgeUI.xldm, | ||||
|     kchp: encodeURI(carInfo?.plateNo || ""), | ||||
|     ksdd: encodeURI(judgeUI.ksdd), | ||||
|     kslx: encodeURI(judgeUI.kslx) || '', | ||||
|     jssj: dayTs().format("YYYY-MM-DD HH:mm:ss") | ||||
|   } | ||||
|   const data: RegulatoryInterfaceParams = { | ||||
|     xtlb: '17', | ||||
|     jkxlh: judgeUI.serialNumber, | ||||
|     jkid: '17C55', | ||||
|     drvexam | ||||
|   } | ||||
|   dConsole.log(ProcessDataTag, "结束项目数据", data) | ||||
|   ProcessDataTaskPoolInstance.addTask(data) | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| const getSBXH = (ksxm: number, xmxh: string, cdsbInfoObj: CDSBInfos, projectsObj: object, examSubject: string): string => { | ||||
|   const project: ProjectInfo = Reflect.get(projectsObj, ksxm); | ||||
|   //科目三不需要 | ||||
|   if (examSubject == '3') { | ||||
|     return "" | ||||
|   } | ||||
|   if (project === undefined) { | ||||
|     return '00000000' | ||||
|   } | ||||
|   const projectKey = `${ksxm}_${xmxh}`; | ||||
|   const currentCdsb: CDSBInfo = Reflect.get(cdsbInfoObj!, projectKey) || {} | ||||
|   const sbxh: string = currentCdsb.sbbm || '00000000' | ||||
|   return sbxh | ||||
| } | ||||
| @ -5,10 +5,14 @@ import http from '@ohos.net.http'; | ||||
| import Request from '../../utils/Request'; | ||||
| 
 | ||||
| export class ProcessDataTaskPool { | ||||
|   private queue: RegulatoryInterfaceParams[] = [] | ||||
|   private queue: RegulatoryInterfaceParams[] = []; | ||||
|   private isProcessing: boolean = false; | ||||
|   /** 最大重试次数。1次初次尝试 + 5次重试 = 总共6次尝试。 */ | ||||
|   private readonly maxRetries = 5; | ||||
|   /** 最小处理时间(毫秒) */ | ||||
|   private readonly minProcessingTime = 2000; | ||||
|   /** 记录每个任务的开始处理时间 */ | ||||
|   private taskStartTime: number = 0; | ||||
| 
 | ||||
|   public addTask(dataItem: RegulatoryInterfaceParams): void { | ||||
|     console.info(`[Queue] 新任务已添加: ${JSON.stringify(dataItem)},当前队列长度: ${this.queue.length + 1}`); | ||||
| @ -23,11 +27,10 @@ export class ProcessDataTaskPool { | ||||
|   private triggerProcessing(): void { | ||||
|     if (this.isProcessing) { | ||||
|       console.log('[Queue] 处理器正在运行中,新任务将在稍后被处理。'); | ||||
|       return; // 如果已经在处理,则直接返回,新任务会被正在运行的循环消费掉 | ||||
|       return; | ||||
|     } | ||||
|     // 使用 Promise.resolve().then() 来确保 processQueue 在下一个事件循环中异步执行 | ||||
|     // 这可以防止阻塞当前的 addTask 调用 | ||||
|     Promise.resolve().then(() => this.processQueue()); | ||||
|     // [优化] 直接调用 async 函数,它会立即返回一个 Promise,不会阻塞当前执行流,效果与 Promise.resolve().then() 相同但更简洁。 | ||||
|     this.processQueue(); | ||||
|   } | ||||
| 
 | ||||
|   private async processQueue(): Promise<void> { | ||||
| @ -36,33 +39,52 @@ export class ProcessDataTaskPool { | ||||
| 
 | ||||
|     while (this.queue.length > 0) { | ||||
|       const taskData = this.queue[0]; // 查看队首任务 | ||||
|       this.taskStartTime = Date.now(); // 记录任务开始时间 | ||||
| 
 | ||||
|       try { | ||||
|         console.log(`[Queue] 开始处理任务: ${JSON.stringify(taskData)}`); | ||||
|         // 此方法若成功则正常返回,若永久失败则会抛出错误 | ||||
|         let obj: WuxiExamType = { | ||||
| 
 | ||||
|         // 预先记录将要处理的数据 | ||||
|         const obj: WuxiExamType = { | ||||
|           xtlb: taskData.xtlb, | ||||
|           jkxlh: taskData.jkxlh, | ||||
|           jkid: taskData.jkid, | ||||
|           drvexam: { | ||||
|             zp: "", | ||||
|           }, | ||||
|         } | ||||
|         dConsole.writeProcessData(ProcessDataEnumType.WuxiExam, JSON.stringify(obj)) | ||||
|         }; | ||||
|         dConsole.writeProcessData(ProcessDataEnumType.WuxiExam, JSON.stringify(obj)); | ||||
| 
 | ||||
|         // 此方法若成功则正常返回,若永久失败则会抛出错误 | ||||
|         await this.processSingleTaskWithRetries(taskData); | ||||
| 
 | ||||
|         // 任务成功,将其从队列中移除 | ||||
|         this.queue.shift(); | ||||
|         console.log(`[Queue] ✅ 任务处理成功,已从队列移除。剩余任务: ${this.queue.length}`); | ||||
| 
 | ||||
|         // 计算任务实际耗时 | ||||
|         const elapsedTime = Date.now() - this.taskStartTime; | ||||
|         // 如果处理时间小于最小要求时间,则延迟剩余时间 | ||||
|         if (elapsedTime < this.minProcessingTime) { | ||||
|           const delayTime = this.minProcessingTime - elapsedTime; | ||||
|           console.log(`[Queue] 任务处理耗时 ${elapsedTime}ms,需要延迟 ${delayTime}ms 以满足最小处理时间要求`); | ||||
|           await this.delay(delayTime); | ||||
|         } | ||||
|       } catch (error) { | ||||
|         // 捕获到永久失败的错误 | ||||
|         console.error(`[Queue] 🔥 致命错误: ${(error as Error).message}`); | ||||
|         console.error('[Queue] 队列已停止,后续任务将不会被处理。'); | ||||
|         // **[健壮性改进]** 捕获到永久失败的错误。 | ||||
|         // 原有逻辑会清空整个队列,导致后续任务丢失。 | ||||
|         // 优化后的逻辑是:仅移除当前失败的任务,并记录错误,然后继续处理队列中的下一个任务。 | ||||
|         console.error(`[Queue] 🔥 任务永久失败: ${(error as Error).message}`); | ||||
|         const failedTask = this.queue.shift(); // 移除失败的任务 | ||||
|         console.error(`[Queue] 失败的任务已被移除: ${JSON.stringify(failedTask)},将继续处理下一个任务。`); | ||||
| 
 | ||||
|         // (可选)可以在此处清空队列,防止下次意外启动时处理旧任务 | ||||
|         this.queue = []; | ||||
| 
 | ||||
|         // 终止循环 | ||||
|         break; | ||||
|         // 即使任务失败,也需要满足最小处理时间要求 | ||||
|         const elapsedTime = Date.now() - this.taskStartTime; | ||||
|         if (elapsedTime < this.minProcessingTime) { | ||||
|           const delayTime = this.minProcessingTime - elapsedTime; | ||||
|           console.log(`[Queue] 失败任务处理耗时 ${elapsedTime}ms,需要延迟 ${delayTime}ms 以满足最小处理时间要求`); | ||||
|           await this.delay(delayTime); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
| @ -70,27 +92,40 @@ export class ProcessDataTaskPool { | ||||
|     console.log('[Queue] 处理器已停止。'); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 延迟指定时间 | ||||
|    * @param ms 延迟的毫秒数 | ||||
|    */ | ||||
|   private delay(ms: number): Promise<void> { | ||||
|     return new Promise(resolve => setTimeout(resolve, ms)); | ||||
|   } | ||||
| 
 | ||||
|   private async processSingleTaskWithRetries(taskData: RegulatoryInterfaceParams): Promise<void> { | ||||
|     // 1 次初次尝试 + 5 次重试 | ||||
|     for (let attempt = 0; attempt <= this.maxRetries; attempt++) { | ||||
|       const attemptNum = attempt + 1; | ||||
|       try { | ||||
|         const attemptType = attempt === 0 ? '初次尝试' : `重试 ${attempt}`; | ||||
|         console.log(`[Queue] 开始上传 (${attemptType}, 总共第 ${attemptNum} 次): ${JSON.stringify(taskData)}`); | ||||
|         console.log(`[Queue] 开始上传 (${attemptType}, 总共第 ${attemptNum} 次)`); | ||||
| 
 | ||||
|         // **注意**: 这里传递的是 taskData 的引用,为了防止 worker 中意外修改原始数据, | ||||
|         // 最佳实践是在 worker 内部或传递前进行深拷贝。 | ||||
|         // 但根据我们下面的修复,worker 不再修改原始数据,所以这里是安全的。 | ||||
|         const result: WR = await taskpool.execute(uploadWorkerTask, taskData); | ||||
|         dConsole.writeProcessData(ProcessDataEnumType.WuxiExam, JSON.stringify(result)) | ||||
| 
 | ||||
|         dConsole.writeProcessData(ProcessDataEnumType.WuxiExam, JSON.stringify(result)); | ||||
|         if (result.code === 1) { | ||||
|           console.log(`[Queue] ✔️ 上传成功 (在第 ${attemptNum} 次尝试)`); | ||||
|           return; // 成功,立即返回 | ||||
|         } | ||||
|         console.warn(`[Queue] ❌ 上传失败 (第 ${attemptNum} 次)。响应: ${result.message}`); | ||||
|       } catch (e) { | ||||
|         console.error(`[Queue] ❌ TaskPool 执行错误 (第 ${attemptNum} 次): ${e}`); | ||||
|         // **[健壮性改进]** 现在可以捕获从 Worker 抛出的更详细的异常信息 | ||||
|         console.error(`[Queue] ❌ TaskPool 执行或网络错误 (第 ${attemptNum} 次): ${e}`); | ||||
|       } | ||||
| 
 | ||||
|       // 如果这是最后一次尝试且依然失败,则不再等待,直接跳出循环去抛出错误 | ||||
|       if (attempt === this.maxRetries) { | ||||
|         break; | ||||
|         break; // 最后一次尝试失败后,跳出循环去抛出错误 | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
| @ -99,26 +134,28 @@ export class ProcessDataTaskPool { | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| export const ProcessDataTaskPoolInstance = new ProcessDataTaskPool(); | ||||
| 
 | ||||
| /** | ||||
|  * 这是将在 Worker 线程中执行的任务函数。 | ||||
|  * 它负责执行单次的上传尝试。 | ||||
|  * | ||||
|  * @param data 需要上传的单条数据项 | ||||
|  * @returns 一个包含本次上传尝试结果的对象 | ||||
|  */ | ||||
| export async function uploadWorkerTask(data: RegulatoryInterfaceParams): Promise<WR> { | ||||
|   let singlePlay: boolean = false | ||||
|   let isJGNew = false | ||||
|   // 这两个变量似乎未在逻辑中使用,暂时保持原样 | ||||
|   let singlePlay: boolean = false; | ||||
|   let isJGNew = false; | ||||
|   try { | ||||
|     const response = await sendProcessData(data, singlePlay, isJGNew); | ||||
|     // 根据返回的 code 判断是否成功 | ||||
|     return response | ||||
|     return response; | ||||
|   } catch (err) { | ||||
|     // 捕获请求过程中可能出现的异常 | ||||
|     // [健壮性改进] 捕获请求过程中的异常,并重新抛出。 | ||||
|     // 这能让主线程的 taskpool.execute() promise 变为 rejected 状态, | ||||
|     // 从而被 processSingleTaskWithRetries 中的 try-catch 捕获,保留了详细的错误信息。 | ||||
|     const error = err as Error; | ||||
|     console.error(`[Worker] 上传时发生异常: ${error.message}`); | ||||
|     return { code: 20038 }; | ||||
|     throw error; // 重新抛出异常 | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| @ -139,32 +176,8 @@ async function sendProcessData(data: RegulatoryInterfaceParams, singlePlay: bool | ||||
|   return await Request<object>({ | ||||
|     host: JGHOST, | ||||
|     url: '/dems_ws/services/TmriOutAccess?wsdl', | ||||
|     data: `<?xml version="1.0"?> | ||||
|                 <SOAP-ENV:Envelope | ||||
|                   xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" | ||||
|                   xmlns:xsd="http://www.w3.org/2001/XMLSchema" | ||||
|                   xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" | ||||
|                  > | ||||
|                  <SOAP-ENV:Body> | ||||
|                     <writeObjectOut  xmlns="http://service.es.doron"> | ||||
|                       <xtlb>${data.xtlb}</xtlb> | ||||
|                       <jkxlh>${data.jkxlh}</jkxlh> | ||||
|                       <jkid>${data.jkid}</jkid> | ||||
|                       <UTF8XmlDoc> | ||||
|                       <![CDATA[ | ||||
|                         <?xm lversion="1.0 "encoding="GBK"?> | ||||
|                         <root> | ||||
|                           <drvexam> | ||||
|                             ${drvexamArr} | ||||
|                           </drvexam> | ||||
|                         </root> | ||||
|                       ]]> | ||||
|                       </UTF8XmlDoc> | ||||
|                     </writeObjectOut> | ||||
|                  </SOAP-ENV:Body> | ||||
|                </SOAP-ENV:Envelope>`, | ||||
|     data: `<?xml version="1.0"?> <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" > <SOAP-ENV:Body> <writeObjectOut  xmlns="http://service.es.doron"> <xtlb>${data.xtlb}</xtlb> <jkxlh>${data.jkxlh}</jkxlh> <jkid>${data.jkid}</jkid> <UTF8XmlDoc> <![CDATA[ <?xm lversion="1.0 "encoding="GBK"?> <root> <drvexam> ${drvexamArr} </drvexam> </root> ]]> </UTF8XmlDoc> </writeObjectOut> </SOAP-ENV:Body> </SOAP-ENV:Envelope>`, | ||||
|     method: http.RequestMethod.POST, | ||||
|     xml: true | ||||
|   }) | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -6,9 +6,11 @@ import { | ||||
|   DefaultJudgeConfigObj, | ||||
|   ExtendType, | ||||
|   Gps, | ||||
|   JudgeSound, | ||||
|   LANE, | ||||
|   MarkRule, | ||||
|   PLCType, | ||||
|   ProcessDataEnumType, | ||||
|   ProjectInfo, | ||||
|   ProjectInfos, | ||||
|   ProjectRoads, | ||||
| @ -18,6 +20,8 @@ import { | ||||
| import { ArrayToByteArray, NumberToByteArray } from '../../utils/Common'; | ||||
| import dayTs from '../../utils/Date'; | ||||
| import { dConsole } from '../../utils/LogWorker'; | ||||
| import VoiceAnnounce from '../judgeSDK/utils/voiceAnnouncements'; | ||||
| import { examJudgeSoundEnd } from './JudgeSDKUtils'; | ||||
| 
 | ||||
| 
 | ||||
| // 中心信号转换 | ||||
| @ -853,3 +857,53 @@ export const CurrentProjectConversion = (code: number, projectsObj: object): str | ||||
|   const project: ProjectInfo = Reflect.get(projectsObj, code) | ||||
|   return project?.abbreviation || '通用评判' | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * 获取评判语音 | ||||
|  * @param sound - 评判音频对象 | ||||
|  * @param avPlayer - 语音播放器实例 | ||||
|  */ | ||||
| export function PlayJudgeVoice(sound: JudgeSound, avPlayer: VoiceAnnounce) { | ||||
|   if (sound.type == 1) { | ||||
|     avPlayer?.playAudio([`voice/${sound.code[0]}.mp3`], false, () => { | ||||
|       examJudgeSoundEnd({ | ||||
|         xmdm: sound.xmdm, code: sound.code[0], type: sound.type | ||||
|       }); | ||||
|       dConsole.writeProcessData(ProcessDataEnumType.JudgeExamData, JSON.stringify({ | ||||
|         method: 'examJudgeSoundEnd', | ||||
|         itemno: sound.xmdm, | ||||
|         code: sound.code[0], | ||||
|         type: sound.type, | ||||
|       })); | ||||
|     }); | ||||
|   } else { | ||||
|     avPlayer?.playAudio([`voice/${sound.code[0]}.mp3`]); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * 检查差分 | ||||
|  */ | ||||
| export const DetectingDifferences = async (type: number, avPlayer: VoiceAnnounce): Promise<boolean> => { | ||||
|   switch (type) { | ||||
|     case 0: | ||||
|       return true; | ||||
|     case 1: | ||||
|       avPlayer?.playAudio([`voice/差分状态异常.mp3`], true) | ||||
|     // setTimeout(() => { | ||||
|     //   router.back() | ||||
|     // }, 3000) | ||||
|       return true | ||||
|     case 2: | ||||
|       avPlayer?.playAudio([`voice/差分状态异常.mp3`], true); | ||||
|       return false | ||||
|     case 3: | ||||
|       avPlayer?.playAudio([`voice/差分状态异常.mp3`], true); | ||||
|       return true | ||||
|     case 4: | ||||
|     //差分异常上报 | ||||
|       return false | ||||
|     default: | ||||
|       return true | ||||
|   } | ||||
| } | ||||
| @ -16,19 +16,12 @@ class differentialSignal { | ||||
|       console.error(TCPTag, "TCP发生错误") | ||||
|       this.differentialSignalTcp.reBind() | ||||
|     }) | ||||
|     // let config: EnvironmentConfigurationType = | ||||
|     //   AppStorage.get<EnvironmentConfigurationType>("EnvironmentConfiguration") || { | ||||
|     //     tcplocalIp: "", | ||||
|     //     tcplocalIpPort: "", | ||||
|     //     tcpOppositeIp: "", | ||||
|     //     tcpOppositePort: "" | ||||
|     //   } | ||||
|     console.log(TCPTag, "初始化", JSON.stringify(config)) | ||||
|     if (config.tcplocalIp || config.tcplocalIpPort || config.tcpOppositeIp || config.tcpOppositePort) { | ||||
|       this.differentialSignalTcp.init(config.tcplocalIp || "", config.tcplocalIpPort || "", config.tcpOppositeIp || "", | ||||
|         config.tcpOppositePort || ""); | ||||
|     } else { | ||||
|       console.log(TCPTag, "未配置差分信号TCP信息,请在环境配置中设置") | ||||
|       console.error(TCPTag, "未配置差分信号TCP信息,请在环境配置中设置") | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user