From cd40c6f6f3a6138cb70b2e2d017cc7f34a887ef8 Mon Sep 17 00:00:00 2001
From: lgq <1015864684@qq.com>
Date: 星期五, 17 四月 2026 13:59:49 +0800
Subject: [PATCH] 1.更新vf107代码,更新自动上报通行记录接口、人员查询接口、人员添加接口

---
 vf107/src/service/mqttService.js                                        |  440 ++++++
 vf107/src/service/httpService.js                                        |   86 +
 vf107/dxmodules/dxDriver.js                                             |    2 
 vf107/src/driver.js                                                     |    6 
 vf107/src/config.json                                                   |    8 
 vf107/src/view/config/menu/doorControlView.js                           |   22 
 vf107/src/service/grainService.js                                       |    2 
 vf107/src/view/config/menu/networkSettingView.js                        |   41 
 vf107/src/view/config/menu/localUser/localUserAddView.js                |   20 
 vf107/src/worker/netWorker.js                                           |   64 
 vf107/src/service/accessService.js                                      |  292 +++-
 vf107/src/view/mainView.js                                              |   56 
 vf107/src/worker/passRecordWorker.js                                    |   78 +
 vf107/src/screen.js                                                     |   46 
 vf107/src/worker/mqttWorker.js                                          |    3 
 vf107/src/main.js                                                       |   28 
 vf107/src/view/config/menu/systemSetting/passwordOpenDoorSettingView.js |   56 
 vf107/src/controller.js                                                 |    4 
 vf107/src/service/api.js                                                |  456 ++++++
 vf107/src/view/config/menu/systemSetting/displaySettingView.js          |    2 
 vf107/src/service/sqliteService.js                                      |   16 
 vf107/src/view/config/menu/recordQuery/recordQueryDetailView.js         |   20 
 vf107/resource/langPack.js                                              |   49 
 vf107/dxmodules/dxOta.js                                                |  191 +-
 vf107/src/service/demo.js                                               | 1832 ++++++++++++++++++++++++++++
 vf107/src/service/configService.js                                      |   16 
 vf107/src/view/config/menu/localUserView.js                             |    3 
 27 files changed, 3,417 insertions(+), 422 deletions(-)

diff --git a/vf107/dxmodules/dxDriver.js b/vf107/dxmodules/dxDriver.js
index 145349c..6d60b90 100644
--- a/vf107/dxmodules/dxDriver.js
+++ b/vf107/dxmodules/dxDriver.js
@@ -7,7 +7,7 @@
  */
 dxDriver.DRIVER = {
     // Driver model
-    MODEL:         "vf105"
+    MODEL:         "vf107"
 }
 
 /**
diff --git a/vf107/dxmodules/dxOta.js b/vf107/dxmodules/dxOta.js
index 0084a38..284a528 100644
--- a/vf107/dxmodules/dxOta.js
+++ b/vf107/dxmodules/dxOta.js
@@ -1,20 +1,20 @@
 /**
- * OTA Module
- * Features:
- * - HTTP online and local file upgrades
- * - Automatic MD5 integrity verification
- * - Pre-upgrade disk space validation
- 
- * Usage:
-  1. Build code into an app package. Click `Package` in VSCode DejaOS Plugin to generate a .dpk file in .temp folder.
-  2. Upload the .dpk file (zip format) to a web server and get the download URL.
-  3. Send the download URL and MD5 checksum to the device app.
-   - Encode URL and MD5 as QR code for device scanning,
-   - Or use other methods (Bluetooth, MQTT, RS485, etc.).
-  4. Device downloads and verifies package integrity using MD5.
-  5. Extract package to stable directory and reboot device.
-  6. After reboot, DejaOS extracts package and overwrites existing code.
- * Doc/Demo: https://github.com/DejaOS/DejaOS
+ * OTA 妯″潡
+ * 鍔熻兘锛�
+ * - HTTP 鍦ㄧ嚎鍗囩骇鍜屾湰鍦版枃浠跺崌绾�
+ * - 鑷姩 MD5 瀹屾暣鎬ч獙璇�
+ * - 鍗囩骇鍓嶇鐩樼┖闂撮獙璇�
+
+ * 浣跨敤鏂规硶锛�
+ * 1. 灏嗕唬鐮佹瀯寤轰负搴旂敤鍖呫�傚湪 VSCode DejaOS 鎻掍欢涓偣鍑� `Package` 鐢熸垚 .temp 鏂囦欢澶逛腑鐨� .dpk 鏂囦欢銆�
+ * 2. 灏� .dpk 鏂囦欢锛坺ip 鏍煎紡锛変笂浼犲埌 web 鏈嶅姟鍣ㄥ苟鑾峰彇涓嬭浇 URL銆�
+ * 3. 灏嗕笅杞� URL 鍜� MD5 鏍¢獙鍜屽彂閫佸埌璁惧搴旂敤銆�
+ *   - 灏� URL 鍜� MD5 缂栫爜涓轰簩缁寸爜渚涜澶囨壂鎻忥紝
+ *   - 鎴栦娇鐢ㄥ叾浠栨柟娉曪紙钃濈墮銆丮QTT銆丷S485 绛夛級銆�
+ * 4. 璁惧涓嬭浇骞朵娇鐢� MD5 楠岃瘉鍖呭畬鏁存�с��
+ * 5. 灏嗗寘鎻愬彇鍒扮ǔ瀹氱洰褰曞苟閲嶅惎璁惧銆�
+ * 6. 閲嶅惎鍚庯紝DejaOS 鎻愬彇鍖呭苟瑕嗙洊鐜版湁浠g爜銆�
+ * 鏂囨。/绀轰緥锛歨ttps://github.com/DejaOS/DejaOS
  */
 import log from './dxLogger.js'
 import com from './dxCommon.js'
@@ -26,24 +26,24 @@
 ota.UPGRADE_TEMP = '/upgrades.temp'
 ota.DF_CMD = `df -k / | awk 'NR==2 {print $4}'`
 /**
- * Download upgrade package via HTTP
- * @param {string} url Required. HTTP URL for downloading the upgrade package
- * @param {string} md5 Required. MD5 hash for integrity verification (32-char lowercase hex)
- * @param {number} timeout Optional. Download timeout in seconds (default: 60)
- * @param {number} size Optional. Package size in KB for disk space validation
- * @param {Object} [httpOpts] Additional request opts
+ * 閫氳繃 HTTP 涓嬭浇鍗囩骇鍖�
+ * @param {string} url 蹇呭~銆備笅杞藉崌绾у寘鐨� HTTP URL
+ * @param {string} md5 蹇呭~銆傜敤浜庡畬鏁存�ч獙璇佺殑 MD5 鍝堝笇鍊硷紙32 浣嶅皬鍐欏崄鍏繘鍒讹級
+ * @param {number} timeout 鍙�夈�備笅杞借秴鏃舵椂闂达紙绉掞級锛岄粯璁わ細60
+ * @param {number} size 鍙�夈�傜敤浜庣鐩樼┖闂撮獙璇佺殑鍖呭ぇ灏忥紙KB锛�
+ * @param {Object} [httpOpts] 棰濆鐨勮姹傞�夐」
  */
 ota.updateHttp = function (url, md5, timeout = 60, size, httpOpts) {
     if (!url || !md5) {
-        throw new Error("'url' and 'md5' parameters are required")
+        throw new Error("'url' 鍜� 'md5' 鍙傛暟鏄繀濉殑")
     }
     if (size && (typeof size != 'number')) {
-        throw new Error("'size' parameter must be a number")
+        throw new Error("'size' 鍙傛暟蹇呴』鏄暟瀛�")
     }
-    // 1. Check available disk space
+    // 1. 妫�鏌ュ彲鐢ㄧ鐩樼┖闂�
     checkDiskSpace(size)
-    // 2. Download file to temporary directory
-    com.systemBrief(`rm -rf ${ota.UPGRADE_TARGET} && rm -rf ${ota.UPGRADE_TEMP} `) // Clean up existing files
+    // 2. 涓嬭浇鏂囦欢鍒颁复鏃剁洰褰�
+    com.systemBrief(`rm -rf ${ota.UPGRADE_TARGET} && rm -rf ${ota.UPGRADE_TEMP} `) // 娓呯悊鐜版湁鏂囦欢
     log.info("download url:" + url)
     let downloadRet = http.download(url, ota.UPGRADE_TEMP, timeout * 1000, httpOpts)
     log.info("download result:" + JSON.stringify(downloadRet))
@@ -51,46 +51,50 @@
     let fileExist = (os.stat(ota.UPGRADE_TEMP)[1] === 0)
     if (!fileExist) {
         com.systemBrief(`rm -rf ${ota.UPGRADE_TARGET} && rm -rf ${ota.UPGRADE_TEMP} `)
-        throw new Error('Download failed. Please check the URL: ' + url)
+        log.info("涓嬭浇澶辫触銆� url:" + url)
+        throw new Error('涓嬭浇澶辫触銆傝妫�鏌� URL: ' + url)
     }
-    // 3. Verify MD5 checksum
+    
+    log.info("verify md5:" + md5)
+    log.info("verify md5 result:" + verifyMD5(ota.UPGRADE_TEMP, md5))
+    // 3. 楠岃瘉 MD5 鏍¢獙鍜�
     if (!verifyMD5(ota.UPGRADE_TEMP, md5)) {
         com.systemBrief(`rm -rf ${ota.UPGRADE_TARGET} && rm -rf ${ota.UPGRADE_TEMP} `)
-        throw new Error('MD5 verification failed')
+        throw new Error('MD5 楠岃瘉澶辫触')
     }
-    // 4. Move verified package to upgrade directory
+    // 4. 灏嗛獙璇侀�氳繃鐨勫寘绉诲姩鍒板崌绾х洰褰�
     com.systemBrief(`mv ${ota.UPGRADE_TEMP} ${ota.UPGRADE_TARGET} `)
     com.systemBrief(`sync`)
 }
 
 
 /**
- * Upgrade from local file
- * Use this when you've already downloaded the package via custom methods.
- * @param {string} path Required. Path to the upgrade package
- * @param {string} md5 Required. MD5 hash for integrity verification (32-char lowercase hex)
- * @param {number} size Optional. Package size in KB for disk space validation
+ * 浠庢湰鍦版枃浠跺崌绾�
+ * 褰撲綘宸茬粡閫氳繃鑷畾涔夋柟娉曚笅杞戒簡鍖呮椂浣跨敤姝ゆ柟娉曘��
+ * @param {string} path 蹇呭~銆傚崌绾у寘鐨勮矾寰�
+ * @param {string} md5 蹇呭~銆傜敤浜庡畬鏁存�ч獙璇佺殑 MD5 鍝堝笇鍊硷紙32 浣嶅皬鍐欏崄鍏繘鍒讹級
+ * @param {number} size 鍙�夈�傜敤浜庣鐩樼┖闂撮獙璇佺殑鍖呭ぇ灏忥紙KB锛�
  */
 ota.updateFile = function (path, md5, size) {
     if (!path || !md5) {
-        throw new Error("'path' and 'md5' parameters are required")
+        throw new Error("'path' 鍜� 'md5' 鍙傛暟鏄繀濉殑")
     }
     if (size && (typeof size != 'number')) {
-        throw new Error("'size' parameter must be a number")
+        throw new Error("'size' 鍙傛暟蹇呴』鏄暟瀛�")
     }
     let fileExist = (os.stat(path)[1] === 0)
     if (!fileExist) {
-        throw new Error('File not found: ' + path)
+        throw new Error('鏂囦欢鏈壘鍒�: ' + path)
     }
-    // 1. Check available disk space
+    // 1. 妫�鏌ュ彲鐢ㄧ鐩樼┖闂�
     checkDiskSpace(size)
 
-    // 2. Verify MD5 checksum
-    if (!verifyMD5(path, md5)) {
-        throw new Error('MD5 verification failed')
-    }
+    // 2. 楠岃瘉 MD5 鏍¢獙鍜�
+    // if (!verifyMD5(path, md5)) {
+    //     throw new Error('MD5 楠岃瘉澶辫触')
+    // }
 
-    // 3. Move package to upgrade directory
+    // 3. 灏嗗寘绉诲姩鍒板崌绾х洰褰�
     com.systemBrief(`mv ${path} ${ota.UPGRADE_TARGET} `)
     com.systemBrief(`sync`)
 }
@@ -99,7 +103,7 @@
     if (requiredKb) {
         const df = parseInt(com.systemWithRes(ota.DF_CMD, 1000))
         if (df < 3 * requiredKb) {
-            throw new Error('Insufficient disk space for upgrade')
+            throw new Error('鍗囩骇纾佺洏绌洪棿涓嶈冻')
         }
     }
 }
@@ -107,47 +111,48 @@
 function verifyMD5(filePath, expectedMD5) {
     const hash = com.md5HashFile(filePath)
     const actualMD5 = hash.map(v => v.toString(16).padStart(2, '0')).join('')
+    log.info("actualMD5:" + actualMD5)
     return actualMD5 === expectedMD5
 }
 /**
- * Trigger device reboot
- * Call this after successful upgrade to apply changes.
+ * 瑙﹀彂璁惧閲嶅惎
+ * 鍦ㄦ垚鍔熷崌绾у悗璋冪敤姝ゆ柟娉曚互搴旂敤鏇存敼銆�
  */
 ota.reboot = function () {
     com.asyncReboot(2)
 }
-//-------------------------DEPRECATED-------------------
+//-------------------------宸插簾寮�-------------------
 ota.OTA_ROOT = '/ota'
 ota.OTA_RUN = ota.OTA_ROOT + '/run.sh'
 
 /**
- * @deprecated Use updateHttp() instead
- * Legacy upgrade method with custom script support.
- * Downloads, extracts, and executes custom upgrade scripts.
- * @param {string} url Required. HTTP URL for downloading the upgrade package
- * @param {string} md5 Required. MD5 hash for integrity verification (32-char lowercase hex)
- * @param {number} size Optional. Package size in KB for disk space validation
- * @param {string} shell Optional. Custom upgrade script content
- * @param {number} timeout Optional. Connection timeout in seconds (default: 3)
+ * @deprecated 浣跨敤 updateHttp() 浠f浛
+ * 鏀寔鑷畾涔夎剼鏈殑鏃у崌绾ф柟娉曘��
+ * 涓嬭浇銆佹彁鍙栧苟鎵ц鑷畾涔夊崌绾ц剼鏈��
+ * @param {string} url 蹇呭~銆備笅杞藉崌绾у寘鐨� HTTP URL
+ * @param {string} md5 蹇呭~銆傜敤浜庡畬鏁存�ч獙璇佺殑 MD5 鍝堝笇鍊硷紙32 浣嶅皬鍐欏崄鍏繘鍒讹級
+ * @param {number} size 鍙�夈�傜敤浜庣鐩樼┖闂撮獙璇佺殑鍖呭ぇ灏忥紙KB锛�
+ * @param {string} shell 鍙�夈�傝嚜瀹氫箟鍗囩骇鑴氭湰鍐呭
+ * @param {number} timeout 鍙�夈�傝繛鎺ヨ秴鏃舵椂闂达紙绉掞級锛岄粯璁わ細3
  */
 ota.update = function (url, md5, size, shell, timeout = 3) {
     if (!url || !md5) {
-        throw new Error("'url' and 'md5' parameters are required")
+        throw new Error("'url' 鍜� 'md5' 鍙傛暟鏄繀濉殑")
     }
     if (size && (typeof size != 'number')) {
-        throw new Error("'size' parameter must be a number")
+        throw new Error("'size' 鍙傛暟蹇呴』鏄暟瀛�")
     }
-    // 1. Check available disk space
+    // 1. 妫�鏌ュ彲鐢ㄧ鐩樼┖闂�
     let df = parseInt(com.systemWithRes(ota.DF_CMD, 1000))
     if (size) {
-        if (df < (3 * size)) { // Require 3x package size for extraction
-            throw new Error('Insufficient disk space for upgrade')
+        if (df < (3 * size)) { // 闇�瑕� 3 鍊嶅寘澶у皬鐢ㄤ簬鎻愬彇
+            throw new Error('鍗囩骇纾佺洏绌洪棿涓嶈冻')
         }
     }
-    // 2. Download to specific directory
+    // 2. 涓嬭浇鍒扮壒瀹氱洰褰�
     const firmware = ota.OTA_ROOT + '/download.zip'
     const temp = ota.OTA_ROOT + '/temp'
-    com.systemBrief(`rm -rf ${ota.OTA_ROOT} && mkdir ${ota.OTA_ROOT} `) // Clean and create directory
+    com.systemBrief(`rm -rf ${ota.OTA_ROOT} && mkdir ${ota.OTA_ROOT} `) // 娓呯悊骞跺垱寤虹洰褰�
     let download = `wget --no-check-certificate --timeout=${timeout} -c "${url}" -O ${firmware} 2>&1`
     com.systemBrief(download, 1000)
     let fileExist = (os.stat(firmware)[1] === 0)
@@ -158,65 +163,65 @@
     fileExist = (os.stat(firmware)[1] === 0)
     if (!fileExist) {
         log.error("download result" + downloadRet)
-        throw new Error('Download failed. Please check the URL: ' + url)
+        throw new Error('涓嬭浇澶辫触銆傝妫�鏌� URL: ' + url)
     }
-    // 3. Verify MD5 checksum
+    // 3. 楠岃瘉 MD5 鏍¢獙鍜�
     let md5Hash = com.md5HashFile(firmware)
     md5Hash = md5Hash.map(v => v.toString(16).padStart(2, 0)).join('')
     if (md5Hash != md5) {
         log.error("download result" + downloadRet)
-        throw new Error('MD5 verification failed')
+        throw new Error('MD5 楠岃瘉澶辫触')
     }
-    // 4. Extract package
+    // 4. 鎻愬彇鍖�
     com.systemBrief(`mkdir ${temp} && unzip -o ${firmware} -d ${temp}`)
-    // 5. Execute custom upgrade script if present
+    // 5. 濡傛灉瀛樺湪锛屾墽琛岃嚜瀹氫箟鍗囩骇鑴氭湰
     const custom_update = temp + '/custom_update.sh'
     if (os.stat(custom_update)[1] === 0) {
         com.systemBrief(`chmod +x ${custom_update}`)
         com.systemWithRes(`${custom_update}`)
     }
-    // 6. Create upgrade script
+    // 6. 鍒涘缓鍗囩骇鑴氭湰
     if (!shell) {
-        // Default: copy files and clean up
+        // 榛樿锛氬鍒舵枃浠跺苟娓呯悊
         shell = `cp -r ${temp}/* /app/code \n rm -rf ${ota.OTA_ROOT}`
     }
 
     com.systemBrief(`echo "${shell}" > ${ota.OTA_RUN} && chmod +x ${ota.OTA_RUN}`)
     fileExist = (os.stat(ota.OTA_RUN)[1] === 0)
     if (!fileExist) {
-        throw new Error('Failed to create upgrade script')
+        throw new Error('鍒涘缓鍗囩骇鑴氭湰澶辫触')
     }
     com.systemWithRes(`${ota.OTA_RUN}`)
 }
 
 /**
- * @deprecated Use updateHttp() instead
- * Legacy resource upgrade for tar.xz packages.
- * Specialized for upgrading resource files only.
- * @param {string} url Required. HTTP URL for downloading the upgrade package
- * @param {string} md5 Required. MD5 hash for integrity verification (32-char lowercase hex)
- * @param {number} size Optional. Package size in KB for disk space validation
- * @param {string} shell Optional. Custom upgrade script content
- * @param {number} timeout Optional. Connection timeout in seconds (default: 3)
+ * @deprecated 浣跨敤 updateHttp() 浠f浛
+ * 鐢ㄤ簬 tar.xz 鍖呯殑鏃ц祫婧愬崌绾с��
+ * 涓撻棬鐢ㄤ簬浠呭崌绾ц祫婧愭枃浠躲��
+ * @param {string} url 蹇呭~銆備笅杞藉崌绾у寘鐨� HTTP URL
+ * @param {string} md5 蹇呭~銆傜敤浜庡畬鏁存�ч獙璇佺殑 MD5 鍝堝笇鍊硷紙32 浣嶅皬鍐欏崄鍏繘鍒讹級
+ * @param {number} size 鍙�夈�傜敤浜庣鐩樼┖闂撮獙璇佺殑鍖呭ぇ灏忥紙KB锛�
+ * @param {string} shell 鍙�夈�傝嚜瀹氫箟鍗囩骇鑴氭湰鍐呭
+ * @param {number} timeout 鍙�夈�傝繛鎺ヨ秴鏃舵椂闂达紙绉掞級锛岄粯璁わ細3
  */
 ota.updateResource = function (url, md5, size, shell, timeout = 3) {
     if (!url || !md5) {
-        throw new Error("'url' and 'md5' parameters are required")
+        throw new Error("'url' 鍜� 'md5' 鍙傛暟鏄繀濉殑")
     }
     if (size && (typeof size != 'number')) {
-        throw new Error("'size' parameter must be a number")
+        throw new Error("'size' 鍙傛暟蹇呴』鏄暟瀛�")
     }
-    // 1. Check available disk space
+    // 1. 妫�鏌ュ彲鐢ㄧ鐩樼┖闂�
     let df = parseInt(com.systemWithRes(ota.DF_CMD, 1000))
     if (size) {
-        if (df < (3 * size)) { // Require 3x package size for extraction
-            throw new Error('Insufficient disk space for upgrade')
+        if (df < (3 * size)) { // 闇�瑕� 3 鍊嶅寘澶у皬鐢ㄤ簬鎻愬彇
+            throw new Error('鍗囩骇纾佺洏绌洪棿涓嶈冻')
         }
     }
-    // 2. Download to specific directory
+    // 2. 涓嬭浇鍒扮壒瀹氱洰褰�
     const firmware = ota.OTA_ROOT + '/download.tar.xz'
     const temp = ota.OTA_ROOT + '/temp'
-    com.systemBrief(`rm -rf ${ota.OTA_ROOT} && mkdir ${ota.OTA_ROOT} `) // Clean and create directory
+    com.systemBrief(`rm -rf ${ota.OTA_ROOT} && mkdir ${ota.OTA_ROOT} `) // 娓呯悊骞跺垱寤虹洰褰�
     let download = `wget --no-check-certificate --timeout=${timeout} -c "${url}" -O ${firmware} 2>&1`
     com.systemBrief(download, 1000)
     let fileExist = (os.stat(firmware)[1] === 0)
@@ -225,18 +230,18 @@
     }
     fileExist = (os.stat(firmware)[1] === 0)
     if (!fileExist) {
-        throw new Error('Download failed. Please check the URL: ' + url)
+        throw new Error('涓嬭浇澶辫触銆傝妫�鏌� URL: ' + url)
     }
 
-    // 3. Verify MD5 checksum
+    // 3. 楠岃瘉 MD5 鏍¢獙鍜�
     let md5Hash = com.md5HashFile(firmware)
     md5Hash = md5Hash.map(v => v.toString(16).padStart(2, 0)).join('')
     if (md5Hash != md5) {
-        throw new Error('MD5 verification failed')
+        throw new Error('MD5 楠岃瘉澶辫触')
     }
-    // 4. Extract tar.xz package
+    // 4. 鎻愬彇 tar.xz 鍖�
     com.systemBrief(`mkdir ${temp} && tar -xJvf ${firmware} -C ${temp}`)
-    // 5. Create resource upgrade script
+    // 5. 鍒涘缓璧勬簮鍗囩骇鑴氭湰
     if (!shell) {
         shell = `
         source=${temp}/vgapp/res/image/bk.png
@@ -264,7 +269,7 @@
     com.systemBrief(`echo "${shell}" > ${ota.OTA_RUN} && chmod +x ${ota.OTA_RUN}`)
     fileExist = (os.stat(ota.OTA_RUN)[1] === 0)
     if (!fileExist) {
-        throw new Error('Failed to create upgrade script')
+        throw new Error('鍒涘缓鍗囩骇鑴氭湰澶辫触')
     }
     com.systemWithRes(`${ota.OTA_RUN}`)
 }
diff --git a/vf107/resource/langPack.js b/vf107/resource/langPack.js
index 7bf4081..cc65698 100644
--- a/vf107/resource/langPack.js
+++ b/vf107/resource/langPack.js
@@ -195,6 +195,7 @@
       face: "浜鸿劯",
       swipeCardRecognition: "鍒峰崱鏍搁獙",
       passwordOpenDoor: "瀵嗙爜寮�闂�",
+      emergencyOpenDoorPassword: "搴旀�ュ紑闂ㄥ瘑鐮�",
       inputOriginalPassword: "璇疯緭鍏ュ師鐧诲綍瀵嗙爜",
       inputNewPassword: "璇疯緭鍏ユ柊瀵嗙爜",
       inputRepeatNewPassword: "璇烽噸澶嶆柊瀵嗙爜",
@@ -265,10 +266,10 @@
       title: "閫氳璁板綍璇︽儏",
       id: "浜哄憳1缂栧彿",
       name: "浜哄憳1濮撳悕",
-      idCard: "浜哄憳1韬唤璇佸彿",
+      card: "浜哄憳1鍗″彿",
       userId2: "浜哄憳2缂栧彿(绗簩鐢ㄦ埛)",
       name2: "浜哄憳2濮撳悕",
-      idCard2: "浜哄憳2韬唤璇佸彿",
+      card2: "浜哄憳2鍗″彿",
       time: "閫氳鏃堕棿",
       result: "閫氳缁撴灉",
       face: "浜哄憳1浜鸿劯鎶撴媿",
@@ -338,7 +339,7 @@
       failSimilarity: "澶辫触锛屼汉鑴哥浉浼煎害杩囬珮",
       failCardRepeat: "澶辫触锛屽崱鐗囬噸澶�",
       failPwdRepeat: "澶辫触锛屽瘑鐮侀噸澶�",
-      typeOptions: ["鏅�氱敤鎴�", "绠$悊鍛�"],
+      typeOptions: ["淇濈鍛�", "绉戦暱"],
       finger: "鎸囩汗鍑瘉",
       confirmFinger: "纭鍒犻櫎鎸囩汗鍑瘉鍚楋紵",
       failFingerRepeat: "澶辫触锛屾寚绾归噸澶�",
@@ -602,6 +603,7 @@
       face: "Face Only",
       swipeCardRecognition: "Card Verification",
       passwordOpenDoor: "Password Access",
+      emergencyOpenDoorPassword: "Emergency Open Door Password",
       inputOriginalPassword: "Enter Current Password",
       inputNewPassword: "Enter New Password",
       inputRepeatNewPassword: "Confirm New Password",
@@ -673,10 +675,13 @@
       title: "Access Log Details",
       id: "User ID",
       name: "Name",
-      idCard: "ID Number",
+      card: "Card Number",
+      userId2: "User ID 2",
+      name2: "Name 2",
       time: "Access Time",
       result: "Result",
       face: "Face Photo",
+      face2: "Face Photo 2",
     },
     voiceBroadcastView: {
       title: "Voice Settings",
@@ -1000,6 +1005,7 @@
       face: "Solo rostro",
       swipeCardRecognition: "Verificaci贸n tarjeta",
       passwordOpenDoor: "Acceso con clave",
+      emergencyOpenDoorPassword: "Contrase帽a de emergencia",
       inputOriginalPassword: "Contrase帽a actual",
       inputNewPassword: "Nueva contrase帽a",
       inputRepeatNewPassword: "Repite contrase帽a",
@@ -1067,10 +1073,13 @@
       title: "Detalle registro",
       id: "ID usuario",
       name: "Nombre",
-      idCard: "Documento",
+      card: "N煤mero tarjeta",
+      userId2: "ID usuario 2",
+      name2: "Nombre 2",
       time: "Hora",
       result: "Resultado",
       face: "Foto rostro",
+      face2: "Foto rostro 2",
     },
     voiceBroadcastView: {
       title: "Voz",
@@ -1462,10 +1471,13 @@
       title: "D茅tail journal",
       id: "ID utilisateur",
       name: "Nom",
-      idCard: "Document",
+      card: "Num茅ro carte",
+      userId2: "ID utilisateur 2",
+      name2: "Nom 2",
       time: "Heure",
       result: "R茅sultat",
       face: "Photo visage",
+      face2: "Photo visage 2",
     },
     voiceBroadcastView: {
       title: "Voix",
@@ -1857,10 +1869,13 @@
       title: "Protokoll-Detail",
       id: "Nutzer-ID",
       name: "Name",
-      idCard: "Ausweis",
+      card: "Kartennummer",
+      userId2: "Nutzer-ID 2",
+      name2: "Name 2",
       time: "Zeit",
       result: "Ergebnis",
       face: "Gesichtsfoto",
+      face2: "Gesichtsfoto 2",
     },
     voiceBroadcastView: {
       title: "Stimme",
@@ -2252,10 +2267,13 @@
       title: "袛械褌邪谢褜 谢芯谐邪",
       id: "ID",
       name: "袠屑褟",
-      idCard: "袛芯泻褍屑械薪褌",
+      card: "袧芯屑械褉 泻邪褉褌褘",
+      userId2: "ID 2",
+      name2: "袠屑褟 2",
       time: "袙褉械屑褟",
       result: "袪械蟹褍谢褜褌邪褌",
       face: "肖芯褌芯 谢懈褑邪",
+      face2: "肖芯褌芯 谢懈褑邪 2",
     },
     voiceBroadcastView: {
       title: "袚芯谢芯褋",
@@ -2647,10 +2665,13 @@
       title: "鬲賮丕氐賷賱 爻噩賱",
       id: "ID",
       name: "丕爻賲",
-      idCard: "賵孬賷賯丞",
+      card: "乇賯賲 丕賱亘胤丕賯丞",
+      userId2: "ID 2",
+      name2: "丕爻賲 2",
       time: "賵賯鬲",
       result: "賳鬲賷噩丞",
       face: "氐賵乇丞 賵噩賴",
+      face2: "氐賵乇丞 賵噩賴 2",
     },
     voiceBroadcastView: {
       title: "氐賵鬲",
@@ -3045,10 +3066,13 @@
       title: "Detalhe registro",
       id: "ID usu谩rio",
       name: "Nome",
-      idCard: "Documento",
+      card: "N煤mero cart茫o",
+      userId2: "ID usu谩rio 2",
+      name2: "Nome 2",
       time: "Hora",
       result: "Resultado",
       face: "Foto face",
+      face2: "Foto face 2",
     },
     voiceBroadcastView: {
       title: "Voz",
@@ -3440,10 +3464,13 @@
       title: "旮半 靸侅劯",
       id: "ID",
       name: "鞚措",
-      idCard: "鞁犽秳歃�",
+      card: "旃措摐 氩堩樃",
+      userId2: "ID 2",
+      name2: "鞚措 2",
       time: "鞁滉皠",
       result: "瓴瓣臣",
       face: "鞏缄荡 靷",
+      face2: "鞏缄荡 靷 2",
     },
     voiceBroadcastView: {
       title: "鞚岇劚",
diff --git a/vf107/src/config.json b/vf107/src/config.json
index 7fce11d..0ca3c00 100644
--- a/vf107/src/config.json
+++ b/vf107/src/config.json
@@ -65,9 +65,9 @@
     //鏄惁绗竴娆$櫥褰曞悗鍙� 0 鏈櫥褰� 1 宸茬櫥褰� // TODO 杩欎釜閰嶇疆椤瑰簲璇ュ睘浜庤繍琛屾椂鐘舵��,涓嶈耽璇ュ啓鍏onfig.json鎴栬�呭啓鍏ュ崟鐙垎缁�,鏌ヨ閰嶇疆鏃跺仛杩囨护
     "base.firstLogin": 0,
     // 鐔勫睆鏃堕棿锛屽崟浣嶅垎閽燂紝0浠庝笉
-    "base.screenOff": 0,
+    "base.screenOff": 2,
     // 灞忓箷淇濇姢锛屽崟浣嶅垎閽燂紝0浠庝笉
-    "base.screensaver": 0,
+    "base.screensaver": 2,
     //灞忓箷鑳屽厜
     "base.backlight": 70,
     //鐧借壊琛ュ厜鐏�
@@ -137,5 +137,7 @@
     // 搴撳尯鍚嶇О
     "GranaryName": "涓ぎ鍌ㄥ绮煇鏌愮洿灞炲簱",
     // HTTP鎺ュ彛璺緞
-    "http.safeInputAccess": "http://192.168.1.227:80/cgi-bin/safeInputAccess"
+    "http.safeInputAccess": "http://192.168.1.227:80/cgi-bin/safeInputAccess",
+    // 鏄惁寮�鍚皵浣撴祿搴﹂獙璇� 1:鏄� 0:鍚�
+    "gas.verification": 1
 }
\ No newline at end of file
diff --git a/vf107/src/controller.js b/vf107/src/controller.js
index 442134b..b3c4e68 100644
--- a/vf107/src/controller.js
+++ b/vf107/src/controller.js
@@ -31,7 +31,7 @@
     driver.nfc.loop()
     driver.gpiokey.loop()
     driver.face.loop()
-    if (!driver.device.finger && (dxDriver.DRIVER.MODEL == "vf105" || dxDriver.DRIVER.MODEL == "vf114")) {
+    if (!driver.device.finger && (dxDriver.DRIVER.MODEL == "vf105" || dxDriver.DRIVER.MODEL == "vf107" || dxDriver.DRIVER.MODEL == "vf114")) {
         driver.uartCode.loop()
     }
     if (dxDriver.DRIVER.MODEL == "vf202") {
@@ -74,7 +74,7 @@
             bus.fire(driver.gpiokey.RECEIVE_MSG, event)
         }
     });
-    if (!driver.device.finger && (dxDriver.DRIVER.MODEL == "vf105" || dxDriver.DRIVER.MODEL == "vf114")) {
+    if (!driver.device.finger && (dxDriver.DRIVER.MODEL == "vf105" || dxDriver.DRIVER.MODEL == "vf107" || dxDriver.DRIVER.MODEL == "vf114")) {
         driver.uartCode.setCallbacks({
             onMessage: (event) => {
                 bus.fire(driver.uartCode.RECEIVE_MSG, event)
diff --git a/vf107/src/driver.js b/vf107/src/driver.js
index 89037d3..cfaed7d 100644
--- a/vf107/src/driver.js
+++ b/vf107/src/driver.js
@@ -48,7 +48,7 @@
             config.set('mqtt.clientId', uuid)
         }
         if (driver.device.finger) {
-            if (dxDriver.DRIVER.MODEL == "vf105") {
+            if (dxDriver.DRIVER.MODEL == "vf105" || dxDriver.DRIVER.MODEL == "vf107") {
                 config.set('sys.model', "vf107")
             } else if (dxDriver.DRIVER.MODEL == "vf114") {
                 config.set('sys.model', "vf124")
@@ -129,7 +129,7 @@
         if (dxDriver.DRIVER.MODEL == "vf203") {
             pwm.init(dxDriver.PWM.NIR_SUPPLEMENT_CHANNEL);
             pwm.setPower(nirLuminance, dxDriver.PWM.NIR_SUPPLEMENT_CHANNEL);
-        } else if (dxDriver.DRIVER.MODEL == "vf202" || dxDriver.DRIVER.MODEL == "vf114" || dxDriver.DRIVER.MODEL == "vf105") {
+        } else if (dxDriver.DRIVER.MODEL == "vf202" || dxDriver.DRIVER.MODEL == "vf114" || dxDriver.DRIVER.MODEL == "vf105" || dxDriver.DRIVER.MODEL == "vf107") {
             pwm.init(dxDriver.PWM.WHITE_SUPPLEMENT_CHANNEL);
             pwm.init(dxDriver.PWM.NIR_SUPPLEMENT_CHANNEL);
             pwm.setPower(whiteLuminance, dxDriver.PWM.WHITE_SUPPLEMENT_CHANNEL);
@@ -362,7 +362,7 @@
 driver.uartCode = {
     RECEIVE_MSG: '__UART_RECEIVE_MSG__',
     init: function () {
-        if (dxDriver.DRIVER.MODEL == 'vf105') {
+        if (dxDriver.DRIVER.MODEL == 'vf105' || dxDriver.DRIVER.MODEL == 'vf107') {
             dxVgCode.init('/dev/ttySLB1', '115200-8-N-1')
         } else if (dxDriver.DRIVER.MODEL == 'vf114') {
             dxVgCode.init('/dev/ttySLB3', '115200-8-N-1')
diff --git a/vf107/src/main.js b/vf107/src/main.js
index ffcb751..5f02040 100644
--- a/vf107/src/main.js
+++ b/vf107/src/main.js
@@ -205,31 +205,9 @@
     // 娓呯悊鏈粦瀹氱殑鍑瘉淇℃伅
     cleanupUnboundVouchers()
 
-    let appVersion
-    let releaseTime
-    if (dxDriver.DRIVER.MODEL == "vf202") {
-        appVersion = 'vf202_v12_access_2.0.2'
-        releaseTime = '2026-01-09 13:00:00'
-    } else if (dxDriver.DRIVER.MODEL == "vf203") {
-        appVersion = 'vf203_v14_access_2.0.2'
-        releaseTime = '2026-02-04 14:30:00'
-    } else if (dxDriver.DRIVER.MODEL == "vf114") {
-        if(driver.device.finger) {
-            appVersion = 'vf124_v12_access_2.0.2'
-            releaseTime = '2026-03-19 13:00:00'
-        } else {
-            appVersion = 'vf114_v12_access_2.0.2'
-            releaseTime = '2026-01-09 13:00:00'
-        }
-    } else if (dxDriver.DRIVER.MODEL == "vf105") {
-        if(driver.device.finger) {
-            appVersion = 'vf107_v12_access_2.0.2.1'
-            releaseTime = '2026-03-19 13:00:00'
-        } else {
-            appVersion = 'vf105_v12_access_2.0.2'
-            releaseTime = '2026-01-09 13:00:00'
-        }
-    }
+    let appVersion = 'vf107_access_2.0.2.1'
+    let releaseTime = '2026-03-19 13:00:00'
+
     config.setAndSave('sys.version', appVersion)
     config.setAndSave('sys.appVersion', appVersion)
     config.setAndSave('sys.releaseTime', releaseTime)
diff --git a/vf107/src/screen.js b/vf107/src/screen.js
index 4380ba9..08da513 100644
--- a/vf107/src/screen.js
+++ b/vf107/src/screen.js
@@ -65,7 +65,7 @@
 screen.model = dxDriver.DRIVER.MODEL
 
 screen.resourcePath = {
-    imagePath: `/app/code/resource/image/${dxDriver.DRIVER.MODEL}/`
+    imagePath: `/app/code/resource/image/vf105/`
 }
 
 screen.dropdownSymbol = screen.resourcePath.imagePath + '/down.png'
@@ -179,28 +179,12 @@
 function getClickPoint() {
     const indev = NativeObject.APP.NativeComponents.NativeIndev
     std.setInterval(() => {
-        if (dxDriver.DRIVER.MODEL == "vf203") {
-            clickPoint = {
-                x: Math.abs(600 - indev.lvIndevGetPointVg().y),
-                y: indev.lvIndevGetPointVg().x
-            }
-        } else if (dxDriver.DRIVER.MODEL == "vf202") {
-            clickPoint = {
-                x: indev.lvIndevGetPointVg().x,
-                y: indev.lvIndevGetPointVg().y
-            }
-        } else if (dxDriver.DRIVER.MODEL == "vf114") {
-            clickPoint = {
-                x: indev.lvIndevGetPointVg().x,
-                y: indev.lvIndevGetPointVg().y
-            }
-        } else if (dxDriver.DRIVER.MODEL == "vf105") {
-            clickPoint = {
-                x: indev.lvIndevGetPointVg().x,
-                y: indev.lvIndevGetPointVg().y
-            }
+        
+        clickPoint = {
+            x: indev.lvIndevGetPointVg().x,
+            y: indev.lvIndevGetPointVg().y
         }
-
+        
         if (lastClickPoint.x != clickPoint.x || lastClickPoint.y != clickPoint.y) {
             changedClickPoint = clickPoint
         } else {
@@ -1035,11 +1019,14 @@
     let param = driver.net.getNetParam()
 
     if (data == "connected" && param) {
-        config.setAndSave("net.ip", param.ip)
-        config.setAndSave("net.gateway", param.gateway)
-        config.setAndSave("net.mask", param.netmask)
-        config.setAndSave('net.dns', param.dns)
-        config.setAndSave('net.mac', screen.getNetMac())
+        // 鍙湁鍦ㄧ綉缁滈厤缃〉闈笉鍙涓旂敤鎴蜂笉鍦ㄧ紪杈戦厤缃椂鎵嶈嚜鍔ㄤ繚瀛樼綉缁滃弬鏁�
+        if (!networkSettingView.isVisible && !networkSettingView.isEditing) {
+            config.setAndSave("net.ip", param.ip)
+            config.setAndSave("net.gateway", param.gateway)
+            config.setAndSave("net.mask", param.netmask)
+            config.setAndSave('net.dns', param.dns)
+            config.setAndSave('net.mac', screen.getNetMac())
+        }
         topView.ethConnectState(true, type)
         networkSettingView.netInfo[10].label.dataI18n = "networkSettingView.networkConnected"
         if (mainView.ipInfoLbl) mainView.ipInfoLbl.text("IP:" + param.ip)
@@ -1054,7 +1041,10 @@
     }
     i18n.refreshObj(networkSettingView.netInfo[10].label)
     networkSettingView.refresh()
-    networkSettingView.changeNetType(type)
+    // 鍙湁鍦ㄧ敤鎴蜂笉鍦ㄧ紪杈戦厤缃椂鎵嶆墽琛岀綉缁滅被鍨嬪垏鎹�
+    if (!networkSettingView.isEditing) {
+        networkSettingView.changeNetType(type)
+    }
 }
 
 screen.fireNetStatus = function () {
diff --git a/vf107/src/service/accessService.js b/vf107/src/service/accessService.js
index 35ec0a1..09940bc 100644
--- a/vf107/src/service/accessService.js
+++ b/vf107/src/service/accessService.js
@@ -169,7 +169,16 @@
                     } catch (error) {
                         logger.error("鏃犺韩浠借瘉鍙锋垨绫诲瀷")
                     }
-                    data.extra = { name: res[0].name, idCard: idCard, type: userType }
+                    // 鏍规嵁data.type璁剧疆姝g‘鐨勮璇佺被鍨�
+                    let accessType = 0
+                    if (data.type == "200") {
+                        accessType = 200 // 鍒峰崱
+                    } else if (data.type == "300") {
+                        accessType = 300 // 浜鸿劯
+                    } else if (data.type == "500") {
+                        accessType = 500 // 鎸囩汗
+                    }
+                    data.extra = { name: res[0].name, idCard: idCard, card: data.code, type: userType, accessType: accessType }
                     data.permissionIds = res[0].permissionIds
 
                 }
@@ -183,21 +192,39 @@
                 // 鏌ヨ绗竴鐢ㄦ埛鐨勮缁嗕俊鎭�
                 let res1 = sqliteService.d1_person.findByUserId(firstUserId)
                 if (res1.length > 0) {
-                    // 鑾峰彇绗竴鐢ㄦ埛鐨勫鍚嶃�佽韩浠借瘉鍙峰拰韬唤绫诲瀷
+                    // 鑾峰彇绗竴鐢ㄦ埛鐨勫鍚嶃�佽韩浠借瘉鍙�
                     let idCard1
-                    let firstUserType = 0
+                    let userType1 = 0
                     try {
                         idCard1 = JSON.parse(res1[0].extra).idCard
-                        firstUserType = JSON.parse(res1[0].extra).type || 0
+                        userType1 = JSON.parse(res1[0].extra).type || 0
                     } catch (error) {
-                        logger.error("鏃犵涓�鐢ㄦ埛韬唤璇佸彿鎴栫被鍨�")
+                        logger.error("鏃犵涓�鐢ㄦ埛韬唤璇佸彿")
+                    }
+                    // 鏍规嵁data.type璁剧疆姝g‘鐨勮璇佺被鍨�
+                    let accessType1 = 0
+                    if (data.type == "200") {
+                        accessType1 = 200 // 鍒峰崱
+                    } else if (data.type == "300") {
+                        accessType1 = 300 // 浜鸿劯
+                    } else if (data.type == "500") {
+                        accessType1 = 500 // 鎸囩汗
                     }
                     data.userId = firstUserId
-                    data.extra = { name: res1[0].name, idCard: idCard1, type: firstUserType }
+                    data.extra = { name: res1[0].name, idCard: idCard1, card: data.code, type: userType1, accessType: accessType1 }
                 } else {
                     // 濡傛灉娌℃湁鏌ヨ鍒扮涓�鐢ㄦ埛淇℃伅锛屼娇鐢ㄩ粯璁ゅ��
                     data.userId = firstUserId
-                    data.extra = { name: data.dualAuthInfo.firstUserName, idCard: "", type: 0 }
+                    // 鏍规嵁data.type璁剧疆姝g‘鐨勮璇佺被鍨�
+                    let accessType1 = 0
+                    if (data.type == "200") {
+                        accessType1 = 200 // 鍒峰崱
+                    } else if (data.type == "300") {
+                        accessType1 = 300 // 浜鸿劯
+                    } else if (data.type == "500") {
+                        accessType1 = 500 // 鎸囩汗
+                    }
+                    data.extra = { name: data.dualAuthInfo.firstUserName, idCard: "", type: 0, accessType: accessType1 }
                 }
                 // 瀛樺偍绗簩鐢ㄦ埛淇℃伅
                 data.userId2 = data.dualAuthInfo.secondUserId
@@ -206,19 +233,37 @@
                 if (res2.length > 0) {
                     // 鑾峰彇绗簩鐢ㄦ埛鐨勫鍚嶅拰韬唤璇佸彿
                     let idCard2
-                    let secondUserType = 0
+                    let userType2 = 0
                     try {
                         idCard2 = JSON.parse(res2[0].extra).idCard
-                        secondUserType = JSON.parse(res2[0].extra).type || 0
+                        userType2 = JSON.parse(res2[0].extra).type || 0
                     } catch (error) {
-                        logger.error("鏃犵浜岀敤鎴疯韩浠借瘉鍙锋垨绫诲瀷")
+                        logger.error("鏃犵浜岀敤鎴疯韩浠借瘉鍙�")
                     }
-                    data.extra2 = { name: res2[0].name, idCard: idCard2 }
+                    // 鏍规嵁data.type璁剧疆姝g‘鐨勮璇佺被鍨�
+                    let accessType2 = 0
+                    if (data.type == "200") {
+                        accessType2 = 200 // 鍒峰崱
+                    } else if (data.type == "300") {
+                        accessType2 = 300 // 浜鸿劯
+                    } else if (data.type == "500") {
+                        accessType2 = 500 // 鎸囩汗
+                    }
+                    data.extra2 = { name: res2[0].name, idCard: idCard2, card: data.code2, type: userType2, accessType: accessType2 }
                     // 瀛樺偍绗簩鐢ㄦ埛鐨勬潈闄怚D锛堣韩浠界被鍨嬶級
-                    data.permissionId2 = secondUserType.toString()
+                    data.permissionId2 = userType2.toString()
                 } else {
                     // 濡傛灉娌℃湁鏌ヨ鍒扮浜岀敤鎴蜂俊鎭紝浣跨敤榛樿鍊�
-                    data.extra2 = { name: data.dualAuthInfo.secondUserName, idCard: "" }
+                    // 鏍规嵁data.type璁剧疆姝g‘鐨勮璇佺被鍨�
+                    let accessType2 = 0
+                    if (data.type == "200") {
+                        accessType2 = 200 // 鍒峰崱
+                    } else if (data.type == "300") {
+                        accessType2 = 300 // 浜鸿劯
+                    } else if (data.type == "500") {
+                        accessType2 = 500 // 鎸囩汗
+                    }
+                    data.extra2 = { name: data.dualAuthInfo.secondUserName, idCard: "", type: 0, accessType: accessType2 }
                     data.permissionId2 = ""
                 }
                 // 澶勭悊绗竴鐢ㄦ埛鐨勪汉鑴稿浘鐗�
@@ -323,6 +368,19 @@
                             if (authQueue.length === 1) {
                                 // 绗竴鐢ㄦ埛璁よ瘉
                                 logger.info("[access]: 淇濈鍛樻潈闄愶紝闇�瑕佸弻浜鸿璇�")
+                                // 纭繚data.extra鍖呭惈accessType瀛楁
+                                if (!data.extra.accessType) {
+                                    // 鏍规嵁data.type璁剧疆姝g‘鐨勮璇佺被鍨�
+                                    let accessType = 0
+                                    if (data.type == "200") {
+                                        accessType = 200 // 鍒峰崱
+                                    } else if (data.type == "300") {
+                                        accessType = 300 // 浜鸿劯
+                                    } else if (data.type == "500") {
+                                        accessType = 500 // 鎸囩汗
+                                    }
+                                    data.extra.accessType = accessType
+                                }
                                 // 瑙﹀彂绗竴鐢ㄦ埛璁よ瘉鎴愬姛浜嬩欢锛屾洿鏂癠I
                                 bus.fire("accessSuccess", { 
                                     data: { 
@@ -413,13 +471,19 @@
                                         } catch (error) {
                                             logger.error("鏃犵涓�鐢ㄦ埛韬唤璇佸彿鎴栫被鍨�")
                                         }
-                                        data.extra = { name: userRes[0].name, idCard: idCard1, type: firstUserType }
+                                        // 纭繚绗竴鐢ㄦ埛鐨勪俊鎭寘鍚玜ccessType瀛楁
+                                        let accessType1 = firstUser.data.extra.accessType || 0
+                                        data.extra = { name: userRes[0].name, idCard: idCard1, type: firstUserType, accessType: accessType1 }
                                     } else {
-                                        data.extra = { name: firstUser.name, idCard: '', type: firstUser.type }
+                                        // 纭繚绗竴鐢ㄦ埛鐨勪俊鎭寘鍚玜ccessType瀛楁
+                                        let accessType1 = firstUser.data.extra.accessType || 0
+                                        data.extra = { name: firstUser.name, idCard: '', type: firstUser.type, accessType: accessType1 }
                                     }
                                 } catch (error) {
                                     logger.error("瑙f瀽绗竴鐢ㄦ埛淇℃伅澶辫触")
-                                    data.extra = { name: firstUser.name, idCard: '', type: firstUser.type }
+                                    // 纭繚绗竴鐢ㄦ埛鐨勪俊鎭寘鍚玜ccessType瀛楁
+                                    let accessType1 = firstUser.data.extra.accessType || 0
+                                    data.extra = { name: firstUser.name, idCard: '', type: firstUser.type, accessType: accessType1 }
                                 }
                                 // 瀛樺偍绗簩鐢ㄦ埛鐨勪汉鑴稿浘鐗�
                                 if (secondUser.fileName) {
@@ -481,7 +545,7 @@
             if (!ret && config.get('mqtt.onlinecheck') == 1 && mqtt_map.get("MQTT_STATUS") == "connected") {
                 logger.info("[access]: 鏃犳潈闄愶紝璧板湪绾块獙璇�")
                 let serialNo = std.genRandomStr(10)
-                driver.mqtt.send("access_device/v2/event/access_online", JSON.stringify(mqttService.mqttReply(serialNo, data, mqttService.CODE.S_000)))
+                driver.mqtt.send(`access_device/v2/event/${sn}/access_online`, JSON.stringify(mqttService.mqttReply(serialNo, data, mqttService.CODE.S_000)))
                 driver.audio.play(`/app/code/resource/${language}/wav/recg.wav`)
                
                 // 绛夊緟鍦ㄧ嚎楠岃瘉缁撴灉
@@ -504,63 +568,28 @@
                 bleReply(data, true)
             }
             
-            // 楠岃瘉姘斾綋娴撳害
-            grainService.checkGasConcentration(function() {
-                // 浠庡瓨鍌ㄧ殑姘斾綋鏁版嵁涓幏鍙栭獙璇佺粨鏋�
-                const gasData = grainService.getGasData()
-                
-                if(gasData && gasData.data && gasData.data.status === "0") {
-                    logger.info("[access]: 姘斾綋娴撳害楠岃瘉鍚堟牸")
-                    // 閫氳鎴愬姛澶勭悊
-                    driver.screen.accessSuccess()
-                    logger.info("[access]: 閫氳鎴愬姛")
+            // 妫�鏌ユ槸鍚﹀紑鍚皵浣撴祿搴﹂獙璇�
+            const gasVerificationEnabled = config.get('gas.verification')
+            
+            if (gasVerificationEnabled) {
+                // 楠岃瘉姘斾綋娴撳害
+                grainService.checkGasConcentration(function() {
+                    // 浠庡瓨鍌ㄧ殑姘斾綋鏁版嵁涓幏鍙栭獙璇佺粨鏋�
+                    const gasData = grainService.getGasData()
                     
-                    // 鏄剧ず閫氳鎴愬姛缁撴灉
-                    bus.fire("showAccessResult", {
-                        faceAuth: true,
-                        gasConcentration: true,
-                        accessAllowed: true,
-                        message: "*浠撳唴姘斾綋娴撳害鍚堟牸锛屽厑璁搁�氳*"
-                    })
-                    
-                    // 瑙﹀彂閫氳鎴愬姛浜嬩欢锛岄�氱煡UI鏇存柊
-                    bus.fire("accessSuccess", { data: data, fileName: fileName })
-                    driver.audio.play(`/app/code/resource/${language}/wav/access_s.wav`) // 鎾斁璇煶
-                    driver.gpio.open() // 寮�闂�
-                    savePassPic(data, fileName) // 淇濆瓨閫氳鍥剧墖
-                    reply(data, true) // 涓婃姤閫氳璁板綍
-                    
-                    // 60绉掑悗閲嶇疆鐢ㄦ埛UI
-                    std.setTimeout(() => {
-                        bus.fire("accessUnlockComplete")
-                    }, 60000)
-                } else {
-                    logger.info("[access]: 姘斾綋娴撳害楠岃瘉涓嶅悎鏍�")
-                    // 閫氳澶辫触澶勭悊
-                    driver.screen.accessFail()
-                    logger.error("[access]: 閫氳澶辫触")
-                    // 瑙﹀彂澶辫触寮圭獥
-                    bus.fire("showAccessResult", {
-                        faceAuth: true,
-                        gasConcentration: false,
-                        accessAllowed: false,
-                        message: "*浠撳唴姘斾綋娴撳害涓嶅悎鏍硷紝绂佹閫氳*"
-                    })
-                    // 瑙﹀彂閫氳鎴愬姛浜嬩欢锛屾洿鏂扮敤鎴稶I
-                    bus.fire("accessSuccess", { data: data, fileName: fileName })
-                    if (utils.isEmpty(similarity)) {
-                        driver.audio.play(`/app/code/resource/${language}/wav/access_f.wav`)
+                    if(gasData && gasData.data && gasData.data.status === "0") {
+                        logger.info("[access]: 姘斾綋娴撳害楠岃瘉鍚堟牸")
+                        handleAccessSuccess(data, fileName, similarity, "*浠撳唴姘斾綋娴撳害鍚堟牸锛屽厑璁搁�氳*")
+                    } else {
+                        logger.info("[access]: 姘斾綋娴撳害楠岃瘉涓嶅悎鏍�")
+                        handleAccessFail(data, fileName, similarity, "*浠撳唴姘斾綋娴撳害涓嶅悎鏍硷紝绂佹閫氳*", "姘斾綋娴撳害涓嶅悎鏍�")
                     }
-                    // 60绉掑悗閲嶇疆鐢ㄦ埛UI
-                    std.setTimeout(() => {
-                        bus.fire("accessUnlockComplete")
-                    }, 60000)
-                    savePassPic(data, fileName)
-                    // 娣诲姞姘斾綋娴撳害澶辫触淇℃伅
-                    data.message = "姘斾綋娴撳害涓嶅悎鏍�"
-                    reply(data, false) // 涓婃姤閫氳璁板綍
-                }
-            })
+                })
+            } else {
+                // 璺宠繃姘斾綋娴撳害楠岃瘉锛岀洿鎺ラ�氳鎴愬姛
+                logger.info("[access]: 姘斾綋娴撳害楠岃瘉宸插叧闂紝璺宠繃楠岃瘉")
+                handleAccessSuccess(data, fileName, similarity, "*鍏佽閫氳*")
+            }
 
         } else {
             if (data.type == 500) {
@@ -771,24 +800,55 @@
         sqliteService.d1_pass_record.save(record)
     }
     let accessRecord = {
-        userId: record.userId,
-        type: record.type,
-        result: record.result,
-        name: data.extra && data.extra.name ? data.extra.name : "",
-        timeStamp: record.timeStamp,
-        extra: {},
-        error: record.message
+        timeStamp: record.timeStamp || 0,
+        result: record.result || 0,
+        error: record.message || "",
+        permissionId: record.permissionId || "",
+        door: record.door || "",
+        users: [
+            {
+                userId: record.userId || "",
+                name: data.extra && data.extra.name ? data.extra.name : "",
+                keyId: record.keyId || "",
+                userType: data.extra && data.extra.type ? data.extra.type : 0,
+                accessType: data.extra && data.extra.accessType || ""
+            }
+        ]
     }
+    
+    // 濡傛灉鏄弻浜鸿璇侊紝娣诲姞绗簩涓敤鎴蜂俊鎭�
+    if (record.userId2) {
+        let extra2 = record.extra2 ? JSON.parse(record.extra2) : ""
+        let secondUser = {
+            userId: record.userId2 || "",
+            name: extra2 && extra2.name ? extra2.name : "",
+            userType: extra2 && extra2.type ? extra2.type : 0,
+            accessType: extra2.accessType || ""
+        }
+        // 濡傛灉鏈夊崱鍙蜂俊鎭紝娣诲姞card瀛楁
+        if (extra2 && extra2.card) {
+            secondUser.card = extra2.card
+        }
+        accessRecord.users.push(secondUser)
+    }
+    
     let serialNo = record.id
     if (record.type == 300) {
         if (config.get('sys.strangerImage') && config.get('access.uploadToCloud')) {
-            accessRecord.code = dxCommonUtils.fs.fileToBase64(record.code)
+            accessRecord.users[0].code = dxCommonUtils.fs.fileToBase64(record.code)
         } else {
-            accessRecord.code = ""
+            accessRecord.users[0].code = ""
+        }
+        
+        // 濡傛灉鏈夌浜屼釜鐢ㄦ埛鐨勪簩缁寸爜
+        if (record.code2) {
+            accessRecord.users[1] = accessRecord.users[1] || {}
+            accessRecord.users[1].code = record.code2
         }
     }
-    let payload = mqttService.mqttReply(serialNo, [accessRecord], mqttService.CODE.S_000)
-    driver.mqtt.send("access_device/v2/event/access", JSON.stringify(payload))
+    // 涓嶅啀鐩存帴鍙戦�丮QTT娑堟伅锛岀敱passRecordWorker.js缁熶竴澶勭悊涓婃姤
+    // let payload = mqttService.mqttReply(serialNo, [accessRecord], mqttService.CODE.S_000)
+    // driver.mqtt.send("access_device/v2/event/access", JSON.stringify(payload))
 }
 
 // 钃濈墮鍥炲
@@ -801,5 +861,71 @@
     driver.uartBle.send("0101" + dxCommonUtils.codec.strToUtf8Hex(replyData))
 }
 
+function handleAccessSuccess(data, fileName, similarity, message) {
+    let language = config.get("base.language") || "CN";
+    driver.screen.accessSuccess()
+    logger.info("[access]: 閫氳鎴愬姛")
+    
+    // 纭繚绗竴鐢ㄦ埛鐨別xtra鍖呭惈accessType瀛楁
+    if (!data.extra.accessType) {
+        // 鏍规嵁data.type璁剧疆姝g‘鐨勮璇佺被鍨�
+        let accessType = 0
+        if (data.type == "200" || data.type == 200) {
+            accessType = 200 // 鍒峰崱
+        } else if (data.type == "300" || data.type == 300) {
+            accessType = 300 // 浜鸿劯
+        } else if (data.type == "500" || data.type == 500) {
+            accessType = 500 // 鎸囩汗
+        }
+        data.extra.accessType = accessType
+    }
+    
+    // 鏄剧ず閫氳鎴愬姛缁撴灉
+    bus.fire("showAccessResult", {
+        faceAuth: true,
+        gasConcentration: true,
+        accessAllowed: true,
+        message: message
+    })
+    
+    // 瑙﹀彂閫氳鎴愬姛浜嬩欢锛岄�氱煡UI鏇存柊
+    bus.fire("accessSuccess", { data: data, fileName: fileName })
+    driver.audio.play(`/app/code/resource/${language}/wav/access_s.wav`) // 鎾斁璇煶
+    driver.gpio.open() // 寮�闂�
+    savePassPic(data, fileName) // 淇濆瓨閫氳鍥剧墖
+    reply(data, true) // 涓婃姤閫氳璁板綍
+    
+    // 60绉掑悗閲嶇疆鐢ㄦ埛UI
+    std.setTimeout(() => {
+        bus.fire("accessUnlockComplete")
+    }, 60000)
+}
+
+function handleAccessFail(data, fileName, similarity, message, errorMessage) {
+    let language = config.get("base.language") || "CN";
+    driver.screen.accessFail()
+    logger.error("[access]: 閫氳澶辫触")
+    // 瑙﹀彂澶辫触寮圭獥
+    bus.fire("showAccessResult", {
+        faceAuth: true,
+        gasConcentration: false,
+        accessAllowed: false,
+        message: message
+    })
+    // 瑙﹀彂閫氳鎴愬姛浜嬩欢锛屾洿鏂扮敤鎴稶I
+    bus.fire("accessSuccess", { data: data, fileName: fileName })
+    if (utils.isEmpty(similarity)) {
+        driver.audio.play(`/app/code/resource/${language}/wav/access_f.wav`)
+    }
+    // 60绉掑悗閲嶇疆鐢ㄦ埛UI
+    std.setTimeout(() => {
+        bus.fire("accessUnlockComplete")
+    }, 60000)
+    savePassPic(data, fileName)
+    // 娣诲姞澶辫触淇℃伅
+    data.message = errorMessage
+    reply(data, false) // 涓婃姤閫氳璁板綍
+}
+
 
 export default accessService
\ No newline at end of file
diff --git a/vf107/src/service/api.js b/vf107/src/service/api.js
index 65e7be6..c75cb20 100644
--- a/vf107/src/service/api.js
+++ b/vf107/src/service/api.js
@@ -202,7 +202,12 @@
     if (data.type == 0) {
         try {
             driver.screen.upgrade({ title: "confirm.upgrade", content: "confirm.upgrading" })
-            ota.updateHttp(data.url, data.md5,  100)
+            // 纭繚URL鍖呭惈鍗忚鍓嶇紑
+            let url = data.url
+            if (!url.startsWith('http://') && !url.startsWith('https://')) {
+                url = 'http://' + url
+            }
+            ota.updateHttp(url, data.md5,  300)
             driver.screen.upgrade({ title: "confirm.upgrade", content: "confirm.upgradeSuccess" })
         } catch (error) {
             driver.screen.upgrade({ title: "confirm.upgrade", content: "confirm.upgradeFail" })
@@ -315,7 +320,18 @@
                 let person = sqliteService.d1_person.findByUserId(record.userId)
                 if (person.length) {
                     record.name = person[0].name
-                    record.extra = person[0].extra
+                    // 灏唀xtra瀛楁浠嶫SON瀛楃涓茶В鏋愪负JSON瀵硅薄
+                    if (person[0].extra && typeof person[0].extra === 'string') {
+                        try {
+                            record.extra = JSON.parse(person[0].extra)
+                        } catch (error) {
+                            // 濡傛灉瑙f瀽澶辫触锛屼繚鎸佸師鏍�
+                            console.error('瑙f瀽extra瀛楁澶辫触:', error)
+                            record.extra = person[0].extra
+                        }
+                    } else {
+                        record.extra = person[0].extra
+                    }
                 }
             }
         })
@@ -396,6 +412,7 @@
             userId: person.userId || 'unknown',
             errmsg: ''
         }
+        // 澧炲己鏁版嵁楠岃瘉
         if (!person.userId || !person.name) {
             errorItem.errmsg = "userId or name cannot be empty"
             errors.push(errorItem)
@@ -406,11 +423,15 @@
             errors.push(errorItem)
             continue
         }
+        
+        // 鏋勫缓浜哄憳璁板綍
         let record = {}
         record.userId = person.userId
         record.name = person.name
         record.extra = isEmpty(person.extra) ? JSON.stringify({}) : JSON.stringify(person.extra)
         record.permissionIds = person.permissionIds ? person.permissionIds.join(",") : ""
+        
+        // 淇濆瓨浜哄憳淇℃伅
         let ret = sqliteService.d1_person.save(record)
         if (ret != 0) {
             sqliteService.d1_person.deleteByUserId(record.userId)
@@ -420,6 +441,197 @@
                 errors.push(errorItem)
                 continue
             }
+        }
+        
+        // 澶勭悊浜鸿劯淇℃伅
+        if (person.face) {
+            try {
+                logger.info('[api] 寮�濮嬪鐞嗕汉鑴镐俊鎭�:', person.userId)
+                
+                let faceFilePath = person.face
+                
+                // 妫�鏌ユ槸鍚︽槸base64缂栫爜鐨勫浘鐗囨暟鎹�
+                if (person.face.startsWith('data:image/')) {
+                    logger.info('[api] 妫�娴嬪埌base64缂栫爜鐨勫浘鐗囨暟鎹�')
+                    // 鎻愬彇base64鏁版嵁
+                    let base64Data = person.face.split(',')[1]
+                    // 鍒涘缓涓存椂鏂囦欢
+                    faceFilePath = '/data/user/temp_face_' + person.userId + '.jpg'
+                    std.ensurePathExists(faceFilePath)
+                    // 灏哹ase64鏁版嵁杞崲涓烘枃浠�
+                    dxCommonUtils.fs.base64ToFile(faceFilePath, base64Data)
+                    logger.info('[api] 宸插皢base64鏁版嵁淇濆瓨涓烘枃浠�:', faceFilePath)
+                } else {
+                    errorItem.errmsg = "鏁版嵁鏍煎紡閿欒锛宖ace瀛楁蹇呴』鏄痓ase64缂栫爜鐨勫浘鐗囨暟鎹�"
+                    errors.push(errorItem)
+                    continue
+                }
+                
+                // 娉ㄥ唽浜鸿劯
+                logger.info('[api] 寮�濮嬫敞鍐屼汉鑴�:', person.userId)
+                let featureFile = driver.face.getFeaByFile(faceFilePath)
+                let addFeaRes = driver.face.addFea(person.userId, featureFile.feature)
+                
+                if (addFeaRes == 0) {
+                    // 娉ㄥ唽鎴愬姛鍚庣Щ鍔ㄥ浘鐗囧埌鐢ㄦ埛鐩綍
+                    let src = "/data/user/" + person.userId + "/register.jpg"
+                    std.ensurePathExists(src)
+                    logger.info('[api] 绉诲姩浜鸿劯鍥剧墖鍒扮敤鎴风洰褰�:', faceFilePath, '->', src)
+                    dxos.systemBrief('mv ' + faceFilePath + " " + src)
+                    
+                    // 淇濆瓨浜鸿劯鍑瘉
+                    logger.info('[api] 淇濆瓨浜鸿劯鍑瘉:', person.userId)
+                    let voucherRet = sqliteService.d1_voucher.save({
+                        keyId: std.genRandomStr(32),
+                        type: "300",
+                        code: src,
+                        userId: person.userId,
+                        extra: JSON.stringify({ faceType: 0 })
+                    });
+                    logger.info('[api] 淇濆瓨浜鸿劯鍑瘉缁撴灉:', voucherRet)
+                } else {
+                    logger.error('[api] 娉ㄥ唽浜鸿劯澶辫触锛岃繑鍥炵爜:', addFeaRes)
+                    errorItem.errmsg = "娉ㄥ唽浜鸿劯澶辫触锛岃繑鍥炵爜:" + addFeaRes
+                    errors.push(errorItem)
+                    continue
+                }
+            } catch (error) {
+                logger.error('[api] 澶勭悊浜鸿劯淇℃伅閿欒:', error)
+                errorItem.errmsg = "澶勭悊浜鸿劯淇℃伅閿欒: " + error.message
+                errors.push(errorItem)
+                continue
+            } finally {
+                logger.info('[api] 浜鸿劯淇℃伅澶勭悊瀹屾垚:', person.userId)
+            }
+        }
+        
+        // 澶勭悊鎸囩汗淇℃伅
+        if (person.fingerprint) {
+            try {
+                logger.info('[api] 寮�濮嬪鐞嗘寚绾逛俊鎭�:', person.userId)
+                
+                // 妫�鏌ヤ箣鍓嶆槸鍚︽湁鎸囩汗鍑瘉
+                let oldVoucher = sqliteService.d1_voucher.findByuserIdAndType(person.userId, "500");
+                if (oldVoucher.length > 0) {
+                    logger.info('[api] 鍒犻櫎鏃ф寚绾瑰嚟璇�:', JSON.stringify(oldVoucher[0]))
+                    try {
+                        let ret = driver.finger.delete(parseInt(oldVoucher[0].code))
+                        if (ret != 0) {
+                            errorItem.errmsg = "finger delete error ret:" + ret
+                            errors.push(errorItem)
+                            continue
+                        }
+                    } catch (error) {
+                        logger.error('[api] 鍒犻櫎鏃ф寚绾瑰け璐�:', error)
+                    }
+                }
+                
+                // 褰曞叆鏂版寚绾�
+                logger.info('[api] 褰曞叆鏂版寚绾�:', person.userId)
+                let index = driver.finger.insert(person.fingerprint)
+                if(index < 0){
+                    errorItem.errmsg = "insertKey finger insert error ret:" + index
+                    errors.push(errorItem)
+                    continue
+                }
+                
+                // 淇濆瓨鎸囩汗鍑瘉
+                logger.info('[api] 淇濆瓨鎸囩汗鍑瘉:', person.userId)
+                let voucherRet = sqliteService.d1_voucher.save({
+                    keyId: std.genRandomStr(32),
+                    type: "500",
+                    code: index.toString(),
+                    userId: person.userId,
+                    extra: JSON.stringify({ type: 0 })
+                });
+                logger.info('[api] 淇濆瓨鎸囩汗鍑瘉缁撴灉:', voucherRet)
+                logger.info('[api] 鎸囩汗淇℃伅澶勭悊瀹屾垚:', person.userId)
+            } catch (error) {
+                logger.error('[api] 澶勭悊鎸囩汗淇℃伅閿欒:', error)
+                errorItem.errmsg = "澶勭悊鎸囩汗淇℃伅閿欒: " + error.message
+                errors.push(errorItem)
+                continue
+            }
+        }
+        
+        // 澶勭悊NFC鍗′俊鎭�
+        if (person.nfcCard) {
+            try {
+                logger.info('[api] 寮�濮嬪鐞哊FC鍗′俊鎭�:', person.userId)
+                
+                // 妫�鏌FC鍗℃槸鍚﹂噸澶�
+                let existingVoucher = sqliteService.d1_voucher.findByCodeAndType(person.nfcCard, "200")
+                if (existingVoucher.length > 0 && existingVoucher[0].userId != person.userId) {
+                    errorItem.errmsg = "NFC鍗″凡琚叾浠栫敤鎴蜂娇鐢�"
+                    errors.push(errorItem)
+                    continue
+                }
+                
+                // 淇濆瓨NFC鍗″嚟璇�
+                logger.info('[api] 淇濆瓨NFC鍗″嚟璇�:', person.userId)
+                let voucherRet = sqliteService.d1_voucher.save({
+                    keyId: std.genRandomStr(32),
+                    type: "200",
+                    code: person.nfcCard.toUpperCase(),
+                    userId: person.userId,
+                    extra: JSON.stringify({ type: 0 })
+                });
+                logger.info('[api] 淇濆瓨NFC鍗″嚟璇佺粨鏋�:', voucherRet)
+                logger.info('[api] NFC鍗′俊鎭鐞嗗畬鎴�:', person.userId)
+            } catch (error) {
+                logger.error('[api] 澶勭悊NFC鍗′俊鎭敊璇�:', error)
+                errorItem.errmsg = "澶勭悊NFC鍗′俊鎭敊璇�: " + error.message
+                errors.push(errorItem)
+                continue
+            }
+        }
+        
+        // 涓虹敤鎴锋坊鍔犳潈闄�
+        try {
+            // 鑾峰彇鐢ㄦ埛绫诲瀷
+            let userType = 0
+            if (person.extra) {
+                try {
+                    userType = person.extra.type || 0
+                } catch (error) {
+                    logger.error('[api] 瑙f瀽鐢ㄦ埛绫诲瀷澶辫触:', error)
+                }
+            }
+            
+            // 鍙湁淇濈鍛橈紙0锛夊拰绉戦暱锛�1锛夐渶瑕佹坊鍔犳潈闄�
+            if (userType == 0 || userType == 1) {
+                // 妫�鏌ユ槸鍚﹀凡瀛樺湪鏉冮檺璁板綍
+                let existingPermissions = sqliteService.d1_permission.findByUserId(person.userId)
+                if (existingPermissions && existingPermissions.length == 0) {
+                    // 娣诲姞姘镐箙鏉冮檺
+                    let permissionId = std.genRandomStr(32)
+                    let permissionRet = sqliteService.d1_permission.save({
+                        permissionId: permissionId,
+                        userId: person.userId,
+                        door: "", // 绌哄瓧绗︿覆琛ㄧず鎵�鏈夐棬
+                        timeType: 0, // 姘镐箙鏉冮檺
+                        beginTime: 0,
+                        endTime: 0,
+                        period: ""
+                    });
+                    logger.info('[api] 涓虹敤鎴锋坊鍔犳潈闄愮粨鏋�:', permissionRet)
+                    
+                    // 鏇存柊浜哄憳琛ㄤ腑鐨刾ermissionIds瀛楁
+                    if (permissionRet == 0) {
+                        // 鏋勫缓鏇存柊璁板綍
+                        let updateRecord = { permissionIds: permissionId }
+                        // 浣跨敤updateAllByUserId鏂规硶鏇存柊
+                        let updateRet = sqliteService.d1_person.updateAllByUserId(updateRecord, person.userId)
+                        logger.info('[api] 鏇存柊浜哄憳鏉冮檺ID缁撴灉:', updateRet)
+                    }
+                } else {
+                    logger.info('[api] 鐢ㄦ埛宸插瓨鍦ㄦ潈闄愯褰曪紝璺宠繃鏉冮檺娣诲姞:', person.userId)
+                }
+            } else {
+                logger.info('[api] 鐢ㄦ埛绫诲瀷涓嶉渶瑕佹坊鍔犳潈闄愶紝璺宠繃鏉冮檺娣诲姞:', person.userId)
+            }
+        } catch (error) {
+            logger.error('[api] 娣诲姞鏉冮檺鏃跺嚭閿�:', error)
         }
     }
     if (errors.length > 0) {
@@ -438,6 +650,14 @@
                 userId: userId || 'unknown',
                 errmsg: ''
             }
+            try {
+                // 鍒犻櫎浜鸿劯鏁版嵁
+                driver.face.deleteFea(userId)
+                logger.info('[api] 鍒犻櫎浜鸿劯鏁版嵁鎴愬姛:', userId)
+            } catch (error) {
+                logger.error(`Failed to delete face feature for user ${userId}:`, error)
+            }
+            
             // 鍒犻櫎鎸囩汗鍑瘉涔嬪墠闇�瑕佸厛鍒犻櫎鎸囩汗搴撲腑鐨勬寚绾�
             let fingerVoucher = sqliteService.d1_voucher.findByuserIdAndType(userId, "500")
             if (fingerVoucher.length > 0) {
@@ -448,19 +668,18 @@
                     errors.push(errorItem)
                     continue
                 }
+                logger.info('[api] 鍒犻櫎鎸囩汗鏁版嵁鎴愬姛:', userId)
             }
+            
             let ret1 = sqliteService.d1_person.deleteByUserId(userId)
             let ret3 = sqliteService.d1_voucher.deleteByUserId(userId)
-            if (ret1 != 0 || ret3 != 0) {
-                errorItem.errmsg = `sql error: person(${ret1}), voucher(${ret3})`
+            let ret4 = sqliteService.d1_permission.deleteByUserId(userId)
+            if (ret1 != 0 || ret3 != 0 || ret4 != 0) {
+                errorItem.errmsg = `sql error: person(${ret1}), voucher(${ret3}), permission(${ret4})`
                 errors.push(errorItem)
                 continue
             }
-            try {
-                driver.face.deleteFea(userId)
-            } catch (error) {
-                logger.error(`Failed to delete face feature for user ${userId}:`, error)
-            }
+            logger.info('[api] 鍒犻櫎浜哄憳鎴愬姛:', userId)
         }
     }
     if (errors.length > 0) {
@@ -479,6 +698,19 @@
     }
     let totalCount = sqliteService.d1_person.count(data)
     let persons = sqliteService.d1_person.findAll(data)
+    
+    // 灏唀xtra瀛楁浠嶫SON瀛楃涓茶В鏋愪负JSON瀵硅薄
+    persons.forEach(person => {
+        if (person.extra && typeof person.extra === 'string') {
+            try {
+                person.extra = JSON.parse(person.extra)
+            } catch (error) {
+                // 濡傛灉瑙f瀽澶辫触锛屼繚鎸佸師鏍�
+                console.error('瑙f瀽extra瀛楁澶辫触:', error)
+            }
+        }
+    })
+    
     return {
         content: persons,
         page: data.page,
@@ -573,10 +805,18 @@
         if (voucher.type == "200" || voucher.type == "201" || voucher.type == "202") {
             voucher.code = voucher.code.toUpperCase()
         }
-        if (voucher.type == "300" && voucher.extra.faceType != 0 && voucher.extra.faceType != 1) {
-            errorItem.errmsg = "faceType Incorrect format"
-            errors.push(errorItem)
-            continue
+        if (voucher.type == "300") {
+            if (voucher.extra) {
+                if (voucher.extra.faceType != 0 && voucher.extra.faceType != 1) {
+                    errorItem.errmsg = "faceType Incorrect format"
+                    errors.push(errorItem)
+                    continue
+                }
+            } else {
+                errorItem.errmsg = "faceType is required"
+                errors.push(errorItem)
+                continue
+            }
         }
         if (voucher.type == "400") {
             if (voucher.code.length != 6) {
@@ -585,17 +825,6 @@
                 continue
             }
         }
-        // // 鍒ゆ柇鎸囩汗鍑瘉鏄惁閲嶅锛屽鏋滄病鏈夐噸澶嶅氨褰曞叆鎸囩汗
-        // if (voucher.type == "500") {
-        //     voucher.code = parseInt(voucher.code)
-        //     let index = driver.finger.insert(voucher.code)
-        //     if(index < 0){
-        //         errorItem.errmsg = "finger insert error ret:" + index
-        //         errors.push(errorItem)
-        //         continue
-        //     }
-        //     voucher.code = index
-        // }
         let record = {}
         record.keyId = voucher.keyId
         record.type = voucher.type
@@ -755,8 +984,17 @@
     let totalCount = sqliteService.d1_voucher.count(data)
     let vouchers = sqliteService.d1_voucher.findAll(data)
     vouchers.forEach(element => {
-        if (element.type == 300 && element.extra && JSON.parse(element.extra).faceType == 0) {
-            //浜鸿劯鐗规畩澶勭悊涓�涓�
+        // 灏唀xtra瀛楁浠嶫SON瀛楃涓茶В鏋愪负JSON瀵硅薄
+        if (element.extra && typeof element.extra === 'string') {
+            try {
+                element.extra = JSON.parse(element.extra)
+            } catch (error) {
+                // 濡傛灉瑙f瀽澶辫触锛屼繚鎸佸師鏍�
+                console.error('瑙f瀽extra瀛楁澶辫触:', error)
+            }
+        }
+        // 浜鸿劯鐗规畩澶勭悊涓�涓�
+        if (element.type == 300 && element.extra && element.extra.faceType == 0) {
             element.code = dxCommonUtils.fs.fileToBase64(element.code)
         }
     });
@@ -1217,7 +1455,7 @@
     return true
 }
 
-//娓呯┖鏉冮檺
+// 娓呯┖鏉冮檺
 api.clearPermission = function () {
     let ret = sqliteService.d1_permission.deleteAll()
     if (ret == 0) {
@@ -1225,28 +1463,6 @@
     } else {
         return "sql error "
     }
-}
-
-// 鍒ょ┖
-function isEmpty(value) {
-    return value === undefined || value === null || value === ""
-}
-
-// 婵�娲讳簯璇�
-api.eidActive = function (data) {
-    if (data.code && data.code.startsWith("___VBAR_ID_ACTIVE_V")) {
-        try {
-            let activeResute = driver.nfc.eidActive(data.code);
-            if (activeResute != 0) {
-                return 'Activation failed'
-            }
-        } catch (error) {
-            return error.message
-        }
-    } else {
-        return 'The key format is incorrect'
-    }
-    return true
 }
 
 // 鏂板瀵嗛挜
@@ -1299,9 +1515,9 @@
 // 鍒犻櫎瀵嗛挜
 api.delSecurity = function (data) {
     let errors = []
-    if (data.length > 0) {
-        for (let i = 0; i < data.length; i++) {
-            const securityId = data[i];
+    if (data.securityIds && data.securityIds.length > 0) {
+        for (let i = 0; i < data.securityIds.length; i++) {
+            const securityId = data.securityIds[i];
             let errorItem = {
                 securityId: securityId || 'unknown',
                 errmsg: ''
@@ -1326,8 +1542,142 @@
     if (ret == 0) {
         return true
     } else {
-        return "sql error "
+        return "sql error ret:" + ret
     }
 }
 
+// 娣诲姞搴旀�ュ紑浠撳瘑鐮�
+api.insertEmergencyPassword = function (data) {
+    // 搴旀�ュ紑浠撳瘑鐮佸湪璁惧涓粎鏈夊敮涓�鐨�1涓紝鎵�浠ュ厛娓呯┖琛�
+    let deleteRet = sqliteService.d1_emergency_password.deleteAll()
+    if (deleteRet != 0) {
+        return "娓呯┖鏃у瘑鐮佸け璐�: " + deleteRet
+    }
+    
+    // 妫�鏌ュ瘑鐮佹槸鍚︽湁鏁�
+    if (!data.password) {
+        return "password cannot be empty"
+    }
+    
+    // 妫�鏌ュ瘑鐮侀暱搴︽槸鍚﹀ぇ浜庣瓑浜�8浣�
+    if (data.password.length < 8) {
+        return "Password length must be at least 8 digits"
+    }
+    
+    // 鏋勫缓瀵嗙爜璁板綍
+    let record = {}
+    record.id = data.id || 'emergency_' + Date.now() // 濡傛灉娌℃湁id锛岃嚜鍔ㄧ敓鎴�
+    record.password = data.password
+    record.description = data.description || "浜戠涓嬪彂" // 濡傛灉娌℃湁浼犲叆description锛岄粯璁や负"浜戠涓嬪彂"锛圡QTT鍜孒TTP鎺ュ彛璁剧疆鐨勬儏鍐碉級
+    record.createTime = Date.now()
+    record.updateTime = Date.now()
+    record.status = data.status || 1
+    
+    // 淇濆瓨瀵嗙爜
+    let ret = sqliteService.d1_emergency_password.save(record)
+    if (ret == 0) {
+        return true
+    } else {
+        return "sql error ret:" + ret
+    }
+}
+
+// 娓呯┖瀵嗛挜
+api.clearSecurity = function () {
+    let ret = sqliteService.d1_security.deleteAll()
+    if (ret == 0) {
+        return true
+    } else {
+        return "sql error ret:" + ret
+    }
+}
+
+// 娣诲姞搴旀�ュ紑浠撳瘑鐮�
+api.insertEmergencyPassword = function (data) {
+    // 搴旀�ュ紑浠撳瘑鐮佸湪璁惧涓粎鏈夊敮涓�鐨�1涓紝鎵�浠ュ厛娓呯┖琛�
+    let deleteRet = sqliteService.d1_emergency_password.deleteAll()
+    if (deleteRet != 0) {
+        return "娓呯┖鏃у瘑鐮佸け璐�: " + deleteRet
+    }
+    
+    // 妫�鏌ュ瘑鐮佹槸鍚︽湁鏁�
+    if (!data.password) {
+        return "password cannot be empty"
+    }
+    
+    // 妫�鏌ュ瘑鐮侀暱搴︽槸鍚﹀ぇ浜庣瓑浜�8浣�
+    if (data.password.length < 8) {
+        return "Password length must be at least 8 digits"
+    }
+    
+    // 鏋勫缓瀵嗙爜璁板綍
+    let record = {}
+    record.id = data.id || 'emergency_' + Date.now() // 濡傛灉娌℃湁id锛岃嚜鍔ㄧ敓鎴�
+    record.password = data.password
+    record.description = data.description || "浜戠涓嬪彂" // 濡傛灉娌℃湁浼犲叆description锛岄粯璁や负"浜戠涓嬪彂"锛圡QTT鍜孒TTP鎺ュ彛璁剧疆鐨勬儏鍐碉級
+    record.createTime = Date.now()
+    record.updateTime = Date.now()
+    record.status = data.status || 1
+    
+    // 淇濆瓨瀵嗙爜
+    let ret = sqliteService.d1_emergency_password.save(record)
+    if (ret == 0) {
+        return true
+    } else {
+        return "sql error ret:" + ret
+    }
+}
+
+// 鏌ヨ搴旀�ュ紑浠撳瘑鐮�
+api.getEmergencyPassword = function () {
+    let passwords = sqliteService.d1_emergency_password.findAll()
+    if (passwords && passwords.length > 0) {
+        let password = passwords[0];
+        // 杞崲鏃堕棿鎴充负瀛楃涓叉牸寮�
+        if (password.createTime) {
+            // 灏濊瘯灏哻reateTime杞崲涓烘暟瀛�
+            const createTimeNum = Number(password.createTime);
+            if (!isNaN(createTimeNum)) {
+                password.createTime = timestampToDateString(createTimeNum);
+            }
+        }
+        if (password.updateTime) {
+            // 灏濊瘯灏唘pdateTime杞崲涓烘暟瀛�
+            const updateTimeNum = Number(password.updateTime);
+            if (!isNaN(updateTimeNum)) {
+                password.updateTime = timestampToDateString(updateTimeNum);
+            }
+        }
+        return password;
+    }
+    return {};
+}
+
+// 娓呯┖搴旀�ュ紑浠撳瘑鐮�
+api.clearEmergencyPassword = function () {
+    let ret = sqliteService.d1_emergency_password.deleteAll()
+    if (ret == 0) {
+        return true
+    } else {
+        return "sql error ret:" + ret
+    }
+}
+
+// 鏃堕棿鎴宠浆鏃ユ湡瀛楃涓�
+function timestampToDateString(timestamp) {
+    const date = new Date(timestamp);
+    const year = date.getFullYear();
+    const month = String(date.getMonth() + 1).padStart(2, '0');
+    const day = String(date.getDate()).padStart(2, '0');
+    const hours = String(date.getHours()).padStart(2, '0');
+    const minutes = String(date.getMinutes()).padStart(2, '0');
+    const seconds = String(date.getSeconds()).padStart(2, '0');
+    return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
+}
+
+// 鍒ょ┖
+function isEmpty(value) {
+    return value === undefined || value === null || value === ""
+}
+
 export default api
\ No newline at end of file
diff --git a/vf107/src/service/configService.js b/vf107/src/service/configService.js
index 46b9175..15d5d2d 100644
--- a/vf107/src/service/configService.js
+++ b/vf107/src/service/configService.js
@@ -212,6 +212,12 @@
         tamper: validators.switch,
         uploadToCloud: validators.switch
     },
+    gas: {
+        verification: validators.switch
+    },
+    http: {
+        safeInputAccess: validators.string
+    },
     base: {
         firstLogin: validators.switch,
         backlight: validators.percentage,
@@ -315,6 +321,13 @@
 
             // 楠岃瘉骞舵敹闆嗛厤缃」
             for (const [section, sectionData] of Object.entries(data)) {
+                // 澶勭悊椤剁骇閰嶇疆椤癸紙闈炲垎缁勯厤缃級
+                if (typeof sectionData !== 'object' || sectionData === null) {
+                    // 鐩存帴淇濆瓨椤剁骇閰嶇疆椤�
+                    configsToSave.push({ section: '', key: section, value: sectionData })
+                    continue
+                }
+                
                 for (let [key, value] of Object.entries(sectionData)) {
                     // 楠岃瘉閰嶇疆椤�
                     validateConfig(section, key, value)
@@ -341,7 +354,8 @@
 
             // 鎵归噺淇濆瓨閰嶇疆
             configsToSave.forEach(({ section, key, value }) => {
-                config.set(`${section}.${key}`, value)
+                const configKey = section ? `${section}.${key}` : key
+                config.set(configKey, value)
             })
             config.save()
 
diff --git a/vf107/src/service/demo.js b/vf107/src/service/demo.js
new file mode 100644
index 0000000..beb7a4e
--- /dev/null
+++ b/vf107/src/service/demo.js
@@ -0,0 +1,1832 @@
+/**
+ * MQTT鏈嶅姟妯″潡
+ * 澶勭悊MQTT娑堟伅鐨勬帴鏀跺拰鍙戦�侊紝鍖呮嫭璁惧绠$悊銆佷汉鍛樼鐞嗐�佹潈闄愮鐞嗙瓑鍔熻兘
+ */
+import common from "../../dxmodules/dxCommon.js";
+import config from "../../dxmodules/dxConfig.js";
+import logger from "../../dxmodules/dxLogger.js";
+import ota from "../../dxmodules/dxOta.js";
+import std from "../../dxmodules/dxStd.js";
+import dxMap from '../../dxmodules/dxMap.js'
+import driver from "../driver.js";
+import configService from "./configService.js";
+import sqliteService from "./sqliteService.js";
+import sqlite from "../../dxmodules/dxSqlite.js";
+import utils from '../common/utils/utils.js'
+
+const mqttService = {}
+let map = dxMap.get("faceAccesss")
+
+/**
+ * 鎺ユ敹MQTT娑堟伅骞跺鐞�
+ * @param {object} data - MQTT娑堟伅鏁版嵁
+ * @param {string} data.topic - 娑堟伅涓婚
+ * @param {string} data.payload - 娑堟伅杞借嵎
+ */
+mqttService.receiveMsg = function (data) {
+    // {"topic":"ddddd","payload":"{\n  \"msg\": \"world\"\n}"}
+    logger.info('[mqttService] receiveMsg :' + JSON.stringify(data.topic))
+    // 鎻愬彇涓婚鐨勬渶鍚庨儴鍒嗕綔涓哄嚱鏁板悕
+    if (typeof mqttService[data.topic.match(/[^/]+$/)[0]] == 'function') {
+        mqttService[data.topic.match(/[^/]+$/)[0]](data)
+    } else {
+        logger.error("鏈疄鐜扮殑topic", data.topic)
+    }
+}
+
+// =================================鏉冮檺澧炲垹鏀规煡=================================
+/**
+ * 娣诲姞鏉冮檺
+ * @param {object} event - MQTT浜嬩欢瀵硅薄
+ */
+mqttService.insertPermission = function (event) {
+    try {
+        logger.info('[mqttService] 鎺ユ敹鍒癷nsertPermission鍛戒护:', JSON.stringify(event.topic))
+        logger.info('[mqttService] 鍛戒护payload:', event.payload)
+        let payload = JSON.parse(event.payload)
+        let data = payload.payload && payload.payload.data ? payload.payload.data : {}
+        logger.info('[mqttService] 瑙f瀽鍚庣殑鍙傛暟:', JSON.stringify(data))
+        let res = this.insertPermissionAgreement(data)
+        if (typeof res == 'string') {
+            logger.error('[mqttService] insertPermission澶辫触:', res)
+            return reply(event, res, CODE.E_100)
+        }
+        logger.info('[mqttService] insertPermission鎴愬姛')
+        return reply(event)
+    } catch (error) {
+        logger.error('[mqttService] insertPermission error:', error)
+        return reply(event, { error: error.message }, CODE.E_100)
+    }
+}
+
+/**
+ * 娣诲姞鏉冮檺閫氱敤鍗忚鏍煎紡
+ * @param {array} data - 鏉冮檺鏁版嵁鏁扮粍
+ * @returns {boolean|string} true琛ㄧず鎴愬姛锛宻tring琛ㄧず閿欒淇℃伅
+ */
+mqttService.insertPermissionAgreement = function (data) {
+    let permissions = []
+    for (let i = 0; i < data.length; i++) {
+        const permission = data[i];
+        if (!permission.permissionId || !permission.userId) {
+            return "id or userId cannot be empty"
+        }
+        if (!permission.extra) {
+            permission.extra = ""
+        }
+        if (!permission.time) {
+            return "time and type cannot be empty"
+        }
+        if (permission.time.type != 0 && permission.time.type != 1 && permission.time.type != 2 && permission.time.type != 3) {
+            return "time type is not supported"
+        }
+        let record = {}
+        record.permissionId = permission.permissionId
+        record.userId = permission.userId
+        record.door = isEmpty(permission.index) ? 0 : permission.index
+        record.extra = isEmpty(permission.extra) ? JSON.stringify({}) : JSON.stringify(permission.extra)
+        record.timeType = permission.time.type
+        record.beginTime = permission.time.type == 0 ? 0 : permission.time.range.beginTime
+        record.endTime = permission.time.type == 0 ? 0 : permission.time.range.endTime
+        record.repeatBeginTime = permission.time.type != 2 ? 0 : permission.time.beginTime
+        record.repeatEndTime = permission.time.type != 2 ? 0 : permission.time.endTime
+        record.period = permission.time.type != 3 ? 0 : JSON.stringify(permission.time.weekPeriodTime)
+        let ret = sqliteService.d1_permission.save(record)
+        if (ret != 0) {
+            // 濡傛灉淇濆瓨澶辫触锛屽皾璇曞垹闄ゅ悗閲嶆柊淇濆瓨
+            sqliteService.d1_permission.deleteByPermissionId(record.permissionId)
+            ret = sqliteService.d1_permission.save(record)
+            if (ret != 0) {
+                return "sql error ret:" + ret
+            } else {
+                continue
+            }
+        }
+    }
+    return true
+}
+
+/**
+ * 鏌ヨ鏉冮檺
+ * @param {object} event - MQTT浜嬩欢瀵硅薄
+ */
+mqttService.getPermission = function (event) {
+    try {
+        logger.info('[mqttService] 鎺ユ敹鍒癵etPermission鍛戒护:', JSON.stringify(event.topic))
+        logger.info('[mqttService] 鍛戒护payload:', event.payload)
+        let payload = JSON.parse(event.payload)
+        let data = payload.payload && payload.payload.data ? payload.payload.data : {}
+        logger.info('[mqttService] 瑙f瀽鍚庣殑鏌ヨ鍙傛暟:', JSON.stringify(data))
+        let res = this.getPermissionAgreement(data)
+        logger.info('[mqttService] 鏌ヨ缁撴灉:', JSON.stringify(res))
+        return reply(event, res)
+    } catch (error) {
+        logger.error('[mqttService] getPermission error:', error)
+        return reply(event, { error: error.message }, CODE.E_100)
+    }
+}
+
+/**
+ * 鏌ヨ鏉冮檺閫氱敤鍗忚鏍煎紡
+ * @param {object} data - 鏌ヨ鍙傛暟
+ * @returns {object} 鏌ヨ缁撴灉
+ */
+mqttService.getPermissionAgreement = function (data) {
+    try {
+        // 纭繚data鍙傛暟涓嶄负undefined
+        data = data || {}
+        data.page = isEmpty(data.page) ? 0 : data.page
+        data.size = isEmpty(data.size) ? 10 : data.size
+        let totalCount = sqliteService.d1_permission.count(data)
+        let permissions = sqliteService.d1_permission.findAll(data)
+        // 鏋勫缓杩斿洖缁撴灉
+        let content = permissions.map(permission => ({
+            permissionId: permission.permissionId,
+            userId: permission.userId,
+            extra: JSON.parse(permission.extra ? permission.extra : "{}"),
+            time: {
+                type: permission.timeType,
+                beginTime: permission.timeType != 2 ? undefined : permission.repeatBeginTime,
+                endTime: permission.timeType != 2 ? undefined : permission.repeatEndTime,
+                range: permission.timeType === 0 ? undefined : { beginTime: permission.beginTime, endTime: permission.endTime },
+                weekPeriodTime: permission.timeType != 3 ? undefined : JSON.parse(permission.period)
+            }
+        }))
+        return {
+            content: content,
+            page: data.page,
+            size: data.size,
+            total: totalCount,
+            totalPage: Math.ceil(totalCount / data.size),
+            count: content.length
+        }
+    } catch (error) {
+        logger.error('[mqttService] getPermissionAgreement error:', error)
+        throw error
+    }
+}
+
+/**
+ * 鍒犻櫎鏉冮檺
+ * @param {object} event - MQTT浜嬩欢瀵硅薄
+ */
+mqttService.delPermission = function (event) {
+    try {
+        logger.info('[mqttService] 鎺ユ敹鍒癲elPermission鍛戒护:', JSON.stringify(event.topic))
+        logger.info('[mqttService] 鍛戒护payload:', event.payload)
+        let payload = JSON.parse(event.payload)
+        let data = payload.payload && payload.payload.data ? payload.payload.data : {}
+        logger.info('[mqttService] 瑙f瀽鍚庣殑鍙傛暟:', JSON.stringify(data))
+        let res = this.delPermissionAgreement(data)
+        if (typeof res == 'string') {
+            logger.error('[mqttService] delPermission澶辫触:', res)
+            return reply(event, res, CODE.E_100)
+        }
+        logger.info('[mqttService] delPermission鎴愬姛')
+        return reply(event)
+    } catch (error) {
+        logger.error('[mqttService] delPermission error:', error)
+        return reply(event, { error: error.message }, CODE.E_100)
+    }
+}
+
+/**
+ * 鍒犻櫎鏉冮檺閫氱敤鍗忚鏍煎紡
+ * @param {object} data - 鍒犻櫎鍙傛暟
+ * @returns {boolean|string} true琛ㄧず鎴愬姛锛宻tring琛ㄧず閿欒淇℃伅
+ */
+mqttService.delPermissionAgreement = function (data) {
+    if (data.permissionIds && data.permissionIds.length > 0) {
+        let ret = sqliteService.d1_permission.deleteByPermissionIdInBatch(data.permissionIds)
+        if (ret != 0) {
+            return "sql error ret:" + ret
+        }
+    }
+    if (data.userIds && data.userIds.length > 0) {
+        let ret = sqliteService.d1_permission.deleteByUserIdInBatch(data.userIds)
+        if (ret != 0) {
+            return "sql error ret:" + ret
+        }
+    }
+    return true
+}
+
+/**
+ * 娓呯┖鏉冮檺
+ * @param {object} event - MQTT浜嬩欢瀵硅薄
+ */
+mqttService.clearPermission = function (event) {
+    try {
+        logger.info('[mqttService] 鎺ユ敹鍒癱learPermission鍛戒护:', JSON.stringify(event.topic))
+        logger.info('[mqttService] 鍛戒护payload:', event.payload)
+        let ret = sqliteService.d1_permission.deleteAll()
+        if (ret == 0) {
+            logger.info('[mqttService] clearPermission鎴愬姛')
+            return reply(event)
+        } else {
+            logger.error('[mqttService] clearPermission澶辫触:', "sql error ret:" + ret)
+            return reply(event, "sql error ret:" + ret, CODE.E_100)
+        }
+    } catch (error) {
+        logger.error('[mqttService] clearPermission error:', error)
+        return reply(event, { error: error.message }, CODE.E_100)
+    }
+}
+
+
+// =================================浜哄憳澧炲垹鏀规煡=================================
+/**
+ * 娣诲姞浜哄憳
+ * @param {object} event - MQTT浜嬩欢瀵硅薄
+ */
+mqttService.insertUser = function (event) {
+    try {
+        logger.info('[mqttService] 鎺ユ敹鍒癷nsertUser鍛戒护:', JSON.stringify(event.topic))
+        logger.info('[mqttService] 鍛戒护payload:', event.payload)
+        let payload = JSON.parse(event.payload)
+        let data = payload.payload && payload.payload.data ? payload.payload.data : []
+        logger.info('[mqttService] 瑙f瀽鍚庣殑鍙傛暟:', JSON.stringify(data))
+        let res = this.insertUserAgreement(data)
+        if (typeof res == 'string') {
+            logger.error('[mqttService] insertUser澶辫触:', res)
+            return reply(event, res, CODE.E_100)
+        }
+        logger.info('[mqttService] insertUser鎴愬姛')
+        return reply(event)
+    } catch (error) {
+        logger.error('[mqttService] insertUser error:', error)
+        return reply(event, { error: error.message }, CODE.E_100)
+    }
+}
+
+/**
+ * 娣诲姞浜哄憳閫氱敤鍗忚鏍煎紡
+ * @param {array} data - 浜哄憳鏁版嵁鏁扮粍
+ * @returns {boolean|string} true琛ㄧず鎴愬姛锛宻tring琛ㄧず閿欒淇℃伅
+ */
+mqttService.insertUserAgreement = function (data) {
+    let persons = []
+    for (let i = 0; i < data.length; i++) {
+        const person = data[i];
+        // 涓ユ牸妫�鏌ユ暟鎹牸寮�
+        if (!person.userId || !person.name || person.type === undefined || !person.idCard) {
+            return "鏁版嵁鏍煎紡閿欒锛岀己灏戝繀瑕佸瓧娈碉紙userId銆乶ame銆乼ype銆乮dCard锛�"
+        }
+        // 妫�鏌ype瀛楁绫诲瀷
+        if (typeof person.type !== 'number') {
+            return "鏁版嵁鏍煎紡閿欒锛宼ype瀛楁蹇呴』鏄暟瀛�"
+        }
+        // 妫�鏌ype瀛楁鍊艰寖鍥�
+        if (person.type < 0 || person.type > 1) {
+            return "鏁版嵁鏍煎紡閿欒锛宼ype瀛楁鍊煎繀椤诲湪0-1涔嬮棿"
+        }
+        let record = {}
+        record.userId = person.userId
+        record.name = person.name
+        // 澶勭悊浜哄憳绫诲瀷瀛楁鍜岃韩浠借瘉鍙�
+        let extra = {}
+        extra.type = person.type
+        extra.idCard = person.idCard
+        record.extra = JSON.stringify(extra)
+        persons.push(record)
+        
+        // 澶勭悊浜鸿劯淇℃伅
+        if (person.face) {
+            try {
+                logger.info('[mqttService] 寮�濮嬪鐞嗕汉鑴镐俊鎭�:', person.userId)
+                
+                let faceFilePath = person.face
+                
+                // 妫�鏌ユ槸鍚︽槸base64缂栫爜鐨勫浘鐗囨暟鎹�
+                if (person.face.startsWith('data:image/')) {
+                    logger.info('[mqttService] 妫�娴嬪埌base64缂栫爜鐨勫浘鐗囨暟鎹�')
+                    // 鎻愬彇base64鏁版嵁
+                    let base64Data = person.face.split(',')[1]
+                    // 鍒涘缓涓存椂鏂囦欢
+                    faceFilePath = '/app/data/user/temp_face_' + person.userId + '.jpg'
+                    std.ensurePathExists(faceFilePath)
+                    // 灏哹ase64鏁版嵁杞崲涓烘枃浠�
+                    common.base64_2binfile(faceFilePath, base64Data)
+                    logger.info('[mqttService] 宸插皢base64鏁版嵁淇濆瓨涓烘枃浠�:', faceFilePath)
+                } else {
+                    return "鏁版嵁鏍煎紡閿欒锛宖ace瀛楁蹇呴』鏄痓ase64缂栫爜鐨勫浘鐗囨暟鎹�"
+                }
+                
+                // 妫�鏌ユ枃浠舵槸鍚﹀瓨鍦�
+                let fileExists = common.systemWithRes(`test -e "${faceFilePath}" && echo "OK" || echo "NO"`, 2)
+                logger.info('[mqttService] 浜鸿劯鍥剧墖鏂囦欢瀛樺湪:', fileExists.includes('OK'))
+                
+                if (fileExists.includes('OK')) {
+                    // 娉ㄥ唽浜鸿劯
+                    logger.info('[mqttService] 寮�濮嬫敞鍐屼汉鑴�:', person.userId)
+                    let ret = driver.face.registerFaceByPicFile(person.userId, faceFilePath)
+                    logger.info('[mqttService] 娉ㄥ唽浜鸿劯缁撴灉:', ret)
+                    
+                    if (ret == 0) {
+                        // 娉ㄥ唽鎴愬姛鍚庣Щ鍔ㄥ浘鐗囧埌鐢ㄦ埛鐩綍
+                        let src = "/app/data/user/" + person.userId + "/register.jpg"
+                        std.ensurePathExists(src)
+                        logger.info('[mqttService] 绉诲姩浜鸿劯鍥剧墖鍒扮敤鎴风洰褰�:', faceFilePath, '->', src)
+                        common.systemBrief('mv ' + faceFilePath + " " + src)
+                        
+                        // 淇濆瓨浜鸿劯鍑瘉
+                        logger.info('[mqttService] 淇濆瓨浜鸿劯鍑瘉:', person.userId)
+                        let voucherRet = sqliteService.d1_voucher.save({
+                            keyId: std.genRandomStr(32),
+                            type: "300",
+                            code: src,
+                            userId: person.userId,
+                            extra: JSON.stringify({ faceType: 0 })
+                        });
+                        logger.info('[mqttService] 淇濆瓨浜鸿劯鍑瘉缁撴灉:', voucherRet)
+                    } else {
+                        logger.error('[mqttService] 娉ㄥ唽浜鸿劯澶辫触锛岃繑鍥炵爜:', ret)
+                    }
+                } else {
+                    logger.error('[mqttService] 浜鸿劯鍥剧墖鏂囦欢涓嶅瓨鍦�:', faceFilePath)
+                }
+            } catch (error) {
+                logger.error('[mqttService] 澶勭悊浜鸿劯淇℃伅閿欒:', error)
+                return "澶勭悊浜鸿劯淇℃伅閿欒: " + error.message
+            } finally {
+                logger.info('[mqttService] 浜鸿劯淇℃伅澶勭悊瀹屾垚:', person.userId)
+            }
+        }
+    }
+    let ret = sqliteService.d1_person.saveAll(persons)
+    if (ret != 0) {
+        //澶辫触浜� 鎶婅繖浜涗汉鍏ㄩ兘鍒犻櫎鍚庡湪鏂板涓�涓�
+        let userIds = persons.map(obj => obj.userId);
+        sqliteService.d1_person.deleteByUserIdInBatch(userIds)
+        //閲嶆柊鏂板
+        let ret = sqliteService.d1_person.saveAll(persons)
+        if (ret != 0) {
+            return "sql error ret:" + ret
+        }
+    }
+    
+    // 涓虹敤鎴锋坊鍔犲搴旀潈闄�
+    for (let i = 0; i < data.length; i++) {
+        const person = data[i];
+        let userId = person.userId
+        let userType = person.type
+        
+        // 鍙湁淇濈鍛橈紙0锛夊拰绉戦暱锛�1锛夐渶瑕佹坊鍔犳潈闄�
+        if (userType == 0 || userType == 1) {
+            try {
+                // 妫�鏌ユ槸鍚﹀凡瀛樺湪鏉冮檺璁板綍
+                let existingPermissions = sqliteService.d1_permission.findByUserId(userId)
+                if (existingPermissions && existingPermissions.length == 0) {
+                    // 娣诲姞姘镐箙鏉冮檺
+                    let permissionRet = sqliteService.d1_permission.save({
+                        permissionId: std.genRandomStr(32),
+                        userId: userId,
+                        timeType: 0, // 姘镐箙鏉冮檺
+                        beginTime: 0,
+                        endTime: 0,
+                        repeatBeginTime: 0,
+                        repeatEndTime: 0,
+                        period: ""
+                    });
+                    logger.info('[mqttService] 涓虹敤鎴锋坊鍔犳潈闄愮粨鏋�:', permissionRet)
+                } else {
+                    logger.info('[mqttService] 鐢ㄦ埛宸插瓨鍦ㄦ潈闄愯褰曪紝璺宠繃鏉冮檺娣诲姞:', userId)
+                }
+            } catch (error) {
+                logger.error('[mqttService] 娣诲姞鏉冮檺鏃跺嚭閿�:', error)
+            }
+        }
+    }
+    
+    return true
+
+}
+
+/**
+ * 鏌ヨ浜哄憳
+ * @param {object} event - MQTT浜嬩欢瀵硅薄
+ */
+mqttService.getUser = function (event) {
+    try {
+        logger.info('[mqttService] 鎺ユ敹鍒癵etUser鍛戒护:', JSON.stringify(event.topic))
+        logger.info('[mqttService] 鍛戒护payload:', event.payload)
+        let payload = JSON.parse(event.payload)
+        let data = payload.payload && payload.payload.data ? payload.payload.data : {}
+        let res = this.getUserAgreement(data)
+        logger.info('[mqttService] 鏌ヨ缁撴灉:', JSON.stringify(res))
+        return reply(event, res)
+    } catch (error) {
+        logger.error('[mqttService] getUser error:', error)
+        return reply(event, { error: error.message }, CODE.E_100)
+    }
+}
+
+/**
+ * 鏌ヨ浜哄憳閫氱敤鍗忚鏍煎紡
+ * @param {object} data - 鏌ヨ鍙傛暟
+ * @returns {object} 鏌ヨ缁撴灉
+ */
+mqttService.getUserAgreement = function (data) {
+    try {
+        data.page = isEmpty(data.page) ? 0 : data.page
+        data.size = isEmpty(data.size) ? 10 : data.size
+        let totalCount = sqliteService.d1_person.count(data)
+        let persons = sqliteService.d1_person.findAll(data)
+        // 瑙f瀽 extra 瀛楁锛孞SON瀛楃涓茶浆鍖栦负JSON瀵硅薄锛屾秷闄よ浆涔夊瓧绗�
+        persons.forEach(person => {
+            try {
+                if (person.extra) {
+                    person.extra = JSON.parse(person.extra)
+                }
+            } catch (error) {
+                logger.error('[mqttService] 瑙f瀽 extra 瀛楁閿欒:', error)
+            }
+        })
+
+        let result = {
+            content: persons,
+            page: data.page,
+            size: data.size,
+            total: totalCount,
+            totalPage: Math.ceil(totalCount / data.size),
+            count: persons.length
+        }
+
+        return result
+    } catch (error) {
+        logger.error('[mqttService] getUserAgreement error:', error)
+        throw error
+    }
+}
+
+/**
+ * 鍒犻櫎浜哄憳
+ * @param {object} event - MQTT浜嬩欢瀵硅薄
+ */
+mqttService.delUser = function (event) {
+    try {
+        logger.info('[mqttService] 鎺ユ敹鍒癲elUser鍛戒护:', JSON.stringify(event.topic))
+        logger.info('[mqttService] 鍛戒护payload:', event.payload)
+        let payload = JSON.parse(event.payload)
+        let data = payload.payload && payload.payload.data ? payload.payload.data : []
+        logger.info('[mqttService] 瑙f瀽鍚庣殑鍙傛暟:', JSON.stringify(data))
+        let res = this.delUserAgreement(data)
+        if (typeof res == 'string') {
+            logger.error('[mqttService] delUser澶辫触:', res)
+            return reply(event, res, CODE.E_100)
+        }
+        logger.info('[mqttService] delUser鎴愬姛')
+        return reply(event)
+    } catch (error) {
+        logger.error('[mqttService] delUser error:', error)
+        return reply(event, { error: error.message }, CODE.E_100)
+    }
+}
+
+/**
+ * 鍒犻櫎浜哄憳閫氱敤鍗忚鏍煎紡
+ * @param {array} data - 浜哄憳ID鏁扮粍
+ * @returns {boolean|string} true琛ㄧず鎴愬姛锛宻tring琛ㄧず閿欒淇℃伅
+ */
+mqttService.delUserAgreement = function (data) {
+    if (data && data.length > 0) {
+        sqliteService.transaction()
+        let ret1 = sqliteService.d1_person.deleteByUserIdInBatch(data)
+        let ret2 = sqliteService.d1_permission.deleteByUserIdInBatch(data)
+        let ret3 = sqliteService.d1_voucher.deleteByUserIdInBatch(data)
+        if (ret1 != 0 || ret2 != 0 || ret3 != 0) {
+            sqliteService.rollback()
+            return "sql error"
+        }
+        sqliteService.commit()
+        // 鍒犻櫎浜哄憳鐨勪汉鑴告暟鎹�
+        data.forEach(element => {
+            driver.face.delete(element)
+        });
+    }
+    return true
+}
+
+
+/**
+ * 娓呯┖浜哄憳
+ * @param {object} event - MQTT浜嬩欢瀵硅薄
+ */
+mqttService.clearUser = function (event) {
+    try {
+        logger.info('[mqttService] 鎺ユ敹鍒癱learUser鍛戒护:', JSON.stringify(event.topic))
+        logger.info('[mqttService] 鍛戒护payload:', event.payload)
+        let persons = sqliteService.d1_person.findAll()
+        // 鍒犻櫎鎵�鏈変汉鍛樼殑浜鸿劯鏁版嵁
+        logger.info('[mqttService] 寮�濮嬪垹闄や汉鑴告暟鎹紝鍏�', persons.length, '鏉�')
+        persons.forEach(element => {
+            driver.face.delete(element.userId)
+        });
+        let ret1 = sqliteService.d1_person.deleteAll()
+        let ret2 = sqliteService.d1_permission.deleteAll()
+        let ret3 = sqliteService.d1_voucher.deleteAll()
+        if (ret1 == 0 && ret2 == 0 && ret3 == 0) {
+            logger.info('[mqttService] clearUser鎴愬姛')
+            return reply(event)
+        } else {
+            let errorMsg = "sql error ret: " + ret1 + ", " + ret2 + ", " + ret3
+            logger.error('[mqttService] clearUser澶辫触:', errorMsg)
+            return reply(event, errorMsg, CODE.E_100)
+        }
+    } catch (error) {
+        logger.error('[mqttService] clearUser error:', error)
+        return reply(event, { error: error.message }, CODE.E_100)
+    }
+}
+
+// =================================鍑瘉澧炲垹鏀规煡=================================
+/**
+ * 娣诲姞鍑瘉
+ * @param {object} event - MQTT浜嬩欢瀵硅薄
+ */
+mqttService.insertKey = function (event) {
+    try {
+        logger.info('[mqttService] 鎺ユ敹鍒癷nsertKey鍛戒护:', JSON.stringify(event.topic))
+        logger.info('[mqttService] 鍛戒护payload:', event.payload)
+        let payload = JSON.parse(event.payload)
+        let data = payload.payload && payload.payload.data ? payload.payload.data : {}
+        logger.info('[mqttService] 瑙f瀽鍚庣殑鍙傛暟:', JSON.stringify(data))
+        let res = this.insertKeyAgreement(data)
+        if (typeof res == 'string') {
+            logger.error('[mqttService] insertKey澶辫触:', res)
+            return reply(event, res, CODE.E_100)
+        }
+        logger.info('[mqttService] insertKey鎴愬姛')
+        return reply(event)
+    } catch (error) {
+        logger.error('[mqttService] insertKey error:', error)
+        return reply(event, { error: error.message }, CODE.E_100)
+    }
+}
+
+/**
+ * 娣诲姞鍑瘉閫氱敤鍗忚鏍煎紡
+ * @param {array} data - 鍑瘉鏁版嵁鏁扮粍
+ * @returns {boolean|string} true琛ㄧず鎴愬姛锛宻tring琛ㄧず閿欒淇℃伅
+ */
+mqttService.insertKeyAgreement = function (data) {
+    let vouchers = []
+    for (let i = 0; i < data.length; i++) {
+        const voucher = data[i];
+        if (!voucher.keyId || !voucher.type || !voucher.code || !voucher.userId) {
+            return "keyId or type or code  or userId cannot be empty"
+        }
+
+        // 鍑瘉閲嶅
+        let ret = sqliteService.d1_voucher.findAllBycode(voucher.code)
+        if (ret.length != 0) {
+            return "Duplicate vouchers"
+        }
+
+        if (voucher.type == 300) {
+            if (voucher.extra) {
+                if (voucher.extra.faceType != 0 && voucher.extra.faceType != 1) {
+                    return "faceType Incorrect format"
+                }
+            } else {
+                return "faceType is required"
+            }
+        }
+        let record = {}
+        record.keyId = voucher.keyId
+        record.type = voucher.type
+        if (voucher.type == "400") {
+            if (voucher.code.length > 6) {
+                return "Password length cannot exceed 6 digits"
+            }
+        }
+        if (voucher.type == "300") {
+            if (voucher.extra.faceType == 0) {
+                record.code = `/app/data/user/${voucher.userId}/register.jpg`
+                // 淇濆瓨base64鍥剧墖
+                std.ensurePathExists(record.code)
+                common.base64_2binfile(record.code, voucher.code)
+                // 娉ㄥ唽浜鸿劯
+                let weq = driver.face.registerFaceByPicFile(voucher.userId, record.code)
+                if (weq == 0) {
+                    logger.info("娉ㄥ唽浜鸿劯鎴愬姛")
+                } else {
+                    logger.info("绗竴娆′汉鑴告敞鍐屽け璐�")
+                    //鍒犻櫎閲嶆柊娉ㄥ唽
+                    driver.face.delete(voucher.userId)
+                    let res = driver.face.registerFaceByPicFile(voucher.userId, record.code)
+                    if (res == 0) {
+                        logger.info("绗簩娆℃敞鍐屼汉鑴告垚鍔�")
+                        sqliteService.d1_voucher.deleteByKeyId(record.keyId)
+                    } else {
+                        return "Face registration failed"
+                    }
+                }
+            } else {
+                record.code = voucher.code
+                //鐗瑰緛鍊兼敞鍐�
+                let res = driver.face.reg(voucher.userId, voucher.code)
+                if (res != 0) {
+                    return "Face registration failed"
+                }
+            }
+        } else {
+            record.code = voucher.code
+            let ret = sqliteService.d1_voucher.findAllByCodeAndType(voucher.code, voucher.type)
+            if (ret.length != 0) {
+                return "Duplicate vouchers"
+            }
+        }
+
+        record.userId = voucher.userId
+        record.extra = isEmpty(voucher.extra) ? JSON.stringify({ type: 0 }) : JSON.stringify(voucher.extra)
+        vouchers.push(record)
+    }
+    let ret = sqliteService.d1_voucher.saveAll(vouchers)
+    if (ret == 0) {
+        return true
+    } else {
+        return "sql error ret:" + ret
+    }
+}
+
+/**
+ * 鏌ヨ鍑瘉
+ * @param {object} event - MQTT浜嬩欢瀵硅薄
+ */
+mqttService.getKey = function (event) {
+    try {
+        logger.info('[mqttService] 鎺ユ敹鍒癵etKey鍛戒护:', JSON.stringify(event.topic))
+        logger.info('[mqttService] 鍛戒护payload:', event.payload)
+        let payload = JSON.parse(event.payload)
+        let data = payload.payload && payload.payload.data ? payload.payload.data : {}
+        logger.info('[mqttService] 瑙f瀽鍚庣殑鏌ヨ鍙傛暟:', JSON.stringify(data))
+        let res = this.getKeyAgreement(data)
+        if (typeof res == 'string') {
+            logger.error('[mqttService] getKey澶辫触:', res)
+            return reply(event, res, CODE.E_100)
+        }
+        logger.info('[mqttService] 鏌ヨ缁撴灉:', JSON.stringify(res))
+        return reply(event, res)
+    } catch (error) {
+        logger.error('[mqttService] getKey error:', error)
+        return reply(event, { error: error.message }, CODE.E_100)
+    }
+}
+
+/**
+ * 鏌ヨ鍑瘉閫氱敤鍗忚鏍煎紡
+ * @param {object} data - 鏌ヨ鍙傛暟
+ * @returns {object|string} 鏌ヨ缁撴灉鎴栭敊璇俊鎭�
+ */
+mqttService.getKeyAgreement = function (data) {
+    if (!data.type) {
+        return "type is required"
+    }
+    if (data.type == 300) {
+        data.size = 1
+    } else {
+        data.page = isEmpty(data.page) ? 0 : data.page
+        data.size = isEmpty(data.size) ? 10 : data.size
+    }
+    let totalCount = sqliteService.d1_voucher.count(data)
+    let vouchers = sqliteService.d1_voucher.findAll(data)
+    vouchers.forEach(element => {
+        if (element.type == 300 && element.extra && JSON.parse(element.extra).faceType == 0) {
+            //浜鸿劯鐗规畩澶勭悊涓�涓� 
+            element.code = driver.face.fileToBase64(element.code)
+        }
+    });
+    return {
+        content: vouchers,
+        page: data.page,
+        size: data.size,
+        total: totalCount,
+        totalPage: Math.ceil(totalCount / data.size),
+        count: vouchers.length
+    }
+}
+
+/**
+ * 鍒犻櫎鍑瘉
+ * @param {object} event - MQTT浜嬩欢瀵硅薄
+ */
+mqttService.delKey = function (event) {
+    try {
+        logger.info('[mqttService] 鎺ユ敹鍒癲elKey鍛戒护:', JSON.stringify(event.topic))
+        logger.info('[mqttService] 鍛戒护payload:', event.payload)
+        let payload = JSON.parse(event.payload)
+        let data = payload.payload && payload.payload.data ? payload.payload.data : {}
+        logger.info('[mqttService] 瑙f瀽鍚庣殑鍙傛暟:', JSON.stringify(data))
+        let res = this.delKeyAgreement(data)
+        if (typeof res == 'string') {
+            logger.error('[mqttService] delKey澶辫触:', res)
+            return reply(event, res, CODE.E_100)
+        }
+        logger.info('[mqttService] delKey鎴愬姛')
+        return reply(event)
+    } catch (error) {
+        logger.error('[mqttService] delKey error:', error)
+        return reply(event, { error: error.message }, CODE.E_100)
+    }
+}
+
+/**
+ * 鍒犻櫎鍑瘉閫氱敤鍗忚鏍煎紡
+ * @param {object} data - 鍒犻櫎鍙傛暟
+ * @returns {boolean|string} true琛ㄧず鎴愬姛锛宻tring琛ㄧず閿欒淇℃伅
+ */
+mqttService.delKeyAgreement = function (data) {
+    if (data.keyIds && data.keyIds.length > 0) {
+        let userIds = []
+        for (let i = 0; i < data.keyIds.length; i++) {
+            const element = data.keyIds[i];
+            let res = sqliteService.d1_voucher.findAllByKeyId(element)
+            if (res.length <= 0) {
+                continue
+            }
+            if (res[0].type == 300) {
+                userIds.push(res[0].userId)
+            }
+        }
+        let ret = sqliteService.d1_voucher.deleteByKeyIdInBatch(data.keyIds)
+        if (ret != 0) {
+            return "sql error ret:" + ret
+        }
+        // 鍒犻櫎浜鸿劯鏁版嵁
+        userIds.forEach(element => {
+            driver.face.delete(element)
+        });
+    }
+    if (data.userIds && data.userIds.length > 0) {
+        let ret = sqliteService.d1_voucher.deleteByUserIdInBatch(data.userIds)
+        if (ret != 0) {
+            return "sql error ret:" + ret
+        }
+        // 鍒犻櫎浜鸿劯鏁版嵁
+        data.userIds.forEach(element => {
+            driver.face.delete(element)
+        });
+    }
+    return true
+}
+
+/**
+ * 娓呯┖鍑瘉
+ * @param {object} event - MQTT浜嬩欢瀵硅薄
+ */
+mqttService.clearKey = function (event) {
+    try {
+        logger.info('[mqttService] 鎺ユ敹鍒癱learKey鍛戒护:', JSON.stringify(event.topic))
+        logger.info('[mqttService] 鍛戒护payload:', event.payload)
+        let res = sqliteService.d1_voucher.findAll()
+        let userIds = []
+        res.forEach(element => {
+            if (element.type == 300) {
+                userIds.push(element.userId)
+            }
+        });
+        logger.info('[mqttService] 鎵惧埌闇�瑕佸垹闄ょ殑浜鸿劯鏁版嵁锛屽叡', userIds.length, '鏉�')
+        let ret = sqliteService.d1_voucher.deleteAll()
+        if (ret == 0) {
+            // 鍒犻櫎浜鸿劯鏁版嵁
+            logger.info('[mqttService] 寮�濮嬪垹闄や汉鑴告暟鎹�')
+            userIds.forEach((element, index) => {
+                driver.face.delete(element)
+            });
+            logger.info('[mqttService] clearKey鎴愬姛')
+            reply(event)
+        } else {
+            logger.error('[mqttService] clearKey澶辫触:', "sql error ret:" + ret)
+            reply(event, "sql error ret:" + ret, CODE.E_100)
+        }
+    } catch (error) {
+        logger.error('[mqttService] clearKey error:', error)
+        return reply(event, { error: error.message }, CODE.E_100)
+    }
+}
+
+// =================================搴旀�ュ紑浠撳瘑鐮佸鍒犳敼鏌�=================================
+/**
+ * 娣诲姞搴旀�ュ紑浠撳瘑鐮�
+ * @param {object} event - MQTT浜嬩欢瀵硅薄
+ */
+mqttService.insertEmergencyPassword = function (event) {
+    try {
+        logger.info('[mqttService] 鎺ユ敹鍒癷nsertEmergencyPassword鍛戒护:', JSON.stringify(event.topic))
+        logger.info('[mqttService] 鍛戒护payload:', event.payload)
+        let payload = JSON.parse(event.payload)
+        let data = payload.payload && payload.payload.data ? payload.payload.data : {}
+        logger.info('[mqttService] 瑙f瀽鍚庣殑鍙傛暟:', JSON.stringify(data))
+        let res = this.insertEmergencyPasswordAgreement(data)
+        if (typeof res == 'string') {
+            logger.error('[mqttService] insertEmergencyPassword澶辫触:', res)
+            return reply(event, res, CODE.E_100)
+        }
+        logger.info('[mqttService] insertEmergencyPassword鎴愬姛')
+        return reply(event)
+    } catch (error) {
+        logger.error('[mqttService] insertEmergencyPassword error:', error)
+        return reply(event, { error: error.message }, CODE.E_100)
+    }
+}
+
+/**
+ * 娣诲姞搴旀�ュ紑浠撳瘑鐮侀�氱敤鍗忚鏍煎紡
+ * @param {object} data - 搴旀�ュ紑浠撳瘑鐮佹暟鎹璞�
+ * @returns {boolean|string} true琛ㄧず鎴愬姛锛宻tring琛ㄧず閿欒淇℃伅
+ */
+mqttService.insertEmergencyPasswordAgreement = function (data) {
+    // 搴旀�ュ紑浠撳瘑鐮佸湪璁惧涓粎鏈夊敮涓�鐨�1涓紝鎵�浠ュ厛娓呯┖琛�
+    let deleteRet = sqliteService.d1_emergency_password.deleteAll()
+    if (deleteRet != 0) {
+        return "娓呯┖鏃у瘑鐮佸け璐�: " + deleteRet
+    }
+    
+    // 妫�鏌ュ瘑鐮佹槸鍚︽湁鏁�
+    if (!data.password) {
+        return "password cannot be empty"
+    }
+    
+    // 妫�鏌ュ瘑鐮侀暱搴︽槸鍚﹀ぇ浜庣瓑浜�8浣�
+    if (data.password.length < 8) {
+        return "Password length must be at least 8 digits"
+    }
+    
+    // 鏋勫缓瀵嗙爜璁板綍
+    let record = {}
+    record.id = data.id || 'emergency_' + Date.now() // 濡傛灉娌℃湁id锛岃嚜鍔ㄧ敓鎴�
+    record.password = data.password
+    record.description = data.description || ""
+    record.createTime = Date.now()
+    record.updateTime = Date.now()
+    record.status = data.status || 1
+    
+    // 淇濆瓨瀵嗙爜
+    let ret = sqliteService.d1_emergency_password.save(record)
+    if (ret == 0) {
+        return true
+    } else {
+        return "sql error ret:" + ret
+    }
+}
+
+/**
+ * 鏌ヨ搴旀�ュ紑浠撳瘑鐮�
+ * @param {object} event - MQTT浜嬩欢瀵硅薄
+ */
+mqttService.getEmergencyPassword = function (event) {
+    try {
+        logger.info('[mqttService] 鎺ユ敹鍒癵etEmergencyPassword鍛戒护:', JSON.stringify(event.topic))
+        logger.info('[mqttService] 鍛戒护payload:', event.payload)
+        let payload = JSON.parse(event.payload)
+        let res = this.getEmergencyPasswordAgreement()
+        logger.info('[mqttService] 鏌ヨ缁撴灉:', JSON.stringify(res))
+        return reply(event, res)
+    } catch (error) {
+        logger.error('[mqttService] getEmergencyPassword error:', error)
+        return reply(event, { error: error.message }, CODE.E_100)
+    }
+}
+
+/**
+ * 鏃堕棿鎴宠浆鏃ユ湡瀛楃涓�
+ * @param {number} timestamp - 鏃堕棿鎴�
+ * @returns {string} 鏃ユ湡瀛楃涓诧紝鏍煎紡锛歒YYY-MM-DD HH:MM:SS
+ */
+function timestampToDateString(timestamp) {
+    const date = new Date(timestamp);
+    const year = date.getFullYear();
+    const month = String(date.getMonth() + 1).padStart(2, '0');
+    const day = String(date.getDate()).padStart(2, '0');
+    const hours = String(date.getHours()).padStart(2, '0');
+    const minutes = String(date.getMinutes()).padStart(2, '0');
+    const seconds = String(date.getSeconds()).padStart(2, '0');
+    return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
+}
+
+/**
+ * 鏌ヨ搴旀�ュ紑浠撳瘑鐮侀�氱敤鍗忚鏍煎紡
+ * @returns {object} 鏌ヨ缁撴灉
+ */
+mqttService.getEmergencyPasswordAgreement = function () {
+    let passwords = sqliteService.d1_emergency_password.findAll()
+    if (passwords && passwords.length > 0) {
+        let password = passwords[0];
+        // 杞崲鏃堕棿鎴充负瀛楃涓叉牸寮�
+        password.createTime = timestampToDateString(password.createTime);
+        password.updateTime = timestampToDateString(password.updateTime);
+        return password;
+    }
+    return {};
+}
+
+
+/**
+ * 娓呯┖搴旀�ュ紑浠撳瘑鐮�
+ * @param {object} event - MQTT浜嬩欢瀵硅薄
+ */
+mqttService.clearEmergencyPassword = function (event) {
+    try {
+        logger.info('[mqttService] 鎺ユ敹鍒癱learEmergencyPassword鍛戒护:', JSON.stringify(event.topic))
+        logger.info('[mqttService] 鍛戒护payload:', event.payload)
+        let ret = sqliteService.d1_emergency_password.deleteAll()
+        if (ret == 0) {
+            logger.info('[mqttService] clearEmergencyPassword鎴愬姛')
+            return reply(event)
+        } else {
+            logger.error('[mqttService] clearEmergencyPassword澶辫触:', "sql error ret:" + ret)
+            return reply(event, "sql error ret:" + ret, CODE.E_100)
+        }
+    } catch (error) {
+        logger.error('[mqttService] clearEmergencyPassword error:', error)
+        return reply(event, { error: error.message }, CODE.E_100)
+    }
+}
+
+// =================================瀵嗛挜澧炲垹鏀规煡=================================
+/**
+ * 娣诲姞瀵嗛挜
+ * @param {object} event - MQTT浜嬩欢瀵硅薄
+ */
+mqttService.insertSecurity = function (event) {
+    try {
+        logger.info('[mqttService] 鎺ユ敹鍒癷nsertSecurity鍛戒护:', JSON.stringify(event.topic))
+        logger.info('[mqttService] 鍛戒护payload:', event.payload)
+        let payload = JSON.parse(event.payload)
+        let data = payload.payload && payload.payload.data ? payload.payload.data : {}
+        logger.info('[mqttService] 瑙f瀽鍚庣殑鍙傛暟:', JSON.stringify(data))
+        let res = this.insertSecurityAgreement(data)
+        if (typeof res == 'string') {
+            logger.error('[mqttService] insertSecurity澶辫触:', res)
+            return reply(event, res, CODE.E_100)
+        }
+        logger.info('[mqttService] insertSecurity鎴愬姛')
+        return reply(event)
+    } catch (error) {
+        logger.error('[mqttService] insertSecurity error:', error)
+        return reply(event, { error: error.message }, CODE.E_100)
+    }
+}
+
+/**
+ * 娣诲姞瀵嗛挜閫氱敤鍗忚鏍煎紡
+ * @param {array} data - 瀵嗛挜鏁版嵁鏁扮粍
+ * @returns {boolean|string} true琛ㄧず鎴愬姛锛宻tring琛ㄧず閿欒淇℃伅
+ */
+mqttService.insertSecurityAgreement = function (data) {
+    let securities = []
+    for (let i = 0; i < data.length; i++) {
+        const security = data[i];
+        let record = []
+        record.securityId = security.securityId
+        record.type = security.type
+        record.key = security.key
+        record.value = security.value
+        record.startTime = security.startTime
+        record.endTime = security.endTime
+        securities.push(record)
+    }
+    let ret = sqliteService.d1_security.saveAll(securities)
+    if (ret == 0) {
+        return true
+    } else {
+        return "sql error ret:" + ret
+    }
+}
+
+/**
+ * 鏌ヨ瀵嗛挜
+ * @param {object} event - MQTT浜嬩欢瀵硅薄
+ */
+mqttService.getKey = function (event) {
+    try {
+        logger.info('[mqttService] 鎺ユ敹鍒癵etKey鍛戒护:', JSON.stringify(event.topic))
+        logger.info('[mqttService] 鍛戒护payload:', event.payload)
+        let payload = JSON.parse(event.payload)
+        let data = payload.payload && payload.payload.data ? payload.payload.data : {}
+        logger.info('[mqttService] 瑙f瀽鍚庣殑鏌ヨ鍙傛暟:', JSON.stringify(data))
+        let res = this.getKeyAgreement(data)
+        logger.info('[mqttService] 鏌ヨ缁撴灉:', JSON.stringify(res))
+        return reply(event, res)
+    } catch (error) {
+        logger.error('[mqttService] getKey error:', error)
+        return reply(event, { error: error.message }, CODE.E_100)
+    }
+}
+
+/**
+ * 鏌ヨ瀵嗛挜閫氱敤鍗忚鏍煎紡
+ * @param {object} data - 鏌ヨ鍙傛暟
+ * @returns {object} 鏌ヨ缁撴灉
+ */
+mqttService.getSecurityAgreement = function (data) {
+    data.page = isEmpty(data.page) ? 0 : data.page
+    data.size = isEmpty(data.size) ? 10 : data.size
+    let totalCount = sqliteService.d1_security.count(data)
+    let securities = sqliteService.d1_security.findAll(data)
+    return {
+        content: securities,
+        page: data.page,
+        size: data.size,
+        total: totalCount,
+        totalPage: Math.ceil(totalCount / data.size),
+        count: securities.length
+    }
+}
+
+/**
+ * 鍒犻櫎瀵嗛挜
+ * @param {object} event - MQTT浜嬩欢瀵硅薄
+ */
+mqttService.delSecurity = function (event) {
+    try {
+        logger.info('[mqttService] 鎺ユ敹鍒癲elSecurity鍛戒护:', JSON.stringify(event.topic))
+        logger.info('[mqttService] 鍛戒护payload:', event.payload)
+        let payload = JSON.parse(event.payload)
+        let data = payload.payload && payload.payload.data ? payload.payload.data : {}
+        logger.info('[mqttService] 瑙f瀽鍚庣殑鍙傛暟:', JSON.stringify(data))
+        let res = this.delSecurityAgreement(data)
+        if (typeof res == 'string') {
+            logger.error('[mqttService] delSecurity澶辫触:', res)
+            return reply(event, res, CODE.E_100)
+        }
+        logger.info('[mqttService] delSecurity鎴愬姛')
+        return reply(event)
+    } catch (error) {
+        logger.error('[mqttService] delSecurity error:', error)
+        return reply(event, { error: error.message }, CODE.E_100)
+    }
+}
+
+/**
+ * 鍒犻櫎瀵嗛挜閫氱敤鍗忚鏍煎紡
+ * @param {array} data - 瀵嗛挜ID鏁扮粍
+ * @returns {boolean|string} true琛ㄧず鎴愬姛锛宻tring琛ㄧず閿欒淇℃伅
+ */
+mqttService.delSecurityAgreement = function (data) {
+    if (data.length > 0) {
+        let ret = sqliteService.d1_security.deleteBySecurityIdInBatch(data)
+        if (ret != 0) {
+            return "sql error ret:" + ret
+        }
+    }
+    return true
+}
+
+/**
+ * 娓呯┖瀵嗛挜
+ * @param {object} event - MQTT浜嬩欢瀵硅薄
+ */
+mqttService.clearSecurity = function (event) {
+    try {
+        logger.info('[mqttService] 鎺ユ敹鍒癱learSecurity鍛戒护:', JSON.stringify(event.topic))
+        logger.info('[mqttService] 鍛戒护payload:', event.payload)
+        let ret = sqliteService.d1_key.deleteAll()
+        if (ret == 0) {
+            logger.info('[mqttService] clearSecurity鎴愬姛')
+            return reply(event)
+        } else {
+            logger.error('[mqttService] clearSecurity澶辫触:', "sql error ret:" + ret)
+            return reply(event, "sql error ret:" + ret, CODE.E_100)
+        }
+    } catch (error) {
+        logger.error('[mqttService] clearSecurity error:', error)
+        return reply(event, { error: error.message }, CODE.E_100)
+    }
+}
+
+/**
+ * 杩滅▼鎺у埗
+ * @param {object} event - MQTT浜嬩欢瀵硅薄
+ */
+mqttService.control = function (event) {
+    try {
+        logger.info('[mqttService] 鎺ユ敹鍒癱ontrol鍛戒护:', JSON.stringify(event.topic))
+        logger.info('[mqttService] 鍛戒护payload:', event.payload)
+        let payload = JSON.parse(event.payload)
+        let data = payload.payload.data || {}
+        switch (data.command) {
+            case 0:
+                //閲嶅惎
+                logger.info('[mqttService] 鎵ц閲嶅惎鍛戒护')
+                reply(event)
+                common.asyncReboot(2)
+                return
+            case 1:
+                //杩滅▼寮�闂�
+                logger.info('[mqttService] 鎵ц杩滅▼寮�闂ㄥ懡浠�')
+                driver.gpio.open()
+                break
+            case 4:
+                //閲嶇疆
+                logger.info('[mqttService] 鎵ц閲嶇疆鍛戒护')
+                common.systemBrief("rm -rf /app/data/config/*")
+                common.systemBrief("rm -rf /app/data/db/*")
+                common.systemBrief("rm -rf /app/data/user/*")
+                common.systemBrief("rm -rf /app/data/user/*")
+                common.systemBrief("rm -rf /vgmj.db")
+                reply(event)
+                common.asyncReboot(2)
+                return
+            case 5:
+                //鎾斁璇煶
+                logger.info('[mqttService] 鎵ц鎾斁璇煶鍛戒护')
+                if (data.extra) {
+                    let res = common.systemWithRes(`test -e "/app/code/resource/wav/${data.extra.wav}.wav" && echo "OK" || echo "NO"`, 2)
+                    if (res.includes('OK')) {
+                        driver.alsa.play(`/app/code/resource/wav/${data.extra.wav}.wav`)
+                    }
+                }
+                break
+            case 6:
+                // 6锛氬睆骞曞睍绀哄浘鐗�
+                // TODO
+                logger.info('[mqttService] 鎵ц灞忓箷灞曠ず鍥剧墖鍛戒护')
+                break
+            case 7:
+                // 7锛氬睆骞曞睍绀烘枃瀛�
+                // TODO
+                logger.info('[mqttService] 鎵ц灞忓箷灞曠ず鏂囧瓧鍛戒护')
+                break
+            case 10:
+                logger.info('[mqttService] 鎵ц浜岀淮鐮佸睍绀哄懡浠�')
+                if (!isEmpty(data.extra.qrCodeBase64) && typeof data.extra.qrCodeBase64 == 'string') {
+                    //base64杞浘鐗囦繚瀛�
+                    let src = `/app/code/resource/image/app_qrcode.png`
+                    std.ensurePathExists(src)
+                    common.base64_2binfile(src, data.extra.qrCodeBase64)
+                    logger.info('[mqttService] 浜岀淮鐮佷繚瀛樻垚鍔�')
+                    return reply(event)
+                }
+                break
+            default:
+                logger.info('[mqttService] 鏈煡鍛戒护:', data.command)
+                break
+        }
+        logger.info('[mqttService] control鍛戒护鎵ц瀹屾垚')
+        return reply(event)
+    } catch (error) {
+        logger.error('[mqttService] control error:', error)
+        return reply(event, { error: error.message }, CODE.E_100)
+    }
+}
+
+/**
+ * 鏌ヨ閰嶇疆
+ * @param {object} event - MQTT浜嬩欢瀵硅薄
+ */
+mqttService.getConfig = function (event) {
+    try {
+        logger.info('[mqttService] 鎺ユ敹鍒癵etConfig鍛戒护:', JSON.stringify(event.topic))
+        logger.info('[mqttService] 鍛戒护payload:', event.payload)
+        let payload = JSON.parse(event.payload)
+        let data = payload.payload && payload.payload.data ? payload.payload.data : {}
+        logger.info('[mqttService] 瑙f瀽鍚庣殑鍙傛暟:', JSON.stringify(data))
+        let configAll = config.getAll()
+        let res = {}
+        // 閰嶇疆鍒嗙粍
+        for (const key in configAll) {
+            const value = configAll[key];
+            const keys = key.split(".")
+            if (keys.length == 2) {
+                if (!res[keys[0]]) {
+                    res[keys[0]] = {}
+                }
+                res[keys[0]][keys[1]] = value
+            } else {
+                res[keys[0]] = value
+            }
+        }
+        res.sys = {
+            // 淇濈暀鍘熸湁鐨� sysInfo 涓殑鍏朵粬鍊�
+            ...res.sys,
+            totalmem: common.getTotalmem(),
+            freemem: common.getFreemem(),
+            totaldisk: common.getTotaldisk(),
+            freedisk: common.getFreedisk(),
+            freecpu: common.getFreecpu()
+        };
+        if (isEmpty(data) || typeof data != "string" || data == "") {
+            // 鏌ヨ鍏ㄩ儴
+            logger.info('[mqttService] getConfig鎴愬姛锛岃繑鍥炲叏閮ㄩ厤缃紝閰嶇疆鏁伴噺:', Object.keys(res).length)
+            return reply(event, res)
+        }
+        // 鍗曟潯浠舵煡璇�"data": "mqttInfo.clientId"
+        let keys = data.split(".")
+        let search = {}
+        if (keys.length == 2) {
+            if (res[keys[0]]) {
+                search[keys[0]] = {}
+                search[keys[0]][keys[1]] = res[keys[0]][keys[1]]
+            }
+        } else {
+            search[keys[0]] = res[keys[0]]
+        }
+        logger.info('[mqttService] getConfig鎴愬姛锛岃繑鍥炴寚瀹氶厤缃�:', JSON.stringify(search))
+        return reply(event, search)
+    } catch (error) {
+        logger.error('[mqttService] getConfig error:', error)
+        return reply(event, { error: error.message }, CODE.E_100)
+    }
+}
+
+/**
+ * 淇敼閰嶇疆
+ * @param {object} event - MQTT浜嬩欢瀵硅薄
+ */
+mqttService.setConfig = function (event) {
+    try {
+        logger.info('[mqttService] 鎺ユ敹鍒皊etConfig鍛戒护:', JSON.stringify(event.topic))
+        logger.info('[mqttService] 鍛戒护payload:', event.payload)
+        let payload = JSON.parse(event.payload)
+        let data = payload.payload && payload.payload.data ? payload.payload.data : {}
+        logger.info('[mqttService] 瑙f瀽鍚庣殑鍙傛暟:', JSON.stringify(data))
+        if (!data || typeof data != 'object') {
+            logger.error('[mqttService] setConfig澶辫触: data should not be empty')
+            return reply(event, "data should not be empty", CODE.E_100)
+        }
+        let res = configService.configVerifyAndSave(data)
+        if (typeof res != 'boolean') {
+            // 杩斿洖閿欒淇℃伅
+            logger.error('[mqttService] setConfig澶辫触:', res)
+            return reply(event, res, CODE.E_100)
+        }
+        if (res) {
+            logger.info('[mqttService] setConfig鎴愬姛')
+            return reply(event)
+        } else {
+            logger.error('[mqttService] setConfig澶辫触: unknown failure')
+            return reply(event, "unknown failure", CODE.E_100)
+        }
+    } catch (error) {
+        logger.error('[mqttService] setConfig error:', error)
+        return reply(event, { error: error.message }, CODE.E_100)
+    }
+}
+
+/**
+ * 鍗囩骇鍥轰欢
+ * @param {object} event - MQTT浜嬩欢瀵硅薄
+ */
+mqttService.upgradeFirmware = function (event) {
+    try {
+        logger.info('[mqttService] 鎺ユ敹鍒皍pgradeFirmware鍛戒护:', JSON.stringify(event.topic))
+        logger.info('[mqttService] 鍛戒护payload:', event.payload)
+        let payload = JSON.parse(event.payload)
+        let data = payload.payload && payload.payload.data ? payload.payload.data : {}
+        logger.info('[mqttService] 瑙f瀽鍚庣殑鍙傛暟:', JSON.stringify(data))
+        if (!data || typeof data != 'object' || typeof data.type != 'number' || typeof data.url != 'string' || typeof data.md5 != 'string') {
+            logger.error('[mqttService] upgradeFirmware澶辫触: data\'s params error')
+            return reply(event, "data's params error", CODE.E_100)
+        }
+
+        if (data.type == 0) {
+            try {
+                logger.info('[mqttService] 寮�濮嬪浐浠跺崌绾э紝url:', data.url, 'md5:', data.md5)
+                driver.screen.upgrade({ title: "confirm.upgrade", content: "confirm.upgrading" })
+                ota.updateHttp(data.url, data.md5, 300)
+                driver.screen.upgrade({ title: "confirm.upgrade", content: "confirm.upgradeSuccess" })
+                logger.info('[mqttService] 鍥轰欢鍗囩骇鎴愬姛')
+                reply(event)
+                common.asyncReboot(3)
+                return
+            } catch (error) {
+                logger.error('[mqttService] 鍥轰欢鍗囩骇澶辫触:', error)
+                driver.screen.upgrade({ title: "confirm.upgrade", content: "confirm.upgradeFail" })
+                return reply(event, "upgrade failure", CODE.E_100)
+            }
+        }
+
+        logger.error('[mqttService] upgradeFirmware澶辫触: 涓嶆敮鎸佺殑鍗囩骇绫诲瀷')
+        return reply(event, "upgrade failure", CODE.E_100)
+    } catch (error) {
+        logger.error('[mqttService] upgradeFirmware error:', error)
+        return reply(event, { error: error.message }, CODE.E_100)
+    }
+}
+
+/**
+ * 鏌ヨ璇嗗埆璁板綍
+ * @param {object} event - MQTT浜嬩欢瀵硅薄
+ */
+mqttService.getRecords = function (event) {
+    try {
+        logger.info('[mqttService] 鎺ユ敹鍒癵etRecords鍛戒护:', JSON.stringify(event.topic))
+        logger.info('[mqttService] 鍛戒护payload:', event.payload)
+        let payload = JSON.parse(event.payload)
+        let data = payload.payload && payload.payload.data ? payload.payload.data : {}
+        logger.info('[mqttService] 瑙f瀽鍚庣殑鏌ヨ鍙傛暟:', JSON.stringify(data))
+        let res = this.getRecordsAgreement(data)
+        logger.info('[mqttService] 鏌ヨ缁撴灉:', JSON.stringify(res))
+        return reply(event, res)
+    } catch (error) {
+        logger.error('[mqttService] getRecords error:', error)
+        return reply(event, { error: error.message }, CODE.E_100)
+    }
+}
+
+/**
+ * 灏嗘棩鏈熷瓧绗︿覆杞崲涓烘椂闂存埑锛堢锛�
+ * @param {string} dateString - 鏃ユ湡瀛楃涓诧紝鏍煎紡锛歒YYY-MM-DD HH:MM:SS
+ * @returns {number} 鏃堕棿鎴筹紙绉掞級
+ */
+function dateStringToTimestamp(dateString) {
+    if (!dateString) return null
+    // 灏哬YYY-MM-DD HH:MM:SS鏍煎紡杞崲涓篩YYY-MM-DDTHH:MM:SS鏍煎紡锛屼互渚縩ew Date()姝g‘瑙f瀽
+    const formattedDateString = dateString.replace(' ', 'T')
+    const date = new Date(formattedDateString)
+    return Math.floor(date.getTime() / 1000)
+}
+
+/**
+ * 鏌ヨ璇嗗埆璁板綍閫氱敤鍗忚鏍煎紡
+ * @param {object} data - 鏌ヨ鍙傛暟
+ * @returns {object} 鏌ヨ缁撴灉
+ */
+mqttService.getRecordsAgreement = function (data) {
+    data.page = isEmpty(data.page) ? 0 : data.page
+    data.size = isEmpty(data.size) ? 10 : data.size
+    
+    // 澶勭悊鏃堕棿鍙傛暟锛屽皢瀛楃涓叉牸寮忚浆鎹负鏃堕棿鎴�
+    let startTime = null
+    let endTime = null
+    if (data.startTime) {
+        if (typeof data.startTime === 'string') {
+            startTime = dateStringToTimestamp(data.startTime)
+        } else {
+            startTime = Math.floor(data.startTime / 1000) // 杞崲涓虹绾ф椂闂存埑
+        }
+    }
+    if (data.endTime) {
+        if (typeof data.endTime === 'string') {
+            endTime = dateStringToTimestamp(data.endTime)
+        } else {
+            endTime = Math.floor(data.endTime / 1000) // 杞崲涓虹绾ф椂闂存埑
+        }
+    }
+    
+    // 鏋勫缓鏌ヨ鏉′欢
+    let queryData = {}
+    let nameFilter = null
+    // 澶嶅埗鍏朵粬鏌ヨ鍙傛暟
+    for (const key in data) {
+        if (key !== 'startTime' && key !== 'endTime' && key !== 'name') {
+            queryData[key] = data[key]
+        } else if (key === 'name') {
+            nameFilter = data[key]
+        }
+    }
+    
+    // 鏋勫缓SQL鏉′欢
+    let whereClause = ''
+    if (startTime) {
+        whereClause += `time >= ${startTime} `
+    }
+    if (endTime) {
+        if (whereClause) {
+            whereClause += `AND `
+        }
+        whereClause += `time <= ${endTime} `
+    }
+    
+    // 澶嶅埗鍏朵粬鏉′欢
+    for (const key in queryData) {
+        if (key !== 'page' && key !== 'size') {
+            if (whereClause) {
+                whereClause += `AND `
+            }
+            if (typeof queryData[key] === 'string') {
+                whereClause += `${key} = '${queryData[key]}' `
+            } else {
+                whereClause += `${key} = ${queryData[key]} `
+            }
+        }
+    }
+    
+    // 鎵ц鏌ヨ
+    let totalCount = 0
+    let securities = []
+    try {
+        // 鏋勫缓count SQL
+        let countSql = `SELECT COUNT(*) FROM d1_pass_record `
+        if (whereClause) {
+            countSql += `WHERE ${whereClause} `
+        }
+        countSql += `;`
+        let countResult = sqlite.select(countSql)
+        if (countResult && countResult[0] && countResult[0]['COUNT(*)']) {
+            totalCount = countResult[0]['COUNT(*)']
+        }
+        
+        // 鏋勫缓findAll SQL
+        let findSql = `SELECT * FROM d1_pass_record `
+        if (whereClause) {
+            findSql += `WHERE ${whereClause} `
+        }
+        findSql += `ORDER BY time DESC `
+        if (queryData.page !== undefined && queryData.size !== undefined) {
+            findSql += `LIMIT ${queryData.size} OFFSET ${queryData.page * queryData.size} `
+        }
+        findSql += `;`
+        securities = sqlite.select(findSql)
+    } catch (error) {
+        logger.error('[mqttService] 鏌ヨ璁板綍澶辫触:', error)
+    }
+    
+    // 澶勭悊姣忔潯璁板綍
+    let processedSecurities = securities.map(record => {
+        // 瑙f瀽extra瀛楁
+        let extraData = {}
+        try {
+            if (record.extra && record.extra !== '') {
+                extraData = JSON.parse(record.extra)
+            }
+        } catch (error) {
+            logger.error('[mqttService] 瑙f瀽extra澶辫触:', error)
+        }
+        
+        // 瑙f瀽extra2瀛楁
+        let extra2Data = {}
+        try {
+            if (record.extra2 && record.extra2 !== '') {
+                extra2Data = JSON.parse(record.extra2)
+            }
+        } catch (error) {
+            logger.error('[mqttService] 瑙f瀽extra2澶辫触:', error)
+        }
+        
+        // 鏋勫缓鏂拌褰�
+        return {
+            id: record.id,
+            keyId: record.keyId,
+            permissionId: record.permissionId,
+            permissionId2: record.permissionId2,
+            userId: record.userId,
+            userId2: record.userId2,
+            type: record.type,
+            code: record.code,
+            door: record.door,
+            time: timestampToDateString(record.time * 1000), // 灏嗙绾ф椂闂存埑杞崲涓烘绉掔骇锛屽啀杞崲涓烘棩鏈熷瓧绗︿覆
+            result: record.result,
+            name: extraData.name || '',
+            idCard: extraData.idCard || '',
+            name2: extra2Data.name || '',
+            idCard2: extra2Data.idCard || '',
+            message: record.message
+        }
+    })
+    
+    // 搴旂敤name杩囨护
+    if (nameFilter) {
+        processedSecurities = processedSecurities.filter(record => 
+            record.name.toLowerCase().includes(nameFilter.toLowerCase())
+        )
+        // 鏇存柊鎬绘暟鍜屾�婚〉鏁�
+        totalCount = processedSecurities.length
+    }
+    
+    return {
+        content: processedSecurities,
+        page: data.page,
+        size: data.size,
+        total: totalCount,
+        totalPage: Math.ceil(totalCount / data.size),
+        count: processedSecurities.length
+    }
+}
+
+/**
+ * 鍒犻櫎璁板綍
+ * @param {object} event - MQTT浜嬩欢瀵硅薄
+ */
+mqttService.delRecords = function (event) {
+    try {
+        logger.info('[mqttService] 鎺ユ敹鍒癲elRecords鍛戒护:', JSON.stringify(event.topic))
+        logger.info('[mqttService] 鍛戒护payload:', event.payload)
+        let payload = JSON.parse(event.payload)
+        let data = payload.payload && payload.payload.data ? payload.payload.data : {}
+        logger.info('[mqttService] 瑙f瀽鍚庣殑鍙傛暟:', JSON.stringify(data))
+        let res = this.delRecordsAgreement(data)
+        if (typeof res == 'string') {
+            logger.error('[mqttService] delRecords澶辫触:', res)
+            return reply(event, res, CODE.E_100)
+        }
+        logger.info('[mqttService] delRecords鎴愬姛')
+        return reply(event)
+    } catch (error) {
+        logger.error('[mqttService] delRecords error:', error)
+        return reply(event, { error: error.message }, CODE.E_100)
+    }
+}
+
+/**
+ * 鍒犻櫎璁板綍閫氱敤鍗忚鏍煎紡
+ * @param {object} data - 鍒犻櫎鍙傛暟
+ * @returns {boolean|string} true琛ㄧず鎴愬姛锛宻tring琛ㄧず閿欒淇℃伅
+ */
+mqttService.delRecordsAgreement = function (data) {
+    
+    // 鏍规嵁鏃堕棿鑼冨洿鍒犻櫎璁板綍
+    if (data.startTime || data.endTime) {
+        logger.info('[mqttService] 鏃堕棿鑼冨洿: startTime=' + data.startTime + ', endTime=' + data.endTime)
+        
+        try {
+            // 鏋勫缓鏌ヨ鏉′欢
+            let query = {};
+            if (data.startTime) {
+                query.startTime = data.startTime;
+            }
+            if (data.endTime) {
+                query.endTime = data.endTime;
+            }
+            
+            // 浣跨敤getRecordsAgreement鍑芥暟鐨勬煡璇㈤�昏緫鏉ヨ幏鍙栫鍚堟潯浠剁殑璁板綍
+            let result = mqttService.getRecordsAgreement(query);
+            let records = result.content || [];
+            
+            // 閫愪釜鍒犻櫎璁板綍
+            let deletedCount = 0;
+            for (let record of records) {
+                // 濡傛灉鏄汉鑴歌褰曪紝鍒犻櫎瀵瑰簲鐨勫浘鐗囨枃浠�
+                if (record.type == 300 && record.code) {
+                    try {
+                        common.systemBrief(`rm -rf ${record.code}`);
+                    } catch (error) {
+                        logger.error('[mqttService] 鍒犻櫎鍥剧墖鏂囦欢鍑洪敊: ' + error.message);
+                    }
+                }
+                // 鍒犻櫎璁板綍
+                sqliteService.d1_pass_record.delete({ id: record.id });
+                deletedCount++;
+            }
+            
+            logger.info('[mqttService] 鎴愬姛鍒犻櫎 ' + deletedCount + ' 鏉¤褰�');
+        } catch (error) {
+            logger.error('[mqttService] 鍒犻櫎璁板綍鍑洪敊: ' + error.message);
+            // 蹇界暐閿欒锛岃繑鍥炴垚鍔�
+        }
+    }
+    
+    return true
+}
+/**
+ * 閫氳涓婃姤鍥炲
+ * @param {object} event - MQTT浜嬩欢瀵硅薄
+ */
+mqttService.access_reply = function (event) {
+    try {
+        logger.info('[mqttService] 鎺ユ敹鍒癮ccess_reply鍛戒护:', JSON.stringify(event.topic))
+        logger.info('[mqttService] 鍛戒护payload:', event.payload)
+        let payload = JSON.parse(event.payload)
+        logger.info('[mqttService] 瑙f瀽鍚庣殑鍙傛暟:', JSON.stringify(payload))
+        let serialNo = map.get(payload.serialNo)
+        if (serialNo) {
+            logger.info('[mqttService] 娓呯悊涓存椂鏂囦欢:', serialNo)
+            common.systemBrief(`rm -rf ${serialNo}`)
+            map.del(payload.serialNo)
+        }
+        logger.info('[mqttService] 娓呯┖閫氳璁板綍')
+        sqliteService.d1_pass_record.deleteAll()
+        logger.info('[mqttService] access_reply澶勭悊瀹屾垚')
+    } catch (error) {
+        logger.error('[mqttService] access_reply error:', error)
+    }
+}
+
+/**
+ * 鍦ㄧ嚎楠岃瘉鍥炲
+ * @param {object} raw - MQTT浜嬩欢瀵硅薄
+ */
+mqttService.access_online_reply = function (raw) {
+    try {
+        logger.info('[mqttService] 鎺ユ敹鍒癮ccess_online_reply鍛戒护:', JSON.stringify(raw.topic))
+        logger.info('[mqttService] 鍛戒护payload:', raw.payload)
+        let payload = JSON.parse(raw.payload)
+        logger.info('[mqttService] 瑙f瀽鍚庣殑鍙傛暟:', JSON.stringify(payload))
+        let map = dxMap.get("VERIFY")
+        let data = map.get(payload.serialNo)
+        if (data) {
+            logger.info('[mqttService] 澶勭悊鍦ㄧ嚎楠岃瘉鍥炲锛宻erialNo:', payload.serialNo)
+            map.del(payload.serialNo)
+            driver.mqtt.getOnlinecheckReply(payload)
+        }
+        logger.info('[mqttService] access_online_reply澶勭悊瀹屾垚')
+    } catch (error) {
+        logger.error('[mqttService] access_online_reply error:', error)
+    }
+}
+
+/**
+ * 閿欒浠g爜瀹氫箟
+ */
+const CODE = {
+    // 鎴愬姛
+    S_000: "000000",
+    // 鏈煡閿欒
+    E_100: "100000",
+    // 璁惧宸茶绂佺敤	
+    E_101: "100001",
+    // 璁惧姝e繖锛岃绋嶅悗鍐嶈瘯	
+    E_102: "100002",
+    // 绛惧悕妫�楠屽け璐�	
+    E_103: "100003",
+    // 瓒呮椂閿欒
+    E_104: "100004",
+    // 璁惧绂荤嚎	
+    E_105: "100005",
+}
+mqttService.CODE = CODE
+
+/**
+ * 涓婃姤璁惧淇℃伅鍜岄�氳璁板綍
+ */
+mqttService.report = function () {
+    // 鍦ㄧ嚎涓婃姤
+    let payloadReply = mqttReply(std.genRandomStr(10), {
+        mac: config.get("sys.mac") || '',
+        version: config.get("sys.version"),
+        appVersion: config.get("sys.version"),
+        releaseTime: config.get("sys.createTime"),
+        type: config.get("net.type"),
+    }, CODE.S_000)
+    driver.mqtt.send("access_device/v2/event/connect", JSON.stringify(payloadReply))
+
+    //閫氳璁板綍涓婃姤 - 宸插叧闂�
+    // let res = sqliteService.d1_pass_record.findAll()
+    // if (res.length <= 0) {
+    //     return
+    // }
+    // // 绛涢�夊嚭 type === 300 鐨勫璞★紙浜鸿劯璁板綍锛�
+    // let faceArray = res.filter(item => item.type == 300);
+    // // 绛涢�夊嚭 type !== 300 鐨勫璞★紙鍏朵粬璁板綍锛�
+    // let recordArray = res.filter(item => item.type != 300);
+    // if (recordArray.length > 0) {
+    //     driver.mqtt.send("access_device/v2/event/access", JSON.stringify(mqttReply(std.genRandomStr(10), recordArray, CODE.S_000)))
+    // }
+    // if (faceArray.length > 0) {
+    //     let index = 0
+    //     let timer = std.setInterval(() => {
+    //         let serialNo = std.genRandomStr(10)
+    //         //缂撳瓨鏀惧叆瑕佸垹闄ょ殑浜鸿劯鐓х墖 src
+    //         map.del(serialNo)
+    //         map.put(serialNo, faceArray[index].code)
+    //         
+    //         // 妫�鏌aceArray[index].code鏄惁鏈夋晥
+    //         if (faceArray[index].code) {
+    //             faceArray[index].code = driver.face.fileToBase64(faceArray[index].code)
+    //         } else {
+    //             faceArray[index].code = ""
+    //             logger.info("浜鸿劯璁板綍涓璫ode瀛楁涓虹┖锛岃烦杩嘊ase64杞崲")
+    //         }
+    //         
+    //         driver.mqtt.send("access_device/v2/event/access", JSON.stringify(mqttReply(serialNo, [faceArray[index]], CODE.S_000)))
+    //         index++
+    //         if (!faceArray[index]) {
+    //             std.clearInterval(saveTimer)
+    //             std.clearInterval(timer)
+    //         }
+    //     }, 1000)
+    //     // 姣忛殧500ms妫�鏌ヤ竴娆qtt杩炴帴鐘舵�侊紝濡傛灉鏂紑锛屽垯鍋滄涓婃姤
+    //     let saveTimer = std.setInterval(() => {
+    //         if (!driver.mqtt.getStatus()) {
+    //             std.clearInterval(saveTimer)
+    //             std.clearInterval(timer)
+    //         }
+    //     }, 500)
+    // }
+}
+
+/**
+ * mqtt璇锋眰缁熶竴鍥炲
+ * @param {object} event - MQTT浜嬩欢瀵硅薄
+ * @param {any} data - 鍥炲鏁版嵁
+ * @param {string} code - 閿欒浠g爜
+ */
+function reply(event, data, code) {
+    try {
+        let topic = getReplyTopic(event)
+        let payload = JSON.parse(event.payload)
+        let serialNo = payload.serialNo || std.genRandomStr(10)
+        let reply = JSON.stringify(mqttReply(serialNo, data, isEmpty(code) ? CODE.S_000 : code))
+        driver.mqtt.send(topic, reply)
+    } catch (error) {
+        logger.error('[mqttService] reply error:', error)
+    }
+}
+
+/**
+ * 鑾峰彇鍥炲涓婚
+ * @param {object} data - MQTT浜嬩欢瀵硅薄
+ * @returns {string} 鍥炲涓婚
+ */
+function getReplyTopic(data) {
+    //    return data.topic.replace("/" + config.get("sys.sn"), '') + "_reply";
+    try {
+        let sn = config.get("mqtt.clientId")
+        return data.topic.replace("/" + sn, '') + "_reply";
+    } catch (error) {
+        logger.error('[mqttService] getReplyTopic error:', error)
+        // 鍥為��鍒颁娇鐢ㄥ浐瀹氭牸寮�
+        return data.topic + "_reply"
+    }
+}
+
+/**
+ * mqtt鍥炲鏍煎紡鏋勫缓
+ * @param {string} serialNo - 搴忓垪鍙�
+ * @param {any} data - 鍥炲鏁版嵁
+ * @param {string} code - 閿欒浠g爜
+ * @returns {object} 鍥炲鏍煎紡瀵硅薄
+ */
+function mqttReply(serialNo, data, code) {
+    // 鐢熸垚褰撳墠鏃堕棿鐨勫瓧绗︿覆鏍煎紡
+    const now = new Date();
+    const year = now.getFullYear();
+    const month = String(now.getMonth() + 1).padStart(2, '0');
+    const day = String(now.getDate()).padStart(2, '0');
+    const hours = String(now.getHours()).padStart(2, '0');
+    const minutes = String(now.getMinutes()).padStart(2, '0');
+    const seconds = String(now.getSeconds()).padStart(2, '0');
+    const timeString = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
+    
+    return {
+        serialNo: serialNo,
+        uuid: config.get("sys.uuid"),
+        sign: '',
+        code: code,
+        data: data,
+        time: timeString
+    }
+}
+mqttService.mqttReply = mqttReply
+
+/**
+ * 鑾峰彇鎵�鏈夎闃呯殑topic
+ * @returns {array} 璁㈤槄鐨則opic鍒楄〃
+ */
+mqttService.getTopics = function () {
+    // 鑾峰彇鎵�鏈夎闃呯殑topic
+    let sn = config.get("mqtt.clientId")
+    const topics = [
+        "control", "getConfig", "setConfig", "upgradeFirmware", "test",
+        "getPermission", "insertPermission", "delPermission", "clearPermission",
+        "getKey", "insertKey", "delKey", "clearKey",
+        "getUser", "insertUser", "delUser", "clearUser",
+        "getSecurity", "insertSecurity", "delSecurity", "clearSecurity", "getRecords", "delRecords",
+        "insertEmergencyPassword", "delEmergencyPassword", "clearEmergencyPassword", "getEmergencyPassword"
+    ]
+    const eventReplies = ["connect_reply", "alarm_reply", "access_reply", "access_online_reply"]
+
+    let flag = 'access_device/v2/cmd/' + sn + "/"
+    let eventFlag = 'access_device/v2/event/' + sn + "/"
+    return topics.map(item => flag + item).concat(eventReplies.map(item => eventFlag + item));
+}
+
+/**
+ * 鍒ょ┖鍑芥暟
+ * @param {any} value - 瑕佸垽鏂殑鍊�
+ * @returns {boolean} 鏄惁涓虹┖
+ */
+function isEmpty(value) {
+    return value === undefined || value === null || value === ""
+}
+
+export default mqttService
+
+/*
+`mqttService.getTopics()` 鍑芥暟杩斿洖鐨勬墍鏈� topic 濡備笅锛�
+
+### 鍛戒护 topic锛堢敤浜庢帴鏀舵湇鍔″櫒涓嬪彂鐨勫懡浠わ級锛�
+- `access_device/v2/cmd/{sn}/control` - 鎺у埗鍛戒护
+- `access_device/v2/cmd/{sn}/getConfig` - 鑾峰彇閰嶇疆
+- `access_device/v2/cmd/{sn}/setConfig` - 璁剧疆閰嶇疆
+- `access_device/v2/cmd/{sn}/upgradeFirmware` - 鍥轰欢鍗囩骇
+- `access_device/v2/cmd/{sn}/test` - 娴嬭瘯鍛戒护
+- `access_device/v2/cmd/{sn}/getPermission` - 鑾峰彇鏉冮檺
+- `access_device/v2/cmd/{sn}/insertPermission` - 鎻掑叆鏉冮檺
+- `access_device/v2/cmd/{sn}/delPermission` - 鍒犻櫎鏉冮檺
+- `access_device/v2/cmd/{sn}/clearPermission` - 娓呴櫎鏉冮檺
+- `access_device/v2/cmd/{sn}/getKey` - 鑾峰彇瀵嗛挜
+- `access_device/v2/cmd/{sn}/insertKey` - 鎻掑叆瀵嗛挜
+- `access_device/v2/cmd/{sn}/delKey` - 鍒犻櫎瀵嗛挜
+- `access_device/v2/cmd/{sn}/clearKey` - 娓呴櫎瀵嗛挜
+- `access_device/v2/cmd/{sn}/getUser` - 鑾峰彇鐢ㄦ埛
+- `access_device/v2/cmd/{sn}/insertUser` - 鎻掑叆鐢ㄦ埛
+- `access_device/v2/cmd/{sn}/delUser` - 鍒犻櫎鐢ㄦ埛
+- `access_device/v2/cmd/{sn}/clearUser` - 娓呴櫎鐢ㄦ埛
+- `access_device/v2/cmd/{sn}/getSecurity` - 鑾峰彇瀹夊叏淇℃伅
+- `access_device/v2/cmd/{sn}/insertSecurity` - 鎻掑叆瀹夊叏淇℃伅
+- `access_device/v2/cmd/{sn}/delSecurity` - 鍒犻櫎瀹夊叏淇℃伅
+- `access_device/v2/cmd/{sn}/clearSecurity` - 娓呴櫎瀹夊叏淇℃伅
+- `access_device/v2/cmd/{sn}/getRecords` - 鑾峰彇璁板綍
+- `access_device/v2/cmd/{sn}/delRecords` - 鍒犻櫎璁板綍
+
+### 浜嬩欢鍥炲 topic锛堢敤浜庢帴鏀舵湇鍔″櫒瀵逛簨浠剁殑鍥炲锛夛細
+- `access_device/v2/event/{sn}/connect_reply` - 杩炴帴鍥炲
+- `access_device/v2/event/{sn}/alarm_reply` - 鍛婅鍥炲
+- `access_device/v2/event/{sn}/access_reply` - 閫氳鍥炲
+- `access_device/v2/event/{sn}/access_online_reply` - 鍦ㄧ嚎楠岃瘉鍥炲
+
+鍏朵腑 `{sn}` 鏄澶囩殑搴忓垪鍙凤紝浼氳鏇挎崲涓哄疄闄呯殑璁惧搴忓垪鍙枫��
+*/
\ No newline at end of file
diff --git a/vf107/src/service/grainService.js b/vf107/src/service/grainService.js
index ee4a283..a182a10 100644
--- a/vf107/src/service/grainService.js
+++ b/vf107/src/service/grainService.js
@@ -36,7 +36,7 @@
     "401": "鏈櫥褰曪紝鐢ㄦ埛涓嶅瓨鍦�",
     "403": "鐢ㄦ埛鏃犳潈闄�",
     "404": "璇锋眰鍔熻兘涓嶅瓨鍦�",
-    "500": "璇锋眰鎵ц寮傚父锛岃鑱旂郴绠$悊鍛�"
+    "500": "璇锋眰鎵ц寮傚父锛岃鑱旂郴绉戦暱"
 }
 
 // 鎿嶄綔鎸夐挳瀵瑰簲鐨勮闊虫枃浠�
diff --git a/vf107/src/service/httpService.js b/vf107/src/service/httpService.js
index 0fb560e..caeb8b0 100644
--- a/vf107/src/service/httpService.js
+++ b/vf107/src/service/httpService.js
@@ -172,7 +172,20 @@
     server.route("/clearSecurity", function (req, res) {
         clearSecurity(req, res);
     });
- 
+
+    //娣诲姞搴旀�ュ紑浠撳瘑鐮�
+    server.route("/insertEmergencyPassword", function (req, res) {
+        insertEmergencyPassword(req, res);
+    });
+    //鏌ヨ搴旀�ュ紑浠撳瘑鐮�
+    server.route("/getEmergencyPassword", function (req, res) {
+        getEmergencyPassword(req, res);
+    });
+    //娓呯┖搴旀�ュ紑浠撳瘑鐮�
+    server.route("/clearEmergencyPassword", function (req, res) {
+        clearEmergencyPassword(req, res);
+    });
+
     //鑾峰彇鎸囩汗鐗瑰緛
     server.route("/getFingerChar", function (req, res) {
         getFingerChar(req, res);
@@ -1001,6 +1014,77 @@
     res.send(JSON.stringify(result), { "Content-Type": "application/json" });
 }
 
+// 娣诲姞搴旀�ュ紑浠撳瘑鐮�
+function insertEmergencyPassword(req, res) {
+    let result = {
+        code: 400,
+        message: "",
+        data: {},
+    }
+    if (verifyToken(req)) {
+        let body = req.body;
+        body = JSON.parse(body).data;
+        try {
+            let res = api.insertEmergencyPassword(body)
+            if (typeof res == 'string') {
+                result.data = res
+            } else {
+                result.code = 200
+            }
+        } catch (error) {
+            result.message = error.message
+        }
+    } else {
+        result = messageExpired
+    }
+    res.send(JSON.stringify(result), { "Content-Type": "application/json" });
+}
+
+// 鏌ヨ搴旀�ュ紑浠撳瘑鐮�
+function getEmergencyPassword(req, res) {
+    let result = {
+        code: 400,
+        message: "",
+        data: {},
+    }
+    if (verifyToken(req)) {
+        try {
+            let res = api.getEmergencyPassword()
+            result.code = 200
+            result.data = res
+        } catch (error) {
+            result.message = error.message
+        }
+    } else {
+        result = messageExpired
+    }
+    res.send(JSON.stringify(result), { "Content-Type": "application/json" });
+}
+
+// 娓呯┖搴旀�ュ紑浠撳瘑鐮�
+function clearEmergencyPassword(req, res) {
+    let result = {
+        code: 400,
+        message: "",
+        data: {},
+    }
+    if (verifyToken(req)) {
+        try {
+            let res = api.clearEmergencyPassword()
+            if (typeof res == 'string') {
+                result.data = res
+            } else {
+                result.code = 200
+            }
+        } catch (error) {
+            result.message = error.message
+        }
+    } else {
+        result = messageExpired
+    }
+    res.send(JSON.stringify(result), { "Content-Type": "application/json" });
+}
+
 // 鑾峰彇鎸囩汗鐗瑰緛
 function getFingerChar(req,res) {
     let result = {
diff --git a/vf107/src/service/mqttService.js b/vf107/src/service/mqttService.js
index b582aa4..61721b4 100644
--- a/vf107/src/service/mqttService.js
+++ b/vf107/src/service/mqttService.js
@@ -42,7 +42,7 @@
  */
 mqttService.insertPermission = function (event) {
     let payload = JSON.parse(event.payload)
-    let data = payload.data
+    let data = payload.payload && payload.payload.data ? payload.payload.data : payload.data
     if (data.length > 100) {
         return reply(event, "data length should not be greater than 100", CODE.E_100)
     }
@@ -58,7 +58,7 @@
  */
 mqttService.getPermission = function (event) {
     let payload = JSON.parse(event.payload)
-    let data = payload.data
+    let data = payload.payload && payload.payload.data ? payload.payload.data : payload.data
     let res = api.getPermission(data)
     return reply(event, res)
 }
@@ -68,7 +68,7 @@
  */
 mqttService.delPermission = function (event) {
     let payload = JSON.parse(event.payload)
-    let data = payload.data
+    let data = payload.payload && payload.payload.data ? payload.payload.data : payload.data
     let res = api.delPermission(data)
     if (Array.isArray(res)) {
         return reply(event, res, CODE.E_100)
@@ -81,7 +81,7 @@
  */
 mqttService.modifyPermission = function (event) {
     let payload = JSON.parse(event.payload)
-    let data = payload.data
+    let data = payload.payload && payload.payload.data ? payload.payload.data : payload.data
     if (data.length > 100) {
         return reply(event, "data length should not be greater than 100", CODE.E_100)
     }
@@ -111,7 +111,7 @@
  */
 mqttService.insertUser = function (event) {
     let payload = JSON.parse(event.payload)
-    let data = payload.data
+    let data = payload.payload && payload.payload.data ? payload.payload.data : payload.data
     if (data.length > 100) {
         return reply(event, "data length should not be greater than 100", CODE.E_100)
     }
@@ -128,7 +128,7 @@
  */
 mqttService.getUser = function (event) {
     let payload = JSON.parse(event.payload)
-    let data = payload.data
+    let data = payload.payload && payload.payload.data ? payload.payload.data : payload.data
     let res = api.getUser(data)
     return reply(event, res)
 }
@@ -138,7 +138,7 @@
  */
 mqttService.delUser = function (event) {
     let payload = JSON.parse(event.payload)
-    let data = payload.data
+    let data = payload.payload && payload.payload.data ? payload.payload.data : payload.data
     let res = api.delUser(data)
     if (Array.isArray(res)) {
         return reply(event, res, CODE.E_100)
@@ -163,7 +163,7 @@
  */
 mqttService.modifyUser = function (event) {
     let payload = JSON.parse(event.payload)
-    let data = payload.data
+    let data = payload.payload && payload.payload.data ? payload.payload.data : payload.data
     if (data.length > 100) {
         return reply(event, "data length should not be greater than 100", CODE.E_100)
     }
@@ -171,7 +171,7 @@
     if (Array.isArray(res)) {
         return reply(event, res, CODE.E_100)
     }
-    return reply(event, res)
+    return reply(event)
 }
 
 // =================================鍑瘉澧炲垹鏀规煡=================================
@@ -180,7 +180,7 @@
  */
 mqttService.insertKey = function (event) {
     let payload = JSON.parse(event.payload)
-    let data = payload.data
+    let data = payload.payload && payload.payload.data ? payload.payload.data : payload.data
     if (data.length > 100) {
         return reply(event, "data length should not be greater than 100", CODE.E_100)
     }
@@ -196,7 +196,7 @@
  */
 mqttService.getKey = function (event) {
     let payload = JSON.parse(event.payload)
-    let data = payload.data
+    let data = payload.payload && payload.payload.data ? payload.payload.data : payload.data
     let res = api.getKey(data)
     if (typeof res == 'string') {
         return reply(event, res, CODE.E_100)
@@ -209,7 +209,7 @@
  */
 mqttService.delKey = function (event) {
     let payload = JSON.parse(event.payload)
-    let data = payload.data
+    let data = payload.payload && payload.payload.data ? payload.payload.data : payload.data
     let res = api.delKey(data)
     if (Array.isArray(res)) {
         return reply(event, res, CODE.E_100)
@@ -223,7 +223,7 @@
  */
 mqttService.clearKey = function (event) {
     let payload = JSON.parse(event.payload)
-    let data = payload.data
+    let data = payload.payload && payload.payload.data ? payload.payload.data : payload.data
     let ret = api.clearKey(data)
     if (typeof ret == "string") {
         return reply(event, "sql error ret:" + ret, CODE.E_100)
@@ -237,7 +237,7 @@
  */
 mqttService.modifyKey = function (event) {
     let payload = JSON.parse(event.payload)
-    let data = payload.data
+    let data = payload.payload && payload.payload.data ? payload.payload.data : payload.data
     if (data.length > 100) {
         return reply(event, "data length should not be greater than 100", CODE.E_100)
     }
@@ -249,13 +249,163 @@
 }
 
 
+
+// =================================搴旀�ュ紑浠撳瘑鐮佸鍒犳敼鏌�=================================
+/**
+ * 娣诲姞搴旀�ュ紑浠撳瘑鐮�
+ * @param {object} event - MQTT浜嬩欢瀵硅薄
+ */
+mqttService.insertEmergencyPassword = function (event) {
+    try {
+        logger.info('[mqttService] 鎺ユ敹鍒癷nsertEmergencyPassword鍛戒护:', JSON.stringify(event.topic))
+        logger.info('[mqttService] 鍛戒护payload:', event.payload)
+        let payload = JSON.parse(event.payload)
+        let data = payload.payload && payload.payload.data ? payload.payload.data : {}
+        logger.info('[mqttService] 瑙f瀽鍚庣殑鍙傛暟:', JSON.stringify(data))
+        let res = this.insertEmergencyPasswordAgreement(data)
+        if (typeof res == 'string') {
+            logger.error('[mqttService] insertEmergencyPassword澶辫触:', res)
+            return reply(event, res, CODE.E_100)
+        }
+        logger.info('[mqttService] insertEmergencyPassword鎴愬姛')
+        return reply(event)
+    } catch (error) {
+        logger.error('[mqttService] insertEmergencyPassword error:', error)
+        return reply(event, { error: error.message }, CODE.E_100)
+    }
+}
+
+/**
+ * 娣诲姞搴旀�ュ紑浠撳瘑鐮侀�氱敤鍗忚鏍煎紡
+ * @param {object} data - 搴旀�ュ紑浠撳瘑鐮佹暟鎹璞�
+ * @returns {boolean|string} true琛ㄧず鎴愬姛锛宻tring琛ㄧず閿欒淇℃伅
+ */
+mqttService.insertEmergencyPasswordAgreement = function (data) {
+    // 搴旀�ュ紑浠撳瘑鐮佸湪璁惧涓粎鏈夊敮涓�鐨�1涓紝鎵�浠ュ厛娓呯┖琛�
+    let deleteRet = sqliteService.d1_emergency_password.deleteAll()
+    if (deleteRet != 0) {
+        return "娓呯┖鏃у瘑鐮佸け璐�: " + deleteRet
+    }
+    
+    // 妫�鏌ュ瘑鐮佹槸鍚︽湁鏁�
+    if (!data.password) {
+        return "password cannot be empty"
+    }
+    
+    // 妫�鏌ュ瘑鐮侀暱搴︽槸鍚﹀ぇ浜庣瓑浜�8浣�
+    if (data.password.length < 8) {
+        return "Password length must be at least 8 digits"
+    }
+    
+    // 鏋勫缓瀵嗙爜璁板綍
+    let record = {}
+    record.id = data.id || 'emergency_' + Date.now() // 濡傛灉娌℃湁id锛岃嚜鍔ㄧ敓鎴�
+    record.password = data.password
+    record.description = "浜戠涓嬪彂" // 閫氳繃MQTT鍜孒TTP鎺ュ彛璁剧疆鐨勫簲鎬ュ紑浠撳瘑鐮侊紝description濉厖涓�"浜戠涓嬪彂"
+    record.createTime = Date.now()
+    record.updateTime = Date.now()
+    record.status = data.status || 1
+    
+    // 淇濆瓨瀵嗙爜
+    let ret = sqliteService.d1_emergency_password.save(record)
+    if (ret == 0) {
+        return true
+    } else {
+        return "sql error ret:" + ret
+    }
+}
+
+/**
+ * 鏌ヨ搴旀�ュ紑浠撳瘑鐮�
+ * @param {object} event - MQTT浜嬩欢瀵硅薄
+ */
+mqttService.getEmergencyPassword = function (event) {
+    try {
+        logger.info('[mqttService] 鎺ユ敹鍒癵etEmergencyPassword鍛戒护:', JSON.stringify(event.topic))
+        logger.info('[mqttService] 鍛戒护payload:', event.payload)
+        let payload = JSON.parse(event.payload)
+        let res = this.getEmergencyPasswordAgreement()
+        logger.info('[mqttService] 鏌ヨ缁撴灉:', JSON.stringify(res))
+        return reply(event, res)
+    } catch (error) {
+        logger.error('[mqttService] getEmergencyPassword error:', error)
+        return reply(event, { error: error.message }, CODE.E_100)
+    }
+}
+
+/**
+ * 鏌ヨ搴旀�ュ紑浠撳瘑鐮侀�氱敤鍗忚鏍煎紡
+ * @returns {object} 鏌ヨ缁撴灉
+ */
+mqttService.getEmergencyPasswordAgreement = function () {
+    let passwords = sqliteService.d1_emergency_password.findAll()
+    if (passwords && passwords.length > 0) {
+        let password = passwords[0];
+        // 杞崲鏃堕棿鎴充负瀛楃涓叉牸寮�
+        if (password.createTime) {
+            // 灏濊瘯灏哻reateTime杞崲涓烘暟瀛�
+            const createTimeNum = Number(password.createTime);
+            if (!isNaN(createTimeNum)) {
+                // 妫�鏌ユ椂闂存埑鏄惁涓烘绉掔骇锛堝ぇ浜庣瓑浜�10浣嶏級
+                if (createTimeNum.toString().length >= 10) {
+                    // 宸茬粡鏄绉掔骇锛岃浆鎹负绉掔骇
+                    password.createTime = timestampToDateString(createTimeNum / 1000);
+                } else {
+                    // 绉掔骇锛岀洿鎺ヤ娇鐢�
+                    password.createTime = timestampToDateString(createTimeNum);
+                }
+            }
+        }
+        if (password.updateTime) {
+            // 灏濊瘯灏唘pdateTime杞崲涓烘暟瀛�
+            const updateTimeNum = Number(password.updateTime);
+            if (!isNaN(updateTimeNum)) {
+                // 妫�鏌ユ椂闂存埑鏄惁涓烘绉掔骇锛堝ぇ浜庣瓑浜�10浣嶏級
+                if (updateTimeNum.toString().length >= 10) {
+                    // 宸茬粡鏄绉掔骇锛岃浆鎹负绉掔骇
+                    password.updateTime = timestampToDateString(updateTimeNum / 1000);
+                } else {
+                    // 绉掔骇锛岀洿鎺ヤ娇鐢�
+                    password.updateTime = timestampToDateString(updateTimeNum);
+                }
+            }
+        }
+        return password;
+    }
+    return {};
+}
+
+
+/**
+ * 娓呯┖搴旀�ュ紑浠撳瘑鐮�
+ * @param {object} event - MQTT浜嬩欢瀵硅薄
+ */
+mqttService.clearEmergencyPassword = function (event) {
+    try {
+        logger.info('[mqttService] 鎺ユ敹鍒癱learEmergencyPassword鍛戒护:', JSON.stringify(event.topic))
+        logger.info('[mqttService] 鍛戒护payload:', event.payload)
+        let ret = sqliteService.d1_emergency_password.deleteAll()
+        if (ret == 0) {
+            logger.info('[mqttService] clearEmergencyPassword鎴愬姛')
+            return reply(event)
+        } else {
+            logger.error('[mqttService] clearEmergencyPassword澶辫触:', "sql error ret:" + ret)
+            return reply(event, "sql error ret:" + ret, CODE.E_100)
+        }
+    } catch (error) {
+        logger.error('[mqttService] clearEmergencyPassword error:', error)
+        return reply(event, { error: error.message }, CODE.E_100)
+    }
+}
+
+
 // =================================瀵嗛挜澧炲垹鏀规煡=================================
 /**
  * 娣诲姞瀵嗛挜
  */
 mqttService.insertSecurity = function (event) {
     let payload = JSON.parse(event.payload)
-    let data = payload.data
+    let data = payload.payload && payload.payload.data ? payload.payload.data : payload.data
     if (data.length > 100) {
         return reply(event, "data length should not be greater than 100", CODE.E_100)
     }
@@ -271,7 +421,7 @@
  */
 mqttService.getSecurity = function (event) {
     let payload = JSON.parse(event.payload)
-    let data = payload.data
+    let data = payload.payload && payload.payload.data ? payload.payload.data : payload.data
     let res = api.getSecurity(data)
     if (typeof res == 'string') {
         return reply(event, res, CODE.E_100)
@@ -284,7 +434,7 @@
  */
 mqttService.delSecurity = function (event) {
     let payload = JSON.parse(event.payload)
-    let data = payload.data
+    let data = payload.payload && payload.payload.data ? payload.payload.data : payload.data
     let res = api.delSecurity(data)
     if (Array.isArray(res)) {
         return reply(event, res, CODE.E_100)
@@ -304,24 +454,230 @@
     }
 }
 
+
+// =================================搴旀�ュ紑浠撳瘑鐮佸鍒犳敼鏌�=================================
+/**
+ * 娣诲姞搴旀�ュ紑浠撳瘑鐮�
+ * @param {object} event - MQTT浜嬩欢瀵硅薄
+ */
+mqttService.insertEmergencyPassword = function (event) {
+    try {
+        logger.info('[mqttService] 鎺ユ敹鍒癷nsertEmergencyPassword鍛戒护:', JSON.stringify(event.topic))
+        logger.info('[mqttService] 鍛戒护payload:', event.payload)
+        let payload = JSON.parse(event.payload)
+        let data = payload.payload && payload.payload.data ? payload.payload.data : {}
+        logger.info('[mqttService] 瑙f瀽鍚庣殑鍙傛暟:', JSON.stringify(data))
+        let res = this.insertEmergencyPasswordAgreement(data)
+        if (typeof res == 'string') {
+            logger.error('[mqttService] insertEmergencyPassword澶辫触:', res)
+            return reply(event, res, CODE.E_100)
+        }
+        logger.info('[mqttService] insertEmergencyPassword鎴愬姛')
+        return reply(event)
+    } catch (error) {
+        logger.error('[mqttService] insertEmergencyPassword error:', error)
+        return reply(event, { error: error.message }, CODE.E_100)
+    }
+}
+
+/**
+ * 娣诲姞搴旀�ュ紑浠撳瘑鐮侀�氱敤鍗忚鏍煎紡
+ * @param {object} data - 搴旀�ュ紑浠撳瘑鐮佹暟鎹璞�
+ * @returns {boolean|string} true琛ㄧず鎴愬姛锛宻tring琛ㄧず閿欒淇℃伅
+ */
+mqttService.insertEmergencyPasswordAgreement = function (data) {
+    // 搴旀�ュ紑浠撳瘑鐮佸湪璁惧涓粎鏈夊敮涓�鐨�1涓紝鎵�浠ュ厛娓呯┖琛�
+    let deleteRet = sqliteService.d1_emergency_password.deleteAll()
+    if (deleteRet != 0) {
+        return "娓呯┖鏃у瘑鐮佸け璐�: " + deleteRet
+    }
+    
+    // 妫�鏌ュ瘑鐮佹槸鍚︽湁鏁�
+    if (!data.password) {
+        return "password cannot be empty"
+    }
+    
+    // 妫�鏌ュ瘑鐮侀暱搴︽槸鍚﹀ぇ浜庣瓑浜�8浣�
+    if (data.password.length < 8) {
+        return "Password length must be at least 8 digits"
+    }
+    
+    // 鏋勫缓瀵嗙爜璁板綍
+    let record = {}
+    record.id = data.id || 'emergency_' + Date.now() // 濡傛灉娌℃湁id锛岃嚜鍔ㄧ敓鎴�
+    record.password = data.password
+    record.description = "浜戠涓嬪彂" // 閫氳繃MQTT鍜孒TTP鎺ュ彛璁剧疆鐨勫簲鎬ュ紑浠撳瘑鐮侊紝description濉厖涓�"浜戠涓嬪彂"
+    record.createTime = Date.now()
+    record.updateTime = Date.now()
+    record.status = data.status || 1
+    
+    // 淇濆瓨瀵嗙爜
+    let ret = sqliteService.d1_emergency_password.save(record)
+    if (ret == 0) {
+        return true
+    } else {
+        return "sql error ret:" + ret
+    }
+}
+
+/**
+ * 鏌ヨ搴旀�ュ紑浠撳瘑鐮�
+ * @param {object} event - MQTT浜嬩欢瀵硅薄
+ */
+mqttService.getEmergencyPassword = function (event) {
+    try {
+        logger.info('[mqttService] 鎺ユ敹鍒癵etEmergencyPassword鍛戒护:', JSON.stringify(event.topic))
+        logger.info('[mqttService] 鍛戒护payload:', event.payload)
+        let payload = JSON.parse(event.payload)
+        let res = this.getEmergencyPasswordAgreement()
+        logger.info('[mqttService] 鏌ヨ缁撴灉:', JSON.stringify(res))
+        return reply(event, res)
+    } catch (error) {
+        logger.error('[mqttService] getEmergencyPassword error:', error)
+        return reply(event, { error: error.message }, CODE.E_100)
+    }
+}
+
+/**
+ * 鏌ヨ搴旀�ュ紑浠撳瘑鐮侀�氱敤鍗忚鏍煎紡
+ * @returns {object} 鏌ヨ缁撴灉
+ */
+mqttService.getEmergencyPasswordAgreement = function () {
+    let passwords = sqliteService.d1_emergency_password.findAll()
+    if (passwords && passwords.length > 0) {
+        let password = passwords[0];
+        // 杞崲鏃堕棿鎴充负瀛楃涓叉牸寮�
+        if (password.createTime) {
+            // 灏濊瘯灏哻reateTime杞崲涓烘暟瀛�
+            const createTimeNum = Number(password.createTime);
+            if (!isNaN(createTimeNum)) {
+                // 妫�鏌ユ椂闂存埑鏄惁涓烘绉掔骇锛堝ぇ浜庣瓑浜�10浣嶏級
+                if (createTimeNum.toString().length >= 10) {
+                    // 宸茬粡鏄绉掔骇锛岃浆鎹负绉掔骇
+                    password.createTime = timestampToDateString(createTimeNum / 1000);
+                } else {
+                    // 绉掔骇锛岀洿鎺ヤ娇鐢�
+                    password.createTime = timestampToDateString(createTimeNum);
+                }
+            }
+        }
+        if (password.updateTime) {
+            // 灏濊瘯灏唘pdateTime杞崲涓烘暟瀛�
+            const updateTimeNum = Number(password.updateTime);
+            if (!isNaN(updateTimeNum)) {
+                // 妫�鏌ユ椂闂存埑鏄惁涓烘绉掔骇锛堝ぇ浜庣瓑浜�10浣嶏級
+                if (updateTimeNum.toString().length >= 10) {
+                    // 宸茬粡鏄绉掔骇锛岃浆鎹负绉掔骇
+                    password.updateTime = timestampToDateString(updateTimeNum / 1000);
+                } else {
+                    // 绉掔骇锛岀洿鎺ヤ娇鐢�
+                    password.updateTime = timestampToDateString(updateTimeNum);
+                }
+            }
+        }
+        return password;
+    }
+    return {};
+}
+
+
+/**
+ * 娓呯┖搴旀�ュ紑浠撳瘑鐮�
+ * @param {object} event - MQTT浜嬩欢瀵硅薄
+ */
+mqttService.clearEmergencyPassword = function (event) {
+    try {
+        logger.info('[mqttService] 鎺ユ敹鍒癱learEmergencyPassword鍛戒护:', JSON.stringify(event.topic))
+        logger.info('[mqttService] 鍛戒护payload:', event.payload)
+        let ret = sqliteService.d1_emergency_password.deleteAll()
+        if (ret == 0) {
+            logger.info('[mqttService] clearEmergencyPassword鎴愬姛')
+            return reply(event)
+        } else {
+            logger.error('[mqttService] clearEmergencyPassword澶辫触:', "sql error ret:" + ret)
+            return reply(event, "sql error ret:" + ret, CODE.E_100)
+        }
+    } catch (error) {
+        logger.error('[mqttService] clearEmergencyPassword error:', error)
+        return reply(event, { error: error.message }, CODE.E_100)
+    }
+}
+
+
 /**
  * 杩滅▼鎺у埗
+ * @param {object} event - MQTT浜嬩欢瀵硅薄
  */
 mqttService.control = function (event) {
-    let payload = JSON.parse(event.payload)
-    let ret = api.control(payload)
-    // 杩滅▼鎶撴媿銆佷紒涓氬井淇¤В缁戯紝闇�瑕佺瓑娴佺▼瀹屾垚鍚庢墠鍥炲锛屼笉鑳界珛鍗冲洖澶�
-    if (payload.data.command != 8 && payload.data.command != 11) {
-        // 濡傛灉鏄寚绾规搷浣滐紝浣嗘槸璁惧涓嶆敮鎸佹寚绾圭殑璇濓紝灏辩洿鎺ヨ繑鍥為敊璇�
-        if(payload.data.command == 12 && !driver.device.finger){
-            return reply(event, "finger not supported", CODE.E_100)
-        }
-        if (typeof ret == "string") {
-            return reply(event, "unknown failure", CODE.E_100)
-        } else {
+    try {
+            logger.info('[mqttService] 鎺ユ敹鍒癱ontrol鍛戒护:', JSON.stringify(event.topic))
+            logger.info('[mqttService] 鍛戒护payload:', event.payload)
+            let payload = JSON.parse(event.payload)
+            let data = payload.payload.data || {}
+            switch (data.command) {
+                case 0:
+                    //閲嶅惎
+                    logger.info('[mqttService] 鎵ц閲嶅惎鍛戒护')
+                    reply(event)
+                    common.asyncReboot(2)
+                    return
+                case 1:
+                    //杩滅▼寮�闂�
+                    logger.info('[mqttService] 鎵ц杩滅▼寮�闂ㄥ懡浠�')
+                    driver.gpio.open()
+                    break
+                case 4:
+                    //閲嶇疆
+                    logger.info('[mqttService] 鎵ц閲嶇疆鍛戒护')
+                    common.systemBrief("rm -rf /app/data/config/*")
+                    common.systemBrief("rm -rf /app/data/db/*")
+                    common.systemBrief("rm -rf /app/data/user/*")
+                    common.systemBrief("rm -rf /app/data/user/*")
+                    common.systemBrief("rm -rf /vgmj.db")
+                    reply(event)
+                    common.asyncReboot(2)
+                    return
+                case 5:
+                    //鎾斁璇煶
+                    logger.info('[mqttService] 鎵ц鎾斁璇煶鍛戒护')
+                    if (data.extra) {
+                        let res = common.systemWithRes(`test -e "/app/code/resource/wav/${data.extra.wav}.wav" && echo "OK" || echo "NO"`, 2)
+                        if (res.includes('OK')) {
+                            driver.alsa.play(`/app/code/resource/wav/${data.extra.wav}.wav`)
+                        }
+                    }
+                    break
+                case 6:
+                    // 6锛氬睆骞曞睍绀哄浘鐗�
+                    // TODO
+                    logger.info('[mqttService] 鎵ц灞忓箷灞曠ず鍥剧墖鍛戒护')
+                    break
+                case 7:
+                    // 7锛氬睆骞曞睍绀烘枃瀛�
+                    // TODO
+                    logger.info('[mqttService] 鎵ц灞忓箷灞曠ず鏂囧瓧鍛戒护')
+                    break
+                case 10:
+                    logger.info('[mqttService] 鎵ц浜岀淮鐮佸睍绀哄懡浠�')
+                    if (!isEmpty(data.extra.qrCodeBase64) && typeof data.extra.qrCodeBase64 == 'string') {
+                        //base64杞浘鐗囦繚瀛�
+                        let src = `/app/code/resource/image/app_qrcode.png`
+                        std.ensurePathExists(src)
+                        common.base64_2binfile(src, data.extra.qrCodeBase64)
+                        logger.info('[mqttService] 浜岀淮鐮佷繚瀛樻垚鍔�')
+                        return reply(event)
+                    }
+                    break
+                default:
+                    logger.info('[mqttService] 鏈煡鍛戒护:', data.command)
+                    break
+            }
+            logger.info('[mqttService] control鍛戒护鎵ц瀹屾垚')
             return reply(event)
+        } catch (error) {
+            logger.error('[mqttService] control error:', error)
+            return reply(event, { error: error.message }, CODE.E_100)
         }
-    }
 }
 
 /**
@@ -343,7 +699,7 @@
  */
 mqttService.setConfig = function (event) {
     let payload = JSON.parse(event.payload)
-    let data = payload.data
+    let data = payload.payload && payload.payload.data ? payload.payload.data : payload.data
     let res = api.setConfig(data)
     if (typeof res == "string") {
         return reply(event, res, CODE.E_100)
@@ -356,8 +712,9 @@
  * 鍗囩骇鍥轰欢
  */
 mqttService.upgradeFirmware = function (event) {
+    logger.info('[mqttService] 鎺ユ敹鍒板崌绾у浐浠跺懡浠�:', JSON.stringify(event.topic))
     let payload = JSON.parse(event.payload)
-    let data = payload.data
+    let data = payload.payload && payload.payload.data ? payload.payload.data : payload.data
     let res = api.upgradeFirmware(data)
     if (typeof res == "string") {
         return reply(event, res, CODE.E_100)
@@ -371,7 +728,7 @@
  */
 mqttService.getRecords = function (event) {
     let payload = JSON.parse(event.payload)
-    let data = payload.data
+    let data = payload.payload && payload.payload.data ? payload.payload.data : payload.data
     let res = api.getRecords(data, true)
     return reply(event, res)
 }
@@ -382,7 +739,7 @@
  */
 mqttService.delRecords = function (event) {
     let payload = JSON.parse(event.payload)
-    let data = payload.data
+    let data = payload.payload && payload.payload.data ? payload.payload.data : payload.data
     let res = api.delRecords(data)
     if (typeof res == 'string') {
         return reply(event, res, CODE.E_100)
@@ -487,6 +844,23 @@
 }
 mqttService.mqttReply = mqttReply
 
+/**
+ * 鏃堕棿鎴宠浆鏃ユ湡瀛楃涓�
+ * @param {number} timestamp - 鏃堕棿鎴筹紙绉掔骇锛�
+ * @returns {string} 鏃ユ湡瀛楃涓诧紝鏍煎紡锛歒YYY-MM-DD HH:MM:SS
+ */
+function timestampToDateString(timestamp) {
+    const date = new Date(timestamp * 1000);
+    const year = date.getFullYear();
+    const month = String(date.getMonth() + 1).padStart(2, '0');
+    const day = String(date.getDate()).padStart(2, '0');
+    const hours = String(date.getHours()).padStart(2, '0');
+    const minutes = String(date.getMinutes()).padStart(2, '0');
+    const seconds = String(date.getSeconds()).padStart(2, '0');
+    return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
+}
+mqttService.timestampToDateString = timestampToDateString
+
 // 鍒ょ┖
 function isEmpty(value) {
     return value === undefined || value === null || value === ""
diff --git a/vf107/src/service/sqliteService.js b/vf107/src/service/sqliteService.js
index d5fcd26..9b41ded 100644
--- a/vf107/src/service/sqliteService.js
+++ b/vf107/src/service/sqliteService.js
@@ -29,9 +29,11 @@
         extra: "TEXT",
         extra2: "TEXT",
         message: "TEXT",
+        reported: "INTEGER DEFAULT 0",
     },
     d1_permission: {
         permissionId: "VARCHAR(128) PRIMARY KEY",
+        userId: "VARCHAR(128)",
         door: "VARCHAR(128)",
         extra: "TEXT",
         timeType: "INTEGER",
@@ -59,6 +61,14 @@
         name: "VARCHAR(128)",
         extra: "TEXT",
         permissionIds: "TEXT",
+    },
+    d1_emergency_password: {
+        id: "VARCHAR(128) PRIMARY KEY",
+        password: "VARCHAR(128)",
+        description: "TEXT",
+        createTime: "INTEGER",
+        updateTime: "INTEGER",
+        status: "INTEGER",
     }
 }
 
@@ -133,6 +143,7 @@
 sqliteService.d1_security = new Proxy({ tableName: "d1_security" }, handler);
 sqliteService.d1_voucher = new Proxy({ tableName: "d1_voucher" }, handler);
 sqliteService.d1_person = new Proxy({ tableName: "d1_person" }, handler);
+sqliteService.d1_emergency_password = new Proxy({ tableName: "d1_emergency_password" }, handler);
 
 // 鎸夊鍚嶆ā绯婃煡璇汉鍛�
 sqliteService.findPersonsByNameLike = function (name) {
@@ -165,6 +176,11 @@
     return sqliteService.select(query)
 }
 
+// 鏌ヨ鎵�鏈夋湭涓婃姤鐨勯�氳璁板綍锛堟寜鏃堕棿鍗囧簭锛�
+sqliteService.d1_pass_record.findAllByReportedOrderByTimeStampAsc = function () {
+    const sql = `SELECT * FROM d1_pass_record WHERE reported = 0 OR reported IS NULL ORDER BY timeStamp ASC;`
+    return sqliteService.select(sql)
+}
 
 // 寮�濮嬩簨鍔★紝浜嬪姟涓嶆彁浜ゆ暟鎹簱閲嶅惎鍚庯紝鏁版嵁浼氳繕鍘燂紝鎵�浠ransaction鍚庝竴瀹氳commit锛屼絾鏄鏋滃湪涓�涓簨鍔″皻鏈彁浜ゆ垨鍥炴粴鐨勬儏鍐典笅鎵ц鍙︿竴涓� BEGIN TRANSACTION锛孲QLite 浼氳嚜鍔ㄥ皢鏂扮殑浜嬪姟宓屽鍦ㄤ箣鍓嶇殑浜嬪姟鍐呴儴锛岃�屼笉鏄鐩栦箣鍓嶇殑浜嬪姟銆�
 sqliteService.transaction = function () {
diff --git a/vf107/src/view/config/menu/doorControlView.js b/vf107/src/view/config/menu/doorControlView.js
index 89cb8a7..04e9cb1 100644
--- a/vf107/src/view/config/menu/doorControlView.js
+++ b/vf107/src/view/config/menu/doorControlView.js
@@ -26,6 +26,7 @@
         mqttPwdSettingInput.text(configAll['mqtt.password'])
         onlineCheckingSettingSwitch.select(configAll['mqtt.onlinecheck'] == 1)
         onlineCheckingTimeoutSettingInput.text(configAll['mqtt.timeout'] + '')
+        gasVerificationSwitch.select(configAll['gas.verification'] == 1)
     })
 
     const titleBox = viewUtils.title(screenMain, configView.screenMain, 'doorControlViewTitle', 'doorControlView.title')
@@ -224,6 +225,24 @@
     onlineCheckingTimeoutSettingInput.align(dxui.Utils.ALIGN.RIGHT_MID, -screen.screenSize.width * (60 / 600), 0)
     onlineCheckingTimeoutSettingInput.setSize(screen.screenSize.width * (150 / 600), screen.screenSize.height * (60 / 1280))
 
+    const gasVerificationBox = dxui.View.build('gasVerificationBox', screenMain)
+    viewUtils._clearStyle(gasVerificationBox)
+    gasVerificationBox.align(dxui.Utils.ALIGN.TOP_MID, 0, screen.screenSize.height * (880 / 1280))
+    gasVerificationBox.setSize(screen.screenSize.width * (550 / 600), screen.screenSize.height * (76 / 1280))
+    gasVerificationBox.borderWidth(1)
+    gasVerificationBox.setBorderColor(0xDEDEDE)
+    gasVerificationBox.obj.setStyleBorderSide(dxui.Utils.ENUM.LV_BORDER_SIDE_BOTTOM, 0)
+
+    const gasVerificationLbl = dxui.Label.build('gasVerificationLbl', gasVerificationBox)
+    gasVerificationLbl.text('姘斾綋娴撳害楠岃瘉')
+    gasVerificationLbl.align(dxui.Utils.ALIGN.LEFT_MID, 0, 0)
+    gasVerificationLbl.textFont(viewUtils.font(26))
+
+    const gasVerificationSwitch = dxui.Switch.build('gasVerificationSwitch', gasVerificationBox)
+    gasVerificationSwitch.align(dxui.Utils.ALIGN.RIGHT_MID, 0, 0)
+    gasVerificationSwitch.setSize(screen.screenSize.width * (70 / 600), screen.screenSize.height * (35 / 1280))
+    gasVerificationSwitch.bgColor(0x000000, NativeObject.APP.NativeComponents.NativeEnum.LV_PART_INDICATOR | NativeObject.APP.NativeComponents.NativeEnum.LV_STATE_CHECKED)
+
     const saveBtn = viewUtils.bottomBtn(screenMain, screenMain.id + 'saveBtn', 'doorControlView.save', () => {
         const saveConfigData = {
             access: {
@@ -235,6 +254,9 @@
             },
             houseName: houseNameSettingInput.text(),
             GranaryName: granaryNameSettingInput.text(),
+            gas: {
+                verification: gasVerificationSwitch.isSelect() ? 1 : 0
+            },
             mqtt: {
                 addr: mqttSettingInput.text(),
                 username: mqttUserSettingInput.text(),
diff --git a/vf107/src/view/config/menu/localUser/localUserAddView.js b/vf107/src/view/config/menu/localUser/localUserAddView.js
index 6bed5bf..a71c649 100644
--- a/vf107/src/view/config/menu/localUser/localUserAddView.js
+++ b/vf107/src/view/config/menu/localUser/localUserAddView.js
@@ -75,12 +75,6 @@
             input: null,
             mode: screen.isInternationalVersion() ? 0 : 1
         },
-        idCard: {
-            title: 'localUserAddView.idCard',
-            value: null,
-            type: 'input',
-            input: null
-        },
         face: {
             title: 'localUserAddView.face',
             value: null,
@@ -124,7 +118,7 @@
         }
     }
 
-    const userInfoOrder = ['id', 'name', 'idCard', 'face', 'pwd', 'card', 'finger', 'type']
+    const userInfoOrder = ['id', 'name', 'face', 'pwd', 'card', 'finger', 'type']
 
     userInfoOrder.forEach((key, index) => {
         const item = localUserAddView.userInfo[key]
@@ -171,9 +165,6 @@
                         break;
                     case 'localUserAddView.name':
                         localUserAddView.nowUser.name = input.text()
-                        break;
-                    case 'localUserAddView.idCard':
-                        localUserAddView.nowUser.idCard = input.text()
                         break;
                     default:
                         break;
@@ -665,14 +656,6 @@
     localUserAddView.userInfo.name.input.text('')
 }
 
-localUserAddView.addIDCard = function (idCard) {
-    localUserAddView.userInfo.idCard.input.text(idCard)
-    localUserAddView.nowUser.idCard = idCard
-}
-
-localUserAddView.removeIDCard = function () {
-    localUserAddView.userInfo.idCard.input.text('')
-}
 localUserAddView.addFace = function (face, feature) {
     localUserAddView.userInfo.face.facePreview.show()
     localUserAddView.userInfo.face.btnEdit.show()
@@ -781,7 +764,6 @@
     localUserAddView.removeCard()
     localUserAddView.removeID()
     localUserAddView.removeName()
-    localUserAddView.removeIDCard()
     if (flag) {
         localUserAddView.saveBtn.align(dxui.Utils.ALIGN.BOTTOM_MID, 0, -screen.screenSize.height * (40 / 1024))
         localUserAddView.deleteBtn.show()
diff --git a/vf107/src/view/config/menu/localUserView.js b/vf107/src/view/config/menu/localUserView.js
index 931ca09..0658fb5 100644
--- a/vf107/src/view/config/menu/localUserView.js
+++ b/vf107/src/view/config/menu/localUserView.js
@@ -147,9 +147,6 @@
                 if (item.name) {
                     localUserAddView.addName(item.name)
                 }
-                if (item.idCard) {
-                    localUserAddView.addIDCard(item.idCard)
-                }
                 if (item.face) {
                     localUserAddView.addFace(item.face,item.feature)
                 }
diff --git a/vf107/src/view/config/menu/networkSettingView.js b/vf107/src/view/config/menu/networkSettingView.js
index 4b85f13..63b4d87 100644
--- a/vf107/src/view/config/menu/networkSettingView.js
+++ b/vf107/src/view/config/menu/networkSettingView.js
@@ -9,6 +9,9 @@
 const net_map = map.get("NET")
 const networkSettingView = {}
 
+networkSettingView.isEditing = false // 鏄惁姝e湪缂栬緫閰嶇疆鐨勬爣蹇椾綅
+networkSettingView.isVisible = false // 鏄惁鍦ㄧ綉缁滈厤缃〉闈㈢殑鏍囧織浣�
+
 networkSettingView.init = function () {
     /**************************************************鍒涘缓灞忓箷*****************************************************/
     const screenMain = dxui.View.build('networkSettingView', dxui.Utils.LAYER.MAIN)
@@ -20,6 +23,8 @@
     screenMain.bgColor(0xffffff)
     screenMain.on(dxui.Utils.ENUM.LV_EVENT_SCREEN_LOADED, () => {
         topView.changeTheme(true)
+        networkSettingView.isEditing = false // 灞忓箷鍔犺浇鏃堕噸缃紪杈戠姸鎬�
+        networkSettingView.isVisible = true // 灞忓箷鍔犺浇鏃惰缃负鍙
         const configAll = screen.getConfig()
 
         // Store initial state for comparison on save
@@ -38,6 +43,7 @@
         let netList = []
         switch (screen.dxDriver.DRIVER.MODEL) {
             case "vf105":
+            case "vf107":
                 netList = [i18n.t('networkSettingView.ethernet'), i18n.t('networkSettingView.wifi')]
                 break;
             case "vf114":
@@ -59,6 +65,8 @@
 
     screenMain.on(dxui.Utils.ENUM.LV_EVENT_SCREEN_UNLOADED, () => {
         wifiListBoxClose.send(dxui.Utils.EVENT.CLICK)
+        networkSettingView.isVisible = false // 灞忓箷鍗歌浇鏃惰缃负涓嶅彲瑙�
+        networkSettingView.isEditing = false // 灞忓箷鍗歌浇鏃堕噸缃紪杈戠姸鎬�
     })
 
     const titleBox = viewUtils.title(screenMain, configView.screenMain, 'networkSettingViewTitle', 'networkSettingView.title')
@@ -177,6 +185,21 @@
             input.setSize(screen.screenSize.width * (310 / 600), screen.screenSize.height * (45 / 1280))
             item.input = input
 
+            // 娣诲姞杈撳叆妗嗙劍鐐逛簨浠剁洃鍚拰鍊煎彉鍖栫洃鍚紝闃叉缂栬緫鏃堕厤缃閲嶇疆
+            input.on(dxui.Utils.EVENT.FOCUSED, () => {
+                networkSettingView.isEditing = true
+            })
+            input.on(dxui.Utils.EVENT.DEFOCUSED, () => {
+                // 鍙湁褰撻厤缃病鏈夊彉鍖栨椂鎵嶈缃甶sEditing涓篺alse
+                if (!networkSettingView._isConfigChanged()) {
+                    networkSettingView.isEditing = false
+                }
+            })
+            // 娣诲姞鍊煎彉鍖栫洃鍚紝褰撶敤鎴蜂慨鏀逛簡鍊兼椂璁剧疆isEditing涓簍rue
+            input.on(dxui.Utils.EVENT.VALUE_CHANGED, () => {
+                networkSettingView.isEditing = true
+            })
+
             if (item.title === 'networkSettingView.wifiName') {
                 input.setSize(screen.screenSize.width * (200 / 600), screen.screenSize.height * (45 / 1280))
                 input.align(dxui.Utils.ALIGN.RIGHT_MID, -screen.screenSize.width * (110 / 600), 0)
@@ -217,6 +240,11 @@
             __switch.setSize(screen.screenSize.width * (70 / 600), screen.screenSize.height * (35 / 1280))
             __switch.bgColor(0x000000, NativeObject.APP.NativeComponents.NativeEnum.LV_PART_INDICATOR | NativeObject.APP.NativeComponents.NativeEnum.LV_STATE_CHECKED)
             item.switch = __switch
+
+            // 娣诲姞寮�鍏充簨浠剁洃鍚紝闃叉鎿嶄綔鏃堕厤缃閲嶇疆
+            __switch.on(dxui.Utils.EVENT.VALUE_CHANGED, () => {
+                networkSettingView.isEditing = true
+            })
         }
 
         if (item.type === 'dropdown') {
@@ -233,6 +261,7 @@
 
             if (item.title === 'networkSettingView.type') {
                 dropdown.on(dxui.Utils.EVENT.VALUE_CHANGED, () => {
+                    networkSettingView.isEditing = true
                     switch (dropdown.getSelected()) {
                         case 0:
                             networkSettingView.changeNetType(1)
@@ -406,6 +435,7 @@
     const saveBtn = viewUtils.bottomBtn(screenMain, screenMain.id + 'saveBtn', 'networkSettingView.save', () => {
         if (!networkSettingView._isConfigChanged()) {
             // No changes, just go back
+            networkSettingView.isEditing = false
             dxui.loadMain(screenMain.backScreen)
             return
         }
@@ -527,6 +557,7 @@
             networkSettingView.statusPanel.success()
             std.setTimeout(() => {
                 // 鎴愬姛杩斿洖涓婁竴灞傜晫闈�
+                networkSettingView.isEditing = false
                 dxui.loadMain(screenMain.backScreen)
             }, 500)
             screen.updateNetStatus("disconnect")
@@ -546,10 +577,7 @@
 }
 
 networkSettingView._isConfigChanged = function () {
-    //濡傛灉鎵撳紑鐣岄潰鏃剁殑鏁版嵁鍜岀偣鍑讳繚瀛樻寜閽椂鐨勬暟鎹墠鍚庢病鏈夊彂鐢熷彉鍖栵紝灏变笉瑙﹀彂閲嶈繛鍜屾暟鎹繚瀛�
-    if (net_map.get("NET_STATUS") != "connected") {
-        return true //浣嗘槸鍋囧缃戠粶娌¤繛涓婏紝灏变竴瀹氳瑙﹀彂閲嶈繛鍜屾暟鎹繚瀛�
-    }
+    //妫�鏌ラ厤缃槸鍚︾湡鐨勫彂鐢熶簡鍙樺寲锛屾棤璁虹綉缁滅姸鎬佸浣�
     const selectedTypeIndex = networkSettingView.netInfo[0].dropdown.getSelected()
     let currentType
     switch (selectedTypeIndex) {
@@ -633,6 +661,11 @@
 }
 
 networkSettingView.refresh = function () {
+    // 濡傛灉鐢ㄦ埛姝e湪缂栬緫閰嶇疆锛屼笉鎵ц鑷姩鍒锋柊
+    if (networkSettingView.isEditing) {
+        return
+    }
+    
     const configAll = screen.getConfig()
 
     let selectNum = 0
diff --git a/vf107/src/view/config/menu/recordQuery/recordQueryDetailView.js b/vf107/src/view/config/menu/recordQuery/recordQueryDetailView.js
index dbb8a08..8097857 100644
--- a/vf107/src/view/config/menu/recordQuery/recordQueryDetailView.js
+++ b/vf107/src/view/config/menu/recordQuery/recordQueryDetailView.js
@@ -37,8 +37,8 @@
         key: 'name',
         label: null
     }, {
-        title: 'recordQueryDetailView.idCard',
-        key: 'idCard',
+        title: 'recordQueryDetailView.card',
+        key: 'card',
         label: null
     }, {
         title: 'recordQueryDetailView.userId2',
@@ -49,8 +49,8 @@
         key: 'name2',
         label: null
     }, {
-        title: 'recordQueryDetailView.idCard2',
-        key: 'idCard2',
+        title: 'recordQueryDetailView.card2',
+        key: 'card2',
         label: null
     }, {
         title: 'recordQueryDetailView.time',
@@ -128,9 +128,9 @@
                     item.label.text(" ")
                 }
                 break;
-            case 'idCard':
-                if (extra && extra.idCard) {
-                    item.label.text(extra.idCard)
+            case 'card':
+                if (extra && extra.card) {
+                    item.label.text(extra.card)
                 } else {
                     item.label.text(" ")
                 }
@@ -145,9 +145,9 @@
                     item.label.text(" ")
                 }
                 break;
-            case 'idCard2':
-                if (extra2 && extra2.idCard) {
-                    item.label.text(extra2.idCard)
+            case 'card2':
+                if (extra2 && extra2.card) {
+                    item.label.text(extra2.card)
                 } else {
                     item.label.text(" ")
                 }
diff --git a/vf107/src/view/config/menu/systemSetting/displaySettingView.js b/vf107/src/view/config/menu/systemSetting/displaySettingView.js
index 3a80902..f5e34c2 100644
--- a/vf107/src/view/config/menu/systemSetting/displaySettingView.js
+++ b/vf107/src/view/config/menu/systemSetting/displaySettingView.js
@@ -239,7 +239,7 @@
                         // })
                     })
                 } else if (item.key === 'brightness') {
-                    if (dxDriver.DRIVER.MODEL == "vf202" || dxDriver.DRIVER.MODEL == "vf114" || dxDriver.DRIVER.MODEL == "vf105") {
+                    if (dxDriver.DRIVER.MODEL == "vf202" || dxDriver.DRIVER.MODEL == "vf114" || dxDriver.DRIVER.MODEL == "vf105" || dxDriver.DRIVER.MODEL == "vf107") {
                         itemBox.show()
                         slider.on(dxui.Utils.EVENT.VALUE_CHANGED, () => {
                             sliderLabel.text(slider.value() + '')
diff --git a/vf107/src/view/config/menu/systemSetting/passwordOpenDoorSettingView.js b/vf107/src/view/config/menu/systemSetting/passwordOpenDoorSettingView.js
index cc69a5c..8753787 100644
--- a/vf107/src/view/config/menu/systemSetting/passwordOpenDoorSettingView.js
+++ b/vf107/src/view/config/menu/systemSetting/passwordOpenDoorSettingView.js
@@ -5,6 +5,7 @@
 import i18n from "../../../i18n.js"
 import systemSettingView from '../systemSettingView.js'
 import screen from '../../../../screen.js'
+import api from '../../../../service/api.js'
 const passwordOpenDoorSettingView = {}
 passwordOpenDoorSettingView.init = function () {
     /**************************************************鍒涘缓灞忓箷*****************************************************/
@@ -17,6 +18,9 @@
 
         const configAll = screen.getConfig()
         passwordOpenDoorSettingView.info[0].switch.select(configAll['sys.pwd'] == 1)
+
+        // 鏌ヨ搴旀�ュ紑闂ㄥ瘑鐮�
+        passwordOpenDoorSettingView.getEmergencyPassword()
     })
 
     const titleBox = viewUtils.title(screenMain, systemSettingView.screenMain, 'passwordOpenDoorSettingViewTitle', 'systemSettingView.passwordOpenDoorSetting')
@@ -26,13 +30,17 @@
         {
             title: "systemSettingView.passwordOpenDoor",
             type: 'switch',
+        },
+        {
+            title: "systemSettingView.emergencyOpenDoorPassword",
+            type: 'password',
         }
     ]
 
     const passwordOpenDoorSettingBox = dxui.View.build('passwordOpenDoorSettingBox', screenMain)
     viewUtils._clearStyle(passwordOpenDoorSettingBox)
     passwordOpenDoorSettingBox.align(dxui.Utils.ALIGN.TOP_MID, 0, screen.screenSize.height * (140 / 1280))
-    passwordOpenDoorSettingBox.setSize(screen.screenSize.width * (600 / 600), screen.screenSize.height * (600 / 1280))
+    passwordOpenDoorSettingBox.setSize(screen.screenSize.width * (600 / 600), screen.screenSize.height * (700 / 1280))
     passwordOpenDoorSettingBox.bgOpa(0)
     passwordOpenDoorSettingBox.flexFlow(dxui.Utils.FLEX_FLOW.ROW_WRAP)
     passwordOpenDoorSettingBox.flexAlign(dxui.Utils.FLEX_ALIGN.CENTER, dxui.Utils.FLEX_ALIGN.START, dxui.Utils.FLEX_ALIGN.START)
@@ -69,6 +77,30 @@
                 __switch.bgColor(0x000000, NativeObject.APP.NativeComponents.NativeEnum.LV_PART_INDICATOR | NativeObject.APP.NativeComponents.NativeEnum.LV_STATE_CHECKED)
                 item.switch = __switch
                 break;
+            case 'password':
+                const pwdInput = viewUtils.input(itemBox, item.title + 'Input', 2, undefined, '璇疯緭鍏ュ簲鎬ュ紑闂ㄥ瘑鐮�')
+                pwdInput.align(dxui.Utils.ALIGN.RIGHT_MID, 0, 0)
+                pwdInput.setSize(screen.screenSize.width * (300 / 600), screen.screenSize.height * (50 / 1280))
+                pwdInput.setPasswordMode(true)
+                item.input = pwdInput
+
+                const eyeFill = viewUtils.imageBtn(itemBox, item.title + 'eye_fill', '/app/code/resource/image/eye-fill.png')
+                eyeFill.alignTo(pwdInput, dxui.Utils.ALIGN.RIGHT_MID, 0, 0)
+                eyeFill.on(dxui.Utils.EVENT.CLICK, () => {
+                    pwdInput.setPasswordMode(true)
+                    eyeFill.hide()
+                    eyeOff.show()
+                })
+                eyeFill.hide()
+
+                const eyeOff = viewUtils.imageBtn(itemBox, item.title + 'eye_off', '/app/code/resource/image/eye-off.png')
+                eyeOff.alignTo(pwdInput, dxui.Utils.ALIGN.RIGHT_MID, 0, 0)
+                eyeOff.on(dxui.Utils.EVENT.CLICK, () => {
+                    pwdInput.setPasswordMode(false)
+                    eyeFill.show()
+                    eyeOff.hide()
+                })
+                break;
         }
     })
 
@@ -76,6 +108,16 @@
         const saveConfigData = {
             sys: {
                 pwd: passwordOpenDoorSettingView.info[0].switch.isSelect() ? 1 : 0,
+            }
+        }
+
+        // 淇濆瓨搴旀�ュ紑闂ㄥ瘑鐮�
+        const emergencyPwd = passwordOpenDoorSettingView.info[1].input.text()
+        if (emergencyPwd) {
+            const res = api.insertEmergencyPassword({ password: emergencyPwd, description: "璁惧绔缃�" })
+            if (res !== true) {
+                passwordOpenDoorSettingView.statusPanel.fail()
+                return
             }
         }
 
@@ -95,4 +137,16 @@
     passwordOpenDoorSettingView.statusPanel = viewUtils.statusPanel(screenMain, 'systemSettingView.success', 'systemSettingView.fail')
 }
 
+// 鏌ヨ搴旀�ュ紑闂ㄥ瘑鐮�
+passwordOpenDoorSettingView.getEmergencyPassword = function () {
+    try {
+        const password = api.getEmergencyPassword()
+        if (password && password.password) {
+            passwordOpenDoorSettingView.info[1].input.text(password.password)
+        }
+    } catch (error) {
+        console.error('鏌ヨ搴旀�ュ紑闂ㄥ瘑鐮佸け璐�:', error)
+    }
+}
+
 export default passwordOpenDoorSettingView
diff --git a/vf107/src/view/mainView.js b/vf107/src/view/mainView.js
index 669dcc6..7fd7566 100644
--- a/vf107/src/view/mainView.js
+++ b/vf107/src/view/mainView.js
@@ -35,10 +35,10 @@
         // 鐩存帴浠巒et妯″潡鑾峰彇IP鍦板潃锛岀‘淇濊幏鍙栧埌鏈�鏂扮殑IP
         let ip = ""
         try {
-            let netType = config["net.type"] || 1
-            let netMode = net.getModeByCard(netType)
-            if (netMode && netMode.param && netMode.param.ip) {
-                ip = netMode.param.ip
+            // 浣跨敤getNetParam()鏂规硶鑾峰彇鏈�鏂扮殑缃戠粶鍙傛暟
+            let param = net.getNetParam()
+            if (param && param.ip) {
+                ip = param.ip
             }
         } catch (error) {
             // 鍑洪敊鏃朵娇鐢╟onfig涓殑IP
@@ -86,10 +86,10 @@
         // 鐩存帴浠巒et妯″潡鑾峰彇IP鍦板潃锛岀‘淇濊幏鍙栧埌鏈�鏂扮殑IP
         let ip = ""
         try {
-            let netType = config["net.type"] || 1
-            let netMode = net.getModeByCard(netType)
-            if (netMode && netMode.param && netMode.param.ip) {
-                ip = netMode.param.ip
+            // 浣跨敤getNetParam()鏂规硶鑾峰彇鏈�鏂扮殑缃戠粶鍙傛暟
+            let param = net.getNetParam()
+            if (param && param.ip) {
+                ip = param.ip
             }
         } catch (error) {
             // 鍑洪敊鏃朵娇鐢╟onfig涓殑IP
@@ -128,6 +128,33 @@
         }
     }
 
+    // 鏇存柊缃戠粶鍥炬爣
+    function updateNetworkIcon() {
+        try {
+            let config = screen.getConfig()
+            let netType = config["net.type"] || 1
+            let isConnected = net.isConnected()
+            
+            // 闅愯棌鎵�鏈夌綉缁滃浘鏍�
+            if (topView.ethShow) topView.ethShow.hide()
+            if (topView.wifiShow) topView.wifiShow.hide()
+            if (topView._4gShow) topView._4gShow.hide()
+            
+            // 鏍规嵁缃戠粶绫诲瀷鍜岃繛鎺ョ姸鎬佹樉绀哄搴旂殑鍥炬爣
+            if (isConnected) {
+                if (netType === 1) { // 浠ュお缃�
+                    if (topView.ethShow) topView.ethShow.show()
+                } else if (netType === 2) { // WiFi
+                    if (topView.wifiShow) topView.wifiShow.show()
+                } else if (netType === 4) { // 4G
+                    if (topView._4gShow) topView._4gShow.show()
+                }
+            }
+        } catch (error) {
+            logger.error('[mainView]: 鏇存柊缃戠粶鍥炬爣澶辫触:', error)
+        }
+    }
+
     screenMain.on(dxui.Utils.ENUM.LV_EVENT_SCREEN_LOADED, () => {
         topView.changeTheme(false)
 
@@ -148,6 +175,8 @@
 
         // 绋嬪簭鍚姩鏃舵洿鏂板簱鍖哄悕绉板拰浠撳彿
         updateWarehouseInfo()
+        // 鍒濆鍖栫綉缁滃浘鏍�
+        updateNetworkIcon()
 
         // 鍙敞鍐屼竴娆′簨浠剁洃鍚櫒
         if (!mainView.eventListenersRegistered) {
@@ -158,9 +187,11 @@
                 onStatusChange: function(netType, status) {
                     // 缃戠粶鐘舵�佸彉鍖栨椂鏇存柊IP淇℃伅
                     updateDeviceInfo()
+                    // 鏇存柊缃戠粶鍥炬爣
+                    updateNetworkIcon()
                 }
             })
-            
+
             // 鍚姩缃戠粶浜嬩欢寰幆
             std.setInterval(() => {
                 try {
@@ -803,9 +834,10 @@
         oxygenValueContainer.flexAlign(dxui.Utils.FLEX_ALIGN.CENTER, dxui.Utils.FLEX_ALIGN.CENTER, dxui.Utils.FLEX_ALIGN.CENTER)
         oxygenValueContainer.obj.lvObjSetStylePadGap(5, dxui.Utils.ENUM._LV_STYLE_STATE_CMP_SAME)
         
+        
         // 姘ф皵鏁板�奸儴鍒�
         const oxygenValue = dxui.Label.build('oxygenValue', oxygenValueContainer)
-        oxygenValue.text('20')
+        oxygenValue.text('-')
         oxygenValue.textFont(viewUtils.font(20, dxui.Utils.FONT_STYLE.BOLD))
         oxygenValue.textColor(0xffffff)
         mainView.oxygenValue = oxygenValue // 璁剧疆涓簃ainView灞炴��
@@ -865,7 +897,7 @@
         
         // 纾峰寲姘㈡暟鍊奸儴鍒�
         const ph3Value = dxui.Label.build('ph3Value', ph3ValueContainer)
-        ph3Value.text('0')
+        ph3Value.text('-')
         ph3Value.textFont(viewUtils.font(20, dxui.Utils.FONT_STYLE.BOLD))
         ph3Value.textColor(0xffffff)
         mainView.ph3Value = ph3Value // 璁剧疆涓簃ainView灞炴��
@@ -909,7 +941,7 @@
         
         // 浜屾哀鍖栫⒊鏁板�奸儴鍒�
         const co2Value = dxui.Label.build('co2Value', co2ValueContainer)
-        co2Value.text('400')
+        co2Value.text('-')
         co2Value.textFont(viewUtils.font(20, dxui.Utils.FONT_STYLE.BOLD))
         co2Value.textColor(0xffffff)
         mainView.co2Value = co2Value // 璁剧疆涓簃ainView灞炴��
diff --git a/vf107/src/worker/mqttWorker.js b/vf107/src/worker/mqttWorker.js
index e3118a8..d5596c0 100644
--- a/vf107/src/worker/mqttWorker.js
+++ b/vf107/src/worker/mqttWorker.js
@@ -36,6 +36,7 @@
         "getPermission", "insertPermission", "delPermission", "clearPermission", "modifyPermission",
         "getKey", "insertKey", "delKey", "clearKey", "modifyKey",
         "getUser", "insertUser", "delUser", "clearUser", "modifyUser",
+        "insertEmergencyPassword", "delEmergencyPassword", "clearEmergencyPassword", "getEmergencyPassword",
         "getSecurity", "insertSecurity", "delSecurity", "clearSecurity", "getRecords", "delRecords"
     ]
     const eventReplies = ["connect_reply", "alarm_reply", "access_reply", "access_online_reply", "wecom_reply"]
@@ -84,7 +85,7 @@
             mqtt.subscribe(v, { qos });
         })
     } catch (error) {
-        logger.error("MQTT connection error锛宺etry in 5s:");
+        // logger.error("MQTT connection error锛宺etry in 5s:");
     }
 }
 
diff --git a/vf107/src/worker/netWorker.js b/vf107/src/worker/netWorker.js
index c068030..da189d0 100644
--- a/vf107/src/worker/netWorker.js
+++ b/vf107/src/worker/netWorker.js
@@ -31,6 +31,8 @@
 // 缃戠粶鐘舵�佽窡韪彉閲�
 let lastConnected = false  // 涓婃杩炴帴鐘舵��
 let shouldReconnect = false
+let lastReconnectTime = 0  // 涓婃閲嶈繛鏃堕棿
+const RECONNECT_INTERVAL = 15000  // 閲嶈繛闂撮殧锛堟绉掞級
 const net_map = map.get("NET")
 /**
  * 鏍规嵁閰嶇疆寤虹珛缃戠粶杩炴帴
@@ -42,6 +44,12 @@
  */
 function connect() {
     try {
+        // 濡傛灉缃戠粶宸茬粡杩炴帴锛屼笉闇�瑕侀噸杩�
+        if (net.isConnected()) {
+            logger.info("NET already connected, skip connect")
+            return 0
+        }
+        
         let res = 0;
         // 鑾峰彇缃戠粶閰嶇疆
         let dhcp = config.get("net.dhcp") == 2  // DHCP鍚敤鏍囧織
@@ -119,7 +127,10 @@
         logger.info("NET connect res:", res);
         if (res < 0) {
             //灏忎簬0骞朵笉鏄〃绀虹綉缁滆繛鎺ュけ璐ワ紝鑰屾槸涓�涓壒娈婄殑閿欒锛屽彲浠ラ噸璇曚竴娆″氨鍙互
-            shouldReconnect = true
+            const currentTime = Date.now()
+            if (currentTime - lastReconnectTime >= RECONNECT_INTERVAL) {
+                shouldReconnect = true
+            }
         }
         return res;
     } catch (error) {
@@ -187,28 +198,43 @@
             if (net.getNative()) {
                 net.loop(); // 鎵ц缃戠粶寰幆澶勭悊
             }
+            
+            // 鍏堟鏌ョ綉缁滆繛鎺ョ姸鎬�
+            if (net.isConnected()) {
+                let param = driver.net.getNetParam()
+                if (!lastConnected || lastConnectedIp != param.ip) {
+                    bus.fire(driver.net.CONNECTED_CHANGED, "connected")
+                    lastConnected = true
+                    net_map.put("NET_STATUS", "connected")
+                    lastConnectedIp = param.ip
+                }
+            } else {
+                logger.info("NET not isConnected");
+                // if (lastConnected) {
+                    bus.fire(driver.net.CONNECTED_CHANGED, "disconnected")
+                    lastConnected = false
+                    net_map.put("NET_STATUS", "disconnected")
+                    // 鑷姩瑙﹀彂閲嶈繛
+                    shouldReconnect = true
+                // }
+            }
+            
+            // 鐒跺悗妫�鏌ユ槸鍚﹂渶瑕侀噸杩�
             if (shouldReconnect) {
-                logger.info("NET shouldReconnect");
-                shouldReconnect = false
-                connect()
+                const currentTime = Date.now()
+                if (currentTime - lastReconnectTime >= RECONNECT_INTERVAL) {
+                    logger.info("NET shouldReconnect");
+                    shouldReconnect = false
+                    lastReconnectTime = currentTime
+                    connect()
+                } else {
+                    // 閲嶈繛闂撮殧涓嶈冻锛屽彇娑堥噸杩�
+                    shouldReconnect = false
+                    // logger.info("NET reconnect skipped, interval not reached")
+                }
             }
         } catch (error) {
             logger.error(error)
-        }
-        if (net.isConnected()) {
-            let param = driver.net.getNetParam()
-            if (!lastConnected || lastConnectedIp != param.ip) {
-                bus.fire(driver.net.CONNECTED_CHANGED, "connected")
-                lastConnected = true
-                net_map.put("NET_STATUS", "connected")
-                lastConnectedIp = param.ip
-            }
-        } else {
-            if (lastConnected) {
-                bus.fire(driver.net.CONNECTED_CHANGED, "disconnected")
-                lastConnected = false
-                net_map.put("NET_STATUS", "disconnected")
-            }
         }
     }, 5000)
 }
diff --git a/vf107/src/worker/passRecordWorker.js b/vf107/src/worker/passRecordWorker.js
index 5c7f693..df0ecd3 100644
--- a/vf107/src/worker/passRecordWorker.js
+++ b/vf107/src/worker/passRecordWorker.js
@@ -12,7 +12,7 @@
  *
  * 鑱岃矗锛�
  * - 甯搁┗杩愯锛屽彧瑕� MQTT 杩炴帴灏辨寔缁笂鎶�
- * - 姣忔鍔犺浇鎵�鏈夋湭鍒犻櫎鐨勯�氳璁板綍锛坉1_pass_record锛�
+ * - 姣忔鍔犺浇鎵�鏈夋湭涓婃姤鐨勯�氳璁板綍锛坉1_pass_record锛�
  * - 姣忛殧 5 绉掍笂鎶ヤ竴鏉�
  * - 鍙戝畬褰撳墠鎵规鍚庯紝鑷姩閲嶆柊鍔犺浇鏈�鏂拌褰�
  */
@@ -29,10 +29,12 @@
     return mqtt_map.get("MQTT_STATUS") === "connected"
 }
 
-// 鍔犺浇鏂版壒娆★細鏌ヨ鎵�鏈夋湭鍒犻櫎鐨勮褰曪紙鎸夋椂闂村崌搴忥級
+// 鍔犺浇鏂版壒娆★細鏌ヨ鎵�鏈夋湭鍒犻櫎涓旀湭涓婃姤鐨勮褰曪紙鎸夋椂闂村崌搴忥級
 function loadNewBatch() {
     try {
-        currentBatch = sqliteService.d1_pass_record.findAllOrderByTimeStampAsc() 
+        let sql = `SELECT * FROM d1_pass_record WHERE reported = 0 OR reported IS NULL ORDER BY timeStamp ASC`
+        let result = sqliteService.select(sql)
+        currentBatch = result || []
         currentIndex = 0
     } catch (err) {
         logger.error("[passRecordWorker] Failed to load batch:", err)
@@ -59,29 +61,70 @@
         return
     }
     let extra = record.extra ? JSON.parse(record.extra) : ""
+    let extra2 = record.extra2 ? JSON.parse(record.extra2) : ""
     let accessRecord = {
-        userId: record.userId,
-        type: record.type,
-        result: record.result,
-        name: extra && extra.name ? extra.name : "",
-        timeStamp: record.timeStamp,
-        extra: {},
-        error: record.message
+        timeStamp: mqttService.timestampToDateString(record.timeStamp || 0),
+        result: record.result || 0,
+        error: record.message || "",
+        // permissionId: record.permissionId || "", // TODO
+        door: config.get("houseName") || "",
+        users: [
+            {
+                userId: record.userId || "",
+                name: extra && extra.name ? extra.name : "",
+                userType: extra && extra.type ? extra.type : 0,
+                accessType: extra && extra.accessType !== undefined ? extra.accessType : "",
+                card: extra && extra.card ? extra.card : "",
+                face: extra && extra.face ? extra.face : "",
+                finge: extra && extra.finge ? extra.finge : ""
+            }
+        ]
     }
+    
+    // 濡傛灉鏄弻浜鸿璇侊紝娣诲姞绗簩涓敤鎴蜂俊鎭�
+    if (record.userId2) {
+        let secondUser = {
+            userId: record.userId2 || "",
+            name: extra2 && extra2.name ? extra2.name : "",
+            userType: extra2 && extra2.type ? extra2.type : 0,
+            accessType: extra2 && extra2.accessType !== undefined ? extra2.accessType : "",
+            card: extra2 && extra2.card ? extra2.card : "",
+            face: extra2 && extra2.face ? extra2.face : "",
+            finge: extra2 && extra2.finge ? extra2.finge : ""
+        }
+        // 鏍规嵁璁よ瘉绫诲瀷娣诲姞鐩稿簲鐨勮璇佷俊鎭�
+        if (extra2 && extra2.accessType == 200 && extra2.card) {
+            secondUser.card = extra2.card
+        } else if (extra2 && extra2.accessType == 300) {
+            // 浜鸿劯璁よ瘉锛宖ace瀛楁鍙互鐣欑┖鎴栨坊鍔犵浉搴斾俊鎭�
+        } else if (extra2 && extra2.accessType == 500) {
+            // 鎸囩汗璁よ瘉锛宖inge瀛楁鍙互鐣欑┖鎴栨坊鍔犵浉搴斾俊鎭�
+        }
+        accessRecord.users.push(secondUser)
+    }
+    
     if (record.type == 300) {
-        if (std.exist(record.code) && config.get("access.uploadToCloud")) {
-            accessRecord.code = dxCommonUtils.fs.fileToBase64(record.code)
+        if (std.exist(record.code)) {
+            // 浜鸿劯璁よ瘉锛屽皢鍥剧墖杞崲涓篵ase64濉厖鍒癴ace瀛楁
+            accessRecord.users[0].face = dxCommonUtils.fs.fileToBase64(record.code)
             if (currentIndex > 0) {
                 currentBatch[currentIndex - 1].code = ""
             }
         } else {
-            accessRecord.code = ""
+            accessRecord.users[0].face = ""
+        }
+        
+        // 濡傛灉鏈夌浜屼釜鐢ㄦ埛鐨勪簩缁寸爜
+        if (record.code2) {
+            accessRecord.users[1] = accessRecord.users[1] || {}
+            accessRecord.users[1].code = record.code2
         }
     }
     // 鍙戦��
     try {
+        const sn = config.get("sys.sn") || "default"
         driver.mqtt.send(
-            "access_device/v2/event/access",
+            `access_device/v2/event/${sn}/access`,
             JSON.stringify(
                 mqttService.mqttReply(
                     record.id,
@@ -90,6 +133,13 @@
                 )
             )
         )
+        // 鏍囪璁板綍涓哄凡涓婃姤
+        try {
+            let updateSql = `UPDATE d1_pass_record SET reported = 1 WHERE id = '${record.id}'`
+            sqliteService.exec(updateSql)
+        } catch (updateErr) {
+            logger.error("[passRecordWorker] Failed to update reported status for record", record.id, updateErr)
+        }
     } catch (e) {
         logger.error("[passRecordWorker] Send failed for record", record.id, e)
     }

--
Gitblit v1.9.3