From e491cdb48129752324c4e3764f99bd9203c56dec Mon Sep 17 00:00:00 2001
From: lgq <1015864684@qq.com>
Date: 星期二, 31 三月 2026 09:48:44 +0800
Subject: [PATCH] 1.新增VF205门禁机代码

---
 vf205_access/src/service/faceService.js |  447 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 447 insertions(+), 0 deletions(-)

diff --git a/vf205_access/src/service/faceService.js b/vf205_access/src/service/faceService.js
new file mode 100644
index 0000000..a84aab1
--- /dev/null
+++ b/vf205_access/src/service/faceService.js
@@ -0,0 +1,447 @@
+/**
+ * 浜鸿劯璇嗗埆鏈嶅姟妯″潡
+ * 澶勭悊浜鸿劯璇嗗埆鐩稿叧鐨勪笟鍔¢�昏緫锛屽寘鎷汉鑴告敞鍐屽拰浜鸿劯姣斿
+ */
+import logger from "../../dxmodules/dxLogger.js";
+import dxCommon from "../../dxmodules/dxCommon.js";
+import bus from "../../dxmodules/dxEventBus.js";
+import dxMap from "../../dxmodules/dxMap.js";
+import driver from "../driver.js";
+import config from "../../dxmodules/dxConfig.js";
+import sqliteService from "./sqliteService.js";
+import std from "../../dxmodules/dxStd.js";
+import pool from "../../dxmodules/dxWorkerPool.js";
+
+let map = dxMap.get("LOGIN")
+const faceService = {}
+
+// 璇煶鎾斁闃叉姈鎺у埗
+let lastPlayTime = 0
+const PLAY_DELAY = 2000 // 2绉掑唴涓嶉噸澶嶆挱鏀剧浉鍚岃闊�
+
+/**
+ * 璇煶鎾斁闃叉姈鍑芥暟
+ * @param {function} playFunction - 鎾斁鍑芥暟
+ * @returns {boolean} 鏄惁鎵ц浜嗘挱鏀�
+ */
+function debouncePlay(playFunction) {
+    const now = Date.now()
+    if (now - lastPlayTime > PLAY_DELAY) {
+        lastPlayTime = now
+        playFunction()
+        return true
+    }
+    return false
+}
+
+// 鍙屼汉璁よ瘉鐘舵�佺鐞�
+let dualAuthState = {
+    firstUserId: null, // 绗竴涓敤鎴稩D
+    firstUserName: null, // 绗竴涓敤鎴峰鍚�
+    firstUserFileName: null, // 绗竴涓敤鎴蜂汉鑴稿浘鐗囨枃浠惰矾寰�
+    firstUserIdCard: null, // 绗竴涓敤鎴疯韩浠借瘉鍙�
+    firstUserType: null, // 绗竴涓敤鎴疯韩浠界被鍨�
+    secondUserId: null, // 绗簩涓敤鎴稩D
+    secondUserName: null, // 绗簩涓敤鎴峰鍚�
+    secondUserIdCard: null, // 绗簩涓敤鎴疯韩浠借瘉鍙�
+    secondUserType: null, // 绗簩涓敤鎴疯韩浠界被鍨�
+    startTime: 0, // 寮�濮嬫椂闂�
+    timeout: null, // 瀹氭椂鍣�
+    authComplete: false // 璁よ瘉鏄惁瀹屾垚
+}
+
+/**
+ * 鎺ユ敹浜鸿劯璇嗗埆娑堟伅骞跺鐞�
+ * @param {object} data - 浜鸿劯璇嗗埆鏁版嵁
+ */
+faceService.receiveMsg = function (data) {
+    logger.info('[faceService] receiveMsg :' + JSON.stringify(data))
+    // 瑙﹀彂閫�鍑虹┖闂茬姸鎬佷簨浠讹紙閿佸睆鍜屾伅灞忥級
+    bus.fire("exitIdle")
+
+    switch (data.type) {
+        case "register":
+            // 娉ㄥ唽浜鸿劯澶勭悊
+            for (let i = 0; i < data.faces.length; i++) {
+                const element = data.faces[i];
+                bus.fire("beginAddFace", element)
+            }
+            break;
+        case "compare":
+            // 浜鸿劯姣斿澶勭悊
+            // 鏄剧ず濮撳悕锛屼唬琛ㄦ湁娉ㄥ唽杩囦汉鑴革紝浣嗘槸鏉冮檺涓嶄竴瀹氭湁鏁堬紝闇�瑕佽繘涓�姝ヨ璇�
+            for (let i = 0; i < data.faces.length; i++) {
+                const element = data.faces[i];
+                
+                // 鍙湁鍦ㄨ璇佹湭瀹屾垚鏃舵墠瑙﹀彂trackResult浜嬩欢
+                if (!dualAuthState.authComplete) {
+                    // 鍒ゆ柇褰撳墠鏄鍑犱釜鐢ㄦ埛锛堢敤浜庡弻浜鸿璇侊級
+                    let userIndex = 1 // 0琛ㄧず鏈煡锛�1琛ㄧず绗竴涓敤鎴凤紝2琛ㄧず绗簩涓敤鎴�
+                    if (!dualAuthState.firstUserId) {
+                        // 绗竴涓敤鎴疯繕鏈缃紝褰撳墠鐢ㄦ埛灏辨槸绗竴涓敤鎴�
+                        userIndex = 1
+                    } else if (element.userId === dualAuthState.firstUserId) {
+                        userIndex = 1
+                    } else if (element.userId !== dualAuthState.firstUserId) {
+                        userIndex = 2
+                    }
+                    
+                    logger.info('[faceService]: 鍑嗗瑙﹀彂trackResult浜嬩欢, userIndex=' + userIndex + ', result=' + element.result + ', userId=' + element.userId + ', authComplete=' + dualAuthState.authComplete + ', fileName=' + element.fileName)
+                    
+                    // 鐩存帴浣跨敤bus.fire瑙﹀彂trackResult浜嬩欢
+                    bus.fire("trackResult", { id: element.id, result: element.result, userId: element.userId, userIndex: userIndex, fileName: element.fileName })
+                }
+                
+                if (element.result) {
+                    // 浜鸿劯鐩镐技搴﹂獙璇侀�氳繃
+                    let ret = sqliteService.d1_person.find({ userId: element.userId })
+                    
+                    if (dxMap.get("UI").get("faceAuthStart") == "Y") {
+                        // 姝e湪浜鸿劯鐧诲綍
+                        if (JSON.parse(ret[0].extra).type != 0) {
+                            bus.fire("faceAuthResult", true)
+                        } else {
+                            bus.fire("faceAuthResult", false)
+                        }
+                        return
+                    }
+
+                    // 妫�鏌ョ敤鎴风被鍨嬶紙绠$悊鍛樼骇鍒級
+                    let userType = 0
+                    try {
+                        userType = JSON.parse(ret[0].extra).type || 0
+                    } catch (error) {
+                        logger.error("瑙f瀽鐢ㄦ埛绫诲瀷澶辫触")
+                    }
+
+                    // 绠$悊鍛樼骇鍒敤鎴凤紙type != 0锛夌洿鎺ヨ璇侀�氳繃
+                    if (userType != 0) {
+                        // 娓呴櫎鍙屼汉璁よ瘉鐘舵��
+                        clearDualAuthState()
+                        
+                        // 鏍规嵁璇煶妯″紡鎾斁鐩稿簲鐨勮闊�
+                        switch (config.get("face.voiceMode")) {
+                            case 0:
+                                // 鏃犺闊�
+                                break;
+                            case 1:
+                                // 鎾斁鍚嶅瓧
+                                driver.alsa.ttsPlay(ret[0].name)
+                                break;
+                            case 2:
+                                // 鎾斁闂�欒
+                                driver.alsa.ttsPlay(config.get("face.voiceModeDate") ? config.get("face.voiceModeDate") : "娆㈣繋鍏変复")
+                                break;
+                            default:
+                                break;
+                        }
+
+                        // 閫氳璁よ瘉澶勭悊
+                        bus.fire("access", { data: { type: "300", code: element.userId }, fileName: element.fileName })
+                    } else {
+                        // 闈炵鐞嗗憳绾у埆鐢ㄦ埛锛岄渶瑕佸弻浜鸿璇�
+                        handleDualAuth(element.userId, ret[0].name, element.fileName)
+                    }
+                } else {
+                    // 浜鸿劯鐩镐技搴﹂獙璇佸け璐�
+                    if (dxMap.get("UI").get("faceAuthStart") == "Y") {
+                        // 浜鸿劯鐧诲綍澶辫触
+                        bus.fire("faceAuthResult", false)
+                    } else {
+                        // 闄岀敓浜哄鐞�
+                        switch (config.get("face.stranger")) {
+                            case 0:
+                                // 鏃犺闊�
+                                break;
+                            case 1:
+                                // 鎾斁璇峰厛娉ㄥ唽锛堥槻鎶栨帶鍒讹級
+                                debouncePlay(() => {
+                                    driver.alsa.play(`/app/code/resource/${config.get("base.language") == "CN" ? "CN" : "EN"}/wav/register.wav`)
+                                })
+                                break;
+                            case 2:
+                                // 鎾斁闄岀敓浜轰綘濂斤紙闃叉姈鎺у埗锛�
+                                debouncePlay(() => {
+                                    driver.alsa.play(`/app/code/resource/${config.get("base.language") == "CN" ? "CN" : "EN"}/wav/stranger.wav`)
+                                })
+                                break;
+                            default:
+                                break;
+                        }
+                        // 閫氳璁よ瘉澶勭悊锛堢浉浼煎害楠岃瘉澶辫触锛�
+                        bus.fire("access", { data: { type: "300", code: element.userId }, fileName: element.fileName, similarity: false })
+                    }
+                }
+            }
+            break;
+        default:
+            break;
+    }
+}
+
+// 鐩戝惉閫氳瑙i攣瀹屾垚浜嬩欢锛岄噸缃弻浜鸿璇佺姸鎬�
+bus.on('accessUnlockComplete', () => {
+    logger.info('[faceService]: accessUnlockComplete浜嬩欢瑙﹀彂锛岄噸缃弻浜鸿璇佺姸鎬�')
+    clearDualAuthState()
+})
+
+/**
+ * 娓呴櫎鍙屼汉璁よ瘉鐘舵��
+ */
+function clearDualAuthState() {
+    dualAuthState.firstUserId = null
+    dualAuthState.firstUserName = null
+    dualAuthState.firstUserFileName = null
+    dualAuthState.firstUserIdCard = null
+    dualAuthState.firstUserType = null
+    dualAuthState.secondUserId = null
+    dualAuthState.secondUserName = null
+    dualAuthState.secondUserIdCard = null
+    dualAuthState.secondUserType = null
+    dualAuthState.startTime = 0
+    dualAuthState.authComplete = false // 閲嶇疆璁よ瘉瀹屾垚鏍囧織
+    if (dualAuthState.timeout) {
+        std.clearTimeout(dualAuthState.timeout)
+        dualAuthState.timeout = null
+    }
+}
+
+/**
+ * 澶勭悊鍙屼汉璁よ瘉瓒呮椂
+ */
+function handleDualAuthTimeout() {
+    try {
+        // 淇濆瓨璁よ瘉璁板綍
+        if (dualAuthState.firstUserId && !dualAuthState.authComplete) {
+            // 鏌ヨ绗竴鐢ㄦ埛鐨勮缁嗕俊鎭紝鑾峰彇韬唤绫诲瀷
+            let firstUserType = dualAuthState.firstUserType || 0
+            if (!firstUserType) {
+                let res = sqliteService.d1_person.findByUserId(dualAuthState.firstUserId)
+                if (res.length > 0) {
+                    try {
+                        firstUserType = JSON.parse(res[0].extra).type || 0
+                    } catch (error) {
+                        logger.error("鏃犵涓�鐢ㄦ埛绫诲瀷")
+                    }
+                }
+            }
+            
+            // 鏌ヨ绗簩鐢ㄦ埛鐨勮缁嗕俊鎭紝鑾峰彇韬唤绫诲瀷
+            let secondUserType = dualAuthState.secondUserType || 0
+            if (dualAuthState.secondUserId && !secondUserType) {
+                let res = sqliteService.d1_person.findByUserId(dualAuthState.secondUserId)
+                if (res.length > 0) {
+                    try {
+                        secondUserType = JSON.parse(res[0].extra).type || 0
+                    } catch (error) {
+                        logger.error("鏃犵浜岀敤鎴风被鍨�")
+                    }
+                }
+            }
+            
+            // 鍒涘缓璁よ瘉璁板綍
+            const record = {
+                id: std.genRandomStr(16),
+                userId: dualAuthState.firstUserId,
+                userId2: dualAuthState.secondUserId || "",
+                type: "300", // 浜鸿劯璁よ瘉锛堝瓧绗︿覆鏍煎紡锛�
+                code: dualAuthState.firstUserFileName, // 浜鸿劯鎶撴媿鍥剧墖璺緞
+                result: 1, // 璁よ瘉澶辫触锛�0鎴愬姛锛�1澶辫触锛�
+                time: Math.floor(Date.now() / 1000), // 鏃堕棿鎴筹紙绉掞級
+                message: "鍙屼汉璁よ瘉瓒呮椂",
+                extra: JSON.stringify({ name: dualAuthState.firstUserName, idCard: dualAuthState.firstUserIdCard, type: firstUserType }),
+                extra2: dualAuthState.secondUserId ? JSON.stringify({ name: dualAuthState.secondUserName || "", idCard: dualAuthState.secondUserIdCard || "", type: secondUserType }) : "",
+                permissionId: firstUserType.toString(),
+                permissionId2: dualAuthState.secondUserId ? secondUserType.toString() : ""
+            }
+            
+            // 淇濆瓨鍒版暟鎹簱
+            sqliteService.d1_pass_record.save(record)
+            logger.info(`[faceService]: 淇濆瓨鍙屼汉璁よ瘉瓒呮椂璁板綍: ${JSON.stringify(record)}`)
+        }
+        
+        // 娓呴櫎璁よ瘉鐘舵��
+        clearDualAuthState()
+        
+        // 鎾斁澶辫触鎻愮ず闊�
+        driver.alsa.play(`/app/code/resource/${config.get("base.language") == "CN" ? "CN" : "EN"}/wav/verify_300_f.wav`)
+        
+        // 璇煶鎻愮ず璁よ瘉澶辫触
+        // driver.alsa.ttsPlay("鍙屼汉璁よ瘉瓒呮椂锛岃璇佸け璐�")
+        
+        // 瑙﹀彂璁よ瘉澶辫触浜嬩欢
+        bus.fire("showAccessResult", {
+            faceAuth: false,
+            gasConcentration: true,
+            accessAllowed: false,
+            message: "*鍙屼汉璁よ瘉瓒呮椂锛岃璇佸け璐�*"
+        })
+        
+        // 瑙﹀彂閫氳澶辫触浜嬩欢锛岄�氱煡UI閲嶇疆
+        bus.fire("accessRes", false)
+        
+
+    } catch (error) {
+        logger.error(`[faceService]: 澶勭悊鍙屼汉璁よ瘉瓒呮椂閿欒: ${error.message}`)
+    }
+}
+
+/**
+ * 澶勭悊鍙屼汉璁よ瘉閫昏緫
+ * @param {string} userId - 褰撳墠鐢ㄦ埛ID
+ * @param {string} userName - 褰撳墠鐢ㄦ埛濮撳悕
+ * @param {string} fileName - 浜鸿劯鍥剧墖鏂囦欢璺緞
+ */
+function handleDualAuth(userId, userName, fileName) {
+    try {
+        if (!dualAuthState.firstUserId) {
+            // 绗竴娆¤璇�
+            dualAuthState.firstUserId = userId
+            dualAuthState.firstUserName = userName
+            dualAuthState.firstUserFileName = fileName
+            
+            // 鏌ヨ绗竴鐢ㄦ埛鐨勮缁嗕俊鎭紝鑾峰彇韬唤璇佸彿鍜岃韩浠界被鍨�
+            let res = sqliteService.d1_person.findByUserId(userId)
+            if (res.length > 0) {
+                let idCard
+                let userType = 0
+                try {
+                    idCard = JSON.parse(res[0].extra).idCard
+                    userType = JSON.parse(res[0].extra).type || 0
+                } catch (error) {
+                    logger.error("鏃犵涓�鐢ㄦ埛韬唤璇佸彿鎴栫被鍨�")
+                }
+                dualAuthState.firstUserIdCard = idCard
+                dualAuthState.firstUserType = userType
+            }
+            
+            dualAuthState.startTime = Date.now()
+            
+            // 娓呴櫎涔嬪墠鐨勫畾鏃跺櫒
+            if (dualAuthState.timeout) {
+                std.clearTimeout(dualAuthState.timeout)
+            }
+            
+            // 璁剧疆1鍒嗛挓瓒呮椂
+            dualAuthState.timeout = std.setTimeout(() => {
+                // 瓒呮椂澶勭悊锛岃涓鸿璇佸け璐�
+                handleDualAuthTimeout()
+            }, 60000)
+            
+            // 璇煶鎻愮ず-璇风浜岀敤鎴疯繘琛岃璇�
+            driver.alsa.play(`/app/code/resource/${config.get("base.language") == "CN" ? "CN" : "EN"}/wav/user2.wav`)
+        } else {
+            // 绗簩娆¤璇�
+            if (userId !== dualAuthState.firstUserId) {
+                // 涓嶅悓鐢ㄦ埛锛岃璇侀�氳繃
+                // 鏌ヨ绗簩鐢ㄦ埛鐨勮缁嗕俊鎭紝鑾峰彇韬唤璇佸彿鍜岃韩浠界被鍨�
+                let secondUserIdCard = ""
+                let secondUserType = 0
+                let res = sqliteService.d1_person.findByUserId(userId)
+                if (res.length > 0) {
+                    try {
+                        secondUserIdCard = JSON.parse(res[0].extra).idCard
+                        secondUserType = JSON.parse(res[0].extra).type || 0
+                    } catch (error) {
+                        logger.error("鏃犵浜岀敤鎴疯韩浠借瘉鍙锋垨绫诲瀷")
+                    }
+                }
+                
+                // 淇濆瓨鍙屼汉璁よ瘉鐘舵�佷俊鎭紝鐢ㄤ簬UI鏇存柊
+                let dualAuthInfo = {
+                    firstUserId: dualAuthState.firstUserId,
+                    firstUserName: dualAuthState.firstUserName,
+                    secondUserId: userId,
+                    secondUserName: userName,
+                    secondUserIdCard: secondUserIdCard,
+                    secondUserType: secondUserType
+                }
+                // 淇濆瓨绗竴鐢ㄦ埛鐨勪汉鑴稿浘鐗囪矾寰�
+                let firstUserFileName = dualAuthState.firstUserFileName
+                // 璁剧疆璁よ瘉瀹屾垚鏍囧織
+                dualAuthState.authComplete = true
+                clearDualAuthState()
+                
+                // 璇煶鎻愮ず-鍙屼汉璁よ瘉閫氳繃
+                driver.alsa.play(`/app/code/resource/${config.get("base.language") == "CN" ? "CN" : "EN"}/wav/user2_s.wav`)
+                
+                // 閫氳璁よ瘉澶勭悊锛屼紶閫掑弻浜鸿璇佷俊鎭�
+                bus.fire("access", { data: { type: "300", code: userId, dualAuthInfo: dualAuthInfo, authComplete: true, firstUserFileName: firstUserFileName }, fileName: fileName })
+            } else {
+                // 鍚屼竴鐢ㄦ埛锛岄噸鏂板紑濮�
+                dualAuthState.firstUserId = userId
+                dualAuthState.firstUserName = userName
+                
+                // 鏌ヨ鐢ㄦ埛鐨勮缁嗕俊鎭紝鑾峰彇韬唤璇佸彿鍜岃韩浠界被鍨�
+                let idCard
+                let userType = 0
+                let res = sqliteService.d1_person.findByUserId(userId)
+                if (res.length > 0) {
+                    try {
+                        idCard = JSON.parse(res[0].extra).idCard
+                        userType = JSON.parse(res[0].extra).type || 0
+                    } catch (error) {
+                        logger.error("鏃犵敤鎴疯韩浠借瘉鍙锋垨绫诲瀷")
+                    }
+                    dualAuthState.firstUserIdCard = idCard
+                    dualAuthState.firstUserType = userType
+                }
+                
+                dualAuthState.startTime = Date.now()
+                
+                // 娓呴櫎涔嬪墠鐨勫畾鏃跺櫒
+                if (dualAuthState.timeout) {
+                    std.clearTimeout(dualAuthState.timeout)
+                }
+                
+                // 閲嶆柊璁剧疆1鍒嗛挓瓒呮椂
+                dualAuthState.timeout = std.setTimeout(() => {
+                    // 瓒呮椂澶勭悊锛岃涓鸿璇佸け璐�
+                    handleDualAuthTimeout()
+                }, 60000)
+                
+                // 璇煶鎻愮ず-璇风浜岀敤鎴疯繘琛岃璇�
+                driver.alsa.play(`/app/code/resource/${config.get("base.language") == "CN" ? "CN" : "EN"}/wav/user2.wav`)
+            }
+        }
+    } catch (error) {
+        logger.error(`[faceService]: 澶勭悊鍙屼汉璁よ瘉閿欒: ${error.message}`)
+        // 娓呴櫎璁よ瘉鐘舵��
+        clearDualAuthState()
+    }
+}
+/**
+ * 浜鸿劯娉ㄥ唽閿欒鏋氫妇
+ * 鍖呭惈鍚勭娉ㄥ唽澶辫触鐨勯敊璇爜鍜屽搴旂殑閿欒淇℃伅
+ */
+faceService.regErrorEnum = {
+    "callback": {
+        title: "娉ㄥ唽鍥炶皟鐘舵�佹灇涓�",
+        "-1": "faceService.contrastFailure",        // 瀵规瘮澶辫触
+        "-2": "faceService.scalingFailure",         // 缂╂斁澶辫触
+        "-3": "faceService.failedToSavePicture",    // 淇濆瓨鍥剧墖澶辫触
+        "-4": "faceService.convertToBase64Fail",    // 杞崲涓篵ase64澶辫触
+    },
+    "feature": {
+        title: "鐗瑰緛鍊兼敞鍐岀姸鎬佹灇涓�",
+        "-1": "faceService.base64DecodingFail",     // base64瑙g爜澶辫触
+        "-10": "faceService.contrastFailure",       // 瀵规瘮澶辫触
+        "-11": "faceService.similarityOverheight",  // 鐩镐技搴﹁繃楂�
+    },
+    "picture": {
+        title: "鍥剧墖娉ㄥ唽鐘舵�佹灇涓�",
+        "-1": "faceService.fileDoesNotExist",               // 鏂囦欢涓嶅瓨鍦�
+        "-2": "faceService.theImageFormatIsNotSupported",    // 鍥剧墖鏍煎紡涓嶆敮鎸�
+        "-3": "faceService.pictureReadFailure",              // 鍥剧墖璇诲彇澶辫触
+        "-4": "faceService.thePictureSizeDoesNotMatch",      // 鍥剧墖灏哄涓嶅尮閰�
+        "-5": "faceService.imageParsingFailure",             // 鍥剧墖瑙f瀽澶辫触
+        "-6": "faceService.imageYUVProcessingFailed",        // 鍥剧墖YUV澶勭悊澶辫触
+        "-7": "faceService.failedToConvertJpegToImage",      // JPEG杞崲涓哄浘鐗囧け璐�
+        "-8": "faceService.faceInformationExtractionFailed", // 浜鸿劯淇℃伅鎻愬彇澶辫触
+        "-9": "faceService.theFaceIsNotUnique",              // 浜鸿劯涓嶅敮涓�
+        "-10": "faceService.contrastFailure",                // 瀵规瘮澶辫触
+        "-11": "faceService.similarityOverheight",           // 鐩镐技搴﹁繃楂�
+    }
+}
+
+export default faceService
\ No newline at end of file

--
Gitblit v1.9.3