diff --git a/Makefile b/Makefile index 99ba50c..3678164 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,8 @@ gitLog: git log --since="2025-08-08 14:00" --until="2025-08-19 15:00" --pretty=format:"
%n %s%n [提交人]:%an
%n [提交时间]:%ad
%n [提交版本]:%h%n
%n" --date=format:"%Y-%m-%d %H:%M" > release_note.md - re: hdc shell mount -o remount,rw / - pushJudge: - hdc file send /Users/wangzhongjie/Desktop/duolun/openHarmony/car_next/ohos/so/libjudgesdk.z.so /system/lib/module/ \ No newline at end of file + hdc file send /Users/wangzhongjie/Desktop/duolun/openHarmony/car_next/ohos/so/libjudgesdk.z.so /system/lib/module/ +uninstall: + hdc uninstall com.oh.dts diff --git a/build-profile.json5 b/build-profile.json5 index e620bae..00c3c80 100644 --- a/build-profile.json5 +++ b/build-profile.json5 @@ -5,9 +5,9 @@ "name": "default", "material": { "certpath": "/Users/wangzhongjie/.ohos/config/openharmony/default_car_next_xIuD6UMCLxZgyeiH-w2XdDck6DewIfdHAvOk_FUbNZo=.cer", - "storePassword": "0000001B3C172BE457130742FD9398569777C93BBF9F9BBC9FA403F3FD8E06D5893F3D14B1789DF6E0F242", + "storePassword": "0000001B42BCAC6B534ABB3B488F5C45764278201EE92A007F988939EC561EEB8ED64F737B8A11A7A72A1E", "keyAlias": "debugKey", - "keyPassword": "0000001BEB9FF05D2B1A12791F121AFD8768580FD640018F6A394C3992EF05F73C2CEFAA130DE40703DFE8", + "keyPassword": "0000001B2A149F63C38A6F5B972EC903EB0ADAB7978BA6C33B8E460C7353BD0BC2248776AB2FD2AE009A98", "profile": "/Users/wangzhongjie/.ohos/config/openharmony/default_car_next_xIuD6UMCLxZgyeiH-w2XdDck6DewIfdHAvOk_FUbNZo=.p7b", "signAlg": "SHA256withECDSA", "storeFile": "/Users/wangzhongjie/.ohos/config/openharmony/default_car_next_xIuD6UMCLxZgyeiH-w2XdDck6DewIfdHAvOk_FUbNZo=.p12" diff --git a/entry/oh-package-lock.json5 b/entry/oh-package-lock.json5 index 3f4c904..d5892e3 100644 --- a/entry/oh-package-lock.json5 +++ b/entry/oh-package-lock.json5 @@ -1,5 +1,5 @@ { - "lockfileVersion": 2, + "lockfileVersion": 1, "ATTENTION": "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.", "specifiers": {}, "packages": {} diff --git a/entry/src/main/ets/api/index.ets b/entry/src/main/ets/api/index.ets index c456c52..0acbfe2 100644 --- a/entry/src/main/ets/api/index.ets +++ b/entry/src/main/ets/api/index.ets @@ -145,4 +145,5 @@ export async function initCarParameter(params: object) { method: http.RequestMethod.POST, xml: false, }) -} \ No newline at end of file +} + diff --git a/entry/src/main/ets/api/judgeNew.ets b/entry/src/main/ets/api/judgeNew.ets index dab1f0c..89dce6f 100644 --- a/entry/src/main/ets/api/judgeNew.ets +++ b/entry/src/main/ets/api/judgeNew.ets @@ -12,6 +12,7 @@ import { } from '../model'; import FileUtils from '../utils/FileUtils'; import { GetSyncData } from '../utils/table/Operation'; +import { JudgeTag } from '../config'; //监管接口序列号映射 const gjxlhObj: Record = { @@ -52,7 +53,7 @@ export default async function writeObjectOutNew(data: RegulatoryInterfaceParams, } // let connectTimeout = sjbs === '02-21-000014' ?60000:1 - console.info('surenjun', '调用新监管') + console.info(JudgeTag, '调用新监管') let temp: WR try { const JGHOST: string = AppStorage.get('JGHOST') || "" diff --git a/entry/src/main/ets/api/networkCamera.ets b/entry/src/main/ets/api/networkCamera.ets new file mode 100644 index 0000000..1ae7c88 --- /dev/null +++ b/entry/src/main/ets/api/networkCamera.ets @@ -0,0 +1,94 @@ +import http from '@ohos.net.http'; +import buffer from '@ohos.buffer'; +import image from '@ohos.multimedia.image'; + +const TAG = 'CameraService'; + +export async function ObtainNetworkCameraImages(): Promise { + const url = "http://192.168.1.125/snapshot.cgi?stream=1&username=admin&password=123456"; + let httpRequest = http.createHttp(); + + try { + console.info(TAG, 'Starting image request...'); + const response = await httpRequest.request(url, { + method: http.RequestMethod.GET, + connectTimeout: 10000, + readTimeout: 10000, + expectDataType: http.HttpDataType.ARRAY_BUFFER, + }); + + if (response.responseCode === 200) { + let arrayBuffer = response.result as ArrayBuffer; + + // 裁剪左半部分 + const croppedBase64 = await cropLeftHalf(arrayBuffer); + + return croppedBase64; + } else { + console.error(TAG, `HTTP Error: ${response.responseCode}`); + return null; + } + } catch (error) { + console.error(TAG, 'An error occurred while fetching the image.', JSON.stringify(error)); + return null; + } finally { + httpRequest.destroy(); + } +} + +async function cropLeftHalf(arrayBuffer: ArrayBuffer): Promise { + let imageSource: image.ImageSource | null = null; + let pixelMap: image.PixelMap | null = null; + + try { + // 1. 创建ImageSource + imageSource = image.createImageSource(arrayBuffer); + + // 2. 获取图片信息 + const imageInfo = await imageSource.getImageInfo(); + console.info(TAG, `Original image size: ${imageInfo.size.width}x${imageInfo.size.height}`); + + // 3. 计算并定义左半部分的裁剪区域 + const leftHalfWidth = Math.floor(imageInfo.size.width / 2); + const cropRegion: image.Region = { + size: { + width: leftHalfWidth, + height: imageInfo.size.height + }, + x: 0, + y: 0 + }; + + // 创建解码选项,并将裁剪区域放入其中 + const decodingOptions: image.DecodingOptions = { + desiredRegion: cropRegion + }; + + // 4. 创建像素映射并进行裁剪 + pixelMap = await imageSource.createPixelMap(decodingOptions); + + // 5. 将裁剪后的PixelMap转换为ArrayBuffer + const imagePacker = image.createImagePacker(); + const packedData = await imagePacker.packing(pixelMap, { + format: "image/jpeg", + quality: 90 + }); + + // 6. 转换为Base64 + const buf = buffer.from(packedData); + const base64 = buf.toString('base64'); + + const result = `data:image/jpeg;base64,${base64}`; + console.info(TAG, `Left half cropped successfully. Size: ${leftHalfWidth}x${imageInfo.size.height}`); + + return result; + + } catch (error) { + console.error(TAG, 'Image cropping failed:', JSON.stringify(error)); + return ""; + } finally { + // 7. 在 finally 块中安全地释放资源 + imageSource?.release(); + pixelMap?.release(); + } +} \ No newline at end of file diff --git a/entry/src/main/ets/config/LogEnum.ets b/entry/src/main/ets/config/LogEnum.ets index da2fbe4..0407a07 100644 --- a/entry/src/main/ets/config/LogEnum.ets +++ b/entry/src/main/ets/config/LogEnum.ets @@ -71,5 +71,19 @@ export const StartExamTag = '[StartExam]' //人脸对比 export const FaceCompareTag = '[FaceCompare]'; + //过程数据处理 -export const ProcessDataTag = '[ProcessData]'; \ No newline at end of file +export const ProcessDataTag = '[ProcessData]'; + +// 日志 +export const LogTag = '[LogWorker]'; + +// 开始考试,结束考试标志 +export const StartEndExamTag = '[StartEndExam]'; + +// Queue +export const QueueTag = '[Queue]' + +// 考试过程数据 +export const ExamProcessDataTag = '[ExamProcessData]'; + diff --git a/entry/src/main/ets/config/global.ets b/entry/src/main/ets/config/global.ets index aa15b05..fa5dc22 100644 --- a/entry/src/main/ets/config/global.ets +++ b/entry/src/main/ets/config/global.ets @@ -10,6 +10,7 @@ import { GlobalConfigType } from '../model'; */ export const GlobalConfig: GlobalConfigType = { commonFileWriteAddress: '/mnt/hmdfs/100/account/device_view/local/files/duolun', + modelPath: "/mnt/hmdfs/100/account/device_view/local/files/duolun/models/model_enc", picSavePath: '/storage/cloud/100/files/Photo/', videoSavePath: '/storage/cloud/100/files/Videos/', host: 'http://192.168.32.105:8089', diff --git a/entry/src/main/ets/config/judge.ets b/entry/src/main/ets/config/judge.ets index 96aeea8..5316320 100644 --- a/entry/src/main/ets/config/judge.ets +++ b/entry/src/main/ets/config/judge.ets @@ -24,9 +24,9 @@ export const JudgeConfig: JudgeConfigType = { //轨迹回放是否开启Udp udpOpen: true, // 本地模型地址 - modelPath: 'models/model_enc', + modelPath: 'models/', // 济南科目三 - trajectoryPath: 'logs/2024_10_12/2024_10_12_11_50_10_9999427676823_744299437502336256_隋统/judge_exam_data.txt', + trajectoryPath: 'logs/2025_08_22/2025_08_22_17_09_49_9999245520855_654211778346526080_杜兰曼/judge_exam_data.txt', //四合一画面配置 fourInOneScreen: { //gps位数 diff --git a/entry/src/main/ets/entryability/EntryAbility.ets b/entry/src/main/ets/entryability/EntryAbility.ets index 61a6792..b4e0f4a 100644 --- a/entry/src/main/ets/entryability/EntryAbility.ets +++ b/entry/src/main/ets/entryability/EntryAbility.ets @@ -8,10 +8,9 @@ import { BaseInfoType, CarInfoType, EnvironmentConfigurationType, ExaminerInfoTy import DB from '../utils/DbSql'; import { DrivingDataStorage } from '../utils/business/DrivingDataStorage'; import { InitTable } from '../utils/table/Operation'; -import FileUtils from '../utils/FileUtils'; import { EntryTag } from '../config'; import { dConsole } from '../utils/LogWorker'; -import { UseAuth } from '../utils/Common'; +import { ReadFileContent, UseAuth } from '../utils/Common'; import { DifferentialAndSignal } from '../utils/business/DifferentialAndSignalWorker'; export default class EntryAbility extends UIAbility { @@ -19,9 +18,8 @@ export default class EntryAbility extends UIAbility { console.log(EntryTag, "多伦鸿蒙车载程序启动") await DB.init(this.context) try { - let fileUtil = new FileUtils(this.context) // 读取系统设置参数 - const data = await fileUtil.readFile(GlobalConfig.commonFileWriteAddress + '/config/ipConfig.txt'); + const data = await ReadFileContent(GlobalConfig.commonFileWriteAddress + '/config/ipConfig.txt') if (data !== '' && data !== undefined) { const result: EnvironmentConfigurationType = JSON.parse(data) AppStorage.setOrCreate("EnvironmentConfiguration", result) @@ -33,7 +31,7 @@ export default class EntryAbility extends UIAbility { AppStorage.setOrCreate("host", host) } // 读取视频配置 - const videoData = await fileUtil.readFile(GlobalConfig.commonFileWriteAddress + '/config/config3.txt'); + const videoData = await ReadFileContent(GlobalConfig.commonFileWriteAddress + '/config/config3.txt') if (videoData !== '' && videoData !== undefined) { const videoConfig: VideoConfig = JSON.parse(videoData) AppStorage.setOrCreate("VideoConfig", videoConfig) @@ -55,38 +53,38 @@ export default class EntryAbility extends UIAbility { async onWindowStageCreate(windowStage: window.WindowStage) { console.log(EntryTag, "onWindowStageCreate", "窗口创建完成") - await UseAuth(this.context) - const windowClass = await windowStage.getMainWindow(); - let rect = windowClass.getWindowProperties().windowRect - let width = rect.width - let height = rect.height - AppStorage.setOrCreate('carInfo', {}) - AppStorage.setOrCreate('examinerInfo', {}) - AppStorage.setOrCreate('lsh', '0000000000000') - AppStorage.setOrCreate('statue', "1") //考试状态 - AppStorage.setOrCreate('signNum', 0) //心跳指令编号 - AppStorage.setOrCreate('deviceNo', "") //设备号 - AppStorage.setOrCreate('baseInfo', { - hasAuth: false, - version: GlobalConfig.version.sz.km2[0] || "", - judgeVersion: GlobalConfig.version.sz.km2[1] || "", - tcpSendNum: 0, - videoVersion: '1.0', - ratio: width / height, //适配比例 - pathDir: this.context.filesDir, - context: this.context, - isJudgeInitBool: false, - }) + try { + await UseAuth(this.context) + const windowClass = await windowStage.getMainWindow(); + AppStorage.setOrCreate('carInfo', {}) + AppStorage.setOrCreate('examinerInfo', {}) + AppStorage.setOrCreate('lsh', '0000000000000') + AppStorage.setOrCreate('statue', "1") //考试状态 + AppStorage.setOrCreate('signNum', 0) //心跳指令编号 + AppStorage.setOrCreate('deviceNo', "") //设备号 + AppStorage.setOrCreate('baseInfo', { + hasAuth: false, + // version: GlobalConfig.version.sz.km2[0] || "", + // judgeVersion: GlobalConfig.version.sz.km2[1] || "", + tcpSendNum: 0, + videoVersion: '1.0', + pathDir: this.context.filesDir, + context: this.context, + isJudgeInitBool: false, + }) + AppStorage.setOrCreate('isJudgeInitBool', false) - let fileUtil = new FileUtils(this.context) - const data = await fileUtil.readFile(GlobalConfig.commonFileWriteAddress + '/config/ipConfig.txt'); - if (data !== '' && data !== undefined) { - const config: EnvironmentConfigurationType = JSON.parse(data) - await windowClass.setWindowLayoutFullScreen(true) - console.log("是否调试模式", config?.isOpenDebugger) - if (config?.isOpenDebugger === "0") { - await windowClass.setWindowSystemBarEnable([]) //全屏 + const data = await ReadFileContent(GlobalConfig.commonFileWriteAddress + '/config/ipConfig.txt') + if (data !== '' && data !== undefined) { + const config: EnvironmentConfigurationType = JSON.parse(data) + await windowClass.setWindowLayoutFullScreen(true) + console.log("是否调试模式", config?.isOpenDebugger) + if (config?.isOpenDebugger === "0") { + await windowClass.setWindowSystemBarEnable([]) //全屏 + } } + } catch (e) { + console.error("onWindowStageCreate error", e) } windowStage.loadContent('pages/Index', (err, data) => { if (err.code) { @@ -96,6 +94,7 @@ export default class EntryAbility extends UIAbility { hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? ''); }); + this.createFiles(); } diff --git a/entry/src/main/ets/mock/Judge.ets b/entry/src/main/ets/mock/Judge.ets index 6b66155..6c99b68 100644 --- a/entry/src/main/ets/mock/Judge.ets +++ b/entry/src/main/ets/mock/Judge.ets @@ -264,7 +264,12 @@ export const DefaultJudgeConfigData: DefaultJudgeConfigObj = { //里程不够允许手工点靠边停车 param_387: '0', //监管模式有扣分续考(0-否++1-是+把上次未考完的扣分带下来重新考试) - param_432: '1' + param_432: '1', + // Todo + // param_634: '1', + // Todo + // param_810: '1' + } //所有的科二 科目三项目 diff --git a/entry/src/main/ets/mock/TerminallInfo.ets b/entry/src/main/ets/mock/TerminallInfo.ets new file mode 100644 index 0000000..15e922f --- /dev/null +++ b/entry/src/main/ets/mock/TerminallInfo.ets @@ -0,0 +1,71 @@ +import { CommonListType } from '../model' + +export const RearMachineModelListData: CommonListType[] = [ + { + label: '一型机', + value: '1' + }, + { + label: '二型机', + value: '2' + }, + { + label: '三型机', + value: '3' + }, + { + label: '一体机', + value: '4' + } +] + +export const BoardListData: CommonListType[] = [ + { + label: '北云', + value: '1' + }, + { + label: '天宝MB2', + value: '2' + } +] + +export const LogListData: CommonListType[] = [ + { + label: '开启', + value: '1' + }, + { + label: '关闭', + value: '0' + } +] + +export const CarTypeListData: CommonListType[] = [ + { + label: '小车C1', + value: '1' + }, + { + label: '小车C2', + value: '2' + }, + { + label: '大车', + value: '3' + }, + { + label: '牵引车A2', + value: '4' + } +] +export const ManufacturerListData: CommonListType[] = [ + { + label: '诚迈', + value: '1' + }, + { + label: '润和', + value: '2' + } +] \ No newline at end of file diff --git a/entry/src/main/ets/mock/index.ets b/entry/src/main/ets/mock/index.ets index d9d3a5d..3a1b7b6 100644 --- a/entry/src/main/ets/mock/index.ets +++ b/entry/src/main/ets/mock/index.ets @@ -7,4 +7,5 @@ export * from "./Judge" export * from "./SignDisplay" export * from "./CarCheck" -export * from "./Test" \ No newline at end of file +export * from "./Test" +export * from "./TerminallInfo" \ No newline at end of file diff --git a/entry/src/main/ets/model/Common.ets b/entry/src/main/ets/model/Common.ets index 72404f5..21fcd0d 100644 --- a/entry/src/main/ets/model/Common.ets +++ b/entry/src/main/ets/model/Common.ets @@ -79,8 +79,9 @@ export interface CommonType { // 基础信息 export interface BaseInfoType { hasAuth?: boolean, - version?: string, - judgeVersion?: string, + + // version?: string, + // judgeVersion?: string, tcpSendNum?: number, videoVersion?: string, ratio?: number, @@ -104,6 +105,8 @@ export interface RouteParamsType { kString?: string; examItems?: string; fromIndex?: boolean; + mode?: number + score?: number } // 车辆信息 @@ -137,6 +140,7 @@ export interface EnvironmentConfigurationType { // 前置机响应后置机端口2 udplocalIpPortTwo?: string, udpOppositeIp?: string, + udpOppositeIpTwo?: string, // 后置机响应端口 udpOppositeIpPort?: string, @@ -169,6 +173,10 @@ export interface EnvironmentConfigurationType { version?: string // 评判版本 judgeVersion?: string + // 是否使用网络摄像头 + isUseNetworkCamera?: string + // 厂商 诚迈 1 润和 2 + manufacturer?: string } //全局配置 @@ -180,6 +188,8 @@ export interface GlobalConfigType { version: VersionType // 几代机 modelNo?: string + // 模型位置 + modelPath?: string } interface VersionType { diff --git a/entry/src/main/ets/model/Judge.ets b/entry/src/main/ets/model/Judge.ets index 1753dc9..a859ca0 100644 --- a/entry/src/main/ets/model/Judge.ets +++ b/entry/src/main/ets/model/Judge.ets @@ -273,7 +273,10 @@ export interface DefaultJudgeConfigObj { param_369: string param_375: string param_387: string + param_392?: string param_432: string + param_634?: string + param_810?: string } export interface SyssetConfig { @@ -308,6 +311,7 @@ export interface ProjectInfo { isRequired?: boolean //项目状态:未做 正在做 及格 不及格 有扣分 type?: '1' | '2' | '3' | '4' | '5' + ykType?: '1' | '2' | '3' | '4' | '5' } /** 科目二项目代码 **/ @@ -431,6 +435,8 @@ export interface MAPPOINT { f_gps_e: number, f_gps_n: number, passed: number + X_MCH: string, + } export interface MAPITEMPOINTITEM { @@ -447,8 +453,8 @@ export interface JudgeUI { startFullTime: string mapPointArr: MAPPOINT[] mapPointItemArr: MAPITEMPOINTITEM[] - systemparmArr: SYSTEMPARMARR[] - carinfoArr: CARINFO[] + systemparmArr: SYSTEM_PARAM[] + carinfoArr: CAR_INFO[] kfArr: MarkRule[] judgeConfigObj: DefaultJudgeConfigObj judgeConfig: SyssetConfig[] @@ -532,16 +538,22 @@ export interface CDSBInfo { xmxh?: string } -export interface SYSTEMPARMARR { - NO1: number, - NO2: number, - NO3: number, - TXT1: string, - TXT2: string, - TXT3: string, +export interface SYSTEM_PARAM { + NO1?: number, + NO2?: number, + NO3?: number, + TXT1?: string, + TXT2?: string, + TXT3?: string, + no1?: string, + no2?: string, + no3?: string, + txt1?: string + txt2?: string + txt3?: string } -export interface CARINFO { +export interface CAR_INFO { CARID: string, IPADDR: string, CARCLASS: string, @@ -550,6 +562,7 @@ export interface CARINFO { FLAG: string, BK1: string, BK2: string + X_MCH: string, } export interface KmItem { @@ -596,12 +609,12 @@ export interface JudgeInitObj extends Km3JudgeInitConfig { carmodel: string allitems: ItemInfo[] iteminfo?: ItemInfo[] - systemparm: SYSTEMPARMARR[] + systemparm: SYSTEM_PARAM[] mark: MarkRule[] sysset: SyssetConfig[] itemInfoObj?: ItemInfos carlist: string - carinfo: CARINFO[] + carinfo: CAR_INFO[] } @@ -646,7 +659,7 @@ export interface JudgeBeginObj { sczbkf?: JudgeKFXM[] dmndg: boolean mfxx: boolean - mfxxn: boolean + zeng: boolean } export interface JudgeXMJS { @@ -807,7 +820,7 @@ export interface DistanceClass { export interface WR { message?: string - code?: number + code: string keystr?: string } @@ -838,7 +851,7 @@ export interface ProjectDataType { } export interface ProjectItemType { - code: ProjectDataType + code: string status: string } @@ -856,6 +869,9 @@ export interface Project { // isEnd: boolean, isUpload: boolean + // 下面是大车使用的 + isRequired?: boolean + ykType?: '1' | '2' | '3' | '4' | '5' } diff --git a/entry/src/main/ets/model/ProcessData.ets b/entry/src/main/ets/model/ProcessData.ets new file mode 100644 index 0000000..dbe24a7 --- /dev/null +++ b/entry/src/main/ets/model/ProcessData.ets @@ -0,0 +1,38 @@ +/** + * 定义批次进度更新时的回调函数类型 + * @param totalTasks 本批次总任务数 + * @param completedTasks 已完成任务数 (成功 + 失败) + * @param successfulTasks 成功完成的任务数 + * @param failedTasks 失败的任务数 + * @param progressPercentage 当前进度百分比 (0-100) + */ +import { RegulatoryInterfaceParams, WR } from '.'; + +export type OnBatchProgressUpdateCallback = ( + totalTasks: number, + completedTasks: number, + successfulTasks: number, + failedTasks: number, + progressPercentage: number +) => void; + +/** + * 定义所有任务完成时的回调函数类型 + * @param totalTasks 本批次总任务数 + * @param completedTasks 已完成任务数 (成功 + 失败) + * @param successfulTasks 成功完成的任务数 + * @param failedTasks 失败的任务数 + */ +export type OnAllTasksCompletedCallback = ( + totalTasks: number, + completedTasks: number, + successfulTasks: number, + failedTasks: number +) => void; + +export type ProgressCallback = (data: WR) => void; + +export interface QueueTask { + data: RegulatoryInterfaceParams; + callback?: ProgressCallback; +} \ No newline at end of file diff --git a/entry/src/main/ets/model/Worker.ets b/entry/src/main/ets/model/Worker.ets index 6f39e65..062ee73 100644 --- a/entry/src/main/ets/model/Worker.ets +++ b/entry/src/main/ets/model/Worker.ets @@ -1,31 +1,90 @@ -import { CarInfoType, CenterCallBackMsgType, EnvironmentConfigurationType, UDPParamType } from '.'; +import { + CarInfoType, + CDSBInfos, + CenterCallBackMsgType, + EnvironmentConfigurationType, + JudgeConfigObjKmItems, + JudgePerformInfo, + MarkRule, +} from '.'; + +export interface JudgeUDPData { + totalScore: number + kfArr: MarkRule[] + startTime: string + examTime: number + xmmcSingleCode: string + kmItems: JudgeConfigObjKmItems + cdsbInfoObj: CDSBInfos + xmxh: string + xmdm: number | string +} + +export enum WorkerMessageDataType { + Init, + Close, + SetExamData, + JudgeSend, + CenterSend +} + +export interface InitData extends ExamData { + config?: EnvironmentConfigurationType; + carInfo?: CarInfoType; + singlePlay?: boolean +} + +export interface JudgeData { + judgeUdpEnd?: boolean, + judgeExamEnd?: boolean + performInfo?: JudgePerformInfo, + business?: JudgeUDPData + remoteType?: 'kf' + remoteData?: number[] +} + +export interface CenterData { + id: number + body: number[] +} + +export interface ExamData { + signNum?: number; + statue?: string; + lsh?: string; +} + +export interface CloseData { + carType: string +} export interface WorkerMessage { - config: EnvironmentConfigurationType; - carInfo: CarInfoType; - centerUdpParam?: UDPParamType; - otherMessage: OtherMessageType; - singlePlay?: boolean - // 关闭 - close?: boolean; + type: WorkerMessageDataType + data: InitData | JudgeData | CenterData | ExamData | CloseData } -export interface OtherMessageType { - signNum: number; - statue: string; - lsh: string; -} export interface WorkerBackMessage { type: WorkerBackMessageType; - data: string | CenterCallBackMsgType + data: string | CenterCallBackMsgType | number[] } export enum WorkerBackMessageType { // 后置机信息 ObtainUdpData = 'obtainUdpData', + // 后置机GPS2消息 + ObtainUdpGps2Data = 'obtainUdpGps2Data', // 中心消息 CenterUdpData = 'centerUdpData', + // 远程开始考试 + RemoteStartExam = 'remoteStartExam', + // 远程结束考试 + RemoteEndExam = 'remoteEndExam', + // 远程扣分 + RemoteKf = 'RemoteKf', + // 远程扣分确认 + RemoteKfConfirm = 'RemoteKfConfirm', + StopExam = 'stopExam' } export interface LogWorkerMessage { @@ -55,22 +114,22 @@ export enum WorkerMessageType { // 过程数据枚举 export enum ProcessDataEnumType { - //four_one_log_byte_data - FourOneLogByteData = "0", - //four_one_log_data - FourOneLogData = "1", + // //four_one_log_byte_data + // FourOneLogByteData = "0", + // //four_one_log_data + // FourOneLogData = "1", //judge_exam_data - JudgeExamData = "2", + JudgeExamData = "0", //judge_log_data - JudgeLogData = "3", + JudgeLogData = "1", //judge_progress_callback_data - JudgeProgressCallbackData = "4", + JudgeProgressCallbackData = "2", //plc_data - PlcData = "5", + PlcData = "3", //wuxi_exam_data - WuxiExam = "6", + WuxiExam = "4", //wuxi_progress_data - WuxiProgressData = "7" + WuxiProgressData = "5" } export interface FileQueueType { diff --git a/entry/src/main/ets/model/api.ets b/entry/src/main/ets/model/api.ets index 3dae78c..0e2ea9a 100644 --- a/entry/src/main/ets/model/api.ets +++ b/entry/src/main/ets/model/api.ets @@ -248,6 +248,7 @@ export interface ObtainCarExamInfoParams { //监管接口参数 export interface RegulatoryInterfaceParams { + JGHOST?: string xtlb?: string; jkxlh?: string; jkid?: string; diff --git a/entry/src/main/ets/model/index.ets b/entry/src/main/ets/model/index.ets index d60d364..620bdf1 100644 --- a/entry/src/main/ets/model/index.ets +++ b/entry/src/main/ets/model/index.ets @@ -20,4 +20,6 @@ export * from "./TableColumn" export * from "./Other" -export * from "./Worker" \ No newline at end of file +export * from "./Worker" + +export * from "./ProcessData" \ No newline at end of file diff --git a/entry/src/main/ets/pages/ExaminerLogin.ets b/entry/src/main/ets/pages/ExaminerLogin.ets index 5e03f82..b06a5cb 100644 --- a/entry/src/main/ets/pages/ExaminerLogin.ets +++ b/entry/src/main/ets/pages/ExaminerLogin.ets @@ -34,7 +34,7 @@ struct ExaminerLoginPage { }) Row() { Text("请考官输入用户名和密码") - .fontSize(40) + .fontSize(50) .fontColor("#EF9335") .width("100%") .height(50) @@ -145,14 +145,14 @@ struct ExaminerLoginPage { router.pushUrl({ url: 'pages/UserInfo', params: { - type: 1 + type: "1" } }, router.RouterMode.Single); }, remainingTime); } catch (e) { this.loadingDialog.close(); - dConsole.error(ExaminerLoginTag, 'examinerLogin error: ' + e); + dConsole.error(ExaminerLoginTag, 'examinerLogin error: ' + JSON.stringify(e)); Prompt.showToast({ message: "登录失败,请稍后重试", duration: 2000 @@ -194,7 +194,7 @@ struct btnComponent { build() { Row() { if (this.text != "确定" && this.text !== "退格" && this.text !== "清空") { - Text(this.text).fontSize(40).fontColor("#F0DEC5") + Text(this.text).fontSize(50).fontColor("#F0DEC5") } } .backgroundImage(this.text === "确定" ? $r("app.media.queding_nor") : this.text === "退格" ? $r("app.media.delete_nor") : this.text === "清空" ? $r("app.media.clear_nor") : $r("app.media.nor_btn")) diff --git a/entry/src/main/ets/pages/Index.ets b/entry/src/main/ets/pages/Index.ets index 7d2ce77..3912c5d 100644 --- a/entry/src/main/ets/pages/Index.ets +++ b/entry/src/main/ets/pages/Index.ets @@ -3,9 +3,15 @@ import router from '@ohos.router'; import { HomeTag, InitTableTag, JudgeConfig } from '../config'; import VoiceAnnounce from './judgeSDK/utils/voiceAnnouncements'; -import { BaseInfoType } from '../model/Common'; -import { CarInfoType, InitializeTheCentralTableType, MASYSSETTableType, TimeSynchronizationRspBody } from '../model'; -import { CreateAlbum, GetCarInfo, GetDeviceInfo, SetCurrentTime } from './Index/utils'; +import { BaseInfoType, EnvironmentConfigurationType } from '../model/Common'; +import { + CarInfoType, + ES_CARINFOType, + InitializeTheCentralTableType, + MASYSSETTableType, + TimeSynchronizationRspBody +} from '../model'; +import { CheckNetUntilConnected, CreateAlbum, GetCarInfo, GetDeviceInfo, SetCurrentTime } from './Index/utils'; import { GetSyncData, InitializeTheCentralTable } from '../utils/table/Operation'; import { BusinessError } from '@ohos.base'; import { delPic } from '../utils/Video'; @@ -31,7 +37,6 @@ struct Index { @State deviceId: string = ''; @State angle: number = 0 @State dialogRatio: number = 0.8 - @State ratio: number = 1700 / 960 @State delLoading: boolean = false @State initParamFlag: boolean = false @State fd: number = -1; @@ -40,6 +45,8 @@ struct Index { @State isPlay: boolean = false; @State initWork: boolean = false @State status: string = "开始" + @State base64Img: string = "" + @State config: EnvironmentConfigurationType = {} // 请求网络表等待弹窗 customDialogController: CustomDialogController = new CustomDialogController({ builder: CarLoadingComponent(), @@ -52,17 +59,10 @@ struct Index { private avPlayer: VoiceAnnounce = new VoiceAnnounce(this.context) private timeInfo: TimeSynchronizationRspBody = {} - @Styles - commStyle(){ - .width(220 * this.ratio * this.dialogRatio) - .height(69 * this.ratio * this.dialogRatio) - .backgroundImage($r('app.media.button_nor')) - .backgroundImageSize({ width: '100%', height: '100%' }) - } - async aboutToAppear() { dConsole.log("权限首页 aboutToAppear") - this.ratio = AppStorage.get('baseInfo')?.ratio || 1.4 + const result = await GetSyncData("ES_CARINFO") + dConsole.log(HomeTag, "读取carinfo", result) this.angle = 0 AppStorage.set('lsh', '1111111111111') JudgeEmitterInstance.init() @@ -77,12 +77,14 @@ struct Index { } async onPageShow(): Promise { - dConsole.log("权限首页 onPageShow2") + dConsole.log("权限首页 onPageShow") + await CheckNetUntilConnected() if (!this.isPlay) { this.avPlayer.playAudio(['welcome.wav']) this.isPlay = true } this.baseInfo = AppStorage.get('baseInfo')! + this.config = AppStorage.get('EnvironmentConfiguration')! this.initParams() AppStorage.setOrCreate('singlePlay', false) @@ -137,8 +139,8 @@ struct Index { const param: InitializeTheCentralTableType = { carId: this.carInfo?.carId, examinationRoomId: this.carInfo?.examinationRoomId, - judgeVersion: this.baseInfo?.judgeVersion, - shellVersion: this.baseInfo?.version || "", + judgeVersion: this.config?.judgeVersion, + shellVersion: this.config?.version || "", paraKdid: this.timeInfo?.paraKdid || this.timeInfo?.kdid, kdid: this.timeInfo?.kdid || this.timeInfo?.paraKdid, mode: this.timeInfo?.mode, @@ -245,8 +247,8 @@ struct Index { }) BottomMessageComponent({ - version: this.baseInfo.version, - judgeVersion: this.baseInfo.judgeVersion, + version: this.config.version, + judgeVersion: this.config.judgeVersion, hasAuth: this.baseInfo.hasAuth, examCarNumber: this.deviceId, versionClick: () => { diff --git a/entry/src/main/ets/pages/Index/utils.ets b/entry/src/main/ets/pages/Index/utils.ets index f313f91..316ded4 100644 --- a/entry/src/main/ets/pages/Index/utils.ets +++ b/entry/src/main/ets/pages/Index/utils.ets @@ -1,11 +1,11 @@ import common from '@ohos.app.ability.common'; -import { GlobalConfig } from '../../config'; +import { GlobalConfig, HomeTag } from '../../config'; import Prompt from '@system.prompt'; import { ApiResponseType, - BaseInfoType, CarConfigurationParamsType, CarInfoType, + EnvironmentConfigurationType, ObtainCarExamInfoParams, ObtainCarExamInfoRspBody, TimeSynchronizationParams, @@ -19,6 +19,8 @@ import { VideoConfigData } from '../../mock'; import FileUtils from '../../utils/FileUtils'; import { FileHelper } from '../../utils/FileHelp'; import { dConsole } from '../../utils/LogWorker'; +import connection from '@ohos.net.connection'; + //获取设备信息 export async function GetDeviceInfo(context: common.UIAbilityContext): Promise { @@ -42,19 +44,28 @@ export async function GetDeviceInfo(context: common.UIAbilityContext): Promise { + let date = new Date(); let params: ObtainCarExamInfoParams = { time: dayTs(date).format("YYYY-MM-DD HH:mm:ss"), deviceNo: AppStorage.get('deviceNo') || "" }; - let res: ApiResponseType = await obtainCarExamInfo(params) - dConsole.log("90", res) - if (res.obtainCarExamInfoRsp && res.obtainCarExamInfoRsp.body) { - const carInfo: ObtainCarExamInfoRspBody = res?.obtainCarExamInfoRsp?.body! - carInfo.plateNo = decodeURIComponent(carInfo.plateNo) - dConsole.log("Worker received message car", JSON.stringify(carInfo)) - AppStorage.setOrCreate('carInfo', carInfo) - return carInfo + try { + let res: ApiResponseType = await obtainCarExamInfo(params) + dConsole.log("90", res) + if (res.obtainCarExamInfoRsp && res.obtainCarExamInfoRsp.body) { + const carInfo: ObtainCarExamInfoRspBody = res?.obtainCarExamInfoRsp?.body! + carInfo.plateNo = decodeURIComponent(carInfo.plateNo) + // dConsole.log("Worker received message car", JSON.stringify(carInfo)) + AppStorage.setOrCreate('carInfo', carInfo) + return carInfo + } + } catch (e) { + dConsole.error(HomeTag, "获取考车信息错误", JSON.stringify(e)) + setTimeout(() => { + dConsole.log(HomeTag, "延迟获取考车信息") + GetCarInfo() + }, 1000) } return {} } @@ -62,12 +73,12 @@ export async function GetCarInfo(): Promise { //获取时间同步 export async function SetCurrentTime(): Promise { let deviceNo: string = AppStorage.get('deviceNo')!; - let baseInfo: BaseInfoType = AppStorage.get('baseInfo')! + let config: EnvironmentConfigurationType = AppStorage.get('EnvironmentConfiguration')! let params: TimeSynchronizationParams = { time: dayTs(new Date()).format("YYYY-MM-DD HH:mm:ss"), deviceNo, - version: baseInfo.version!, - judgeVersion: baseInfo.judgeVersion! + version: config.version!, + judgeVersion: config.judgeVersion! } let res: ApiResponseType = await timeSynchronization(params); if (res.timeSynchronizationRsp?.body) { @@ -141,3 +152,35 @@ export function CreateAlbum(fileHelper: FileHelper) { fileHelper.createAlbum(date); } +const RETRY_INTERVAL_MS = 3000; + +export async function CheckNetUntilConnected(): Promise { + return new Promise(async (resolve, reject) => { + const doCheck = async () => { + try { + let netHandle: connection.NetHandle = await connection.getDefaultNet(); + // getDefaultNet().netId 在网络连接正常时会大于0 + // 在没有默认网络时,getDefaultNet()可能会抛出异常或者返回netId为0的NetHandle + // 最新的OpenHarmony API中,推荐使用connection.getNetCapabilities(netHandle) + // 或 connection.hasDefaultNet() 来更准确判断网络状态 + + let hasDefaultNet: boolean = await connection.hasDefaultNet(); + + if (hasDefaultNet && netHandle && netHandle.netId > 0) { + dConsole.log(HomeTag, "网络通畅"); + resolve(); // 网络通畅,解决Promise + } else { + dConsole.log(HomeTag, "网络不通畅,等待 " + RETRY_INTERVAL_MS / 1000 + " 秒后重试..."); + setTimeout(doCheck, RETRY_INTERVAL_MS); // 网络不通畅,继续重试 + } + } catch (error) { + dConsole.log(HomeTag, "网络不通畅,等待 " + RETRY_INTERVAL_MS / 1000 + " 秒后重试..."); + setTimeout(doCheck, RETRY_INTERVAL_MS); // 即使出错,也继续重试 + } + }; + + // 首次执行检查 + doCheck(); + }); +} + diff --git a/entry/src/main/ets/pages/Judge.ets b/entry/src/main/ets/pages/Judge.ets index 1184498..828f8be 100644 --- a/entry/src/main/ets/pages/Judge.ets +++ b/entry/src/main/ets/pages/Judge.ets @@ -3,7 +3,6 @@ import Prompt from '@system.prompt'; import common from '@ohos.app.ability.common'; import DeductedPopup from './compontents/judge/DeductionPopup'; import AmplifyPopup from './compontents/judge/AmplifyPopup'; -import Judge from './judgeSDK/judge'; import { uploadExamMileage } from '../api/judge'; import DwztErrorPopup from './compontents/judge/DwztErrorPopup'; import MsgPopup from './compontents/judge/MsgPopup'; @@ -11,7 +10,7 @@ import { JudgeConfig, JudgeTag } from '../config'; import JudgeAndProjectComponent from './Judge/components/JudgeAndProject'; import { AmplifyItem, - CARINFO, + CAR_INFO, CarInfoType, CDSBInfo, CDSBInfos, @@ -24,7 +23,6 @@ import { LANE, MA_CDSBINFOType, MA_ITEMINFOType, - MA_SYSTEMPARMType, MAPITEMPOINTITEM, MAPPOINT, MarkRule, @@ -37,8 +35,11 @@ import { RouteParamsType, SYSSET, SyssetConfig, - SYSTEMPARMARR, - User + SYSTEM_PARAM, + User, + WorkerBackMessage, + WorkerBackMessageType, + WorkerMessageDataType } from '../model'; import { GetSyncData } from '../utils/table/Operation'; import dayTs from '../utils/Date'; @@ -53,11 +54,13 @@ import MessageComponent from './Judge/components/Message'; import OperatingAreaComponent from './Judge/components/OperatingArea'; import { GetIsExitManualProject } from './Judge/utils'; import { InitMapPoint, InitMapPointItem } from './Judge/TableUtils'; +import JudgeBusiness from './Judge/JudgeBusiness'; +import { DifferentialAndSignal } from '../utils/business/DifferentialAndSignalWorker'; @Entry @Component -struct JudgePage { +export struct JudgePage { @State wayno: number = 0 @State isDdxk: boolean = false; //开始时间 @@ -78,7 +81,7 @@ struct JudgePage { @State singlePlay: boolean = false; @State totalScore: number = 100 //模拟考试项目 - @State projects: ProjectInfo[] = [] + @State projects: Project[] = [] @State projectsObj: ProjectInfos = {} @State projectsCenterObj: ProjectInfos = {} @State markRuleListObj: MarkRules = {} @@ -112,10 +115,11 @@ struct JudgePage { @State artSubject3Projects: string[] = ['直线', '会车', '变道', '超车', '掉头', '停车'] @State artSubject3ProjectsCodesArr: string[] = ['3', '9', '4', '10', '12', '11'] @State manualMarkRules: MarkRule[] = [] + @State markRules: MarkRule[] = [] //科目三评判初始化数据 - @State systemparmArr: SYSTEMPARMARR[] = [] + @State systemparmArr: SYSTEM_PARAM[] = [] @State mapPointItemArr: MAPITEMPOINTITEM[] = [] - @State carinfoArr: CARINFO[] = [] + @State carinfoArr: CAR_INFO[] = [] @State mapPointArr: MAPPOINT[] = [] //手动项目是否在进行中 @State isManualProjectIn: boolean = false; @@ -145,6 +149,7 @@ struct JudgePage { @State isErrorMsgEnd: boolean = false @State disConnectErrorOpen: boolean = false @State @Watch("laneSignalChange") laneSignal: PerLane = InitialPerLane + public examTime: number = 0 public context = getContext(this) as common.UIAbilityContext; // 信号查看弹窗 signalTrajectoryDialogController: CustomDialogController = new CustomDialogController({ @@ -161,12 +166,14 @@ struct JudgePage { }), customStyle: true }) - private judge: Judge = new Judge(this) + // private judge: Judge = new Judge(this) + private judgeBusiness = new JudgeBusiness(this) // 结束考试弹窗 endExamDialogController: CustomDialogController = new CustomDialogController({ builder: ConfirmDialog({ text: "确认结束考试?", onConfirm: async () => { + dConsole.log(JudgeTag, "点击确认结束") if (this.isErrorMsgEnd) { dConsole.log(JudgeTag, "router back1") router.back() @@ -185,7 +192,7 @@ struct JudgePage { clearInterval(this.timer); clearInterval(AppStorage.get('judgeTimer')) try { - this.judge.checkExamIsEnd(true); + this.judgeBusiness.JudgeEnd(true); } catch (e) { dConsole.log(JudgeTag, "router back2") router.back() @@ -196,43 +203,16 @@ struct JudgePage { }) laneSignalChange() { - dConsole.log("车道信号变化1", this.laneSignal) - } - - async aboutToDisappear() { - this.generateExamRecordsDialogController.close() - this.signalTrajectoryDialogController.close() - clearInterval(this.mileageTimer) + // dConsole.log("车道信号变化1", this.laneSignal) } async aboutToAppear() { + DifferentialAndSignal.onMsg(this.onCenterMsg) this.carInfo = AppStorage.get('carInfo')! this.singlePlay = AppStorage.get('singlePlay')! this.startFullTime = dayTs().format("YYYYMMDDHHmmss"); this.startTime = dayTs().format("YYYY-MM-DD HH:mm:ss") this.startExamTime = dayTs().format("YYYY-MM-DD HH:mm:ss") - // let count = 0; - // const totalTimes = 1000; - // const intervalTime = 100; // 0.1秒 = 100毫秒 - // - // const timer = setInterval(() => { - // if (count < totalTimes) { - // dConsole.writeProcessData(ProcessDataEnumType.FourOneLogByteData, ProcessDataMock); - // dConsole.writeProcessData(ProcessDataEnumType.FourOneLogData, ProcessDataMock); - // dConsole.writeProcessData(ProcessDataEnumType.JudgeExamData, ProcessDataMock); - // dConsole.writeProcessData(ProcessDataEnumType.JudgeLogData, ProcessDataMock); - // dConsole.writeProcessData(ProcessDataEnumType.JudgeProgressCallbackData, ProcessDataMock); - // dConsole.writeProcessData(ProcessDataEnumType.PlcData, ProcessDataMock); - // dConsole.writeProcessData(ProcessDataEnumType.WuxiExam, ProcessDataMock); - // dConsole.writeProcessData(ProcessDataEnumType.WuxiProgressData, ProcessDataMock); - // count++; - // console.log(`已调用 ${count} 次`); - // } else { - // dConsole.closeProcessData() - // clearInterval(timer); - // console.log('已完成1000次调用'); - // } - // }, intervalTime); //初始化数据库表 await this.initDb() //断点续考 @@ -241,6 +221,15 @@ struct JudgePage { await this.initJudge(); } + async aboutToDisappear() { + this.generateExamRecordsDialogController.close() + this.signalTrajectoryDialogController.close() + this.judgeBusiness.close() + clearInterval(this.mileageTimer) + DifferentialAndSignal.offMsg(this.onCenterMsg) + + } + //初始化相关数据库表 async initDb() { this.examSubject = this.carInfo.examSubject!; @@ -282,8 +271,9 @@ struct JudgePage { FLAG: carInfo.flag!, BK1: carInfo.bk1!, BK2: carInfo.bk2!, + X_MCH: carInfo.x_mch || "", }) - dConsole.info(JudgeTag, 'surenjun =>carinfoArrr', JSON.stringify(this.carinfoArr)) + dConsole.info(JudgeTag, '=>carinfoArrr', JSON.stringify(this.carinfoArr)) } // 获取考生信息 @@ -323,6 +313,7 @@ struct JudgePage { if (Number(tempObj.markserial) > 100 && Number(tempObj.markserial) < 200) { this.manualMarkRules.push(tempObj) } + this.markRules.push(tempObj) tempObj.markserial = mark.markserial Reflect.set(this.markRuleListObj, `${mark.itemno}_${mark.markserial}`, tempObj) }) @@ -332,7 +323,7 @@ struct JudgePage { async initSysset(sysset?: SYSSET[]) { const syssetParams: SYSSET[] | MASYSSETTableType[] = sysset || await GetSyncData('MA_SYSSET') const serialNumberArr = (syssetParams as SYSSET[]).filter(sys => sys.v_no === '901'); - dConsole.info(JudgeTag, 'surenjun serialNumberArr' + JSON.stringify(serialNumberArr)) + dConsole.info(JudgeTag, 'serialNumberArr' + JSON.stringify(serialNumberArr)) this.serialNumber = (serialNumberArr[0] && serialNumberArr[0].v_value) || ''; const syssetJudgeConfigArr: SyssetConfig[] = [] @@ -401,113 +392,19 @@ struct JudgePage { } //初始化systemParam表 - async initSystemParam(sysParam?: MA_SYSTEMPARMType []) { - let systemParms: MA_SYSTEMPARMType[] = sysParam || await GetSyncData('MA_SYSTEMPARM') - - let currentParams: RouteParamsType = router.getParams() as RouteParamsType; - //小车车型列表 - const sCarTypes = ['C1', 'C2', 'C5'] - if (this.singlePlay) { - this.wayno = Number(currentParams.wayno) || 1; - } - //真实监管下发的项目 - let kStringArr: string[] = (currentParams.kString?.split(',') || []).filter(item => item); - dConsole.info(JudgeTag, 'surenjun kStringArr', JSON.stringify(kStringArr)) - let isInExam = kStringArr.length > 0; - let carNo = '', allItems: string[] = []; - systemParms.forEach((systemParm) => { - if (JudgeConfig.isTrajectoryOpen) { - systemParm.no1 = systemParm.NO1! + ''; - systemParm.no2 = systemParm.NO2! + ''; - systemParm.no3 = systemParm.NO3! + ''; - systemParm.txt1 = systemParm.TXT1!; - systemParm.txt2 = systemParm.TXT2!; - systemParm.txt3 = systemParm.TXT3!; - } - const txt1 = decodeURI(systemParm.txt1 || "") - const txt2 = decodeURI(systemParm.txt2 || "") - - const no1 = systemParm.no1; - const no2 = systemParm.no2; - const no3 = systemParm.no3; - - //获取当前考车的no2 - if (systemParm.no1 == "3" && systemParm.no3 == "1") { - if (txt1 === this.carName) { - carNo = systemParm?.no2 || "" - this.carlist = carNo - } - } - - //获取及格分数线 - if (systemParm.no1 == "3" && systemParm.no3 == "3" && carNo === systemParm.no2) { - this.passingScore = Number(txt1) || 0; - } - //根据车型获取应行驶里程数 - if (systemParm.no1 == "3" && systemParm.no3 == "15" && carNo === systemParm.no2) { - this.examMileage = ((decodeURI(systemParm.txt1 || "")) || '').split('^')[0]; - } - //获取当前考车的考试项目 - if (carNo !== '' && systemParm.no1 == "3" && systemParm.no2 == carNo && systemParm.no3 == "10") { - allItems = decodeURIComponent(systemParm.txt1 || "").split(',').filter(txt => txt !== '') - dConsole.info(JudgeTag, '考试项目', allItems) - } - if ( - //科目二获取项目 - (this.examSubject == "2" && allItems.length && systemParm.no1 == '6' && allItems.includes(systemParm?.no2 || "")) - || - //科目三获取项目 - (this.examSubject == "3" && systemParm.no1 == "6") - ) { - const name = decodeURI(systemParm.txt1 || "") - //小车过滤掉 夜间模拟行驶 - if (sCarTypes.includes(this.carType) && name === '夜间行驶') { - return - } - const currentProject: ProjectInfo = { - name, - abbreviation: decodeURI(systemParm.txt3 || ""), - projectCode: no2, - projectCodeCenter: txt2, - //是否是必考 加减档设置成非必考 - isRequired: no2 == '14' ? false : allItems.includes(no2 + ''), - //是否考过了 - isEnd: false, - //项目开始数据是否上传过 - isUpload: false, - } - const no2Num = Number(systemParm.no2) - //真实监管下发考试项目 - if (isInExam && !(kStringArr.includes(txt2) || kStringArr.includes(no2 + ''))) { - dConsole.info(JudgeTag, 'surenjun =>', txt2) - dConsole.info(JudgeTag, 'surenjun => no2', systemParm.no2) - currentProject.type = '3' - currentProject.isUpload = true - currentProject.isEnd = true - this.ddxkKsxmArr.push(txt2) - } - Reflect.set(this.projectsObj, no2Num, currentProject) - Reflect.set(this.projectsCenterObj, txt2, currentProject) - this.projects.push(currentProject); - } - this.systemparmArr.push({ - NO1: Number(systemParm.no1), - NO2: Number(systemParm.no2), - NO3: Number(systemParm.no3), - TXT1: decodeURIComponent(systemParm.txt1 || ""), - TXT2: decodeURIComponent(systemParm.txt2 || ""), - TXT3: decodeURIComponent(systemParm.txt3 || ""), - }) - }) - dConsole.log(JudgeTag, "考试项目", JSON.stringify(this.projects)) - if (!this.projects.length) { - Prompt.showToast({ - message: '读取数据库信息失败,请重新联网更新!', - duration: 8000 - }); - dConsole.log(JudgeTag, "router back3") - router.back(); - } + async initSystemParam(sysParam?: SYSTEM_PARAM[]) { + let result = await this.judgeBusiness.JudgeInit() + this.totalScore = result.totalScore + this.wayno = result.wayno + this.carlist = result.carlist + this.passingScore = result.passingScore + this.examMileage = result.examMileage + this.projectsObj = result.projectsObj + this.projectsCenterObj = result.projectsCenterObj + this.ddxkKsxmArr = result.ddxkKsxmArr + this.singlePlay = result.singlePlay + this.systemparmArr = result.systemparmArr + this.projects = result.projects } // 获取场地设备信息 @@ -542,7 +439,8 @@ struct JudgePage { const carlistArr = info.carlist === '' ? [] : (decodeURI(info.carlist || "").split(',') || []); const newKey = key.split('~').join('_') const xmdm = Number(key.split('~')[0]) - const currentProject: ProjectInfo = Reflect.get(this.projectsObj, xmdm) + const data: ProjectInfos = JSON.parse(JSON.stringify(this.projectsObj)) + const currentProject: ProjectInfo = Reflect.get(data, xmdm) if (currentProject && (carlistArr.length == 0 || carlistArr.includes(this.carlist))) { Reflect.set(this.itemInfoObj!, newKey, { modelKey: newKey, @@ -551,16 +449,17 @@ struct JudgePage { }) } }) + dConsole.info(JudgeTag, this.projectsObj, this.itemInfoObj) } // 评判相关初始化 async initJudge() { - await this.judge.onJudgeFn(async (judgeData: JudgeCallBacData) => { + this.judgeBusiness.JudgeStart((judgeData: JudgeCallBacData) => { + dConsole.log(JudgeTag, "扣分", judgeData.kfArr) this.xmmcStr = judgeData.xmmcStr || ""; this.carztStr = judgeData.carztStr || ""; - dConsole.log(JudgeTag, "扣分", judgeData.kfArr) this.kfArr = judgeData.kfArr || []; - }); + }) } // 断点续考判断 @@ -575,7 +474,7 @@ struct JudgePage { const examItems: string | undefined = currentParams?.examItems; // 2024-01-03 16:29:26;0;20300,;2,4^2,4;null; if (examItems !== '' && examItems !== undefined) { - dConsole.info(JudgeTag, 'surenjun examItems=>', JSON.stringify(examItems)) + dConsole.info(JudgeTag, 'examItems=>', examItems) const examItemsArrs = examItems.split(';'); const startTime = examItemsArrs[0] const ddxkKsxmArr = examItemsArrs[2]?.split(',').filter(item => item) || [] @@ -646,7 +545,7 @@ struct JudgePage { this.carInfo.examSubject = this.examSubject this.singlePlay = beginDataObj.exam == 0; this.carName = initDataObj.name; - await this.initSystemParam(initDataObj.systemparm as MA_SYSTEMPARMType[]) + await this.initSystemParam(initDataObj.systemparm) await this.initMarkRules(initDataObj.mark); await this.initSysset(initDataObj.sysset as SYSSET[]); } @@ -666,6 +565,61 @@ struct JudgePage { } } + //人工项目操作 + async setManualProjectFn(index: number) { + const isManualProjectIn = this.isManualProjectIn; + const artSubject3ProjectsCodesArr = this.artSubject3ProjectsCodesArr; + const projectsObj = this.projectsObj; + const projectCode = artSubject3ProjectsCodesArr[index] + let sideParkingStatus = GetIsExitManualProject(index, this.judgeConfigObj, this.artSubject3ProjectsCodesArr, this.projectsObj, this.carztStr, this.isManualProjectIn, this.isProjectIn, this.jl, this.examMileage, this.isRequiredProjectsEnd, this.lane) + if (index === 5) { + dConsole.info(JudgeTag, '靠边停车状态=> ', sideParkingStatus) + } + const currentProject: ProjectInfo = Reflect.get(projectsObj, projectCode) + if (sideParkingStatus) { + // 正在进行的项目 取消项目 + if (isManualProjectIn && currentProject.type == '2') { + //判断人工是否能取消项目 && 当前项目有扣分的不能取消 + if (Reflect.get(this.judgeConfigObj, '340') == 1) { + // TODO + // await this.judge.setJudgeItem(projectCode, 2); + Prompt.showToast({ + message: '项目取消', + duration: 2000 + }) + return + } + } + + // 靠边停车时候可以触发 + if (Reflect.get(this.judgeConfigObj, '343') === '0') { + const xmmcStr = this.xmmcStr; + if (xmmcStr == '无' || xmmcStr == '') { + //512[6] 人工项目按钮放大确认 + const param512: string[] = (Reflect.get(this.judgeConfigObj, '512') || '').split(','); + dConsole.info(JudgeTag, param512) + if (param512[6] !== '0') { + this.amplifiedImgIndex = index; + this.isAmplifyPopShow = true + } else { + // TODO + // await this.judge.setJudgeItem(projectCode, 1); + } + } else { + if (index === 5) { + Prompt.showToast({ + message: `${xmmcStr}未结束,不允许靠边停车`, + duration: 8000 + }); + } + } + } else { + this.amplifiedImgIndex = index; + this.isAmplifyPopShow = true + } + } + } + // 信号区域 @Builder logoExpansionBuilder() { @@ -705,6 +659,9 @@ struct JudgePage { jl: this.jl, wayno: this.wayno, judgeConfigObj: this.judgeConfigObj, + onTimeUpdate: (time) => { + this.examTime = time + } }) // 扣分列表和评判列表 JudgeAndProjectComponent({ @@ -733,6 +690,8 @@ struct JudgePage { // 操作区域,分数显示区域 OperatingAreaComponent({ + kfArr: this.kfArr, + isAllProjectsEnd: this.isAllProjectsEnd, totalScore: this.totalScore, kszp: this.kszp, examSubject: this.examSubject, @@ -779,7 +738,8 @@ struct JudgePage { confirmMark: async (item: string, serial: string) => { clearTimeout(this.popTimer) this.popTimer = setTimeout(async () => { - await this.judge.setJudgeMark(item, serial); + // TODO + // await this.judge.setJudgeMark(item, serial); this.isDeductedPopShow = false this.popTimer = null; }, 500) @@ -795,7 +755,8 @@ struct JudgePage { confirmAmplify: async (amplify: AmplifyItem) => { clearTimeout(this.popTimer) this.popTimer = setTimeout(async () => { - await this.judge.setJudgeItem(amplify.projectCode, 1); + // TODO + // await this.judge.setJudgeItem(amplify.projectCode, 1); this.isAmplifyPopShow = false this.popTimer = null; }, 500) @@ -831,7 +792,7 @@ struct JudgePage { confirmFn: () => { clearInterval(this.timer); // clearInterval(AppStorage.get('judgeTimer')) - this.judge.checkExamIsEnd(true); + this.judgeBusiness.JudgeEnd(true); }, }) } @@ -839,56 +800,33 @@ struct JudgePage { .height('100%').backgroundColor('#000').justifyContent(FlexAlign.Start) } - //人工项目操作 - async setManualProjectFn(index: number) { - const isManualProjectIn = this.isManualProjectIn; - const artSubject3ProjectsCodesArr = this.artSubject3ProjectsCodesArr; - const projectsObj = this.projectsObj; - const projectCode = artSubject3ProjectsCodesArr[index] - let sideParkingStatus = GetIsExitManualProject(index, this.judgeConfigObj, this.artSubject3ProjectsCodesArr, this.projectsObj, this.carztStr, this.isManualProjectIn, this.isProjectIn, this.jl, this.examMileage, this.isRequiredProjectsEnd, this.lane) - if (index === 5) { - dConsole.info(JudgeTag, 'surenjun 靠边停车状态=> ', sideParkingStatus) - } - const currentProject: ProjectInfo = Reflect.get(projectsObj, projectCode) - if (sideParkingStatus) { - // 正在进行的项目 取消项目 - if (isManualProjectIn && currentProject.type == '2') { - //判断人工是否能取消项目 && 当前项目有扣分的不能取消 - if (Reflect.get(this.judgeConfigObj, '340') == 1) { - await this.judge.setJudgeItem(projectCode, 2); - Prompt.showToast({ - message: '项目取消', - duration: 2000 - }) - return - } + private onCenterMsg = (msg: string) => { + let result: WorkerBackMessage = JSON.parse(msg) + if (result.type === WorkerBackMessageType.RemoteEndExam) { + dConsole.info(JudgeTag, msg) + this.judgeBusiness.JudgeEnd(true) + } else if (result.type === WorkerBackMessageType.RemoteKf) { + let data = result.data as number[] + const config810 = this.judgeConfigObj.param_810 + dConsole.info(JudgeTag, '评判收到远程扣分项目内容:' + `kfxh=>${data[1]}; directives=>${data[0]}`) + let currentKf = this.markRules.filter(item => { + return item.kfxh === data[1].toString() && (config810 === "1" || Number(item.markserial) > 99) + })[0] + if (!currentKf) { + return } - - // 靠边停车时候可以触发 - if (Reflect.get(this.judgeConfigObj, '343') === '0') { - const xmmcStr = this.xmmcStr; - if (xmmcStr == '无' || xmmcStr == '') { - //512[6] 人工项目按钮放大确认 - const param512: string[] = (Reflect.get(this.judgeConfigObj, '512') || '').split(','); - dConsole.info(JudgeTag, 'surenjun', param512) - if (param512[6] !== '0') { - this.amplifiedImgIndex = index; - this.isAmplifyPopShow = true - } else { - await this.judge.setJudgeItem(projectCode, 1); - } - } else { - if (index === 5) { - Prompt.showToast({ - message: `${xmmcStr}未结束,不允许靠边停车`, - duration: 8000 - }); - } + dConsole.info(JudgeTag, '远程扣分项目:', currentKf) + this.judgeBusiness.setJudgeMark(currentKf.itemno!, currentKf.markserial!, 2) + DifferentialAndSignal.sendMsg({ + type: WorkerMessageDataType.JudgeSend, + data: { + remoteType: 'kf', + remoteData: [data[0]] } - } else { - this.amplifiedImgIndex = index; - this.isAmplifyPopShow = true - } + }) + } else if (result.type === WorkerBackMessageType.StopExam) { + const config392 = (this.judgeConfigObj.param_392 || '20,81').split(','); + this.judgeBusiness.setJudgeMark(Number(config392[0]), config392[1], 2) } } } diff --git a/entry/src/main/ets/pages/Judge/BaseJudgeBussines.ets b/entry/src/main/ets/pages/Judge/BaseJudgeBussines.ets new file mode 100644 index 0000000..8d81952 --- /dev/null +++ b/entry/src/main/ets/pages/Judge/BaseJudgeBussines.ets @@ -0,0 +1,902 @@ +import { + JudgeBeginObj, + JudgeCallBackData, + JudgeConfigObj, + JudgeInitObj, + JudgeSound, + KmItem, + MarkRule, + ProcessDataEnumType, + Project, + ProjectInfo, + ProjectInfos, + SYSTEM_PARAM, + User, + WorkerMessageDataType, + WR +} from '../../model' +import JudgeBusiness from './JudgeBusiness' +import { JudgePage } from '../Judge' +import VoiceAnnounce from '../judgeSDK/utils/voiceAnnouncements' +import { dConsole } from '../../utils/LogWorker' +import { ExamProcessDataTag, JudgeConfig, JudgeTag, QueueTag } from '../../config' +import { + examJudgeArtificialItem, + examJudgeBeginExam, + examJudgeEndExam, + examJudgeInit, + examJudgeSetLogCallback, + examJudgeSetPerformCallback, + examJudgeSetRealExamCallback, + examJudgeSoundEnd +} from './JudgeSDKUtils' +import { DeductPoints, ProjectEnd, ProjectStart, TheExamIsOver, UploadProgressPhoto } from './ProcessDataProcessing' +import { endRecordVideo, saveStartRecordVideo } from '../../utils/Video' +import router from '@ohos.router' +import { GetSyncData, UpdateTableByArray } from '../../utils/table/Operation' +import { CurrentProjectConversion, DeductionProjectConversion, DetectingDifferences, GetCarStatus } from './utils' +import { DifferentialAndSignal } from '../../utils/business/DifferentialAndSignalWorker' +import dayTs from '../../utils/Date' + + +export interface GetSysSetResult { + totalScore: number + wayno: number + carlist: string + passingScore: number + examMileage: string + projectsObj: ProjectInfos + projectsCenterObj: ProjectInfos + ddxkKsxmArr: Array + singlePlay: boolean + systemparmArr: Array + projects: Array +} + +export interface BaseJudgeImpl { + getIsUdpEnd: () => boolean + JudgeInit: (judgeUI: JudgePage, that: JudgeBusiness) => Promise + JudgeStart: (callBack: Function, judgeUI: JudgePage, that: JudgeBusiness) => void + Judging: (strData: string, callBack: Function, judgeUI: JudgePage, that: JudgeBusiness) => void + JudgeEnd: (judgeUI: JudgePage, that: JudgeBusiness, isManual?: boolean) => void +} + +export const SetJudgeItem = async (itemno: string, type: 1 | 2) => { + await examJudgeArtificialItem(Number(itemno), type); + const str = JSON.stringify({ + method: 'examJudgeArtificialItem', + itemno: Number(itemno), + type + }) + dConsole.writeProcessData(ProcessDataEnumType.JudgeExamData, str) + dConsole.info(JudgeTag, `人工评判${type == 1 ? '进入' : '取消'}项目-${itemno}`) +} + +export class BaseJudge { + private isUdpEnd: boolean = false + + getIsUdpEnd() { + return this.isUdpEnd + } + + async goJudgeVoice(sound: JudgeSound, avPlayer: VoiceAnnounce) { + dConsole.info(JudgeTag, '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`]) + } + } + + /** + * 改变考试状态 + * old goVoiceAnnounce + * @param event + * @param xmdm + * @param kf + * @param judgeUI + * @param that + */ + async changeExamStatus(event: number, xmdm: number, xmxh: string, kf: MarkRule[], judgeUI: JudgePage, 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.xmmcSingleCode = "0"; + // judgeTask.addTask(async () => { + // console.info(judgeTag, `项目开始-${xmdm}-${projectsObj[xmdm].name}`) + // await beginProject(xmdm, xmxh) + // }, { + // isDelay: true + // }) + // judgeTask.addTask(async () => { + // console.info(judgeTag, `项目-${xmdm}-上传照片 start`) + // await uploadProgressPhoto(xmdm) + // }, { + // isDelay: true + // }) + ProjectStart(xmdm, xmxh, judgeUI) + UploadProgressPhoto(xmdm, that.plcData!, judgeUI) + } + // this.judgeUI.projectsObj[xmdm].isUpload = true + + break; + } + case 2: { + dConsole.log(JudgeTag, ExamProcessDataTag, "项目结束判定1") + const project: ProjectInfo = Reflect.get(judgeUI.projectsObj, xmdm) + // const isStart = await this.checkProjectIsStart(xmdm, 1, judgeUI, that, kf) + + // if (isStart) { + // // 项目结束了就不再生成数据 + // dConsole.info(JudgeTag, ExamProcessDataTag, ' 项目是否结束 =>', project.isEnd) + // if (!project.isEnd) { + // judgeTask.addTask(async () => { + // dConsole.info(JudgeTag, `项目结束-${xmdm}-${project.name}`) + // await endProject(xmdm); + // this.xmmcSingleCode = '0'; + // this.xmmcEndCode = undefined; + // }, { + // isDelay: true + // }) + ProjectEnd(xmdm, xmxh, judgeUI) + // } + // } + dConsole.log(JudgeTag, ExamProcessDataTag, "项目结束判定3") + try { + const param512: JudgeConfigObj = (Reflect.get(judgeUI.judgeConfigObj, '512') || '').split(','); + if (!judgeUI.isProjectIn) { + that.deductedPopShowTimer = setTimeout(() => { + judgeUI.isDeductedPopShow = false + }, (Reflect.get(param512!, 5) || 0) * 1000) + } + } catch (e) { + dConsole.error(JudgeTag, "项目结束后弹窗定时器异常", e) + } + project.isEnd = true; + dConsole.log(JudgeTag, "项目结束判定4") + break; + } + case 3: { + dConsole.log(JudgeTag, "扣分开始") + const currentKf = kf[kf.length -1]; + if (JudgeConfig.kfVoiceOpen || (judgeUI.examSubject == "2" && Reflect.get(judgeUI.judgeConfigObj, '618') === "1") || (judgeUI.examSubject == "3" && Reflect.get(judgeUI.judgeConfigObj, '418') === "1")) { + that.avPlayer?.playAudio([`voice/${currentKf.markcatalog}.mp3`, + `voice/mark_${Math.abs(currentKf?.score || 0)}.mp3`]) + } + // const isStart = await this.checkProjectIsStart(Number(currentKf.xmdm), 2, judgeUI, that, kf); + // if (isStart) { + // await judgeTask.addTask(async () => { + // dConsole.info(JudgeTag, `项目扣分-${currentKf.markcatalog}-${currentKf.desc}`) + // await pointsDedute(Number(currentKf.xmdm), currentKf) + // }, { + // isDelay: true + // }) + DeductPoints(Number(currentKf.xmdm), currentKf, that.xmmcEndCode || "", judgeUI) + if (judgeUI.totalScore < judgeUI.passingScore) { + try { + ProjectEnd(xmdm, xmxh, judgeUI) + } catch (e) { + dConsole.info(e) + } + } + // } + break + } + case 5: { + dConsole.log(JudgeTag, QueueTag, "考试结束") + const singlePlay = AppStorage.get('singlePlay') + // 关闭录像 + if (!singlePlay && that.videoData) { + await endRecordVideo(that.videoData) + } + // TODO + // ProcessDataTaskPoolInstance.setOnAllTasksCompletedCallback((data) => { + // if (event === 5) { + // dConsole.log(JudgeTag, QueueTag, "这才是考试结束判定") + // } + // dConsole.log(JudgeTag, QueueTag, "考试结束判断", data) + // }) + // judgeTask.addTask(async () => { + // dConsole.info(JudgeTag, '考试结束 start') + // AppStorage.setOrCreate('isJudge', false) + await this.handEndExam(judgeUI, that) + // }) + break + + } + default: + break + } + if (event === 2 || event === 3) { + dConsole.log(JudgeTag, "项目结束判定统计项目") + await this.setCountItems(judgeUI); + await this.judgeEnd(judgeUI, that) + } + } + + /** + * 统计必考项目,所有项目,已考数量 + */ + async setCountItems(judgeUI: JudgePage) { + dConsole.log(JudgeTag, "项目结束判定,统计考试项目") + const projectsObj: object = judgeUI.projectsObj; + //必考项目数量 必考项目已考数量 所有考试项目数量 项目已考项目数量 + let projectNum = 0, endProjectsNum = 0, allProjectNum = 0, allEndProjectsNum = 0; + Reflect.ownKeys(projectsObj).forEach(projectKey => { + const projectObj: ProjectInfo = Reflect.get(projectsObj, projectKey) + const type = projectObj.type + const ykType = projectObj.ykType + const isRequired = projectObj.isRequired + allProjectNum += 1; + if (type == '3' || type == '4' || ykType === "3" || ykType === "4") { + allEndProjectsNum += 1; + } + + if (isRequired) { + projectNum += 1; + if (type == '3' || type == '4' || ykType === "3" || ykType === "4") { + endProjectsNum += 1; + } + } + }) + dConsole.info(JudgeTag, '项目状态' + JSON.stringify(projectsObj)); + dConsole.info(JudgeTag, '所有考试项目数量:' + allProjectNum) + dConsole.info(JudgeTag, '必考项目数量:' + projectNum) + dConsole.info(JudgeTag, '必考项目已考数量:' + endProjectsNum) + judgeUI.isRequiredProjectsEnd = (projectNum - endProjectsNum === 0) + judgeUI.isAllProjectsEnd = (allProjectNum - allEndProjectsNum === 0) + } + + /** + * 结束考试 + */ + async handEndExam(judgeUI: JudgePage, that: JudgeBusiness) { + judgeUI.endExamDialogController.close(); + judgeUI.generateExamRecordsDialogController.open(); + judgeUI.isDeductedPopShow = false; + + const param302 = judgeUI.judgeConfigObj.param_302; + //自动退出待验证并且不合格 + if (!that.isManual && judgeUI.examSubject === "3" && (param302 === "1" || (judgeUI.singlePlay && param302 === "2")) && judgeUI.totalScore < judgeUI.passingScore) { + that.avPlayer?.playAudio([`voice/考试结束.mp3`]) + } + //联网模式下:项目没有做完、当前分数大于及格分;手动结束直接退出 + if (!judgeUI.singlePlay && that.isManual && !judgeUI.isAllProjectsEnd && judgeUI.totalScore >= judgeUI.passingScore) { + that.avPlayer?.playAudio(['voice/empty.mp3'], true, () => { + this.isUdpEnd = true + dConsole.log(JudgeTag, "考试结束自动退出1") + router.back(); + }) + return + } + that.avPlayer?.playAudio(['voice/exam_waiting.mp3'], judgeUI.singlePlay, async () => { + + if (judgeUI.singlePlay) { + // 单机结束 + await this.endExam(judgeUI, that) + } else { + TheExamIsOver(judgeUI, that, async (res: WR) => { + dConsole.log(JudgeTag, ExamProcessDataTag, "考试结束接口完成", res) + const code = res.code!.toString() + if (code !== "1") { + that?.avPlayer?.playAudio(['voice/监管失败.mp3']) + judgeUI.errorMsg = decodeURIComponent(res?.message || "") + if (code.toString() === "2300028" || code.toString() === "2300007") { + judgeUI.errorMsg = '当前的考试过程信息监管审核未通过,程序将退出!' + } + judgeUI.generateExamRecordsDialogController.close(); + return + } else { + await this.endExam(judgeUI, that) + } + }) + } + + }) + } + + // 考试结束 Todo + async endExam(judgeUI: JudgePage, that: JudgeBusiness) { + const singlePlay = judgeUI.singlePlay + //TODO 断网考试结束补传 + // await uploadDisConnectData(); + // let backTimeOut = setTimeout(() => { + // router.back() + // }, 90 * 1000) + + console.info(JudgeTag, '考试结束 end') + const param302 = judgeUI.judgeConfigObj.param_302; + let currentKssycs = 0; + let voiceURL = '' + if (judgeUI.examSubject === "2") { + if (judgeUI.isAllProjectsEnd) { + voiceURL = (judgeUI.totalScore < judgeUI.passingScore ? `voice/unqualified_${judgeUI.kssycs === "1" ? 'one' : 'two'}.wav` : 'voice/qualified.mp3') + } else { + voiceURL = `voice/unqualified_${judgeUI.kssycs === "1" ? 'one' : 'two'}.wav` + currentKssycs = judgeUI.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 (judgeUI.examSubject === "3") { + if (judgeUI.isAllProjectsEnd) { + if (judgeUI.totalScore < judgeUI.passingScore) { + voiceURL = `voice/${judgeUI.kssycs === "1" ? 'exam_no_pass_finish' : 'exam_no_pass'}.mp3` + currentKssycs = judgeUI.kssycs === "1" ? 0 : 1 + } else { + voiceURL = 'voice/exam_pass.mp3' + currentKssycs = 0 + } + } else { + voiceURL = `voice/${judgeUI.kssycs === "1" ? 'exam_no_pass_finish' : 'exam_no_pass'}.mp3` + currentKssycs = judgeUI.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'); + let user = USER[0] + user.kssycs = currentKssycs.toString() + dConsole.info(JudgeTag, `更新后学员信息`, user) + try { + await UpdateTableByArray('USER', [user]) + } catch (e) { + dConsole.error(JudgeTag, `更新学员信息失败`, e) + } + dConsole.info(JudgeTag, `考试成绩:${judgeUI.totalScore}`) + if (!singlePlay) { + // await uploadProgressData(); + } + // clearTimeout(backTimeOut) + //语音播放扣分项 + let score = 0; + //结束考试时候是否播报一遍所有扣分 + const param634 = judgeUI.judgeConfigObj.param_634; + if (judgeUI.kfArr.length && ((judgeUI.examSubject === "2" && param634 === "1") || judgeUI.examSubject === "3")) { + that.avPlayer?.playAudio([`voice/kfdesc.mp3`], false, () => { + try { + judgeUI.kfArr.forEach((kf, index) => { + score += Math.abs(Number(kf.score)); + //TODO 考试分数待替换 + if (score <= (judgeUI.examSubject === "3" ? 10 : 20)) { + if (judgeUI.kfArr.length - 1 === index) { + that.avPlayer?.playAudio([`voice/${kf.markcatalog}.mp3`, voiceURL], false, () => { + this.isUdpEnd = true + dConsole.log(JudgeTag, "考试结束自动退出2") + router.back(); + }) + // throw new Error('End Loop') + } + that.avPlayer?.playAudio([`voice/${kf.markcatalog}.mp3`]) + } else { + that.avPlayer?.playAudio([`voice/${kf.markcatalog}.mp3`, voiceURL], false, () => { + this.isUdpEnd = true + dConsole.log(JudgeTag, "考试结束自动退出3") + router.back(); + }) + // throw new Error('End Loop') + } + }) + this.isUdpEnd = true + try { + if (!judgeUI.singlePlay) { + console.log("四合一结束1") + let startTime: Date = AppStorage.get("startTime") || new Date() + DifferentialAndSignal.sendMsg({ type: WorkerMessageDataType.JudgeSend, data: { + judgeUdpEnd: this.isUdpEnd, + judgeExamEnd: true, + performInfo: that.performInfo, + business: { + totalScore: that.judgeUI.totalScore, + kfArr: that.judgeUI.kfArr, + startTime: dayTs(startTime).format("HHmmssSSS"), + xmmcSingleCode: that.xmmcSingleCode, + kmItems: that.kmItems, + examTime: that.judgeUI.examTime, + cdsbInfoObj: that.judgeUI.cdsbInfoObj!, + xmdm: that.xmdm, + xmxh: that.xmxh + } } }) + } + } catch (e) { + console.info(JudgeTag, JSON.stringify(e)) + } + } catch (e) { + console.info(JudgeTag, JSON.stringify(e)) + } + }) + } else { + that.avPlayer?.playAudio([voiceURL], true, () => { + setTimeout(() => { + this.isUdpEnd = true + try { + if (!judgeUI.singlePlay) { + console.log("四合一结束2") + let startTime: Date = AppStorage.get("startTime") || new Date() + DifferentialAndSignal.sendMsg({ type: WorkerMessageDataType.JudgeSend, data: { + judgeUdpEnd: this.isUdpEnd, + judgeExamEnd: true, + performInfo: that.performInfo, + business: { + totalScore: that.judgeUI.totalScore, + kfArr: that.judgeUI.kfArr, + startTime: dayTs(startTime).format("HHmmssSSS"), + xmmcSingleCode: that.xmmcSingleCode, + kmItems: that.kmItems, + examTime: that.judgeUI.examTime, + cdsbInfoObj: that.judgeUI.cdsbInfoObj!, + xmdm: that.xmdm, + xmxh: that.xmxh + } } }) + } + } catch (e) { + console.info(JudgeTag, JSON.stringify(e)) + } + dConsole.log(JudgeTag, "考试结束自动退出5") + router.back(); + }, param302 === "8" ? 3000 : 0) + }) + } + } + + /** + * 检测扣分、结束项目时该项目是否开始 + */ + // async checkProjectIsStart(xmdm: number, currentType: 1 | 2, judgeUI: JudgePage, that: JudgeBusiness, kf?: MarkRule[]): Promise { + // if (xmdm == 20) { + // return true + // } + // const currentProject: ProjectInfo = Reflect.get(judgeUI.projectsObj, xmdm) + // + // if (!currentProject.isUpload) { + // dConsole.info(JudgeTag, '项目补传开始') + // // judgeTask.addTask(async () => { + // // await this.beginProject(xmdm) + // // }, { + // // isDelay: true + // // }) + // // judgeTask.addTask(async () => { + // // await this.uploadProgressPhoto(xmdm) + // // }, { + // // isDelay: true + // // }) + // ProjectStart(xmdm, xmxh, judgeUI) + // UploadProgressPhoto(xmdm, that.plcData!, judgeUI) + // currentProject.isUpload = true; + // Reflect.set(judgeUI.projectsObj, xmdm, currentProject) + // if (currentType == 2) { + // //项目结束需要等补传完毕 + // // judgeTask.addTask(async () => { + // // await this.pointsDedute(xmdm, kf!) + // // }, { + // // isDelay: true + // // })\ + // const currentKf = kf[kf.length -1]; + // DeductPoints(Number(currentKf.xmdm), currentKf, that.xmmcEndCode || "", judgeUI) + // } + // //扣分补传判断是否合格 不合格补传项目结束 + // if (currentType == 1 || (currentType == 2 && that.totalScore < judgeUI.passingScore)) { + // // judgeTask.addTask(async () => { + // // await this.endProject(xmdm) + // // }, { + // // isDelay: true + // // }) + // ProjectEnd(xmdm, that.xmxh, judgeUI) + // currentProject.isEnd = true; + // Reflect.set(judgeUI.projectsObj, xmdm, currentProject) + // } + // // judgeTask.addTask(async () => { + // // this.checkExamIsEnd() + // // }) + // return false; + // } + // return true + // } + + async judgeStart(callBack: Function, judgeUI: JudgePage, that: JudgeBusiness, beginExamInfo: JudgeBeginObj, initInfo: JudgeInitObj) { + this.isUdpEnd = false + const name = judgeUI.name + const kssycs = judgeUI.kssycs + // 处理远程扣分使用 + // 处理单机模式 + const isTrajectoryOpen = JudgeConfig.isTrajectoryOpen; + const isJudgeInitBool = AppStorage.get('isJudgeInitBool'); + const trajectoryPath = JudgeConfig.trajectoryPath; + let strArr: string[] = []; + if (isTrajectoryOpen) { + const folderPath = await that.fileUtil.initFolder(trajectoryPath); + const str: string = await that.fileUtil.readFile(folderPath) + strArr = str.split('\n') + } + //日志回调 + dConsole.info(JudgeTag, '1.进入评判入口') + await examJudgeSetLogCallback(3, async (level: number, info: string, len: number) => { + dConsole.log(JudgeTag, '评判日志:' + info) + dConsole.writeProcessData(ProcessDataEnumType.JudgeLogData, info) + }) + + dConsole.info(JudgeTag, '2.注册日志回调完成') + + //相关评判初始化只做一次 + if (!isJudgeInitBool) { + dConsole.log(JudgeTag, "评判初始化参数", initInfo) + await examJudgeInit(initInfo); + AppStorage.setOrCreate('isJudgeInitBool', true) + dConsole.info(JudgeTag, '4.评判初始化完成') + } + dConsole.writeProcessData(ProcessDataEnumType.JudgeExamData, JSON.stringify(initInfo)) + AppStorage.setOrCreate('isJudge', true) + // 2.评判过程回调 + await examJudgeSetRealExamCallback(async (strData: string, len: number) => { + // 评判回调日志 + dConsole.writeProcessData(ProcessDataEnumType.JudgeProgressCallbackData, strData) + dConsole.info(JudgeTag, '评判回调数据', strData) + await this.judging(strData, callBack, judgeUI, that) + }) + await examJudgeSetPerformCallback(async (info: string) => { + // dConsole.info('评判实时数据', info) + that.performInfo = JSON.parse(info) + const jl = Math.floor((that.performInfo!.qjjl + that.performInfo!.dcjl) / 100); + if (jl > Number(judgeUI.examMileage)) { + that.JudgeEnd() + } + judgeUI.jl = jl + judgeUI.laneSignal = that.performInfo!.lane + }) + + // 3.开始考试 + if (beginExamInfo) { + await examJudgeBeginExam(beginExamInfo); + dConsole.writeProcessData(ProcessDataEnumType.JudgeExamData, JSON.stringify(beginExamInfo)) + } + dConsole.info(JudgeTag, '6.开始考试注册完成') + that.avPlayer?.playAudio([judgeUI.singlePlay ? 'voice/ksks.wav' : 'voice/监管成功.mp3']) + if (!judgeUI.singlePlay) { + that.videoData = await saveStartRecordVideo(`${name}_${kssycs}`, that.context) + } + judgeUI.draw = true + // 处理单机泡轨迹模式 + if (isTrajectoryOpen) { + that.SingleMachineTrajectory(strArr) + return + } + }; + + async judging(strData: string, callBack: Function, judgeUI: JudgePage, that: JudgeBusiness) { + let examData: JudgeCallBackData = JSON.parse(strData); + const carzt = examData.carzt + const xmks = examData.xmks + const kf = examData.kf + const event = examData.event + const xmjs = examData.xmjs + const xmqx = examData.xmqx + const ksjs = examData.ksjs + const sound = examData.sound + const mndg = examData.mndg + const lane = examData.lane + const precast = examData.precast + const nongps = examData.nongps + //获取项目结束、项目开始代码 + const xmdm = event == 2 ? xmjs.xmdm : xmks.xmdm + const xmxh = event == 2 ? xmjs.xmxh : xmks.xmxh; + let artSubject3ProjectsCodesArr: number[] = [3, 9, 4, 10, 12, 11] + const isManualProjectIn = artSubject3ProjectsCodesArr.includes(xmdm); + const examSubject = judgeUI.examSubject + switch (event) { + // 项目开始 + case 1: { + dConsole.info(JudgeTag, "项目开始") + const project: ProjectInfo = Reflect.get(judgeUI.projectsObj, xmdm) + project.type = '2'; + if (isManualProjectIn) { + //手动项目是否在进行中 + judgeUI.isManualProjectIn = true + } + if (xmdm == 41 && examSubject == '3') { + that.rmndg = 1 + } + 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; + that.xmmcSingleCode = xmmcSingleCode + that.xmmcEndCode = xmmcCode + that.xmdm = xmdm; + that.xmxh = xmxh; + judgeUI.isProjectIn = true + Reflect.set(judgeUI.projectsObj, xmdm, project) + Reflect.set(that.kmItems, xmmcCode || 0, kmItem) + break; + } + // 项目结束 + case 2: { + dConsole.info(JudgeTag, "项目结束") + 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) => { + const fillProject: ProjectInfo = Reflect.get(judgeUI.projectsObj, projectKey) + return fillProject.type == '2' + }).length) > 0; + if (isManualProjectIn) { + judgeUI.isManualProjectIn = false + } + const kmItem: KmItem = Reflect.get(that.kmItems, xmmcCode) + kmItem.status = 3; + //统计必考项目数量 + that.xmmcStr = '无'; + that.xmmcCode = ''; + that.xmdm = ''; + judgeUI.currentXmdm = undefined; + Reflect.set(judgeUI.projectsObj, xmdm, project) + Reflect.set(that.kmItems, xmmcCode, kmItem) + break; + } + // 扣分 + case 3: { + dConsole.info(JudgeTag, "项目扣分") + const thisKf = DeductionProjectConversion(`${kf.xmdm}_${kf.kfdm}`, judgeUI.markRuleListObj) + const kfObj: MarkRule = { + //扣分项目名称 + xmmcStr: CurrentProjectConversion(kf.xmdm, judgeUI.projectsObj), + xmdm: kf.xmdm + "", + //扣分描述 + desc: thisKf.desc, + //扣分分数 + score: thisKf.score, + // 扣分无锡所代码 + markcatalog: thisKf.markcatalog, + markserial: thisKf.markserial, + kfxh: thisKf.kfxh, + //扣分类型 + type: kf.type + } + dConsole.log(JudgeTag, "扣分组装", kfObj) + judgeUI.kfArr.push(kfObj) + dConsole.log(JudgeTag, "扣分类组装", judgeUI.kfArr) + judgeUI.totalScore += Number(thisKf?.score); + if (kf.xmdm != 20) { + const project: ProjectInfo = Reflect.get(judgeUI.projectsObj, kf.xmdm) + const type = project.type; + project.type = (type == '3' || type == '4') ? '4' : '5' + Reflect.set(judgeUI.projectsObj, kf.xmdm, project) + } + break; + } + // 考试状态 + case 4: { + that.carztStr = GetCarStatus(carzt); + break; + } + // 考试结束 + case 5: { + dConsole.info(JudgeTag, "考试结束距离1", ksjs) + that.ksjs = ksjs; + dConsole.writeProcessData(ProcessDataEnumType.JudgeExamData, JSON.stringify({ + method: 'examJudgeEndExam' + })) + break; + } + // 项目取消 + 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: { + dConsole.info(JudgeTag, '播放语音'); + this.goJudgeVoice(sound, that.avPlayer!) + break; + } + // 模拟灯光事件 + case 8: { + that.mndgStr = mndg + break; + } + // 车道和路段变化 + case 9: { + judgeUI.lane = lane + that.lane = lane; + break; + } + // 预进项目事件 + case 10: { + dConsole.info(JudgeTag, '预进项目'); + const xmdm = precast.xmdm + const xmxh = precast.xmxh + const project: ProjectInfo = Reflect.get(judgeUI.projectsObj, xmdm) + const xmmcCode: string = project.projectCodeCenter!; + const xmmcSingleCode: string = project.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: { + DetectingDifferences(nongps.type, that.avPlayer!) + break; + } + default: + break; + } + callBack({ + //项目名称 考车状态 扣分arr + xmmcStr: that.xmmcStr, carztStr: that.carztStr, kfArr: judgeUI.kfArr + }); + // TODO 语音播报 + this.changeExamStatus(event, xmdm, xmxh, judgeUI.kfArr!, judgeUI, that); + // 更新ui + if (event == 1 || event == 2 || event == 3 || event == 6) { + judgeUI.projectsObj = JSON.parse(JSON.stringify(judgeUI.projectsObj)) + } + } + + async judgeEnd(judgeUI: JudgePage, that: JudgeBusiness, isManual?: boolean) { + dConsole.info(JudgeTag, '收到远程结束考试消息3') + const isAllProjectsEnd = judgeUI.isAllProjectsEnd + const examSubject = judgeUI.examSubject + const singlePlay = judgeUI.singlePlay + const totalScore = Number(judgeUI.totalScore) + const judgeConfigObj = judgeUI.judgeConfigObj + const examMileage = Number(judgeUI.examMileage) + const passingScore = Number(judgeUI.passingScore) + const jl = judgeUI.jl + if (that.isExamEnd) { + dConsole.log("JudgeTag", "已经结束考试") + return + } + if (isManual) { + dConsole.log(JudgeTag, '收到远程结束考试消息5') + judgeUI.generateExamRecordsDialogController.close() + // 考试不合格 + await examJudgeEndExam() + that.isExamEnd = true + that.isManual = true + } else { + const param302: number = Reflect.get(judgeConfigObj, '302') + const param342: number = Reflect.get(judgeConfigObj, '342') + const param512: number[] = (Reflect.get(judgeConfigObj, '512') || '').split(','); + dConsole.log(JudgeTag, '收到远程结束考试消息4') + //单机模式 + if (singlePlay) { + dConsole.info(JudgeTag + ' 单机模式结束 => ', isAllProjectsEnd) + if (isAllProjectsEnd && jl >= examMileage) { + //成绩合格 + if (totalScore >= passingScore && !that.isEndTip) { + if (examSubject == '3' && (param342 == 0 || param342 == 2) && + (param302 != 6 && param302 != 7 && param302 != 8)) { + if (param512[7] != 0) { + clearTimeout(that.deductedPopShowTimer) + that.avPlayer?.playAudio(['voice/综合评判.mp3']) + judgeUI.isDeductedPopShow = true + judgeUI.defaultTabIndex = 1 + that.isEndTip = true + return + } + } else { + await examJudgeEndExam() + that.isExamEnd = true + return + } + } else { + if (examSubject == '3' && (param302 == 4 || param302 == 5 || param302 == 7 || param302 == 8)) { + await examJudgeEndExam() + that.isExamEnd = true + return + } + } + await examJudgeEndExam() + that.isExamEnd = true + } + } else { + //成绩不合格 + if (totalScore < passingScore) { + //科目三不合格报靠边停车 + if (examSubject == '3' && param302 == 1) { + that.avPlayer?.playAudio([`voice/考试结束.mp3`]); + return + } + await examJudgeEndExam() + that.isExamEnd = true + return + } + //成绩合格 + if (isAllProjectsEnd && totalScore >= passingScore && !that.isEndTip) { + if (examSubject == '2') { + await examJudgeEndExam() + that.isExamEnd = true + return + } + + //考试里程判断 + if (examSubject == '3' && jl < examMileage) { + return + } + + //考试合格自动退出 + if (examSubject == '3' && (param302 == 4 || param302 == 7) || param302 == 8) { + await examJudgeEndExam() + that.isExamEnd = true + return + } + + if (examSubject == '3' && (param342 == 0 || param342 == 2) && + (param302 != 6 && param302 != 7 && param302 != 8)) { + if (param512[7] != 0) { + clearTimeout(that.deductedPopShowTimer) + judgeUI.isDeductedPopShow = false + that.avPlayer?.playAudio(['voice/综合评判.mp3']) + judgeUI.isDeductedPopShow = true + judgeUI.defaultTabIndex = 1 + that.isEndTip = true + } + } else { + await examJudgeEndExam() + that.isExamEnd = true + } + } + } + } + } +} \ No newline at end of file diff --git a/entry/src/main/ets/pages/Judge/JudgeBusiness.ets b/entry/src/main/ets/pages/Judge/JudgeBusiness.ets index d463dda..90267d3 100644 --- a/entry/src/main/ets/pages/Judge/JudgeBusiness.ets +++ b/entry/src/main/ets/pages/Judge/JudgeBusiness.ets @@ -1,27 +1,29 @@ import { + EnvironmentConfigurationType, JudgeConfigObjKmItems, JudgeKSJS, JudgePerformInfo, - JudgeUI, LANE, - MarkRule, PLCType, ProcessDataEnumType, RecordHandleType, WorkerBackMessage, - WorkerBackMessageType + WorkerBackMessageType, + WorkerMessageDataType } from '../../model' import FileUtils from '../../utils/FileUtils' import VoiceAnnounce from '../judgeSDK/utils/voiceAnnouncements' import common from '@ohos.app.ability.common' -import { JudgeStartFn } from './JudgeStart' +import { LargeJudge } from './LargeJudgeBusiness' +import { SmallJudge } from './SmallJudgeBusiness' import { dConsole } from '../../utils/LogWorker' import { JudgeTag } from '../../config' -import { examJudgeRealExam } from './JudgeSDKUtils' -import { JudgingFn, SetJudgeItem } from './JudgeIng' +import { examJudgeArtificialMark, examJudgeRealExam } from './JudgeSDKUtils' import { DifferentialAndSignal } from '../../utils/business/DifferentialAndSignalWorker' import { PlcStrToJson, PlcStrToWXJson } from './utils' -import { JudgeEndFn } from './JudgeEnd' +import { BaseJudgeImpl, SetJudgeItem } from './BaseJudgeBussines' +import { JudgePage } from '../Judge' +import dayTs from '../../utils/Date' export default class JudgeBusiness { public mndgStr: string | undefined @@ -33,38 +35,43 @@ export default class JudgeBusiness { public performInfo?: JudgePerformInfo public context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext; //考试是否结束了 - public isExamEnd: boolean + public isExamEnd: boolean = false public isEndTip: boolean = false; //是否手动结束考试 public isManual: boolean = false public deductedPopShowTimer: number = -1; public videoData?: RecordHandleType //是否是考试模式 - public isExam: boolean + public isExam: boolean = true // PLC原始数据 public plcStr: string = "" public rmndg: 0 | 1 = 0 //所有的科目考试项目(大车&小车) - public kmItems: JudgeConfigObjKmItems + public kmItems: JudgeConfigObjKmItems = {} public xmmcStr: string = "" public xmmcCode: string = "" public xmmcSingleCode: string = "" public xmmcEndCode?: string public xmdm: string | number = "" public xmxh: string = "" - public kfArr?: MarkRule[] - public carztStr: string + public carztStr: string = "" public ksjs?: JudgeKSJS public plcData?: PLCType - private judgeUI: JudgeUI - private tempData?: PLCType - // 是否发送udp - private isUdpEnd: boolean = false + public totalScore: number = -1 + public judgeUI: JudgePage + private judgeBusiness: BaseJudgeImpl + private plc2Data?: string - constructor(judgeUI: JudgeUI) { + constructor(judgeUI: JudgePage) { this.judgeUI = judgeUI this.fileUtil = new FileUtils(judgeUI.context) this.avPlayer = new VoiceAnnounce(this.context); + const config = AppStorage.get("EnvironmentConfiguration") + if (config?.carType === '1' || config?.carType === '2') { + this.judgeBusiness = new SmallJudge() + } else { + this.judgeBusiness = new LargeJudge() + } } // 单机轨迹模式 @@ -81,7 +88,6 @@ export default class JudgeBusiness { const msg: PLCType = JSON.parse(strArr[num]); num++ // 4.过程数据 - this.tempData = msg this.judgeUI.sd = Math.floor(msg?.gps?.sd * 1.852) + ''; this.judgeUI.dw = Math.floor(msg?.sensor?.dw) + '' this.plcData = msg @@ -96,43 +102,64 @@ export default class JudgeBusiness { }, 200) } + // 考试初始化 + public async JudgeInit() { + return this.judgeBusiness.JudgeInit(this.judgeUI, this) + } + // 开始考试 public async JudgeStart(callBack: Function) { // 处理考试前需要做的业务 // 调用开始考试 - JudgeStartFn(callBack, this.judgeUI, this) + this.judgeBusiness.JudgeStart(callBack, this.judgeUI, this) // 处理PLC数据 // 处理实时udp里的plc信号 - DifferentialAndSignal.onMsg((data: string) => { - const result: WorkerBackMessage = JSON.parse(data) - if (result.type === WorkerBackMessageType.ObtainUdpData) { - this.HandlePLCData(result.data as string) - dConsole.writeProcessData(ProcessDataEnumType.PlcData, result.data as string) - } - }) + DifferentialAndSignal.onMsg(this.onUdpMessageCallback) this.JudgeEnd() } + // 人工扣分 + public async setJudgeMark(itemno: number, markserial: string, type: number) { + await examJudgeArtificialMark(itemno, markserial, type) + // TODO 写扣分轨迹日志 + } + // 考试过程 callback优化 public async Judging(strData: string, callBack: Function) { - JudgingFn(strData, callBack, this.judgeUI, this) + this.judgeBusiness.Judging(strData, callBack, this.judgeUI, this) } // 结束考试 public JudgeEnd(isManual?: boolean) { - JudgeEndFn(this.judgeUI, this, isManual) + dConsole.info(JudgeTag, '收到远程结束考试消息1') + this.judgeBusiness.JudgeEnd(this.judgeUI, this, isManual) + } + + close() { + DifferentialAndSignal.offMsg(this.onUdpMessageCallback) + } + + private onUdpMessageCallback = (data: string) => { + dConsole.log(JudgeTag, '收到UDP数据', data) + const result: WorkerBackMessage = JSON.parse(data) + if (result.type === WorkerBackMessageType.ObtainUdpData) { + this.HandlePLCData(result.data as string) + dConsole.writeProcessData(ProcessDataEnumType.PlcData, result.data as string) + } + if (result.type === WorkerBackMessageType.ObtainUdpGps2Data) { + this.plc2Data = result.data as string + } } // 处理PLC数据 private async HandlePLCData(msg: string) { const plcArr = msg.split(',') - if (plcArr[0] != '#DN_GD' || this.isUdpEnd) { + if (plcArr[0] != '#DN_GD' || this.judgeBusiness.getIsUdpEnd()) { return } const gpsPart = msg.split("#END$GPS,")[1]; const gpsStatus = gpsPart.split(",")[0]; if (gpsStatus === "4") { - dConsole.log(JudgeTag, "差分状态正常", gpsStatus) this.judgeUI.isDwztRight = true } else { dConsole.log(JudgeTag, "差分状态异常", gpsStatus) @@ -140,14 +167,13 @@ export default class JudgeBusiness { } // 记录原始PLC数据 dConsole.writeProcessData(ProcessDataEnumType.PlcData, msg) - const tempData = await PlcStrToJson(msg); + const tempData = await PlcStrToJson(msg, this.plc2Data); tempData.sensor.rmndg = this.rmndg; tempData.sensor.mndg = this.mndgStr || ""; const wuXiDataStr = await PlcStrToWXJson(msg) // 无锡所数据记录 dConsole.writeProcessData(ProcessDataEnumType.WuxiProgressData, wuXiDataStr) this.plcData = tempData - this.tempData = tempData this.plcStr = msg; this.mndgStr = ''; this.rmndg = 0; @@ -157,10 +183,33 @@ export default class JudgeBusiness { const param350: number = Reflect.get(this.judgeUI.judgeConfigObj, '350') this.judgeUI.sd = ((param350 == 0 ? this.plcData.gps.sd : this.plcData.sensor.cs) as number * 1.852).toFixed(0) + '' this.judgeUI.dw = (Math.floor(this.plcData.sensor.dw as number) || 0) + '' + + // dConsole.info("小红球过程数据1", this.judgeBusiness.getIsUdpEnd(), this.judgeUI.kfArr) + + let startTime: Date = AppStorage.get("startTime") || new Date() + + DifferentialAndSignal.sendMsg({ + type: WorkerMessageDataType.JudgeSend, data: { + performInfo: this.performInfo, + judgeUdpEnd: this.judgeBusiness.getIsUdpEnd(), + judgeExamEnd: this.isExamEnd, + business: { + totalScore: this.judgeUI.totalScore, + kfArr: this.judgeUI.kfArr, + startTime: dayTs(startTime).format("HHmmssSSS"), + xmmcSingleCode: this.xmmcSingleCode, + kmItems: this.kmItems, + examTime: this.judgeUI.examTime, + cdsbInfoObj: this.judgeUI.cdsbInfoObj!, + xmdm: this.xmdm, + xmxh: this.xmxh + } + } + }) + if (!this.isExamEnd) { await examJudgeRealExam(this.plcData) } - } } diff --git a/entry/src/main/ets/pages/Judge/JudgeEnd.ets b/entry/src/main/ets/pages/Judge/JudgeEnd.ets deleted file mode 100644 index b224356..0000000 --- a/entry/src/main/ets/pages/Judge/JudgeEnd.ets +++ /dev/null @@ -1,110 +0,0 @@ -import { JudgeTag } from '../../config' -import { JudgeUI } from '../../model' -import { dConsole } from '../../utils/LogWorker' -import JudgeBusiness from './JudgeBusiness' -import { examJudgeEndExam } from './JudgeSDKUtils' - -export const JudgeEndFn = async (judgeUI: JudgeUI, that: JudgeBusiness, isManual?: boolean) => { - const isAllProjectsEnd = judgeUI.isAllProjectsEnd - const examSubject = judgeUI.examSubject - const singlePlay = judgeUI.singlePlay - const totalScore = Number(judgeUI.totalScore) - const judgeConfigObj = judgeUI.judgeConfigObj - const examMileage = Number(judgeUI.examMileage) - const passingScore = Number(judgeUI.passingScore) - const jl = judgeUI.jl - if (that.isExamEnd) { - return - } - if (isManual) { - // 考试不合格 - await examJudgeEndExam() - that.isExamEnd = true - that.isManual = true - } else { - const param302: number = Reflect.get(judgeConfigObj, '302') - const param342: number = Reflect.get(judgeConfigObj, '342') - const param512: number[] = (Reflect.get(judgeConfigObj, '512') || '').split(','); - - //单机模式 - if (singlePlay) { - dConsole.info(JudgeTag + ' 单机模式结束 => ', isAllProjectsEnd) - if (isAllProjectsEnd && jl >= examMileage) { - //成绩合格 - if (totalScore >= passingScore && !that.isEndTip) { - if (examSubject == '3' && (param342 == 0 || param342 == 2) && - (param302 != 6 && param302 != 7 && param302 != 8)) { - if (param512[7] != 0) { - clearTimeout(that.deductedPopShowTimer) - that.avPlayer?.playAudio(['voice/综合评判.mp3']) - judgeUI.isDeductedPopShow = true - judgeUI.defaultTabIndex = 1 - that.isEndTip = true - return - } - } else { - await examJudgeEndExam() - that.isExamEnd = true - return - } - } else { - if (examSubject == '3' && (param302 == 4 || param302 == 5 || param302 == 7 || param302 == 8)) { - await examJudgeEndExam() - that.isExamEnd = true - return - } - } - await examJudgeEndExam() - that.isExamEnd = true - } - } else { - //成绩不合格 - if (totalScore < passingScore) { - //科目三不合格报靠边停车 - if (examSubject == '3' && param302 == 1) { - that.avPlayer?.playAudio([`voice/考试结束.mp3`]); - return - } - await examJudgeEndExam() - that.isExamEnd = true - return - } - - //成绩合格 - if (isAllProjectsEnd && totalScore >= passingScore && !that.isEndTip) { - if (examSubject == '2') { - await examJudgeEndExam() - that.isExamEnd = true - return - } - - //考试里程判断 - if (examSubject == '3' && jl < examMileage) { - return - } - - //考试合格自动退出 - if (examSubject == '3' && (param302 == 4 || param302 == 7) || param302 == 8) { - await examJudgeEndExam() - that.isExamEnd = true - return - } - - if (examSubject == '3' && (param342 == 0 || param342 == 2) && - (param302 != 6 && param302 != 7 && param302 != 8)) { - if (param512[7] != 0) { - clearTimeout(that.deductedPopShowTimer) - judgeUI.isDeductedPopShow = false - that.avPlayer?.playAudio(['voice/综合评判.mp3']) - judgeUI.isDeductedPopShow = true - judgeUI.defaultTabIndex = 1 - that.isEndTip = true - } - } else { - await examJudgeEndExam() - that.isExamEnd = true - } - } - } - } -} \ No newline at end of file diff --git a/entry/src/main/ets/pages/Judge/JudgeIng.ets b/entry/src/main/ets/pages/Judge/JudgeIng.ets deleted file mode 100644 index 42e2793..0000000 --- a/entry/src/main/ets/pages/Judge/JudgeIng.ets +++ /dev/null @@ -1,276 +0,0 @@ -import { JudgeTag } from '../../config'; -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, 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); - const carzt = examData.carzt - const xmks = examData.xmks - const kf = examData.kf - const event = examData.event - const xmjs = examData.xmjs - const xmqx = examData.xmqx - const ksjs = examData.ksjs - const sound = examData.sound - const mndg = examData.mndg - const lane = examData.lane - const precast = examData.precast - const nongps = examData.nongps - //获取项目结束、项目开始代码 - const xmdm = event == 2 ? xmjs.xmdm : xmks.xmdm - const xmxh = event == 2 ? xmjs.xmxh : xmks.xmxh; - let artSubject3ProjectsCodesArr: number[] = [3, 9, 4, 10, 12, 11] - const isManualProjectIn = artSubject3ProjectsCodesArr.includes(xmdm); - const examSubject = judgeUI.examSubject - const judgeConfigObj = judgeUI.judgeConfigObj - switch (event) { - // 项目开始 - case 1: { - const project: ProjectInfo = Reflect.get(judgeUI.projectsObj, xmdm) - project.type = '2'; - if (isManualProjectIn) { - //手动项目是否在进行中 - judgeUI.isManualProjectIn = true - } - if (xmdm == 41 && examSubject == '3') { - that.rmndg = 1 - } - 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; - that.xmmcSingleCode = xmmcSingleCode - that.xmmcEndCode = xmmcCode - that.xmdm = xmdm; - that.xmxh = xmxh; - judgeUI.isProjectIn = true - Reflect.set(judgeUI.projectsObj, xmdm, project) - Reflect.set(that.kmItems, xmmcCode || 0, kmItem) - break; - } - // 项目结束 - 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) => { - const fillProject: ProjectInfo = Reflect.get(judgeUI.projectsObj, projectKey) - return fillProject.type == '2' - }).length) > 0; - if (isManualProjectIn) { - judgeUI.isManualProjectIn = false - } - const kmItem: KmItem = Reflect.get(that.kmItems, xmmcCode) - kmItem.status = 3; - //统计必考项目数量 - that.xmmcStr = '无'; - that.xmmcCode = ''; - that.xmdm = ''; - judgeUI.currentXmdm = undefined; - Reflect.set(judgeUI.projectsObj, xmdm, project) - Reflect.set(that.kmItems, xmmcCode, kmItem) - break; - } - // 扣分 - case 3: { - const thisKf = DeductionProjectConversion(`${kf.xmdm}_${kf.kfdm}`, judgeUI.markRuleListObj) - const kfObj: MarkRule = { - //扣分项目名称 - xmmcStr: CurrentProjectConversion(kf.xmdm, judgeUI.projectsObj), - xmdm: kf.xmdm + "", - //扣分描述 - desc: thisKf.desc, - //扣分分数 - score: thisKf.score, - // 扣分无锡所代码 - markcatalog: thisKf.markcatalog, - markserial: thisKf.markserial, - kfxh: thisKf.kfxh, - //扣分类型 - type: kf.type - } - dConsole.log(JudgeTag, "扣分组装", kfObj) - that.kfArr?.push(kfObj) - dConsole.log(JudgeTag, "扣分类组装", that.kfArr) - judgeUI.totalScore += Number(thisKf?.score); - if (kf.xmdm != 20) { - const project: ProjectInfo = Reflect.get(judgeUI.projectsObj, kf.xmdm) - const type = project.type; - project.type = (type == '3' || type == '4') ? '4' : '5' - Reflect.set(judgeUI.projectsObj, kf.xmdm, project) - } - break; - } - // 考试状态 - case 4: { - that.carztStr = GetCarStatus(carzt); - break; - } - // 考试结束 - case 5: { - that.ksjs = ksjs; - // await fileLog?.setExamJudgeData(JSON.stringify({ - // method: 'examJudgeEndExam' - // })) - dConsole.writeProcessData(ProcessDataEnumType.JudgeExamData, JSON.stringify({ - method: 'examJudgeEndExam' - })) - break; - } - // 项目取消 - 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: { - goJudgeVoice(sound, that.avPlayer) - break; - } - // 模拟灯光事件 - case 8: { - that.mndgStr = mndg - break; - } - // 车道和路段变化 - case 9: { - judgeUI.lane = lane - that.lane = lane; - 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: { - DetectingDifferences(nongps.type, that.avPlayer) - break; - } - default: - break; - } - await callBack({ - //项目名称 考车状态 扣分arr - xmmcStr: that.xmmcStr, carztStr: that.carztStr, kfArr: that.kfArr - }); - -} - -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) => { - await examJudgeArtificialItem(Number(itemno), type); - const str = JSON.stringify({ - method: 'examJudgeArtificialItem', - itemno: Number(itemno), - type - }) - 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; - } - } -} \ No newline at end of file diff --git a/entry/src/main/ets/pages/Judge/JudgeSDKUtils.ets b/entry/src/main/ets/pages/Judge/JudgeSDKUtils.ets index c6692e2..2167621 100644 --- a/entry/src/main/ets/pages/Judge/JudgeSDKUtils.ets +++ b/entry/src/main/ets/pages/Judge/JudgeSDKUtils.ets @@ -115,8 +115,6 @@ export async function examJudgeBeginExam(data: JudgeBeginObj) { } - - /* * @desc结束考试 * @@ -205,7 +203,7 @@ async function handle(temp: number, fnName: string): Promise { if (temp == 0) { resolve(temp); } else { - dConsole.error('surenjun error:' + `调用c++函数 ${fnName} 异常:` + libJudgeSdk.examJudgeErrorInfo(temp * 1)) + dConsole.error('error:' + `调用c++函数 ${fnName} 异常:` + libJudgeSdk.examJudgeErrorInfo(temp * 1)) reject(temp) } }) diff --git a/entry/src/main/ets/pages/Judge/JudgeStart.ets b/entry/src/main/ets/pages/Judge/JudgeStart.ets deleted file mode 100644 index bad0c84..0000000 --- a/entry/src/main/ets/pages/Judge/JudgeStart.ets +++ /dev/null @@ -1,249 +0,0 @@ -//开始评判 -import { JudgeConfig, JudgeTag } from '../../config'; -import { - BaseInfoType, - CARINFO, - CarInfoType, - CDSBInfo, - ExaminerInfoType, - ItemInfo, - ItemInfos, - JudgeBeginObj, - JudgeInitObj, - JudgeKFXM, - JudgeKSXM, - JudgeUI, - Km3JudgeInitConfig, - MAPITEMPOINTITEM, - MAPPOINT, - MarkRule, - ProcessDataEnumType, - ProjectInfo, - RouteParamsType, - SyssetConfig, - SYSTEMPARMARR -} from '../../model'; -import common from '@ohos.app.ability.common'; -import { dConsole } from '../../utils/LogWorker'; -import { - examJudgeBeginExam, - examJudgeInit, - examJudgeSetLogCallback, - examJudgeSetPerformCallback, - examJudgeSetRealExamCallback, - examJudgeVersion -} from './JudgeSDKUtils'; -import FileModel from '../judgeSDK/utils/fileModel'; -import JudgeBusiness from './JudgeBusiness'; -import { saveStartRecordVideo } from '../../utils/Video'; -import router from '@ohos.router'; -import systemTime from '@ohos.systemTime'; - -export const JudgeStartFn = async (callBack: Function, judgeUI: JudgeUI, that: JudgeBusiness) => { - const name = judgeUI.name - const kssycs = judgeUI.kssycs - const manualMarkRules = judgeUI.manualMarkRules - // 处理单机模式 - const isTrajectoryOpen = JudgeConfig.isTrajectoryOpen; - const isJudgeInitBool = AppStorage.get('isJudgeInitBool'); - const trajectoryPath = JudgeConfig.trajectoryPath; - let strArr: string[] = []; - if (isTrajectoryOpen) { - const folderPath = await that.fileUtil.initFolder(trajectoryPath); - const str: string = await that.fileUtil.readFile(folderPath) - strArr = str.split('\n') - } - //日志回调 - dConsole.info(JudgeTag, '1.进入评判入口') - await examJudgeSetLogCallback(6, async (level: number, info: string, len: number) => { - dConsole.log(JudgeTag, '评判日志:' + info) - dConsole.writeProcessData(ProcessDataEnumType.JudgeLogData, info) - }) - - dConsole.info(JudgeTag, '2.注册日志回调完成') - - let initInfo: JudgeInitObj = isTrajectoryOpen ? JSON.parse(strArr[0]) : await GetJudgeInitData(judgeUI.context, judgeUI.markRuleListObj, judgeUI.carType, judgeUI.carName, judgeUI.systemparmArr, judgeUI.carinfoArr, judgeUI.examSubject, judgeUI.itemInfoObj, judgeUI.judgeConfig, judgeUI.carlist, judgeUI.mapPointArr, judgeUI.mapPointItemArr); - //相关评判初始化只做一次 - if (!isJudgeInitBool) { - dConsole.log(JudgeTag, "评判初始化参数", initInfo) - await examJudgeInit(initInfo); - AppStorage.setOrCreate('isJudgeInitBool', true) - dConsole.info(JudgeTag, '4.评判初始化完成') - } - AppStorage.setOrCreate('isJudge', true) - // 2.评判过程回调 - await examJudgeSetRealExamCallback(async (strData: string, len: number) => { - // 评判回调日志 - dConsole.writeProcessData(ProcessDataEnumType.JudgeProgressCallbackData, strData) - dConsole.info(JudgeTag, '评判回调数据', strData) - await that.Judging(strData, callBack) - }) - await examJudgeSetPerformCallback(async (info: string) => { - dConsole.info('评判实时数据', info) - that.performInfo = JSON.parse(info) - const jl = Math.floor((that.performInfo.qjjl + that.performInfo.dcjl) / 100); - if (jl > Number(judgeUI.examMileage)) { - that.JudgeEnd() - } - judgeUI.jl = jl - judgeUI.laneSignal = that.performInfo.lane - }) - let beginExamInfo: JudgeBeginObj | undefined = undefined - // 3.开始考试 - if (isTrajectoryOpen) { - beginExamInfo = JSON.parse(strArr[1]) - beginExamInfo && (beginExamInfo.replay = 1) - } else { - beginExamInfo = await GetJudgeBeginData(judgeUI.projects, judgeUI.carType, judgeUI.kssycs, judgeUI.isDdxk, judgeUI.ddxkTime, judgeUI.projectsCenterObj, judgeUI.ddxkKsxmArr, judgeUI.ddxkKfArr, judgeUI.passingScore, judgeUI.wayno, judgeUI.name, judgeUI.lsh, judgeUI.idCard, that.isExam) - } - if (beginExamInfo) { - await examJudgeBeginExam(beginExamInfo); - } - dConsole.info(JudgeTag, '6.开始考试注册完成') - that.avPlayer?.playAudio([judgeUI.singlePlay ? 'voice/ksks.wav' : 'voice/监管成功.mp3']) - if (!judgeUI.singlePlay) { - that.videoData = await saveStartRecordVideo(`${name}_${kssycs}`, that.context) - } - judgeUI.draw = true - // 处理单机泡轨迹模式 - if (isTrajectoryOpen) { - that.SingleMachineTrajectory(strArr) - return - } -} - -// 获取评判开始考试数据 -const GetJudgeBeginData = async (projects: ProjectInfo[], carType: string, kssycs: string, isDdxk: boolean, ddxkTime: number, projectsCenterObj: Object, ddxkKsxmArr: string[], ddxkKfArr: string[], passingScore: number, wayno: number, name: string, lsh: string, idCard: string, isExam: boolean) => { - const examinerInfo = AppStorage.get('examinerInfo') - const examinerName = examinerInfo?.name || "" - let currentParams: RouteParamsType = router.getParams() as RouteParamsType; - const sczb = currentParams.sczb; - const kfdm = currentParams.kfdm; - const ksxm: JudgeKSXM[] = projects.map(project => { - const temp: JudgeKSXM = { - xmdm: Number(project.projectCode), xmxh: '' - } - return temp - }) - const ykxm: number[] = (ddxkKsxmArr?.map(projectCenterCode => { - const currentProject: ProjectInfo = Reflect.get(projectsCenterObj, projectCenterCode) - return Number(currentProject.projectCode) - })) || []; - const kfxm: JudgeKFXM[] = isDdxk ? (ddxkKfArr?.map(kf => { - return { - xmdm: Number(kf.split(',')[0]), kfdm: kf.split(',')[1] - } as JudgeKFXM - })) : [] - const beginInfo: JudgeBeginObj = { - kgid: '012', - kgxm: decodeURI(examinerName || ''), - exam: isExam ? 1 : 0, - //是否回放 - replay: 0, - //生成的轨迹文件 - track: '', - xm: name, - sex: 0, - kslsh: lsh, - sfzmhm: idCard, - ksyy: '', - kscx: carType, - kkcs: Number(kssycs) || 2, - sfyk: 0, - ykkkcs: 1, - wayno: Number(wayno), - czlx: 0, - kskssj: await systemTime.getCurrentTime(), - passing: Number(passingScore), - ksxm, - //断点续考 - ddxk: isDdxk ? 1 : 0, - ddkssj: ddxkTime || 0, - ykxm, - kfxm, - yklc: 0, - special: [], - sczb: (sczb === undefined || sczb == '0') ? 0 : 1, - sczbkf: kfdm, - dmndg: false, - mfxx: false, - mfxxn: false - } - dConsole.info(JudgeTag, '5.获取开始考试数据完成') - return beginInfo -} - -// 获取评判初始化数据 -const GetJudgeInitData = async (context: common.UIAbilityContext, markRuleListObj: object, carType: string, carName: string, systemparmArr: SYSTEMPARMARR[], carinfoArr: CARINFO[], examSubject: string, itemInfoObj: ItemInfos, judgeConfig: SyssetConfig[], carlist: string, mapPointArr: MAPPOINT[], mapPointItemArr: MAPITEMPOINTITEM[]) => { - const carInfo = AppStorage.get('carInfo'); - const examType = carInfo?.examSubject == '2' ? 'km2' : 'km3' - - let allitems: ItemInfo[] = []; - if (examSubject == '2' && itemInfoObj) { - allitems = Reflect.ownKeys(itemInfoObj).map(cdsbKey => { - const cdsb: CDSBInfo = Reflect.get(itemInfoObj, cdsbKey); - const model = GetModelData(`${examType}/${cdsb.modelKey}.txt`, context) - const temp: ItemInfo = { - xmdm: cdsb?.xmdm || 0, - xmxh: cdsb?.xmxh || "", - model: model || "" - } - return temp - }) - } - - //获取版本号 - const mark: MarkRule[] = Reflect.ownKeys(markRuleListObj).map(ruleKey => { - const current: MarkRule = Reflect.get(markRuleListObj, ruleKey) - return current - }) - const initInfo: JudgeInitObj = { - sdkver: await examJudgeVersion(), - appver: AppStorage.get('baseInfo')?.version || "", - kskm: Number(carInfo?.examSubject || "2"), - kchp: carInfo?.plateNo || "", - kchm: Number(carInfo?.carId || ""), - kscx: carType, - cxcode: '1', - name: carName, - carmodel: GetModelData(`${examType}/${carType}.txt`, context) || "", - allitems, - iteminfo: [], - systemparm: systemparmArr, - mark, - sysset: judgeConfig, - itemInfoObj, - carlist: carlist, - carinfo: carinfoArr, - }; - let km3Config: Km3JudgeInitConfig = {} - if (examSubject == '3') { - km3Config = { - map_point: mapPointArr, - map_point_item: mapPointItemArr, - //科目三暂时为空 - iteminfo: [], - roads: GetModelData('km3/Roads.txt', context) || "", - sharps: GetModelData('km3/Sharps.txt', context) || "" - }; - initInfo.map_point = km3Config.map_point - initInfo.map_point_item = km3Config.map_point_item - initInfo.iteminfo = km3Config.iteminfo - initInfo.roads = km3Config.roads - initInfo.sharps = km3Config.sharps - } - // 获取科目三的评判配置 - dConsole.info(JudgeTag, '3.获取评判初始化数据完成') - return initInfo -} - -export const GetModelData = (modelName: string, context: common.UIAbilityContext): string => { - try { - return new FileModel(context).getModelContent(JudgeConfig.modelPath, modelName); - } catch (e) { - // 可根据实际需求,返回空字符串或抛出异常 - dConsole.error(JudgeTag, `获取模型数据失败: ${modelName}`, e.message) - return ''; - } -}; - diff --git a/entry/src/main/ets/pages/Judge/LargeJudgeBusiness.ets b/entry/src/main/ets/pages/Judge/LargeJudgeBusiness.ets new file mode 100644 index 0000000..ef53d82 --- /dev/null +++ b/entry/src/main/ets/pages/Judge/LargeJudgeBusiness.ets @@ -0,0 +1,469 @@ +import { JudgeConfig, JudgeTag } from '../../config'; +import { + BaseInfoType, + CAR_INFO, + CarInfoType, + CDSBInfo, + ExaminerInfoType, + ItemInfo, + ItemInfos, + JudgeBeginObj, + JudgeCallBackData, + JudgeInitObj, + JudgeKFXM, + JudgeKSXM, + Km3JudgeInitConfig, + MAPITEMPOINTITEM, + MAPPOINT, + MarkRule, + Project, + ProjectInfo, + ProjectInfos, + RouteParamsType, + SyssetConfig, + SYSTEM_PARAM, + EnvironmentConfigurationType +} from '../../model'; +import common from '@ohos.app.ability.common'; +import { dConsole } from '../../utils/LogWorker'; +import { examJudgeVersion } from './JudgeSDKUtils'; +import JudgeBusiness from './JudgeBusiness'; +import router from '@ohos.router'; +import { GetModelData } from './utils'; +import { BaseJudge, BaseJudgeImpl, GetSysSetResult } from './BaseJudgeBussines'; +import { GetSyncData } from '../../utils/table/Operation'; +import promptAction from '@ohos.promptAction'; +import { JudgePage } from '../Judge'; +import systemDateTime from '@ohos.systemDateTime'; +import { testKm2Items, testKm3Items } from '../../mock'; + +export class LargeJudge extends BaseJudge implements BaseJudgeImpl { + private mockLight: boolean = false + private mode: number = 1 + + getIsUdpEnd(): boolean { + return super.getIsUdpEnd() + } + + private async GetJudgeBeginData(projects: Project[], carType: string, kssycs: string, isDdxk: boolean, ddxkTime: number, projectsCenterObj: Object, ddxkKsxmArr: string[], ddxkKfArr: string[], passingScore: number, wayno: number, name: string, lsh: string, idCard: string, isExam: boolean) { + const examinerInfo = AppStorage.get('examinerInfo') + const examinerName = examinerInfo?.name || "" + let currentParams: RouteParamsType = router.getParams() as RouteParamsType; + const sczb = currentParams.sczb; + const kfdm = currentParams.kfdm; + const ksxm: JudgeKSXM[] = projects.map(project => { + const temp: JudgeKSXM = { + xmdm: Number(project.projectCode), xmxh: '' + } + return temp + }) + const ykxm: number[] = (ddxkKsxmArr?.map(projectCenterCode => { + const currentProject: ProjectInfo = Reflect.get(projectsCenterObj, projectCenterCode) + return Number(currentProject.projectCode) + })) || []; + const kfxm: JudgeKFXM[] = isDdxk ? (ddxkKfArr?.map(kf => { + return { + xmdm: Number(kf.split(',')[0]), kfdm: kf.split(',')[1] + } as JudgeKFXM + })) : [] + const beginInfo: JudgeBeginObj = { + kgid: '012', + kgxm: decodeURI(examinerName || ''), + exam: isExam ? 1 : 0, + //是否回放 + replay: 0, + //生成的轨迹文件 + track: '', + xm: name, + sex: 0, + kslsh: lsh, + sfzmhm: idCard, + ksyy: '', + kscx: carType, + kkcs: Number(kssycs) || 2, + sfyk: 0, + ykkkcs: 1, + wayno: Number(wayno), + czlx: 0, + kskssj: await systemDateTime.getCurrentTime(), + passing: Number(passingScore), + ksxm, + //断点续考 + ddxk: isDdxk ? 1 : 0, + ddkssj: ddxkTime || 0, + ykxm, + kfxm, + yklc: 0, + special: [], + sczb: (sczb === undefined || sczb == '0') ? 0 : 1, + sczbkf: kfdm, + dmndg: this.mockLight, + mfxx: this.mode === 5, + zeng: this.mode === 3 || this.mode === 4 + } + dConsole.info(JudgeTag, '5.获取开始考试数据完成') + return beginInfo + }; + + private async GetJudgeInitData(context: common.UIAbilityContext, markRuleListObj: object, carType: string, carName: string, systemparmArr: SYSTEM_PARAM[], carinfoArr: CAR_INFO[], examSubject: string, itemInfoObj: ItemInfos, judgeConfig: SyssetConfig[], carlist: string, mapPointArr: MAPPOINT[], mapPointItemArr: MAPITEMPOINTITEM[]) { + const carInfo = AppStorage.get('carInfo'); + + let allitems: ItemInfo[] = []; + if (examSubject == '2' && itemInfoObj) { + const promiseItems = Reflect.ownKeys(itemInfoObj).map(async cdsbKey => { + const cdsb: CDSBInfo = Reflect.get(itemInfoObj, cdsbKey); + const model = await GetModelData(`/${cdsb.modelKey}.txt`, context); + const temp: ItemInfo = { + xmdm: cdsb?.xmdm || 0, + xmxh: cdsb?.xmxh || "", + model: model || "" + }; + return temp; + }); + // 等待所有的 Promise 解析完成 + allitems = await Promise.all(promiseItems); + } + + const mark: MarkRule[] = Object.values(markRuleListObj) + const initInfo: JudgeInitObj = { + sdkver: await examJudgeVersion(), + appver: AppStorage.get('EnvironmentConfigurationType')?.version || "", + kskm: Number(carInfo?.examSubject || "2"), + kchp: carInfo?.plateNo || "", + kchm: Number(carInfo?.carId || ""), + kscx: carType, + cxcode: '1', + name: carName, + carmodel: await GetModelData(`/${carType}.txt`, context) || "", + allitems, + iteminfo: [], + systemparm: systemparmArr, + mark, + sysset: judgeConfig, + itemInfoObj, + carlist: carlist, + carinfo: carinfoArr, + }; + let km3Config: Km3JudgeInitConfig = {} + if (examSubject == '3') { + km3Config = { + map_point: mapPointArr, + map_point_item: mapPointItemArr, + //科目三暂时为空 + iteminfo: [], + roads: await GetModelData('/Roads.txt', context) || "", + sharps: await GetModelData('/Sharps.txt', context) || "" + }; + initInfo.map_point = km3Config.map_point + initInfo.map_point_item = km3Config.map_point_item + initInfo.iteminfo = km3Config.iteminfo + initInfo.roads = km3Config.roads + initInfo.sharps = km3Config.sharps + } + // 获取科目三的评判配置 + dConsole.info(JudgeTag, '3.获取评判初始化数据完成') + return initInfo + }; + + public async JudgeInit(judgeUI: JudgePage, that: JudgeBusiness): Promise { + const systemParams = await GetSyncData('MA_SYSTEMPARM') + let currentParams: RouteParamsType = router.getParams() as RouteParamsType; + this.mode = currentParams.mode || 1 + let totalScore: number = 100 + let wayno: number = 1 + let carlist: string = "" + let passingScore: number = 90 + let examMileage: string = "" + let projectsObj: ProjectInfos = {} + let projectsCenterObj: ProjectInfos = {} + let ddxkKsxmArr: Array = [] + let singlePlay: boolean = AppStorage.get("singlePlay")! + let systemparmArr: Array = [] + let projects: Array = [] + let examSubject: string = AppStorage.get('carInfo')!.examSubject! + if (this.mode === 2) { + totalScore = Number(currentParams.score) || 100 + } + if (singlePlay) { + wayno = Number(currentParams.wayno) || 1; + } + //真实监管下发的项目 + let kStringArr: string[] = (currentParams.kString?.split(',') || []).filter(item => item); + // 单机模式下增驾进模拟灯光 + this.mockLight = kStringArr.includes("41700") || singlePlay && this.mode === 3 + + let isInExam = kStringArr.length > 0; + + // const {isTrajectoryOpen} = judgeConfig + + let carNo = '', allItems: string[] = []; + systemParams.forEach((systemParam: SYSTEM_PARAM) => { + const no1 = systemParam.no1; + const no2 = systemParam.no2; + const no3 = systemParam.no3; + + const txt1 = decodeURI(systemParam.txt1 || "") + //获取当前考车的no2 + if (no1 === "3" && no3 === "1" && txt1 === judgeUI.carName) { + carNo = no2! + carlist = carNo + } + //获取及格分数线 + if (no1 === "3" && no3 === "3" && carNo === no2) { + passingScore = Number(txt1) || 0; + } + //根据车型获取应行驶里程数 + if (no1 === "3" && no3 === "15" && carNo === no2) { + let mileage = (decodeURI(systemParam.txt1 || '')).split('^') + if (this.mode === 1) { + examMileage = mileage[1] + } else if (this.mode === 2) { + examMileage = mileage[2] + } else { + examMileage = mileage[0] + } + } + // 满分学习里程 + if (this.mode === 5 && no1 === "3" && no2 === carNo && no3 === "63") { + let data = decodeURI(systemParam.txt1 || "")?.split("^") + examMileage = data[1] || examMileage + } + //获取当前考车的考试项目 + if (this.mode === 2 && no1 === "3" && no2 === carNo && no3 === "46") { + // 夜考必考项目读取 + allItems = decodeURIComponent(systemParam.txt1 || "").split(',').filter(txt => txt !== '') + } else if (this.mode !== 2 && no1 === "3" && no2 === carNo && no3 === "10") { + // 其他模式必考项目获取 + allItems = decodeURIComponent(systemParam.txt1 || "").split(',').filter(txt => txt !== '') + } else if (this.mode == 5 && no1 === "3" && no2 === carNo && no3 === "63") { + // 满分学习项目 + let data = decodeURI(systemParam.txt1 || "")?.split("^") + allItems = data[0]?.split(",").filter(item => item !== "") || [] + } + }) + systemParams.forEach((systemParam) => { + if (JudgeConfig.isTrajectoryOpen) { + systemParam.no1 = systemParam.NO1!.toString()!; + systemParam.no2 = systemParam.NO2!.toString()!; + systemParam.no3 = systemParam.NO3!.toString()!; + systemParam.txt1 = systemParam.TXT1!; + systemParam.txt2 = systemParam.TXT2!; + systemParam.txt3 = systemParam.TXT3!; + } + const no1 = systemParam.no1; + const no2 = systemParam.no2; + const no3 = systemParam.no3; + const txt2 = decodeURI(systemParam.txt2 || "") + + if (no1 === "6") { + const name = decodeURI(systemParam.txt1 || "") + // 白考过滤掉夜间行驶 + if (this.mode !== 2 && no2 === "13") { + return + } + // 模拟夜间驾驶(灯光) + if (!this.mockLight && no2 === "41") { + return + } + let isRequired = (this.mode === 5 && allItems.length === 0) || allItems.includes(no2 + '') + let isEnd = false + let isUpload = false + + // 夜考除夜间行驶其他项目不需要重复上传 + if (this.mode === 2 && no2 !== "13") { + isUpload = true + } + // 加减档自动完成,为非必须项目 + if (no2 === "14") { + isRequired = false + } + const currentProject: Project = { + name, + abbreviation: decodeURI(systemParam.txt3 || ""), + projectCode: no2 + '', + projectCodeCenter: txt2, + // 白考夜间行驶非必考 + isRequired, + //是否考过了 + isEnd, + //项目开始数据是否上传过 + isUpload, + } + // 夜考时 + if (this.mode === 2 && no2 !== "13") { + currentProject.ykType = isRequired ? "1" : "3" + currentProject.isEnd = !allItems.includes(no2 + '') + } + Reflect.set(projectsObj, no2!, currentProject) + Reflect.set(projectsCenterObj, no2!, currentProject) + projects.push(currentProject); + // 真实监管下发考试项目, 夜考模式不进此逻辑 + if (isInExam && this.mode !== 2 && !(kStringArr.includes(txt2) || kStringArr.includes(no2 + ''))) { + let temp: ProjectInfo = Reflect.get(projectsObj, no2!) + temp.type = '3' + temp.isUpload = true + temp.isEnd = true + Reflect.set(projectsObj, no2!, temp) + + temp = Reflect.get(projectsCenterObj, txt2!) + temp.type = '3' + temp.isUpload = true + temp.isEnd = true + Reflect.set(projectsCenterObj, txt2!, temp) + + ddxkKsxmArr.push(txt2) + } + } + systemparmArr.push({ + NO1: Number(no1), + NO2: Number(no2), + NO3: Number(no3), + TXT1: decodeURIComponent(systemParam.txt1 || ""), + TXT2: decodeURIComponent(systemParam.txt2 || ""), + TXT3: decodeURIComponent(systemParam.txt3 || ""), + }) + }) + if (!projects.length) { + promptAction.showToast({ + message: '读取数据库信息失败,请重新联网更新!', + duration: 8000 + }); + router.back(); + } + (examSubject === '2' ? testKm2Items : testKm3Items).forEach(item => { + let project: ProjectInfo = Reflect.get(judgeUI.projectsCenterObj, item.code) + Reflect.set(that.kmItems, item.code, { + code: item.code, + status: project === undefined ? 0 : (project.isEnd ? 3 : 1) + }) + }) + + return { + totalScore, + wayno, + carlist, + passingScore, + examMileage, + projectsObj, + projectsCenterObj, + ddxkKsxmArr, + singlePlay, + systemparmArr, + projects, + } + } + + public async JudgeStart(callBack: Function, judgeUI: JudgePage, that: JudgeBusiness) { + const isTrajectoryOpen = JudgeConfig.isTrajectoryOpen; + const trajectoryPath = JudgeConfig.trajectoryPath; + let strArr: string[] = []; + if (isTrajectoryOpen) { + const folderPath = await that.fileUtil.initFolder(trajectoryPath); + const str: string = await that.fileUtil.readFile(folderPath) + strArr = str.split('\n') + } + let initInfo: JudgeInitObj = isTrajectoryOpen ? JSON.parse(strArr[0]) : await this.GetJudgeInitData(judgeUI.context, judgeUI.markRuleListObj, judgeUI.carType, judgeUI.carName, judgeUI.systemparmArr, judgeUI.carinfoArr, judgeUI.examSubject, judgeUI.itemInfoObj!, judgeUI.judgeConfig, judgeUI.carlist, judgeUI.mapPointArr, judgeUI.mapPointItemArr); + let beginExamInfo: JudgeBeginObj | undefined = undefined + + if (isTrajectoryOpen) { + beginExamInfo = JSON.parse(strArr[1]) + beginExamInfo && (beginExamInfo.replay = 1) + } else { + beginExamInfo = await this.GetJudgeBeginData(judgeUI.projects, judgeUI.carType, judgeUI.kssycs, judgeUI.isDdxk, judgeUI.ddxkTime, judgeUI.projectsCenterObj, judgeUI.ddxkKsxmArr, judgeUI.ddxkKfArr, judgeUI.passingScore, judgeUI.wayno, judgeUI.name, judgeUI.lsh, judgeUI.idCard, that.isExam) + } + super.judgeStart(callBack, judgeUI, that, beginExamInfo!, initInfo) + }; + + public async Judging(strData: string, callBack: Function, judgeUI: JudgePage, that: JudgeBusiness) { + let examData: JudgeCallBackData = JSON.parse(strData); + const xmks = examData.xmks + const kf = examData.kf + const event = examData.event + const xmjs = examData.xmjs + + const xmdm = event == 2 ? xmjs.xmdm : xmks.xmdm + + switch (event) { + // 项目开始 + case 1: { + if (this.mode === 2) { + const project: ProjectInfo = Reflect.get(judgeUI.projectsObj, xmdm) + project.ykType = '2'; + Reflect.set(judgeUI.projectsObj, xmdm, project) + } + break; + } + // 项目结束 + case 2: { + if (this.mode === 2) { + const project: ProjectInfo = Reflect.get(judgeUI.projectsObj, xmdm) + project.ykType = xmjs.xmhg === 0 ? '4' : '3'; + Reflect.set(judgeUI.projectsObj, xmdm, project) + } + break; + } + // 扣分 + case 3: { + if (kf.xmdm != 20) { + const project: ProjectInfo = Reflect.get(judgeUI.projectsObj, kf.xmdm) + const type = project.type; + if (this.mode === 2) { + project.ykType = (type === "3" || type === "4") ? '4' : '5'; + Reflect.set(judgeUI.projectsObj, kf.xmdm, project) + } + } + break; + } + // 考试状态 + case 4: { + break; + } + // 考试结束 + case 5: { + break; + } + // 项目取消 + case 6: { + if (this.mode === 2) { + const project: ProjectInfo = Reflect.get(judgeUI.projectsObj, xmdm) + project.ykType = '1'; + Reflect.set(judgeUI.projectsObj, xmdm, project) + } + break; + } + // 语音播报和提示 + case 7: { + break; + } + // 模拟灯光事件 + case 8: { + break; + } + // 车道和路段变化 + case 9: { + break; + } + // 预进项目事件 + case 10: { + if (this.mode === 2) { + const project: ProjectInfo = Reflect.get(judgeUI.projectsObj, xmdm) + project.ykType = '2'; + Reflect.set(judgeUI.projectsObj, xmdm, project) + } + } + // 差分事件 + case 11: { + break; + } + default: + break; + } + super.judging(strData, callBack, judgeUI, that) + } + + public async JudgeEnd(judgeUI: JudgePage, that: JudgeBusiness, isManual?: boolean) { + super.judgeEnd(judgeUI, that, isManual) + }; + + +} \ No newline at end of file diff --git a/entry/src/main/ets/pages/Judge/ProcessDataProcessing.ets b/entry/src/main/ets/pages/Judge/ProcessDataProcessing.ets index 734dfde..4486db3 100644 --- a/entry/src/main/ets/pages/Judge/ProcessDataProcessing.ets +++ b/entry/src/main/ets/pages/Judge/ProcessDataProcessing.ets @@ -1,30 +1,32 @@ /** * 过程数据处理 */ -import { ProcessDataTag } from '../../config'; +import { ExamProcessDataTag, JudgeTag, ProcessDataTag, QueueTag } from '../../config'; import { CarInfoType, CDSBInfo, CDSBInfos, DrvexamType, - JudgeUI, MarkRule, PLCType, + ProgressCallback, ProjectInfo, RegulatoryInterfaceParams } from '../../model'; import { GetPhotoBase64 } from '../../utils/Common'; import dayTs from '../../utils/Date'; import { dConsole } from '../../utils/LogWorker'; +import { JudgePage } from '../Judge'; +import JudgeBusiness from './JudgeBusiness'; import { ProcessDataTaskPoolInstance } from './ProcessDataTaskPool'; /** * beginProject 项目开始 */ -export const ProjectStart = (ksxm: number, xmxh: string, judgeUI: JudgeUI) => { - const carInfo = AppStorage.get('carInfo'); +export const ProjectStart = (ksxm: number, xmxh: string, judgeUI: JudgePage) => { + const carInfo = AppStorage.get('carInfo')!; const project: ProjectInfo = Reflect.get(judgeUI.projectsObj, ksxm) - const sbxh = getSBXH(ksxm, xmxh, judgeUI.cdsbInfoObj, judgeUI.projectsObj, carInfo.examSubject); + const sbxh = getSBXH(ksxm, xmxh, judgeUI.cdsbInfoObj!, judgeUI.projectsObj, carInfo.examSubject!); const drvexam: DrvexamType = { lsh: judgeUI.lsh, kskm: carInfo?.examSubject || "2", @@ -38,20 +40,21 @@ export const ProjectStart = (ksxm: number, xmxh: string, judgeUI: JudgeUI) => { kssj: dayTs().format("YYYY-MM-DD HH:mm:ss") } const data: RegulatoryInterfaceParams = { + JGHOST: AppStorage.get("JGHOST") || "", //系统类别 接口序列号 接口标识 xtlb: '17', jkxlh: judgeUI.serialNumber, jkid: '17C52', drvexam } - dConsole.log(ProcessDataTag, "项目开始数据处理", data) + dConsole.log(ProcessDataTag, QueueTag, ExamProcessDataTag, "项目开始数据处理", data) ProcessDataTaskPoolInstance.addTask(data) } /** * uploadProgressPhoto 上传过程照片 */ -export const UploadProgressPhoto = async (ksxm: number, plcData: PLCType, judgeUI: JudgeUI) => { +export const UploadProgressPhoto = async (ksxm: number, plcData: PLCType, judgeUI: JudgePage) => { const photoBase64 = await GetPhotoBase64(judgeUI.context); const carInfo = AppStorage.get('carInfo'); const project: ProjectInfo = Reflect.get(judgeUI.projectsObj, ksxm) @@ -68,19 +71,20 @@ export const UploadProgressPhoto = async (ksxm: number, plcData: PLCType, judgeU ksdd: encodeURI(judgeUI.ksdd) } const data: RegulatoryInterfaceParams = { + JGHOST: AppStorage.get("JGHOST") || "", xtlb: '17', jkxlh: judgeUI.serialNumber, jkid: '17C54', drvexam }; - dConsole.log(ProcessDataTag, "上传过程照片数据处理", data); + dConsole.log(ProcessDataTag, QueueTag, ExamProcessDataTag, "上传过程照片数据处理", data); ProcessDataTaskPoolInstance.addTask(data) } /** * pointsDedute 扣分补传 */ -export const DeductPoints = (ksxm: number, kf: MarkRule, xmmcEndCode: string, judgeUI: JudgeUI) => { +export const DeductPoints = (ksxm: number, kf: MarkRule, xmmcEndCode: string, judgeUI: JudgePage) => { const carInfo = AppStorage.get('carInfo')!; const examSubject = carInfo.examSubject const lsh = judgeUI.lsh @@ -130,22 +134,23 @@ export const DeductPoints = (ksxm: number, kf: MarkRule, xmmcEndCode: string, ju kfsj: dayTs().format("YYYY-MM-DD HH:mm:ss"), } const data: RegulatoryInterfaceParams = { + JGHOST: AppStorage.get("JGHOST") || "", xtlb: '17', jkxlh: serialNumber, jkid: '17C53', drvexam } - dConsole.log(ProcessDataTag, "扣分上传数据", data) + dConsole.log(ProcessDataTag, QueueTag, ExamProcessDataTag, "扣分上传数据", data) ProcessDataTaskPoolInstance.addTask(data) } /** * endProject 结束项目 */ -export const ProjectEnd = (ksxm: number, xmxh: string, judgeUI: JudgeUI) => { - const carInfo = AppStorage.get('carInfo'); +export const ProjectEnd = (ksxm: number, xmxh: string, judgeUI: JudgePage) => { + const carInfo = AppStorage.get('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 sbxh = carInfo.examSubject == '3' ? undefined : getSBXH(ksxm, xmxh, judgeUI.cdsbInfoObj!, judgeUI.projectsObj!, carInfo.examSubject!); const drvexam: DrvexamType = { lsh: judgeUI.lsh, kskm: carInfo?.examSubject || "2", @@ -162,14 +167,47 @@ export const ProjectEnd = (ksxm: number, xmxh: string, judgeUI: JudgeUI) => { } const data: RegulatoryInterfaceParams = { xtlb: '17', + JGHOST: AppStorage.get("JGHOST") || "", jkxlh: judgeUI.serialNumber, jkid: '17C55', drvexam } - dConsole.log(ProcessDataTag, "结束项目数据", data) + dConsole.log(ProcessDataTag, QueueTag, ExamProcessDataTag, "结束项目数据", data) ProcessDataTaskPoolInstance.addTask(data) } +/** + * 考试结束接口 + * @returns + */ +export const TheExamIsOver = async (judgeUI: JudgePage, that: JudgeBusiness, callback: ProgressCallback) => { + const carInfo: CarInfoType = AppStorage.get("carInfo")! + const photoBase64 = await GetPhotoBase64(judgeUI.context); + const ksjs = that.ksjs! + dConsole.log(JudgeTag, "考试结束距离", that.ksjs) + const data: RegulatoryInterfaceParams = { + JGHOST: AppStorage.get("JGHOST") || "", + xtlb: '17', + jkxlh: judgeUI.serialNumber, + jkid: '17C56', + drvexam: { + lsh: judgeUI.lsh, + kchp: encodeURI(carInfo?.plateNo || ""), + kskm: carInfo?.examSubject || "2", + sfzmhm: judgeUI.idCard, + zp: photoBase64, + jssj: dayTs().format("YYYY-MM-DD HH:mm:ss"), + kscj: (judgeUI.totalScore * 1) > 0 ? judgeUI.totalScore : 0, + // kslc: Math.ceil(((ksjs?.qjjl + ksjs?.dcjl) || 0) / 100), + kslc: Math.ceil(((ksjs?.qjjl + ksjs?.dcjl) || 0) / 100), + dwlc: [ksjs.d1, ksjs.d2, ksjs.d3, ksjs.d4, ksjs!.d5].map((d, index) => `${index + 1},${Math.floor(d / 100)}`) + .join(';'), + } + } + dConsole.log(ProcessDataTag, QueueTag, ExamProcessDataTag, "考试结束数据", data) + ProcessDataTaskPoolInstance.addTask(data, callback) +} + const getSBXH = (ksxm: number, xmxh: string, cdsbInfoObj: CDSBInfos, projectsObj: object, examSubject: string): string => { const project: ProjectInfo = Reflect.get(projectsObj, ksxm); diff --git a/entry/src/main/ets/pages/Judge/ProcessDataTaskPool.ets b/entry/src/main/ets/pages/Judge/ProcessDataTaskPool.ets index 348cf68..8cc8f3e 100644 --- a/entry/src/main/ets/pages/Judge/ProcessDataTaskPool.ets +++ b/entry/src/main/ets/pages/Judge/ProcessDataTaskPool.ets @@ -1,11 +1,23 @@ -import { ProcessDataEnumType, RegulatoryInterfaceParams, WR, WuxiExamType } from '../../model'; +import { + DrvexamType, + OnAllTasksCompletedCallback, + OnBatchProgressUpdateCallback, + ProcessDataEnumType, + ProgressCallback, + QueueTask, + RegulatoryInterfaceParams, + WR, + WuxiExamType +} from '../../model'; import taskpool from '@ohos.taskpool'; -import { dConsole } from '../../utils/LogWorker'; +import { QueueTag } from '../../config'; import http from '@ohos.net.http'; import Request from '../../utils/Request'; +import { dConsole } from '../../utils/LogWorker'; + export class ProcessDataTaskPool { - private queue: RegulatoryInterfaceParams[] = []; + private queue: QueueTask[] = []; private isProcessing: boolean = false; /** 最大重试次数。1次初次尝试 + 5次重试 = 总共6次尝试。 */ private readonly maxRetries = 5; @@ -13,10 +25,45 @@ export class ProcessDataTaskPool { private readonly minProcessingTime = 2000; /** 记录每个任务的开始处理时间 */ private taskStartTime: number = 0; + /** 批次进度更新时的回调函数 */ + private onBatchProgressUpdateCallback: OnBatchProgressUpdateCallback | null = null; + /** 所有任务完成时的回调函数 (批次) */ + private onAllTasksCompletedCallback: OnAllTasksCompletedCallback | null = null; + // 用于跟踪批次任务完成情况 + private totalTasksInCurrentBatch: number = 0; + private completedTasksInCurrentBatch: number = 0; + private successfulTasksInCurrentBatch: number = 0; + private failedTasksInCurrentBatch: number = 0; - public addTask(dataItem: RegulatoryInterfaceParams): void { - console.info(`[Queue] 新任务已添加: ${JSON.stringify(dataItem)},当前队列长度: ${this.queue.length + 1}`); - this.queue.push(dataItem); // 将任务添加到队尾 + /** + * 设置批次进度更新时的回调函数 + * @param callback 回调函数 + */ + public setOnBatchProgressUpdateCallback(callback: OnBatchProgressUpdateCallback): void { + this.onBatchProgressUpdateCallback = callback; + } + + /** + * 设置所有任务完成时的回调函数 + * @param callback 回调函数 + */ + public setOnAllTasksCompletedCallback(callback: OnAllTasksCompletedCallback): void { + this.onAllTasksCompletedCallback = callback; + } + + /** + * 添加任务到队列。 + * 注意:为了正确追踪批次,通常建议一次性添加一个批次的所有任务。 + * 如果在处理过程中动态添加任务,会影响 `totalTasksInCurrentBatch` 的准确性, + * 进而影响 `onAllTasksCompletedCallback` 的触发时机和进度计算。 + * @param dataItem 任务数据 + */ + public addTask(dataItem: RegulatoryInterfaceParams, callback?: ProgressCallback): void { + console.info(QueueTag, `新任务已添加: ${JSON.stringify(dataItem)},当前队列长度: ${this.queue.length + 1}`); + this.queue.push({ data: dataItem, callback: callback }); // 将任务添加到队尾 + + // 每次添加任务,增加当前批次的总任务数 + this.totalTasksInCurrentBatch++; this.triggerProcessing(); // 尝试启动处理流程 } @@ -26,70 +73,107 @@ export class ProcessDataTaskPool { */ private triggerProcessing(): void { if (this.isProcessing) { - console.log('[Queue] 处理器正在运行中,新任务将在稍后被处理。'); + console.log(QueueTag, '处理器正在运行中,新任务将在稍后被处理。'); return; } - // [优化] 直接调用 async 函数,它会立即返回一个 Promise,不会阻塞当前执行流,效果与 Promise.resolve().then() 相同但更简洁。 this.processQueue(); } private async processQueue(): Promise { this.isProcessing = true; - console.log(`[Queue] 启动处理器... 待处理任务数: ${this.queue.length}`); + console.log(QueueTag, `启动处理器... 待处理任务数: ${this.queue.length}`); while (this.queue.length > 0) { - const taskData = this.queue[0]; // 查看队首任务 + const taskData = this.queue[0].data; // 查看队首任务 + const callback = this.queue[0].callback || (() => { + }); this.taskStartTime = Date.now(); // 记录任务开始时间 try { - console.log(`[Queue] 开始处理任务: ${JSON.stringify(taskData)}`); + console.log(QueueTag, `开始处理任务: ${JSON.stringify(taskData)}`); + + let drvexam: DrvexamType = JSON.parse(JSON.stringify(taskData.drvexam)) + drvexam.zp = "" - // 预先记录将要处理的数据 const obj: WuxiExamType = { xtlb: taskData.xtlb, jkxlh: taskData.jkxlh, jkid: taskData.jkid, - drvexam: { - zp: "", - }, + drvexam: drvexam, }; + dConsole.writeProcessData(ProcessDataEnumType.WuxiExam, JSON.stringify(obj)); - // 此方法若成功则正常返回,若永久失败则会抛出错误 - await this.processSingleTaskWithRetries(taskData); + await this.processSingleTaskWithRetries(taskData, callback); - // 任务成功,将其从队列中移除 + // 任务成功 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); - } + console.log(QueueTag, `✅ 任务处理成功,已从队列移除。剩余任务: ${this.queue.length}`); + this.successfulTasksInCurrentBatch++; // 增加成功任务计数 } catch (error) { - // **[健壮性改进]** 捕获到永久失败的错误。 - // 原有逻辑会清空整个队列,导致后续任务丢失。 - // 优化后的逻辑是:仅移除当前失败的任务,并记录错误,然后继续处理队列中的下一个任务。 - console.error(`[Queue] 🔥 任务永久失败: ${(error as Error).message}`); + // 任务永久失败 + console.error(QueueTag, ` 🔥 任务永久失败: ${(error as Error).message}`); const failedTask = this.queue.shift(); // 移除失败的任务 console.error(`[Queue] 失败的任务已被移除: ${JSON.stringify(failedTask)},将继续处理下一个任务。`); + this.failedTasksInCurrentBatch++; // 增加失败任务计数 + } finally { + // 无论成功或失败,都增加已完成任务计数 + this.completedTasksInCurrentBatch++; - // 即使任务失败,也需要满足最小处理时间要求 + // 每次任务完成(或失败),都更新进度 + this.reportBatchProgress(); + + // 检查是否所有任务都已处理完 + if (this.queue.length === 0 && this.completedTasksInCurrentBatch === this.totalTasksInCurrentBatch) { + console.log(QueueTag, ' 所有任务处理完毕!"总数', this.totalTasksInCurrentBatch, "完成的"); + this.onAllTasksCompletedCallback?.( + this.totalTasksInCurrentBatch, + this.completedTasksInCurrentBatch, + this.successfulTasksInCurrentBatch, + this.failedTasksInCurrentBatch + ); + // 重置批次计数器,为下一批次做准备 + this.resetBatchCounters(); + } + + // 计算任务实际耗时,并根据需要延迟 const elapsedTime = Date.now() - this.taskStartTime; if (elapsedTime < this.minProcessingTime) { const delayTime = this.minProcessingTime - elapsedTime; - console.log(`[Queue] 失败任务处理耗时 ${elapsedTime}ms,需要延迟 ${delayTime}ms 以满足最小处理时间要求`); + console.log(QueueTag, ` 任务处理耗时 ${elapsedTime}ms,需要延迟 ${delayTime}ms 以满足最小处理时间要求`); await this.delay(delayTime); } } } this.isProcessing = false; - console.log('[Queue] 处理器已停止。'); + console.log(QueueTag, ' 处理器已停止。'); + } + + /** + * 报告批次进度 + */ + private reportBatchProgress(): void { + if (this.onBatchProgressUpdateCallback && this.totalTasksInCurrentBatch > 0) { + const progressPercentage = Math.floor((this.completedTasksInCurrentBatch / this.totalTasksInCurrentBatch) * 100); + this.onBatchProgressUpdateCallback( + this.totalTasksInCurrentBatch, + this.completedTasksInCurrentBatch, + this.successfulTasksInCurrentBatch, + this.failedTasksInCurrentBatch, + progressPercentage + ); + } + } + + /** + * 重置批次任务计数器 + */ + private resetBatchCounters(): void { + this.totalTasksInCurrentBatch = 0; + this.completedTasksInCurrentBatch = 0; + this.successfulTasksInCurrentBatch = 0; + this.failedTasksInCurrentBatch = 0; } /** @@ -100,28 +184,22 @@ export class ProcessDataTaskPool { return new Promise(resolve => setTimeout(resolve, ms)); } - private async processSingleTaskWithRetries(taskData: RegulatoryInterfaceParams): Promise { - // 1 次初次尝试 + 5 次重试 + private async processSingleTaskWithRetries(taskData: RegulatoryInterfaceParams, callback: ProgressCallback): Promise { for (let attempt = 0; attempt <= this.maxRetries; attempt++) { const attemptNum = attempt + 1; try { const attemptType = attempt === 0 ? '初次尝试' : `重试 ${attempt}`; - console.log(`[Queue] 开始上传 (${attemptType}, 总共第 ${attemptNum} 次)`); - - // **注意**: 这里传递的是 taskData 的引用,为了防止 worker 中意外修改原始数据, - // 最佳实践是在 worker 内部或传递前进行深拷贝。 - // 但根据我们下面的修复,worker 不再修改原始数据,所以这里是安全的。 - const result: WR = await taskpool.execute(uploadWorkerTask, taskData); - + console.log(QueueTag, `开始上传 (${attemptType}, 总共第 ${attemptNum} 次)`); + const result: WR = (await taskpool.execute(uploadWorkerTask, taskData)) as WR; + callback(result) dConsole.writeProcessData(ProcessDataEnumType.WuxiExam, JSON.stringify(result)); - if (result.code === 1) { - console.log(`[Queue] ✔️ 上传成功 (在第 ${attemptNum} 次尝试)`); + if (result.code === "1") { + console.log(QueueTag, ` ✔️ 上传成功 (在第 ${attemptNum} 次尝试)`); return; // 成功,立即返回 } - console.warn(`[Queue] ❌ 上传失败 (第 ${attemptNum} 次)。响应: ${result.message}`); + console.warn(QueueTag, ` ❌ 上传失败 (第 ${attemptNum} 次)。${result.code},响应: ${decodeURIComponent(result.message)}`); } catch (e) { - // **[健壮性改进]** 现在可以捕获从 Worker 抛出的更详细的异常信息 - console.error(`[Queue] ❌ TaskPool 执行或网络错误 (第 ${attemptNum} 次): ${e}`); + console.error(QueueTag, ` ❌ TaskPool 执行或网络错误 (第 ${attemptNum} 次): ${e}`); } if (attempt === this.maxRetries) { @@ -129,55 +207,45 @@ export class ProcessDataTaskPool { } } - // 如果循环结束,意味着所有尝试都失败了 throw new Error(`任务 ${JSON.stringify(taskData)} 在 ${this.maxRetries + 1} 次尝试后永久失败。`); } } export const ProcessDataTaskPoolInstance = new ProcessDataTaskPool(); -/** - * 这是将在 Worker 线程中执行的任务函数。 - * 它负责执行单次的上传尝试。 - * @param data 需要上传的单条数据项 - * @returns 一个包含本次上传尝试结果的对象 - */ +@Concurrent export async function uploadWorkerTask(data: RegulatoryInterfaceParams): Promise { - // 这两个变量似乎未在逻辑中使用,暂时保持原样 let singlePlay: boolean = false; let isJGNew = false; try { + const sendProcessData = async (data: RegulatoryInterfaceParams, singlePlay: boolean, isJGNew: boolean): Promise => { + if (singlePlay) { + return { code: "1" } + } + if (isJGNew) { + // 调用新监管 + } + data.drvexam = data.drvexam ?? {}; + if (data.drvexam.zp !== undefined && data.drvexam.zp !== null) { + data.drvexam.zp = encodeURIComponent(data.drvexam.zp); + } + + const drvexamArr = Object.entries(data.drvexam) + .filter((item: [string, string]) => item[1] != undefined) + .map((item: [string, object]) => `<${item[0]}>${item[1]}`) + return await Request({ + host: data.JGHOST, + url: '/dems_ws/services/TmriOutAccess?wsdl', + data: ` ${data.xtlb} ${data.jkxlh} ${data.jkid} ${drvexamArr.join('')} ]]> `, + method: http.RequestMethod.POST, + xml: true + }) as WR + } const response = await sendProcessData(data, singlePlay, isJGNew); return response; } catch (err) { - // [健壮性改进] 捕获请求过程中的异常,并重新抛出。 - // 这能让主线程的 taskpool.execute() promise 变为 rejected 状态, - // 从而被 processSingleTaskWithRetries 中的 try-catch 捕获,保留了详细的错误信息。 const error = err as Error; - console.error(`[Worker] 上传时发生异常: ${error.message}`); - throw error; // 重新抛出异常 + console.error(QueueTag, `[Worker] 上传时发生异常: ${error.message}`); + throw error; } } - -async function sendProcessData(data: RegulatoryInterfaceParams, singlePlay: boolean, isJGNew: boolean): Promise { - if (singlePlay) { - return { code: 1 } - } - if (isJGNew) { - // 调用新监管 - } - data.drvexam = data.drvexam ?? {}; - data.drvexam.zp = data.drvexam.zp === undefined ? undefined : encodeURIComponent(data.drvexam.zp); - - const drvexamArr = Object.entries(data.drvexam) - .filter((item: [string, string]) => item[1] != undefined) - .map((item: [string, object]) => `<${item[0]}>${item[1]}`) - let JGHOST: string = AppStorage.get("JGHOST") || "" - return await Request({ - host: JGHOST, - url: '/dems_ws/services/TmriOutAccess?wsdl', - data: ` ${data.xtlb} ${data.jkxlh} ${data.jkid} ${drvexamArr} ]]> `, - method: http.RequestMethod.POST, - xml: true - }) -} \ No newline at end of file diff --git a/entry/src/main/ets/pages/Judge/SmallJudgeBusiness.ets b/entry/src/main/ets/pages/Judge/SmallJudgeBusiness.ets new file mode 100644 index 0000000..0b8da64 --- /dev/null +++ b/entry/src/main/ets/pages/Judge/SmallJudgeBusiness.ets @@ -0,0 +1,328 @@ +import { JudgeConfig, JudgeTag } from '../../config'; +import { + CAR_INFO, + CarInfoType, + CDSBInfo, + EnvironmentConfigurationType, + ExaminerInfoType, + ItemInfo, + ItemInfos, + JudgeBeginObj, + JudgeInitObj, + JudgeKFXM, + JudgeKSXM, + Km3JudgeInitConfig, + MAPITEMPOINTITEM, + MAPPOINT, + MarkRule, + Project, + ProjectInfo, + ProjectInfos, + RouteParamsType, + SyssetConfig, + SYSTEM_PARAM +} from '../../model'; +import common from '@ohos.app.ability.common'; +import { dConsole } from '../../utils/LogWorker'; +import { examJudgeVersion } from './JudgeSDKUtils'; +import JudgeBusiness from './JudgeBusiness'; +import router from '@ohos.router'; +import { GetModelData } from './utils'; +import { BaseJudge, BaseJudgeImpl, GetSysSetResult } from './BaseJudgeBussines'; +import { GetSyncData } from '../../utils/table/Operation'; +import promptAction from '@ohos.promptAction'; +import { JudgePage } from '../Judge'; +import systemDateTime from '@ohos.systemDateTime'; +import { testKm2Items, testKm3Items } from '../../mock/Judge'; + +export class SmallJudge extends BaseJudge implements BaseJudgeImpl { + getIsUdpEnd(): boolean { + return super.getIsUdpEnd() + } + + public async GetJudgeBeginData(projects: Project[], carType: string, kssycs: string, isDdxk: boolean, ddxkTime: number, projectsCenterObj: Object, ddxkKsxmArr: string[], ddxkKfArr: string[], passingScore: number, wayno: number, name: string, lsh: string, idCard: string, isExam: boolean) { + const examinerInfo = AppStorage.get('examinerInfo') + const examinerName = examinerInfo?.name || "" + let currentParams: RouteParamsType = router.getParams() as RouteParamsType; + const sczb = currentParams.sczb; + const kfdm = currentParams.kfdm; + const ksxm: JudgeKSXM[] = projects.map(project => { + const temp: JudgeKSXM = { + xmdm: Number(project.projectCode), xmxh: '' + } + return temp + }) + const ykxm: number[] = (ddxkKsxmArr?.map(projectCenterCode => { + const currentProject: ProjectInfo = Reflect.get(projectsCenterObj, projectCenterCode) + return Number(currentProject.projectCode) + })) || []; + const kfxm: JudgeKFXM[] = isDdxk ? (ddxkKfArr?.map(kf => { + return { + xmdm: Number(kf.split(',')[0]), kfdm: kf.split(',')[1] + } as JudgeKFXM + })) : [] + const beginInfo: JudgeBeginObj = { + kgid: '012', + kgxm: decodeURI(examinerName || ''), + exam: isExam ? 1 : 0, + //是否回放 + replay: 0, + //生成的轨迹文件 + track: '', + xm: name, + sex: 0, + kslsh: lsh, + sfzmhm: idCard, + ksyy: '', + kscx: carType, + kkcs: Number(kssycs) || 2, + sfyk: 0, + ykkkcs: 1, + wayno: Number(wayno), + czlx: 0, + kskssj: await systemDateTime.getCurrentTime(), + passing: Number(passingScore), + ksxm, + //断点续考 + ddxk: isDdxk ? 1 : 0, + ddkssj: ddxkTime || 0, + ykxm, + kfxm, + yklc: 0, + special: [], + sczb: (sczb === undefined || sczb == '0') ? 0 : 1, + sczbkf: kfdm, + dmndg: false, + mfxx: false, + zeng: false + } + dConsole.info(JudgeTag, '5.获取开始考试数据完成') + return beginInfo + }; + + public async GetJudgeInitData(context: common.UIAbilityContext, markRuleListObj: object, carType: string, carName: string, systemparmArr: SYSTEM_PARAM[], carinfoArr: CAR_INFO[], examSubject: string, itemInfoObj: ItemInfos, judgeConfig: SyssetConfig[], carlist: string, mapPointArr: MAPPOINT[], mapPointItemArr: MAPITEMPOINTITEM[]) { + const carInfo = AppStorage.get('carInfo'); + dConsole.log(JudgeTag, "itemInfoObj", itemInfoObj) + let allitems: ItemInfo[] = []; + if (examSubject == '2' && itemInfoObj) { + const promiseItems = Reflect.ownKeys(itemInfoObj).map(async cdsbKey => { + // const cdsb: CDSBInfo = Reflect.get(itemInfoObj, cdsbKey); + const cdsb: CDSBInfo = Object.entries(itemInfoObj).find((arr: Array) => arr[0] === cdsbKey)![1]; + const model = await GetModelData(`/${cdsb.modelKey}.txt`, context); + const temp: ItemInfo = { + xmdm: cdsb?.xmdm || 0, + xmxh: cdsb?.xmxh || "", + model: model || "" + }; + return temp; + }); + // 等待所有的 Promise 解析完成 + allitems = await Promise.all(promiseItems); + } + + const mark: MarkRule[] = Object.values(markRuleListObj) + const initInfo: JudgeInitObj = { + sdkver: await examJudgeVersion(), + appver: AppStorage.get('EnvironmentConfigurationType')?.version || "", + kskm: Number(carInfo?.examSubject || "2"), + kchp: carInfo?.plateNo || "", + kchm: Number(carInfo?.carId || ""), + kscx: carType, + cxcode: '1', + name: carName, + carmodel: await GetModelData(`/${carType}.txt`, context) || "", + allitems, + iteminfo: [], + systemparm: systemparmArr, + mark, + sysset: judgeConfig, + itemInfoObj, + carlist: carlist, + carinfo: carinfoArr, + }; + let km3Config: Km3JudgeInitConfig = {} + if (examSubject == '3') { + km3Config = { + map_point: mapPointArr, + map_point_item: mapPointItemArr, + //科目三暂时为空 + iteminfo: [], + roads: await GetModelData('/Roads.txt', context) || "", + sharps: await GetModelData('/Sharps.txt', context) || "" + }; + initInfo.map_point = km3Config.map_point + initInfo.map_point_item = km3Config.map_point_item + initInfo.iteminfo = km3Config.iteminfo + initInfo.roads = km3Config.roads + initInfo.sharps = km3Config.sharps + } + // 获取科目三的评判配置 + dConsole.info(JudgeTag, '3.获取评判初始化数据完成') + return initInfo + }; + + public async JudgeInit(judgeUI: JudgePage, that: JudgeBusiness): Promise { + const systemParams = await GetSyncData('MA_SYSTEMPARM') + let currentParams: RouteParamsType = router.getParams() as RouteParamsType; + let totalScore: number = 100 + let wayno: number = 1 + let carlist: string = "" + let passingScore: number = 90 + let examMileage: string = "" + let projectsObj: ProjectInfos = {} + let projectsCenterObj: ProjectInfos = {} + let ddxkKsxmArr: Array = [] + let singlePlay: boolean = AppStorage.get("singlePlay")! + let systemparmArr: Array = [] + let projects: Array = [] + let examSubject: string = AppStorage.get('carInfo')!.examSubject! + if (singlePlay) { + wayno = Number(currentParams.wayno) || 1; + } + //真实监管下发的项目 + let kStringArr: string[] = (currentParams.kString?.split(',') || []).filter(item => item); + let isInExam = kStringArr.length > 0; + let carNo: string, allItems: string[] = []; + systemParams.forEach((systemParam) => { + if (JudgeConfig.isTrajectoryOpen) { + systemParam.no1 = systemParam.NO1!.toString()!; + systemParam.no2 = systemParam.NO2!.toString()!; + systemParam.no3 = systemParam.NO3!.toString()!; + systemParam.txt1 = systemParam.TXT1!; + systemParam.txt2 = systemParam.TXT2!; + systemParam.txt3 = systemParam.TXT3!; + } + const txt1 = decodeURI(systemParam.txt1 || "") + const txt2 = decodeURI(systemParam.txt2 || "") + + const no1 = systemParam.no1; + const no2 = systemParam.no2; + const no3 = systemParam.no3; + + //获取当前考车的no2 + if (no1 === "3" && no3 === "1") { + if (txt1 === judgeUI.carName) { + carNo = no2! + } + } + + //获取及格分数线 + if (no1 === "3" && no3 === "3" && carNo === no2) { + passingScore = Number(txt1) || 0; + } + //根据车型获取应行驶里程数 + if (no1 === "3" && no3 === "15" && carNo === no2) { + examMileage = ((decodeURI(systemParam.txt1 || "")) || '').split('^')[0]; + } + //获取当前考车的考试项目 + if (carNo && no1 === "3" && no2 == carNo && no3 === "10") { + allItems = decodeURIComponent(systemParam.txt1 || "").split(',').filter(txt => txt !== '') + dConsole.info(JudgeTag, '考试项目', allItems) + } + if ( + //科目二获取项目 + (examSubject == "2" && allItems.length && no1 === "6" && allItems.includes(no2 + "" || "")) + || + //科目三获取项目 + (examSubject == "3" && no1 === "6") + ) { + const name = decodeURI(systemParam.txt1 || "") + //小车过滤掉 夜间模拟行驶 + if (name === '夜间行驶') { + return + } + const currentProject: Project = { + name, + abbreviation: decodeURI(systemParam.txt3 || ""), + projectCode: no2 + '', + projectCodeCenter: txt2, + //是否是必考 加减档设置成非必考 + isRequired: no2 === "14" ? false : allItems.includes(no2 + ''), + //是否考过了 + isEnd: false, + //项目开始数据是否上传过 + isUpload: false, + } + const no2Num = Number(no2) + //真实监管下发考试项目 + if (isInExam && !(kStringArr.includes(txt2) || kStringArr.includes(no2 + ''))) { + dConsole.info(JudgeTag, '=> no2', no2) + currentProject.type = '3' + currentProject.isUpload = true + currentProject.isEnd = true + ddxkKsxmArr.push(txt2) + } + Reflect.set(projectsObj, no2Num, currentProject) + Reflect.set(projectsCenterObj, txt2, currentProject) + projects.push(currentProject); + } + systemparmArr.push({ + NO1: Number(no1), + NO2: Number(no2), + NO3: Number(no3), + TXT1: decodeURIComponent(systemParam.txt1 || ""), + TXT2: decodeURIComponent(systemParam.txt2 || ""), + TXT3: decodeURIComponent(systemParam.txt3 || ""), + }) + }) + if (!projects.length) { + promptAction.showToast({ + message: '读取数据库信息失败,请重新联网更新!', + duration: 8000 + }); + dConsole.log(JudgeTag, "router back3") + router.back(); + } + + (examSubject === '2' ? testKm2Items : testKm3Items).forEach(item => { + let project: ProjectInfo = Reflect.get(judgeUI.projectsCenterObj, item.code) + Reflect.set(that.kmItems, item.code, { + code: item.code, + status: project === undefined ? 0 : (project.isEnd ? 3 : 1) + }) + }) + + return { + totalScore, + wayno, + carlist, + passingScore, + examMileage, + projectsObj, + projectsCenterObj, + ddxkKsxmArr, + singlePlay, + systemparmArr, + projects, + } + } + + public async JudgeStart(callBack: Function, judgeUI: JudgePage, that: JudgeBusiness) { + const isTrajectoryOpen = JudgeConfig.isTrajectoryOpen; + const trajectoryPath = JudgeConfig.trajectoryPath; + let strArr: string[] = []; + if (isTrajectoryOpen) { + const folderPath = await that.fileUtil.initFolder(trajectoryPath); + const str: string = await that.fileUtil.readFile(folderPath) + strArr = str.split('\n') + } + let initInfo: JudgeInitObj = isTrajectoryOpen ? JSON.parse(strArr[0]) : await this.GetJudgeInitData(judgeUI.context, judgeUI.markRuleListObj, judgeUI.carType, judgeUI.carName, judgeUI.systemparmArr, judgeUI.carinfoArr, judgeUI.examSubject, judgeUI.itemInfoObj!, judgeUI.judgeConfig, judgeUI.carlist, judgeUI.mapPointArr, judgeUI.mapPointItemArr); + let beginExamInfo: JudgeBeginObj | undefined = undefined + + if (isTrajectoryOpen) { + beginExamInfo = JSON.parse(strArr[1]) + beginExamInfo && (beginExamInfo.replay = 1) + } else { + beginExamInfo = await this.GetJudgeBeginData(judgeUI.projects, judgeUI.carType, judgeUI.kssycs, judgeUI.isDdxk, judgeUI.ddxkTime, judgeUI.projectsCenterObj, judgeUI.ddxkKsxmArr, judgeUI.ddxkKfArr, judgeUI.passingScore, judgeUI.wayno, judgeUI.name, judgeUI.lsh, judgeUI.idCard, that.isExam) + } + super.judgeStart(callBack, judgeUI, that, beginExamInfo!, initInfo) + }; + + public async Judging(strData: string, callBack: Function, judgeUI: JudgePage, that: JudgeBusiness) { + super.judging(strData, callBack, judgeUI, that) + } + + public async JudgeEnd(judgeUI: JudgePage, that: JudgeBusiness, isManual?: boolean) { + super.judgeEnd(judgeUI, that, isManual) + }; +} diff --git a/entry/src/main/ets/pages/Judge/components/JudgeAndProject.ets b/entry/src/main/ets/pages/Judge/components/JudgeAndProject.ets index 3c45847..bb6a7f4 100644 --- a/entry/src/main/ets/pages/Judge/components/JudgeAndProject.ets +++ b/entry/src/main/ets/pages/Judge/components/JudgeAndProject.ets @@ -1,5 +1,5 @@ import { JudgeTag } from '../../../config/index'; -import { DefaultJudgeConfigObj, LANE, MarkRule, ProjectInfo, ProjectInfos } from '../../../model/index'; +import { DefaultJudgeConfigObj, LANE, MarkRule, Project, ProjectInfo, ProjectInfos } from '../../../model/index'; import { CutArray } from '../../../utils/Common'; import { dConsole } from '../../../utils/LogWorker'; import { GetIsEndManualProject, GetIsExitManualProject } from '../utils'; @@ -11,9 +11,9 @@ export default struct JudgeAndProjectComponent { @Prop judgeConfigObj: DefaultJudgeConfigObj @Prop dw: string @Prop sd: string - @Prop @Watch("scrollLengthChange") kfArr: MarkRule[] + @Prop @Watch("scrollLengthChange") kfArr: MarkRule[] = [] @Prop examSubject: string - @Prop projects: ProjectInfo[] + @Prop projects: Project[] @Prop artSubject3Projects: string[] @Prop artSubject3ProjectsCodesArr: string[] @Prop projectsObj: ProjectInfos @@ -26,9 +26,8 @@ export default struct JudgeAndProjectComponent { examClick: (index: number) => void = (index: number) => { } - scrollLengthChange(data: MarkRule[]) { - dConsole.log(JudgeTag, "容器滚动", data.length) - if (data.length > 4) { + scrollLengthChange() { + if (this.kfArr.length > 4) { this.kfArrScroller.scrollTo({ yOffset: 999999, xOffset: 0 }) @@ -37,6 +36,7 @@ export default struct JudgeAndProjectComponent { getProjectColor(project: ProjectInfo) { const type = project.type; + dConsole.log(JudgeTag, "扣分", project, type) switch (type) { case '1': return '#E6DECF'; @@ -133,42 +133,31 @@ export default struct JudgeAndProjectComponent { //科目二 if (this.examSubject == "2") { Flex({ wrap: FlexWrap.Wrap, direction: FlexDirection.Row, justifyContent: FlexAlign.SpaceBetween }) { - List({}) { - ForEach(CutArray(this.projects, 2), (item: [ProjectInfo, ProjectInfo]) => { - ListItem() { - Row() { - Row() { - //#FF7566 #00FFD5 #E6DECF - // Text(this.projectsObj[item[0].projectCode]) - Text(item[0].abbreviation) - .fontSize(item[0].abbreviation!.length > 5 ? 28 : 32) - .fontColor(this.getProjectColor(item[0])) - } - .backgroundImage($rawfile('judge/project_item.png'), ImageRepeat.NoRepeat) - .backgroundImageSize({ width: '100%', height: '100%' }) - .width('48.5%') - .height(115) - .margin({ bottom: 5 }) - .justifyContent(FlexAlign.Center) - - if (item[1]) { - Row() { - //#FF7566 #00FFD5 #E6DECF - Text(item[1].abbreviation) - .fontSize(item[1].abbreviation.length > 5 ? 28 : 32) - .fontColor(this.getProjectColor(item[1])) - } - .backgroundImage($rawfile('judge/project_item.png'), ImageRepeat.NoRepeat) - .backgroundImageSize({ width: '100%', height: '100%' }) - .width('48.5%') - .height(115) - .margin({ left: 5, bottom: 5 }) - .justifyContent(FlexAlign.Center) - } - } + ForEach(this.projects, (item: ProjectInfo, index: number) => { + Row() { + Row() { + Text(item.abbreviation) + .fontSize(item.abbreviation!.length > 5 ? 28 : 32) + .fontColor(this.getProjectColor(Reflect.get(this.projectsObj, item.projectCode))) } - }); - } + .backgroundImage($rawfile('judge/project_item.png'), ImageRepeat.NoRepeat) + .backgroundImageSize({ width: '100%', height: '100%' }) + .width('48.5%') + .height(115) + .margin({ bottom: 5 }) + .justifyContent(FlexAlign.Center) + + if (this.projects.length % 2 === 1 && index === this.projects.length - 1) { + Row() { + + } + .width('48.5%') + .height(115) + .margin({ left: 5, bottom: 5 }) + .justifyContent(FlexAlign.Center) + } + } + }); } .backgroundImage($rawfile('judge/project_bg.png'), ImageRepeat.NoRepeat) .backgroundImageSize({ width: '100%', height: '100%' }) @@ -214,10 +203,6 @@ export default struct JudgeAndProjectComponent { ForEach(this.artSubject3Projects, (item: string, index) => { ListItem() { } - // $rawfile( - // `judge/km3/${this.getIsExitManualProject(index) ? (this.getIsEndManualProject(index)) : - // (item + '_gray')}.png` - // ) .backgroundImage( $rawfile( `judge/km3/${GetIsExitManualProject(index, this.judgeConfigObj, this.artSubject3ProjectsCodesArr, this.projectsObj, this.carztStr, this.isManualProjectIn, this.isProjectIn, this.jl, this.examMileage, this.isRequiredProjectsEnd, this.lane) ? (GetIsEndManualProject(index, this.artSubject3Projects, this.artSubject3ProjectsCodesArr, this.projectsObj)) : @@ -228,12 +213,7 @@ export default struct JudgeAndProjectComponent { .height(118 * 0.95) .margin({ bottom: 8 }) .onClick(() => { - // this.vocObj.playAudio({ - // type: 1, - // name: 'button_media.wav' - // }) this.examClick(index) - // this.setManualProjectFn(index) }) }) }.lanes(3).margin({ left: 5, top: 12 }) diff --git a/entry/src/main/ets/pages/Judge/components/Message.ets b/entry/src/main/ets/pages/Judge/components/Message.ets index f7d8895..598dc69 100644 --- a/entry/src/main/ets/pages/Judge/components/Message.ets +++ b/entry/src/main/ets/pages/Judge/components/Message.ets @@ -12,13 +12,21 @@ export default struct MessageComponent { @Prop jl: number @Prop wayno: number @Prop judgeConfigObj: DefaultJudgeConfigObj + @State timer: number = -1 + onTimeUpdate?: (time: number) => void aboutToAppear(): void { - setInterval(async () => { + this.timer = setInterval(async () => { this.examTime += 1; + this.onTimeUpdate?.(this.examTime) }, 1000); } + aboutToDisappear(): void { + clearInterval(this.timer) + this.timer = -1 + } + build() { Row() { Column() { diff --git a/entry/src/main/ets/pages/Judge/components/OperatingArea.ets b/entry/src/main/ets/pages/Judge/components/OperatingArea.ets index 58506d8..a9f24e6 100644 --- a/entry/src/main/ets/pages/Judge/components/OperatingArea.ets +++ b/entry/src/main/ets/pages/Judge/components/OperatingArea.ets @@ -1,4 +1,4 @@ -import { DefaultJudgeConfigObj } from '../../../model/index' +import { DefaultJudgeConfigObj, MarkRule } from '../../../model/index' import Prompt from '@system.prompt' @Component @@ -8,6 +8,8 @@ export default struct OperatingAreaComponent { @Prop examSubject: string @Prop singlePlay: boolean @Prop judgeConfigObj: DefaultJudgeConfigObj + @Prop kfArr: MarkRule[] + @Prop isAllProjectsEnd: boolean // 信号查看 signalViewingClick: () => void = () => { } @@ -112,6 +114,14 @@ export default struct OperatingAreaComponent { .backgroundImage($rawfile('judge/anniu_nor.png'), ImageRepeat.NoRepeat) .backgroundImageSize({ width: '100%', height: '100%' }) .onClick(() => { + //考试未结束且有扣分,不允许退出 + if (!this.singlePlay && Reflect.get(this.judgeConfigObj, '344') == "1" && this.kfArr.length > 0 && !this.isAllProjectsEnd) { + Prompt.showToast({ + message: '考试未结束且有扣分,不允许手动退出!', + duration: 4000 + }); + return + } if (Reflect.get(this.judgeConfigObj, '353') == '0') { // this.endExamDialogController.open() this.endTheExamClick() diff --git a/entry/src/main/ets/pages/Judge/components/SignalTrajectoryDialog.ets b/entry/src/main/ets/pages/Judge/components/SignalTrajectoryDialog.ets index 94918de..1e25e92 100644 --- a/entry/src/main/ets/pages/Judge/components/SignalTrajectoryDialog.ets +++ b/entry/src/main/ets/pages/Judge/components/SignalTrajectoryDialog.ets @@ -37,20 +37,21 @@ export default struct SignalTrajectoryDialog { }) } - Scroll() { - Column() { - if (this.active !== 2) { - SignalDisplayComponent({ - active: this.active, - }) - } else { - TrajectoryViewComponent({ - laneSignal: this.laneSignal - }) - } + // Scroll() { + Column() { + if (this.active !== 2) { + SignalDisplayComponent({ + active: this.active, + heightNum: 1500 + }) + } else { + TrajectoryViewComponent({ + laneSignal: this.laneSignal + }) + } - }.height(890) - }.width("100%") + }.height(890) + // }.width("100%") .height(700) }.width(1500) diff --git a/entry/src/main/ets/pages/Judge/utils.ets b/entry/src/main/ets/pages/Judge/utils.ets index c804cf0..7be5310 100644 --- a/entry/src/main/ets/pages/Judge/utils.ets +++ b/entry/src/main/ets/pages/Judge/utils.ets @@ -17,11 +17,13 @@ import { Radar, Vision } from '../../model'; -import { ArrayToByteArray, NumberToByteArray } from '../../utils/Common'; +import { ArrayToByteArray, NumberToByteArray, ReadFileContent } from '../../utils/Common'; import dayTs from '../../utils/Date'; import { dConsole } from '../../utils/LogWorker'; import VoiceAnnounce from '../judgeSDK/utils/voiceAnnouncements'; import { examJudgeSoundEnd } from './JudgeSDKUtils'; +import common from '@ohos.app.ability.common'; +import { GlobalConfig, JudgeConfig, JudgeTag } from '../../config'; // 中心信号转换 @@ -124,7 +126,7 @@ export function getKmProjectVoice( const param544Str: number[] = (Reflect.get(judgeConfig, '544')?.split(',')) || [] const param405Str: number = Reflect.get(judgeConfig, '405') || 0; - dConsole.info('surenjun => param544Str.length', param544Str.length) + dConsole.info('param544Str.length', param544Str.length) const num: number = lane?.num const count: number = lane?.count @@ -466,8 +468,9 @@ export function UploadRegulatoryCodeConversion( /** * 将PLC字符串转换为JSON对象 */ -export const PlcStrToJson = async (plc: string) => { +export const PlcStrToJson = async (plc: string, plc2?: string) => { const plcArr = plc.split(',') + const plc2Arr = plc2?.split(",") || [] const p = plcArr.map((val, key) => { if (key !== 27 && key !== 92) { return Number(val); @@ -475,6 +478,16 @@ export const PlcStrToJson = async (plc: string) => { return 0; // 或者返回 undefined,根据需求选择 } }); + let gps2p: number[] = [] + if (plc2) { + gps2p = plc2Arr.map((val, key) => { + if (key !== 27 && key !== 92) { + return Number(val); + } else { + return 0; // 或者返回 undefined,根据需求选择 + } + }); + } const time = await systemTime.getCurrentTime() const gps2: Gps = TestRealExam.gps2 const radar: Radar = TestRealExam.radar @@ -551,7 +564,30 @@ export const PlcStrToJson = async (plc: string) => { // 角度搜星数 jdsxs: Number(plcArr[92].split('-')[1]) || 0 }, - gps2: gps2, + gps2: plc2 ? { + //办卡类型 定位差分状态 + bklx: gps2p[56], + dwzt: gps2p[83], + // 角度差分状态 + jdzt: Number(plc2Arr[92].split('-')[0]), + //gps数据 + //gps时间 经度 纬度 航向角 俯仰角 海拔高 高度差 速度 + sj: time, + jd: gps2p[96], + wd: gps2p[95], + hxj: gps2p[90], + fyj: gps2p[91], + hbg: gps2p[85], + gdc: gps2p[86], + sd: gps2p[97], + //龄期 经度因子 纬度因子 定位搜星数 + age: gps2p[87], + jdyz: gps2p[89], + wdyz: gps2p[88], + dwsxs: gps2p[84] || 0, + // 角度搜星数 + jdsxs: Number(plc2Arr[92].split('-')[1]) || 0 + } : gps2, vision, radar, extend @@ -906,4 +942,20 @@ export const DetectingDifferences = async (type: number, avPlayer: VoiceAnnounce default: return true } -} \ No newline at end of file +} + +/** + * 获取车辆模型 + */ +export const GetModelData = async (modelName: string, context: common.UIAbilityContext): Promise => { + try { + let path = GlobalConfig.commonFileWriteAddress + "/" + JudgeConfig.modelPath + "/" + modelName + const res = await ReadFileContent(path) + return res || "" + // return new FileModel(context).getModelContent(JudgeConfig.modelPath, modelName) || ""; + } catch (e) { + // 可根据实际需求,返回空字符串或抛出异常 + dConsole.error(JudgeTag, `获取模型数据失败: ${modelName}`, e.message) + return ''; + } +}; diff --git a/entry/src/main/ets/pages/Settings.ets b/entry/src/main/ets/pages/Settings.ets index 22da083..0b4aa52 100644 --- a/entry/src/main/ets/pages/Settings.ets +++ b/entry/src/main/ets/pages/Settings.ets @@ -1,5 +1,5 @@ import router from '@ohos.router' -import { BaseInfoType, CarInfoType } from '../model/Common' +import { BaseInfoType, CarInfoType, EnvironmentConfigurationType } from '../model/Common' import HeaderComponent from './compontents/Header' import BottomMessageComponent from './Index/BottomMessage' @@ -10,10 +10,12 @@ struct SettingPage { @State url: string = '' @State baseInfo: BaseInfoType = {} @State carInfo: CarInfoType = {} + @State config: EnvironmentConfigurationType = {} aboutToAppear() { this.carInfo = AppStorage.get('carInfo')! this.baseInfo = AppStorage.get('baseInfo')! + this.config = AppStorage.get('EnvironmentConfiguration')! } build() { @@ -49,8 +51,8 @@ struct SettingPage { Column() { BottomMessageComponent({ - version: this.baseInfo.version, - judgeVersion: this.baseInfo.judgeVersion, + version: this.config.version, + judgeVersion: this.config.judgeVersion, hasAuth: this.baseInfo.hasAuth, examCarNumber: this.carInfo.carNo, }) diff --git a/entry/src/main/ets/pages/TerminalInfo.ets b/entry/src/main/ets/pages/TerminalInfo.ets index 1ff452e..d23d2cf 100644 --- a/entry/src/main/ets/pages/TerminalInfo.ets +++ b/entry/src/main/ets/pages/TerminalInfo.ets @@ -1,30 +1,43 @@ import HeaderComponent from './compontents/Header'; import { CommonListType, EnvironmentConfigurationType } from '../model'; import common from '@ohos.app.ability.common'; -import FileUtils from '../utils/FileUtils'; import { GlobalConfig, TerminalInfoTag } from '../config'; import ethernet from '@ohos.net.ethernet'; import { BusinessError } from '@ohos.base'; import Prompt from '@system.prompt'; import { dConsole } from '../utils/LogWorker'; +import window from '@ohos.window'; +import { BoardListData, CarTypeListData, LogListData, ManufacturerListData, RearMachineModelListData } from '../mock'; +import { OverWriteFile, ReadFileContent } from '../utils/Common'; @Entry @Component struct TerminalInfoPage { - @State config: EnvironmentConfigurationType = {} - private fileUtil!: FileUtils - private context = getContext(this) as common.UIAbilityContext; + @State config: EnvironmentConfigurationType = { + version: "2024.08.21.01", + judgeVersion: "2024.08.24.1" + } @State isProcessing: boolean = false; + @State IpConfigFilePath: string = GlobalConfig.commonFileWriteAddress + '/config/ipConfig.txt' + private context = getContext(this) as common.UIAbilityContext; async aboutToAppear() { - this.fileUtil = new FileUtils(this.context) - const data = await this.fileUtil.readFile(GlobalConfig.commonFileWriteAddress + '/config/ipConfig.txt'); + const data = await ReadFileContent(this.IpConfigFilePath) dConsole.log(TerminalInfoTag, "data", data) if (data) { this.config = JSON.parse(data) + if (!this.config.version) { + this.config.version = "2024.08.21.01" + } + if (!this.config.judgeVersion) { + this.config.judgeVersion = "2024.08.24.1" + } AppStorage.setOrCreate("EnvironmentConfiguration", this.config) } + } + async aboutToDisappear() { + dConsole.log(TerminalInfoTag, "TerminalInfoPage aboutToDisappear") } build() { @@ -80,6 +93,15 @@ struct TerminalInfoPage { this.config.udpOppositeIp = value; } }) + if (this.config.carType === "4") { + blockComponent({ + label: "后置机2IP", + value: this.config.udpOppositeIpTwo, + change: (value: string) => { + this.config.udpOppositeIpTwo = value; + } + }) + } blockComponent({ label: "后置机响应端口", value: this.config.udpOppositeIpPort, @@ -89,7 +111,7 @@ struct TerminalInfoPage { }) if (this.config.carType === "4") { blockComponent({ - label: "后置机响应端口2", + label: "后置机2响应端口", value: this.config.udpOppositeIpPortTwo, change: (value: string) => { this.config.udpOppositeIpPortTwo = value; @@ -186,6 +208,14 @@ struct TerminalInfoPage { this.config.isOpenFiniteDifference = value; } }) + blockComponent({ + label: "开启网络摄像头", + type: 7, + value: this.config.isUseNetworkCamera, + change: (value: string) => { + this.config.isUseNetworkCamera = value; + } + }) blockComponent({ label: "是否开启日志", type: 2, @@ -203,15 +233,28 @@ struct TerminalInfoPage { } }) blockComponent({ - label: "开启调试(重启APP)", + label: "开启调试", type: 6, value: this.config.isOpenDebugger, - change: (value: string) => { + change: async (value: string) => { this.config.isOpenDebugger = value; + const win = await window.getLastWindow(this.context); + if (value === "1") { + win.setWindowSystemBarEnable(['status', 'navigation']) + } else { + win.setWindowSystemBarEnable([]) + } + } + }) + blockComponent({ + label: "前置机厂商", + type: 8, + value: this.config.manufacturer, + change: (value: string) => { + this.config.manufacturer = value; } }) }.margin(20) - } .height(650) .width("100%") @@ -222,9 +265,8 @@ struct TerminalInfoPage { top: 10 }) - Row() { - Image($r('app.media.bc')).height(80).objectFit(ImageFit.Contain).onClick(() => { + Image($r('app.media.bc')).height(80).objectFit(ImageFit.Contain).onClick(async () => { if (this.isProcessing) { Prompt.showToast({ message: "请勿频繁点击", @@ -235,33 +277,43 @@ struct TerminalInfoPage { this.isProcessing = true dConsole.log(TerminalInfoTag, "保存配置", JSON.stringify(this.config)) AppStorage.setOrCreate("EnvironmentConfiguration", this.config) - this.fileUtil.addFile(GlobalConfig.commonFileWriteAddress + '/config/ipConfig.txt', JSON.stringify(this.config)) + // this.fileUtil.addFile(GlobalConfig.commonFileWriteAddress + '/config/ipConfig.txt', JSON.stringify(this.config)) + // 先删除文件 + const result = await OverWriteFile(this.IpConfigFilePath, JSON.stringify(this.config)) + if (result) { + Prompt.showToast({ + message: "保存配置文件成功", + duration: 3000 + }) + ethernet.setIfaceConfig("eth0", { + mode: ethernet.IPSetMode.STATIC, + ipAddr: this.config.udplocalIp, + route: "0.0.0.0", + gateway: this.config.gateway, //value.gateway网关 + netMask: this.config.netMask, //value.netMask网络掩码 + dnsServers: this.config.dnsServers, + domain: "" + }, (error: BusinessError) => { + if (error) { + Prompt.showToast({ + message: '设置失败' + JSON.stringify(error), + duration: 3000 + }); + } else { + Prompt.showToast({ + message: '设置网络成功', + duration: 3000 + }); + // 延迟几秒 + setTimeout(() => { + this.isProcessing = false + }, 3000) + } + }); + } + dConsole.init(this.config.isOpenLog) - ethernet.setIfaceConfig("eth0", { - mode: ethernet.IPSetMode.STATIC, - ipAddr: this.config.udplocalIp, - route: "0.0.0.0", - gateway: this.config.gateway, //value.gateway网关 - netMask: this.config.netMask, //value.netMask网络掩码 - dnsServers: this.config.dnsServers, - domain: "" - }, (error: BusinessError) => { - if (error) { - Prompt.showToast({ - message: '设置失败' + JSON.stringify(error), - duration: 3000 - }); - } else { - Prompt.showToast({ - message: '设置成功', - duration: 3000 - }); - // 延迟几秒 - setTimeout(() => { - this.isProcessing = false - }, 3000) - } - }); + }) } @@ -302,64 +354,13 @@ struct blockComponent { // 0 -输入框,1 -后置机类型,2 -日志开关,3 -板卡类型 @State type: number = 0 // '一型机', '二型机', '三型机', '一体机' - @State rearMachineModelList: CommonListType[] = [ - { - label: '一型机', - value: '1' - }, - { - label: '二型机', - value: '2' - }, - { - label: '三型机', - value: '3' - }, - { - label: '一体机', - value: '4' - } - ] + @State rearMachineModelList: CommonListType[] = RearMachineModelListData // '北云', '天宝MB2' - @State boardList: CommonListType[] = [ - { - label: '北云', - value: '1' - }, - { - label: '天宝MB2', - value: '2' - } - ] - @State logList: CommonListType[] = [ - { - label: '开启', - value: '1' - }, - { - label: '关闭', - value: '0' - } - ] + @State boardList: CommonListType[] = BoardListData + @State logList: CommonListType[] = LogListData // 车型 "小车C1", "小车C2", "大车", "牵引车A2" - @State carTypeList: CommonListType[] = [ - { - label: '小车C1', - value: '1' - }, - { - label: '小车C2', - value: '2' - }, - { - label: '大车', - value: '3' - }, - { - label: '牵引车A2', - value: '4' - } - ] + @State carTypeList: CommonListType[] = CarTypeListData + @State manufacturerList: CommonListType[] = ManufacturerListData aboutToAppear(): void { } @@ -396,8 +397,8 @@ struct blockComponent { }) } else { ForEach(this.type === 1 ? this.rearMachineModelList : - this.type === 2 || this.type === 5 || this.type === 6 ? this.logList : - this.type === 3 ? this.boardList : this.carTypeList, (item: CommonListType, index) => { + this.type === 2 || this.type === 5 || this.type === 6 || this.type === 7 ? this.logList : + this.type === 3 ? this.boardList : this.type === 8 ? this.manufacturerList : this.carTypeList, (item: CommonListType, index) => { Radio({ value: item.label, group: 'terRadioGroup' + this.type }) .borderColor('#E5CBA1') .checked(item.value === this.value ? true : false) diff --git a/entry/src/main/ets/pages/UserInfo.ets b/entry/src/main/ets/pages/UserInfo.ets index a95b50d..69fcfc0 100644 --- a/entry/src/main/ets/pages/UserInfo.ets +++ b/entry/src/main/ets/pages/UserInfo.ets @@ -32,7 +32,10 @@ import { SYSSET_VNO_MAP, SystemParamType, UDPParamType, - User + User, + WorkerBackMessage, + WorkerBackMessageType, + WorkerMessageDataType } from '../model'; import { BusinessError } from '@ohos.base'; import { GetSyncData, SqlInsertTable } from '../utils/table/Operation'; @@ -40,9 +43,7 @@ import { CheckSignal, GetCurrentUserKeyValue, InitializeExamProcessData } from ' import dayTs from '../utils/Date'; import { GetCurrentTime, GetPhotoBase64, NumberToByteArray } from '../utils/Common'; import DB from '../utils/DbSql'; -import { CenterUDPBusinessInstance } from '../utils/business/CenterUdpBusiness'; -import { JudgeEmitterInstance } from '../utils/business/UdpEvent'; -import { StartExamTag, UserInfoTag } from '../config'; +import { StartEndExamTag, StartExamTag, UserInfoTag } from '../config'; import { dConsole } from '../utils/LogWorker'; import HeaderComponent from './compontents/Header'; import AvatarComponent from './UserInfo/Avatar'; @@ -156,16 +157,9 @@ struct UserInfoPage { @State singlePlay: boolean = false private context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext; private avPlayer!: VoiceAnnounce - private labelBlocks: LabelBlockType[] = [ - { label: '考生姓名', key: 'xm' }, - { label: '身份证号', key: 'sfzmhm' }, - { label: ' 流 水 号 ', key: 'lsh' }, - { label: '考试路线', key: 'ksxl' }, - { label: '待考次数', key: 'kssycs' }, - { label: '考试员名', key: 'ksy2' }, - ] //开始考试准备 prePareExam = async () => { + dConsole.log(StartExamTag, 'prePareExam') try { // await this.checkSignal() await CheckSignal(this.systemParam, this.avPlayer) @@ -175,14 +169,20 @@ struct UserInfoPage { if (!this.currentUser.xm) { return } + // 单机 if (this.singlePlay) { this.currentUser.id = '0' - dConsole.log('开始考试3') - SqlInsertTable('USER', [this.currentUser]).catch((e: BusinessError) => { - dConsole.log("error", JSON.stringify(e)) - }) + dConsole.log(StartExamTag, '开始考试3', this.currentUser) + try { + // let data: Array = JSON.parse(JSON.stringify([this.currentUser])) + await SqlInsertTable('USER', [this.currentUser]) + } catch (e) { + dConsole.error(StartExamTag, '开始考试插入用户表失败', JSON.stringify(e)) + } // 初始化开始考试过程数据文件夹 InitializeExamProcessData(this.currentUser) + dConsole.log(StartExamTag, '开始考试4') + dConsole.log(StartEndExamTag, "-----------------------------身份证号:" + this.currentUser.sfzmhm + "考生开始考试-----------------------------") router.pushUrl({ url: this.carInfo.examSubject == '3' ? 'pages/Roads' : 'pages/Judge', params: { @@ -193,7 +193,7 @@ struct UserInfoPage { this.stopDeviceById() return } - dConsole.log('this.FaceOpenStatuethis.FaceOpenStatue', this.FaceOpenStatue) + dConsole.log(StartExamTag, 'this.FaceOpenStatuethis.FaceOpenStatue', this.FaceOpenStatue) if (this.FaceOpenStatue != '0') { // 同一学员连续第二次考试时不再验证身份 if (this.currentUser.kssycs == '1' && this.systemParam.Param830Str == '1') { @@ -205,37 +205,48 @@ struct UserInfoPage { this.sfbdinterfaceFn() } } catch (e) { - dConsole.info('Throw Error', JSON.stringify(e)) + dConsole.error(UserInfoTag, 'Throw Error', JSON.stringify(e)) } } + private labelBlocks: LabelBlockType[] = [ + { label: '考生姓名', key: 'xm' }, + { label: '身份证号', key: 'sfzmhm' }, + { label: ' 流 水 号 ', key: 'lsh' }, + { label: '考试路线', key: 'ksxl' }, + { label: '待考次数', key: 'kssycs' }, + { label: '考试员名', key: 'ksy2' }, + ] - async aboutToAppear() { + async onPageShow() { + dConsole.closeProcessData() this.avPlayer = new VoiceAnnounce(this.context); this.isExamStart = false this.startExam = false this.updateTimeLimit = false this.currentUser = EmptyCandidateObject this.singlePlay = AppStorage.get('singlePlay') || false - dConsole.log("this.singlePlay", this.singlePlay) this.examinerLoginInfo = AppStorage.get('examinerInfo')! this.carInfo = AppStorage.get('carInfo')! //语音功能on // new WebRTCVoice(this.context); //初始化数据 - this.initData() + try { + this.initData() + dConsole.log(UserInfoTag, "初始化数据完成") + } catch (e) { + dConsole.error(UserInfoTag, '初始化数据失败', JSON.stringify(e)) + } //身份证读卡器初始化 // this.openDeviceByIDCard() const routerParam: RouteParamsType = router.getParams() as RouteParamsType - dConsole.log('routerParam', JSON.stringify(routerParam)) + dConsole.log(UserInfoTag, 'routerParam', JSON.stringify(routerParam)) if (!this.singlePlay) { - if (routerParam.type != "1") { + if (!routerParam) { + dConsole.log(UserInfoTag, "评判退出") this.list = await GetSyncData("USERLIST") const data = await GetSyncData("USER") - dConsole.log('useruser,', JSON.stringify(this.list)) - dConsole.log('useruser1,', JSON.stringify(data)) - const user = data[0] if (user && Number(user.kssycs)) { let flag = false @@ -250,7 +261,6 @@ struct UserInfoPage { this.currentUser = (this.list.length ? this.list[0] : EmptyCandidateObject) } } else if (user && (user.kssycs == '0' || user.kssycs == '')) { - dConsole.log('datadatadatadata') this.list = this.list.filter(res => { return res.sfzmhm != user.sfzmhm }) @@ -261,6 +271,11 @@ struct UserInfoPage { this.currentUser = this.dataList[0] this.currentUser.ksy2 = this.examinerLoginInfo.kgxm || "" AppStorage.setOrCreate('lsh', this.currentUser.lsh) + DifferentialAndSignal.sendMsg({ + type: WorkerMessageDataType.SetExamData, + data: { lsh: this.currentUser.lsh } + }) + }, 200) } else { this.currentUser = EmptyCandidateObject @@ -269,8 +284,15 @@ struct UserInfoPage { this.list.forEach((res, index) => { res.id = index.toString() }) - await SqlInsertTable("USERLIST", this.list || []) + try { + await SqlInsertTable("USERLIST", this.list || []) + } catch (e) { + dConsole.error(UserInfoTag, '插入USERLIST表失败', JSON.stringify(e)) + } + dConsole.log(UserInfoTag, '接口读取数据', JSON.stringify(this.currentUser)) + // await this.getExaminationStudentInfoFn() } else { + // 考官登录拉取学员 await this.getExaminationStudentInfoFn() } } @@ -291,19 +313,16 @@ struct UserInfoPage { // initJudgeUdp() // TODO UDP更改 //监听远程开始考试 - JudgeEmitterInstance.onBeginExam(async () => { - dConsole.info('surenjun', 'userInfo收到UdpEvent事件') - if (this.isBoardPrePareSetPopupOpen && !this.isFirstBoardPrePareSetPopupBtnShow) { - await this.prePareSCZB() - } else { - await this.prePareExam() - } - }) } + async onPageHide(): Promise { + DifferentialAndSignal.offMsg(this.heartMsg) + } + async aboutToDisappear(): Promise { - CenterUDPBusinessInstance.offMsg(this.onCenterMsg) + // CenterUDPBusinessInstance.offMsg(this.onCenterMsg) + // DifferentialAndSignal.offMsg(this.onCenterMsg) this.outClick() } @@ -315,7 +334,7 @@ struct UserInfoPage { if (ret == 0) { testNapi.StartReadCard(this.onReadCard); } else { - dConsole.error("zzctest Failed to Open Device"); + dConsole.error(UserInfoTag, " Failed to Open Device"); } } @@ -343,6 +362,10 @@ struct UserInfoPage { this.examinerLoginInfo.ksyh = res.ksy1sfzmhm AppStorage.setOrCreate('examinerInfo', this.examinerLoginInfo) AppStorage.setOrCreate('lsh', res.lsh) + DifferentialAndSignal.sendMsg({ + type: WorkerMessageDataType.SetExamData, + data: { lsh: res.lsh } + }) // const { examSubject } = this.carInfo; dConsole.log("开始考试2") if (this.singlePlay) { @@ -370,6 +393,10 @@ struct UserInfoPage { this.currentUser = this.list[0] this.currentUser.ksy2 = this.examinerLoginInfo.kgxm || "" AppStorage.setOrCreate('lsh', this.currentUser.lsh) + DifferentialAndSignal.sendMsg({ + type: WorkerMessageDataType.SetExamData, + data: { lsh: this.currentUser.lsh } + }) }, 200) // promptAction.showToast({ @@ -380,7 +407,7 @@ struct UserInfoPage { } onReadCard(ret: IDCardSDK.IDCardInfo) { - dConsole.info(`zzctest xx Read Card ret =${ret.status}`) + dConsole.log(`zzctest xx Read Card ret =${ret.status}`) let thisVar: IdCard = AppStorage.get('indexComponent')!; if (ret.status == 0) { // status = 1 为读到身份证信息; status = 1 为身份证离开读卡器 @@ -399,10 +426,10 @@ struct UserInfoPage { if (ret.baseInfo.length > 2) { // 收到身份证信息,填充页面 - dConsole.info(`zzctest Read Card 1`); + dConsole.log(`zzctest Read Card 1`); let subIndex = ret.baseInfo.indexOf(":") let baseInfo: string = ret.baseInfo.substring(subIndex + 1, ret.baseInfo.length - 1); - dConsole.info(`zzctest Read Card 2 baseInfo=${baseInfo}`); + dConsole.log(`zzctest Read Card 2 baseInfo=${baseInfo}`); let baseInfos: string[] = baseInfo.split("|"); thisVar.name = baseInfos[0]; thisVar.sex = baseInfos[1]; @@ -418,7 +445,7 @@ struct UserInfoPage { // 身份证照片数据处理 if (ret.photo instanceof ArrayBuffer) { let dataView = new DataView(ret.photo) - dConsole.info(`Read Card ret = length = ${dataView.byteLength}`) + dConsole.log(`Read Card ret = length = ${dataView.byteLength}`) let str = "" for (let i = 0; i < dataView.byteLength; ++i) { let c = String.fromCharCode(dataView.getUint8(i)) @@ -428,7 +455,7 @@ struct UserInfoPage { } thisVar.photo += str; } - dConsole.info(`zzctest Read Card end`); + dConsole.log(`zzctest Read Card end`); return true; } @@ -445,6 +472,10 @@ struct UserInfoPage { this.callBackFlag = false AppStorage.setOrCreate('lsh', this.lsh) AppStorage.setOrCreate('statue', 2) + DifferentialAndSignal.sendMsg({ + type: WorkerMessageDataType.SetExamData, + data: { lsh: this.currentUser.lsh } + }) // this.currentUser = EmptyCandidateObject this.numCount = 0 if (this.singlePlay) { @@ -463,7 +494,10 @@ struct UserInfoPage { } async heartMsg() { - CenterUDPBusinessInstance.onMsg(this.onCenterMsg) + DifferentialAndSignal.onMsg(this.onCenterMsg) + // CenterUDPBusinessInstance.onMsg((data) => { + // this.onCenterMsg(data) + // }) } //考点端查询缺考指令内容消息请求 @@ -477,8 +511,8 @@ struct UserInfoPage { carNo: this.carInfo.carNo as string, placeId: this.carInfo.examinationRoomId as string } - // globalThis.udpClient2.sendMsgExt(param, this.context) - CenterUDPBusinessInstance.sendData(param) + // TODO + // CenterUDPBusinessInstance.sendData(param) } async initSysset() { @@ -703,7 +737,7 @@ struct UserInfoPage { this.list = JSON.parse(JSON.stringify(dataList)) - dConsole.log("temp list", JSON.stringify(this.list)) + dConsole.log(UserInfoTag, "temp list", JSON.stringify(this.list)) this.list.forEach((listData, index) => { //考过一次不允许切换学员 if (listData.kssycs == '1') { @@ -725,7 +759,7 @@ struct UserInfoPage { }) // await upDateTableByArray('USERLIST', this.list || []) - dConsole.log("temp list", JSON.stringify(this.list)) + dConsole.log(UserInfoTag, "temp list", JSON.stringify(this.list)) // await sqlInsertCommonFn("USERLIST", this.list || []) await SqlInsertTable('USERLIST', this.list || []) @@ -742,6 +776,10 @@ struct UserInfoPage { this.currentUser = user.length ? user[0] : this.dataList[0] this.currentUser.ksy2 = this.examinerLoginInfo.kgxm || "" AppStorage.setOrCreate('lsh', this.currentUser.lsh) + DifferentialAndSignal.sendMsg({ + type: WorkerMessageDataType.SetExamData, + data: { lsh: this.currentUser.lsh } + }) this.examinerLoginInfo.ksyh = this.currentUser.ksy1sfzmhm AppStorage.setOrCreate('examinerInfo', this.examinerLoginInfo) }, 200) @@ -806,7 +844,8 @@ struct UserInfoPage { carNo: this.carInfo.carNo || "", placeId: this.carInfo.examinationRoomId || "" } - CenterUDPBusinessInstance.sendData(param) + // TODO + // CenterUDPBusinessInstance.sendData(param) // globalThis.udpClient2.sendMsgExt(param, this.context) if (res.examinationStuAbsentRsp && res.examinationStuAbsentRsp.head && res.examinationStuAbsentRsp.head.resultCode == '0') { @@ -823,18 +862,31 @@ struct UserInfoPage { } - onCenterMsg = (val: CenterCallBackMsgType) => { - if (val.id == 32) { - AppStorage.setOrCreate('signNum', val.body[1]) - if (val.body[0] == 7) { - //缺考处理 - this.getqkFn() - this.signNum = val.body[1] + onCenterMsg = (msg: string) => { + let result = JSON.parse(msg) as WorkerBackMessage + + if (result.type === WorkerBackMessageType.RemoteStartExam) { + dConsole.log('userInfo收到开始考试事件') + if (this.isBoardPrePareSetPopupOpen && !this.isFirstBoardPrePareSetPopupBtnShow) { + this.prePareSCZB() + } else { + this.prePareExam() + } + } else if (result.type === WorkerBackMessageType.CenterUdpData) { + let val = result.data as CenterCallBackMsgType + if (val.id == 32) { + AppStorage.setOrCreate('signNum', val.body[1]) + if (val.body[0] == 7) { + //缺考处理 + this.getqkFn() + this.signNum = val.body[1] + } + } else if (val.id == 42) { + //收到中心缺考确认消息 + this.qkFn() } - } else if (val.id == 42) { - //收到中心缺考确认消息 - this.qkFn() } + } async getExaminationItemFn() { @@ -880,9 +932,9 @@ struct UserInfoPage { this.startExamDialogController.open() avPlayer.playAudio([`voice/监管通信中.mp3`], false, async () => { - dConsole.info('surenjun', '播放结束开始考试接口调用') + dConsole.log(StartExamTag, '播放结束开始考试接口调用') const res = await this.beginExam() - dConsole.info('surenjun', '开始考试接口调用结束', JSON.stringify(res)) + dConsole.log(StartExamTag, '开始考试接口调用结束', res) //TODO code转换 if (res.code != 1) { avPlayer.playAudio([res.code == -200 ? 'voice/photo_error.mp3' : 'voice/监管审核未通过.mp3']); @@ -895,12 +947,18 @@ struct UserInfoPage { return } this.currentUser.id = '0' - // await upDateTableByArray('USER', [this.currentUser]) - await SqlInsertTable('USER', [this.currentUser]) + dConsole.log(StartExamTag, '插入用户表1') + try { + await SqlInsertTable('USER', [this.currentUser]) + } catch (e) { + dConsole.error(StartExamTag, '插入用户表失败', e) + } + dConsole.log(StartExamTag, '插入用户表结束', res) this.stepFlag = false this.startExamDialogController.close() // 初始化开始考试过程数据文件夹 InitializeExamProcessData(this.currentUser) + router.pushUrl({ url: 'pages/Judge', params: { @@ -923,11 +981,14 @@ struct UserInfoPage { const startHourTime = dayTs().format("HHmmssSSS") AppStorage.setOrCreate('startHourTime', startHourTime) const photoBase64 = await GetPhotoBase64(this.context); + dConsole.log(StartExamTag, "开始考试拍照完成") if (photoBase64 == '') { dConsole.log(StartExamTag, "拍照失败") this.startExamDialogController.close() return { code: -200 } } + let startTime = new Date() + AppStorage.setOrCreate("startTime", startTime) const drvexam: DrvexamType = { lsh: this.currentUser.lsh, kskm: this.carInfo.examSubject, @@ -936,7 +997,7 @@ struct UserInfoPage { ksysfzmhm: this.currentUser.ksy1sfzmhm || '', ksxl: this.currentUser.xldm, zp: photoBase64, - kssj: dayTs().format("YYYY-MM-DD HH:mm:ss") || '', + kssj: dayTs(startTime).format("YYYY-MM-DD HH:mm:ss") || '', kchp: decodeURI(this.carInfo.plateNo || ""), Ksy2sfzmhm: this.currentUser.ksy2sfzmhm || '' } @@ -949,12 +1010,23 @@ struct UserInfoPage { //接口标识 jkid: '17C51', } - dConsole.info('surenjunjianguan', JSON.stringify(param)) - const temp = await writeObjectOut(param, "", this.context); - AppStorage.setOrCreate('lsh', this.currentUser.lsh) - this.examinerLoginInfo.ksyh = this.currentUser.ksy1sfzmhm - AppStorage.setOrCreate('examinerInfo', this.examinerLoginInfo) - return temp + dConsole.log(StartExamTag, "开始考试上传中心参数", param) + try { + const temp = await writeObjectOut(param, "", this.context); + AppStorage.setOrCreate('lsh', this.currentUser.lsh) + dConsole.info(UserInfoTag, this.currentUser.lsh, this.currentUser) + this.examinerLoginInfo.ksyh = this.currentUser.ksy1sfzmhm + AppStorage.setOrCreate('examinerInfo', this.examinerLoginInfo) + DifferentialAndSignal.sendMsg({ + type: WorkerMessageDataType.SetExamData, + data: { + lsh: this.currentUser.lsh + } + }) + return temp + } catch (e) { + return e + } } //开始上车准备 @@ -1030,6 +1102,10 @@ struct UserInfoPage { } this.currentUser = EmptyCandidateObject AppStorage.setOrCreate('lsh', item.lsh) + DifferentialAndSignal.sendMsg({ + type: WorkerMessageDataType.SetExamData, + data: { lsh: item.lsh } + }) setTimeout(() => { this.currentUser = item this.currentUser.ksy2 = this.examinerLoginInfo.kgxm || "" @@ -1110,6 +1186,7 @@ struct UserInfoPage { .onClick(() => { if ((this.systemParam.Param352Str == '1' && this.currentUser.kssycs == '1') || this.systemParam.Param770Str == '1') { + dConsole.log(UserInfoTag, '不允许缺考') return } // this.qkFlag = true @@ -1136,6 +1213,7 @@ struct UserInfoPage { dConsole.log(UserInfoTag, "不给开始考试") return } + dConsole.log(StartExamTag, "开始考试按钮点击") await this.prePareExam() }) } diff --git a/entry/src/main/ets/pages/UserInfo/FaceRecognition.ets b/entry/src/main/ets/pages/UserInfo/FaceRecognition.ets index 69f991d..ef13ff9 100644 --- a/entry/src/main/ets/pages/UserInfo/FaceRecognition.ets +++ b/entry/src/main/ets/pages/UserInfo/FaceRecognition.ets @@ -142,7 +142,8 @@ export default struct FaceRecognitionDialog { this.callBackFlag = true } } - CenterUDPBusinessInstance.sendData(param) + // TODO + // CenterUDPBusinessInstance.sendData(param) clearInterval(this.interval) this.interval = setInterval(() => { if (this.callBackFlag) { @@ -152,7 +153,8 @@ export default struct FaceRecognitionDialog { carNo: this.carInfo.carNo || "", placeId: this.carInfo.examinationRoomId || "", } - CenterUDPBusinessInstance.sendData(param2) + // TODO + // CenterUDPBusinessInstance.sendData(param2) } }, 1000) CenterUDPBusinessInstance.onMsg(this.getUdpMsg) @@ -212,7 +214,7 @@ export default struct FaceRecognitionDialog { .width(600) // 图片 Row() { - Image(this.base64).height("100%").width("100%") + Image(this.base64).height("100%").width("100%").objectFit(ImageFit.Contain) } .height("100%") .width(600) diff --git a/entry/src/main/ets/pages/compontents/Block.ets b/entry/src/main/ets/pages/compontents/Block.ets index daa4044..6a76a23 100644 --- a/entry/src/main/ets/pages/compontents/Block.ets +++ b/entry/src/main/ets/pages/compontents/Block.ets @@ -2,19 +2,19 @@ export default struct BlockComponent { @State label: string = "发送次数" @Prop value: string = "1" - @State widthNum: number = 130 + @State widthNum: number = 150 @State heightNum: number = 70 @State color: string = "#FDF5E7" build() { Row() { Row() { - Text(this.label + ":").fontColor(this.color).fontSize(14) + Text(this.label + ":").fontColor(this.color).fontSize(20) }.width(this.widthNum).justifyContent(FlexAlign.End) Row() { - Text(this.value).fontColor(this.color) - }.width(80).justifyContent(FlexAlign.Start).margin({ + Text(this.value).fontColor(this.color).fontSize(24) + }.width(150).justifyContent(FlexAlign.Start).margin({ left: 20 }) } diff --git a/entry/src/main/ets/pages/compontents/Coordinate.ets b/entry/src/main/ets/pages/compontents/Coordinate.ets index 4c0bd4e..35d26c9 100644 --- a/entry/src/main/ets/pages/compontents/Coordinate.ets +++ b/entry/src/main/ets/pages/compontents/Coordinate.ets @@ -10,11 +10,13 @@ export default struct CoordinateComponent { build() { Flex({ direction: FlexDirection.Column, - alignItems: ItemAlign.Center + alignItems: ItemAlign.Center, + justifyContent: FlexAlign.Center }) { - Text("GPS坐标").fontColor("#FFB433").fontSize(20).margin({ - top: 10 - }) + Row() { + Text("GPS坐标").fontColor("#FFB433").fontSize(20) + }.height(70) + Flex({ wrap: FlexWrap.Wrap, direction: this.isItHorizontal ? FlexDirection.Row : FlexDirection.Column @@ -30,7 +32,10 @@ export default struct CoordinateComponent { }.width("100%") } .width("100%") - .height(this.isItHorizontal ? 210 : "100%") + .height(this.isItHorizontal ? 280 : "100%") .backgroundColor("#1A1A1A") + .margin({ + bottom: 20 + }) } } \ No newline at end of file diff --git a/entry/src/main/ets/pages/compontents/FaceCompare.ets b/entry/src/main/ets/pages/compontents/FaceCompare.ets index 834f1b8..aee17a1 100644 --- a/entry/src/main/ets/pages/compontents/FaceCompare.ets +++ b/entry/src/main/ets/pages/compontents/FaceCompare.ets @@ -2,7 +2,7 @@ import { faceCompare } from '../../api/userInfo'; import common from '@ohos.app.ability.common'; -import { GlobalConfig } from '../../config/index'; +import { FaceCompareTag, GlobalConfig } from '../../config/index'; import { VideoConfigData } from '../../mock'; import { CarInfoType, UDPParamType, VideoConfig } from '../../model'; import { NumberToByteArray } from '../../utils/Common'; @@ -11,6 +11,7 @@ import { CenterUDPBusinessInstance } from '../../utils/business/CenterUdpBusines import { takePhoto, takePhotoParam } from '../../utils/Video'; import { voiceService } from '../../utils/Voice'; import { dConsole } from '../../utils/LogWorker'; +import { BusinessError } from '@ohos.base'; @Component @@ -56,41 +57,50 @@ export default struct FaceCompare { } async faceCompareFn() { - dConsole.log('mmmmm0', 2) + dConsole.log(FaceCompareTag, '人脸对比开始', 2) this.param.pztd = this.param.rlls const data: takePhotoParam = await takePhoto(this.param, this.context, 'jt/', 1,) this.base64 = this.imageBase64 + (data?.base64 || "") - dConsole.log('mmmmt', this.base64) + + faceCompare({ sfzh: this.sfzh.toString(), firstImage: this.firstImage.substr(22), secondImage: data?.base64 || "", type: "2", verifyType: "1" - }) - .then(res => { - dConsole.log('mmmmm8', JSON.stringify(res)) - if (res.imageCompareRsp?.head?.resultCode == '0') { - this.controller.stop() - this.showFaceCompare = !this.showFaceCompare - this.showFaceCompareFlag = !this.showFaceCompareFlag - this.faceCompareSuccess = 1; - // this.faceCatchImg = result - this.vocObj.playAudio({ - type: 1, - name: 'yzcg.wav' - }) - } else { - this.times++; - //3s后开始语音提示 - this.vocObj.playAudio({ - type: 1, - name: 'face_fail.mp3' - }) + }).then(res => { + dConsole.log(FaceCompareTag, '人脸比对结果', JSON.stringify(res)) + if (res.imageCompareRsp?.head?.resultCode == '0') { + this.controller.stop() + this.showFaceCompare = !this.showFaceCompare + this.showFaceCompareFlag = !this.showFaceCompareFlag + this.faceCompareSuccess = 1; + dConsole.log(FaceCompareTag, "人脸对比成功") + // this.faceCatchImg = result + this.vocObj.playAudio({ + type: 1, + name: 'yzcg.wav' + }) + } else { + dConsole.log(FaceCompareTag, "人脸对比失败") + this.times++; + //3s后开始语音提示 + this.vocObj.playAudio({ + type: 1, + name: 'face_fail.mp3' + }) - } + } + }).catch((err: BusinessError) => { + console.log(FaceCompareTag, "人脸对比失败", JSON.stringify(err)) + this.times++; + //3s后开始语音提示 + this.vocObj.playAudio({ + type: 1, + name: 'face_fail.mp3' }) - dConsole.log('mmmmm8', 9) + }) } async heartMsg() { @@ -111,7 +121,8 @@ export default struct FaceCompare { this.callBackFlag = true } } - CenterUDPBusinessInstance.sendData(param) + // TODO + // CenterUDPBusinessInstance.sendData(param) // UDP缺失 // globalThis.udpClient2 && globalThis.udpClient2.sendMsgExt(param, this.context) clearInterval(this.interval) @@ -123,7 +134,8 @@ export default struct FaceCompare { carNo: this.carInfo.carNo || "", placeId: this.carInfo.examinationRoomId || "", } - CenterUDPBusinessInstance.sendData(param2) + // TODO + // CenterUDPBusinessInstance.sendData(param2) } }, 1000) CenterUDPBusinessInstance.onMsg((val) => { diff --git a/entry/src/main/ets/pages/compontents/SignalDisplay.ets b/entry/src/main/ets/pages/compontents/SignalDisplay.ets index 787d19b..81b7d6c 100644 --- a/entry/src/main/ets/pages/compontents/SignalDisplay.ets +++ b/entry/src/main/ets/pages/compontents/SignalDisplay.ets @@ -20,6 +20,7 @@ export default struct SignalDisplayComponent { @Prop active: number = 0 // 原始数据 @State rawData: string = "$GPS,,,,,,,,,,,,,,,,,,,,,,,,,,,,," + @State heightNum: number = 1200 aboutToAppear(): void { DifferentialAndSignal.onMsg(this.getMsg) @@ -47,7 +48,6 @@ export default struct SignalDisplayComponent { for (let i = 0; i <= 12; i++) { this.vehicleSignal[i].value = this.signArr[i+2] } - this.vehicleSignal[13].value = this.signArr[17] this.vehicleSignal[14].value = this.signArr[18] this.vehicleSignal[15].value = this.signArr[19] @@ -85,11 +85,12 @@ export default struct SignalDisplayComponent { this.signArr[93] = str2 + str1 + str0 } this.GPSColum[10].value = this.signArr[93] - - // this.signArr[53]=192.168.7.170' this.vehicleSignal = JSON.parse(JSON.stringify((this.vehicleSignal))) this.signArr = JSON.parse(JSON.stringify((this.signArr))) this.GPSColum = JSON.parse(JSON.stringify((this.GPSColum))) + // this.vehicleSignal = this.vehicleSignal.slice() + // this.signArr = this.signArr.slice() + // this.GPSColum = this.GPSColum.slice() } build() { @@ -97,26 +98,28 @@ export default struct SignalDisplayComponent { Flex({ direction: FlexDirection.Column, }) { - // 信号查看 - if (this.active === 0) { - // GPS信号展示 - GPSComponent({ - data: this.signArr - }) - // 车载信号以及车载坐标 - CarComponent({ - data: this.vehicleSignal - }) - CoordinateComponent({ - data: this.GPSColum - }) - - } else if (this.active === 1) { - // 原始数据 - Column() { - Text(this.rawData).fontSize(20).fontColor("#fff") - }.backgroundColor("#282828").width("100%").height("100%") - } + Scroll() { + // 信号查看 + if (this.active === 0) { + Column() { + // 车载信号以及车载坐标 + CarComponent({ + data: this.vehicleSignal, + GPSData: this.signArr + }) + CoordinateComponent({ + data: this.GPSColum + }) + }.height(this.heightNum).padding({ + bottom: 20 + }) + } else if (this.active === 1) { + // 原始数据 + Column() { + Text(this.rawData).fontSize(20).fontColor("#fff") + }.backgroundColor("#282828").width("100%").height("100%") + } + }.height("100%").backgroundColor("#1A1A1A") } .width("100%") .height("100%") @@ -129,8 +132,9 @@ export default struct SignalDisplayComponent { @Component -struct GPSComponent { - @Prop data: Array +struct CarComponent { + @Prop data: Array + @Prop GPSData: Array @State ip: string = "" aboutToAppear(): void { @@ -147,35 +151,36 @@ struct GPSComponent { build() { Flex({ - wrap: FlexWrap.Wrap + wrap: FlexWrap.Wrap, + justifyContent: FlexAlign.Center }) { BlockComponent({ label: "发送次数", - value: this.data[49] || "-" + value: this.GPSData[49] || "-" }) BlockComponent({ label: "固件版本", - value: this.data[54] || "-" + value: this.GPSData[54] || "-" }) BlockComponent({ label: "方向盘类型", - value: this.data[50] || "-" + value: this.GPSData[50] || "-" }) BlockComponent({ label: "按键数值", - value: this.data[55] || "-" + value: this.GPSData[55] || "-" }) BlockComponent({ label: "GPS错误次数", - value: this.data[60] || "-" + value: this.GPSData[60] || "-" }) BlockComponent({ label: "汽车类型", - value: this.data[51] || "-" + value: this.GPSData[51] || "-" }) BlockComponent({ label: "GPS板卡类型", - value: this.data[56] || "-" + value: this.GPSData[56] || "-" }) BlockComponent({ label: "本机IP", @@ -183,47 +188,35 @@ struct GPSComponent { }) BlockComponent({ label: "接口心跳", - value: this.data[52] || "-" + value: this.GPSData[52] || "-" }) BlockComponent({ label: "GPS板卡软件版本", - value: this.data[57] || "-" + value: this.GPSData[57] || "-" }) BlockComponent({ label: "改正数次数/改正数大小", - value: this.data[58] || "-" + value: this.GPSData[58] || "-" }) BlockComponent({ label: "已工作时长/设定工作时长", - value: this.data[61] || "-" + value: this.GPSData[61] || "-" }) BlockComponent({ label: "GPS数据次数/数据长度", - value: this.data[59] || "-" + value: this.GPSData[59] || "-" }) BlockComponent({ label: "改正数据长度*数据长度-基准站RTCM改正数类型", - value: this.data[62] || "-" + value: this.GPSData[62] || "-" }) - }.backgroundColor("#282828").width("100%").height(140) - } -} - -@Component -struct CarComponent { - @Prop data: Array - - build() { - Flex({ - wrap: FlexWrap.Wrap - }) { ForEach(this.data, (item: SignalDataType) => { BlockComponent({ label: item.key, value: item.value }) }) - }.width("100%").backgroundColor("#282828").height(490) + }.width("100%").backgroundColor("#282828") } } diff --git a/entry/src/main/ets/pages/compontents/judge/BoardPrePareSetPopup.ets b/entry/src/main/ets/pages/compontents/judge/BoardPrePareSetPopup.ets index 9a3f08f..a2f49fd 100644 --- a/entry/src/main/ets/pages/compontents/judge/BoardPrePareSetPopup.ets +++ b/entry/src/main/ets/pages/compontents/judge/BoardPrePareSetPopup.ets @@ -190,7 +190,7 @@ export default struct DeductedPopup { // const carInfo = this.carInfo; // const { examSubject, plateNo, carNo } = carInfo; const time = GetCurrentTime(); - dConsole.info('surenjun uploadProgressPhoto',) + dConsole.info('uploadProgressPhoto',) const photoBase64 = await GetPhotoBase64(this.context) const photoData: RegulatoryInterfaceParams = { xtlb: '17', @@ -210,7 +210,7 @@ export default struct DeductedPopup { } }; const code = await writeObjectOut(photoData, "", this.context); - dConsole.info('surenjun uploadProgressPhoto end',) + dConsole.info('uploadProgressPhoto end',) } // 扣分 @@ -289,7 +289,7 @@ export default struct DeductedPopup { //获取sysset表数据 async initSysset(sysset?: MASYSSETTableType[]) { const syssetParams = sysset || await GetSyncData('MA_SYSSET'); - dConsole.info('surenjun syssetParams', JSON.stringify(syssetParams)); + // dConsole.info('surenjun syssetParams', JSON.stringify(syssetParams)); syssetParams.forEach(sys => { //监管序列号 if (sys.v_no == '901') { diff --git a/entry/src/main/ets/pages/judgeSDK/judge.ets b/entry/src/main/ets/pages/judgeSDK/judge.ets deleted file mode 100644 index 352de01..0000000 --- a/entry/src/main/ets/pages/judgeSDK/judge.ets +++ /dev/null @@ -1,1824 +0,0 @@ -import systemTime from '@ohos.systemDateTime'; -import router from '@ohos.router'; -import util from '@ohos.util'; -import buffer from '@ohos.buffer'; - -import VoiceAnnounce from './utils/voiceAnnouncements'; -import FileModel from './utils/fileModel'; -import JudgeTask from './utils/judgeTask'; -import { JudgeConfig, JudgeTag } from '../../config'; -import { GetSyncData, SqlInsertTable } from '../../utils/table/Operation'; - -import { uploadExamProgressData, writeObjectOut } from '../../api/judge'; -import { endRecordVideo, saveStartRecordVideo } from '../../utils/Video'; -import common from '@ohos.app.ability.common'; - -import { ConvertDdmmToDecimalDegrees, DeepClone, GetCurrentTime, GetPhotoBase64 } from '../../utils/Common'; -import UsbService from '../../utils/USB'; -import FileUtils from '../../utils/FileUtils'; -import { - BaseInfoType, - CarInfoType, - CDSBInfo, - CDSBInfos, - DrvexamType, - ExaminerInfoType, - ItemInfo, - JudgeBeginObj, - JudgeCallBackData, - JudgeConfigObj, - JudgeConfigObjKmItems, - JudgeInitObj, - JudgeKFXM, - JudgeKSJS, - JudgeKSXM, - JudgePerformInfo, - JudgeSound, - JudgeUI, - JudgeXMJS, - Km3JudgeInitConfig, - KmItem, - LANE, - MarkRule, - PLCType, - ProcessDataEnumType, - ProjectInfo, - RecordHandleType, - RegulatoryInterfaceParams, - RouteParamsType, - TKmItem, - User, - WorkerBackMessage, - WorkerBackMessageType, - WR -} from '../../model'; -import { - examJudgeArtificialItem, - examJudgeArtificialMark, - examJudgeBeginExam, - examJudgeEndExam, - examJudgeInit, - examJudgeRealExam, - examJudgeSetLogCallback, - examJudgeSetPerformCallback, - examJudgeSetRealExamCallback, - examJudgeSoundEnd, - examJudgeVersion -} from '../Judge/JudgeSDKUtils'; -import { - GetCarStatus, - GetCenterProjectStatus, - PlcStrToJson, - PlcStrToWXJson, - UploadRegulatoryCodeConversion -} from '../Judge/utils'; -import { DifferentialAndSignal } from '../../utils/business/DifferentialAndSignalWorker'; -import { dConsole } from '../../utils/LogWorker'; -import { testKm2Items, testKm3Items } from '../../mock'; - - -type GetKm3JudgeInitConfig = () => Promise -type GetgSbbm = (ksxm: number, xmxh: string) => string -type SendWriteObjectOut = (data: RegulatoryInterfaceParams, filePath: string) => Promise -type GetKfStr = (code: string) => MarkRule -type GetDqxmStr = (xmdm: number) => string - -export default class Judge { - public plcStr: string = "" - public judgeUI: JudgeUI - //获取科目三的评判初始化配置 - getKm3JudgeInitConfig: GetKm3JudgeInitConfig = async () => { - return { - map_point: this.judgeUI.mapPointArr, - map_point_item: this.judgeUI.mapPointItemArr, - //科目三暂时为空 - iteminfo: [], - roads: this.getModelData('km3/Roads.txt') || "", - sharps: this.getModelData('km3/Sharps.txt') || "" - } - } - //人工扣分 - public setJudgeMark = async (itemno: string, serial: string, type = 1) => { - await examJudgeArtificialMark(Number(itemno), serial, type); - dConsole.info(JudgeTag, `进入人工扣分-${itemno}-${serial}`) - const str = JSON.stringify({ - method: 'examJudgeArtificialMark', - itemno: Number(itemno), - serial, - type - }) - // await this.fileLog?.setExamJudgeData(str) - dConsole.writeProcessData(ProcessDataEnumType.JudgeExamData, str) - dConsole.info(JudgeTag, `人工扣分-${itemno}-${serial}`) - } - //人工操作项目 - public setJudgeItem = async (itemno: string, type: 1 | 2) => { - // const { fileLog } = this; - await examJudgeArtificialItem(Number(itemno), type); - const str = JSON.stringify({ - method: 'examJudgeArtificialItem', - itemno: Number(itemno), - type - }) - // await this.fileLog?.setExamJudgeData(str) - dConsole.writeProcessData(ProcessDataEnumType.JudgeExamData, str) - dConsole.info(JudgeTag, `人工评判${type == 1 ? '进入' : '取消'}项目-${itemno}`) - } - private context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext; - private filePath: string = "" - private totalScore: number = -1 - private prevJd: number = 0 - private prevWd: number = 0 - private dwztNum: number = 0 - private folderPath: string = "" - private modelPath: string = "" - private avPlayer?: VoiceAnnounce - // 处理特殊参数配置 - handleSEP = async (code: number) => { - const judgeConfigObj = this.judgeUI.judgeConfigObj - const avPlayer = this.avPlayer - switch (code) { - //结束考试方式 - case 306: - if (Reflect.get(judgeConfigObj, code) == 5) { - //靠边停车 - avPlayer?.playAudio(['voice/406001.mp3']) - } - break; - } - } - private carztStr: string - private rmndg: 0 | 1 = 0 - private mndgStr: string | undefined - // 模拟灯光 - setMndg = async (mndgStr: string) => { - this.mndgStr = mndgStr - } - private xmmcStr: string = "" - private xmmcCode: string = "" - private xmmcSingleCode: string = "" - private xmmcEndCode?: string - private xmdm: string | number = "" - private xmxh: string = "" - private fileModel?: FileModel - private usbService: UsbService - //是否是考试模式 - private isExam: boolean - //考试是否结束了 - private isExamEnd: boolean - // 是否发送udp - private isUdpEnd: boolean = false - // 处理udp plc信号 - handleUdp = async (msg: string) => { - const stachArr = msg.split(',') - if (stachArr[0] != '#DN_GD' || this.isUdpEnd) { - return - } - const gpsPart = msg.split("#END$GPS,")[1]; - const gpsStatus = gpsPart.split(",")[0]; - if (gpsStatus === "4") { - dConsole.log(JudgeTag, "差分状态正常", gpsStatus) - this.judgeUI.isDwztRight = true - } else { - dConsole.log(JudgeTag, "差分状态异常", gpsStatus) - this.judgeUI.isDwztRight = false - } - this.judgeUI.isDwztRight - const plcData = await this.getPlcData(msg); - // 4.过程数据 - // await this.fileLog?.setExamJudgeData(JSON.stringify(plcData)) - dConsole.writeProcessData(ProcessDataEnumType.JudgeExamData, JSON.stringify(plcData)) - //检测到有无锡所设备接入,需要发送特定的数据,供检测 - // if (this.usbService.isWXUSBDevice) { - // const str = await senorToWXDataStr(msg); - // this.usbService.sendUSB(str) - // } - const param350: number = Reflect.get(this.judgeUI.judgeConfigObj, '350') - 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 (!this.isExamEnd) { - await examJudgeRealExam(plcData) - } - // let udpIndex = AppStorage.get('udpIndex') || 0; - // if (udpIndex % 5 === 0 && !this.isUdpEnd) { - // TODO UPD缺失 - // const judgeUdp = globalThis.judgeUdp - // const bytes = await this.getMessageHeartbeat(this.isExamEnd); - // judgeUdp.send(bytes) - // } - // AppStorage.setOrCreate('udpIndex', udpIndex++) - } - //是否手动结束考试 - private isManual: boolean = false - //UDP服务序列号 - private serialIndex: number - private fileUtil: FileUtils - //上传无锡所过程数据 - uploadProgressData = async () => { - const carInfo = AppStorage.get('carInfo') - const judgeUI = this.judgeUI - const fileUtil = this.fileUtil - const carId = carInfo?.carId || "" - const examinationRoomId = carInfo?.examinationRoomId || "" - - const base64 = new util.Base64(); - const time = GetCurrentTime(); - const endTime = GetCurrentTime(1) - let examDataBase64: string = '' - const examDataStr: string = await this.fileUtil.readFile(`${dConsole.currentExamCatalog}/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) { - dConsole.info(JudgeTag, JSON.stringify(e)) - } - dConsole.info(JudgeTag, '过程数据文件上传 start') - - try { - await uploadExamProgressData({ - carId, - examinationRoomId, - type: 1, - time, - cardNo: judgeUI.idCard, - examData: examDataBase64, - examStartTime: judgeUI.startFullTime, - examEndTime: endTime, - }) - } catch (e) { - dConsole.info(JudgeTag, '过程数据文件上传失败:' + JSON.stringify(e)) - } - dConsole.info(JudgeTag, '过程数据文件上传 end') - } - private judgeTask: JudgeTask - // 检测扣分、结束项目时该项目是否开始 - checkProjectIsStart = async (xmdm: number, currentType: 1 | 2, kf?: MarkRule) => { - if (xmdm == 20) { - return true - } - const judgeUI = this.judgeUI; - const judgeTask = this.judgeTask; - const projectsObj: object = this.judgeUI.projectsObj - const currentProject: ProjectInfo = Reflect.get(projectsObj, xmdm) - const isUpload = currentProject.isUpload - - //如果项目没有开始 - dConsole.info(JudgeTag, 'surenjun isUpload=>', isUpload) - if (!isUpload) { - dConsole.info(JudgeTag, '项目补传开始') - //项目开始补传 - judgeTask.addTask(async () => { - await this.beginProject(xmdm) - }, { - isDelay: true - }) - judgeTask.addTask(async () => { - await this.uploadProgressPhoto(xmdm) - }, { - isDelay: true - }) - currentProject.isUpload = true; - Reflect.set(this.judgeUI.projectsObj, xmdm, currentProject) - //扣分补传 - if (currentType == 2) { - judgeTask.addTask(async () => { - await this.pointsDedute(xmdm, kf!) - }, { - isDelay: true - }) - } - //扣分补传判断是否合格 不合格补传项目结束 - if (currentType == 1 || (currentType == 2 && this.totalScore < judgeUI.passingScore)) { - judgeTask.addTask(async () => { - await this.endProject(xmdm) - }, { - isDelay: true - }) - currentProject.isEnd = true; - Reflect.set(this.judgeUI.projectsObj, xmdm, currentProject) - } - judgeTask.addTask(async () => { - this.checkExamIsEnd() - }) - return false; - } else { - return true - } - } - private tempData?: PLCType - //实时计算gps经纬度距离 - handDistance = async () => { - const dwzt = this.tempData?.gps?.dwzt || ""; - const jdzt = this.tempData?.gps?.jdzt || ""; - const tJD = ConvertDdmmToDecimalDegrees(this.tempData?.gps?.jd || 0) - const tWD = ConvertDdmmToDecimalDegrees(this.tempData?.gps?.wd || 0) - if (this.prevJd && dwzt == 4 && jdzt == 3) { - // const distance = await examCalcGpsDistance({ - // jd1: this.prevJd, - // wd1: this.prevWd, - // jd2: tJD, - // wd2: tWD, - // h: this.tempData?.gps?.hxj || 1, - // }) - // const distanceClass = AppStorage.get('distanceClass') - // distanceClass?.setTimeData(Number(((distance / 100).toFixed(2)))) - // DrivingDataStorage.setDrivingProcessData(Number(((distance / 100).toFixed(2)))) - } - this.prevJd = tJD; - this.prevWd = tWD; - } - private performInfo?: JudgePerformInfo - private ksjs?: JudgeKSJS - private kfArr?: MarkRule[] - //所有的科目考试项目(大车&小车) - private kmItems: JudgeConfigObjKmItems - private plcData?: PLCType - // 获取plc数据 - getPlcData = async (plc: string) => { - // await this.fileLog?.setPlcProgressData(plc) - dConsole.writeProcessData(ProcessDataEnumType.PlcData, plc) - //plc字符串转化成评判初始化数据 - const tempData = await PlcStrToJson(plc); - //模拟灯光回放时刻 - tempData.sensor.rmndg = this.rmndg; - //模拟灯灯光灯光项目 - tempData.sensor.mndg = this.mndgStr || ""; - //plc字符串转化成无锡所过程数据 - const wuXiDataStr = await PlcStrToWXJson(plc) - this.plcData = tempData - // await this.fileLog?.setExamJudgeWuxiProgressData(wuXiDataStr) - dConsole.writeProcessData(ProcessDataEnumType.WuxiProgressData, wuXiDataStr) - this.tempData = tempData - this.plcStr = plc; - this.mndgStr = ''; - this.rmndg = 0; - AppStorage.setOrCreate('msgStr', plc) - return tempData - } - // 处理轨迹plc信号 - handleTrajectoryUdp = async (strArr: string[]) => { - let num = 2; - const judgeTimer = setInterval(async () => { - const msgStr = strArr[num]; - if (msgStr == '') { - dConsole.info(JudgeTag, '模拟数据考试结束') - clearInterval(judgeTimer) - this.checkExamIsEnd(true) - return - } - const msg: PLCType = 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; - AppStorage.setOrCreate('msgStr', '') - if (msg.method === 'examJudgeArtificialItem') { - this.setJudgeItem(msg.itemno, msg.type) - } - if (msg.method === 'examJudgeArtificialMark') { - this.setJudgeItem(msg.itemno, msg.serial) - } - await examJudgeRealExam(msg) - // const bytes = await this.getMessageHeartbeat(); - // bytes && globalThis.judgeUdp.send(bytes) - - }, 200) - // TODO 定时器缺失 - // globalThis.judgeTimer = judgeTimer; - } - private isEndTip: boolean = false; - //本地轨迹回放地址 - private trajectoryPath: string - // private currentKm2ItemsObj: any - private isTrajectoryOpen: boolean; - // 调代理接口是否断网了 - private isJudgeDisConnect: boolean = false; - // 断网数据补传 - uploadDisConnectData = async () => { - if (!this.isJudgeDisConnect) { - return - } - const examDataStr = await this.fileUtil.readFile(`${dConsole.currentExamCatalog}/wuxi_dis_progress_data.txt`); - const examDataArr = examDataStr.split('\n'); - for (let examDataStr of examDataArr) { - const code = await writeObjectOut(JSON.parse(examDataStr), "", this.context); - } - } - // 项目开始接口同步 - beginProject = async (ksxm: number) => { - const carInfo = AppStorage.get('carInfo'); - const judgeUI = this.judgeUI - const time = GetCurrentTime(); - const project: ProjectInfo = Reflect.get(judgeUI.projectsObj, ksxm) - const sbxh = this.getSbbm(ksxm, this.xmxh) - - 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: time - } - const data: RegulatoryInterfaceParams = { - //系统类别 接口序列号 接口标识 - xtlb: '17', - jkxlh: judgeUI.serialNumber, - jkid: '17C52', - drvexam - } - const temp: WR = await this.sendWriteObjectOut(data, this.filePath) - dConsole.info(JudgeTag, '项目开始 end') - if (temp.code === 2300007) { - this.isJudgeDisConnect = true; - } - UploadRegulatoryCodeConversion('17C52', temp.code || 0) - } - // 项目结束接口同步 - endProject = async (ksxm: number) => { - const carInfo = AppStorage.get('carInfo'); - const judgeUI = this.judgeUI; - const time = GetCurrentTime(); - const project: ProjectInfo = Reflect.get(judgeUI.projectsObj, ksxm) - const sbxh = judgeUI.examSubject == '3' ? undefined : this.getSbbm(ksxm, this.xmxh) - - 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: time - } - const data: RegulatoryInterfaceParams = { - xtlb: '17', - jkxlh: judgeUI.serialNumber, - jkid: '17C55', - drvexam - } - const temp: WR = await this.sendWriteObjectOut(data, this.filePath) - if (temp.code === 2300007) { - this.isJudgeDisConnect = true; - } - dConsole.info(JudgeTag, '项目结束 end') - UploadRegulatoryCodeConversion('17C55', temp.code || 0) - } - // 考试过程照片 - uploadProgressPhoto = async (ksxm: number) => { - const time = GetCurrentTime(); - const judgeUI = this.judgeUI - const plcData = this.plcData - const photoBase64 = await GetPhotoBase64(this.context); - const carInfo = AppStorage.get('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: time, - 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 - }; - const temp: WR = await this.sendWriteObjectOut(data, this.filePath); - if (temp.code === 2300007) { - this.isJudgeDisConnect = true - } - UploadRegulatoryCodeConversion('17C54', temp.code || 0) - dConsole.info(JudgeTag, '上传照片 end') - } - private artSubject3ProjectsCodesArr: number[] = [3, 9, 4, 10, 12, 11] - private lane: LANE = { - road: '', num: 0, count: 0 - } - private disConnectNum: number = 0; - //调用监管接口 - sendWriteObjectOut: SendWriteObjectOut = async (data, filePath) => { - const temp = await writeObjectOut(data, filePath, this.context); - dConsole.log(JudgeTag, "wzj", JSON.stringify(temp)) - //断网&网络超时次数计算 - if (temp.code == 2300007 || temp.code == 2300028) { - this.disConnectNum += 1; - if (this.disConnectNum < 5) { - return await this.sendWriteObjectOut(data, filePath) - } - } - - if (this.disConnectNum >= 5) { - dConsole.info('surenjun', '123') - this.judgeUI.errorMsg = '当前的考试过程信息网络传输异常,程序点击确认将重启!'; - this.judgeUI.disConnectErrorOpen = true - } - - this.disConnectNum = 0 - return temp - } - private videoData?: RecordHandleType - //当前科目二的考试项目 - private deductedPopShowTimer: number = 0; - // 校验考试是否结束 - checkExamIsEnd = async (isManual?: boolean) => { - dConsole.log(JudgeTag, "校验考试是否结束") - const judgeUI = this.judgeUI - const isAllProjectsEnd = judgeUI.isAllProjectsEnd - const examSubject = judgeUI.examSubject - const singlePlay = judgeUI.singlePlay - const totalScore = Number(judgeUI.totalScore) - const judgeConfigObj = judgeUI.judgeConfigObj - const examMileage = Number(judgeUI.examMileage) - const passingScore = Number(judgeUI.passingScore) - const jl = judgeUI.jl - - if (this.isExamEnd) { - return - } - //及格分 - let passingGrade = passingScore - if (isManual) { - // 考试不合格 - await examJudgeEndExam() - this.isExamEnd = true - this.isManual = true - } else { - const param302: number = Reflect.get(judgeConfigObj, '302') - const param342: number = Reflect.get(judgeConfigObj, '342') - const param512: number[] = (Reflect.get(judgeConfigObj, '512') || '').split(','); - - //单机模式 - if (singlePlay) { - dConsole.info(JudgeTag + ' 单机模式结束 => ', isAllProjectsEnd) - if (isAllProjectsEnd && jl >= examMileage) { - //成绩合格 - if (totalScore >= passingGrade && !this.isEndTip) { - if (examSubject == '3' && (param342 == 0 || param342 == 2) && - (param302 != 6 && param302 != 7 && param302 != 8)) { - if (param512[7] != 0) { - clearTimeout(this.deductedPopShowTimer) - this.avPlayer?.playAudio(['voice/综合评判.mp3']) - this.judgeUI.isDeductedPopShow = true - this.judgeUI.defaultTabIndex = 1 - this.isEndTip = true - return - } - } else { - await examJudgeEndExam() - this.isExamEnd = true - return - } - } else { - if (examSubject == '3' && (param302 == 4 || param302 == 5 || param302 == 7 || param302 == 8)) { - await examJudgeEndExam() - this.isExamEnd = true - return - } - } - await examJudgeEndExam() - this.isExamEnd = true - } - } else { - //成绩不合格 - if (totalScore < passingGrade) { - //科目三不合格报靠边停车 - if (examSubject == '3' && param302 == 1) { - this.avPlayer?.playAudio([`voice/考试结束.mp3`]); - return - } - await examJudgeEndExam() - this.isExamEnd = true - return - } - - //成绩合格 - if (isAllProjectsEnd && totalScore >= passingGrade && !this.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 - this.avPlayer?.playAudio(['voice/综合评判.mp3']) - this.judgeUI.isDeductedPopShow = true - this.judgeUI.defaultTabIndex = 1 - this.isEndTip = true - } - } else { - await examJudgeEndExam() - this.isExamEnd = true - } - } - } - } - } - - constructor(judgeUI: JudgeUI) { - this.serialIndex = 1; - this.judgeUI = judgeUI - //语音播放工具 - this.avPlayer = new VoiceAnnounce(this.context); - //模型工具 - this.fileModel = new FileModel(judgeUI.context); - //文件工具 - this.fileUtil = new FileUtils(judgeUI.context) - this.judgeTask = new JudgeTask() - this.usbService = new UsbService(); - this.kfArr = judgeUI.kfArr - this.xmmcStr = ''; - this.xmmcCode = ''; - this.xmmcEndCode = undefined; - this.carztStr = ''; - this.kmItems = {}; - // 考试回放配置 - this.isTrajectoryOpen = JudgeConfig.isTrajectoryOpen; - this.modelPath = JudgeConfig.modelPath; - this.trajectoryPath = JudgeConfig.trajectoryPath; - - //TODO 临时改动 - this.isExam = !AppStorage.get('singlePlay')!; - (judgeUI.examSubject == '2' ? testKm2Items : testKm3Items).forEach(item => { - const projectCenterObj: ProjectInfo = Reflect.get(judgeUI.projectsCenterObj, item.code) - - Reflect.set(this.kmItems, item.code, { - code: item.code, - status: projectCenterObj === undefined ? 0 : (projectCenterObj.isEnd ? 3 : 1) - }) - }) - dConsole.info(JudgeTag + 'testKmItems', JSON.stringify(this.kmItems)) - this.isExamEnd = false; - } - - public async onJudgeFn(fn: Function) { - await this.judging(fn) - } - - // 获取评判初始化数据 - getJudgeInitData = async () => { - const carInfo = AppStorage.get('carInfo'); - const judgeUI = this.judgeUI - // const projectsObj = judgeUI.projectsObj - const itemInfoObj = judgeUI.itemInfoObj - const markRuleListObj = judgeUI.markRuleListObj - const carType = judgeUI.carType - const carName = judgeUI.carName - const systemparmArr = judgeUI.systemparmArr - const carinfoArr = judgeUI.carinfoArr - const examType = carInfo?.examSubject == '2' ? 'km2' : 'km3' - - let allitems: ItemInfo[] = []; - if (judgeUI.examSubject == '2' && itemInfoObj) { - allitems = Reflect.ownKeys(itemInfoObj).map(cdsbKey => { - const cdsb: CDSBInfo = Reflect.get(itemInfoObj, cdsbKey); - const model = this.getModelData(`${examType}/${cdsb.modelKey}.txt`) - const temp: ItemInfo = { - xmdm: cdsb?.xmdm || 0, - xmxh: cdsb?.xmxh || "", - model: model || "" - } - return temp - }) - } - - //获取版本号 - const mark: MarkRule[] = Reflect.ownKeys(markRuleListObj).map(ruleKey => { - const current: MarkRule = Reflect.get(markRuleListObj, ruleKey) - return current - }) - const initInfo: JudgeInitObj = { - sdkver: await examJudgeVersion(), - appver: AppStorage.get('baseInfo')?.version || "", - kskm: Number(carInfo?.examSubject || "2"), - kchp: carInfo?.plateNo || "", - kchm: Number(carInfo?.carId || ""), - kscx: carType, - cxcode: '1', - name: carName, - carmodel: this.getModelData(`${examType}/${carType}.txt`) || "", - allitems, - iteminfo: [], - systemparm: systemparmArr, - mark, - sysset: judgeUI.judgeConfig, - itemInfoObj, - carlist: judgeUI.carlist, - carinfo: carinfoArr, - }; - let km3Config: Km3JudgeInitConfig = {} - - if (judgeUI.examSubject == '3') { - km3Config = await this.getKm3JudgeInitConfig(); - initInfo.map_point = km3Config.map_point - initInfo.map_point_item = km3Config.map_point_item - initInfo.iteminfo = km3Config.iteminfo - initInfo.roads = km3Config.roads - initInfo.sharps = km3Config.sharps - } - // 获取科目三的评判配置 - dConsole.info(JudgeTag, '3.获取评判初始化数据完成') - return initInfo - - } - // 获取开始考试数据 - getJudgeBeginData = async () => { - const examinerInfo = AppStorage.get('examinerInfo') - const examinerName = examinerInfo?.name || "" - - let currentParams: RouteParamsType = router.getParams() as RouteParamsType; - const sczb = currentParams.sczb; - const kfdm = currentParams.kfdm; - const judgeUI = this.judgeUI - - const projects = judgeUI.projects - const carType = judgeUI.carType - const kssycs = judgeUI.kssycs - const isDdxk = judgeUI.isDdxk - const ddxkTime = judgeUI.ddxkTime - const projectsCenterObj: object = judgeUI.projectsCenterObj - const ddxkKsxmArr = judgeUI.ddxkKsxmArr - const ddxkKfArr = judgeUI.ddxkKfArr - const passingScore = judgeUI.passingScore - - const ksxm: JudgeKSXM[] = projects.map(project => { - const temp: JudgeKSXM = { - xmdm: Number(project.projectCode), xmxh: '' - } - return temp - }) - - const ykxm: number[] = (ddxkKsxmArr?.map(projectCenterCode => { - const currentProject: ProjectInfo = Reflect.get(projectsCenterObj, projectCenterCode) - return Number(currentProject.projectCode) - })) || []; - - const kfxm: JudgeKFXM[] = isDdxk ? (ddxkKfArr?.map(kf => { - return { - xmdm: Number(kf.split(',')[0]), kfdm: kf.split(',')[1] - } as JudgeKFXM - })) : [] - - const beginInfo: JudgeBeginObj = { - kgid: '012', - kgxm: decodeURI(examinerName || ''), - exam: this.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: Number(judgeUI.wayno), - czlx: 0, - kskssj: await systemTime.getCurrentTime(), - passing: Number(passingScore), - ksxm, - //断点续考 - ddxk: isDdxk ? 1 : 0, - ddkssj: ddxkTime || 0, - ykxm, - kfxm, - //TODO 已考里程待修改 - yklc: 0, - special: [], - sczb: (sczb === undefined || sczb == '0') ? 0 : 1, - sczbkf: kfdm, - dmndg: false, - mfxx: false, - mfxxn: false - } - dConsole.info(JudgeTag, '5.获取开始考试数据完成') - return beginInfo - } - //处理评判过程回调 - handleRealExam = async (strData: string, callBack: Function) => { - let examData: JudgeCallBackData = JSON.parse(strData); - const judgeUI = this.judgeUI; - const carzt = examData.carzt - const xmks = examData.xmks - const kf = examData.kf - const event = examData.event - const xmjs = examData.xmjs - const xmqx = examData.xmqx - const ksjs = examData.ksjs - const sound = examData.sound - const mndg = examData.mndg - const lane = examData.lane - const precast = examData.precast - const nongps = examData.nongps - //获取项目结束、项目开始代码 - const xmdm = event == 2 ? xmjs.xmdm : xmks.xmdm - const xmxh = event == 2 ? xmjs.xmxh : xmks.xmxh; - const isManualProjectIn = this.artSubject3ProjectsCodesArr.includes(xmdm); - const examSubject = this.judgeUI.examSubject - const projects = this.judgeUI.projects - const judgeConfigObj = this.judgeUI.judgeConfigObj - - - switch (event) { - //项目开始 - case 1: { - const project: ProjectInfo = Reflect.get(judgeUI.projectsObj, xmdm) - project.type = '2'; - if (isManualProjectIn) { - //手动项目是否在进行中 - this.judgeUI.isManualProjectIn = true - } - if (xmdm == 41 && examSubject == '3') { - this.rmndg = 1 - } - this.judgeUI.currentXmdm = xmdm; - const xmmcStr = project.name || ""; - const xmmcCode = project.projectCodeCenter || ""; - const xmmcSingleCode = project.projectCode || ""; - const kmItem: KmItem = Reflect.get(this.kmItems, xmmcCode) - kmItem.status = 2; - this.xmmcStr = xmmcStr; - this.xmmcCode = xmmcCode; - this.xmmcSingleCode = xmmcSingleCode - this.xmmcEndCode = xmmcCode - this.xmdm = xmdm; - this.xmxh = xmxh; - this.judgeUI.isProjectIn = true - Reflect.set(this.judgeUI.projectsObj, xmdm, project) - Reflect.set(this.kmItems, xmmcCode || 0, kmItem) - break; - } - //项目结束 - case 2: { - const project: ProjectInfo = Reflect.get(judgeUI.projectsObj, xmdm) - const xmmcCode = project.projectCodeCenter || ""; - project.type = (xmjs.xmhg === 0 ? '4' : '3') - - //计算项目是否全部结束 - this.judgeUI.isProjectIn = (Reflect.ownKeys(judgeUI.projectsObj).filter((projectKey) => { - const fillProject: ProjectInfo = Reflect.get(judgeUI.projectsObj, projectKey) - return fillProject.type == '2' - }).length) > 0; - - if (isManualProjectIn) { - this.judgeUI.isManualProjectIn = false - } - const kmItem: KmItem = Reflect.get(this.kmItems, xmmcCode) - kmItem.status = 3; - //统计必考项目数量 - this.xmmcStr = '无'; - this.xmmcCode = ''; - this.xmdm = ''; - this.judgeUI.currentXmdm = undefined; - Reflect.set(this.judgeUI.projectsObj, xmdm, project) - Reflect.set(this.kmItems, xmmcCode, kmItem) - break; - } - - //扣分 - case 3: { - const thisKf = this.getKfStr(`${kf.xmdm}_${kf.kfdm}`) - const kfObj: MarkRule = { - //扣分项目名称 - xmmcStr: this.getDqxmStr(kf.xmdm), - xmdm: kf.xmdm + "", - //扣分描述 - desc: thisKf.desc, - //扣分分数 - score: thisKf.score, - // 扣分无锡所代码 - markcatalog: thisKf.markcatalog, - markserial: thisKf.markserial, - kfxh: thisKf.kfxh, - //扣分类型 - type: kf.type - } - dConsole.log(JudgeTag, "扣分组装", kfObj) - //扣分信息 - this.kfArr?.push(kfObj) - dConsole.log(JudgeTag, "扣分类组装", this.kfArr) - this.judgeUI.totalScore += Number(thisKf?.score); - if (kf.xmdm != 20) { - const project: ProjectInfo = Reflect.get(judgeUI.projectsObj, kf.xmdm) - const type = project.type; - project.type = (type == '3' || type == '4') ? '4' : '5' - Reflect.set(this.judgeUI.projectsObj, kf.xmdm, project) - } - break; - } - //考车状态 - case 4: { - this.carztStr = GetCarStatus(carzt); - break; - } - //考试结束 - case 5: { - this.ksjs = ksjs; - // await fileLog?.setExamJudgeData(JSON.stringify({ - // method: 'examJudgeEndExam' - // })) - dConsole.writeProcessData(ProcessDataEnumType.JudgeExamData, JSON.stringify({ - method: 'examJudgeEndExam' - })) - break; - } - //项目取消 - case 6: { - dConsole.info(JudgeTag, '项目取消'); - const xmdm = xmqx.xmdm; - const project: ProjectInfo = Reflect.get(judgeUI.projectsObj, xmdm) - // const examSubject = this.judgeUI.examSubject - const xmmcCode = project.projectCodeCenter || ""; - // const voiceCode = getKmProjectCancelVoice(examSubject, xmmcCode); - // avPlayer.playAudio([`voice/${voiceCode}.mp3`],true) - project.type = '1' - const kmItem: KmItem = Reflect.get(this.kmItems, xmmcCode) - Reflect.set(this.judgeUI.projectsObj, xmdm, project) - kmItem.status = 1 - Reflect.set(this.kmItems, xmmcCode, kmItem) - break; - } - - //语音播放和提示 - case 7: { - this.goJudgeVoice(sound) - break; - } - //模拟灯光事件 - case 8: { - this.setMndg(mndg) - break; - } - //车道和路段变化 - case 9: { - this.judgeUI.lane = lane - this.lane = lane; - break; - } - //预进项目事件 - case 10: { - const param611: JudgeConfigObj = Reflect.get(judgeConfigObj, '611') || '' - 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(this.kmItems, xmmcCode) - const xmmcStr = project?.name || ""; - kmItem.status = 2; - Reflect.set(this.kmItems, xmmcCode, project) - this.xmmcStr = xmmcStr || ""; - this.xmmcCode = xmmcCode || ""; - this.xmdm = xmdm; - this.xmxh = xmxh; - this.xmmcSingleCode = xmmcSingleCode || ""; - project.type = '2'; - Reflect.set(this.judgeUI.projectsObj, xmdm, project) - } - break; - //差分事件 - case 11: { - this.checkDwzt(nongps.type) - } - default: - break; - } - await callBack({ - //项目名称 考车状态 扣分arr - xmmcStr: this.xmmcStr, carztStr: this.carztStr, kfArr: this.kfArr - }); - - //语音播报 - this.goVoiceAnnounce(event, xmdm, this.kfArr || [], xmjs, ksjs, xmxh) - //更新UI - if (event == 1 || event == 2 || event == 3 || event == 6) { - const copyProjectsObj: object = this.judgeUI.projectsObj; - judgeUI.projectsObj = DeepClone(copyProjectsObj); - } - } - // 更改考试状态 - goVoiceAnnounce = async (event: number, xmdm: number, kf: MarkRule[], xmjs: JudgeXMJS, ksjs: JudgeKSJS, xmxh: string) => { - const beginProject = this.beginProject - const pointsDedute = this.pointsDedute - const endProject = this.endProject - const avPlayer = this.avPlayer - const uploadProgressPhoto = this.uploadProgressPhoto - const judgeTask = this.judgeTask - const handEndExam = this.handEndExam - const judgeUI = this.judgeUI - const checkExamIsEnd = this.checkExamIsEnd - const checkProjectIsStart = this.checkProjectIsStart - - const projectsObj: object = judgeUI.projectsObj - const judgeConfigObj: object = judgeUI.judgeConfigObj - const examSubject = judgeUI.examSubject - - const kfLen = kf.length; - //不报语音的项目列表 - // const ignoreVoiceCodeArr = (judgeConfigObj['312'] || '').split(',') - // const param611 = judgeConfigObj['611'] || ''; - // const [f, s] = param611.split('/') - switch (event) { - // 项目开始 - case 1: - const param512: JudgeConfigObj = (Reflect.get(judgeConfigObj, '512') || '').split(','); - const project: ProjectInfo = Reflect.get(projectsObj, xmdm) - const code = project.projectCodeCenter; - const isEnd = project.isEnd; - setTimeout(() => { - if (Reflect.get(param512, 7) != 0) { - clearTimeout(this.deductedPopShowTimer) - this.judgeUI.isDeductedPopShow = true - } - }, 200) - //项目已考不上传监管信息 - if (!isEnd) { - judgeTask.addTask(async () => { - dConsole.info(JudgeTag, `项目开始-${xmdm}-${project.name}`) - await beginProject(xmdm) - }, { - isDelay: true - }) - judgeTask.addTask(async () => { - dConsole.info(JudgeTag, `项目-${xmdm}-上传照片 start`) - await uploadProgressPhoto(xmdm) - }, { - isDelay: true - }) - project.isUpload = true; - // Reflect.set(this.judgeUI.projectsObj, xmdm, project) - } - break; - - // 项目结束 - case 2: { - const project: ProjectInfo = Reflect.get(projectsObj, xmdm) - const projectIsEnd = project.isEnd; - const isStart = await this.checkProjectIsStart(xmdm, 1); - if (isStart) { - //项目结束了就不再生成数据 - dConsole.info(JudgeTag + ' projectIsEnd =>', projectIsEnd) - if (!projectIsEnd) { - judgeTask.addTask(async () => { - dConsole.info(JudgeTag, `项目结束-${xmdm}-${project.name}`) - await endProject(xmdm); - this.xmmcSingleCode = '0'; - this.xmmcEndCode = undefined; - }, { - isDelay: true - }) - } - } - if (!this.judgeUI.isProjectIn) { - this.deductedPopShowTimer = setTimeout(() => { - this.judgeUI.isDeductedPopShow = false - }, (Reflect.get(param512!, 5) || 0) * 1000) - } - project.isEnd = true; - // Reflect.set(this.judgeUI.projectsObj, xmdm, project) - break; - } - - // 扣分 - case 3: { - dConsole.info(JudgeTag, '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 || 0)}.mp3`]) - } - const isStart = await checkProjectIsStart(Number(currentKf.xmdm), 2, currentKf); - if (isStart) { - await judgeTask.addTask(async () => { - dConsole.info(JudgeTag, `项目扣分-${currentKf.markcatalog}-${currentKf.desc}`) - await pointsDedute(Number(currentKf.xmdm), currentKf) - }, { - isDelay: true - }) - } - break; - } - // 考车状态 - case 4: - break - - // 考试结束 - case 5: { - dConsole.info(JudgeTag, '考试结束') - //关闭录像 - const singlePlay = AppStorage.get('singlePlay') - if (!singlePlay && this.videoData) { - await endRecordVideo(this.videoData) - } - judgeTask.addTask(async () => { - dConsole.info(JudgeTag, '考试结束 start') - AppStorage.setOrCreate('isJudge', false) - await handEndExam() - }) - // TODO待修改 - // 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: number, kf: MarkRule) => { - const carInfo = AppStorage.get('carInfo')!; - const examSubject = carInfo.examSubject - - const judgeUI = this.judgeUI - const xmmcEndCode = this.xmmcEndCode - const filePath = this.filePath - - const lsh = judgeUI.lsh - const idCard = judgeUI.idCard - const serialNumber = judgeUI.serialNumber - const ksdd = judgeUI.ksdd - const projectsObj: object = judgeUI.projectsObj - - const time = GetCurrentTime(); - const project: ProjectInfo = this.getProjectInfo(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 - } - }) - - // const ksxmD: string = !project - // ? (commonKsxm - // ? (project?.projectCodeCenter!) - // : (examSubject == '3' ? '30000' : (xmmcEndCode == undefined ? '10000' : xmmcEndCode))) - // : project.projectCodeCenter - 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: time - } - const data: RegulatoryInterfaceParams = { - xtlb: '17', - jkxlh: serialNumber, - jkid: '17C53', - drvexam - } - // dConsole.info(judgeTag + 'ksxm=>', data.drvexam.ksxm) - - const temp = await this.sendWriteObjectOut(data, filePath); - if (temp.code == 2300007) { - this.isJudgeDisConnect = true - } - dConsole.info(JudgeTag, '项目扣分 end') - UploadRegulatoryCodeConversion('17C53', temp?.code || 0) - } - // 评判语音提示 - goJudgeVoice = async (sound: JudgeSound) => { - // const fileLog = this.fileLog - dConsole.info('surenjun code=>', JSON.stringify(sound.code)) - //判断是不是模拟灯光语音 - if (sound.type == 1) { - this.avPlayer?.playAudio([`voice/${sound.code[0]}.mp3`], false, () => { - examJudgeSoundEnd({ - xmdm: sound.xmdm, code: sound.code[0], type: sound.type - }) - // fileLog?.setExamJudgeData(JSON.stringify({ - // method: 'examJudgeSoundEnd', - // itemno: 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 { - this.avPlayer?.playAudio([`voice/${sound.code[0]}.mp3`]) - } - } - // 处理考试结束 - public handEndExam = async () => { - dConsole.info(JudgeTag, '处理考试结束 handEndExam') - // this.judgeUI.loadingPopupVisible = true; - dConsole.log(JudgeTag, ' 打开车辆loading1') - this.judgeUI.generateExamRecordsDialogController.open() - // this.judgeUI.endPopupVisible = false; - this.judgeUI.endExamDialogController.close() - this.judgeUI.isDeductedPopShow = false; - - const judgeUI = this.judgeUI - const endExam = this.endExam - const handleSEP = this.handleSEP - const avPlayer = this.avPlayer - const isManual = this.isManual - - const judgeConfigObj = judgeUI.judgeConfigObj - const examSubject = judgeUI.examSubject - const isAllProjectsEnd = judgeUI.isAllProjectsEnd - const totalScore = judgeUI.totalScore - const passingScore = judgeUI.passingScore - - //计算考试分数 - // this.judgeUI.totalScore = isAllProjectsEnd ? totalScore : 0; - const singlePlay = AppStorage.get('singlePlay') - const param302: string = Reflect.get(judgeConfigObj, '302') - - //自动退出待验证并且不合格 - if (!isManual && examSubject == '3' && (param302 == '1' || (singlePlay && param302 == '2')) && - totalScore < passingScore) { - avPlayer?.playAudio([`voice/考试结束.mp3`]) - } - //联网模式下手动结束的直接退出 - if (!singlePlay && isManual && !isAllProjectsEnd) { - avPlayer?.playAudio(['voice/empty.mp3'], true, () => { - this.isUdpEnd = true; - dConsole.log(JudgeTag, "router back7") - router.back(); - }) - return - } - if (examSubject == '3') { - if (totalScore < passingScore) { - //考试不合格;考试模式,自动退出; - if (param302 == '4' || param302 == '5' || param302 == '7' || param302 == '8') { - } - } else { - //考试合格 - } - } - await handleSEP(306); - avPlayer?.playAudio(['voice/exam_waiting.mp3'], AppStorage.get('singlePlay'), async () => { - try { - if (!singlePlay) { - // TODO const bytes = await this.getMessageHeartbeat(true); - // TODO globalThis.judgeUdp.send(bytes) - } - } catch (e) { - dConsole.info(JudgeTag, JSON.stringify(e)) - } - await endExam() - }); - - } - // 考试结束 - public endExam = async (isManual?: Boolean) => { - dConsole.log(JudgeTag, '考试结束 endExam') - const carInfo = AppStorage.get('carInfo')!; - const singlePlay = AppStorage.get('singlePlay') || false - const examSubject = carInfo?.examSubject || "2" - const plateNo = carInfo?.plateNo || "" - - const judgeUI = this.judgeUI - const ksjs = this.ksjs - const avPlayer = this.avPlayer - const kfArr = this.kfArr - const filePath = this.filePath - - const lsh = judgeUI.lsh; - const idCard = judgeUI.idCard; - const serialNumber = judgeUI.serialNumber; - const kssycs = judgeUI.kssycs; - const totalScore = judgeUI.totalScore; - const judgeConfigObj = judgeUI.judgeConfigObj; - const isAllProjectsEnd = judgeUI.isAllProjectsEnd; - const passingScore = judgeUI.passingScore; - //TODO 断网考试结束补传 - // await uploadDisConnectData(); - const time = GetCurrentTime(); - const photoBase64 = await GetPhotoBase64(this.context); - const d1 = ksjs?.d1 || 0; - const d2 = ksjs?.d2 || 0; - const d3 = ksjs?.d3 || 0; - const d4 = ksjs?.d4 || 0; - const d5 = ksjs?.d5 || 0; - - const drvexam: DrvexamType = { - lsh, - kchp: encodeURI(plateNo), - kskm: examSubject, - sfzmhm: idCard, - zp: photoBase64, - jssj: time, - kscj: (totalScore * 1) > 0 ? totalScore : 0, - kslc: Math.ceil(((ksjs?.qjjl ?? 0) + (ksjs?.dcjl ?? 0)) / 100), - // 1,22;2,560;3,128;4,0;5,0; - dwlc: [d1, d2, d3, d4, d5].map((d, index) => `${index + 1},${Math.floor(d / 100)}`).join(';'), - } - - const data: RegulatoryInterfaceParams = { - xtlb: '17', - jkxlh: serialNumber, - jkid: '17C56', - drvexam - } - let backTimeOut = setTimeout(() => { - dConsole.log(JudgeTag, "router back6") - router.back() - }, 90 * 1000) - const temp = await this.sendWriteObjectOut(data, filePath); - UploadRegulatoryCodeConversion('17C56', temp?.code || 0) - - if (temp.code != 1) { - avPlayer?.playAudio(['voice/监管失败.mp3']) - this.judgeUI.errorMsg = decodeURIComponent(temp?.message || "") - - if (temp.code == 2300028 || temp.code == 2300007) { - this.judgeUI.errorMsg = '当前的考试过程信息监管审核未通过,程序将退出!' - } - this.isUdpEnd = true; - // this.judgeUI.loadingPopupVisible = false; - dConsole.log(JudgeTag, ' 关闭车辆loading1') - this.judgeUI.generateExamRecordsDialogController.close() - return - } - dConsole.info(JudgeTag, '考试结束 end') - const param302: string = Reflect.get(judgeConfigObj, '302') - // judgeUI.loadingPopupVisible = true; - dConsole.log(JudgeTag, ' 打开车辆loading2') - // judgeUI.generateExamRecordsDialogController.open() - 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'); - USER[0].kssycs = currentKssycs - await SqlInsertTable('USER', USER) - - dConsole.info(JudgeTag, `考试成绩:${totalScore}`) - if (!singlePlay) { - // await uploadProgressData(); - } - clearTimeout(backTimeOut) - //语音播放扣分项 - let score = 0; - //结束考试时候是否播报一遍所有扣分 - const param634: string = Reflect.get(judgeConfigObj, '634') - if (kfArr && 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 && kfArr.length - 1 === index) { - avPlayer?.playAudio([`voice/${kf.markcatalog}.mp3`, voiceURL], false, () => { - this.isUdpEnd = true; - dConsole.log(JudgeTag, "router back4") - 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; - dConsole.log(JudgeTag, "router back5") - router.back(); - }) - throw new Error('End Loop') - } - }) - } catch (e) { - dConsole.info(JudgeTag, JSON.stringify(e)) - } - }) - } else { - avPlayer?.playAudio([voiceURL], true, () => { - setTimeout(() => { - this.isUdpEnd = true - dConsole.log(JudgeTag, ' 关闭车辆loading2') - this.judgeUI.generateExamRecordsDialogController.close() - dConsole.log(JudgeTag, "router back8") - DifferentialAndSignal.clearMsg() - router.back(); - }, param302 == '8' ? 3000 : 0) - }) - } - - } - // 当前项目转换 - getDqxmStr: GetDqxmStr = (xmdm) => { - const project: ProjectInfo = Reflect.get(this.judgeUI.projectsObj, xmdm) - return project?.abbreviation || '通用评判' - } - // 扣分项目转换 - getKfStr: GetKfStr = (code) => { - const markRuleListObj = this.judgeUI.markRuleListObj; - const thisMark: MarkRule = Reflect.get(markRuleListObj, code) - return { - desc: thisMark.markshow, - score: thisMark.markreal, - markcatalog: thisMark.markcatalog, - markserial: thisMark.markserial, - kfxh: thisMark.kfxh - } - } - //获取场地序号 - getSbxh: GetgSbbm = (ksxm, xmxh) => { - const judgeUI = this.judgeUI; - const projectsObj: object = judgeUI.projectsObj; - const cdsbInfoObj: CDSBInfos = judgeUI.cdsbInfoObj!; - const project: ProjectInfo = Reflect.get(projectsObj, ksxm); - if (judgeUI.examSubject == '3') { - return '0000000000' - } - if (project === undefined) { - return '0000000000' - } - const projectKey = `${ksxm}_${xmxh}`; - const currentCdsb: CDSBInfo = Reflect.get(cdsbInfoObj, projectKey) ?? {} as CDSBInfo; - const sbxh: string = currentCdsb.sbbh || '0000000000' - return sbxh - } - getSbbm: GetgSbbm = (ksxm, xmxh) => { - const judgeUI = this.judgeUI; - const cdsbInfoObj = judgeUI.cdsbInfoObj; - const projectsObj: object = judgeUI.projectsObj; - const project: ProjectInfo = Reflect.get(projectsObj, ksxm); - //科目三不需要 - if (judgeUI.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 - } - // 中心所有项目转换 - getTranslateProject = () => { - const examSubject = this.judgeUI.examSubject; - const tempItems: TKmItem[] = (examSubject == '2' ? testKm2Items : testKm3Items).map(item => { - const kmItem: KmItem = Reflect.get(this.kmItems, item.code) - const status = GetCenterProjectStatus(kmItem.status) - const temp: TKmItem = { - code: item.code, status - } - return temp - }) - - const arr: string[] = []; - 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: number) => { - const project: ProjectInfo = Reflect.get(this.judgeUI.projectsObj, projectCode) - return project - } - // 获取模型数据 - getModelData = (modelName: string) => { - const modelData = this.fileModel?.getModelContent(this.modelPath, modelName); - return modelData - } - // 统计必考项目、所有项目、已考数量 - setCountItems = async () => { - const projectsObj: object = this.judgeUI.projectsObj; - //必考项目数量 必考项目已考数量 - let projectNum = 0, endProjectsNum = 0; - // 所有考试项目数量 项目已考项目数量 - let allProjectNum = 0, allEndProjectsNum = 0; - Reflect.ownKeys(projectsObj).forEach(projectKey => { - const projectObj: ProjectInfo = Reflect.get(projectsObj, projectKey) - const type = projectObj.type - const isRequired = projectObj.isRequired - allProjectNum += 1; - if (type == '3' || type == '4') { - allEndProjectsNum += 1; - } - - if (isRequired) { - projectNum += 1; - if (type == '3' || type == '4') { - endProjectsNum += 1; - } - } - }) - - dConsole.info(JudgeTag, '项目状态projectsObj:' + JSON.stringify(projectsObj)); - dConsole.info(JudgeTag, '所有考试项目数量:' + allProjectNum) - dConsole.info(JudgeTag, '必考项目数量:' + projectNum) - dConsole.info(JudgeTag, '必考项目已考数量:' + endProjectsNum) - //必考项目除靠边停车是否全部完成 - this.judgeUI.isRequiredProjectsEnd = (projectNum - endProjectsNum === 0) - this.judgeUI.isAllProjectsEnd = (allProjectNum - allEndProjectsNum === 0) - } - // 检测差分状态 - checkDwzt = async (type: number) => { - const avPlayer = this.avPlayer; - 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; - } - } - - //开始评判 - private async judging(callBack: Function) { - const judgeUI = this.judgeUI; - - const name = judgeUI.name - const kssycs = judgeUI.kssycs - const manualMarkRules = judgeUI.manualMarkRules - - - const getJudgeBeginData = this.getJudgeBeginData; - const handleTrajectoryUdp = this.handleTrajectoryUdp; - const isTrajectoryOpen = this.isTrajectoryOpen; - const trajectoryPath = this.trajectoryPath; - const avPlayer = this.avPlayer; - - const isJudgeInitBool = AppStorage.get('isJudgeInitBool'); - let strArr: string[] = []; - if (isTrajectoryOpen) { - const folderPath = await this.fileUtil.initFolder(trajectoryPath); - const str: string = await this.fileUtil.readFile(folderPath) - strArr = str.split('\n') - } - //日志回调 - dConsole.info(JudgeTag, '1.进入评判入口') - await examJudgeSetLogCallback(6, async (level: number, info: string, len: number) => { - dConsole.log(JudgeTag, '评判日志:' + info) - // await fileLog?.setExamJudgeLogData(info); - dConsole.writeProcessData(ProcessDataEnumType.JudgeLogData, info) - }) - - dConsole.info(JudgeTag, '2.注册日志回调完成') - - let initInfo: JudgeInitObj = isTrajectoryOpen ? JSON.parse(strArr[0]) : await this.getJudgeInitData(); - // await fileLog?.setExamJudgeData(JSON.stringify(initInfo)) - //相关评判初始化只做一次 - if (!isJudgeInitBool) { - dConsole.log(JudgeTag, "评判初始化参数", initInfo) - const tempJudge = await examJudgeInit(initInfo); - AppStorage.setOrCreate('isJudgeInitBool', true) - dConsole.info(JudgeTag, '4.评判初始化完成') - } - AppStorage.setOrCreate('isJudge', true) - // 2.评判过程回调 - await examJudgeSetRealExamCallback(async (strData: string, len: number) => { - // 评判回调日志 - // await fileLog?.setExamJudgeCallbackData(strData) - dConsole.writeProcessData(ProcessDataEnumType.JudgeProgressCallbackData, strData) - dConsole.info(JudgeTag, '评判回调数据', strData) - await this.handleRealExam(strData, callBack) - }) - - await examJudgeSetPerformCallback(async (info: string) => { - dConsole.info('评判实时数据', info) - const performInfo: JudgePerformInfo = JSON.parse(info) - this.performInfo = performInfo - const jl = Math.floor((performInfo.qjjl + performInfo.dcjl) / 100); - if (jl > Number(this.judgeUI.examMileage)) { - this.checkExamIsEnd() - } - this.judgeUI.jl = jl - //TODO 待优化 跨组件传值不生效 - // globalThis.laneData = performInfo.lane; - // let res = InitialPerLane - // res.MapRoad_Code_No = dayTs().format("YYYY-MM-DD HH:mm:ss") - // dConsole.log(JudgeTag, "车道信息", res) - // this.judgeUI.laneSignal = res - this.judgeUI.laneSignal = performInfo.lane - }) - - let beginExamInfo: JudgeBeginObj | undefined = undefined - // 3.开始考试 - if (isTrajectoryOpen) { - beginExamInfo = JSON.parse(strArr[1]) - beginExamInfo && (beginExamInfo.replay = 1) - } else { - beginExamInfo = await getJudgeBeginData() - } - if (beginExamInfo) { - await examJudgeBeginExam(beginExamInfo); - } - dConsole.info(JudgeTag, '6.开始考试注册完成') - avPlayer?.playAudio([judgeUI.singlePlay ? 'voice/ksks.wav' : 'voice/监管成功.mp3']) - - if (!judgeUI.singlePlay) { - this.videoData = await saveStartRecordVideo(`${name}_${kssycs}`, this.context) - } - - this.judgeUI.draw = true - // 处理轨迹plc信息 - if (isTrajectoryOpen) { - handleTrajectoryUdp(strArr); - return - } - // 处理实时udp里的plc信号 - DifferentialAndSignal.onMsg((data: string) => { - const result: WorkerBackMessage = JSON.parse(data) - if (result.type === WorkerBackMessageType.ObtainUdpData) { - this.handleUdp(result.data as string) - dConsole.writeProcessData(ProcessDataEnumType.PlcData, result.data as string) - } - //TODO UDP修改 - // const udpIndex = globalThis.udpIndex; - // if (udpIndex % 5 === 0) { - // handDistance(); - // } - }) - - // this.checkExamIsEnd() - - //TODO 监听远程结束考试 - // globalThis.udpEvent.onEndExam(async () => { - // this.checkExamIsEnd(true); - // }) - - dConsole.info(JudgeTag, JSON.stringify(manualMarkRules)) - //TODO 监听远程扣分 - // globalThis.udpEvent.onKfExam(async (content:JudgeUdpKf) => { - // dConsole.info('评判收到远程扣分项目内容' + JSON.stringify(content)) - // const kfxh = content.data.kfxh; - // const directives = content.data.directives; - // dConsole.info(judgeTag, '评判收到远程扣分项目内容,扣分序号:' + `kfxh=>${kfxh}; directives=>${directives}`) - // //根据扣分序号找扣分代码 - // const currentKf:MarkRule = manualMarkRules.filter(mark => mark.kfxh == kfxh)[0]; - // dConsole.info(judgeTag, '扣分项目:' + JSON.stringify(currentKf)) - // this.setJudgeMark(String(currentKf.itemno), currentKf.markserial, 2); - // //TODO - // //globalThis.judgeUdp.confirmKf(directives, 1) - // }) - this.checkExamIsEnd(); - - } -} \ No newline at end of file diff --git a/entry/src/main/ets/pages/judgeSDK/utils/fileModel.ets b/entry/src/main/ets/pages/judgeSDK/utils/fileModel.ets index 394531c..5d21a5a 100644 --- a/entry/src/main/ets/pages/judgeSDK/utils/fileModel.ets +++ b/entry/src/main/ets/pages/judgeSDK/utils/fileModel.ets @@ -55,7 +55,7 @@ export default class FileModel { try { return this.fileUtil?.getFileContent(`${folderPath}/${fileName}`); } catch (e) { - dConsole.info('surenjun', JSON.stringify(e)); + dConsole.info(JSON.stringify(e)); promptAction.showToast({ message: `请检查模型路径${folderPath}/${fileName}是否正确!`, duration: 4000 diff --git a/entry/src/main/ets/pages/judgeSDK/utils/voiceAnnouncements.ets b/entry/src/main/ets/pages/judgeSDK/utils/voiceAnnouncements.ets index 2d0c3ee..1e26c7f 100644 --- a/entry/src/main/ets/pages/judgeSDK/utils/voiceAnnouncements.ets +++ b/entry/src/main/ets/pages/judgeSDK/utils/voiceAnnouncements.ets @@ -224,4 +224,4 @@ class AVPlayer { } }) } -} \ No newline at end of file +} diff --git a/entry/src/main/ets/utils/Common.ets b/entry/src/main/ets/utils/Common.ets index 7ea88e5..4931364 100644 --- a/entry/src/main/ets/utils/Common.ets +++ b/entry/src/main/ets/utils/Common.ets @@ -1,7 +1,7 @@ import dayTs from './Date'; import fs from '@ohos.file.fs'; import { BusinessError } from '@ohos.base'; -import { CommonFileTag, JudgeConfig, JudgeTag } from '../config'; +import { CommonFileTag, JudgeConfig, JudgeTag, LogTag } from '../config'; import abilityAccessCtrl, { Permissions } from '@ohos.abilityAccessCtrl'; import Prompt from '@system.prompt'; import common from '@ohos.app.ability.common'; @@ -88,6 +88,22 @@ export function ArrayToByteArray(array: number[]): Uint8Array { * @returns 返回字节数组 */ export function NumberToByteArray(number: number | string, len: number): number[] { + if (len === 8) { + return [...new Uint8Array([Number(number)])] + } + if (len === 16) { + return [...new Uint8Array(new Uint16Array([Number(number)]).buffer)] + } + if (len === 32) { + return [...new Uint8Array(new Uint32Array([Number(number)]).buffer)] + } else { + let buffer = new ArrayBuffer(len / 8) + let array = new Uint8Array(buffer) + array.set([Number(number)]) + return [...array] + } + + let str = Math.floor(Number(number)).toString(2); if (str.length > len) { console.log('数据长度不对~~'); @@ -109,11 +125,11 @@ export function NumberToByteArray(number: number | string, len: number): number[ return arrBytes; } -/* - * 将字符串填充为指定长度的字符串,前面补0 - * @param str 要填充的字符串或数字 - * @param len 目标长度 - * @return 返回填充后的字符串 +/** + * 将字符串填充为指定长度的字符串,前面补0 + * @param str 要填充的字符串或数字 + * @param len 目标长度 + * @return 返回填充后的字符串 */ export function FillZero(str: string | number, len: number): string { str = str.toString(); @@ -176,10 +192,10 @@ export function DeepClone(target: T): T { return target; } -/* - * 检查文件或目录是否存在 - * @param path 文件或目录的路径 - * @return 返回一个 Promise,解析为 true 如果存在,否则为 false +/** + * 检查文件或目录是否存在 + * @param path 文件或目录的路径 + * @return 返回一个 Promise,解析为 true 如果存在,否则为 false */ export function IsExit(path: string): Promise { return new Promise((resolve, reject) => { @@ -221,13 +237,70 @@ export function CreateDir(path: string): Promise { } /** - * 写文件 + * 打开文件 + */ +export function OpenFile(path: string): Promise { + return new Promise((resolve, reject) => { + try { + const file = fs.openSync(path, fs.OpenMode.READ_WRITE | fs.OpenMode.APPEND | fs.OpenMode.CREATE) + resolve(file.fd) + } catch (e) { + reject(-1) + } + }) +} + +/** + * 关闭文件 + */ +export function CloseFile(fd: number): Promise { + return new Promise((resolve, reject) => { + try { + fs.closeSync(fd) + resolve(true) + } catch (e) { + reject(false) + } + }) +} + +/** + * 追加写文件 + * @params fd 文件描述符 + * @params data 写入的数据 */ export function EditFile(fd: number, data: string): Promise { return new Promise((resolve, reject) => { try { + // console.log(LogTag, "写入数据:" + data) fs.writeSync(fd, data + "\n") resolve(true) + } catch (e) { + console.error(LogTag, "写入数据失败", data) + reject(false) + } + }) +} + +/** + * 覆盖写文件 + */ +export function OverWriteFile(path: string, data: string): Promise { + return new Promise(async (resolve, reject) => { + try { + // 先删除文件 + const res = await DeleteFile(path); + if (res) { + // 创建文件 + const fd = await CreateFile(path); + if (fd !== -1) { + // 写入数据 + await EditFile(fd, data); + // 关闭文件 + await CloseFile(fd); + } + } + resolve(true) } catch (e) { reject(false) } @@ -252,10 +325,41 @@ export function CreateFile(path: string): Promise { }) } -/* - * 将秒数转换为灵活的时间格式(HH:MM:SS) - * @param seconds 要转换的秒数 - * @return 返回格式化后的时间字符串 +/** + * 删除文件 + */ +export function DeleteFile(path: string): Promise { + return new Promise((resolve, reject) => { + try { + fs.unlinkSync(path) + console.log(CommonFileTag, "删除文件成功", path) + resolve(true) + } catch (e) { + console.log(CommonFileTag, "删除文件失败", path) + reject(false) + } + }) +} + +/** + * 读取文件内容 + * @params path 文件具体路径 + */ +export function ReadFileContent(path: string): Promise { + return new Promise((resolve, reject) => { + try { + const data = fs.readTextSync(path) + resolve(data) + } catch (e) { + reject(e) + } + }) +} + +/** + * 将秒数转换为灵活的时间格式(HH:MM:SS) + * @param seconds 要转换的秒数 + * @return 返回格式化后的时间字符串 */ export function FormatTimeFlexible(seconds: number): string { if (seconds < 0) { @@ -291,10 +395,10 @@ export function ApplyForAuthorization(context: Context, permissionList: Array { const permissions: Array = [ @@ -351,4 +455,10 @@ export const GetPhotoBase64 = async (context: common.UIAbilityContext): Promise< return '' } } +} + + +export function GetObjectValue(obj: T, key: string): ESObject { + // 推荐:直接使用索引访问 + return obj[key as keyof T]; } \ No newline at end of file diff --git a/entry/src/main/ets/utils/Date.ets b/entry/src/main/ets/utils/Date.ets index 897d094..def6f6a 100644 --- a/entry/src/main/ets/utils/Date.ets +++ b/entry/src/main/ets/utils/Date.ets @@ -45,8 +45,8 @@ class DayTs { 'h{2}': (dateData: DateData) => DayTs._paddingZero(dateData.getHours() % 12), 'm{2}': (dateData: DateData) => DayTs._paddingZero(dateData.getMinutes()), 's{2}': (dateData: DateData) => DayTs._paddingZero(dateData.getSeconds()), - 'S{2}': (dateData: DateData) => DayTs._paddingZero(dateData.getMilliseconds() / 10 | 0), // 2-digit milliseconds 'S{3}': (dateData: DateData) => DayTs._paddingZero(dateData.getMilliseconds(), 3), // 添加毫秒支持 + 'S{2}': (dateData: DateData) => DayTs._paddingZero(dateData.getMilliseconds() / 10 | 0), // 2-digit milliseconds 'M': (dateData: DateData) => dateData.getMonth() + 1, 'd': (dateData: DateData) => dateData.getDate(), 'H': (dateData: DateData) => dateData.getHours(), diff --git a/entry/src/main/ets/utils/DbSql.ets b/entry/src/main/ets/utils/DbSql.ets index 73768dd..c727f77 100644 --- a/entry/src/main/ets/utils/DbSql.ets +++ b/entry/src/main/ets/utils/DbSql.ets @@ -15,8 +15,20 @@ export enum ColumnType { } class DbUtils { + private static instance: DbUtils | null = null; rdbStore: relationalStore.RdbStore | undefined = undefined + private constructor() { + console.log(DbTag, "DbUtils instance created."); + } + + public static getInstance(): DbUtils { + if (!DbUtils.instance) { + DbUtils.instance = new DbUtils(); + } + return DbUtils.instance; + } + // 初始化 无需记录日志 init(context: common.UIAbilityContext) { let config: relationalStore.StoreConfig = { @@ -27,6 +39,7 @@ class DbUtils { relationalStore.getRdbStore(context, config) .then(rdbStore => { this.rdbStore = rdbStore + console.log(DbTag, "rdbStore:", JSON.stringify(rdbStore)) console.log(DbTag, "db rdbStore init success") resolve() }) @@ -60,6 +73,7 @@ class DbUtils { clearTable(tableName: string): Promise { let sql = `DELETE FROM ${tableName}` return new Promise((resolve, reject) => { + console.log(DbTag, "sql clearTable", JSON.stringify(this.rdbStore)) if (this.rdbStore) { this.rdbStore?.executeSql(sql).then(() => { console.log(DbTag, "sql clearTable success", sql) @@ -242,6 +256,7 @@ class DbUtils { } } -let DB: DbUtils = new DbUtils() +// let DB: DbUtils = new DbUtils() +const DB: DbUtils = DbUtils.getInstance(); export default DB diff --git a/entry/src/main/ets/utils/LogWorker.ets b/entry/src/main/ets/utils/LogWorker.ets index f09908e..28c95a1 100644 --- a/entry/src/main/ets/utils/LogWorker.ets +++ b/entry/src/main/ets/utils/LogWorker.ets @@ -1,10 +1,10 @@ // 日志向外暴露的方法 import worker from '@ohos.worker'; -import { GlobalConfig } from '../config'; +import { GlobalConfig, LogTag } from '../config'; import { LogWorkerMessage, ProcessDataEnumType, WorkerMessageType } from '../model/index'; import dayTs from './Date'; -const MAX_MESSAGE_LENGTH = 300; +const MAX_MESSAGE_LENGTH = 400; const LOG_CHUNK_PREFIX = '[切割消息序号'; class logWorker { @@ -13,7 +13,7 @@ class logWorker { public currentExamCatalog: string = "" private workerInstance: worker.ThreadWorker | null = null; // 是否开启日志 1开启 - private isLogEnabled: string = "0"; + private isLogEnabled: string = "1"; constructor() { if (logWorker.instance) { @@ -37,6 +37,11 @@ class logWorker { this.logWithLevel('info', ...args); } + // 低优先级日志 + low(...args: ESObject[]) { + this.logWithLevel('low', ...args); + } + // 调试日志 warn(msg: string) { console.warn(msg) @@ -70,6 +75,7 @@ class logWorker { // 过程数据写入 writeProcessData(type: ProcessDataEnumType, data: string) { + // dConsole.log(LogTag, "传入过程数据", data) let params: LogWorkerMessage = { type: WorkerMessageType.WriteProcessData, data, @@ -82,16 +88,15 @@ class logWorker { // 关闭过程数据写入 closeProcessData() { + dConsole.log(LogTag, "关闭过程数据1") let params: LogWorkerMessage = { type: WorkerMessageType.CloseProcessData, } - if (this.isLogEnabled === "1") { - this.workerInstance?.postMessage(JSON.stringify(params)) - } + this.workerInstance?.postMessage(JSON.stringify(params)) } // 通用日志方法 - private logWithLevel(level: 'log' | 'info' | 'error', ...args: ESObject[]): void { + private logWithLevel(level: 'log' | 'info' | 'error' | 'low', ...args: ESObject[]): void { // console.log("当前环境查看", this.isLogEnabled, "日志级别:", level) if (this.isLogEnabled === "1") { const message = this.formatMessage(...args); @@ -104,7 +109,7 @@ class logWorker { } // 日志输出到控制台 - private logConsole(level: 'log' | 'info' | 'error', msg: string) { + private logConsole(level: 'log' | 'info' | 'error' | 'low', msg: string) { switch (level) { case 'log': console.log(msg); @@ -115,11 +120,14 @@ class logWorker { case 'error': console.error(msg); break; + case 'low': + console.log(msg); + break; } } // 处理长消息分割和记录 - private logLongMessage(level: 'log' | 'info' | 'error', message: string): void { + private logLongMessage(level: 'log' | 'info' | 'error' | 'low', message: string): void { const chunks = this.splitLongMessage(message); const chunkId = Math.random().toString(36).substring(2, 8); // 生成简短随机ID chunks.forEach((chunk, index) => { diff --git a/entry/src/main/ets/utils/Request.ets b/entry/src/main/ets/utils/Request.ets index 775e119..a1719a3 100644 --- a/entry/src/main/ets/utils/Request.ets +++ b/entry/src/main/ets/utils/Request.ets @@ -145,7 +145,7 @@ type RequestResult = Object | object | string | CenterCodeResult export default function Request(options: RequestOption): Promise { return new Promise((resolve, reject) => { - const base: string = AppStorage.get("host") || "http://127.0.0.1" + const base: string = options.host ? options.host : AppStorage.get("host") || "http://127.0.0.1" const instance = http.createHttp() const baseURL = options.host || base console.log(RequestTag, "基础url:", baseURL) diff --git a/entry/src/main/ets/utils/SerialPort.ets b/entry/src/main/ets/utils/SerialPort.ets index 5b972aa..c137f82 100644 --- a/entry/src/main/ets/utils/SerialPort.ets +++ b/entry/src/main/ets/utils/SerialPort.ets @@ -1,14 +1,14 @@ -import testNapi from '@ohos.hiserialsdk'; import HiSerialSDK from '@ohos.hiserialsdk'; import { SerialPortTag } from '../config'; -// 打开串口工具 -/* - * @param serialPort 串口名称 + +/** + * 打开串口工具 + * @param serialPort 串口名称 */ export const OpenSerialPort = (serialPort: string) => { return new Promise((resolve, reject) => { - testNapi.SerialOpenAsync(serialPort, (value: number) => { + HiSerialSDK.SerialOpenAsync(serialPort, (value: number) => { if (value === -1) { console.error(SerialPortTag, "打开串口失败!") reject(-1) @@ -19,16 +19,17 @@ export const OpenSerialPort = (serialPort: string) => { }) } -//初始化串口数据 -/* - * @param fd 串口文件描述符 - * @param speed 波特率 - * @returns Promise 成功返回true,失败返回false + +/** + * 初始化串口数据 + * @param fd 串口文件描述符 + * @param speed 波特率 + * @returns Promise 成功返回true,失败返回false */ export const InitSerialPortData = async (fd: number, speed: number) => { return new Promise((resolve, reject) => { - testNapi.SerialSetAsync(fd, speed, 0, 8, 1, 0x4e, (value: number) => { + HiSerialSDK.SerialSetAsync(fd, speed, 0, 8, 1, 0x4e, (value: number) => { // 0 成功 -1失败 if (value === 0) { console.log(SerialPortTag, "初始化成功!") @@ -42,16 +43,17 @@ export const InitSerialPortData = }) } -//发送数据 -/* - * @param fd 串口文件描述符 - * @param data 要发送的数据数组 - * @returns Promise 成功返回发送的字节数,失败返回-1 +/** + * 发送数据 + * @param fd 串口文件描述符 + * @param data 要发送的数据数组 + * @returns Promise 成功返回发送的字节数,失败返回-1 */ export const SendSerialPortData = (fd: number, data: number[]) => { // console.log(SerialPortTag, "wzj-----发送数据") return new Promise((resolve, reject) => { - testNapi.SerialSendAsync(fd, data, (value: number) => { + HiSerialSDK.SerialSendAsync(fd, data, (value: number) => { + // console.log(SerialPortTag, "发送数据完成!") if (value === -1) { console.error(SerialPortTag, "发送失败!") reject(-1) @@ -61,16 +63,16 @@ export const SendSerialPortData = (fd: number, data: number[]) => { }) } -// 接受数据 -/* - * @param fd 串口文件描述符 - * @param timeout 超时时间,单位毫秒 - * @returns Promise 成功返回接收到的数据,失败返回-1 +/** + * 接受数据 + * @param fd 串口文件描述符 + * @param timeout 超时时间,单位毫秒 + * @returns Promise 成功返回接收到的数据,失败返回-1 */ export const ReceiveSerialPortData = (fd: number, timeout: number,) => { // console.log(SerialPortTag, "wzj-----接受数据") return new Promise((resolve) => { - testNapi.SerialRecvAsync(fd, timeout, (value: HiSerialSDK.receiveInfo) => { + HiSerialSDK.SerialRecvAsync(fd, timeout, (value: HiSerialSDK.receiveInfo) => { resolve(value) }) }) @@ -78,13 +80,13 @@ export const ReceiveSerialPortData = (fd: number, timeout: number,) => { // 主动接受数据 export const ReceiveSerialPortDataBySelf = (fd: number, callback: Function) => { - testNapi.SerialListenCallbackSet(fd, callback) + HiSerialSDK.SerialListenCallbackSet(fd, callback) } // 取消主动接受 export const CancelReceiveSerialPortData = async (fd: number) => { return new Promise((resolve, reject) => { - let result: number = testNapi.SerialListenCallbackCancel(fd) + let result: number = HiSerialSDK.SerialListenCallbackCancel(fd) if (result === 0) { resolve(true) } else { diff --git a/entry/src/main/ets/utils/UdpUtils.ets b/entry/src/main/ets/utils/UdpUtils.ets index e06b934..04080e7 100644 --- a/entry/src/main/ets/utils/UdpUtils.ets +++ b/entry/src/main/ets/utils/UdpUtils.ets @@ -1,20 +1,20 @@ import socket from '@ohos.net.socket' import { UDPTag } from '../config' -import { FillZero, StringToASCII } from './Common' +import { FillZero } from './Common' import { BusinessError } from '@ohos.base' +import { dConsole } from './LogWorker' -interface MsgExt { +export interface MsgExt { id: number, list: number[], carNo: string, placeId: string, } -function generateHead(param: MsgExt): number[] { - let lshNo = AppStorage.get("lsh") - let a = new Uint16Array(StringToASCII(`${param.id}${FillZero(param.placeId, 3)}`)) - let b = new Uint32Array(StringToASCII(`${FillZero(param.carNo, 4)}${lshNo}`)) - let c = new Uint16Array(param.list.length) +function generateHead(param: MsgExt, lsh: number): number[] { + let a = new Uint8Array(new Uint16Array([Number(`${param.id}${FillZero(param.placeId, 3)}`)]).buffer) + let b = new Uint8Array(new Uint32Array([Number(`${FillZero(param.carNo, 4)}${FillZero(lsh, 6)}`)]).buffer) + let c = new Uint8Array(new Uint16Array([param.list.length]).buffer) return [...a, ...b, ...c]; } @@ -28,7 +28,6 @@ function exclusive(target: number[]): number[] { type DealMethod = (value: ArrayBuffer) => T - export default class UdpClient { protected udp: socket.UDPSocket | null = null private localIp: string = '' @@ -81,27 +80,31 @@ export default class UdpClient { address: { address: this.oppositeIp, port: parseInt(this.oppositeIpPort), family: 1 } - }).then(res => { - console.log(UDPTag, "udp发送成功", JSON.stringify(res)) + }).then(() => { + // console.log(UDPTag, "udp发送成功") }).catch((e: BusinessError) => { console.error(UDPTag, "udp发送失败", JSON.stringify(e)) }) } // 组装消息 - setWholeMsg(params: MsgExt): ArrayBuffer { - let head = generateHead(params); - let headJudge = exclusive(head); - let body = params.list; - let bodyJudge = exclusive(body); - let end = [13, 10]; - const arr = [...head, ...headJudge, ...body, ...bodyJudge, ...end] - return new Uint8Array(arr).buffer + setWholeMsg(params: MsgExt, lsh: number): ArrayBuffer { + try { + let head = generateHead(params, lsh); + let headJudge = exclusive(head); + let body = params.list; + let bodyJudge = exclusive(body); + let end = [13, 10]; + const arr = [...head, ...headJudge, ...body, ...bodyJudge, ...end] + return new Uint8Array(arr).buffer + } catch (e) { + return new Uint8Array([]).buffer + } } // 发送消息 - sendMsgExt(param: MsgExt) { - const msgData = this.setWholeMsg(param) + sendMsgExt(param: MsgExt, lsh: number) { + const msgData = this.setWholeMsg(param, lsh) this.sendMsg(msgData) } @@ -144,7 +147,7 @@ export default class UdpClient { private bindEvent() { this.udp?.on("message", value => { let result = this.dealMethod?.(value.message) - console.log(UDPTag, "udp获取消息", result) + // console.log(UDPTag, "udp获取消息", result) this.messageEvents.forEach(cb => { cb(result) }) diff --git a/entry/src/main/ets/utils/business/CenterUdpBusiness.ets b/entry/src/main/ets/utils/business/CenterUdpBusiness.ets index 9bbd132..2d50e78 100644 --- a/entry/src/main/ets/utils/business/CenterUdpBusiness.ets +++ b/entry/src/main/ets/utils/business/CenterUdpBusiness.ets @@ -1,15 +1,9 @@ // 中心心跳/发送消息 -import { - CarInfoType, - CenterCallBackMsgType, - EnvironmentConfigurationType, - OtherMessageType, - UDPParamType -} from '../../model'; -import { ArrayToByteArray, FillZero, NumberToByteArray } from '../Common'; -import UdpClient from '../UdpUtils'; +import { CarInfoType, CenterCallBackMsgType, EnvironmentConfigurationType, ExamData, } from '../../model'; +import { FillZero, NumberToByteArray } from '../Common'; +import UdpClient, { MsgExt } from '../UdpUtils'; import { CenterUdpTag, UDPTag } from '../../config'; -import { SerialNumberInstance } from '../SerialNumber'; + // 中心UDP业务逻辑 class CenterUDPBusiness { @@ -33,42 +27,35 @@ class CenterUDPBusiness { return CenterUDPBusiness.instance } - sendData(data: UDPParamType) { - this.sendId = data.id - const param = this.setWholeMsg(data) - this.udp.sendMsg(param); + startHeartBeat(lsh: number) { + const arr = [this.signNum || 0, this.statue || 1] + let tmpList: number[] = []; + tmpList.push(NumberToByteArray(Number(arr[0]), 1 * 8)[0]) + tmpList.push(NumberToByteArray(Number(arr[1]), 1 * 8)[0]) + + // 学员流水号 + const str = this.lsh || '0000000000000' + for (let i = 0; i < str.length; i++) { + tmpList.push(NumberToByteArray(str.charCodeAt(i), 1 * 8)[0]) + } + const data: MsgExt = { + id: 31, + list: tmpList, + carNo: this.carInfo.carNo!, + placeId: this.carInfo.examinationRoomId! + } + // dConsole.info(Tag, "发送中心数据", data) + this.udp.sendMsgExt(data, lsh); } - startHeartBeat() { - console.log(CenterUdpTag, "心跳", JSON.stringify(this.carInfo)) - // 组装消息,一秒发送一次 - this.timer = setInterval(() => { - // 生成流水号 - SerialNumberInstance.generate() - // console.log(CenterUdpTag, "流水号生成") - // SetSerialNumber() - const arr = [this.signNum || 0, this.statue || 1] - let tmpList: number[] = []; - tmpList.push(NumberToByteArray(Number(arr[0]), 1 * 8)[0]) - tmpList.push(NumberToByteArray(Number(arr[1]), 1 * 8)[0]) - - // 学员流水号 - const str = this.lsh || '0000000000000' - for (let i = 0; i < str.length; i++) { - tmpList.push(NumberToByteArray(str.charCodeAt(i), 1 * 8)[0]) - } - // console.log(CenterUdpTag, "学员流水号", JSON.stringify(tmpList)) - const data: UDPParamType = { - id: 31, - list: tmpList, - carNo: this.carInfo.carNo!, - placeId: this.carInfo.examinationRoomId! - } - // console.log(CenterUdpTag, "查看生成的", JSON.stringify(data)) - const param = this.setWholeMsg(data) - // console.log(CenterUdpTag, "查看", JSON.stringify(param)) - this.udp.sendMsg(param); - }, 1000); + sendMsgExt(id: number, body: number[], lsh: number) { + // dConsole.info("中心udp", id, body, lsh) + this.udp.sendMsgExt({ + id: id, + list: body, + carNo: this.carInfo.carNo!, + placeId: this.carInfo!.examinationRoomId!, + }, lsh) } onMsg(cb: (param: CenterCallBackMsgType) => void) { @@ -79,14 +66,14 @@ class CenterUDPBusiness { this.udp.offMsg(cb) } - changeKeyValue(value: OtherMessageType) { + changeKeyValue(value: ExamData) { value.signNum && (this.signNum = value.signNum) value.lsh && (this.lsh = value.lsh) value.statue && (this.statue = value.statue) } // 初始化 - async init(config: EnvironmentConfigurationType, carInfo: CarInfoType, otherMessage: OtherMessageType) { + async init(config: EnvironmentConfigurationType, carInfo: CarInfoType, otherMessage: ExamData) { console.log(CenterUdpTag, "初始化", JSON.stringify(otherMessage), JSON.stringify(carInfo)) try { this.signNum = otherMessage.signNum || 0 @@ -94,10 +81,9 @@ class CenterUDPBusiness { this.lsh = otherMessage.lsh || '0000000000000' this.carInfo = carInfo // TODO - // this.udp.create(config.udplocalIp!, '8800', carInfo.udpAddress!, carInfo.messagePort!) - this.udp.create(config.udplocalIp!, '8800', "112.80.35.83", "11056") - + this.udp.create(config.udplocalIp!, "8800", carInfo.udpAddress!, carInfo.messagePort!) this.udp.setDealMethod(this.dealMsg) + this.udp.bindUdp() } catch (e) { console.error(UDPTag, "初始化中心 udp失败") } @@ -109,7 +95,7 @@ class CenterUDPBusiness { return this.udp.close() } - private dealMsg(msg: ArrayBuffer): CenterCallBackMsgType { + private dealMsg = (msg: ArrayBuffer): CenterCallBackMsgType => { let arr: number[] = [] let dataView = new DataView(msg) for (let i = 0; i < dataView?.byteLength; ++i) { @@ -128,41 +114,6 @@ class CenterUDPBusiness { sendId: this.sendId } } - - private setWholeMsg(params: UDPParamType) { - let head: Array = this.setMsgHead(params); - let headJudge = this.setMessageExclusive(head); - let bodyJudge = this.setMessageExclusive(params.list); - let end = [13, 10]; - const arr: number[] = [] - head.forEach(item => arr.push(item)) - headJudge.forEach(item => arr.push(item)) - params.list?.forEach(item => arr.push(item)) - bodyJudge.forEach(item => arr.push(item)) - end.forEach(item => arr.push(item)) - return ArrayToByteArray(arr).buffer - } - - private setMsgHead(params: UDPParamType) { - // 自增流水号 - const lshNo = SerialNumberInstance.get() - let a = NumberToByteArray(Number(`${params.id}${FillZero(params.placeId, 3)}`), 2 * 8); - let b = NumberToByteArray(Number(`${FillZero(params.carNo, 4)}${lshNo}`), 4 * 8); - let c = NumberToByteArray(params.list.length, 2 * 8); - let result: number[] = [] - a?.forEach(item => result.push(item)) - b?.forEach(item => result.push(item)) - c?.forEach(item => result.push(item)) - return result; - } - - private setMessageExclusive(tmpList: Array) { - let result: number = tmpList[0]; - for (let i = 1; i < tmpList.length; i++) { - result = result ^ tmpList[i] - } - return [result]; - } } export const CenterUDPBusinessInstance = new CenterUDPBusiness(); \ No newline at end of file diff --git a/entry/src/main/ets/utils/business/DifferentialAndSignalWorker.ets b/entry/src/main/ets/utils/business/DifferentialAndSignalWorker.ets index de8b6fd..70309cc 100644 --- a/entry/src/main/ets/utils/business/DifferentialAndSignalWorker.ets +++ b/entry/src/main/ets/utils/business/DifferentialAndSignalWorker.ets @@ -1,18 +1,14 @@ // 拉起Worker处理tcp信息以及接受后置机UDP信息 import worker, { MessageEvents } from '@ohos.worker'; import { WorkerTag } from '../../config'; -import { CarInfoType, EnvironmentConfigurationType, WorkerMessage } from '../../model'; +import { CarInfoType, EnvironmentConfigurationType, WorkerMessage, WorkerMessageDataType } from '../../model'; class differentialAndSignal { private workerInstance = new worker.ThreadWorker("entry/ets/workers/DifferentialCorrection.ets") private events: Array = [] - constructor() { - } - // 初始化Worker init() { - this.workerInstance = new worker.ThreadWorker("entry/ets/workers/DifferentialCorrection.ets"); let config: EnvironmentConfigurationType = AppStorage.get("EnvironmentConfiguration") || { tcplocalIp: "", @@ -26,17 +22,43 @@ class differentialAndSignal { const lsh = AppStorage.get('lsh') const singlePlay = AppStorage.get("singlePlay") const data: WorkerMessage = { - config: config, - carInfo: carInfo, - otherMessage: { + type: WorkerMessageDataType.Init, + data: { + config: config, + carInfo: carInfo, signNum: signNum || 0, statue: statue || "", - lsh: lsh || "" - }, - singlePlay: singlePlay || false + lsh: lsh || "", + singlePlay: singlePlay || false + } } this.workerInstance.postMessage(JSON.stringify(data)) this.getMessage() + setInterval(() => { + this.setUDPStatus() + }, 1000) + } + + setUDPStatus() { + let signNum: number = AppStorage.get("signNum")! || 0 + let statue: number = AppStorage.get("statue")! || 1 + let lsh: string = AppStorage.get("lsh")! + + let body: number [] = [...new Uint8Array([signNum]), ...new Uint8Array([statue])] + for (let i = 0; i < lsh.length; i++) { + body.push(...new Uint8Array([lsh.charCodeAt(i)])) + } + this.sendMsg({ + type: WorkerMessageDataType.CenterSend, + data: { + id: 31, + body: body, + } + }) + } + + sendMsg(msg: WorkerMessage) { + this.workerInstance.postMessage(JSON.stringify(msg)) } // 添加监听 @@ -72,8 +94,7 @@ class differentialAndSignal { getMessage() { this.workerInstance.onmessage = (e: MessageEvents): void => { if (e.data) { - console.log(WorkerTag, "Worker 收到消息: " + e.data); - console.log(WorkerTag, "Worker 目前监听数量: " + this.events.length.toString()); + // console.log(WorkerTag, "Worker 收到消息: " + e.data); this.events.forEach((callback) => { callback(e.data); }); diff --git a/entry/src/main/ets/utils/business/DifferentialSignal.ets b/entry/src/main/ets/utils/business/DifferentialSignal.ets index e905e2c..5576c3f 100644 --- a/entry/src/main/ets/utils/business/DifferentialSignal.ets +++ b/entry/src/main/ets/utils/business/DifferentialSignal.ets @@ -1,6 +1,7 @@ //差分信号 import { TCPTag } from '../../config'; import { EnvironmentConfigurationType } from '../../model'; +import { dConsole } from '../LogWorker'; import TcpClient from '../TcpUtils'; class differentialSignal { @@ -16,7 +17,7 @@ class differentialSignal { console.error(TCPTag, "TCP发生错误") this.differentialSignalTcp.reBind() }) - console.log(TCPTag, "初始化", JSON.stringify(config)) + dConsole.low(TCPTag, "初始化", JSON.stringify(config)) if (config.tcplocalIp || config.tcplocalIpPort || config.tcpOppositeIp || config.tcpOppositePort) { this.differentialSignalTcp.init(config.tcplocalIp || "", config.tcplocalIpPort || "", config.tcpOppositeIp || "", config.tcpOppositePort || ""); @@ -30,7 +31,7 @@ class differentialSignal { // 组装消息,一秒发送五次 let data = "1"; this.timer = setInterval(() => { - console.log(TCPTag, "发送给中心消息") + // dConsole.low(TCPTag, "发送给中心消息") this.differentialSignalTcp.sendMsg(data); }, 200); @@ -39,7 +40,7 @@ class differentialSignal { // 获取消息 getData(callback: (data: ArrayBuffer) => void) { this.differentialSignalTcp.onMsg((data: ArrayBuffer) => { - console.log(TCPTag, "获取TCP消息", data); + // dConsole.low(TCPTag, "获取TCP消息", data); callback(data); }); } diff --git a/entry/src/main/ets/utils/business/GetDistance.ets b/entry/src/main/ets/utils/business/GetDistance.ets index df93091..99260dc 100644 --- a/entry/src/main/ets/utils/business/GetDistance.ets +++ b/entry/src/main/ets/utils/business/GetDistance.ets @@ -10,13 +10,23 @@ export default class GetDistance { public totalTime: number public date: string public fd: number + //上传行驶里程数据 + uploadData = async () => { + // setInterval(() => { + // // const { carId } = AppStorage.get('carInfo'); + // // const { date, timeStr, totalDistance } = this; + // return + // //"carid":"1001","startTime":"2024-08-24 08:09:01","time":"111233", "mileage":"1222" + // + // }, 5000) + } //后续文件路径待替换 private fileUtil: FileUtils // 设置文件夹 public initFolder = async () => { const time = GetCurrentTime() const folderPath = await this.fileUtil.initFolder(`/车辆行驶距离统计`); - console.info('surenjun folderPath=>', folderPath); + console.info('folderPath=>', folderPath); const date = time.split(' ')[0].split('-').join('_') const timeStr = time.split(' ')[1] this.timeStr = timeStr @@ -35,7 +45,6 @@ export default class GetDistance { this.fileUtil = fileUtil; } - // 过程文件数据 public setTimeData = async (str: number) => { console.log('folderPath', this.folderPath) @@ -55,14 +64,4 @@ export default class GetDistance { // `${folderPath}/${date}.txt`,contentArr.join('\n') // ); } - //上传行驶里程数据 - uploadData = async () => { - setInterval(() => { - // const { carId } = AppStorage.get('carInfo'); - // const { date, timeStr, totalDistance } = this; - return - //"carid":"1001","startTime":"2024-08-24 08:09:01","time":"111233", "mileage":"1222" - - }, 5000) - } } diff --git a/entry/src/main/ets/utils/business/JudgeUdpBusiness.ets b/entry/src/main/ets/utils/business/JudgeUdpBusiness.ets index 510828d..460f8cd 100644 --- a/entry/src/main/ets/utils/business/JudgeUdpBusiness.ets +++ b/entry/src/main/ets/utils/business/JudgeUdpBusiness.ets @@ -1,7 +1,11 @@ import { CarInfoType, + CDSBInfo, EnvironmentConfigurationType, Gps, + JudgePerformInfo, + JudgeUDPData, + KmItem, PLCDataType, ProjectDataType, ProjectItemType, @@ -9,28 +13,30 @@ import { UDPParamType } from '../../model'; -import { JudgeConfig } from '../../config'; +import { JudgeConfig, JudgeTag } from '../../config'; import { FillZero, NumberToByteArray, StringToASCII } from '../Common'; -import UdpClient from '../UdpUtils'; -import { CenterUDPBusinessInstance } from './CenterUdpBusiness'; -import { ObtainUdpBusinessInstance } from './ObtainUdpBusiness'; +import UdpClient, { MsgExt } from '../UdpUtils'; import systemTime from '@ohos.systemDateTime'; import { SerialNumberInstance } from '../SerialNumber'; -import { GetDwStatusType, GetTranslateSignals } from '../../pages/Judge/utils'; +import { GetCenterProjectStatus, GetDwStatusType, GetTranslateSignals } from '../../pages/Judge/utils'; import { testKm2Items, testKm3Items } from '../../mock'; +import { dConsole } from '../LogWorker'; +import { CenterUDPBusinessInstance } from './CenterUdpBusiness'; -// import { examCalcGpsDistance } from '../../pages/Judge/JudgeUtils'; +const Tag = "JudgeUdpBusiness" class JudgeUdpBusiness { private static instance: JudgeUdpBusiness - public udpIndex = 0; + public business: JudgeUDPData | null = null + public performInfo: JudgePerformInfo | null = null + public isUDPEnd: boolean = false + public isExamEnd: boolean = false private udp: UdpClient = new UdpClient() - private currentUdpIndex = 0; private carInfo: CarInfoType = {} private singlePlay: boolean = false private lsh: string = "" - private serialIndex: number = 0 + private serialIndex: number = 1 constructor() { if (!JudgeUdpBusiness.instance) { @@ -39,29 +45,139 @@ class JudgeUdpBusiness { return JudgeUdpBusiness.instance } - async getMessageHeartbeat(msg: string): Promise { + async getMessageHeartbeat(msg: string, gps2?: string): Promise { + if (!this.business || !this.performInfo) { + return this.getOBDMessageHeart(msg) + } let gpsDigit = JudgeConfig.fourInOneScreen.gpsDigit const asclshArr = StringToASCII(FillZero( this.singlePlay - ? '1111111111111' + ? '0000000000000' : this.lsh, 13)); - const ascksyhArr = StringToASCII(this.carInfo.examSubject === '2' ? '0000000000000' : '1111111111111') - const ascsbxhArr = StringToASCII('00000000') - // const serialIndex = AppStorage.get("serialIndex")! + const ascksyhArr = StringToASCII('0000000000000') + const ascsbxhArr = StringToASCII(this.getSbxh(this.business.xmdm, this.business.xmxh)) const plcData = await this.getPlcData(msg); - let param: number[] = Object.entries(plcData.sensor) - .filter((item: [string, number]) => { - let keys = - ["zfxd", "yfxd", "shtd", "ygd", "jgd", "skd", "dh1", "dh2", "lhq", "jsc", "ssc", "fsc", "lb", "mkg", "aqd"] - return keys.indexOf(item[0]) - }) - .map((item: [string, number]) => item[1]) + let plc2Data: PLCDataType | undefined = undefined; + try { + plc2Data = await this.getPlcData(gps2 || "") + } catch (e) { + console.log(JSON.stringify(e)) + } + let param: number[] = [plcData.sensor.zfxd, plcData.sensor.yfxd, plcData.sensor.shtd, plcData.sensor.ygd, plcData.sensor.jgd, plcData.sensor.skd, plcData.sensor.dh1, plcData.sensor.dh2, plcData.sensor.lhq, plcData.sensor.jsc, plcData.sensor.ssc, plcData.sensor.fsc, plcData.sensor.lb, plcData.sensor.mkg, plcData.sensor.aqd] .concat(GetDwStatusType(plcData.sensor.dw)) .concat([0, 0, plcData.sensor.ygq, plcData.sensor.wd, 0]) const translateSignals = GetTranslateSignals(param) - const translateProject = this.getTranslateProject(); + const translateProject = this.getTranslateProject(1); + const translateJd = Number(this.convertGpsCoord2(plcData.gps.wd).toFixed(gpsDigit)) * Math.pow(10, gpsDigit); + const translateWd = Number(this.convertGpsCoord2(plcData.gps.jd).toFixed(gpsDigit)) * Math.pow(10, gpsDigit) + let translateGps2Jd: number = 0 + let translateGps2Wd: number = 0 + if (gps2) { + translateGps2Jd = Number(this.convertGpsCoord2(plc2Data!.gps.wd).toFixed(gpsDigit)) * Math.pow(10, gpsDigit); + translateGps2Wd = Number(this.convertGpsCoord2(plc2Data!.gps.jd).toFixed(gpsDigit)) * Math.pow(10, gpsDigit) + } + + const translateProjects = translateProject.map(numStr => NumberToByteArray(parseInt(numStr, 2), 8)[0]) + let tempSd = Number((plcData.gps.sd * 1.852).toFixed(0)) + if (tempSd < 1) { + tempSd = 0 + } + let fyj = Number(plcData.gps.fyj.toFixed(2)) + fyj = Math.floor(fyj > 0 ? (fyj * 100) : (fyj * 100 + 65536)) + + const arr: number[][] = [ + //考生号 + asclshArr.map(lsh => NumberToByteArray(lsh, 8)[0]), + //考试员号 + ascksyhArr.map(ksyh => NumberToByteArray(ksyh, 8)[0]), + //科目类型(0:未考试 1:科目二 2:科目三) + 考试开始时间 + NumberToByteArray(`${this.carInfo.examSubject}${this.business.startTime}`, 4 * 8), + // 消息序号 + NumberToByteArray(this.isExamEnd ? 0 : this.serialIndex, 2 * 8), + translateSignals, + NumberToByteArray(tempSd * 100, 2 * 8), + NumberToByteArray(plcData.sensor.fdjzs / 100, 8), + NumberToByteArray(translateJd, 4 * 8), + NumberToByteArray(translateWd, 4 * 8), + NumberToByteArray(1, 8), + //GPS东向距离 + NumberToByteArray(this.performInfo.dxjl! < 0 ? this.performInfo.dxjl! + 4294967296 : this.performInfo.dxjl!, 4 * 8), + //GPS北向距离 + NumberToByteArray(this.performInfo.bxjl! < 0 ? this.performInfo.bxjl! + 4294967296 : this.performInfo.bxjl!, 4 * 8), + //航向角 + NumberToByteArray(plcData.gps.hxj * 100, 2 * 8), + //俯仰角 + NumberToByteArray(fyj, 2 * 8), + // 高程(海拔) + NumberToByteArray(plcData.gps.hbg * 100, 4 * 8), + //dddd + translateProjects, + //当前项目编号 + NumberToByteArray(this.business.xmmcSingleCode, 8), + //场地设备编号 + ascsbxhArr.map(sbxh => NumberToByteArray(sbxh, 8)[0]), + //本次考试行驶距离 + NumberToByteArray(Math.floor(this.performInfo.dcjl! + this.performInfo.qjjl!) / 100, 2 * 8), + //扣分值 + NumberToByteArray(100 - Math.abs(this.business.totalScore < 0 ? 0 : this.business.totalScore), 2 * 8), + //扣分数量 + NumberToByteArray(this.business.kfArr.length, 8), + //n个扣分序号 + this.business.kfArr.map(kf => NumberToByteArray(kf.kfxh!, 8)[0]), + + + //牵引车第二gps精度、纬度 + NumberToByteArray(translateGps2Jd, 4 * 8), + NumberToByteArray(translateGps2Wd, 4 * 8), + //牵引车第二航向角 + NumberToByteArray(plc2Data?.gps?.hxj || 0, 2 * 8), + //摩托压线 Byte[20], + NumberToByteArray(0, 20 * 8), + //考试用时 + NumberToByteArray(this.business.examTime, 4 * 8), + //项目用时 + NumberToByteArray(FillZero(0, 2), 2 * 8), + //设备信号状态 + NumberToByteArray(0, 4 * 8), + ] + let result: number[] = []; + arr.forEach(itemArr => { + result = result.concat(itemArr) + }) + if (this.isExamEnd) { + this.serialIndex = 1 + this.business = null + this.performInfo = null + this.isExamEnd = false + } else { + this.serialIndex += 1 + } + return [...new Uint8Array(result)] + } + + send(data: UDPParamType) { + const param = this.setWholeMsg(data) + this.udp.sendMsg(param); + } + + async getOBDMessageHeart(msg: string): Promise { + let gpsDigit = JudgeConfig.fourInOneScreen.gpsDigit + const asclshArr = StringToASCII(FillZero( + this.singlePlay + ? '0000000000000' + : this.lsh, + 13)); + const ascksyhArr = StringToASCII('0000000000000') + const ascsbxhArr = StringToASCII('00000000') + + const plcData = await this.getPlcData(msg); + let param: number[] = [plcData.sensor.zfxd, plcData.sensor.yfxd, plcData.sensor.shtd, plcData.sensor.ygd, plcData.sensor.jgd, plcData.sensor.skd, plcData.sensor.dh1, plcData.sensor.dh2, plcData.sensor.lhq, plcData.sensor.jsc, plcData.sensor.ssc, plcData.sensor.fsc, plcData.sensor.lb, plcData.sensor.mkg, plcData.sensor.aqd] + .concat(GetDwStatusType(plcData.sensor.dw)) + .concat([0, 0, plcData.sensor.ygq, plcData.sensor.wd, 0]) + const translateSignals = GetTranslateSignals(param) + const translateProject = this.getTranslateProject(0); const translateJd = Number(this.convertGpsCoord2(plcData.gps.wd).toFixed(gpsDigit)) * Math.pow(10, gpsDigit); const translateWd = Number(this.convertGpsCoord2(plcData.gps.jd).toFixed(gpsDigit)) * Math.pow(10, gpsDigit) const translateProjects = translateProject.map(numStr => NumberToByteArray(parseInt(numStr, 2), 8)[0]) @@ -69,6 +185,9 @@ class JudgeUdpBusiness { if (tempSd < 1) { tempSd = 0 } + let fyj = Number(plcData.gps.fyj.toFixed(2)) + fyj = Math.floor(fyj > 0 ? (fyj * 100) : (fyj * 100 + 65536)) + const arr: number[][] = [ //考生号 asclshArr.map(lsh => NumberToByteArray(lsh, 8)[0]), @@ -77,7 +196,7 @@ class JudgeUdpBusiness { //科目类型(0:未考试 1:科目二 2:科目三) + 考试开始时间 NumberToByteArray(`${0}${'00:00:000'}`, 4 * 8), // 消息序号 - NumberToByteArray(this.serialIndex, 2 * 8), + NumberToByteArray(0, 2 * 8), translateSignals, NumberToByteArray(tempSd * 100, 2 * 8), NumberToByteArray(plcData.sensor.fdjzs / 100, 8), @@ -90,7 +209,7 @@ class JudgeUdpBusiness { //航向角 NumberToByteArray(plcData.gps.hxj * 100, 2 * 8), //俯仰角 - NumberToByteArray(plcData.gps.fyj * 100, 2 * 8), + NumberToByteArray(fyj, 2 * 8), // 高程(海拔) NumberToByteArray(plcData.gps.hbg * 100, 4 * 8), //dddd @@ -103,13 +222,10 @@ class JudgeUdpBusiness { NumberToByteArray(0, 2 * 8), //扣分值 NumberToByteArray(0, 2 * 8), - //扣分数 + //扣分数量 NumberToByteArray(0, 2 * 8), - //扣分项数量 - NumberToByteArray(0, 8), //n个扣分序号 - // [].map(kf => string2Bytes(kf.markcatalog, 8)), - [], + NumberToByteArray(0, 8), //牵引车第二gps精度、纬度 NumberToByteArray(0, 4 * 8), NumberToByteArray(0, 4 * 8), //牵引车第二航向角 @@ -127,126 +243,93 @@ class JudgeUdpBusiness { arr.forEach(itemArr => { result = result.concat(itemArr) }) - // AppStorage.setOrCreate("serialIndex", 0) - this.serialIndex = 0 return [...new Uint8Array(result)] } - send(data: UDPParamType) { - const param = this.setWholeMsg(data) - this.udp.sendMsg(param); + sendData(bytes: number[], udpLsh: number) { + let data: MsgExt = { + id: 45, + list: bytes, + carNo: this.carInfo.carNo!, + placeId: this.carInfo!.examinationRoomId!, + } + // dConsole.info(Tag, "发送小红球数据", data) + this.udp.sendMsgExt(data, udpLsh) } - sendData(bytes: number[]) { - if (this.udpIndex > this.currentUdpIndex) { - this.udp.sendMsgExt({ - id: 45, - list: bytes, - carNo: this.carInfo.carNo!, - placeId: this.carInfo.examinationRoomId! - }) - this.currentUdpIndex = this.udpIndex - } + sendMsgExt(id: number, body: number[], lsh: number) { + this.udp.sendMsgExt({ + id: id, + list: body, + carNo: this.carInfo.carNo!, + placeId: this.carInfo!.examinationRoomId!, + }, lsh) } //申请远程扣分查询 - askKf(directives: number) { - CenterUDPBusinessInstance.sendData({ - id: 35, - list: [directives], - carNo: this.carInfo.carNo!, - placeId: this.carInfo.examinationRoomId!, - }) + askKf(directives: number, lsh: number) { + // TODO + CenterUDPBusinessInstance.sendMsgExt(35, [directives], lsh) console.info('surenjun', `考车查询扣分项目内容,请求指令为:${directives}`) } + askStopExam(directives: number, lsh: number) { + CenterUDPBusinessInstance.sendMsgExt(38, [directives], lsh) + dConsole.info('surenjun', `考车查询扣分项目内容,请求指令为:${directives}`) + } + + confirmStopExam(directives: number, lsh: number) { + CenterUDPBusinessInstance.sendMsgExt(40, [directives, 1], lsh) + dConsole.info('surenjun', '确定远程终止考试 directives=》' + directives) + } + //确定远程扣分 - confirmKf(directives: number, code: number) { - CenterUDPBusinessInstance.sendData({ - id: 37, - list: [directives, code], - carNo: this.carInfo.carNo!, - placeId: this.carInfo.examinationRoomId! - }) + confirmKf(directives: number, code: number, lsh: number) { + // TODO + CenterUDPBusinessInstance.sendMsgExt(37, [directives, code], lsh) console.info('surenjun', `考车发送确定扣分指令,指令为:${directives}`) } // 初始化 async init(config: EnvironmentConfigurationType, carInfo: CarInfoType, singlePlay: boolean, lsh: string): Promise { this.lsh = lsh - this.carInfo = carInfo + // this.carNo = carInfo.carNo! + // this.examinationRoomId = carInfo.examinationRoomId! this.singlePlay = singlePlay + this.carInfo = carInfo return new Promise((resolve, reject) => { try { + dConsole.info(JudgeTag, "udp", config.udplocalIp!, '8080', carInfo.udpAddress!, carInfo.hintPort!) this.udp.create(config.udplocalIp!, '8080', carInfo.udpAddress!, carInfo.hintPort!).then(resolve).catch(reject) - ObtainUdpBusinessInstance.onMsg(async (msg: string) => { - let prevJd = 0, preWd = 0 - - const stashArr = msg.split(',') - if (stashArr[0] != '#DN_GD') { - return - } - const udpIndex = AppStorage.get("udpIndex")!; - const isJudge = AppStorage.get("isJudge")!; - if (udpIndex % 5 === 0 && !isJudge) { - const bytes = await this.getMessageHeartbeat(msg); - const msgArr: string[] = msg.split(','); - const jd = this.convertGpsCoord2(Number(msgArr[96])); - const wd = this.convertGpsCoord2(Number(msgArr[95]) || 0); - this.sendData(bytes) - if (prevJd && Number(msgArr[83]) === 4) { - //TODO 解决轨迹黑屏 - // await examCalcGpsDistance({ - // jd1: prevJd, - // wd1: preWd, - // jd2: jd, - // wd2: wd, - // h: Number(msgArr[90]) || 1, - // }) - - } - prevJd = jd; - preWd = wd; - } - // AppStorage.setOrCreate("udpIndex", udpIndex + 1) - }) - setInterval(() => { - this.udpIndex += 1 - }, 1000) } catch (e) { reject(e) } }) } + setLsh(lsh?: string) { + this.lsh = lsh || this.lsh + } + + getLsh() { + return this.lsh + } + private setWholeMsg(params: UDPParamType) { let head: Array = this.setMsgHead(params); let headJudge = this.setMessageExclusive(head); let bodyJudge = this.setMessageExclusive(params.list); let end = [13, 10]; const arr: Array = [...head, ...headJudge, ...params.list, ...bodyJudge, ...end] - return this.array2Byte(arr).buffer - } - - private array2Byte(array: Array) { - const buf = new ArrayBuffer(array.length); - const view = new Uint8Array(buf); - for (let i = 0; i != array.length; ++i) { - view[i] = array[i] & 0xFF; - } - return view; + return new Uint8Array(arr).buffer } private setMsgHead(params: UDPParamType) { const lshNo = SerialNumberInstance.get() let a = NumberToByteArray(Number(`${params.id}${FillZero(params.placeId, 3)}`), 2 * 8); - let b = NumberToByteArray(Number(`${FillZero(params.carNo, 4)}${lshNo}`), 4 * 8); + let b = NumberToByteArray(Number(`${FillZero(params.carNo, 4)}${FillZero(lshNo, 6)}`), 4 * 8); let c = NumberToByteArray(params.list.length, 2 * 8); - let result: number[] = [] - a?.forEach(item => result.push(item)) - b?.forEach(item => result.push(item)) - c?.forEach(item => result.push(item)) - return result; + return [...a, ...b, ...c]; } private setMessageExclusive(tmpList: Array) { @@ -265,15 +348,24 @@ class JudgeUdpBusiness { } // 中心所有项目转换 - private getTranslateProject(): string[] { + private getTranslateProject(type: number): string[] { this.carInfo.examSubject const tempItems: ProjectItemType[] = - (this.carInfo.examSubject === '2' ? testKm2Items : testKm3Items).map((code: ProjectDataType) => { - let data: ProjectItemType = { - code, - status: '0' + (this.carInfo.examSubject === '2' ? testKm2Items : testKm3Items).map((item: ProjectDataType) => { + if (type === 1) { + const current: KmItem = Reflect.get(this.business!.kmItems, item.code)! + let data: ProjectItemType = { + code: item.code, + status: GetCenterProjectStatus(current.status) + } + return data + } else { + let data: ProjectItemType = { + code: item.code, + status: "0" + } + return data } - return data }) const arr: string[] = []; for (let i = 0; i <= 4; i++) { @@ -281,9 +373,7 @@ class JudgeUdpBusiness { let tempArr = temp.map(item => item.status) if (i === 4) { tempArr = this.carInfo.examSubject === '2' - //bit36-bit39保留 ? tempArr.concat(['00', '00']) - //bit30-bit39保留 : tempArr.concat(['00', '00', '00']) } @@ -402,6 +492,13 @@ class JudgeUdpBusiness { gps, } } + + private getSbxh(ksxm: string | number, xmxh: string) { + const projectKey = `${ksxm}_${xmxh}`; + const currentCdsb: CDSBInfo = Reflect.get(this.business!.cdsbInfoObj, projectKey); + const sbxh = currentCdsb?.sbbh || '0000000000' + return sbxh + } } diff --git a/entry/src/main/ets/utils/business/ObtainUdpBusiness.ets b/entry/src/main/ets/utils/business/ObtainUdpBusiness.ets index 16d2862..460bca1 100644 --- a/entry/src/main/ets/utils/business/ObtainUdpBusiness.ets +++ b/entry/src/main/ets/utils/business/ObtainUdpBusiness.ets @@ -6,14 +6,17 @@ import UdpClient from '../UdpUtils' class ObtainUdpBusiness { // 三代机UDP private thirdGenerationMachineUdp?: UdpClient + private thirdGenerationMachineUdpGps2?: UdpClient // 几代机 private modelNo: string = "3" + private config?: EnvironmentConfigurationType constructor() { this.modelNo = GlobalConfig.modelNo || "" } init(config: EnvironmentConfigurationType) { + this.config = config switch (this.modelNo) { case "0": this.initSecondaryBoard() @@ -52,6 +55,25 @@ class ObtainUdpBusiness { } } + onGps2Msg(callback: (data: string) => void) { + switch (this.modelNo) { + case "0": + this.onSecondaryBoardMsg(callback) + break + case "1": + this.onFirstGenerationMsg(callback) + break + case "2": + this.onSecondGenerationMsg(callback) + break + case "3": + this.onThirdGenerationGps2Msg(callback) + break + default: + break + } + } + offMsg(cb: Function) { switch (this.modelNo) { case "0": @@ -61,7 +83,23 @@ class ObtainUdpBusiness { case "2": break case "3": - this.thirdGenerationMachineUdp!.offMsg(cb) + this.thirdGenerationMachineUdpGps2!.offMsg(cb) + break + default: + break + } + } + + offGps2Msg(cb: Function) { + switch (this.modelNo) { + case "0": + break + case "1": + break + case "2": + break + case "3": + this.thirdGenerationMachineUdpGps2!.offMsg(cb) break default: break @@ -99,6 +137,7 @@ class ObtainUdpBusiness { break case "3": this.thirdGenerationMachineUdp!.close() + this.thirdGenerationMachineUdpGps2?.close() break default: break @@ -120,8 +159,6 @@ class ObtainUdpBusiness { // 三代机udp初始化 private initThirdGeneration(config: EnvironmentConfigurationType) { try { - // let config: EnvironmentConfigurationType = - // AppStorage.get("EnvironmentConfiguration")! console.log("获取udp设置", JSON.stringify(config)) this.thirdGenerationMachineUdp = new UdpClient() this.thirdGenerationMachineUdp.create(config.udplocalIp!, config.udplocalIpPort!, config.udpOppositeIp!, @@ -130,6 +167,11 @@ class ObtainUdpBusiness { } catch (e) { console.error(UDPTag, "三代机 udp失败") } + if (config.carType === "4") { + this.thirdGenerationMachineUdpGps2 = new UdpClient() + this.thirdGenerationMachineUdpGps2.create(config.udplocalIp!, config.udplocalIpPortTwo!, config.udpOppositeIpTwo!, config.udpOppositeIpPortTwo!) + this.thirdGenerationMachineUdpGps2.setDealMethod(this.dealThirdGenerationMsg) + } } private dealSecondaryBoardMsg() { @@ -176,6 +218,10 @@ class ObtainUdpBusiness { this.thirdGenerationMachineUdp!.onMsg(cb) } + private onThirdGenerationGps2Msg(cb: Function) { + this.thirdGenerationMachineUdpGps2!.onMsg(cb) + } + private sendSecondaryBoardMsg(data: string | ArrayBuffer) { } @@ -190,6 +236,9 @@ class ObtainUdpBusiness { private sendThirdGenerationMsg(data: string | ArrayBuffer) { this.thirdGenerationMachineUdp!.sendMsg(data) + if (this.config?.carType === '4') { + this.thirdGenerationMachineUdpGps2!.sendMsg(data) + } } } diff --git a/entry/src/main/ets/utils/business/SerialPortService.ets b/entry/src/main/ets/utils/business/SerialPortService.ets index 2c46c66..c7dda54 100644 --- a/entry/src/main/ets/utils/business/SerialPortService.ets +++ b/entry/src/main/ets/utils/business/SerialPortService.ets @@ -72,6 +72,10 @@ class serialPortService { } } + offMsg() { + this.events = []; + } + async closed() { const res = await CancelReceiveSerialPortData(this.fd); this.events = []; diff --git a/entry/src/main/ets/utils/business/UdpEvent.ets b/entry/src/main/ets/utils/business/UdpEvent.ets index fc9cd6d..78a55ae 100644 --- a/entry/src/main/ets/utils/business/UdpEvent.ets +++ b/entry/src/main/ets/utils/business/UdpEvent.ets @@ -1,5 +1,5 @@ import emitter from '@ohos.events.emitter'; -import { JudgeUdpBusinessInstance } from './JudgeUdpBusiness'; +// import { JudgeUdpBusinessInstance } from './JudgeUdpBusiness'; enum EventId { //远程扣分处理 @@ -80,7 +80,8 @@ class JudgeEmitter { //监听扣分指令 public sendOnKf(directives: string) { this.directives = directives - JudgeUdpBusinessInstance.askKf(Number(directives)) + // TODO 远程扣分 + // JudgeUdpBusinessInstance.askKf(Number(directives)) } // 获取扣分项目编号 diff --git a/entry/src/main/ets/utils/table/Operation.ets b/entry/src/main/ets/utils/table/Operation.ets index 90c8555..74db78c 100644 --- a/entry/src/main/ets/utils/table/Operation.ets +++ b/entry/src/main/ets/utils/table/Operation.ets @@ -26,6 +26,15 @@ export async function InitTable() { // 插表操作 export function SqlInsertTable(tableName: string, data: Array, delFlag = true): Promise { return new Promise((resolve, reject) => { + if (data.length === 0) { + DB.clearTable(tableName).then(() => { + dConsole.log(DbOperationTag, '清空表成功', 'tableName', tableName) + resolve(true) + }).catch((err: BusinessError) => { + dConsole.error(DbOperationTag, '清空表失败,', JSON.stringify(err), 'tableName', tableName) + reject(err) + }) + } data.forEach((element, index) => { element.id = !delFlag ? `${index + data.length}` : `${index}` }) @@ -34,7 +43,10 @@ export function SqlInsertTable(tableName: string, data: Array, delFl const columns: string = columnsData?.filter((column) => column !== "id").join(",") || ""; const values = data.map(item => { const value = columnsData?.filter(column => column !== "id") - .map((column) => `'${Reflect.get(item, column) || ""}'`) + .map((column) => { + return `'${Reflect.get(item, column) || ""}'` + // return `'${Object.entries(item).find((keyArr: Array) => keyArr[0] === column)?.[1] || ""}'` + }) .join(",") return `(${value})` }).join(",") @@ -52,9 +64,6 @@ export function SqlInsertTable(tableName: string, data: Array, delFl }) } -// 参数平台 - - // TODO 后续废弃这个方法,直接调用SqlInsertTable // 依据数组和表名更新sql表 export function UpdateTableByArray(tableName: string, arr: Array): Promise { @@ -142,44 +151,39 @@ export async function InitializeTheCentralTable(params: InitializeTheCentralTabl const initPromises = tableKeys.map(async (key) => { // 后端传递的字段首字母小写了,需要转换下 const newKey = key.charAt(0).toUpperCase() + key.slice(1); - const isExit = CenterMap.has(newKey); - - dConsole.log(InitTableTag, "-------------------表名-----------------------", newKey, isExit); - - if (!isExit) { - dConsole.error(InitTableTag, newKey, "表不存在") - return false + // TODO 先忽略这张表 + if (newKey !== "GunCameraInfo") { + const isExit = CenterMap.has(newKey); + dConsole.log(InitTableTag, "-------------------表名-----------------------", newKey, isExit); + if (!isExit) { + dConsole.error(InitTableTag, newKey, "表不存在") + return false + } + dConsole.log(InitTableTag, "可以插入的表", newKey, CenterMap.get(newKey)); + let arrList: Array | RecordType = []; + const value: PublicInfoType = Reflect.get(res.body, key); + arrList = value instanceof Array ? value : [value]; + const folderPath = await fileUtil.initFolder(`/config/tableList`); + await fileUtil.addFile( + `${folderPath}/${RemappingTableName.get(newKey)}.txt`, + JSON.stringify(arrList) + ); + dConsole.log(InitTableTag, "插入表操作", newKey); + dConsole.log(InitTableTag, "插入表别名", RemappingTableName.get(newKey)); + dConsole.log(InitTableTag, "插入表长度", arrList.length); + const result = await SqlInsertTable(RemappingTableName.get(newKey)!, arrList); + dConsole.log(InitTableTag, "插入表结果,表", newKey, "结果", result); + if (!result) { + dConsole.log(InitTableTag, "初始化失败", newKey) + Prompt.showToast({ + message: `初始化表 ${newKey} 失败` + }); + return false; + } + dConsole.log(InitTableTag, "~~~~~~~~~~~~~~~~~~~~~~初始化成功~~~~~~~~~~~~~~~~~~~~~~", newKey); + return true; } - - dConsole.log(InitTableTag, "可以插入的表", newKey, CenterMap.get(newKey)); - - let arrList: Array | RecordType = []; - const value: PublicInfoType = Reflect.get(res.body, key); - arrList = value instanceof Array ? value : [value]; - - const folderPath = await fileUtil.initFolder(`/config/tableList`); - await fileUtil.addFile( - `${folderPath}/${RemappingTableName.get(newKey)}.txt`, - JSON.stringify(arrList) - ); - - dConsole.log(InitTableTag, "插入表操作", newKey); - dConsole.log(InitTableTag, "插入表别名", RemappingTableName.get(newKey)); - dConsole.log(InitTableTag, "插入表长度", arrList.length); - - const result = await SqlInsertTable(RemappingTableName.get(newKey)!, arrList); - dConsole.log(InitTableTag, "插入表结果,表", newKey, "结果", result); - - if (!result) { - dConsole.log(InitTableTag, "初始化失败", newKey) - Prompt.showToast({ - message: `初始化表 ${newKey} 失败` - }); - return false; - } - - dConsole.log(InitTableTag, "~~~~~~~~~~~~~~~~~~~~~~初始化成功~~~~~~~~~~~~~~~~~~~~~~", newKey); - return true; + return true }); const results = await Promise.all(initPromises); diff --git a/entry/src/main/ets/workers/DifferentialCorrection.ets b/entry/src/main/ets/workers/DifferentialCorrection.ets index 7f95cd6..1636201 100644 --- a/entry/src/main/ets/workers/DifferentialCorrection.ets +++ b/entry/src/main/ets/workers/DifferentialCorrection.ets @@ -1,57 +1,114 @@ // 处理worker线程的消息tcp拿差分改正数,udp给后置机 import worker, { ErrorEvent, MessageEvents, ThreadWorkerGlobalScope } from '@ohos.worker'; -import { WorkerTag } from '../config'; +import { SerialPortTag, WorkerTag } from '../config'; import { CenterCallBackMsgType, + CenterData, + CloseData, EnvironmentConfigurationType, + ExamData, + InitData, + JudgeData, WorkerBackMessage, WorkerBackMessageType, - WorkerMessage + WorkerMessage, + WorkerMessageDataType } from '../model'; import { CenterUDPBusinessInstance } from '../utils/business/CenterUdpBusiness'; import { DifferentialSignal } from '../utils/business/DifferentialSignal'; +import { JudgeUdpBusinessInstance } from '../utils/business/JudgeUdpBusiness'; import { ObtainUdpBusinessInstance } from '../utils/business/ObtainUdpBusiness'; import { SerialPortService } from '../utils/business/SerialPortService'; +import dayTs from '../utils/Date'; +import { NumberToByteArray } from '../utils/Common'; const workerPort: ThreadWorkerGlobalScope = worker.workerPort; +let initDate = dayTs(new Date()).format().split(" ")[0] +let udpLsh = 1 +let udpIndex = 0 +let kfDirective: number | undefined = undefined +let signNum: number = 0 +let gps2: string | undefined = undefined -workerPort.onmessage = (e: MessageEvents) => { - console.log(WorkerTag, `Worker received message: ${e.data}`); - const result: WorkerMessage = JSON.parse(e.data); - initFn(result) - // TODO 内部已经实现,外部未实现 - // 如果外部有这个值就去更新中心这个值 - if (result.otherMessage) { - CenterUDPBusinessInstance.changeKeyValue(result.otherMessage) - } - // 如果外部有这个消息进来就开始给中心发送,暂时看不需要 - // if (result.centerUdpParam) { - // CenterUDPBusinessInstance.sendData(result.centerUdpParam); - // } - getDataFn(result.config) - // 必传环境配置 - if (result.close) { - closedFn(result) +function checkLsh() { + let now = dayTs(new Date()).format().split(" ")[0] + if (now === initDate) { + udpLsh++ + } else { + initDate = now + udpLsh = 0 } } + +workerPort.onmessage = async (e: MessageEvents) => { + // console.log(WorkerTag, `Worker received message: ${e.data}`); + const result: WorkerMessage = JSON.parse(e.data); + switch (result.type) { + case WorkerMessageDataType.Init: { + let data = result.data as InitData + initFn(data) + getDataFn(data.config!) + break + } + case WorkerMessageDataType.SetExamData: { + let data = result.data as ExamData + JudgeUdpBusinessInstance.setLsh(data.lsh!) + CenterUDPBusinessInstance.changeKeyValue(data) + break + } + case WorkerMessageDataType.JudgeSend: { + let data = result.data as JudgeData + JudgeUdpBusinessInstance.business = data.business ?? null + JudgeUdpBusinessInstance.performInfo = data.performInfo ?? null + JudgeUdpBusinessInstance.isUDPEnd = data.judgeUdpEnd ?? false + JudgeUdpBusinessInstance.isExamEnd = data.judgeExamEnd ?? false + if (data.remoteType) { + if (data.remoteType === "kf") { + JudgeUdpBusinessInstance.confirmKf(data.remoteData![0], 1, udpLsh) + } + } + break + } + case WorkerMessageDataType.CenterSend: { + let data = result.data as CenterData + checkLsh() + CenterUDPBusinessInstance.sendMsgExt(data.id, data.body, udpLsh) + break + } + case WorkerMessageDataType.Close: + let data = result.data as CloseData + closedFn(data) + break + default: + return + } + // TODO 内部已经实现,外部未实现 +} + // 初始化函数 -function initFn(result: WorkerMessage) { +function initFn(result: InitData) { + if (result.config?.carType === '4') { + + } // 初始化差分校正TCP - DifferentialSignal.init(result.config); + DifferentialSignal.init(result.config!); // 定时发送TCP消息 DifferentialSignal.sendData() // 初始化后置机UDP - ObtainUdpBusinessInstance.init(result.config) + ObtainUdpBusinessInstance.init(result.config!) // 初始化中心UDP - CenterUDPBusinessInstance.init(result.config, result.carInfo, result.otherMessage) - // 中心心跳 - CenterUDPBusinessInstance.startHeartBeat() + CenterUDPBusinessInstance.init(result.config!, result.carInfo!, result) + + setInterval(() => { + checkLsh() + CenterUDPBusinessInstance.startHeartBeat(udpLsh) + }, 1000) // 初始化考试过程UDP - // JudgeUdpBusinessInstance.init(result.config, result.carInfo, result?.singlePlay || false, result.otherMessage.lsh) + JudgeUdpBusinessInstance.init(result.config!, result.carInfo!, result?.singlePlay || false, result!.lsh!) // 初始化档位信号串口 - if (result.config.carType !== "2") { + if (result.config?.carType !== "2") { SerialPortService.init() } } @@ -59,7 +116,6 @@ function initFn(result: WorkerMessage) { function getDataFn(config: EnvironmentConfigurationType) { // 获取TCP差分改正数信号 DifferentialSignal.getData((data: ArrayBuffer) => { - console.log(WorkerTag, "获取中心差分改正消息:", data.byteLength, "bytes") // TCP拿到差分改正数发给后置机 ObtainUdpBusinessInstance.sendData(data) }) @@ -69,14 +125,26 @@ function getDataFn(config: EnvironmentConfigurationType) { // TODO // 需要观察 // console.log(WorkerTag, "后置机消息", data) - const res = await SerialPortService.getData() - if (res.length > 0) { - const dataArray = data.split(","); - // 替换data的第28位 - dataArray[28] = res[9].toString(); - data = dataArray.join(","); + try { + const res = await SerialPortService.getData() + // console.log(SerialPortTag, "档位原始数据", res) + if (res.length > 0) { + const dataArray = data.split(","); + // 替换data的第28位 + dataArray[28] = res[9].toString(); + data = dataArray.join(","); + // console.log(SerialPortTag, "档位", res[9].toString()) + } + } catch (err) { + console.error(SerialPortTag, "获取档位信号失败", err) } - // console.log(SerialPortTag, "处理完的档位信号", data) + if (udpIndex % 5 === 0) { + checkLsh() + let byte = await JudgeUdpBusinessInstance.getMessageHeartbeat(data, gps2) + JudgeUdpBusinessInstance.sendData(byte, udpLsh) + } + udpIndex++ + // console.log(SerialPortTag, "后置机消息", data) workerPort.postMessage( JSON.stringify({ type: WorkerBackMessageType.ObtainUdpData, @@ -84,11 +152,90 @@ function getDataFn(config: EnvironmentConfigurationType) { } as WorkerBackMessage)) } }) + if (config.carType === '4') { + ObtainUdpBusinessInstance.onGps2Msg(async (data: string) => { + if (data !== "" && config.carType !== "2") { + try { + const res = await SerialPortService.getData() + if (res.length > 0) { + const dataArray = data.split(","); + dataArray[28] = res[9].toString(); + data = dataArray.join(","); + } + } catch (err) { + console.error(SerialPortTag, "获取档位信号失败", err) + } + gps2 = data + workerPort.postMessage( + JSON.stringify({ + type: WorkerBackMessageType.ObtainUdpGps2Data, + data: data + } as WorkerBackMessage)) + } + }) + } // 中心UDP回执消息 CenterUDPBusinessInstance.onMsg((data: CenterCallBackMsgType) => { // TODO // 需要观察 - console.log(WorkerTag, "中心消息", data) + checkLsh() + switch (Number(data.id)) { + case 32: + signNum = data.body![1] + if (Number(data.body![0]) === 5) { + kfDirective = data.body![1] + JudgeUdpBusinessInstance.askKf(data.body![1], udpLsh) + } else if (Number(data.body![0]) === 6) { + JudgeUdpBusinessInstance.askStopExam(data.body![1], udpLsh) + } else if (Number(data.body![0]) === 11) { + workerPort.postMessage( + JSON.stringify({ + type: WorkerBackMessageType.RemoteStartExam + } as WorkerBackMessage) + ) + } else if (Number(data.body![0]) === 12) { + workerPort.postMessage( + JSON.stringify({ + type: WorkerBackMessageType.RemoteEndExam + } as WorkerBackMessage) + ) + } else if (Number(data.body![0]) === 18) { + // TODO + } + break + case 36: + workerPort.postMessage( + JSON.stringify({ + type: WorkerBackMessageType.RemoteKf, + data: [kfDirective, data.body![0]] + } as WorkerBackMessage) + ) + break + case 39: { + let lsh = data.body.map(byte => String.fromCharCode(byte)).join("") + if (lsh === JudgeUdpBusinessInstance.getLsh()) { + workerPort.postMessage( + JSON.stringify({ + type: WorkerBackMessageType.StopExam, + data: data + } as WorkerBackMessage)) + JudgeUdpBusinessInstance.confirmStopExam(signNum, udpLsh) + } + break + } + case 46: { + let lsh = JudgeUdpBusinessInstance.getLsh() + let tempList: number[] = [] + for (let i = 0; i < lsh.length; i++) { + tempList.push(NumberToByteArray(lsh.charCodeAt(i), 8)[0]) + } + JudgeUdpBusinessInstance.sendMsgExt(47, tempList, udpLsh) + break + } + default: + return + } + // 收到中心指令发送出去 workerPort.postMessage( JSON.stringify({ @@ -100,11 +247,11 @@ function getDataFn(config: EnvironmentConfigurationType) { } // 关闭函数 -function closedFn(result: WorkerMessage) { +function closedFn(result: CloseData) { ObtainUdpBusinessInstance.close() CenterUDPBusinessInstance.close() // 关闭串口 - if (result.config.carType !== "2") { + if (result?.carType !== "2") { SerialPortService.closed() } } diff --git a/entry/src/main/ets/workers/Log.ets b/entry/src/main/ets/workers/Log.ets index 8709e26..a04ed33 100644 --- a/entry/src/main/ets/workers/Log.ets +++ b/entry/src/main/ets/workers/Log.ets @@ -1,26 +1,20 @@ import worker, { ErrorEvent, MessageEvents, ThreadWorkerGlobalScope } from '@ohos.worker'; -import { GlobalConfig } from '../config'; -import { - FileQueueType, - LogFileFd, - LogPathType, - LogWorkerMessage, - ProcessDataEnumType, - WorkerMessageType -} from '../model'; +import { GlobalConfig, LogTag } from '../config'; +import { FileQueueType, LogPathType, LogWorkerMessage, ProcessDataEnumType, WorkerMessageType } from '../model'; import { CreateDir, CreateFile, EditFile, IsExit } from '../utils/Common'; import dayTs from '../utils/Date'; import fs from '@ohos.file.fs'; const workerPort: ThreadWorkerGlobalScope = worker.workerPort; // 过程数据文件 -const fileNameArr: string[] = ["four_one_log_byte_data.txt", "four_one_log_data.txt", "judge_exam_data.txt", "judge_log_data.txt", "judge_progress_callback_data.txt", "plc_data.txt", "wuxi_exam_data.txt", "wuxi_progress_data.txt"] +// "four_one_log_byte_data.txt", "four_one_log_data.txt", +const fileNameArr: string[] = ["judge_exam_data.txt", "judge_log_data.txt", "judge_progress_callback_data.txt", "plc_data.txt", "wuxi_exam_data.txt", "wuxi_progress_data.txt"] // 过程数据fd let fileFdArr: number[] = [] let writeQueue: Array = []; let isProcessing = false; workerPort.onmessage = (e: MessageEvents) => { - console.log("日志系统worker收到消息") + // console.log(LogTag, "日志系统worker收到消息") // 日志文件目录 let logPaths: LogPathType = { log: `${GlobalConfig.commonFileWriteAddress}/logs/${dayTs().format("YYYY_MM_DD")}/log/log.log`, @@ -36,10 +30,12 @@ workerPort.onmessage = (e: MessageEvents) => { } // 写过程数据 if (result.type === WorkerMessageType.WriteProcessData && result.processDataType) { + // console.log(LogTag, "work收到过程数据") WriteProcessData(result.processDataType, result.data || "") } // 关闭过程数据 if (result.type === WorkerMessageType.CloseProcessData) { + console.log(LogTag, "关闭过程数据") CloseProcessData() } } @@ -80,7 +76,7 @@ async function InitLog() { // 初始化学员过程数据目录 async function InitExam(dirName: string) { - console.log("初始化过程", dirName) + console.log(LogTag, "初始化过程", dirName) let date = dayTs().format("YYYY_MM_DD") const path = `${GlobalConfig.commonFileWriteAddress}/logs/${date}/${dirName}` const nameDirIsExit = await IsExit(path) @@ -88,50 +84,22 @@ async function InitExam(dirName: string) { await CreateDir(path); } // 创建几个文件 - fileNameArr.forEach(async (item: string, index: number) => { + fileNameArr.forEach(async (item: string) => { let filePath = path + "/" + item - console.log("创建文件", filePath) + console.log(LogTag, "创建文件", filePath) let result = await CreateFile(filePath) - fileFdArr[index] = result + // fileFdArr[index] = result + fileFdArr.push(result) }) } // 写过程数据 async function WriteProcessData(type: ProcessDataEnumType, data: string) { - if (type === ProcessDataEnumType.WuxiExam) { - // 改变数据为无锡所需要的数据 - const plcData = data.split(','); - const time = dayTs().format("YYYY-MM-DD HH:mm:ss") - const lineData = [ - /*帧头*/time, - /*卫星时间*/time, - /*经度*/ plcData[95], - /*纬度*/ plcData[95], - /*高度*/ plcData[86], - /*方位角*/ 0, - /*俯仰角*/ plcData[91], - /*速度角*/'', - /*速度*/ plcData[97], - /*横滚*/'', - /*卫星定位状态*/'', - /*卫星定向状态*/'', - /*前天线可用星数*/'', - /*后天线可用星数*/'', - /*东向位置坐标*/'', - /*北向位置坐标*/'', - /*天向位置坐标*/'', - /*东向速度*/'', - /*北向速度*/'', - /*评判信号1*/[plcData[14], plcData[19], plcData[5], '', plcData[2], plcData[3], plcData[7], plcData[8], - plcData[13], plcData[12], plcData[17], '', plcData[4], plcData[11], plcData[20], plcData[9], 0].join(','), - /*评判信号2*/['', plcData[28], '', '', plcData[10], '', '', '', '', '', '', '', '', '', '', '', '', ''].join(','), - /*发动机转速*/ plcData[25], - /*结束符*/ time, - ]; - writeQueue.push({ type, data: JSON.stringify(lineData) }); - } else { - writeQueue.push({ type, data }); + // console.log(LogTag, "推入过程数据", type, data) + if (fileFdArr.length === 0) { + return } + writeQueue.push({ type, data }); if (!isProcessing) { processQueue(); @@ -140,20 +108,33 @@ async function WriteProcessData(type: ProcessDataEnumType, data: string) { async function processQueue() { isProcessing = true; - while (writeQueue.length > 0) { + while (writeQueue.length > 0 && isProcessing) { const item = writeQueue.shift()!; const index = Number(item.type); - await EditFile(fileFdArr[index], item.data); + try { + await EditFile(fileFdArr[index], item.data); + } catch (e) { + console.error(LogTag, "写过程数据错误", JSON.stringify(e)) + } } isProcessing = false; } // 关闭过程数据 function CloseProcessData() { - fileFdArr.forEach((item: number) => { - fs.closeSync(item) - }) - console.log("关闭过程数据") + writeQueue = [] + isProcessing = false + if (fileFdArr.length > 0) { + console.log(LogTag, "有文件需要 关闭过程数据", fileFdArr) + fileFdArr.forEach((item: number) => { + try { + fs.closeSync(item) + } catch (e) { + console.error(LogTag, JSON.stringify(e)) + } + }) + } + fileFdArr = [] } workerPort.onmessageerror = (e: MessageEvents) => { diff --git a/entry/src/main/module.json5 b/entry/src/main/module.json5 index db1c5f8..a444b23 100644 --- a/entry/src/main/module.json5 +++ b/entry/src/main/module.json5 @@ -54,6 +54,7 @@ { "name": "ohos.permission.SET_TIME" }, + {"name": "ohos.permission.ACCESS_SERVICE_DM"}, { "name": "ohos.permission.INTERNET" }, diff --git a/oh-package-lock.json5 b/oh-package-lock.json5 index d61f840..f76874c 100644 --- a/oh-package-lock.json5 +++ b/oh-package-lock.json5 @@ -1,20 +1,18 @@ { - "lockfileVersion": 2, + "lockfileVersion": 1, "ATTENTION": "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.", "specifiers": { "@ohos/crypto-js@2.0.3": "@ohos/crypto-js@2.0.3", "@ohos/hypium@1.0.19": "@ohos/hypium@1.0.19" }, "packages": { - "@ohos/hypium@1.0.19": { - "resolved": "https://ohpm.openharmony.cn/ohpm/@ohos/hypium/-/hypium-1.0.19.har", - "integrity": "sha512-cEjDgLFCm3cWZDeRXk7agBUkPqjWxUo6AQeiu0gEkb3J8ESqlduQLSIXeo3cCsm8U/asL7iKjF85ZyOuufAGSQ==", - "registryType": "ohpm" - }, "@ohos/crypto-js@2.0.3": { "resolved": "https://ohpm.openharmony.cn/ohpm/@ohos/crypto-js/-/crypto-js-2.0.3.har", - "integrity": "sha512-LuHaR1kD5PxnOXnuR1fWvPwGtbed9Q/QGzk6JOh8y5Wdzvi8brPesODZiaWf9scOVRHsbTPOtZw91vWB35p1vQ==", - "registryType": "ohpm" + "integrity": "sha512-LuHaR1kD5PxnOXnuR1fWvPwGtbed9Q/QGzk6JOh8y5Wdzvi8brPesODZiaWf9scOVRHsbTPOtZw91vWB35p1vQ==" + }, + "@ohos/hypium@1.0.19": { + "resolved": "https://ohpm.openharmony.cn/ohpm/@ohos/hypium/-/hypium-1.0.19.har", + "integrity": "sha512-cEjDgLFCm3cWZDeRXk7agBUkPqjWxUo6AQeiu0gEkb3J8ESqlduQLSIXeo3cCsm8U/asL7iKjF85ZyOuufAGSQ==" } } } \ No newline at end of file