vf107/dxmodules/dxDriver.js
@@ -7,7 +7,7 @@ */ dxDriver.DRIVER = { // Driver model MODEL: "vf105" MODEL: "vf107" } /** 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 æä»¶ï¼zip æ ¼å¼ï¼ä¸ä¼ å° web æå¡å¨å¹¶è·åä¸è½½ URLã * 3. å°ä¸è½½ URL å MD5 æ ¡éªååéå°è®¾å¤åºç¨ã * - å° URL å MD5 ç¼ç 为äºç»´ç ä¾è®¾å¤æ«æï¼ * - æä½¿ç¨å ¶ä»æ¹æ³ï¼èçãMQTTãRS485 çï¼ã * 4. 设å¤ä¸è½½å¹¶ä½¿ç¨ MD5 éªè¯å 宿´æ§ã * 5. å°å æåå°ç¨³å®ç®å½å¹¶éå¯è®¾å¤ã * 6. éå¯åï¼DejaOS æåå å¹¶è¦çç°æä»£ç ã * ææ¡£/示ä¾ï¼https://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() ä»£æ¿ * æ¯æèªå®ä¹èæ¬çæ§åçº§æ¹æ³ã * ä¸è½½ãæåå¹¶æ§è¡èªå®ä¹åçº§èæ¬ã * @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() ä»£æ¿ * ç¨äº 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}`) } 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: "ìì±", vf107/src/config.json
@@ -65,9 +65,9 @@ //æ¯å¦ç¬¬ä¸æ¬¡ç»å½åå° 0 æªç»å½ 1 å·²ç»å½ // TODO è¿ä¸ªé 置项åºè¯¥å±äºè¿è¡æ¶ç¶æ,ä¸èµ¢è¯¥åå ¥config.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 } 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) 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') 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) 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 () { 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设置æ£ç¡®ç认è¯ç±»å 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设置æ£ç¡®ç认è¯ç±»å 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设置æ£ç¡®ç认è¯ç±»å 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设置æ£ç¡®ç认è¯ç±»å 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 } // åå¨ç¬¬äºç¨æ·çæéIDï¼èº«ä»½ç±»åï¼ data.permissionId2 = secondUserType.toString() data.permissionId2 = userType2.toString() } else { // å¦ææ²¡ææ¥è¯¢å°ç¬¬äºç¨æ·ä¿¡æ¯ï¼ä½¿ç¨é»è®¤å¼ data.extra2 = { name: data.dualAuthInfo.secondUserName, idCard: "" } // æ ¹æ®data.type设置æ£ç¡®ç认è¯ç±»å 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设置æ£ç¡®ç认è¯ç±»å 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 } // 触å第ä¸ç¨æ·è®¤è¯æåäºä»¶ï¼æ´æ°UI bus.fire("accessSuccess", { data: { @@ -413,13 +471,19 @@ } catch (error) { logger.error("æ 第ä¸ç¨æ·èº«ä»½è¯å·æç±»å") } data.extra = { name: userRes[0].name, idCard: idCard1, type: firstUserType } // ç¡®ä¿ç¬¬ä¸ç¨æ·çä¿¡æ¯å å«accessTypeåæ®µ 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 } // ç¡®ä¿ç¬¬ä¸ç¨æ·çä¿¡æ¯å å«accessTypeåæ®µ let accessType1 = firstUser.data.extra.accessType || 0 data.extra = { name: firstUser.name, idCard: '', type: firstUser.type, accessType: accessType1 } } } catch (error) { logger.error("è§£æç¬¬ä¸ç¨æ·ä¿¡æ¯å¤±è´¥") data.extra = { name: firstUser.name, idCard: '', type: firstUser.type } // ç¡®ä¿ç¬¬ä¸ç¨æ·çä¿¡æ¯å å«accessTypeåæ®µ 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: "*ä»å æ°ä½æµåº¦ä¸åæ ¼ï¼ç¦æ¢éè¡*" }) // 触åéè¡æåäºä»¶ï¼æ´æ°ç¨æ·UI 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)) // ä¸åç´æ¥åéMQTTæ¶æ¯ï¼ç±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]: éè¡æå") // ç¡®ä¿ç¬¬ä¸ç¨æ·çextraå å«accessTypeåæ®µ if (!data.extra.accessType) { // æ ¹æ®data.type设置æ£ç¡®ç认è¯ç±»å 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 }) // 触åéè¡æåäºä»¶ï¼æ´æ°ç¨æ·UI 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 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 // å°extraåæ®µä»JSONå符串解æä¸ºJSON对象 if (person[0].extra && typeof person[0].extra === 'string') { try { record.extra = JSON.parse(person[0].extra) } catch (error) { // å¦æè§£æå¤±è´¥ï¼ä¿æåæ · console.error('è§£æ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) // å°base64æ°æ®è½¬æ¢ä¸ºæä»¶ dxCommonUtils.fs.base64ToFile(faceFilePath, base64Data) logger.info('[api] å·²å°base64æ°æ®ä¿å为æä»¶:', faceFilePath) } else { errorItem.errmsg = "æ°æ®æ ¼å¼é误ï¼faceåæ®µå¿ é¡»æ¯base64ç¼ç çå¾çæ°æ®" 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] å¼å§å¤çNFCå¡ä¿¡æ¯:', person.userId) // æ£æ¥NFC塿¯å¦éå¤ 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] è§£æç¨æ·ç±»å失败:', 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) // æ´æ°äººå表ä¸çpermissionIdsåæ®µ 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) // å°extraåæ®µä»JSONå符串解æä¸ºJSON对象 persons.forEach(person => { if (person.extra && typeof person.extra === 'string') { try { person.extra = JSON.parse(person.extra) } catch (error) { // å¦æè§£æå¤±è´¥ï¼ä¿æåæ · console.error('è§£æ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) { //人è¸ç¹æ®å¤çä¸ä¸ // å°extraåæ®µä»JSONå符串解æä¸ºJSON对象 if (element.extra && typeof element.extra === 'string') { try { element.extra = JSON.parse(element.extra) } catch (error) { // å¦æè§£æå¤±è´¥ï¼ä¿æåæ · console.error('è§£æ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ï¼é»è®¤ä¸º"äºç«¯ä¸å"ï¼MQTTåHTTPæ¥å£è®¾ç½®çæ åµï¼ 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ï¼é»è®¤ä¸º"äºç«¯ä¸å"ï¼MQTTåHTTPæ¥å£è®¾ç½®çæ åµï¼ 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) { // å°è¯å°createTime转æ¢ä¸ºæ°å const createTimeNum = Number(password.createTime); if (!isNaN(createTimeNum)) { password.createTime = timestampToDateString(createTimeNum); } } if (password.updateTime) { // å°è¯å°updateTime转æ¢ä¸ºæ°å 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 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() 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] æ¥æ¶å°insertPermissionå½ä»¤:', 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] è§£æåçåæ°:', 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表示æåï¼string表示éè¯¯ä¿¡æ¯ */ 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] æ¥æ¶å°getPermissionå½ä»¤:', 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] è§£æåçæ¥è¯¢åæ°:', 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] æ¥æ¶å°delPermissionå½ä»¤:', 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] è§£æåçåæ°:', 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表示æåï¼string表示éè¯¯ä¿¡æ¯ */ 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] æ¥æ¶å°clearPermissionå½ä»¤:', 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] æ¥æ¶å°insertUserå½ä»¤:', 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] è§£æåçåæ°:', 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表示æåï¼string表示éè¯¯ä¿¡æ¯ */ 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ãnameãtypeãidCardï¼" } // æ£æ¥typeåæ®µç±»å if (typeof person.type !== 'number') { return "æ°æ®æ ¼å¼é误ï¼typeåæ®µå¿ é¡»æ¯æ°å" } // æ£æ¥typeåæ®µå¼èå´ if (person.type < 0 || person.type > 1) { return "æ°æ®æ ¼å¼é误ï¼typeåæ®µå¼å¿ é¡»å¨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) // å°base64æ°æ®è½¬æ¢ä¸ºæä»¶ common.base64_2binfile(faceFilePath, base64Data) logger.info('[mqttService] å·²å°base64æ°æ®ä¿å为æä»¶:', faceFilePath) } else { return "æ°æ®æ ¼å¼é误ï¼faceåæ®µå¿ é¡»æ¯base64ç¼ç çå¾çæ°æ®" } // æ£æ¥æä»¶æ¯å¦åå¨ 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] æ¥æ¶å°getUserå½ä»¤:', 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) // è§£æ extra åæ®µï¼JSONå符串转å为JSONå¯¹è±¡ï¼æ¶é¤è½¬ä¹å符 persons.forEach(person => { try { if (person.extra) { person.extra = JSON.parse(person.extra) } } catch (error) { logger.error('[mqttService] è§£æ 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] æ¥æ¶å°delUserå½ä»¤:', 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] è§£æåçåæ°:', 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表示æåï¼string表示éè¯¯ä¿¡æ¯ */ 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] æ¥æ¶å°clearUserå½ä»¤:', 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] æ¥æ¶å°insertKeyå½ä»¤:', 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] è§£æåçåæ°:', 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表示æåï¼string表示éè¯¯ä¿¡æ¯ */ 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] æ¥æ¶å°getKeyå½ä»¤:', 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] è§£æåçæ¥è¯¢åæ°:', 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] æ¥æ¶å°delKeyå½ä»¤:', 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] è§£æåçåæ°:', 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表示æåï¼string表示éè¯¯ä¿¡æ¯ */ 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] æ¥æ¶å°clearKeyå½ä»¤:', 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] æ¥æ¶å°insertEmergencyPasswordå½ä»¤:', 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] è§£æåçåæ°:', 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表示æåï¼string表示éè¯¯ä¿¡æ¯ */ 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] æ¥æ¶å°getEmergencyPasswordå½ä»¤:', 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} æ¥æåç¬¦ä¸²ï¼æ ¼å¼ï¼YYYY-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] æ¥æ¶å°clearEmergencyPasswordå½ä»¤:', 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] æ¥æ¶å°insertSecurityå½ä»¤:', 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] è§£æåçåæ°:', 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表示æåï¼string表示éè¯¯ä¿¡æ¯ */ 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] æ¥æ¶å°getKeyå½ä»¤:', 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] è§£æåçæ¥è¯¢åæ°:', 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] æ¥æ¶å°delSecurityå½ä»¤:', 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] è§£æåçåæ°:', 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表示æåï¼string表示éè¯¯ä¿¡æ¯ */ 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] æ¥æ¶å°clearSecurityå½ä»¤:', 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] æ¥æ¶å°controlå½ä»¤:', 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] æ¥æ¶å°getConfigå½ä»¤:', 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] è§£æåçåæ°:', 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] æ¥æ¶å°setConfigå½ä»¤:', 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] è§£æåçåæ°:', 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] æ¥æ¶å°upgradeFirmwareå½ä»¤:', 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] è§£æåçåæ°:', 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] æ¥æ¶å°getRecordså½ä»¤:', 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] è§£æåçæ¥è¯¢åæ°:', 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 - æ¥æåç¬¦ä¸²ï¼æ ¼å¼ï¼YYYY-MM-DD HH:MM:SS * @returns {number} æ¶é´æ³ï¼ç§ï¼ */ function dateStringToTimestamp(dateString) { if (!dateString) return null // å°YYYY-MM-DD HH:MM:SSæ ¼å¼è½¬æ¢ä¸ºYYYY-MM-DDTHH:MM:SSæ ¼å¼ï¼ä»¥ä¾¿new Date()æ£ç¡®è§£æ 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 => { // è§£æextraåæ®µ let extraData = {} try { if (record.extra && record.extra !== '') { extraData = JSON.parse(record.extra) } } catch (error) { logger.error('[mqttService] è§£æextra失败:', error) } // è§£æextra2åæ®µ let extra2Data = {} try { if (record.extra2 && record.extra2 !== '') { extra2Data = JSON.parse(record.extra2) } } catch (error) { logger.error('[mqttService] è§£æ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] æ¥æ¶å°delRecordså½ä»¤:', 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] è§£æåçåæ°:', 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表示æåï¼string表示éè¯¯ä¿¡æ¯ */ 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] æ¥æ¶å°access_replyå½ä»¤:', JSON.stringify(event.topic)) logger.info('[mqttService] å½ä»¤payload:', event.payload) let payload = JSON.parse(event.payload) logger.info('[mqttService] è§£æåçåæ°:', 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] æ¥æ¶å°access_online_replyå½ä»¤:', JSON.stringify(raw.topic)) logger.info('[mqttService] å½ä»¤payload:', raw.payload) let payload = JSON.parse(raw.payload) logger.info('[mqttService] è§£æåçåæ°:', JSON.stringify(payload)) let map = dxMap.get("VERIFY") let data = map.get(payload.serialNo) if (data) { logger.info('[mqttService] å¤çå¨çº¿éªè¯åå¤ï¼serialNo:', 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) } } /** * é误代ç å®ä¹ */ const CODE = { // æå S_000: "000000", // æªç¥é误 E_100: "100000", // 设å¤å·²è¢«ç¦ç¨ E_101: "100001", // è®¾å¤æ£å¿ï¼è¯·ç¨ååè¯ 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) // // // æ£æ¥faceArray[index].codeæ¯å¦ææ // if (faceArray[index].code) { // faceArray[index].code = driver.face.fileToBase64(faceArray[index].code) // } else { // faceArray[index].code = "" // logger.info("人è¸è®°å½ä¸codeåæ®µä¸ºç©ºï¼è·³è¿Base64转æ¢") // } // // 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æ£æ¥ä¸æ¬¡mqttè¿æ¥ç¶æï¼å¦ææå¼ï¼å忢䏿¥ // 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 - é误代ç */ 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 - é误代ç * @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} 订é çtopicå表 */ 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}` æ¯è®¾å¤çåºåå·ï¼ä¼è¢«æ¿æ¢ä¸ºå®é ç设å¤åºåå·ã */ vf107/src/service/grainService.js
@@ -36,7 +36,7 @@ "401": "æªç»å½ï¼ç¨æ·ä¸åå¨", "403": "ç¨æ·æ æé", "404": "请æ±åè½ä¸åå¨", "500": "è¯·æ±æ§è¡å¼å¸¸ï¼è¯·è系管çå" "500": "è¯·æ±æ§è¡å¼å¸¸ï¼è¯·èç³»ç§é¿" } // æä½æé®å¯¹åºçè¯é³æä»¶ 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 = { 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] æ¥æ¶å°insertEmergencyPasswordå½ä»¤:', 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] è§£æåçåæ°:', 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表示æåï¼string表示éè¯¯ä¿¡æ¯ */ 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åHTTPæ¥å£è®¾ç½®çåºæ¥å¼ä»å¯ç ï¼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] æ¥æ¶å°getEmergencyPasswordå½ä»¤:', 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) { // å°è¯å°createTime转æ¢ä¸ºæ°å 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) { // å°è¯å°updateTime转æ¢ä¸ºæ°å 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] æ¥æ¶å°clearEmergencyPasswordå½ä»¤:', 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] æ¥æ¶å°insertEmergencyPasswordå½ä»¤:', 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] è§£æåçåæ°:', 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表示æåï¼string表示éè¯¯ä¿¡æ¯ */ 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åHTTPæ¥å£è®¾ç½®çåºæ¥å¼ä»å¯ç ï¼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] æ¥æ¶å°getEmergencyPasswordå½ä»¤:', 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) { // å°è¯å°createTime转æ¢ä¸ºæ°å 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) { // å°è¯å°updateTime转æ¢ä¸ºæ°å 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] æ¥æ¶å°clearEmergencyPasswordå½ä»¤:', 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] æ¥æ¶å°controlå½ä»¤:', 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} æ¥æåç¬¦ä¸²ï¼æ ¼å¼ï¼YYYY-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 === "" 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) } // å¼å§äºå¡ï¼äºå¡ä¸æäº¤æ°æ®åºéå¯åï¼æ°æ®ä¼è¿åï¼æä»¥transactionåä¸å®è¦commitï¼ä½æ¯å¦æå¨ä¸ä¸ªäºå¡å°æªæäº¤æåæ»çæ åµä¸æ§è¡å¦ä¸ä¸ª BEGIN TRANSACTIONï¼SQLite ä¼èªå¨å°æ°çäºå¡åµå¥å¨ä¹åçäºå¡å é¨ï¼è䏿¯è¦çä¹åçäºå¡ã sqliteService.transaction = function () { 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(), 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() 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) } vf107/src/view/config/menu/networkSettingView.js
@@ -9,6 +9,9 @@ const net_map = map.get("NET") const networkSettingView = {} networkSettingView.isEditing = false // æ¯å¦æ£å¨ç¼è¾é ç½®çæ å¿ä½ 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, () => { // åªæå½é 置没æååæ¶æè®¾ç½®isEditing为false if (!networkSettingView._isConfigChanged()) { networkSettingView.isEditing = false } }) // æ·»å å¼ååçå¬ï¼å½ç¨æ·ä¿®æ¹äºå¼æ¶è®¾ç½®isEditing为true 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 () { // å¦æç¨æ·æ£å¨ç¼è¾é ç½®ï¼ä¸æ§è¡èªå¨å·æ° if (networkSettingView.isEditing) { return } const configAll = screen.getConfig() let selectNum = 0 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(" ") } 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() + '') 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 vf107/src/view/mainView.js
@@ -35,10 +35,10 @@ // ç´æ¥ä»net模åè·å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) { // åºéæ¶ä½¿ç¨configä¸çIP @@ -86,10 +86,10 @@ // ç´æ¥ä»net模åè·å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) { // åºéæ¶ä½¿ç¨configä¸ç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 // 设置为mainView屿§ @@ -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 // 设置为mainView屿§ @@ -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 // 设置为mainView屿§ 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ï¼retry in 5s:"); // logger.error("MQTT connection errorï¼retry in 5s:"); } } 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) } vf107/src/worker/passRecordWorker.js
@@ -12,7 +12,7 @@ * * èè´£ï¼ * - 常驻è¿è¡ï¼åªè¦ MQTT è¿æ¥å°±æç»ä¸æ¥ * - æ¯æ¬¡å è½½æææªå é¤çéè¡è®°å½ï¼d1_pass_recordï¼ * - æ¯æ¬¡å è½½æææªä¸æ¥çéè¡è®°å½ï¼d1_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) { // 人è¸è®¤è¯ï¼faceåæ®µå¯ä»¥çç©ºææ·»å ç¸åºä¿¡æ¯ } else if (extra2 && extra2.accessType == 500) { // æçº¹è®¤è¯ï¼fingeåæ®µå¯ä»¥çç©ºææ·»å ç¸åºä¿¡æ¯ } 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)) { // 人è¸è®¤è¯ï¼å°å¾ç转æ¢ä¸ºbase64å¡«å å°faceåæ®µ 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) }