diff --git a/entry/src/main/ets/config/LogEnum.ets b/entry/src/main/ets/config/LogEnum.ets index 260f70a..f4e3854 100644 --- a/entry/src/main/ets/config/LogEnum.ets +++ b/entry/src/main/ets/config/LogEnum.ets @@ -67,4 +67,7 @@ export const UserInfoTag = '[UserInfo]'; export const SignDisplayTag = '[SignDisplay]'; //开始考试 -export const StartExamTag = '[StartExam]' \ No newline at end of file +export const StartExamTag = '[StartExam]' + +//人脸对比 +export const FaceCompareTag = '[FaceCompare]'; \ No newline at end of file diff --git a/entry/src/main/ets/pages/UserInfo.ets b/entry/src/main/ets/pages/UserInfo.ets index 3b17e6c..176c4c6 100644 --- a/entry/src/main/ets/pages/UserInfo.ets +++ b/entry/src/main/ets/pages/UserInfo.ets @@ -50,6 +50,7 @@ import LabelBlockComponent from './UserInfo/LabelBlock'; import CarLoadingDialog from './compontents/CarLoading'; import ConfirmDialog from './compontents/ConfirmDialog'; import { DifferentialAndSignal } from '../utils/business/DifferentialAndSignalWorker'; +import FaceRecognitionDialog from './UserInfo/FaceRecognition'; @Entry @Component @@ -72,7 +73,6 @@ struct UserInfoPage { @State isSecondBoardPrePareSetPopupOpen: boolean = false @State isFirstBoardPrePareSetPopupBtnShow: boolean = false @State isBoardPrePareSetPopupShow: boolean = false - @State loadingText: string = '正在认证监管信息,请稍后...' @State sczbkf: SckType[] = [] @State currentUser: User = EmptyCandidateObject // 开始考试弹窗 @@ -112,6 +112,16 @@ struct UserInfoPage { customStyle: true, autoCancel: true }) + // 人脸对比弹窗 + faceCompareController: CustomDialogController = new CustomDialogController({ + builder: FaceRecognitionDialog({ + sfzh: this.currentUser.sfzmhm, + firstImage: this.currentUser.kszp, + lsh: AppStorage.get('lsh'), + }), + customStyle: true, + autoCancel: true + }) @State faceFlag: string = '0'; @State FaceOpenStatue: string = '0'; //是否开启人脸识别 @State faceCatchImg: string = '' @@ -490,11 +500,6 @@ struct UserInfoPage { async initSysset() { const that = this; - // DB.queryListBySql("select * from MA_SYSSET", ['id', 'v_no', 'v_name', 'v_value'].map(item => ({ - // type: ColumnType.STRING, - // name: item, - // columnName: item - // }))).then((syssetParams: any) => { GetSyncData("MA_SYSSET").then((syssetParams: MASYSSETTableType[]) => { const serialNumberArr = syssetParams.filter(sys => sys.v_no === '901') that.jkxlh = serialNumberArr?.[0]?.v_value || '' @@ -647,8 +652,6 @@ struct UserInfoPage { dConsole.log('isFirstBoardPrePareSetPopupBtnShow', this.isFirstBoardPrePareSetPopupBtnShow, this.isBoardPrePareSetPopupOpen) this.startExam = false - // await upDateTableByArray('USER', []) - // await upDateTableByArray('USERLIST', []) await DB.clearTable('USER') await DB.clearTable('USERLIST') this.updateTimeLimit = true @@ -689,7 +692,6 @@ struct UserInfoPage { this.list.forEach((listData, index) => { //考过一次不允许切换学员 if (listData.kssycs == '1') { - this.startExam = true } listData.id = index.toString() @@ -743,7 +745,6 @@ struct UserInfoPage { } this.pageIndex = 0 - // getSyncData('USER').then(data => { GetSyncData("USER").then(data => { if (data?.[0]) { this.getCurrentStudent(data[0].sfzmhm) @@ -759,6 +760,7 @@ struct UserInfoPage { } } + // 缺考 qkFn() { if (this.systemParam.Param352Str == '1' && this.currentUser.kssycs == '1') { return @@ -806,11 +808,24 @@ 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] + } + } else if (val.id == 42) { + //收到中心缺考确认消息 + this.qkFn() + } + } + async getExaminationItemFn() { if (!this.currentUser.lsh || this.singlePlay) { return } - // const { carId, examinationRoomId } = this.carInfo; const examItems = await getExaminationItem({ time: GetCurrentTime() || "", carId: this.carInfo.carId || "", @@ -930,7 +945,6 @@ struct UserInfoPage { //开始上车准备 prePareSCZB = async () => { try { - // await this.checkSignal() await CheckSignal(this.systemParam, this.avPlayer) DifferentialAndSignal.clearMsg() this.isExamStart = true @@ -940,9 +954,7 @@ struct UserInfoPage { }).catch((err: BusinessError) => { dConsole.log("USER insert fail", JSON.stringify(err)) }) - // await upDateTableByArray('USER', [this.currentUser]) dConsole.log("User", JSON.stringify(this.currentUser)) - // await sqlInsertCommonFn("USER", [this.currentUser]) AppStorage.setOrCreate('statue', 4) this.isBoardPrePareSetPopupShow = true; this.isFirstBoardPrePareSetPopupBtnShow = true; @@ -1147,20 +1159,6 @@ struct UserInfoPage { .backgroundImage($r('app.media.bg')) .backgroundImageSize({ width: '100%', height: '100%' }) } - - 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] - } - } else if (val.id == 42) { - //收到中心缺考确认消息 - this.qkFn() - } - } } diff --git a/entry/src/main/ets/pages/UserInfo/FaceRecognition.ets b/entry/src/main/ets/pages/UserInfo/FaceRecognition.ets new file mode 100644 index 0000000..db60554 --- /dev/null +++ b/entry/src/main/ets/pages/UserInfo/FaceRecognition.ets @@ -0,0 +1,279 @@ +/** + * 人脸识别弹窗 + */ +import common from '@ohos.app.ability.common'; +import { faceCompare } from '../../api/userInfo'; +import { FaceCompareTag, GlobalConfig } from '../../config'; +import { VideoConfigData } from '../../mock'; +import { CarInfoType, CenterCallBackMsgType, UDPParamType, VideoConfig } from '../../model'; +import { CenterUDPBusinessInstance } from '../../utils/business/CenterUdpBusiness'; +import { NumberToByteArray } from '../../utils/Common'; +import FileUtils from '../../utils/FileUtils'; +import { dConsole } from '../../utils/LogWorker'; +import { takePhoto, takePhotoParam } from '../../utils/Video'; +import { voiceService } from '../../utils/Voice'; + +@CustomDialog +export default struct FaceRecognitionDialog { + // 身份证号 + @Prop sfzh: string; + // 第一张图片 + @Prop firstImage: string; + // 流水号 + @Prop lsh: string; + @State videoConfig: VideoConfig = VideoConfigData + @State previewUri: Resource = $r('app.media.index_bg') + @State base64: string = '' + // 回调标志位 + @State callBackFlag: boolean = false; + // 车辆信息 + @State carInfo: CarInfoType = {}; + private context = getContext(this) as common.UIAbilityContext; + private controller?: CustomDialogController; + private videoController: VideoController = new VideoController() + private fileUtil!: FileUtils + private voiceController!: voiceService + // 人脸对比失败次数 + private times: number = 0 + // 采集照片定时器 + private interval: number = -1 + // 人脸对比成功 + FacialComparisonSuccess: () => void = () => { + } + // 人脸对比失败 + FacialComparisonFailure: () => void = () => { + } + + aboutToAppear(): void { + const fileUtil = new FileUtils(this.context) + this.carInfo = AppStorage.get('carInfo')! + this.fileUtil = fileUtil + this.getConfig() + } + + async getConfig() { + try { + this.voiceController = new voiceService(async (status: string, val?: string) => { + if (status == 'idle') { + if (val === 'face_check.mp3' || val === 'face_fail.mp3') { + if (this.times >= 3) { + AppStorage.setOrCreate('statue', 3); + this.FacialComparisonFailure() + this.voiceController && this.voiceController.playAudio({ + type: 1, + name: 'face_checking.wav', + }); + this.heartMsg(); + } else { + setTimeout(() => { + this.faceCompareFn(); + }, 2000); + } + } else if (val === 'yzcg.wav') { + // 人脸对比成功 + AppStorage.setOrCreate('statue', 4); + this.FacialComparisonSuccess() + this.controller?.close(); + } else if (val === 'face_chekc_fail.wav') { + // 人脸对比失败 + this.FacialComparisonFailure() + this.controller?.close(); + } + } + }, this.context) + const data = await this.fileUtil.readFile(GlobalConfig.commonFileWriteAddress + '/config/config3.txt'); + dConsole.log('faceEnterIn,data', data) + + setTimeout(() => { + this.voiceController && this.voiceController.playAudio({ + type: 1, + name: 'face_check.mp3' + }) + }, 1000) + this.videoConfig = JSON.parse(data) + this.videoController.start() + } catch (e) { + dConsole.error(FaceCompareTag, "人脸识别弹窗获取配置失败", e) + } + } + + async faceCompareFn() { + this.videoConfig.pztd = this.videoConfig.rlls + const data: takePhotoParam = await takePhoto(this.videoConfig, this.context, 'jt/', 1,) + this.base64 = "data:image/jpeg;base64," + (data?.base64 || "") + dConsole.log(FaceCompareTag, "人脸拿到的图片", this.base64) + const result = await faceCompare({ + sfzh: this.sfzh.toString(), + firstImage: this.firstImage.slice(22), + secondImage: data?.base64 || "", + type: "2", + verifyType: "1" + }) + if (result.imageCompareRsp?.head?.resultCode == '0') { + this.videoController.stop() + this.controller.close() + this.FacialComparisonSuccess() + this.voiceController.playAudio({ + type: 1, + name: 'yzcg.wav' + }) + } else { + this.times++; + this.voiceController.playAudio({ + type: 1, + name: 'face_fail.mp3' + }) + } + } + + async heartMsg() { + let tmpList: number[] = [] + for (let i = 0; i < this.lsh.length; i++) { + if (this.lsh && this.lsh.charCodeAt(i) !== undefined) { + tmpList.push(NumberToByteArray(this.lsh.charCodeAt(i), 1 * 8)[0]); + } + } + const param: UDPParamType = { + id: 46, + list: tmpList, + carNo: this.carInfo.carNo || "", + placeId: this.carInfo.examinationRoomId || "", + sendCallback: () => { + this.callBackFlag = true + } + } + CenterUDPBusinessInstance.sendData(param) + clearInterval(this.interval) + this.interval = setInterval(() => { + if (this.callBackFlag) { + const param2: UDPParamType = { + id: 47, + list: tmpList, + carNo: this.carInfo.carNo || "", + placeId: this.carInfo.examinationRoomId || "", + } + CenterUDPBusinessInstance.sendData(param2) + } + }, 1000) + CenterUDPBusinessInstance.onMsg(this.getUdpMsg) + + } + + getUdpMsg = (val: CenterCallBackMsgType) => { + if (AppStorage.get('statue') != 3) { + return + } + if (val.id === 48) { + if (val.body[13] == 1) { + this.voiceController && this.voiceController.releasePlayer() + this.controller?.close() + this.FacialComparisonFailure() + clearInterval(this.interval) + } else if (val.body[13] == 1 && this.callBackFlag) { + AppStorage.setOrCreate('statue', 2) + this.voiceController && this.voiceController.playAudio({ + type: 1, + name: 'face_chekc_fail.wav' + }) + this.controller.close() + } + } + } + + aboutToDisappear(): void { + clearInterval(this.interval) + CenterUDPBusinessInstance.offMsg(this.getUdpMsg) + } + + build() { + Column() { + Column() { + // 标题 + Row() { + Text("照片对比").fontSize(24).fontWeight(FontWeight.Bold) + }.height(80) + + // 视频图片 + Flex({ + alignItems: ItemAlign.Center, + justifyContent: FlexAlign.Center + }) { + // 视频 + Video({ + src: `rtsp://${this.videoConfig.userName}:${this.videoConfig.pwd}@${this.videoConfig.ip}:${this.videoConfig.port}/h264/ch${this.videoConfig.rlls}/main/av_stream`, + previewUri: this.previewUri, + currentProgressRate: PlaybackSpeed.Speed_Forward_1_00_X, + controller: this.videoController, + }) + .muted(true) + .autoPlay(true) + .controls(true) + .height("100%") + .width(600) + // 图片 + Row() { + Image(this.base64).height("100%").width("100%") + } + .height("100%") + .width(600) + .backgroundColor(Color.Black) + .margin({ + left: 20 + }) + }.width("100%").height(400) + + Text("正在等待拍照...").fontWeight(FontWeight.Bold).fontSize(24).margin({ + top: 20, + bottom: 20 + }).fontColor("#CC7E00") + Flex({ + justifyContent: FlexAlign.SpaceBetween, + alignItems: ItemAlign.Center + }) { + Text("若验证无响应,点击此处").fontSize(24) + Row() { + Text("重新打开").fontSize(20).fontColor("#fff") + } + .width(200) + .height(80) + .backgroundImage($r("app.media.nor")) + .backgroundImageSize({ + width: "100%", + height: "100%" + }) + .justifyContent(FlexAlign.Center) + .alignItems(VerticalAlign.Center) + .onClick(() => { + this.times = 1; + this.videoController.stop() + this.voiceController && this.voiceController.releasePlayer() + this.FacialComparisonFailure() + AppStorage.setOrCreate('statue', 2) + this.controller?.close(); + }) + }.backgroundColor("#CBC4B9").borderRadius({ + bottomLeft: 20, + bottomRight: 20 + }) + .padding({ + left: 20, + right: 20, + top: 10, + bottom: 10 + }) + }.backgroundColor("#E5E3DF").borderRadius(20) + + // 关闭按钮 + Row() { + Image($r('app.media.close')).width(80).height(80) + }.margin({ + top: 50 + }).onClick(() => { + this.FacialComparisonFailure() + this.videoController && this.videoController.stop(); + this.controller?.close(); + AppStorage.setOrCreate('statue', 2) + }) + }.width("80%") + } +} \ No newline at end of file diff --git a/entry/src/main/ets/pages/UserInfo/GetReadyToBoardTheCar.ets b/entry/src/main/ets/pages/UserInfo/GetReadyToBoardTheCar.ets new file mode 100644 index 0000000..27f2aac --- /dev/null +++ b/entry/src/main/ets/pages/UserInfo/GetReadyToBoardTheCar.ets @@ -0,0 +1,12 @@ +/** + * 上车准备弹窗 + */ + +@CustomDialog +export default struct GetReadyToBoardTheCarDialog { + private controller?: CustomDialogController; + + build() { + + } +} \ No newline at end of file diff --git a/entry/src/main/ets/pages/UserInfo/StartTheExamDialog.ets b/entry/src/main/ets/pages/UserInfo/StartTheExamDialog.ets deleted file mode 100644 index fadfcf9..0000000 --- a/entry/src/main/ets/pages/UserInfo/StartTheExamDialog.ets +++ /dev/null @@ -1,9 +0,0 @@ -// 开始考试弹窗 - -@CustomDialog -export default struct StartTheExamDialog { - private controller?: CustomDialogController; - - build() { - } -} \ No newline at end of file diff --git a/entry/src/main/ets/pages/compontents/judge/BoardPrePareSetPopup.ets b/entry/src/main/ets/pages/compontents/judge/BoardPrePareSetPopup.ets index 67c8198..7a64a25 100644 --- a/entry/src/main/ets/pages/compontents/judge/BoardPrePareSetPopup.ets +++ b/entry/src/main/ets/pages/compontents/judge/BoardPrePareSetPopup.ets @@ -559,6 +559,4 @@ export default struct DeductedPopup { } private confirmMark: Function = (itemno: number, serial: string) => { } - private endLoading: Function = () => { - } } \ No newline at end of file diff --git a/entry/src/main/ets/pages/compontents/judge/LoadingPopup.ets b/entry/src/main/ets/pages/compontents/judge/LoadingPopup.ets deleted file mode 100644 index 39edd9f..0000000 --- a/entry/src/main/ets/pages/compontents/judge/LoadingPopup.ets +++ /dev/null @@ -1,18 +0,0 @@ -@Component -export default struct LoadingPopup { - constructor() { - super() - } - - private title:string = '' - - build(){ - Column(){ - Column(){ - Image($rawfile('judge/loading-car.gif')).width(250).margin({top:20,bottom:20}) - Text(this.title).fontSize(32).margin({top:15}) - }.width('45%').height('50%').backgroundColor('#E6E3DF').borderRadius(38).position({y:'27.5%',x:'25%'}).justifyContent(FlexAlign.Center) - - }.width('100%').height('100%').position({y:0}).backgroundColor('rgba(0,0,0,0.7)') - } -} diff --git a/entry/src/main/ets/pages/compontents/judge/video-play.ets b/entry/src/main/ets/pages/compontents/judge/video-play.ets deleted file mode 100644 index f37e4dc..0000000 --- a/entry/src/main/ets/pages/compontents/judge/video-play.ets +++ /dev/null @@ -1,25 +0,0 @@ - -@Component -export default struct EndPopup { - constructor() { - super() - } - - private title:string = '' - private cancelFn:(event?: ClickEvent) => void - private confirmFn:(event?: ClickEvent) => void - - build(){ - Column(){ - Column(){ - Text(this.title).fontSize(38).margin({bottom:20}) - Row(){}.height(50) - Row(){ - Text('取消').backgroundImage($rawfile('judge/end-btn.png'),ImageRepeat.NoRepeat).backgroundImageSize({width:'100%',height:'100%'}).width(250).height(100).fontSize(30).fontColor('#FFF').textAlign(TextAlign.Center).onClick(this.cancelFn) - Text('确定').backgroundImage($rawfile('judge/end-btn.png'),ImageRepeat.NoRepeat).backgroundImageSize({width:'100%',height:'100%'}).width(250).height(100).fontSize(30).fontColor('#FFF').textAlign(TextAlign.Center).margin({left:45}).onClick(this.confirmFn) - } - }.width('80%').height('70%').backgroundColor('#E6E3DF').borderRadius(38).position({y:'12%',x:'10%'}).justifyContent(FlexAlign.Center) - - }.width('100%').height('100%').position({y:0}).backgroundColor('rgba(0,0,0,0.7)') - } -}