fix: 人脸对比窗口

This commit is contained in:
wangzhongjie 2025-07-28 16:06:15 +08:00
parent 2d912d4ea3
commit 658e59760b
8 changed files with 321 additions and 83 deletions

View File

@ -68,3 +68,6 @@ export const SignDisplayTag = '[SignDisplay]';
//开始考试 //开始考试
export const StartExamTag = '[StartExam]' export const StartExamTag = '[StartExam]'
//人脸对比
export const FaceCompareTag = '[FaceCompare]';

View File

@ -50,6 +50,7 @@ import LabelBlockComponent from './UserInfo/LabelBlock';
import CarLoadingDialog from './compontents/CarLoading'; import CarLoadingDialog from './compontents/CarLoading';
import ConfirmDialog from './compontents/ConfirmDialog'; import ConfirmDialog from './compontents/ConfirmDialog';
import { DifferentialAndSignal } from '../utils/business/DifferentialAndSignalWorker'; import { DifferentialAndSignal } from '../utils/business/DifferentialAndSignalWorker';
import FaceRecognitionDialog from './UserInfo/FaceRecognition';
@Entry @Entry
@Component @Component
@ -72,7 +73,6 @@ struct UserInfoPage {
@State isSecondBoardPrePareSetPopupOpen: boolean = false @State isSecondBoardPrePareSetPopupOpen: boolean = false
@State isFirstBoardPrePareSetPopupBtnShow: boolean = false @State isFirstBoardPrePareSetPopupBtnShow: boolean = false
@State isBoardPrePareSetPopupShow: boolean = false @State isBoardPrePareSetPopupShow: boolean = false
@State loadingText: string = '正在认证监管信息,请稍后...'
@State sczbkf: SckType[] = [] @State sczbkf: SckType[] = []
@State currentUser: User = EmptyCandidateObject @State currentUser: User = EmptyCandidateObject
// 开始考试弹窗 // 开始考试弹窗
@ -112,6 +112,16 @@ struct UserInfoPage {
customStyle: true, customStyle: true,
autoCancel: true autoCancel: true
}) })
// 人脸对比弹窗
faceCompareController: CustomDialogController = new CustomDialogController({
builder: FaceRecognitionDialog({
sfzh: this.currentUser.sfzmhm,
firstImage: this.currentUser.kszp,
lsh: AppStorage.get<string>('lsh'),
}),
customStyle: true,
autoCancel: true
})
@State faceFlag: string = '0'; @State faceFlag: string = '0';
@State FaceOpenStatue: string = '0'; //是否开启人脸识别 @State FaceOpenStatue: string = '0'; //是否开启人脸识别
@State faceCatchImg: string = '' @State faceCatchImg: string = ''
@ -490,11 +500,6 @@ struct UserInfoPage {
async initSysset() { async initSysset() {
const that = this; 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<MASYSSETTableType>("MA_SYSSET").then((syssetParams: MASYSSETTableType[]) => { GetSyncData<MASYSSETTableType>("MA_SYSSET").then((syssetParams: MASYSSETTableType[]) => {
const serialNumberArr = syssetParams.filter(sys => sys.v_no === '901') const serialNumberArr = syssetParams.filter(sys => sys.v_no === '901')
that.jkxlh = serialNumberArr?.[0]?.v_value || '' that.jkxlh = serialNumberArr?.[0]?.v_value || ''
@ -647,8 +652,6 @@ struct UserInfoPage {
dConsole.log('isFirstBoardPrePareSetPopupBtnShow', this.isFirstBoardPrePareSetPopupBtnShow, dConsole.log('isFirstBoardPrePareSetPopupBtnShow', this.isFirstBoardPrePareSetPopupBtnShow,
this.isBoardPrePareSetPopupOpen) this.isBoardPrePareSetPopupOpen)
this.startExam = false this.startExam = false
// await upDateTableByArray('USER', [])
// await upDateTableByArray('USERLIST', [])
await DB.clearTable('USER') await DB.clearTable('USER')
await DB.clearTable('USERLIST') await DB.clearTable('USERLIST')
this.updateTimeLimit = true this.updateTimeLimit = true
@ -689,7 +692,6 @@ struct UserInfoPage {
this.list.forEach((listData, index) => { this.list.forEach((listData, index) => {
//考过一次不允许切换学员 //考过一次不允许切换学员
if (listData.kssycs == '1') { if (listData.kssycs == '1') {
this.startExam = true this.startExam = true
} }
listData.id = index.toString() listData.id = index.toString()
@ -743,7 +745,6 @@ struct UserInfoPage {
} }
this.pageIndex = 0 this.pageIndex = 0
// getSyncData('USER').then(data => {
GetSyncData<User>("USER").then(data => { GetSyncData<User>("USER").then(data => {
if (data?.[0]) { if (data?.[0]) {
this.getCurrentStudent(data[0].sfzmhm) this.getCurrentStudent(data[0].sfzmhm)
@ -759,6 +760,7 @@ struct UserInfoPage {
} }
} }
// 缺考
qkFn() { qkFn() {
if (this.systemParam.Param352Str == '1' && this.currentUser.kssycs == '1') { if (this.systemParam.Param352Str == '1' && this.currentUser.kssycs == '1') {
return 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() { async getExaminationItemFn() {
if (!this.currentUser.lsh || this.singlePlay) { if (!this.currentUser.lsh || this.singlePlay) {
return return
} }
// const { carId, examinationRoomId } = this.carInfo;
const examItems = await getExaminationItem({ const examItems = await getExaminationItem({
time: GetCurrentTime() || "", time: GetCurrentTime() || "",
carId: this.carInfo.carId || "", carId: this.carInfo.carId || "",
@ -930,7 +945,6 @@ struct UserInfoPage {
//开始上车准备 //开始上车准备
prePareSCZB = async () => { prePareSCZB = async () => {
try { try {
// await this.checkSignal()
await CheckSignal(this.systemParam, this.avPlayer) await CheckSignal(this.systemParam, this.avPlayer)
DifferentialAndSignal.clearMsg() DifferentialAndSignal.clearMsg()
this.isExamStart = true this.isExamStart = true
@ -940,9 +954,7 @@ struct UserInfoPage {
}).catch((err: BusinessError) => { }).catch((err: BusinessError) => {
dConsole.log("USER insert fail", JSON.stringify(err)) dConsole.log("USER insert fail", JSON.stringify(err))
}) })
// await upDateTableByArray('USER', [this.currentUser])
dConsole.log("User", JSON.stringify(this.currentUser)) dConsole.log("User", JSON.stringify(this.currentUser))
// await sqlInsertCommonFn("USER", [this.currentUser])
AppStorage.setOrCreate('statue', 4) AppStorage.setOrCreate('statue', 4)
this.isBoardPrePareSetPopupShow = true; this.isBoardPrePareSetPopupShow = true;
this.isFirstBoardPrePareSetPopupBtnShow = true; this.isFirstBoardPrePareSetPopupBtnShow = true;
@ -1147,20 +1159,6 @@ struct UserInfoPage {
.backgroundImage($r('app.media.bg')) .backgroundImage($r('app.media.bg'))
.backgroundImageSize({ width: '100%', height: '100%' }) .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()
}
}
} }

View File

@ -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<CarInfoType>('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%")
}
}

View File

@ -0,0 +1,12 @@
/**
* 上车准备弹窗
*/
@CustomDialog
export default struct GetReadyToBoardTheCarDialog {
private controller?: CustomDialogController;
build() {
}
}

View File

@ -1,9 +0,0 @@
// 开始考试弹窗
@CustomDialog
export default struct StartTheExamDialog {
private controller?: CustomDialogController;
build() {
}
}

View File

@ -559,6 +559,4 @@ export default struct DeductedPopup {
} }
private confirmMark: Function = (itemno: number, serial: string) => { private confirmMark: Function = (itemno: number, serial: string) => {
} }
private endLoading: Function = () => {
}
} }

View File

@ -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)')
}
}

View File

@ -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)')
}
}