From b5c641c16bcb7fb6790fed4c74c8c8574f3c8369 Mon Sep 17 00:00:00 2001 From: Surenjun Date: Wed, 27 Aug 2025 13:50:20 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E6=96=B0=E7=A7=91=E7=9B=AE=E4=B8=89?= =?UTF-8?q?=E5=BC=80=E5=8F=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- entry/src/main/ets/common/lidar/index.ts | 72 ++++++++++ .../src/main/ets/common/lidar/sense/index.ts | 10 ++ .../main/ets/common/lidar/udpClient/index.ts | 112 +++++++++++++++ .../main/ets/common/service/videoService.ts | 1 + entry/src/main/ets/mock/SignDisplay.ets | 4 + entry/src/main/ets/pages/Judge.ets | 3 + entry/src/main/ets/pages/TerminalInfos.ets | 132 +++++++++++++++++- .../ets/pages/compontents/SignDisplayCom.ets | 38 +++++ .../ets/pages/compontents/judge/RealTime.ets | 2 +- entry/src/main/ets/pages/judgeSDK/judge.ts | 6 +- .../ets/pages/judgeSDK/utils/judgeConfig.ts | 8 +- 11 files changed, 378 insertions(+), 10 deletions(-) create mode 100644 entry/src/main/ets/common/lidar/index.ts create mode 100644 entry/src/main/ets/common/lidar/sense/index.ts create mode 100644 entry/src/main/ets/common/lidar/udpClient/index.ts diff --git a/entry/src/main/ets/common/lidar/index.ts b/entry/src/main/ets/common/lidar/index.ts new file mode 100644 index 00000000..1c479c32 --- /dev/null +++ b/entry/src/main/ets/common/lidar/index.ts @@ -0,0 +1,72 @@ +import UdpClient from './udpClient/index' +import FileUtil from '../../common/utils/File'; +import { GlobalConfig } from '../../config/index'; +import emitter from '@ohos.events.emitter'; + +interface messageIds { + [k:string]:number; +} + +class Lidar { + public localRadarUdp: UdpClient + public localVisionUdp: UdpClient + private isNewKm3: Boolean + private messageIds:messageIds = {} + + constructor() { + this.init() + } + + //监听雷达信息 + async onRadarMsg(messageId:string,callback:Function) { + if(this.messageIds[messageId] === undefined){ + let timer = setInterval(()=>{ + callback(this.radarObj) + },200) + this.messageIds[messageId] = timer; + } + } + + //监听视觉信息 + async onSenseMsg(messageId:string,callback:Function) { + if(this.messageIds[messageId] === undefined){ + let timer = setInterval(()=>{ + callback(this.senseObj) + },200) + this.messageIds[messageId] = timer; + } + } + + //关闭消息 + async offVisionMsg(eventId) { + clearInterval(this.messageIds[eventId]) + delete this.messageIds[eventId] + } + + async init() { + const fileUtil = new FileUtil(globalThis.context) + const addressStr = await fileUtil.readFile(GlobalConfig.comoonfileWriteAddress + '/config/ipConfig.txt'); + const {deviceType,deviceIpArr,devicePortArr,udplocalIp} = JSON.parse(addressStr); + + //新科目三设备 + if (deviceType == '2') { + //雷达数据 + this.localRadarUdp = new UdpClient('radar', { + deviceIpArr, devicePortArr, udplocalIp + }); + + //视觉数据 + this.localVisionUdp = new UdpClient('vision', { + deviceIpArr, devicePortArr, udplocalIp + }) + + this.localRadarUdp.onMessage((obj) => { + this.radarObj = obj + }) + this.localVisionUdp.onMessage((obj) => { + this.visionObj = obj + }) + this.isNewKm3 = true; + } + } +} \ No newline at end of file diff --git a/entry/src/main/ets/common/lidar/sense/index.ts b/entry/src/main/ets/common/lidar/sense/index.ts new file mode 100644 index 00000000..e480a683 --- /dev/null +++ b/entry/src/main/ets/common/lidar/sense/index.ts @@ -0,0 +1,10 @@ + + +export default class SenseUtil{ + constructor() {} + + //扣分 + //开始考试 + //结束考试 + +} \ No newline at end of file diff --git a/entry/src/main/ets/common/lidar/udpClient/index.ts b/entry/src/main/ets/common/lidar/udpClient/index.ts new file mode 100644 index 00000000..4cf3ef38 --- /dev/null +++ b/entry/src/main/ets/common/lidar/udpClient/index.ts @@ -0,0 +1,112 @@ +import socket from '@ohos.net.socket'; +import FileUtil from '../../../common/utils/File'; +import { GlobalConfig } from '../../../config/index'; +import promptAction from '@ohos.promptAction' + +const TAG = 'LIDAUDP' +type TYPE = 'vision' | 'radar' + +interface IPAPORT{ + address:string, + port:number +} + +interface Params{ + deviceIpArr:string[], + devicePortArr:number[], + udplocalIp:string +} + +export default class LidaUdpClient{ + // 0: 视觉 1: 雷达 + public type:TYPE + private udpClient:socket.UDPSocket + private localIp:string + private localSensePort: 33313 + private localVisionPort: 33314 + private params:Params + public message:string + + constructor(type:TYPE,params:Params) { + this.type = type; + this.params = params + this.localIp = params.udplocalIp + } + + async init(){ + const {address,port} = await this.getIpAPort() + this.udpClient = socket.constructUDPSocketInstance(); + + //bind + await this.safeFn(async()=>{ + await this.udpClient.bind({ + address: this.localIp, + port: port, + family: 1 + }); + }) + } + + async onMessage(callback){ + this.offMessage() + //message + this.udpClient.on('message',(val)=>{ + //TODO 消息解析 + switch (this.type){ + //激光雷达 + case 'radar': + this.radarStrToObj(val) + break; + //视觉 + case 'vision': + this.visionStrToObj(val) + break; + } + console.log(val+''); + }); + } + + //获取对应的IP和端口 + async getIpAPort(): Promise{ + const fileUtil = new FileUtil(globalThis.context) + const addressStr = await fileUtil.readFile(GlobalConfig.comoonfileWriteAddress + '/config/ipConfig.txt'); + const {deviceIpArr,devicePortArr,udplocalIp} = JSON.parse(addressStr); + this.localIp = udplocalIp + return { + address:this.type === 'radar' ? deviceIpArr[0] : deviceIpArr[1], + port: Number(this.type === 'vision' ? devicePortArr[1] : devicePortArr[1]) + } + } + + // + async radarStrToObj(str:string){ + //$MachineVision,30.950^0_-1_1_1,-1^-1_-1_-1_1,-1^-1_-1_-1_1,-1^-1_-1_-1_1,-1^-1_-1_-1_1,-1^-1_-1_-1_1,-1^-1_-1_-1_1,-1^-1_-1_-1_1,-1^-1_-1_-1_1,-1^-1_-1^-1,43083,0_0_0_0,-1^-1_-1_-1_1,-1^-1_-1_-1_1,-1^-1_-1_-1_1,10102264201.69632,1.1.1.2,0*+$VisualInfo,1_-7205_3480_-7300_3350_-7655_3610_-7560_3735_,*+[ { "bodyangle": "1.00", "bodyx": "0.490", "bodyy": "31.300", "elevation": "2.403", "geoangle": "323.90", "geolat": "29.92678975", "geolon": "119.89823128", "id": 1, "type": 2 } ] + + } + + async visionStrToObj(str:string){ + + } + + async offMessage(){ + this.udpClient.off('message') + } + + async closeUdp(){ + this.offMessage(); + this.udpClient.close() + } + + async safeFn(fn:Function){ + try { + await fn() + } catch (e) { + console.info(TAG + JSON.stringify(e)) + promptAction.showToast({ + message: TAG + JSON.stringify(e), + duration: 3000 + }); + throw e + } + } +} diff --git a/entry/src/main/ets/common/service/videoService.ts b/entry/src/main/ets/common/service/videoService.ts index 779b0ebb..fd3a7d4a 100644 --- a/entry/src/main/ets/common/service/videoService.ts +++ b/entry/src/main/ets/common/service/videoService.ts @@ -218,6 +218,7 @@ export async function takePhoto(param, context, dir, flag = 1, callback?) { // @ts-ignore // var snapResult = rtsp_server.getVideoSnapshot(context, video_uri, '', dir); if (flag == 0) { + //@ts-ignore rtsp_server.detectVideoSnapshotSize(video_uri, fileName, (err, snapResult) => { console.log("baohaowen_detectLoop round end size1:" + snapResult.fileSize); callback({ fileSize: snapResult.fileSize, errorCode: snapResult.errorCode }) diff --git a/entry/src/main/ets/mock/SignDisplay.ets b/entry/src/main/ets/mock/SignDisplay.ets index 3e27eecc..90df8cbc 100644 --- a/entry/src/main/ets/mock/SignDisplay.ets +++ b/entry/src/main/ets/mock/SignDisplay.ets @@ -85,3 +85,7 @@ export const RoadData = [ {name:'形状',key:['InShapeAttr','ShapeNo','']}, {name:'路段点',key:['CrossPointNo']}, ] + +export const radarData = [ + +] diff --git a/entry/src/main/ets/pages/Judge.ets b/entry/src/main/ets/pages/Judge.ets index f9d02cdf..42b39aa6 100644 --- a/entry/src/main/ets/pages/Judge.ets +++ b/entry/src/main/ets/pages/Judge.ets @@ -1121,6 +1121,9 @@ struct Index { case '4': return '#FF7566'; break; + case '5': + return '#FF7566'; + break; default: return '#E6DECF'; break; diff --git a/entry/src/main/ets/pages/TerminalInfos.ets b/entry/src/main/ets/pages/TerminalInfos.ets index dea7bf30..70dc8402 100644 --- a/entry/src/main/ets/pages/TerminalInfos.ets +++ b/entry/src/main/ets/pages/TerminalInfos.ets @@ -23,10 +23,15 @@ struct Index { @State terTextList: string[] = ['一型机', '二型机', '三型机', '一体机'] @State cardTextList: string[] = ['北云', '天宝MB2'] @State netTextList: string[] = ['否', '是'] + @State deviceTypeSelect: string[] = ['正常', '安全员','新科目三'] @State selectedTerType: number = 0 @State selectedCardType: number = 0 //是否启用网络差分 @State netOpen: number = 0 + //设备应用类型 + @State deviceType: number = 0 + @State deviceIpArr: string[] = ['192.168.7.173', '192.168.7.173'] + @State devicePortArr: string[] = ['8052', '8053'] // @State inputTextList2: string[] = [] // 112.80.35.83 11052 // @State inputTextList1: string[] = ['192.168.36.2','8084','192.168.36.200','20122','255.255.255.0','192.168.36.1','','','114.114.114.114','192.168.36.139','8000'] @@ -118,7 +123,6 @@ struct Index { }) }.width('51%').height('14%') - Row(){ Text('板卡类型') .width('40%') @@ -140,6 +144,124 @@ struct Index { }) }.width('49%').height('14%') + Row() { + Text('设备应用场景') + .width('40%') + .height('100%') + .fontColor('#E5CBA1') + .padding({ 'left': '35px' }) + .fontSize(this.inputFontSize * this.ratio) + + ForEach(this.deviceTypeSelect, (netText, index) => { + Radio({ value: netText, group: 'deviceRadioGroup' }) + .borderColor('#E5CBA1') + .checked(index === this.deviceType) + .onChange((value: boolean) => { + if(value){ + this.deviceType = index + } + }) + Text(netText).fontSize(20).fontColor('#FFF') + }) + }.width('52%').height('14%') + + if(this.deviceType == 2){ + Row() { + Text('雷达设备IP') + .width('40%') + .height('100%') + .fontColor('#E5CBA1') + .padding({ 'left': '35px' }) + .fontSize(this.inputFontSize * this.ratio) + TextInput({ 'text':this.deviceIpArr[0] }) + .width('50%') + .height('50%') + .fontColor('#fff') + .borderColor('#E6E0D8') + .borderRadius('10px') + .borderWidth('2px') + .fontSize(this.inputFontSize * this.ratio) + .padding({ top: 0, bottom: 0 }) + .linearGradient({angle: 0,colors: [[0x403C36, 0.0], [0x4D473D, 0.34], [0x3D3A34, 1.0]] }) + .onChange((value: string) => { + this.deviceIpArr[0] = value + }) + }.width('50%').height('14%') + Row() { + Text('响应端口') + .width('40%') + .height('100%') + .fontColor('#E5CBA1') + .padding({ 'left': '35px' }) + .fontSize(this.inputFontSize * this.ratio) + TextInput({ 'text':this.devicePortArr[0] }) + .width('50%') + .height('50%') + .fontColor('#fff') + .borderColor('#E6E0D8') + .borderRadius('10px') + .borderWidth('2px') + .fontSize(this.inputFontSize * this.ratio) + .padding({ top: 0, bottom: 0 }) + .linearGradient({ + angle: 0, + colors: [[0x403C36, 0.0], [0x4D473D, 0.34], [0x3D3A34, 1.0]] + }) + .onChange((value: string) => { + this.devicePortArr[0] = value + }) + }.width('50%').height('14%') + Row() { + Text('视觉设备IP') + .width('40%') + .height('100%') + .fontColor('#E5CBA1') + .padding({ 'left': '35px' }) + .fontSize(this.inputFontSize * this.ratio) + TextInput({ 'text': this.deviceIpArr[1] }) + .width('50%') + .height('50%') + .fontColor('#fff') + .borderColor('#E6E0D8') + .borderRadius('10px') + .borderWidth('2px') + .fontSize(this.inputFontSize * this.ratio) + .padding({ top: 0, bottom: 0 }) + .linearGradient({ + angle: 0, + colors: [[0x403C36, 0.0], [0x4D473D, 0.34], [0x3D3A34, 1.0]] + }) + .onChange((value: string) => { + this.deviceIpArr[1] = value + }) + }.width('50%').height('14%') + Row() { + Text('响应端口') + .width('40%') + .height('100%') + .fontColor('#E5CBA1') + .padding({ 'left': '35px' }) + .fontSize(this.inputFontSize * this.ratio) + TextInput({ 'text': this.devicePortArr[1] }) + .width('50%') + .height('50%') + .fontColor('#fff') + .borderColor('#E6E0D8') + .borderRadius('10px') + .borderWidth('2px') + .fontSize(this.inputFontSize * this.ratio) + .padding({ top: 0, bottom: 0 }) + .linearGradient({ + angle: 0, + colors: [[0x403C36, 0.0], [0x4D473D, 0.34], [0x3D3A34, 1.0]] + + }) + .onChange((value: string) => { + this.devicePortArr[1] = value; + }) + }.width('50%').height('14%') + } + } } .width('95%') @@ -172,7 +294,10 @@ struct Index { centerPort: this.inputTextList1[3], terType: this.selectedTerType, cardType: this.selectedCardType, - netOpen: this.netOpen + netOpen: this.netOpen, + deviceType: this.deviceType, + deviceIpArr: this.deviceIpArr, + devicePortArr: this.devicePortArr, } fileUtil.addFile(`${folderPath}/ipConfig.txt`, JSON.stringify(param), '') // upDateTableByArray('IpConfigTable',[]) @@ -247,6 +372,9 @@ struct Index { this.selectedTerType = result.terType this.selectedCardType = result.cardType this.netOpen= result.netOpen + this.deviceType= result.deviceType || 0 + this.deviceIpArr= result.deviceIpArr || ['',''] + this.devicePortArr= result.devicePortArr || ['',''] console.log('surenjun', this.selectedTerType + ''); } diff --git a/entry/src/main/ets/pages/compontents/SignDisplayCom.ets b/entry/src/main/ets/pages/compontents/SignDisplayCom.ets index b076d3be..e8f6e0a9 100644 --- a/entry/src/main/ets/pages/compontents/SignDisplayCom.ets +++ b/entry/src/main/ets/pages/compontents/SignDisplayCom.ets @@ -69,6 +69,18 @@ export default struct SignDisplayCom { }) } + Row() { + Text('雷达数据').fontColor(this.active == 3 ? '#FFAD33' : '#e7cba3').fontSize(20 * this.ratio) + } + .backgroundImage(this.active == 3 ? $r('app.media.signal_tabS') : $r('app.media.signal_tab')) + .width(144 * this.ratio) + .height(50 * this.ratio) + .backgroundImageSize({ width: '100%', height: '100%' }) + .justifyContent(FlexAlign.Center) + .onClick(() => { + this.active = 3 + }) + Row() { Text('原始数据').fontColor(this.active == 2 ? '#FFAD33' : '#e7cba3').fontSize(20 * this.ratio) } @@ -314,6 +326,30 @@ export default struct SignDisplayCom { .backgroundImage($r('app.media.km_open')) .backgroundImageSize({ width: '100%', height: '100%' }) .visibility(this.active == 1 ? Visibility.Visible : Visibility.None) + + Row(){ + Column() { + Column(){ + Text('雷达').fontColor('#fff') + } + Column(){ + Text('视觉').fontColor('#fff') + } + .height(436 * this.ratio) + + } + .backgroundColor('#282828') + .width(this.ratio * 880) + .height(415 * this.ratio) + .margin({ left: 15 * this.ratio, top: 15 * this.ratio }) + } + .width(936 * this.ratio) + .height(460 * this.ratio) + .margin({ left: 10 * this.ratio }) + .padding({ left: 10 * this.ratio, right: 10 * this.ratio }) + .backgroundImage($r('app.media.km_open')) + .backgroundImageSize({ width: '100%', height: '100%' }) + .visibility(this.active == 3 ? Visibility.Visible : Visibility.None) } .width('100%') .height('100%') @@ -323,6 +359,8 @@ export default struct SignDisplayCom { aboutToDisappear() { clearInterval(this.interval) + //TODO + console.info('surenjun','123') } async aboutToAppear() { diff --git a/entry/src/main/ets/pages/compontents/judge/RealTime.ets b/entry/src/main/ets/pages/compontents/judge/RealTime.ets index 51fea143..d578a59d 100644 --- a/entry/src/main/ets/pages/compontents/judge/RealTime.ets +++ b/entry/src/main/ets/pages/compontents/judge/RealTime.ets @@ -44,7 +44,7 @@ export default struct RealTime { Row() { Column() { Row() { - Text('车道信息').fontColor(this.gpsActive == 0 ? '#2D3C5A' : '#fff').fontSize(20) + Text('车道信息').fontColor(this.gpsActive == 0 ? '#2D3C5A' : '#fff').fontSize(14) } .width('100%') .height(37) diff --git a/entry/src/main/ets/pages/judgeSDK/judge.ts b/entry/src/main/ets/pages/judgeSDK/judge.ts index 2dd16e31..cfae62ff 100644 --- a/entry/src/main/ets/pages/judgeSDK/judge.ts +++ b/entry/src/main/ets/pages/judgeSDK/judge.ts @@ -934,6 +934,8 @@ export default class Judge { this.judgeUI.totalScore += thisKf.score * 1; if (kf.xmdm != 20) { const type = judgeUI.projectsObj[kf.xmdm].type; + console.info('surejun kf=>',JSON.stringify(kf)) + console.info('surejun kf_type=>',type) judgeUI.projectsObj[kf.xmdm].type = (type == 3 || type == 4) ? '4' : '5'; } break; @@ -956,11 +958,11 @@ export default class Judge { console.info(judgeTag, '项目取消'); const {examSubject} = this.judgeUI const xmdm = xmqx.xmdm; - const xmmcCode = judgeUI.projectsObj[xmdm].projectCodeCenter; + const xmmcCode1 = judgeUI.projectsObj[xmdm].projectCodeCenter; // const voiceCode = getKmProjectCancelVoice(examSubject, xmmcCode); // avPlayer.playAudio([`voice/${voiceCode}.mp3`],true) this.judgeUI.projectsObj[xmdm].type = '1'; - this.testKmItems[xmmcCode].status = '1'; + this.testKmItems[xmmcCode1].status = '1'; break; } diff --git a/entry/src/main/ets/pages/judgeSDK/utils/judgeConfig.ts b/entry/src/main/ets/pages/judgeSDK/utils/judgeConfig.ts index d6ea58e8..abe78287 100644 --- a/entry/src/main/ets/pages/judgeSDK/utils/judgeConfig.ts +++ b/entry/src/main/ets/pages/judgeSDK/utils/judgeConfig.ts @@ -2,9 +2,9 @@ export const judgeConfig = { version:'2024.08.21.01', //本地目录开关 - isTrajectoryOpen: false, + isTrajectoryOpen: true, //是否开启拍照 - isPhotoOpen: true, + isPhotoOpen: false, //扣分语音是否强制开启 kfVoiceOpen: false, //忽略的考试项目 @@ -16,14 +16,12 @@ export const judgeConfig = { // 本地模型地址 // modelPath: 'models/model_enc', // 济南科目三 - trajectoryPath: 'logs/2025_04_23_09_50_55_2504755332926_320924199111132926_陈静/judge_exam_data.txt', + trajectoryPath: 'logs/2025_06_20_08_20_09_2250107217821_340823199508126112_左江辉/judge_exam_data.txt', //四合一画面配置 fourInOneScreen:{ //gps位数 gpsDigit:7 }, - // 杭州科目二 - // trajectoryPath: 'logs/2024_07_19/0000000000001_342323199501470011_测试学员1_2024_07_19_06_49_12/judge_exam_data.txt', //TODO 济南临时特殊配置 systemParamConfig:{} } \ No newline at end of file