From e44ecb571bb2df6390503f4303282e18db5d60ef Mon Sep 17 00:00:00 2001
From: lgq <1015864684@qq.com>
Date: 星期一, 20 四月 2026 13:43:52 +0800
Subject: [PATCH] 1.修复安全入仓联动控制按钮无权限问题 2.增加安全入仓联动控制配置项,默认不启用 3.修改气体浓度验证选项默认不启用 4.增加门禁web页面源码  Changes to be committed: 	new file:   "face_webserver/ 	modified:   vf107/src/config.json 	modified:   vf107/src/service/grainService.js 	modified:   vf107/src/view/config/menu/doorControlView.js 	modified:   vf107/src/view/mainView.js

---
 face_webserver/face_webserver-修复2.0.2版本和企微bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/language/ko.js                  |  431 +
 face_webserver/face_webserver-修复2.0.2版本和企微bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/assets/right.png                |    0 
 vf107/src/config.json                                                                                                               |    4 
 vf107/src/view/config/menu/doorControlView.js                                                                                       |   21 
 face_webserver/face_webserver-修复2.0.2版本和企微bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/assets/font/iconfont.json       |   65 
 face_webserver/face_webserver-修复2.0.2版本和企微bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/public/favicon.ico                  |    0 
 face_webserver/face_webserver-修复2.0.2版本和企微bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/language/en.js                  |  450 +
 face_webserver/face_webserver-修复2.0.2版本和企微bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/views/config/index.vue          | 2241 ++++++++
 vf107/src/view/mainView.js                                                                                                          |  278 
 face_webserver/face_webserver-修复2.0.2版本和企微bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/assets/font/iconfont.eot        |    0 
 face_webserver/face_webserver-修复2.0.2版本和企微bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/language/index.js               |   64 
 face_webserver/face_webserver-修复2.0.2版本和企微bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/views/home/index.vue            |  535 ++
 face_webserver/face_webserver-修复2.0.2版本和企微bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/public/config.js                    |    1 
 face_webserver/face_webserver-修复2.0.2版本和企微bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/assets/font/iconfont.woff2      |    0 
 face_webserver/face_webserver-修复2.0.2版本和企微bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/assets/styles/theme.css         |  307 +
 face_webserver/face_webserver-修复2.0.2版本和企微bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/assets/font/iconfont.css        |   49 
 face_webserver/face_webserver-修复2.0.2版本和企微bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/components/table/tableList.vue  |  222 
 face_webserver/face_webserver-修复2.0.2版本和企微bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/views/person/index.vue          |  254 
 face_webserver/face_webserver-修复2.0.2版本和企微bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/utils/timezones.js              |  790 ++
 face_webserver/face_webserver-修复2.0.2版本和企微bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/excel/Blob.js                   |  179 
 face_webserver/face_webserver-修复2.0.2版本和企微bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/views/security/add.vue          |  132 
 face_webserver/face_webserver-修复2.0.2版本和企微bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/views/record/index.vue          |  314 +
 face_webserver/face_webserver-修复2.0.2版本和企微bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/main.js                         |   42 
 face_webserver/face_webserver-修复2.0.2版本和企微bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/utils/index.js                  |  118 
 face_webserver/face_webserver-修复2.0.2版本和企微bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/language/fr.js                  |  435 +
 face_webserver/face_webserver-修复2.0.2版本和企微bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/views/person/vourcher.vue       | 1026 +++
 vf107/.temp/md5s.json                                                                                                               |   53 
 face_webserver/face_webserver-修复2.0.2版本和企微bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/directives/model-permission.js  |   44 
 face_webserver/face_webserver-修复2.0.2版本和企微bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/package.json                        |   56 
 face_webserver/face_webserver-修复2.0.2版本和企微bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/language/de.js                  |  433 +
 face_webserver/face_webserver-修复2.0.2版本和企微bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/views/control/index.vue         |  982 +++
 face_webserver/face_webserver-修复2.0.2版本和企微bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/assets/font/iconfont.ttf        |    0 
 face_webserver/face_webserver-修复2.0.2版本和企微bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/assets/font/base64ToImg.js      |   18 
 face_webserver/face_webserver-修复2.0.2版本和企微bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/assets/font/iconfont.svg        |   50 
 face_webserver/face_webserver-修复2.0.2版本和企微bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/utils/bus.js                    |    5 
 face_webserver/face_webserver-修复2.0.2版本和企微bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/views/person/addOrEdit.vue      |  132 
 face_webserver/face_webserver-修复2.0.2版本和企微bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/babel.config.js                     |    5 
 face_webserver/face_webserver-修复2.0.2版本和企微bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/views/person/info.vue           |  140 
 face_webserver/face_webserver-修复2.0.2版本和企微bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/public/index.css                    |  136 
 vf107/src/service/grainService.js                                                                                                   |   66 
 face_webserver/face_webserver-修复2.0.2版本和企微bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/utils/export.js                 |   99 
 face_webserver/face_webserver-修复2.0.2版本和企微bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/excel/Export2Excel.js           |  142 
 face_webserver/face_webserver-修复2.0.2版本和企微bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/router.js                       |   57 
 face_webserver/face_webserver-修复2.0.2版本和企微bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/README.md                           |   33 
 face_webserver/face_webserver-修复2.0.2版本和企微bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/assets/font/demo_index.html     |  354 +
 face_webserver/face_webserver-修复2.0.2版本和企微bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/assets/font/iconfont.js         |    1 
 face_webserver/face_webserver-修复2.0.2版本和企微bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/language/zh.js                  |  452 +
 face_webserver/face_webserver-修复2.0.2版本和企微bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/utils/request.js                |   91 
 face_webserver/face_webserver-修复2.0.2版本和企微bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/language/ar.js                  |  432 +
 face_webserver/face_webserver-修复2.0.2版本和企微bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/views/security/index.vue        |  217 
 vf107/.temp/md5snew.json                                                                                                            |   53 
 face_webserver/face_webserver-修复2.0.2版本和企微bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/assets/bg.png                   |    0 
 face_webserver/face_webserver-修复2.0.2版本和企微bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/assets/font/demo.css            |  539 ++
 face_webserver/face_webserver-修复2.0.2版本和企微bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/components/table/pagination.vue |   56 
 face_webserver/face_webserver-修复2.0.2版本和企微bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/vue.config.js                       |   39 
 face_webserver/face_webserver-修复2.0.2版本和企微bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/assets/font/iconfont.woff       |    0 
 face_webserver/face_webserver-修复2.0.2版本和企微bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/views/person/permission.vue     |  702 ++
 vf107/.temp/dxide_debug.log                                                                                                         |   18 
 face_webserver/face_webserver-修复2.0.2版本和企微bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/views/monitor/index.vue         |  715 ++
 face_webserver/face_webserver-修复2.0.2版本和企微bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/language/es.js                  |  452 +
 face_webserver/face_webserver-修复2.0.2版本和企微bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/public/index.html                   |   39 
 face_webserver/face_webserver-修复2.0.2版本和企微bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/language/pt.js                  |  430 +
 face_webserver/face_webserver-修复2.0.2版本和企微bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/language/ru.js                  |  430 +
 face_webserver/face_webserver-修复2.0.2版本和企微bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/.gitignore                          |   24 
 face_webserver/face_webserver-修复2.0.2版本和企微bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/App.vue                         |  172 
 face_webserver/face_webserver-修复2.0.2版本和企微bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/views/login/index.vue           |  348 +
 66 files changed, 15,866 insertions(+), 107 deletions(-)

diff --git "a/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/.gitignore" "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/.gitignore"
new file mode 100644
index 0000000..cc31708
--- /dev/null
+++ "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/.gitignore"
@@ -0,0 +1,24 @@
+.DS_Store
+node_modules
+/dist
+
+
+# local env files
+.env.local
+.env.*.local
+
+# Log files
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+
+# Editor directories and files
+.idea
+.vscode
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
+/package-lock.json
diff --git "a/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/README.md" "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/README.md"
new file mode 100644
index 0000000..bfd0ef3
--- /dev/null
+++ "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/README.md"
@@ -0,0 +1,33 @@
+# 瀹夎渚濊禆
+npm install
+
+# 鍚姩寮�鍙戞湇鍔″櫒
+npm run serve
+
+# 鏋勫缓鐢熶骇鐗堟湰
+npm run build
+
+# 椤圭洰缁撴瀯
+main.js          # Vue 搴旂敤鐨勫叆鍙f枃浠讹紝鍒涘缓Vue瀹炰緥鎸傚湪鍒癉OM涓�
+vue.config.js    # Vue CLI 閰嶇疆鏂囦欢锛堝彲閰嶇疆浠g悊锛�
+public/
+鈹溾攢鈹� config.js       # 瀛樻斁杩愯鏃堕厤缃�
+鈹溾攢鈹� favicon.ico   # 缃戠珯鍥炬爣
+鈹溾攢鈹� index.html     # 搴旂敤鐨勪富鏂囦欢锛孷ue鐨勫叆鍙�
+鈹溾攢鈹� index.css        # 鍏ㄥ眬CSS鏍峰紡鏂囦欢
+
+src/
+鈹溾攢鈹� assets/       # 闈欐�佽祫婧�
+鈹溾攢鈹� components/   # 鍏叡缁勪欢
+鈹溾攢鈹� language/     # 鍥介檯鍖栨枃浠�
+鈹溾攢鈹� utils/        # 宸ュ叿鍑芥暟
+鈹�   鈹溾攢鈹� bus.js  # 缁勪欢闂撮�氫俊
+鈹�   鈹溾攢鈹� request.js  # http璁剧疆
+鈹溾攢鈹� views/        # 椤甸潰缁勪欢
+鈹斺攢鈹� router.js     # 璺敱閰嶇疆
+
+# UI缁勪欢浣跨敤鍙傝��
+https://element.eleme.cn/#/zh-CN/component/installation
+
+# vue2瀛︿範鍙傝��
+https://v2.cn.vuejs.org/v2/guide/index.html
\ No newline at end of file
diff --git "a/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/babel.config.js" "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/babel.config.js"
new file mode 100644
index 0000000..e955840
--- /dev/null
+++ "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/babel.config.js"
@@ -0,0 +1,5 @@
+module.exports = {
+  presets: [
+    '@vue/cli-plugin-babel/preset'
+  ]
+}
diff --git "a/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/package.json" "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/package.json"
new file mode 100644
index 0000000..45496fc
--- /dev/null
+++ "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/package.json"
@@ -0,0 +1,56 @@
+{
+  "name": "webserver",
+  "version": "0.1.0",
+  "private": true,
+  "scripts": {
+    "serve": "vue-cli-service serve",
+    "build": "vue-cli-service build",
+    "lint": "vue-cli-service lint"
+  },
+  "dependencies": {
+    "axios": "^0.21.1",
+    "core-js": "^3.6.5",
+    "echarts": "^5.2.2",
+    "element-ui": "^2.15.1",
+    "file-saver": "^2.0.5",
+    "install": "^0.13.0",
+    "jszip": "^3.7.1",
+    "npm": "^7.21.0",
+    "or": "^0.2.0",
+    "vue": "^2.6.11",
+    "vue-i18n": "8.23.0",
+    "vue-router": "^3.5.1",
+    "xlsx": "^0.17.0"
+  },
+  "devDependencies": {
+    "@vue/cli-plugin-babel": "~4.5.0",
+    "@vue/cli-plugin-eslint": "~4.5.0",
+    "@vue/cli-service": "~4.5.0",
+    "babel-eslint": "^10.1.0",
+    "eslint": "^6.7.2",
+    "eslint-plugin-vue": "^6.2.2",
+    "less": "^3.13.1",
+    "less-loader": "^5.0.0",
+    "script-loader": "^0.7.2",
+    "vue-template-compiler": "^2.6.11"
+  },
+  "eslintConfig": {
+    "root": true,
+    "env": {
+      "node": true
+    },
+    "extends": [
+      "plugin:vue/essential",
+      "eslint:recommended"
+    ],
+    "parserOptions": {
+      "parser": "babel-eslint"
+    },
+    "rules": {}
+  },
+  "browserslist": [
+    "> 1%",
+    "last 2 versions",
+    "not dead"
+  ]
+}
diff --git "a/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/public/config.js" "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/public/config.js"
new file mode 100644
index 0000000..029ab6a
--- /dev/null
+++ "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/public/config.js"
@@ -0,0 +1 @@
+document.title = '浜鸿劯绯荤粺'
\ No newline at end of file
diff --git "a/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/public/favicon.ico" "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/public/favicon.ico"
new file mode 100644
index 0000000..df36fcf
--- /dev/null
+++ "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/public/favicon.ico"
Binary files differ
diff --git "a/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/public/index.css" "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/public/index.css"
new file mode 100644
index 0000000..e23fb54
--- /dev/null
+++ "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/public/index.css"
@@ -0,0 +1,136 @@
+html,
+body,
+#app {
+  width: 100%;
+  height: 100%;
+  margin: 0;
+  padding: 0;
+  position: absolute;
+}
+
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
+  margin: 0;
+}
+
+/*
+ *
+ * 鏈寸礌鎸夐挳瀛椾綋棰滆壊
+ * 榛樿涓洪粦鑹诧紝涓轰笌涓婚涓�鑷存敼鎴愪富棰樿壊
+ * 涓庝富棰樿壊涓�鑷�
+ * 鏇存敼涓婚鑹叉椂锛岄渶瑕佹洿鏀硅鑹插��
+ *
+ */
+/* .el-button.el-button--default {
+  color: #00bcd4;
+} */
+
+.el-button.el-button--default.el-button--primary {
+  color: #ffffff;
+}
+
+/*
+ * 鎼滅储妗嗙粺涓�鏍峰紡
+ */
+.el-InputForm {
+  background-color: #fff;
+  padding: 10px 20px;
+  box-shadow: 0px 4px 16px 0px rgba(0, 0, 0, 0.16);
+  border-radius: 15px;
+  position: relative;
+}
+
+.el-InputForm .el-form-item {
+  margin-top: 10px;
+  margin-bottom: 10px;
+  padding: 5px 0;
+}
+
+/*
+ * 渚ц竟鏍忛�夐」琛岄珮
+ */
+.el-submenu__title,
+.el-menu-item {
+  height: 46px !important;
+  line-height: 46px !important;
+}
+
+/*
+ * 闈㈠寘灞戞渶鍚庝竴椤归鑹�
+ */
+.el-breadcrumb__item:last-child span {
+  color: #999 !important;
+}
+
+/* 琛ㄦ牸榧犳爣鎮仠妗嗗搴﹂檺鍒� */
+.el-tooltip__popper {
+  max-width: 90%;
+  line-height: 2 !important;
+}
+
+/* 绂佺敤鐘舵�佽緭鍏ユ鏂囧瓧棰滆壊 */
+.the-main .el-textarea.is-disabled .el-textarea__inner,
+.the-main .el-input.is-disabled .el-input__inner {
+  color: #000;
+}
+
+.el-button {
+  min-width: 120px;
+}
+
+.el-button--text {
+  min-width: auto;
+}
+
+/* 淇敼寮�鍏虫寜閽牱寮� */
+.el-switch__core {
+  width: 60px !important;
+}
+
+.el-switch__label {
+  display: none;
+  color: #ffffff00 !important;
+  position: absolute;
+  z-index: 9;
+  margin-left: 0;
+  margin-right: 0;
+}
+
+.el-switch__label--right {
+  right: 22px;
+}
+
+.el-switch__label--left {
+  left: 22px;
+}
+
+.el-switch .is-active {
+  color: #fff !important;
+}
+
+.el-dialog__footer {
+  text-align: center !important;
+}
+
+.el-dialog {
+  border-radius: 10px !important;
+}
+
+.dialog-footer {
+  text-align: center;
+  margin-top: 15px;
+}
+
+.el-message {
+  pointer-events: none;
+  z-index: 999 !important;
+}
+
+.el-message__content,
+.el-message__closeBtn {
+  pointer-events: auto;
+}
\ No newline at end of file
diff --git "a/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/public/index.html" "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/public/index.html"
new file mode 100644
index 0000000..d3a1bb0
--- /dev/null
+++ "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/public/index.html"
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<html lang="">
+  <head>
+    <meta charset="utf-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta name="viewport" content="width=device-width,initial-scale=1.0">
+    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
+    <title>Sistema facial</title>
+    <link href="./index.css" rel="stylesheet">
+    <script src="./config.js"></script>
+  </head>
+  <body>
+    <div id="app">
+    <div class="loading">
+      <svg width="135" height="135" viewBox="0 0 135 135" xmlns="http://www.w3.org/2000/svg" fill="#7493FF">
+        <path d="M67.447 58c5.523 0 10-4.477 10-10s-4.477-10-10-10-10 4.477-10 10 4.477 10 10 10zm9.448 9.447c0 5.523 4.477 10 10 10 5.522 0 10-4.477 10-10s-4.478-10-10-10c-5.523 0-10 4.477-10 10zm-9.448 9.448c-5.523 0-10 4.477-10 10 0 5.522 4.477 10 10 10s10-4.478 10-10c0-5.523-4.477-10-10-10zM58 67.447c0-5.523-4.477-10-10-10s-10 4.477-10 10 4.477 10 10 10 10-4.477 10-10z">
+          <animateTransform
+          attributeName="transform"
+          type="rotate"
+          from="0 67 67"
+          to="-360 67 67"
+          dur="2.5s"
+          repeatCount="indefinite"/>
+        </path>
+        <path d="M28.19 40.31c6.627 0 12-5.374 12-12 0-6.628-5.373-12-12-12-6.628 0-12 5.372-12 12 0 6.626 5.372 12 12 12zm30.72-19.825c4.686 4.687 12.284 4.687 16.97 0 4.686-4.686 4.686-12.284 0-16.97-4.686-4.687-12.284-4.687-16.97 0-4.687 4.686-4.687 12.284 0 16.97zm35.74 7.705c0 6.627 5.37 12 12 12 6.626 0 12-5.373 12-12 0-6.628-5.374-12-12-12-6.63 0-12 5.372-12 12zm19.822 30.72c-4.686 4.686-4.686 12.284 0 16.97 4.687 4.686 12.285 4.686 16.97 0 4.687-4.686 4.687-12.284 0-16.97-4.685-4.687-12.283-4.687-16.97 0zm-7.704 35.74c-6.627 0-12 5.37-12 12 0 6.626 5.373 12 12 12s12-5.374 12-12c0-6.63-5.373-12-12-12zm-30.72 19.822c-4.686-4.686-12.284-4.686-16.97 0-4.686 4.687-4.686 12.285 0 16.97 4.686 4.687 12.284 4.687 16.97 0 4.687-4.685 4.687-12.283 0-16.97zm-35.74-7.704c0-6.627-5.372-12-12-12-6.626 0-12 5.373-12 12s5.374 12 12 12c6.628 0 12-5.373 12-12zm-19.823-30.72c4.687-4.686 4.687-12.284 0-16.97-4.686-4.686-12.284-4.686-16.97 0-4.687 4.686-4.687 12.284 0 16.97 4.686 4.687 12.284 4.687 16.97 0z">
+          <animateTransform
+          attributeName="transform"
+          type="rotate"
+          from="0 67 67"
+          to="360 67 67"
+          dur="8s"
+          repeatCount="indefinite"/>
+        </path>
+      </svg>
+    </div>
+  </div>
+    <!-- built files will be auto injected -->
+  </body>
+</html>
diff --git "a/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/App.vue" "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/App.vue"
new file mode 100644
index 0000000..d73041a
--- /dev/null
+++ "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/App.vue"
@@ -0,0 +1,172 @@
+<template>
+  <div id="app">
+    <router-view></router-view>
+  </div>
+</template>
+<script>
+export default {
+  name: "App",
+   mounted(){
+    function checkIE(){
+      return '-ms-scroll-limit' in document.documentElement.style && '-ms-ime-align' in document.documentElement.style
+    }
+    if (checkIE()) {
+      window.addEventListener('hashchange', () => {
+        var currentPath = window.location.hash.slice(1);
+        if (this.$route.path !== currentPath) {
+        this.$router.push(currentPath)
+      }
+    }, false)
+    }
+  }
+};
+</script>
+<style lang="less">
+@import './assets/styles/theme.css';
+
+html {
+  height: 100%;
+  font-size: 14px;
+  
+  body {
+    padding: 0;
+    margin: 0;
+    height: 100%;
+    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', 'Helvetica Neue', Helvetica, Arial, sans-serif;
+    background-color: var(--bg-secondary);
+    color: var(--text-primary);
+    line-height: 1.5715;
+    
+    #app {
+      height: 100%;
+    }
+  }
+}
+
+/* 鍏ㄥ眬Element UI鏍峰紡浼樺寲 */
+.el-button {
+  border-radius: var(--radius-md);
+  font-weight: 500;
+  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+  
+  &:hover {
+    transform: translateY(-1px);
+    box-shadow: var(--shadow-md);
+  }
+}
+
+.el-input__inner {
+  border-radius: var(--radius-md);
+  border: 1px solid var(--border-color);
+  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+  
+  &:focus {
+    border-color: var(--primary-color);
+    box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
+  }
+}
+
+.el-table {
+  border-radius: var(--radius-lg);
+  overflow: hidden;
+  
+  .el-table__header th {
+    background: var(--bg-tertiary);
+    color: var(--text-primary);
+    font-weight: 600;
+  }
+  
+  .el-table__row:hover {
+    background: rgba(24, 144, 255, 0.04);
+  }
+}
+
+.el-card {
+  border-radius: var(--radius-lg);
+  box-shadow: var(--shadow-md);
+  border: 1px solid var(--border-light);
+  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+  
+  &:hover {
+    box-shadow: var(--shadow-lg);
+    transform: translateY(-2px);
+  }
+}
+
+.el-drawer {
+  .el-drawer__header {
+    margin-bottom: 0;
+    padding: var(--spacing-lg);
+    border-bottom: 1px solid var(--border-light);
+    background: var(--bg-primary);
+  }
+  
+  .el-drawer__body {
+    padding: var(--spacing-lg);
+    background: var(--bg-secondary);
+  }
+}
+
+.el-dialog {
+  border-radius: var(--radius-lg);
+  overflow: hidden;
+  
+  .el-dialog__header {
+    background: var(--bg-primary);
+    border-bottom: 1px solid var(--border-light);
+    padding: var(--spacing-lg);
+  }
+  
+  .el-dialog__body {
+    background: var(--bg-secondary);
+    padding: var(--spacing-lg);
+  }
+  
+  .el-dialog__footer {
+    background: var(--bg-primary);
+    border-top: 1px solid var(--border-light);
+    padding: var(--spacing-md) var(--spacing-lg);
+  }
+}
+
+/* 婊氬姩鏉$編鍖� */
+::-webkit-scrollbar {
+  width: 6px;
+  height: 6px;
+}
+
+::-webkit-scrollbar-track {
+  background: var(--bg-tertiary);
+  border-radius: var(--radius-sm);
+}
+
+::-webkit-scrollbar-thumb {
+  background: var(--border-color);
+  border-radius: var(--radius-sm);
+  transition: background 0.3s ease;
+}
+
+::-webkit-scrollbar-thumb:hover {
+  background: var(--text-disabled);
+}
+
+/* 鍔犺浇鍔ㄧ敾 */
+.el-loading-mask {
+  background-color: rgba(255, 255, 255, 0.9);
+  backdrop-filter: blur(4px);
+}
+
+/* 娑堟伅鎻愮ず浼樺寲 */
+.el-message {
+  border-radius: var(--radius-md);
+  box-shadow: var(--shadow-lg);
+  border: none;
+}
+
+.el-notification {
+  border-radius: var(--radius-lg);
+  box-shadow: var(--shadow-xl);
+  border: 1px solid var(--border-light);
+}
+</style>
+
diff --git "a/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/assets/bg.png" "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/assets/bg.png"
new file mode 100644
index 0000000..3515271
--- /dev/null
+++ "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/assets/bg.png"
Binary files differ
diff --git "a/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/assets/font/base64ToImg.js" "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/assets/font/base64ToImg.js"
new file mode 100644
index 0000000..845a589
--- /dev/null
+++ "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/assets/font/base64ToImg.js"
@@ -0,0 +1,18 @@
+/*
+    *dataurl:base64
+    *filename:璁剧疆鏂囦欢鍚嶇О
+*/
+export const dataURLtoFile=(dataurl,filename) =>{
+    let arr = dataurl.split(',')
+    let mime = arr[0].match(/:(.*?);/)[1]
+    let suffix = mime.split('/')[1]
+    let bstr = atob(arr[1])
+    let n = bstr.length
+    let u8arr = new Uint8Array(n)
+    while (n--) {
+      u8arr[n] = bstr.charCodeAt(n)
+    }
+    return new File([u8arr], `${filename}.${suffix}`, {
+      type: mime
+    })
+}
\ No newline at end of file
diff --git "a/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/assets/font/demo.css" "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/assets/font/demo.css"
new file mode 100644
index 0000000..a67054a
--- /dev/null
+++ "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/assets/font/demo.css"
@@ -0,0 +1,539 @@
+/* Logo 瀛椾綋 */
+@font-face {
+  font-family: "iconfont logo";
+  src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834');
+  src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834#iefix') format('embedded-opentype'),
+    url('https://at.alicdn.com/t/font_985780_km7mi63cihi.woff?t=1545807318834') format('woff'),
+    url('https://at.alicdn.com/t/font_985780_km7mi63cihi.ttf?t=1545807318834') format('truetype'),
+    url('https://at.alicdn.com/t/font_985780_km7mi63cihi.svg?t=1545807318834#iconfont') format('svg');
+}
+
+.logo {
+  font-family: "iconfont logo";
+  font-size: 160px;
+  font-style: normal;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+
+/* tabs */
+.nav-tabs {
+  position: relative;
+}
+
+.nav-tabs .nav-more {
+  position: absolute;
+  right: 0;
+  bottom: 0;
+  height: 42px;
+  line-height: 42px;
+  color: #666;
+}
+
+#tabs {
+  border-bottom: 1px solid #eee;
+}
+
+#tabs li {
+  cursor: pointer;
+  width: 100px;
+  height: 40px;
+  line-height: 40px;
+  text-align: center;
+  font-size: 16px;
+  border-bottom: 2px solid transparent;
+  position: relative;
+  z-index: 1;
+  margin-bottom: -1px;
+  color: #666;
+}
+
+
+#tabs .active {
+  border-bottom-color: #f00;
+  color: #222;
+}
+
+.tab-container .content {
+  display: none;
+}
+
+/* 椤甸潰甯冨眬 */
+.main {
+  padding: 30px 100px;
+  width: 960px;
+  margin: 0 auto;
+}
+
+.main .logo {
+  color: #333;
+  text-align: left;
+  margin-bottom: 30px;
+  line-height: 1;
+  height: 110px;
+  margin-top: -50px;
+  overflow: hidden;
+  *zoom: 1;
+}
+
+.main .logo a {
+  font-size: 160px;
+  color: #333;
+}
+
+.helps {
+  margin-top: 40px;
+}
+
+.helps pre {
+  padding: 20px;
+  margin: 10px 0;
+  border: solid 1px #e7e1cd;
+  background-color: #fffdef;
+  overflow: auto;
+}
+
+.icon_lists {
+  width: 100% !important;
+  overflow: hidden;
+  *zoom: 1;
+}
+
+.icon_lists li {
+  width: 100px;
+  margin-bottom: 10px;
+  margin-right: 20px;
+  text-align: center;
+  list-style: none !important;
+  cursor: default;
+}
+
+.icon_lists li .code-name {
+  line-height: 1.2;
+}
+
+.icon_lists .icon {
+  display: block;
+  height: 100px;
+  line-height: 100px;
+  font-size: 42px;
+  margin: 10px auto;
+  color: #333;
+  -webkit-transition: font-size 0.25s linear, width 0.25s linear;
+  -moz-transition: font-size 0.25s linear, width 0.25s linear;
+  transition: font-size 0.25s linear, width 0.25s linear;
+}
+
+.icon_lists .icon:hover {
+  font-size: 100px;
+}
+
+.icon_lists .svg-icon {
+  /* 閫氳繃璁剧疆 font-size 鏉ユ敼鍙樺浘鏍囧ぇ灏� */
+  width: 1em;
+  /* 鍥炬爣鍜屾枃瀛楃浉閭绘椂锛屽瀭鐩村榻� */
+  vertical-align: -0.15em;
+  /* 閫氳繃璁剧疆 color 鏉ユ敼鍙� SVG 鐨勯鑹�/fill */
+  fill: currentColor;
+  /* path 鍜� stroke 婧㈠嚭 viewBox 閮ㄥ垎鍦� IE 涓嬩細鏄剧ず
+      normalize.css 涓篃鍖呭惈杩欒 */
+  overflow: hidden;
+}
+
+.icon_lists li .name,
+.icon_lists li .code-name {
+  color: #666;
+}
+
+/* markdown 鏍峰紡 */
+.markdown {
+  color: #666;
+  font-size: 14px;
+  line-height: 1.8;
+}
+
+.highlight {
+  line-height: 1.5;
+}
+
+.markdown img {
+  vertical-align: middle;
+  max-width: 100%;
+}
+
+.markdown h1 {
+  color: #404040;
+  font-weight: 500;
+  line-height: 40px;
+  margin-bottom: 24px;
+}
+
+.markdown h2,
+.markdown h3,
+.markdown h4,
+.markdown h5,
+.markdown h6 {
+  color: #404040;
+  margin: 1.6em 0 0.6em 0;
+  font-weight: 500;
+  clear: both;
+}
+
+.markdown h1 {
+  font-size: 28px;
+}
+
+.markdown h2 {
+  font-size: 22px;
+}
+
+.markdown h3 {
+  font-size: 16px;
+}
+
+.markdown h4 {
+  font-size: 14px;
+}
+
+.markdown h5 {
+  font-size: 12px;
+}
+
+.markdown h6 {
+  font-size: 12px;
+}
+
+.markdown hr {
+  height: 1px;
+  border: 0;
+  background: #e9e9e9;
+  margin: 16px 0;
+  clear: both;
+}
+
+.markdown p {
+  margin: 1em 0;
+}
+
+.markdown>p,
+.markdown>blockquote,
+.markdown>.highlight,
+.markdown>ol,
+.markdown>ul {
+  width: 80%;
+}
+
+.markdown ul>li {
+  list-style: circle;
+}
+
+.markdown>ul li,
+.markdown blockquote ul>li {
+  margin-left: 20px;
+  padding-left: 4px;
+}
+
+.markdown>ul li p,
+.markdown>ol li p {
+  margin: 0.6em 0;
+}
+
+.markdown ol>li {
+  list-style: decimal;
+}
+
+.markdown>ol li,
+.markdown blockquote ol>li {
+  margin-left: 20px;
+  padding-left: 4px;
+}
+
+.markdown code {
+  margin: 0 3px;
+  padding: 0 5px;
+  background: #eee;
+  border-radius: 3px;
+}
+
+.markdown strong,
+.markdown b {
+  font-weight: 600;
+}
+
+.markdown>table {
+  border-collapse: collapse;
+  border-spacing: 0px;
+  empty-cells: show;
+  border: 1px solid #e9e9e9;
+  width: 95%;
+  margin-bottom: 24px;
+}
+
+.markdown>table th {
+  white-space: nowrap;
+  color: #333;
+  font-weight: 600;
+}
+
+.markdown>table th,
+.markdown>table td {
+  border: 1px solid #e9e9e9;
+  padding: 8px 16px;
+  text-align: left;
+}
+
+.markdown>table th {
+  background: #F7F7F7;
+}
+
+.markdown blockquote {
+  font-size: 90%;
+  color: #999;
+  border-left: 4px solid #e9e9e9;
+  padding-left: 0.8em;
+  margin: 1em 0;
+}
+
+.markdown blockquote p {
+  margin: 0;
+}
+
+.markdown .anchor {
+  opacity: 0;
+  transition: opacity 0.3s ease;
+  margin-left: 8px;
+}
+
+.markdown .waiting {
+  color: #ccc;
+}
+
+.markdown h1:hover .anchor,
+.markdown h2:hover .anchor,
+.markdown h3:hover .anchor,
+.markdown h4:hover .anchor,
+.markdown h5:hover .anchor,
+.markdown h6:hover .anchor {
+  opacity: 1;
+  display: inline-block;
+}
+
+.markdown>br,
+.markdown>p>br {
+  clear: both;
+}
+
+
+.hljs {
+  display: block;
+  background: white;
+  padding: 0.5em;
+  color: #333333;
+  overflow-x: auto;
+}
+
+.hljs-comment,
+.hljs-meta {
+  color: #969896;
+}
+
+.hljs-string,
+.hljs-variable,
+.hljs-template-variable,
+.hljs-strong,
+.hljs-emphasis,
+.hljs-quote {
+  color: #df5000;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-type {
+  color: #a71d5d;
+}
+
+.hljs-literal,
+.hljs-symbol,
+.hljs-bullet,
+.hljs-attribute {
+  color: #0086b3;
+}
+
+.hljs-section,
+.hljs-name {
+  color: #63a35c;
+}
+
+.hljs-tag {
+  color: #333333;
+}
+
+.hljs-title,
+.hljs-attr,
+.hljs-selector-id,
+.hljs-selector-class,
+.hljs-selector-attr,
+.hljs-selector-pseudo {
+  color: #795da3;
+}
+
+.hljs-addition {
+  color: #55a532;
+  background-color: #eaffea;
+}
+
+.hljs-deletion {
+  color: #bd2c00;
+  background-color: #ffecec;
+}
+
+.hljs-link {
+  text-decoration: underline;
+}
+
+/* 浠g爜楂樹寒 */
+/* PrismJS 1.15.0
+https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */
+/**
+ * prism.js default theme for JavaScript, CSS and HTML
+ * Based on dabblet (http://dabblet.com)
+ * @author Lea Verou
+ */
+code[class*="language-"],
+pre[class*="language-"] {
+  color: black;
+  background: none;
+  text-shadow: 0 1px white;
+  font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
+  text-align: left;
+  white-space: pre;
+  word-spacing: normal;
+  word-break: normal;
+  word-wrap: normal;
+  line-height: 1.5;
+
+  -moz-tab-size: 4;
+  -o-tab-size: 4;
+  tab-size: 4;
+
+  -webkit-hyphens: none;
+  -moz-hyphens: none;
+  -ms-hyphens: none;
+  hyphens: none;
+}
+
+pre[class*="language-"]::-moz-selection,
+pre[class*="language-"] ::-moz-selection,
+code[class*="language-"]::-moz-selection,
+code[class*="language-"] ::-moz-selection {
+  text-shadow: none;
+  background: #b3d4fc;
+}
+
+pre[class*="language-"]::selection,
+pre[class*="language-"] ::selection,
+code[class*="language-"]::selection,
+code[class*="language-"] ::selection {
+  text-shadow: none;
+  background: #b3d4fc;
+}
+
+@media print {
+
+  code[class*="language-"],
+  pre[class*="language-"] {
+    text-shadow: none;
+  }
+}
+
+/* Code blocks */
+pre[class*="language-"] {
+  padding: 1em;
+  margin: .5em 0;
+  overflow: auto;
+}
+
+:not(pre)>code[class*="language-"],
+pre[class*="language-"] {
+  background: #f5f2f0;
+}
+
+/* Inline code */
+:not(pre)>code[class*="language-"] {
+  padding: .1em;
+  border-radius: .3em;
+  white-space: normal;
+}
+
+.token.comment,
+.token.prolog,
+.token.doctype,
+.token.cdata {
+  color: slategray;
+}
+
+.token.punctuation {
+  color: #999;
+}
+
+.namespace {
+  opacity: .7;
+}
+
+.token.property,
+.token.tag,
+.token.boolean,
+.token.number,
+.token.constant,
+.token.symbol,
+.token.deleted {
+  color: #905;
+}
+
+.token.selector,
+.token.attr-name,
+.token.string,
+.token.char,
+.token.builtin,
+.token.inserted {
+  color: #690;
+}
+
+.token.operator,
+.token.entity,
+.token.url,
+.language-css .token.string,
+.style .token.string {
+  color: #9a6e3a;
+  background: hsla(0, 0%, 100%, .5);
+}
+
+.token.atrule,
+.token.attr-value,
+.token.keyword {
+  color: #07a;
+}
+
+.token.function,
+.token.class-name {
+  color: #DD4A68;
+}
+
+.token.regex,
+.token.important,
+.token.variable {
+  color: #e90;
+}
+
+.token.important,
+.token.bold {
+  font-weight: bold;
+}
+
+.token.italic {
+  font-style: italic;
+}
+
+.token.entity {
+  cursor: help;
+}
diff --git "a/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/assets/font/demo_index.html" "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/assets/font/demo_index.html"
new file mode 100644
index 0000000..17c497b
--- /dev/null
+++ "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/assets/font/demo_index.html"
@@ -0,0 +1,354 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta charset="utf-8"/>
+  <title>IconFont Demo</title>
+  <link rel="shortcut icon" href="https://img.alicdn.com/tps/i4/TB1_oz6GVXXXXaFXpXXJDFnIXXX-64-64.ico" type="image/x-icon"/>
+  <link rel="stylesheet" href="https://g.alicdn.com/thx/cube/1.3.2/cube.min.css">
+  <link rel="stylesheet" href="demo.css">
+  <link rel="stylesheet" href="iconfont.css">
+  <script src="iconfont.js"></script>
+  <!-- jQuery -->
+  <script src="https://a1.alicdn.com/oss/uploads/2018/12/26/7bfddb60-08e8-11e9-9b04-53e73bb6408b.js"></script>
+  <!-- 浠g爜楂樹寒 -->
+  <script src="https://a1.alicdn.com/oss/uploads/2018/12/26/a3f714d0-08e6-11e9-8a15-ebf944d7534c.js"></script>
+</head>
+<body>
+  <div class="main">
+    <h1 class="logo"><a href="https://www.iconfont.cn/" title="iconfont 棣栭〉" target="_blank">&#xe86b;</a></h1>
+    <div class="nav-tabs">
+      <ul id="tabs" class="dib-box">
+        <li class="dib active"><span>Unicode</span></li>
+        <li class="dib"><span>Font class</span></li>
+        <li class="dib"><span>Symbol</span></li>
+      </ul>
+      
+      <a href="https://www.iconfont.cn/manage/index?manage_type=myprojects&projectId=2399544" target="_blank" class="nav-more">鏌ョ湅椤圭洰</a>
+      
+    </div>
+    <div class="tab-container">
+      <div class="content unicode" style="display: block;">
+          <ul class="icon_lists dib-box">
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe7ff;</span>
+                <div class="name">鐢ㄦ埛</div>
+                <div class="code-name">&amp;#xe7ff;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe616;</span>
+                <div class="name">鍏抽棴</div>
+                <div class="code-name">&amp;#xe616;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe78d;</span>
+                <div class="name">浜鸿劯璇嗗埆</div>
+                <div class="code-name">&amp;#xe78d;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe60d;</span>
+                <div class="name">閫�鍑�</div>
+                <div class="code-name">&amp;#xe60d;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xeb15;</span>
+                <div class="name">娑堟伅</div>
+                <div class="code-name">&amp;#xeb15;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe612;</span>
+                <div class="name">娑堟伅</div>
+                <div class="code-name">&amp;#xe612;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe644;</span>
+                <div class="name">瀵嗙爜</div>
+                <div class="code-name">&amp;#xe644;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#x666;</span>
+                <div class="name">璐﹀彿</div>
+                <div class="code-name">&amp;#x666;</div>
+              </li>
+          
+          </ul>
+          <div class="article markdown">
+          <h2 id="unicode-">Unicode 寮曠敤</h2>
+          <hr>
+
+          <p>Unicode 鏄瓧浣撳湪缃戦〉绔渶鍘熷鐨勫簲鐢ㄦ柟寮忥紝鐗圭偣鏄細</p>
+          <ul>
+            <li>鍏煎鎬ф渶濂斤紝鏀寔 IE6+锛屽強鎵�鏈夌幇浠f祻瑙堝櫒銆�</li>
+            <li>鏀寔鎸夊瓧浣撶殑鏂瑰紡鍘诲姩鎬佽皟鏁村浘鏍囧ぇ灏忥紝棰滆壊绛夌瓑銆�</li>
+            <li>浣嗘槸鍥犱负鏄瓧浣擄紝鎵�浠ヤ笉鏀寔澶氳壊銆傚彧鑳戒娇鐢ㄥ钩鍙伴噷鍗曡壊鐨勫浘鏍囷紝灏辩畻椤圭洰閲屾湁澶氳壊鍥炬爣涔熶細鑷姩鍘昏壊銆�</li>
+          </ul>
+          <blockquote>
+            <p>娉ㄦ剰锛氭柊鐗� iconfont 鏀寔澶氳壊鍥炬爣锛岃繖浜涘鑹插浘鏍囧湪 Unicode 妯″紡涓嬪皢涓嶈兘浣跨敤锛屽鏋滄湁闇�姹傚缓璁娇鐢╯ymbol 鐨勫紩鐢ㄦ柟寮�</p>
+          </blockquote>
+          <p>Unicode 浣跨敤姝ラ濡備笅锛�</p>
+          <h3 id="-font-face">绗竴姝ワ細鎷疯礉椤圭洰涓嬮潰鐢熸垚鐨� <code>@font-face</code></h3>
+<pre><code class="language-css"
+>@font-face {
+  font-family: 'iconfont';
+  src: url('iconfont.eot');
+  src: url('iconfont.eot?#iefix') format('embedded-opentype'),
+      url('iconfont.woff2') format('woff2'),
+      url('iconfont.woff') format('woff'),
+      url('iconfont.ttf') format('truetype'),
+      url('iconfont.svg#iconfont') format('svg');
+}
+</code></pre>
+          <h3 id="-iconfont-">绗簩姝ワ細瀹氫箟浣跨敤 iconfont 鐨勬牱寮�</h3>
+<pre><code class="language-css"
+>.iconfont {
+  font-family: "iconfont" !important;
+  font-size: 16px;
+  font-style: normal;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+</code></pre>
+          <h3 id="-">绗笁姝ワ細鎸戦�夌浉搴斿浘鏍囧苟鑾峰彇瀛椾綋缂栫爜锛屽簲鐢ㄤ簬椤甸潰</h3>
+<pre>
+<code class="language-html"
+>&lt;span class="iconfont"&gt;&amp;#x33;&lt;/span&gt;
+</code></pre>
+          <blockquote>
+            <p>"iconfont" 鏄綘椤圭洰涓嬬殑 font-family銆傚彲浠ラ�氳繃缂栬緫椤圭洰鏌ョ湅锛岄粯璁ゆ槸 "iconfont"銆�</p>
+          </blockquote>
+          </div>
+      </div>
+      <div class="content font-class">
+        <ul class="icon_lists dib-box">
+          
+          <li class="dib">
+            <span class="icon iconfont icon-dashujukeshihuaico-"></span>
+            <div class="name">
+              鐢ㄦ埛
+            </div>
+            <div class="code-name">.icon-dashujukeshihuaico-
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-guanxi"></span>
+            <div class="name">
+              鍏抽棴
+            </div>
+            <div class="code-name">.icon-guanxi
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-renlianshibie1"></span>
+            <div class="name">
+              浜鸿劯璇嗗埆
+            </div>
+            <div class="code-name">.icon-renlianshibie1
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-tuichu"></span>
+            <div class="name">
+              閫�鍑�
+            </div>
+            <div class="code-name">.icon-tuichu
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-biaoqiankuozhan_xiaoxi-157"></span>
+            <div class="name">
+              娑堟伅
+            </div>
+            <div class="code-name">.icon-biaoqiankuozhan_xiaoxi-157
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-xiaoxi"></span>
+            <div class="name">
+              娑堟伅
+            </div>
+            <div class="code-name">.icon-xiaoxi
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-mima"></span>
+            <div class="name">
+              瀵嗙爜
+            </div>
+            <div class="code-name">.icon-mima
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-zhanghao"></span>
+            <div class="name">
+              璐﹀彿
+            </div>
+            <div class="code-name">.icon-zhanghao
+            </div>
+          </li>
+          
+        </ul>
+        <div class="article markdown">
+        <h2 id="font-class-">font-class 寮曠敤</h2>
+        <hr>
+
+        <p>font-class 鏄� Unicode 浣跨敤鏂瑰紡鐨勪竴绉嶅彉绉嶏紝涓昏鏄В鍐� Unicode 涔﹀啓涓嶇洿瑙傦紝璇剰涓嶆槑纭殑闂銆�</p>
+        <p>涓� Unicode 浣跨敤鏂瑰紡鐩告瘮锛屽叿鏈夊涓嬬壒鐐癸細</p>
+        <ul>
+          <li>鍏煎鎬ц壇濂斤紝鏀寔 IE8+锛屽強鎵�鏈夌幇浠f祻瑙堝櫒銆�</li>
+          <li>鐩告瘮浜� Unicode 璇剰鏄庣‘锛屼功鍐欐洿鐩磋銆傚彲浠ュ緢瀹规槗鍒嗚鲸杩欎釜 icon 鏄粈涔堛��</li>
+          <li>鍥犱负浣跨敤 class 鏉ュ畾涔夊浘鏍囷紝鎵�浠ュ綋瑕佹浛鎹㈠浘鏍囨椂锛屽彧闇�瑕佷慨鏀� class 閲岄潰鐨� Unicode 寮曠敤銆�</li>
+          <li>涓嶈繃鍥犱负鏈川涓婅繕鏄娇鐢ㄧ殑瀛椾綋锛屾墍浠ュ鑹插浘鏍囪繕鏄笉鏀寔鐨勩��</li>
+        </ul>
+        <p>浣跨敤姝ラ濡備笅锛�</p>
+        <h3 id="-fontclass-">绗竴姝ワ細寮曞叆椤圭洰涓嬮潰鐢熸垚鐨� fontclass 浠g爜锛�</h3>
+<pre><code class="language-html">&lt;link rel="stylesheet" href="./iconfont.css"&gt;
+</code></pre>
+        <h3 id="-">绗簩姝ワ細鎸戦�夌浉搴斿浘鏍囧苟鑾峰彇绫诲悕锛屽簲鐢ㄤ簬椤甸潰锛�</h3>
+<pre><code class="language-html">&lt;span class="iconfont icon-xxx"&gt;&lt;/span&gt;
+</code></pre>
+        <blockquote>
+          <p>"
+            iconfont" 鏄綘椤圭洰涓嬬殑 font-family銆傚彲浠ラ�氳繃缂栬緫椤圭洰鏌ョ湅锛岄粯璁ゆ槸 "iconfont"銆�</p>
+        </blockquote>
+      </div>
+      </div>
+      <div class="content symbol">
+          <ul class="icon_lists dib-box">
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-dashujukeshihuaico-"></use>
+                </svg>
+                <div class="name">鐢ㄦ埛</div>
+                <div class="code-name">#icon-dashujukeshihuaico-</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-guanxi"></use>
+                </svg>
+                <div class="name">鍏抽棴</div>
+                <div class="code-name">#icon-guanxi</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-renlianshibie1"></use>
+                </svg>
+                <div class="name">浜鸿劯璇嗗埆</div>
+                <div class="code-name">#icon-renlianshibie1</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-tuichu"></use>
+                </svg>
+                <div class="name">閫�鍑�</div>
+                <div class="code-name">#icon-tuichu</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-biaoqiankuozhan_xiaoxi-157"></use>
+                </svg>
+                <div class="name">娑堟伅</div>
+                <div class="code-name">#icon-biaoqiankuozhan_xiaoxi-157</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-xiaoxi"></use>
+                </svg>
+                <div class="name">娑堟伅</div>
+                <div class="code-name">#icon-xiaoxi</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-mima"></use>
+                </svg>
+                <div class="name">瀵嗙爜</div>
+                <div class="code-name">#icon-mima</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-zhanghao"></use>
+                </svg>
+                <div class="name">璐﹀彿</div>
+                <div class="code-name">#icon-zhanghao</div>
+            </li>
+          
+          </ul>
+          <div class="article markdown">
+          <h2 id="symbol-">Symbol 寮曠敤</h2>
+          <hr>
+
+          <p>杩欐槸涓�绉嶅叏鏂扮殑浣跨敤鏂瑰紡锛屽簲璇ヨ杩欐墠鏄湭鏉ョ殑涓绘祦锛屼篃鏄钩鍙扮洰鍓嶆帹鑽愮殑鐢ㄦ硶銆傜浉鍏充粙缁嶅彲浠ュ弬鑰冭繖绡�<a href="">鏂囩珷</a>
+            杩欑鐢ㄦ硶鍏跺疄鏄仛浜嗕竴涓� SVG 鐨勯泦鍚堬紝涓庡彟澶栦袱绉嶇浉姣斿叿鏈夊涓嬬壒鐐癸細</p>
+          <ul>
+            <li>鏀寔澶氳壊鍥炬爣浜嗭紝涓嶅啀鍙楀崟鑹查檺鍒躲��</li>
+            <li>閫氳繃涓�浜涙妧宸э紝鏀寔鍍忓瓧浣撻偅鏍凤紝閫氳繃 <code>font-size</code>, <code>color</code> 鏉ヨ皟鏁存牱寮忋��</li>
+            <li>鍏煎鎬ц緝宸紝鏀寔 IE9+锛屽強鐜颁唬娴忚鍣ㄣ��</li>
+            <li>娴忚鍣ㄦ覆鏌� SVG 鐨勬�ц兘涓�鑸紝杩樹笉濡� png銆�</li>
+          </ul>
+          <p>浣跨敤姝ラ濡備笅锛�</p>
+          <h3 id="-symbol-">绗竴姝ワ細寮曞叆椤圭洰涓嬮潰鐢熸垚鐨� symbol 浠g爜锛�</h3>
+<pre><code class="language-html">&lt;script src="./iconfont.js"&gt;&lt;/script&gt;
+</code></pre>
+          <h3 id="-css-">绗簩姝ワ細鍔犲叆閫氱敤 CSS 浠g爜锛堝紩鍏ヤ竴娆″氨琛岋級锛�</h3>
+<pre><code class="language-html">&lt;style&gt;
+.icon {
+  width: 1em;
+  height: 1em;
+  vertical-align: -0.15em;
+  fill: currentColor;
+  overflow: hidden;
+}
+&lt;/style&gt;
+</code></pre>
+          <h3 id="-">绗笁姝ワ細鎸戦�夌浉搴斿浘鏍囧苟鑾峰彇绫诲悕锛屽簲鐢ㄤ簬椤甸潰锛�</h3>
+<pre><code class="language-html">&lt;svg class="icon" aria-hidden="true"&gt;
+  &lt;use xlink:href="#icon-xxx"&gt;&lt;/use&gt;
+&lt;/svg&gt;
+</code></pre>
+          </div>
+      </div>
+
+    </div>
+  </div>
+  <script>
+  $(document).ready(function () {
+      $('.tab-container .content:first').show()
+
+      $('#tabs li').click(function (e) {
+        var tabContent = $('.tab-container .content')
+        var index = $(this).index()
+
+        if ($(this).hasClass('active')) {
+          return
+        } else {
+          $('#tabs li').removeClass('active')
+          $(this).addClass('active')
+
+          tabContent.hide().eq(index).fadeIn()
+        }
+      })
+    })
+  </script>
+</body>
+</html>
diff --git "a/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/assets/font/iconfont.css" "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/assets/font/iconfont.css"
new file mode 100644
index 0000000..848e1e5
--- /dev/null
+++ "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/assets/font/iconfont.css"
@@ -0,0 +1,49 @@
+@font-face {font-family: "iconfont";
+  src: url('iconfont.eot?t=1614833736726'); /* IE9 */
+  src: url('iconfont.eot?t=1614833736726#iefix') format('embedded-opentype'), /* IE6-IE8 */
+  url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAAewAAsAAAAADuQAAAdgAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCECgqPRI0IATYCJAMkCxQABCAFhG0HgRgbzAwRFaxTIPvqgDebctK2YsIVXhR2hagG9WP1vtcZPG76914gQNIUVpLKTAyZOFZzOhEJm8PmyGCm0JkIsi+uBAC4MZCJtxogwBL4pk2TlOD2ThqWEK6lHdeaZFt+0NcvlxIggOz/1lq9c+q9DQX7eNsQqWVmd0/mxHwQtUTGQyYkUW+UfITIo3ZTqc1LwWeI629cDQQAh7paI0bzcBvUUEDTE3SYOK6qFOqYA4oSFYHazOYcqQDZCCXUdA19AmCD+/nkG3RMDVAoGWjXGu00VaA/6/xGYuSkrALGBbk/HwBxPYAB0BqgEE2hXKsXMJA3w4DrrsBYAGl09DUp6/xc+Dzt8/TPjV+s+yL5jZRMpkfS5iJI0w3Yh1oWFKrRiPL3z2OhGVJIPrVODbBOkwudnwuwQQFjGmxgYUyHDRRGI6pABXyxzgYGxiSqgADfSL2gBABo7CPSAI2AbgSYfGgW4xwslBMxOj11FdMzRVEQREm3ZggoaifUy9Kci63fNEXfMGVGIuGIxx3RqC0as9ukRmT8SZIrd36cSMSH+tOzdBPMxsGxmJ3Pfix3rnMsNjl0ranflXHoeq2ARwpebeKTxf1XMr3ueSHieZ7HfHVzo1Pc6U5guVmlT/aWuct8VQFP/kUrvALn9hPiirgPAzteduE91a7IlEhU9nKc21wO8/z51/UKTUWxjT0+QA57qgnZ+WquE3AF+BaU4868qJ19vmmBnZfOZPpe2OKvMvznGnu3S76YfeHUU12LhMaozUQwnN3IEIEzXOYIyWip2xHX14snEtmBQweCwa3ipnghx7Q8T8JGXAXUH6o+JCVw5rmiXLE/QphAtScsUflwuTvdH+og5k/n3O/mrmpe6wmDunEpbtHmLXKHe/H8gTAg+3yejOxAM8H+Zhk/l3Pwmuu656p8xeH2yj5PwOW3pdafsv2F+1XdYtc19xXg1LrBF23sPRwMD9it2nUw/WA8gxygb0YKWQc+Ta4ByUis546+iALc/sOgW0mEFYsYmiOLKX4Px3uiZP/hTF9QQuWehAS2ZYQiC07dj+DlBLk8W8mxHl7xQbT9CfD93pF3OfclBt2NNdgdNd6Ll80f2tiwTjc6bdT8MgsssK36UbG1jeuGNA40ufQV2T6Dbnd+xNYmFaxXV3LkYrV9j5jGM0v7Td75849jML9UP1oUrT3XxoYX3ua8v5fBYJr0dFPD82/z3ry6eV8H7m0cxyzrN2nDz7oTuwy1Rk5v1G2rc41FsKypDDYRpLA9GJ4r6DgsCR0+fHIpVF9Vf9tFqqIXt/l5oUvBrvgvB1MTGok0YBtYe1AVIk9V9hHDTdqI1uS0sGsvlfCqwDvClgqR8XATWk1zWePXO5s59X4h8sL3TYyKsSF5qhcRwWVZ8hpWed7OA1rUa7K+34aNjMbwfmFi9LU/U+5SsX91U7LK8iYoGbLZz3bqnUyEcTZt/sUS0Sm2FFtymO6PvSmSS0qyG9sb9R8wZMigmzVeVp6y9VnRqdsJpWv58G6trW0cZaN7bZw2bVOvPRt6OU16bxxd1saRtdbwrheHZ92+b+9Teao6avJOQ4YOHHjEXMzhQ5v2fKqhXqfU81ob1uj5/bEvtb2UnfrvlZ5IZ01TyF1LZBouHffohyqN5qwR29v/iVRhrfrKDq5xb+tEtfosmq9tesLWw9bdzFmtPP596f3076Xvn+anMUYGrvORmLSSLbWUsrv5rA7dO2RxBil/DkZZWU3VnBc6tU5QCPVrtrvh5MayVozMmW3OwB8f7jAQc2Gh2dIRAeFe3BXxiobmzp6dS1sNr3el3rBWhvb9L0sO6Yr098z3cEiPtasU/f/qr3AolX8Zb6UY0D5IU874crnH+sdczoE7Ag2i049tLyp6+Puna9rbOxPLpMkW0hEBoWmXDvbgp7GH+V23Hze3pYsOHVoEHeUQurY1f3cw1Wb96CPTmap174clMgAknzJXmRIAoNfoSCAZcZxxsM1lf8S4AICZRw8yph19zrSif4Zy6JvHz1Y4/n+XN8Xa3r/t/0ta8a5zzWBKJOVEPwE1aBEhH/5hI9ScovhoNKdG8Rq7ybco0mAf1JQC4PRZwCMmkub9fk1SbeGZZpJCoFChDjBQo7FYIW8NSvDoDCzU6AccWhl0PA+96WBAFBoALa1gQKBzHChScR0Y6DxFQJC/B0qk+w5Y6GKAg4Poz8hD2jS6vM+oBR2YPyDLrTfccul1fMFQap2jGjf/A3NPaZhPZsmGZ2wx97FP/x0WIh585gae2PWwrhm6zAmtTKJId5hOfd6+E8vN4JIhoxa7vAPmj02WWz+3XKZy/4Kh1DqXjPhmf2DuafVgbmJWQ/xsaGuNOJfu/XdYEKIeeLE9N+CJfFjrtQy6/M0SWpmILWh3MKWZfF3DZHxTc60Nunyjane8ApMUzbAcT/p1H0sqFTo68og+kH3Hp6Ho9pduM7Y16TZzf0M4P5VCNpY7Q5q/xO5V4f+o28/fODLrxvP19jRocdxQo8/zdYH8PBgAAAAA') format('woff2'),
+  url('iconfont.woff?t=1614833736726') format('woff'),
+  url('iconfont.ttf?t=1614833736726') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */
+  url('iconfont.svg?t=1614833736726#iconfont') format('svg'); /* iOS 4.1- */
+}
+
+.iconfont {
+  font-family: "iconfont" !important;
+  font-size: 16px;
+  font-style: normal;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+
+.icon-dashujukeshihuaico-:before {
+  content: "\e7ff";
+}
+
+.icon-guanxi:before {
+  content: "\e616";
+}
+
+.icon-renlianshibie1:before {
+  content: "\e78d";
+}
+
+.icon-tuichu:before {
+  content: "\e60d";
+}
+
+.icon-biaoqiankuozhan_xiaoxi-157:before {
+  content: "\eb15";
+}
+
+.icon-xiaoxi:before {
+  content: "\e612";
+}
+
+.icon-mima:before {
+  content: "\e644";
+}
+
+.icon-zhanghao:before {
+  content: "\666";
+}
+
diff --git "a/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/assets/font/iconfont.eot" "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/assets/font/iconfont.eot"
new file mode 100644
index 0000000..cf497b3
--- /dev/null
+++ "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/assets/font/iconfont.eot"
Binary files differ
diff --git "a/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/assets/font/iconfont.js" "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/assets/font/iconfont.js"
new file mode 100644
index 0000000..9b75104
--- /dev/null
+++ "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/assets/font/iconfont.js"
@@ -0,0 +1 @@
+!function(c){var t,e,a,i,f,l,o='<svg><symbol id="icon-dashujukeshihuaico-" viewBox="0 0 1024 1024"><path d="M611.413333 516.693333a231.253333 231.253333 0 1 0-199.253333 0 441.173333 441.173333 0 0 0-341.333333 429.653334h882.773333a441.173333 441.173333 0 0 0-342.186667-429.653334z" fill="#ffffff" ></path><path d="M611.413333 516.693333a231.253333 231.253333 0 1 0-199.253333 0 441.173333 441.173333 0 0 0-341.333333 429.653334h882.773333a441.173333 441.173333 0 0 0-342.186667-429.653334z" fill="#ffffff" ></path><path d="M611.413333 516.693333a231.253333 231.253333 0 1 0-199.253333 0 441.173333 441.173333 0 0 0-341.333333 429.653334h882.773333a441.173333 441.173333 0 0 0-342.186667-429.653334z" fill="#ffffff" ></path><path d="M953.6 946.346667a441.173333 441.173333 0 0 0-341.333333-429.653334 229.546667 229.546667 0 0 0 11.093333-409.173333 228.693333 228.693333 0 0 0-32-3.413333 230.4 230.4 0 0 0-99.413333 438.613333 440.32 440.32 0 0 0-341.333334 403.2z" fill="#ffffff" ></path><path d="M653.653333 334.933333a230.4 230.4 0 0 1-131.413333 207.786667 441.173333 441.173333 0 0 1 341.333333 403.2h90.453334a441.173333 441.173333 0 0 0-341.333334-429.653333 229.546667 229.546667 0 0 0 11.093334-409.173334 228.266667 228.266667 0 0 0-32-3.413333 229.973333 229.973333 0 0 0-85.333334 15.786667 230.826667 230.826667 0 0 1 147.2 215.466666z" fill="#ffffff" ></path><path d="M104.96 206.08A135.68 135.68 0 0 0 31.146667 131.84a9.813333 9.813333 0 0 1 0-18.346667A135.68 135.68 0 0 0 104.96 39.253333a9.813333 9.813333 0 0 1 18.346667 0 135.68 135.68 0 0 0 74.24 74.24 9.813333 9.813333 0 0 1 0 18.346667 135.68 135.68 0 0 0-74.24 74.24 9.813333 9.813333 0 0 1-18.346667 0z" fill="#ffffff" ></path><path d="M905.813333 416a69.546667 69.546667 0 0 0-37.973333-37.973333 5.12 5.12 0 0 1 0-9.386667 69.546667 69.546667 0 0 0 37.973333-37.973333 5.12 5.12 0 0 1 9.386667 0 69.546667 69.546667 0 0 0 37.973333 37.973333 5.12 5.12 0 0 1 0 9.386667 69.546667 69.546667 0 0 0-37.973333 37.973333 5.12 5.12 0 0 1-9.386667 0z" fill="#ffffff" ></path><path d="M42.666667 672a69.546667 69.546667 0 0 0-37.973334-37.973333 5.12 5.12 0 0 1 0-9.386667 69.546667 69.546667 0 0 0 37.973334-38.4 5.12 5.12 0 0 1 9.386666 0 69.546667 69.546667 0 0 0 37.973334 37.973333 5.12 5.12 0 0 1 0 9.386667 69.546667 69.546667 0 0 0-37.973334 37.973333 5.12 5.12 0 0 1-9.386666 0.426667z" fill="#ffffff" ></path></symbol><symbol id="icon-guanxi" viewBox="0 0 1024 1024"><path d="M683.008 689.664c-4.608 0-9.216-2.048-13.312-5.632L336.384 350.72c-7.168-7.168-7.168-18.944 0-26.112 7.168-7.168 18.944-7.168 26.112 0l333.824 333.824c7.168 7.168 7.168 18.944 0 26.112-3.584 3.584-8.704 5.12-13.312 5.12z" fill="#686464" ></path><path d="M337.408 677.888c-4.608 0-9.216-2.048-13.312-5.632-7.168-7.168-7.168-18.944 0-26.112L657.92 312.32c7.168-7.168 18.944-7.168 26.112 0 7.168 7.168 7.168 18.944 0 26.112l-333.824 333.824c-3.584 4.096-8.192 5.632-12.8 5.632z" fill="#686464" ></path></symbol><symbol id="icon-renlianshibie1" viewBox="0 0 1024 1024"><path d="M298.666667 896H149.333333c-12.8 0-21.333333-8.533333-21.333333-21.333333V725.333333c0-25.6-17.066667-42.666667-42.666667-42.666666s-42.666667 17.066667-42.666666 42.666666v149.333334C42.666667 934.4 89.6 981.333333 149.333333 981.333333H298.666667c25.6 0 42.666667-17.066667 42.666666-42.666666s-17.066667-42.666667-42.666666-42.666667zM938.666667 682.666667c-25.6 0-42.666667 17.066667-42.666667 42.666666v149.333334c0 12.8-8.533333 21.333333-21.333333 21.333333H725.333333c-25.6 0-42.666667 17.066667-42.666666 42.666667s17.066667 42.666667 42.666666 42.666666h149.333334c59.733333 0 106.666667-46.933333 106.666666-106.666666V725.333333c0-25.6-17.066667-42.666667-42.666666-42.666666zM874.666667 42.666667H725.333333c-25.6 0-42.666667 17.066667-42.666666 42.666666s17.066667 42.666667 42.666666 42.666667h149.333334c12.8 0 21.333333 8.533333 21.333333 21.333333V298.666667c0 25.6 17.066667 42.666667 42.666667 42.666666s42.666667-17.066667 42.666666-42.666666V149.333333C981.333333 89.6 934.4 42.666667 874.666667 42.666667zM85.333333 341.333333c25.6 0 42.666667-17.066667 42.666667-42.666666V149.333333c0-12.8 8.533333-21.333333 21.333333-21.333333H298.666667c25.6 0 42.666667-17.066667 42.666666-42.666667s-17.066667-42.666667-42.666666-42.666666H149.333333C89.6 42.666667 42.666667 89.6 42.666667 149.333333V298.666667c0 25.6 17.066667 42.666667 42.666666 42.666666zM721.066667 661.333333c12.8-21.333333 4.266667-46.933333-17.066667-59.733333-21.333333-12.8-46.933333-4.266667-59.733333 17.066667 0 0-38.4 64-132.266667 64s-132.266667-59.733333-132.266667-64c-12.8-21.333333-38.4-25.6-59.733333-17.066667-21.333333 12.8-25.6 38.4-17.066667 59.733333 4.266667 4.266667 64 106.666667 209.066667 106.666667s204.8-102.4 209.066667-106.666667zM512 512c25.6 0 42.666667-17.066667 42.666667-42.666667V298.666667c0-25.6-17.066667-42.666667-42.666667-42.666667s-42.666667 17.066667-42.666667 42.666667v170.666666c0 25.6 17.066667 42.666667 42.666667 42.666667zM725.333333 384c25.6 0 42.666667-17.066667 42.666667-42.666667V298.666667c0-25.6-17.066667-42.666667-42.666667-42.666667s-42.666667 17.066667-42.666666 42.666667v42.666666c0 25.6 17.066667 42.666667 42.666666 42.666667zM298.666667 256c-25.6 0-42.666667 17.066667-42.666667 42.666667v42.666666c0 25.6 17.066667 42.666667 42.666667 42.666667s42.666667-17.066667 42.666666-42.666667V298.666667c0-25.6-17.066667-42.666667-42.666666-42.666667z" fill="#dfe5f4" ></path></symbol><symbol id="icon-tuichu" viewBox="0 0 1024 1024"><path d="M511.924148 1023.924148a470.660741 470.660741 0 0 1-184.395852-37.167407 471.115852 471.115852 0 0 1-150.679703-101.376A471.87437 471.87437 0 0 1 236.468148 166.381037a37.091556 37.091556 0 1 1 43.159704 59.998815 404.745481 404.745481 0 0 0-121.742222 139.339852 392.305778 392.305778 0 0 0-45.700741 185.078518c0 106.571852 41.604741 206.810074 117.077333 282.206815a397.349926 397.349926 0 0 0 282.661926 117.001482c106.68563 0 207.151407-41.528889 282.737778-117.001482a396.09837 396.09837 0 0 0 117.039407-282.244741c0.227556-64.474074-15.435852-128.037926-45.662814-185.040592a404.366222 404.366222 0 0 0-121.742223-139.188148 36.939852 36.939852 0 1 1 43.159704-60.074667 471.798519 471.798519 0 0 1 59.58163 719.075555A472.936296 472.936296 0 0 1 511.924148 1024v-0.075852z m11.150222-513.403259a37.015704 37.015704 0 0 1-37.091555-36.939852V35.384889a37.129481 37.129481 0 0 1 74.221037 0v438.196148a36.939852 36.939852 0 0 1-37.167408 36.939852z" fill="#ffffff" ></path></symbol><symbol id="icon-biaoqiankuozhan_xiaoxi-157" viewBox="0 0 1024 1024"><path d="M393.7792 876.1344c-7.3728 0-14.848-1.6384-21.8624-5.0176-17.7664-8.4992-28.8256-26.0096-28.7744-45.6704l0.1536-59.4944c0-3.4304-1.7408-5.7344-2.7648-6.7584-1.024-1.024-3.328-2.816-6.7584-2.816H172.1344c-27.8528 0-50.4832-22.6304-50.4832-50.4832v-436.736c0-27.8528 22.6304-50.4832 50.4832-50.4832h665.6c27.8528 0 50.4832 22.6304 50.4832 50.4832v436.736c0 27.8528-22.6304 50.4832-50.4832 50.4832h-275.712c-2.2016 0-4.3008 0.768-6.0416 2.1504L425.472 864.7168a49.9968 49.9968 0 0 1-31.6928 11.4176zM172.1344 259.584c-5.2736 0-9.5232 4.3008-9.5232 9.5232v436.736c0 5.2736 4.2496 9.5232 9.5232 9.5232h161.5872c13.5168 0 26.2144 5.2736 35.7376 14.848a50.176 50.176 0 0 1 14.7456 35.7888l-0.1536 59.4944c0 5.4272 3.7888 7.8336 5.4272 8.6528 1.6384 0.768 5.888 2.2528 10.1376-1.2288l130.5088-106.1888a50.43712 50.43712 0 0 1 31.8464-11.3152h275.712c5.2736 0 9.5232-4.2496 9.5232-9.5232v-436.736c0-5.2736-4.3008-9.5232-9.5232-9.5232H172.1344z m525.056 295.4752c-36.7104 0-66.56-29.8496-66.56-66.56s29.8496-66.56 66.56-66.56 66.56 29.8496 66.56 66.56-29.8496 66.56-66.56 66.56z m0-92.16c-14.1312 0-25.6 11.4688-25.6 25.6s11.4688 25.6 25.6 25.6 25.6-11.4688 25.6-25.6-11.52-25.6-25.6-25.6z m-195.0208 92.16c-36.7104 0-66.56-29.8496-66.56-66.56s29.8496-66.56 66.56-66.56 66.56 29.8496 66.56 66.56-29.8496 66.56-66.56 66.56z m0-92.16c-14.1312 0-25.6 11.4688-25.6 25.6s11.4688 25.6 25.6 25.6 25.6-11.4688 25.6-25.6-11.4688-25.6-25.6-25.6z m-194.9696 92.16c-36.7104 0-66.56-29.8496-66.56-66.56s29.8496-66.56 66.56-66.56 66.56 29.8496 66.56 66.56-29.9008 66.56-66.56 66.56z m0-92.16c-14.1312 0-25.6 11.4688-25.6 25.6s11.4688 25.6 25.6 25.6 25.6-11.4688 25.6-25.6-11.52-25.6-25.6-25.6z" fill="#ffffff" ></path></symbol><symbol id="icon-xiaoxi" viewBox="0 0 1024 1024"><path d="M621.6 761.4c0 50.5-43 89.8-96.6 89.8s-96.6-39.3-96.6-89.8h193.2m-32.2-523.9c0-33.7-27.9-59.9-64.4-59.9s-64.4 26.2-64.4 59.9v9.3c-88 28.1-161 117.8-161 222.7v82.3s0 117.8-32.2 119.7c-19.3 0-32.2 13.1-32.2 29.9 0 16.9 15 29.9 32.2 29.9h515.3c17.2 0 32.2-13.1 32.2-29.9 0-16.9-15-29.9-32.2-29.9-32.2 0-32.2-119.7-32.2-119.7v-82.3c0-104.7-68.7-192.7-161-222.7v-9.3" fill="#ffffff" ></path></symbol><symbol id="icon-mima" viewBox="0 0 1024 1024"><path d="M760.171097 415.494703 346.927843 415.494703l0-67.441135c0-91.90006 74.809514-166.709574 166.811913-166.709574 92.002399 0 166.811913 74.911853 166.811913 166.914251 0 12.485309 10.029182 22.514491 22.514491 22.514491s22.514491-10.029182 22.514491-22.514491c0-116.870678-95.072556-211.943234-211.840895-211.943234-56.593244 0-109.809314 22.002798-149.823706 62.01719-40.014391 40.014391-62.01719 93.128123-62.01719 149.721367L301.898861 415.494703l-47.485109 0c-27.631421 0-49.736558 22.105137-49.736558 49.634219l0 341.913252c0 27.631421 22.207476 50.452928 49.736558 50.452928l505.655007 0c27.631421 0 50.35059-22.821507 50.35059-50.452928L810.419348 465.128923C810.521687 437.59984 787.802518 415.494703 760.171097 415.494703zM765.492704 807.553868c0 2.763142-2.251449 5.014591-5.014591 5.014591L254.720768 812.568459c-2.763142 0-5.014591-2.251449-5.014591-5.014591L249.706176 465.538277c0-2.763142 2.251449-5.014591 5.014591-5.014591l505.655007 0c2.763142 0 5.014591 2.251449 5.014591 5.014591L765.390366 807.553868zM503.505896 532.160704c-25.482311 0-46.052369 20.570058-46.052369 46.052369 0 16.78353 9.005797 31.520288 22.514491 39.605037L479.968019 707.159704c0 12.38297 10.131521 22.514491 22.514491 22.514491s22.514491-10.131521 22.514491-22.514491l0-88.21587c14.634419-7.675395 24.561263-23.026184 24.561263-40.730762C549.558265 552.730762 528.988207 532.160704 503.505896 532.160704z" fill="#666666" ></path></symbol><symbol id="icon-zhanghao" viewBox="0 0 1024 1024"><path d="M828.1 722.4c-17.3-40.9-42-77.5-73.5-109s-68.2-56.2-109.1-73.5c-10.2-4.3-20.6-8.1-31-11.4 54.5-34.7 90.8-95.7 90.8-164.9 0-107.7-87.6-195.4-195.4-195.4-107.7 0-195.4 87.6-195.4 195.4 0 69.9 36.9 131.3 92.2 165.8-9.6 3.1-19 6.6-28.3 10.5-40.9 17.3-77.5 42-109 73.5s-56.2 68.2-73.5 109c-17.9 42.3-27 87.2-27 133.6h46c0-163.8 133.3-297.1 297.1-297.1S809.1 692.2 809.1 856h46c0-46.4-9.1-91.3-27-133.6zM360.6 363.5c0-82.4 67-149.4 149.4-149.4s149.4 67 149.4 149.4-67 149.4-149.4 149.4c-82.4-0.1-149.4-67.1-149.4-149.4z" fill="#666666" ></path></symbol></svg>',n=(n=document.getElementsByTagName("script"))[n.length-1].getAttribute("data-injectcss");if(n&&!c.__iconfont__svg__cssinject__){c.__iconfont__svg__cssinject__=!0;try{document.write("<style>.svgfont {display: inline-block;width: 1em;height: 1em;fill: currentColor;vertical-align: -0.1em;font-size:16px;}</style>")}catch(c){console&&console.log(c)}}function s(){f||(f=!0,a())}t=function(){var c,t,e,a;(a=document.createElement("div")).innerHTML=o,o=null,(e=a.getElementsByTagName("svg")[0])&&(e.setAttribute("aria-hidden","true"),e.style.position="absolute",e.style.width=0,e.style.height=0,e.style.overflow="hidden",c=e,(t=document.body).firstChild?(a=c,(e=t.firstChild).parentNode.insertBefore(a,e)):t.appendChild(c))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(t,0):(e=function(){document.removeEventListener("DOMContentLoaded",e,!1),t()},document.addEventListener("DOMContentLoaded",e,!1)):document.attachEvent&&(a=t,i=c.document,f=!1,(l=function(){try{i.documentElement.doScroll("left")}catch(c){return void setTimeout(l,50)}s()})(),i.onreadystatechange=function(){"complete"==i.readyState&&(i.onreadystatechange=null,s())})}(window);
\ No newline at end of file
diff --git "a/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/assets/font/iconfont.json" "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/assets/font/iconfont.json"
new file mode 100644
index 0000000..b4cebe7
--- /dev/null
+++ "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/assets/font/iconfont.json"
@@ -0,0 +1,65 @@
+{
+  "id": "2399544",
+  "name": "vp",
+  "font_family": "iconfont",
+  "css_prefix_text": "icon-",
+  "description": "",
+  "glyphs": [
+    {
+      "icon_id": "5920503",
+      "name": "鐢ㄦ埛",
+      "font_class": "dashujukeshihuaico-",
+      "unicode": "e7ff",
+      "unicode_decimal": 59391
+    },
+    {
+      "icon_id": "14720218",
+      "name": "鍏抽棴",
+      "font_class": "guanxi",
+      "unicode": "e616",
+      "unicode_decimal": 58902
+    },
+    {
+      "icon_id": "19984626",
+      "name": "浜鸿劯璇嗗埆",
+      "font_class": "renlianshibie1",
+      "unicode": "e78d",
+      "unicode_decimal": 59277
+    },
+    {
+      "icon_id": "14843450",
+      "name": "閫�鍑�",
+      "font_class": "tuichu",
+      "unicode": "e60d",
+      "unicode_decimal": 58893
+    },
+    {
+      "icon_id": "16386636",
+      "name": "娑堟伅",
+      "font_class": "biaoqiankuozhan_xiaoxi-157",
+      "unicode": "eb15",
+      "unicode_decimal": 60181
+    },
+    {
+      "icon_id": "15954693",
+      "name": "娑堟伅",
+      "font_class": "xiaoxi",
+      "unicode": "e612",
+      "unicode_decimal": 58898
+    },
+    {
+      "icon_id": "1111451",
+      "name": "瀵嗙爜",
+      "font_class": "mima",
+      "unicode": "e644",
+      "unicode_decimal": 58948
+    },
+    {
+      "icon_id": "3851393",
+      "name": "璐﹀彿",
+      "font_class": "zhanghao",
+      "unicode": "666",
+      "unicode_decimal": 1638
+    }
+  ]
+}
diff --git "a/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/assets/font/iconfont.svg" "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/assets/font/iconfont.svg"
new file mode 100644
index 0000000..bffcfdb
--- /dev/null
+++ "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/assets/font/iconfont.svg"
@@ -0,0 +1,50 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
+<!--
+2013-9-30: Created.
+-->
+<svg>
+<metadata>
+Created by iconfont
+</metadata>
+<defs>
+
+<font id="iconfont" horiz-adv-x="1024" >
+  <font-face
+    font-family="iconfont"
+    font-weight="500"
+    font-stretch="normal"
+    units-per-em="1024"
+    ascent="896"
+    descent="-128"
+  />
+    <missing-glyph />
+    
+    <glyph glyph-name="dashujukeshihuaico-" unicode="&#59391;" d="M611.413333 379.30666699999995a231.253333 231.253333 0 1 1-199.253333 0 441.173333 441.173333 0 0 1-341.333333-429.653334h882.773333a441.173333 441.173333 0 0 1-342.186667 429.653334zM611.413333 379.30666699999995a231.253333 231.253333 0 1 1-199.253333 0 441.173333 441.173333 0 0 1-341.333333-429.653334h882.773333a441.173333 441.173333 0 0 1-342.186667 429.653334zM611.413333 379.30666699999995a231.253333 231.253333 0 1 1-199.253333 0 441.173333 441.173333 0 0 1-341.333333-429.653334h882.773333a441.173333 441.173333 0 0 1-342.186667 429.653334zM953.6-50.346667000000025a441.173333 441.173333 0 0 1-341.333333 429.653334 229.546667 229.546667 0 0 1 11.093333 409.173333 228.693333 228.693333 0 0 1-32 3.413333 230.4 230.4 0 0 1-99.413333-438.613333 440.32 440.32 0 0 1-341.333334-403.2zM653.653333 561.066667a230.4 230.4 0 0 0-131.413333-207.786667 441.173333 441.173333 0 0 0 341.333333-403.2h90.453334a441.173333 441.173333 0 0 1-341.333334 429.653333 229.546667 229.546667 0 0 1 11.093334 409.173334 228.266667 228.266667 0 0 1-32 3.413333 229.973333 229.973333 0 0 1-85.333334-15.786667 230.826667 230.826667 0 0 0 147.2-215.466666zM104.96 689.92A135.68 135.68 0 0 1 31.146667 764.16a9.813333 9.813333 0 0 0 0 18.346667A135.68 135.68 0 0 1 104.96 856.746667a9.813333 9.813333 0 0 0 18.346667 0 135.68 135.68 0 0 1 74.24-74.24 9.813333 9.813333 0 0 0 0-18.346667 135.68 135.68 0 0 1-74.24-74.24 9.813333 9.813333 0 0 0-18.346667 0zM905.813333 480a69.546667 69.546667 0 0 1-37.973333 37.973333 5.12 5.12 0 0 0 0 9.386667 69.546667 69.546667 0 0 1 37.973333 37.973333 5.12 5.12 0 0 0 9.386667 0 69.546667 69.546667 0 0 1 37.973333-37.973333 5.12 5.12 0 0 0 0-9.386667 69.546667 69.546667 0 0 1-37.973333-37.973333 5.12 5.12 0 0 0-9.386667 0zM42.666667 224a69.546667 69.546667 0 0 1-37.973334 37.973333 5.12 5.12 0 0 0 0 9.386667 69.546667 69.546667 0 0 1 37.973334 38.4 5.12 5.12 0 0 0 9.386666 0 69.546667 69.546667 0 0 1 37.973334-37.973333 5.12 5.12 0 0 0 0-9.386667 69.546667 69.546667 0 0 1-37.973334-37.973333 5.12 5.12 0 0 0-9.386666-0.426667z"  horiz-adv-x="1024" />
+
+    
+    <glyph glyph-name="guanxi" unicode="&#58902;" d="M683.008 206.336c-4.608 0-9.216 2.048-13.312 5.632L336.384 545.28c-7.168 7.168-7.168 18.944 0 26.112 7.168 7.168 18.944 7.168 26.112 0l333.824-333.824c7.168-7.168 7.168-18.944 0-26.112-3.584-3.584-8.704-5.12-13.312-5.12zM337.408 218.11199999999997c-4.608 0-9.216 2.048-13.312 5.632-7.168 7.168-7.168 18.944 0 26.112L657.92 583.6800000000001c7.168 7.168 18.944 7.168 26.112 0 7.168-7.168 7.168-18.944 0-26.112l-333.824-333.824c-3.584-4.096-8.192-5.632-12.8-5.632z"  horiz-adv-x="1024" />
+
+    
+    <glyph glyph-name="renlianshibie1" unicode="&#59277;" d="M298.666667 0H149.333333c-12.8 0-21.333333 8.533333-21.333333 21.333333V170.66666699999996c0 25.6-17.066667 42.666667-42.666667 42.666666s-42.666667-17.066667-42.666666-42.666666v-149.333334C42.666667-38.39999999999998 89.6-85.33333300000004 149.333333-85.33333300000004H298.666667c25.6 0 42.666667 17.066667 42.666666 42.666666s-17.066667 42.666667-42.666666 42.666667zM938.666667 213.33333300000004c-25.6 0-42.666667-17.066667-42.666667-42.666666v-149.333334c0-12.8-8.533333-21.333333-21.333333-21.333333H725.333333c-25.6 0-42.666667-17.066667-42.666666-42.666667s17.066667-42.666667 42.666666-42.666666h149.333334c59.733333 0 106.666667 46.933333 106.666666 106.666666V170.66666699999996c0 25.6-17.066667 42.666667-42.666666 42.666666zM874.666667 853.333333H725.333333c-25.6 0-42.666667-17.066667-42.666666-42.666666s17.066667-42.666667 42.666666-42.666667h149.333334c12.8 0 21.333333-8.533333 21.333333-21.333333V597.333333c0-25.6 17.066667-42.666667 42.666667-42.666666s42.666667 17.066667 42.666666 42.666666V746.666667C981.333333 806.4 934.4 853.333333 874.666667 853.333333zM85.333333 554.666667c25.6 0 42.666667 17.066667 42.666667 42.666666V746.666667c0 12.8 8.533333 21.333333 21.333333 21.333333H298.666667c25.6 0 42.666667 17.066667 42.666666 42.666667s-17.066667 42.666667-42.666666 42.666666H149.333333C89.6 853.333333 42.666667 806.4 42.666667 746.666667V597.333333c0-25.6 17.066667-42.666667 42.666666-42.666666zM721.066667 234.66666699999996c12.8 21.333333 4.266667 46.933333-17.066667 59.733333-21.333333 12.8-46.933333 4.266667-59.733333-17.066667 0 0-38.4-64-132.266667-64s-132.266667 59.733333-132.266667 64c-12.8 21.333333-38.4 25.6-59.733333 17.066667-21.333333-12.8-25.6-38.4-17.066667-59.733333 4.266667-4.266667 64-106.666667 209.066667-106.666667s204.8 102.4 209.066667 106.666667zM512 384c25.6 0 42.666667 17.066667 42.666667 42.666667V597.333333c0 25.6-17.066667 42.666667-42.666667 42.666667s-42.666667-17.066667-42.666667-42.666667v-170.666666c0-25.6 17.066667-42.666667 42.666667-42.666667zM725.333333 512c25.6 0 42.666667 17.066667 42.666667 42.666667V597.333333c0 25.6-17.066667 42.666667-42.666667 42.666667s-42.666667-17.066667-42.666666-42.666667v-42.666666c0-25.6 17.066667-42.666667 42.666666-42.666667zM298.666667 640c-25.6 0-42.666667-17.066667-42.666667-42.666667v-42.666666c0-25.6 17.066667-42.666667 42.666667-42.666667s42.666667 17.066667 42.666666 42.666667V597.333333c0 25.6-17.066667 42.666667-42.666666 42.666667z"  horiz-adv-x="1024" />
+
+    
+    <glyph glyph-name="tuichu" unicode="&#58893;" d="M511.924148-127.92414799999995a470.660741 470.660741 0 0 0-184.395852 37.167407 471.115852 471.115852 0 0 0-150.679703 101.376A471.87437 471.87437 0 0 0 236.468148 729.618963a37.091556 37.091556 0 1 0 43.159704-59.998815 404.745481 404.745481 0 0 1-121.742222-139.339852 392.305778 392.305778 0 0 1-45.700741-185.078518c0-106.571852 41.604741-206.810074 117.077333-282.206815a397.349926 397.349926 0 0 1 282.661926-117.001482c106.68563 0 207.151407 41.528889 282.737778 117.001482a396.09837 396.09837 0 0 1 117.039407 282.244741c0.227556 64.474074-15.435852 128.037926-45.662814 185.040592a404.366222 404.366222 0 0 1-121.742223 139.188148 36.939852 36.939852 0 1 0 43.159704 60.074667 471.798519 471.798519 0 0 0 59.58163-719.075555A472.936296 472.936296 0 0 0 511.924148-128v0.075852z m11.150222 513.403259a37.015704 37.015704 0 0 0-37.091555 36.939852V860.615111a37.129481 37.129481 0 0 0 74.221037 0v-438.196148a36.939852 36.939852 0 0 0-37.167408-36.939852z"  horiz-adv-x="1024" />
+
+    
+    <glyph glyph-name="biaoqiankuozhan_xiaoxi-157" unicode="&#60181;" d="M393.7792 19.865599999999972c-7.3728 0-14.848 1.6384-21.8624 5.0176-17.7664 8.4992-28.8256 26.0096-28.7744 45.6704l0.1536 59.4944c0 3.4304-1.7408 5.7344-2.7648 6.7584-1.024 1.024-3.328 2.816-6.7584 2.816H172.1344c-27.8528 0-50.4832 22.6304-50.4832 50.4832v436.736c0 27.8528 22.6304 50.4832 50.4832 50.4832h665.6c27.8528 0 50.4832-22.6304 50.4832-50.4832v-436.736c0-27.8528-22.6304-50.4832-50.4832-50.4832h-275.712c-2.2016 0-4.3008-0.768-6.0416-2.1504L425.472 31.283199999999965a49.9968 49.9968 0 0 0-31.6928-11.4176zM172.1344 636.4159999999999c-5.2736 0-9.5232-4.3008-9.5232-9.5232v-436.736c0-5.2736 4.2496-9.5232 9.5232-9.5232h161.5872c13.5168 0 26.2144-5.2736 35.7376-14.848a50.176 50.176 0 0 0 14.7456-35.7888l-0.1536-59.4944c0-5.4272 3.7888-7.8336 5.4272-8.6528 1.6384-0.768 5.888-2.2528 10.1376 1.2288l130.5088 106.1888a50.43712 50.43712 0 0 0 31.8464 11.3152h275.712c5.2736 0 9.5232 4.2496 9.5232 9.5232v436.736c0 5.2736-4.3008 9.5232-9.5232 9.5232H172.1344z m525.056-295.4752c-36.7104 0-66.56 29.8496-66.56 66.56s29.8496 66.56 66.56 66.56 66.56-29.8496 66.56-66.56-29.8496-66.56-66.56-66.56z m0 92.16c-14.1312 0-25.6-11.4688-25.6-25.6s11.4688-25.6 25.6-25.6 25.6 11.4688 25.6 25.6-11.52 25.6-25.6 25.6z m-195.0208-92.16c-36.7104 0-66.56 29.8496-66.56 66.56s29.8496 66.56 66.56 66.56 66.56-29.8496 66.56-66.56-29.8496-66.56-66.56-66.56z m0 92.16c-14.1312 0-25.6-11.4688-25.6-25.6s11.4688-25.6 25.6-25.6 25.6 11.4688 25.6 25.6-11.4688 25.6-25.6 25.6z m-194.9696-92.16c-36.7104 0-66.56 29.8496-66.56 66.56s29.8496 66.56 66.56 66.56 66.56-29.8496 66.56-66.56-29.9008-66.56-66.56-66.56z m0 92.16c-14.1312 0-25.6-11.4688-25.6-25.6s11.4688-25.6 25.6-25.6 25.6 11.4688 25.6 25.6-11.52 25.6-25.6 25.6z"  horiz-adv-x="1024" />
+
+    
+    <glyph glyph-name="xiaoxi" unicode="&#58898;" d="M621.6 134.60000000000002c0-50.5-43-89.8-96.6-89.8s-96.6 39.3-96.6 89.8h193.2m-32.2 523.9c0 33.7-27.9 59.9-64.4 59.9s-64.4-26.2-64.4-59.9v-9.3c-88-28.1-161-117.8-161-222.7v-82.3s0-117.8-32.2-119.7c-19.3 0-32.2-13.1-32.2-29.9 0-16.9 15-29.9 32.2-29.9h515.3c17.2 0 32.2 13.1 32.2 29.9 0 16.9-15 29.9-32.2 29.9-32.2 0-32.2 119.7-32.2 119.7v82.3c0 104.7-68.7 192.7-161 222.7v9.3"  horiz-adv-x="1024" />
+
+    
+    <glyph glyph-name="mima" unicode="&#58948;" d="M760.171097 480.505297L346.927843 480.505297l0 67.441135c0 91.90006 74.809514 166.709574 166.811913 166.709574 92.002399 0 166.811913-74.911853 166.811913-166.914251 0-12.485309 10.029182-22.514491 22.514491-22.514491s22.514491 10.029182 22.514491 22.514491c0 116.870678-95.072556 211.943234-211.840895 211.943234-56.593244 0-109.809314-22.002798-149.823706-62.01719-40.014391-40.014391-62.01719-93.128123-62.01719-149.721367L301.898861 480.505297l-47.485109 0c-27.631421 0-49.736558-22.105137-49.736558-49.634219l0-341.913252c0-27.631421 22.207476-50.452928 49.736558-50.452928l505.655007 0c27.631421 0 50.35059 22.821507 50.35059 50.452928L810.419348 430.871077C810.521687 458.40016 787.802518 480.505297 760.171097 480.505297zM765.492704 88.44613200000003c0-2.763142-2.251449-5.014591-5.014591-5.014591L254.720768 83.43154100000004c-2.763142 0-5.014591 2.251449-5.014591 5.014591L249.706176 430.461723c0 2.763142 2.251449 5.014591 5.014591 5.014591l505.655007 0c2.763142 0 5.014591-2.251449 5.014591-5.014591L765.390366 88.44613200000003zM503.505896 363.839296c-25.482311 0-46.052369-20.570058-46.052369-46.052369 0-16.78353 9.005797-31.520288 22.514491-39.605037L479.968019 188.84029599999997c0-12.38297 10.131521-22.514491 22.514491-22.514491s22.514491 10.131521 22.514491 22.514491l0 88.21587c14.634419 7.675395 24.561263 23.026184 24.561263 40.730762C549.558265 343.269238 528.988207 363.839296 503.505896 363.839296z"  horiz-adv-x="1024" />
+
+    
+    <glyph glyph-name="zhanghao" unicode="&#1638;" d="M828.1 173.60000000000002c-17.3 40.9-42 77.5-73.5 109s-68.2 56.2-109.1 73.5c-10.2 4.3-20.6 8.1-31 11.4 54.5 34.7 90.8 95.7 90.8 164.9 0 107.7-87.6 195.4-195.4 195.4-107.7 0-195.4-87.6-195.4-195.4 0-69.9 36.9-131.3 92.2-165.8-9.6-3.1-19-6.6-28.3-10.5-40.9-17.3-77.5-42-109-73.5s-56.2-68.2-73.5-109c-17.9-42.3-27-87.2-27-133.6h46c0 163.8 133.3 297.1 297.1 297.1S809.1 203.79999999999995 809.1 40h46c0 46.4-9.1 91.3-27 133.6zM360.6 532.5c0 82.4 67 149.4 149.4 149.4s149.4-67 149.4-149.4-67-149.4-149.4-149.4c-82.4 0.1-149.4 67.1-149.4 149.4z"  horiz-adv-x="1024" />
+
+    
+
+
+  </font>
+</defs></svg>
diff --git "a/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/assets/font/iconfont.ttf" "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/assets/font/iconfont.ttf"
new file mode 100644
index 0000000..be7f86b
--- /dev/null
+++ "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/assets/font/iconfont.ttf"
Binary files differ
diff --git "a/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/assets/font/iconfont.woff" "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/assets/font/iconfont.woff"
new file mode 100644
index 0000000..afc522d
--- /dev/null
+++ "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/assets/font/iconfont.woff"
Binary files differ
diff --git "a/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/assets/font/iconfont.woff2" "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/assets/font/iconfont.woff2"
new file mode 100644
index 0000000..ea39607
--- /dev/null
+++ "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/assets/font/iconfont.woff2"
Binary files differ
diff --git "a/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/assets/right.png" "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/assets/right.png"
new file mode 100644
index 0000000..8ae1d8e
--- /dev/null
+++ "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/assets/right.png"
Binary files differ
diff --git "a/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/assets/styles/theme.css" "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/assets/styles/theme.css"
new file mode 100644
index 0000000..56e807d
--- /dev/null
+++ "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/assets/styles/theme.css"
@@ -0,0 +1,307 @@
+/* 鐜颁唬鍖栧悗鍙扮鐞嗙郴缁熶富棰樻牱寮� */
+
+/* ========== 鑹插僵瑙勮寖 ========== */
+:root {
+  /* 涓昏壊璋� */
+  --primary-color: #1890ff;
+  --primary-light: #40a9ff;
+  --primary-dark: #096dd9;
+  
+  /* 杈呭姪鑹� */
+  --success-color: #52c41a;
+  --warning-color: #faad14;
+  --error-color: #ff4d4f;
+  --info-color: #1890ff;
+  
+  /* 涓�ц壊 */
+  --text-primary: #262626;
+  --text-secondary: #595959;
+  --text-disabled: #bfbfbf;
+  --text-white: #ffffff;
+  
+  /* 鑳屾櫙鑹� */
+  --bg-primary: #ffffff;
+  --bg-secondary: #fafafa;
+  --bg-tertiary: #f5f5f5;
+  --bg-dark: #001529;
+  --bg-sidebar: #001529;
+  --bg-header: #ffffff;
+  
+  /* 杈规鑹� */
+  --border-color: #d9d9d9;
+  --border-light: #f0f0f0;
+  --border-dark: #434343;
+  
+  /* 闃村奖 */
+  --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);
+  --shadow-md: 0 4px 6px rgba(0, 0, 0, 0.07), 0 1px 3px rgba(0, 0, 0, 0.06);
+  --shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.1), 0 4px 6px rgba(0, 0, 0, 0.05);
+  --shadow-xl: 0 20px 25px rgba(0, 0, 0, 0.1), 0 10px 10px rgba(0, 0, 0, 0.04);
+  
+  /* 鍦嗚 */
+  --radius-sm: 4px;
+  --radius-md: 6px;
+  --radius-lg: 8px;
+  --radius-xl: 12px;
+  
+  /* 闂磋窛 */
+  --spacing-xs: 4px;
+  --spacing-sm: 8px;
+  --spacing-md: 16px;
+  --spacing-lg: 24px;
+  --spacing-xl: 32px;
+  --spacing-xxl: 48px;
+}
+
+/* ========== 鍏ㄥ眬鏍峰紡閲嶇疆 ========== */
+* {
+  box-sizing: border-box;
+}
+
+body {
+  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', 'Helvetica Neue', Helvetica, Arial, sans-serif;
+  line-height: 1.5715;
+  color: var(--text-primary);
+  background-color: var(--bg-secondary);
+  margin: 0;
+  padding: 0;
+}
+
+/* ========== 鍗$墖鏍峰紡 ========== */
+.modern-card {
+  background: var(--bg-primary);
+  border-radius: var(--radius-lg);
+  box-shadow: var(--shadow-md);
+  border: 1px solid var(--border-light);
+  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+}
+
+.modern-card:hover {
+  box-shadow: var(--shadow-lg);
+  transform: translateY(-2px);
+}
+
+/* ========== 鎸夐挳鏍峰紡澧炲己 ========== */
+.modern-btn {
+  border-radius: var(--radius-md);
+  font-weight: 500;
+  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+  border: none;
+  cursor: pointer;
+  display: inline-flex;
+  align-items: center;
+  justify-content: center;
+  gap: var(--spacing-sm);
+}
+
+.modern-btn:hover {
+  transform: translateY(-1px);
+  box-shadow: var(--shadow-md);
+}
+
+.modern-btn-primary {
+  background: linear-gradient(135deg, var(--primary-color) 0%, var(--primary-light) 100%);
+  color: var(--text-white);
+}
+
+.modern-btn-primary:hover {
+  background: linear-gradient(135deg, var(--primary-dark) 0%, var(--primary-color) 100%);
+}
+
+.modern-btn-success {
+  background: linear-gradient(135deg, var(--success-color) 0%, #73d13d 100%);
+  color: var(--text-white);
+}
+
+.modern-btn-warning {
+  background: linear-gradient(135deg, var(--warning-color) 0%, #ffc53d 100%);
+  color: var(--text-white);
+}
+
+.modern-btn-danger {
+  background: linear-gradient(135deg, var(--error-color) 0%, #ff7875 100%);
+  color: var(--text-white);
+}
+
+/* ========== 琛ㄥ崟鏍峰紡澧炲己 ========== */
+.modern-form-item {
+  margin-bottom: var(--spacing-lg);
+}
+
+.modern-input {
+  border-radius: var(--radius-md);
+  border: 1px solid var(--border-color);
+  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+  padding: var(--spacing-sm) var(--spacing-md);
+}
+
+.modern-input:focus {
+  border-color: var(--primary-color);
+  box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
+  outline: none;
+}
+
+/* ========== 琛ㄦ牸鏍峰紡澧炲己 ========== */
+.modern-table {
+  background: var(--bg-primary);
+  border-radius: var(--radius-lg);
+  overflow: hidden;
+  box-shadow: var(--shadow-sm);
+}
+
+.modern-table .el-table__header {
+  background: var(--bg-tertiary);
+}
+
+.modern-table .el-table__header th {
+  background: var(--bg-tertiary);
+  color: var(--text-primary);
+  font-weight: 600;
+  border-bottom: 2px solid var(--border-light);
+}
+
+.modern-table .el-table__row:hover {
+  background: rgba(24, 144, 255, 0.04);
+}
+
+/* ========== 瀵艰埅鏍峰紡澧炲己 ========== */
+.modern-sidebar {
+  background: var(--bg-sidebar);
+  box-shadow: var(--shadow-lg);
+}
+
+.modern-sidebar .el-menu {
+  background: transparent;
+  border: none;
+}
+
+.modern-sidebar .el-menu-item {
+  color: rgba(255, 255, 255, 0.65);
+  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+  border-radius: var(--radius-md);
+  margin: var(--spacing-xs) var(--spacing-md);
+  width: calc(100% - 32px);
+}
+
+.modern-sidebar .el-menu-item:hover {
+  color: var(--text-white);
+  background: rgba(255, 255, 255, 0.1);
+  transform: translateX(4px);
+}
+
+.modern-sidebar .el-menu-item.is-active {
+  color: var(--text-white);
+  background: var(--primary-color);
+  box-shadow: var(--shadow-md);
+}
+
+.modern-header {
+  background: var(--bg-header);
+  box-shadow: var(--shadow-sm);
+  border-bottom: 1px solid var(--border-light);
+}
+
+/* ========== 鍔ㄧ敾鏁堟灉 ========== */
+@keyframes fadeInUp {
+  from {
+    opacity: 0;
+    transform: translateY(30px);
+  }
+  to {
+    opacity: 1;
+    transform: translateY(0);
+  }
+}
+
+@keyframes fadeInLeft {
+  from {
+    opacity: 0;
+    transform: translateX(-30px);
+  }
+  to {
+    opacity: 1;
+    transform: translateX(0);
+  }
+}
+
+@keyframes fadeInRight {
+  from {
+    opacity: 0;
+    transform: translateX(30px);
+  }
+  to {
+    opacity: 1;
+    transform: translateX(0);
+  }
+}
+
+.fade-in-up {
+  animation: fadeInUp 0.6s cubic-bezier(0.4, 0, 0.2, 1);
+}
+
+.fade-in-left {
+  animation: fadeInLeft 0.6s cubic-bezier(0.4, 0, 0.2, 1);
+}
+
+.fade-in-right {
+  animation: fadeInRight 0.6s cubic-bezier(0.4, 0, 0.2, 1);
+}
+
+/* ========== 宸ュ叿绫� ========== */
+.text-center { text-align: center; }
+.text-left { text-align: left; }
+.text-right { text-align: right; }
+
+.flex { display: flex; }
+.flex-center { display: flex; align-items: center; justify-content: center; }
+.flex-between { display: flex; align-items: center; justify-content: space-between; }
+.flex-column { display: flex; flex-direction: column; }
+
+.mt-sm { margin-top: var(--spacing-sm); }
+.mt-md { margin-top: var(--spacing-md); }
+.mt-lg { margin-top: var(--spacing-lg); }
+.mt-xl { margin-top: var(--spacing-xl); }
+
+.mb-sm { margin-bottom: var(--spacing-sm); }
+.mb-md { margin-bottom: var(--spacing-md); }
+.mb-lg { margin-bottom: var(--spacing-lg); }
+.mb-xl { margin-bottom: var(--spacing-xl); }
+
+.p-sm { padding: var(--spacing-sm); }
+.p-md { padding: var(--spacing-md); }
+.p-lg { padding: var(--spacing-lg); }
+.p-xl { padding: var(--spacing-xl); }
+
+/* ========== 鍝嶅簲寮忚璁� ========== */
+@media (max-width: 768px) {
+  :root {
+    --spacing-md: 12px;
+    --spacing-lg: 16px;
+    --spacing-xl: 24px;
+  }
+  
+  .modern-card {
+    margin: var(--spacing-md);
+    border-radius: var(--radius-md);
+  }
+}
+
+/* ========== 婊氬姩鏉℃牱寮� ========== */
+::-webkit-scrollbar {
+  width: 6px;
+  height: 6px;
+}
+
+::-webkit-scrollbar-track {
+  background: var(--bg-tertiary);
+  border-radius: var(--radius-sm);
+}
+
+::-webkit-scrollbar-thumb {
+  background: var(--border-color);
+  border-radius: var(--radius-sm);
+}
+
+::-webkit-scrollbar-thumb:hover {
+  background: var(--text-disabled);
+}
diff --git "a/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/components/table/pagination.vue" "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/components/table/pagination.vue"
new file mode 100644
index 0000000..767dccb
--- /dev/null
+++ "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/components/table/pagination.vue"
@@ -0,0 +1,56 @@
+<template>
+  <div class="pagination">
+    <el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="page.page" :page-sizes="pageSizes" :page-size="page.limit" layout="total, sizes, prev, pager, next, jumper" :total="total">
+    </el-pagination>
+  </div>
+</template>
+
+<script>
+export default {
+  props: {
+    total: {
+      type: Number,
+      default: () => { }
+    },
+    pageSizes: {
+      type: Array,
+      default: () => {
+        return [5, 10, 20, 100]
+      }
+    }
+  },
+  data () {
+    return {
+      page: {
+        page: 1,
+        limit: 20
+      }
+    }
+  },
+
+  methods: {
+    Page (val) {
+      this.page.page = val
+    },
+    handleSizeChange (val) {
+      this.page.limit = val
+      this.$emit('pageChange', this.page)
+    },
+    handleCurrentChange (val) {
+      this.page.page = val
+      this.$emit('pageChange', this.page)
+    }
+  }
+}
+</script>
+
+<style scoped lang="less">
+.pagination {
+  float: right;
+  padding: 1% 4% 2% 0px;
+}
+::v-deep .el-pagination .el-select .el-input {
+  width: 110px;
+}
+</style>
+
diff --git "a/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/components/table/tableList.vue" "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/components/table/tableList.vue"
new file mode 100644
index 0000000..4201f8d
--- /dev/null
+++ "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/components/table/tableList.vue"
@@ -0,0 +1,222 @@
+<template>
+  <!-- 涓诲垪琛� -->
+  <el-table :data='tableData' :height='tableHeight' :show-header='showHeader' stripe @expand-change="expandSelect"
+    :expand-row-keys="expands" @cell-click="handleCellClick" :empty-text="$t('common.noData')" class='el_tab_alage'
+    :header-cell-style="cellHeaderStyle" :row-key='getRowKeys' @selection-change="handleSelectionChange">
+    <!-- 鍗曢�夋 -->
+    <el-table-column align="center" width="50" label=""
+      v-if="tableSelection.key === true && tableSelection.type === 'radio'">
+      <template slot-scope="scope">
+        <el-radio :label="scope.$index" v-model="radio"
+          @change="handleTemplateRow(scope.$index, scope.row)">&nbsp;</el-radio>
+      </template>
+    </el-table-column>
+    <!-- index绱㈠紩 -->
+    <el-table-column label="搴忓彿" type="index" width="50" align="center"
+      v-if="tableSelection.key === true && tableSelection.type === 'index'"></el-table-column>
+    <!-- 澶氶�夋 -->
+    <el-table-column type="selection" width="50" align="center"
+      v-if="tableSelection.key === true && tableSelection.type === 'selection'"></el-table-column>
+    <!-- 鍒楄〃琛ㄥご-->
+    <el-table-column type="expand" v-if="tableSelection.key === true && tableSelection.type === 'expand'">
+      <template slot-scope="scope">
+        <el-form label-position="left" inline class="demo-table-expand">
+          <el-form-item :label="index.label" v-for="(index, item) in tableLabel" :key='item'
+            v-show="index.type === 'expand'">
+            <span>{{ scope.row[index.list] }}</span>
+          </el-form-item>
+        </el-form>
+      </template>
+    </el-table-column>
+    <template v-for="(index, item) in tableLabel">
+      <el-table-column fit :align='index.tableAlign ? index.tableAlign : "center"' :key='item' :sortable='index.sort'
+        v-if="index.type !== 'expand'" :label="index.label" :width="index.width"
+        :show-overflow-tooltip="index.overflowShow === 'hidden' ? true : false" :prop="index.list">
+        <template slot-scope="scope">
+          <!-- 鍥剧墖 -->
+          <template v-if="index.type === 'image'">
+            <el-image v-if="scope.row[index.list] !== ''" style="width: 100px; height: 50px;"
+              :src="scope.row[index.list]">
+            </el-image>
+            <div v-else></div>
+          </template>
+          <!-- 浜у搧鍥剧墖 -->
+          <template v-if="index.type === 'productImage'">
+            <el-image v-if="scope.row[index.list] !== ''" style="width: 100px; height: 50px;"
+              :src="getProductImageUrl(scope.row[index.list])">
+            </el-image>
+            <div v-else></div>
+          </template>
+          <!-- 澶村儚 -->
+          <template v-else-if="index.type === 'head'">
+            <el-image v-if="!(scope.row[index.list] === '' || scope.row[index.list] === null)"
+              style="width: 50px; height: 50px;" :src="scope.row[index.list]">
+            </el-image>
+            <div v-else></div>
+          </template>
+          <!-- 鎸夐挳 -->
+          <template v-else-if="index.type === 'btn'">
+            <el-button type="text" @click.native.prevent="index.method(scope.row, scope)">
+              <u>{{ scope.row[index.list] }}</u>
+            </el-button>
+          </template>
+          <!-- 涓嬫媺 -->
+          <template v-else-if="index.type === 'select'">
+            <el-select v-model="scope.row[index.list]" @change="changeType($event, scope.row, item)" size="medium">
+              <el-option v-for="item in index.options" :key="item.value" :label="item.label" :value="item.value">
+              </el-option>
+            </el-select>
+          </template>
+          <!-- 寮�鍏虫寜閽� -->
+          <template v-else-if="index.type === 'switch'">
+            <div v-if="index.noSwitch(scope.row)">
+              <el-switch @change="index.method(scope.row, scope)" v-model="scope.row[index.list]"
+                :inactive-value="index.offValue !== null ? index.offValue : 'off'"
+                :active-value="index.onValue ? index.onValue : 'on'" :inactive-text="index.offText ? index.offText : ''"
+                :active-text="index.onText ? index.onText : ''"
+                :inactive-color="index.offColor ? index.offColor : '#ff4949'"
+                :active-color="index.onColor ? index.onColor : '#13ce66'"></el-switch>
+            </div>
+          </template>
+          <!-- 鍐呭鑷畾涔� -->
+          <template v-else-if="index.type === 'html'">
+            <div v-html="index.code(scope.row)" class="theHtml"></div>
+          </template>
+          <!-- 姝e父鏄剧ず -->
+          <template v-else>
+            <!-- {{scope.row[index.list]}} -->
+            {{ scope.row[index.list] ? scope.row[index.list] : '-' }}
+          </template>
+        </template>
+      </el-table-column>
+    </template>
+    <!-- 姝e父鎸夐挳鎿嶄綔 -->
+    <el-table-column v-if="tableOption.value !== undefined" fit
+      :align='tableOption.align ? tableOption.align : "center"' :label="tableOption.label"
+      :fixed="tableOption.fixed ? tableOption.fixed : false" :width="tableOption.width">
+      <template style="margin-left: 30px;" slot-scope="scope">
+        <el-button v-for="(value, item) in filteredOptions(scope.row)" :key='item'
+          :disabled="value.disabled ? value.disabled(scope.row) : false" :type="value.type ? value.type : 'text'"
+          :style="value.style ? value.style : {}" :plain='value.plain ? value.plain : false'
+          :round='value.round ? value.round : false' :size='value.size ? value.size : "medium"' :icon="value.icon"
+          @click.native.prevent="value.method(scope.row, scope)">{{ value.label }}
+        </el-button>
+        <el-popover placement="top" trigger="hover"
+          v-if="tableOption.isShowMore ? tableOption.isShowMore(scope.row) : false">
+          <div class="popover-content">
+            <el-button class="popover-button" v-for="(value, item) in filteredPopoverOptions(scope.row)" :key='item'
+              :disabled="value.disabled ? value.disabled(scope.row) : false" :type="value.type ? value.type : 'info'"
+              :style="value.style ? value.style : {}" :size='value.size ? value.size : "mini"'
+              @click.native.prevent="value.method(scope.row, scope)">{{ value.label }}
+            </el-button>
+          </div>
+          <el-button slot="reference" type="text"
+            :style="tableOption.buttonStyle ? tableOption.buttonStyle : {}">{{ tableOption.buttonText }}</el-button>
+        </el-popover>
+      </template>
+    </el-table-column>
+  </el-table>
+</template>
+
+<script>
+export default {
+  data () {
+    return {
+      radio: '',
+      cellHeaderStyle: {
+        fontSize: "16px",
+        color: "#606266"
+      },
+      expands: [],
+      getRowKeys (row) {
+        return row.id
+      }
+    }
+  },
+  props: {
+    tableData: {
+      type: Array,
+      default: () => { }
+    },
+    tableHeight: {
+      type: Number,
+      default: () => {
+        return null
+      }
+    },
+    showHeader: {
+      type: Boolean,
+      default: () => {
+        return true
+      }
+    },
+    tableSelection: {
+      type: Object,
+      default: () => {
+        return {
+          key: false,
+          type: '',
+          detaile: false
+        }
+      }
+    },
+    tableLabel: {
+      type: Array,
+      default: () => { }
+    },
+    tableOption: {
+      type: Object,
+      default: () => {
+        return {
+          value: undefined
+        }
+      }
+    }
+  },
+
+  methods: {
+    handleSelectionChange (val) {
+      this.$emit('onHandleSelectionChange', val)
+    },
+    handleTemplateRow (index, row) {
+      this.$emit('onHandleTemplateRow', row)
+    },
+    changeType (event, row) {
+      this.$emit('onChangeType', event, row)
+    },
+    expandSelect (row, expandedRows) {
+      const that = this
+      if (expandedRows.length) {
+        that.expands = []
+        if (row) {
+          that.expands.push(row.id)
+        }
+      } else {
+        that.expands = []
+      }
+    },
+    handleCellClick (row, column) {
+      this.$emit('onHandleCellClick', row, column)
+    },
+    getProductImageUrl (id) {
+      return process.env.VUE_APP_BASE_API + 'saas/sysadmin/product/download/id?id=' + id
+    },
+    
+    // 鉁� 鏂板锛氳繃婊ら�夐」鐨勬柟娉�
+    filteredOptions(row) {
+      if (!this.tableOption.options) return [];
+      return this.tableOption.options.filter(value => {
+        return value.show ? value.show(row) : true;
+      });
+    },
+    
+    // 鉁� 鏂板锛氳繃婊ゅ脊鍑烘閫夐」鐨勬柟娉�
+    filteredPopoverOptions(row) {
+      if (!this.tableOption.popoverOptions) return [];
+      return this.tableOption.popoverOptions.filter(value => {
+        return value.show ? value.show(row) : true;
+      });
+    }
+  }
+}
+</script>
\ No newline at end of file
diff --git "a/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/directives/model-permission.js" "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/directives/model-permission.js"
new file mode 100644
index 0000000..8709bba
--- /dev/null
+++ "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/directives/model-permission.js"
@@ -0,0 +1,44 @@
+// src/directives/model-permission.js
+
+export default {
+  inserted(el, binding) {
+    // 浠巗essionStorage鑾峰彇璁惧鍨嬪彿
+    let publicConfig = sessionStorage.getItem('publicConfig')
+    let { model } = publicConfig ? JSON.parse(publicConfig) : {}
+    const { value } = binding
+    
+    if (!value) return // 娌℃湁閰嶇疆鏉冮檺锛岄粯璁ゆ樉绀�
+    
+    if (Array.isArray(value)) {
+      // 鍏佽鐨勫瀷鍙峰垪琛�
+      if (!value.includes(model)) {
+        el.parentNode?.removeChild(el)
+      }
+    } else if (typeof value === 'string') {
+      // 鍗曚釜鍏佽鐨勫瀷鍙�
+      if (model !== value) {
+        el.parentNode?.removeChild(el)
+      }
+    } else if (typeof value === 'object') {
+      // 澶嶆潅閰嶇疆锛歿 allow: [], deny: [] }
+      const { allow, deny } = value
+      
+      if (allow && !allow.includes(model)) {
+        el.parentNode?.removeChild(el)
+      }
+      if (deny && deny.includes(model)) {
+        el.parentNode?.removeChild(el)
+      }
+    }
+  },
+  
+  // update(el, binding) {
+  //   const { value, oldValue } = binding
+    
+  //   if (value !== oldValue) {
+  //     const elClone = el.cloneNode(true)
+  //     el.parentNode?.replaceChild(elClone, el)
+  //     this.inserted(elClone, binding)
+  //   }
+  // }
+}
\ No newline at end of file
diff --git "a/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/excel/Blob.js" "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/excel/Blob.js"
new file mode 100644
index 0000000..26382cc
--- /dev/null
+++ "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/excel/Blob.js"
@@ -0,0 +1,179 @@
+/* eslint-disable */
+/* Blob.js
+ * A Blob implementation.
+ * 2014-05-27
+ *
+ * By Eli Grey, http://eligrey.com
+ * By Devin Samarin, https://github.com/eboyjr
+ * License: X11/MIT
+ *   See LICENSE.md
+ */
+
+/*global self, unescape */
+/*jslint bitwise: true, regexp: true, confusion: true, es5: true, vars: true, white: true,
+ plusplus: true */
+
+/*! @source http://purl.eligrey.com/github/Blob.js/blob/master/Blob.js */
+
+(function (view) {
+    "use strict";
+
+    view.URL = view.URL || view.webkitURL;
+
+    if (view.Blob && view.URL) {
+        try {
+            new Blob;
+            return;
+        } catch (e) {}
+    }
+
+    // Internally we use a BlobBuilder implementation to base Blob off of
+    // in order to support older browsers that only have BlobBuilder
+    var BlobBuilder = view.BlobBuilder || view.WebKitBlobBuilder || view.MozBlobBuilder || (function(view) {
+            var
+                get_class = function(object) {
+                    return Object.prototype.toString.call(object).match(/^\[object\s(.*)\]$/)[1];
+                }
+                , FakeBlobBuilder = function BlobBuilder() {
+                    this.data = [];
+                }
+                , FakeBlob = function Blob(data, type, encoding) {
+                    this.data = data;
+                    this.size = data.length;
+                    this.type = type;
+                    this.encoding = encoding;
+                }
+                , FBB_proto = FakeBlobBuilder.prototype
+                , FB_proto = FakeBlob.prototype
+                , FileReaderSync = view.FileReaderSync
+                , FileException = function(type) {
+                    this.code = this[this.name = type];
+                }
+                , file_ex_codes = (
+                    "NOT_FOUND_ERR SECURITY_ERR ABORT_ERR NOT_READABLE_ERR ENCODING_ERR "
+                    + "NO_MODIFICATION_ALLOWED_ERR INVALID_STATE_ERR SYNTAX_ERR"
+                ).split(" ")
+                , file_ex_code = file_ex_codes.length
+                , real_URL = view.URL || view.webkitURL || view
+                , real_create_object_URL = real_URL.createObjectURL
+                , real_revoke_object_URL = real_URL.revokeObjectURL
+                , URL = real_URL
+                , btoa = view.btoa
+                , atob = view.atob
+
+                , ArrayBuffer = view.ArrayBuffer
+                , Uint8Array = view.Uint8Array
+                ;
+            FakeBlob.fake = FB_proto.fake = true;
+            while (file_ex_code--) {
+                FileException.prototype[file_ex_codes[file_ex_code]] = file_ex_code + 1;
+            }
+            if (!real_URL.createObjectURL) {
+                URL = view.URL = {};
+            }
+            URL.createObjectURL = function(blob) {
+                var
+                    type = blob.type
+                    , data_URI_header
+                    ;
+                if (type === null) {
+                    type = "application/octet-stream";
+                }
+                if (blob instanceof FakeBlob) {
+                    data_URI_header = "data:" + type;
+                    if (blob.encoding === "base64") {
+                        return data_URI_header + ";base64," + blob.data;
+                    } else if (blob.encoding === "URI") {
+                        return data_URI_header + "," + decodeURIComponent(blob.data);
+                    } if (btoa) {
+                        return data_URI_header + ";base64," + btoa(blob.data);
+                    } else {
+                        return data_URI_header + "," + encodeURIComponent(blob.data);
+                    }
+                } else if (real_create_object_URL) {
+                    return real_create_object_URL.call(real_URL, blob);
+                }
+            };
+            URL.revokeObjectURL = function(object_URL) {
+                if (object_URL.substring(0, 5) !== "data:" && real_revoke_object_URL) {
+                    real_revoke_object_URL.call(real_URL, object_URL);
+                }
+            };
+            FBB_proto.append = function(data/*, endings*/) {
+                var bb = this.data;
+                // decode data to a binary string
+                if (Uint8Array && (data instanceof ArrayBuffer || data instanceof Uint8Array)) {
+                    var
+                        str = ""
+                        , buf = new Uint8Array(data)
+                        , i = 0
+                        , buf_len = buf.length
+                        ;
+                    for (; i < buf_len; i++) {
+                        str += String.fromCharCode(buf[i]);
+                    }
+                    bb.push(str);
+                } else if (get_class(data) === "Blob" || get_class(data) === "File") {
+                    if (FileReaderSync) {
+                        var fr = new FileReaderSync;
+                        bb.push(fr.readAsBinaryString(data));
+                    } else {
+                        // async FileReader won't work as BlobBuilder is sync
+                        throw new FileException("NOT_READABLE_ERR");
+                    }
+                } else if (data instanceof FakeBlob) {
+                    if (data.encoding === "base64" && atob) {
+                        bb.push(atob(data.data));
+                    } else if (data.encoding === "URI") {
+                        bb.push(decodeURIComponent(data.data));
+                    } else if (data.encoding === "raw") {
+                        bb.push(data.data);
+                    }
+                } else {
+                    if (typeof data !== "string") {
+                        data += ""; // convert unsupported types to strings
+                    }
+                    // decode UTF-16 to binary string
+                    bb.push(unescape(encodeURIComponent(data)));
+                }
+            };
+            FBB_proto.getBlob = function(type) {
+                if (!arguments.length) {
+                    type = null;
+                }
+                return new FakeBlob(this.data.join(""), type, "raw");
+            };
+            FBB_proto.toString = function() {
+                return "[object BlobBuilder]";
+            };
+            FB_proto.slice = function(start, end, type) {
+                var args = arguments.length;
+                if (args < 3) {
+                    type = null;
+                }
+                return new FakeBlob(
+                    this.data.slice(start, args > 1 ? end : this.data.length)
+                    , type
+                    , this.encoding
+                );
+            };
+            FB_proto.toString = function() {
+                return "[object Blob]";
+            };
+            FB_proto.close = function() {
+                this.size = this.data.length = 0;
+            };
+            return FakeBlobBuilder;
+        }(view));
+
+    view.Blob = function Blob(blobParts, options) {
+        var type = options ? (options.type || "") : "";
+        var builder = new BlobBuilder();
+        if (blobParts) {
+            for (var i = 0, len = blobParts.length; i < len; i++) {
+                builder.append(blobParts[i]);
+            }
+        }
+        return builder.getBlob(type);
+    };
+}(typeof self !== "undefined" && self || typeof window !== "undefined" && window || this.content || this));
diff --git "a/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/excel/Export2Excel.js" "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/excel/Export2Excel.js"
new file mode 100644
index 0000000..e62bfef
--- /dev/null
+++ "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/excel/Export2Excel.js"
@@ -0,0 +1,142 @@
+/* eslint-disable */
+require('script-loader!file-saver');
+require('./Blob');
+require('script-loader!xlsx/dist/xlsx.core.min');
+function generateArray(table) {
+    var out = [];
+    var rows = table.querySelectorAll('tr');
+    var ranges = [];
+    for (var R = 0; R < rows.length; ++R) {
+        var outRow = [];
+        var row = rows[R];
+        var columns = row.querySelectorAll('td');
+        for (var C = 0; C < columns.length; ++C) {
+            var cell = columns[C];
+            var colspan = cell.getAttribute('colspan');
+            var rowspan = cell.getAttribute('rowspan');
+            var cellValue = cell.innerText;
+            if (cellValue !== "" && cellValue == +cellValue) cellValue = +cellValue;
+
+            //Skip ranges
+            ranges.forEach(function (range) {
+                if (R >= range.s.r && R <= range.e.r && outRow.length >= range.s.c && outRow.length <= range.e.c) {
+                    for (var i = 0; i <= range.e.c - range.s.c; ++i) outRow.push(null);
+                }
+            });
+
+            //Handle Row Span
+            if (rowspan || colspan) {
+                rowspan = rowspan || 1;
+                colspan = colspan || 1;
+                ranges.push({s: {r: R, c: outRow.length}, e: {r: R + rowspan - 1, c: outRow.length + colspan - 1}});
+            }
+            ;
+
+            //Handle Value
+            outRow.push(cellValue !== "" ? cellValue : null);
+
+            //Handle Colspan
+            if (colspan) for (var k = 0; k < colspan - 1; ++k) outRow.push(null);
+        }
+        out.push(outRow);
+    }
+    return [out, ranges];
+};
+
+function datenum(v, date1904) {
+    if (date1904) v += 1462;
+    var epoch = Date.parse(v);
+    return (epoch - new Date(Date.UTC(1899, 11, 30))) / (24 * 60 * 60 * 1000);
+}
+
+function sheet_from_array_of_arrays(data, opts) {
+    var ws = {};
+    var range = {s: {c: 10000000, r: 10000000}, e: {c: 0, r: 0}};
+    for (var R = 0; R != data.length; ++R) {
+        for (var C = 0; C != data[R].length; ++C) {
+            if (range.s.r > R) range.s.r = R;
+            if (range.s.c > C) range.s.c = C;
+            if (range.e.r < R) range.e.r = R;
+            if (range.e.c < C) range.e.c = C;
+            var cell = {v: data[R][C]};
+            if (cell.v == null) continue;
+            var cell_ref = XLSX.utils.encode_cell({c: C, r: R});
+
+            if (typeof cell.v === 'number') cell.t = 'n';
+            else if (typeof cell.v === 'boolean') cell.t = 'b';
+            else if (cell.v instanceof Date) {
+                cell.t = 'n';
+                cell.z = XLSX.SSF._table[14];
+                cell.v = datenum(cell.v);
+            }
+            else cell.t = 's';
+
+            ws[cell_ref] = cell;
+        }
+    }
+    if (range.s.c < 10000000) ws['!ref'] = XLSX.utils.encode_range(range);
+    return ws;
+}
+
+function Workbook() {
+    if (!(this instanceof Workbook)) return new Workbook();
+    this.SheetNames = [];
+    this.Sheets = {};
+}
+
+function s2ab(s) {
+    var buf = new ArrayBuffer(s.length);
+    var view = new Uint8Array(buf);
+    for (var i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF;
+    return buf;
+}
+
+export function export_table_to_excel(id) {
+    var theTable = document.getElementById(id);
+    console.log('a')
+    var oo = generateArray(theTable);
+    var ranges = oo[1];
+
+    /* original data */
+    var data = oo[0];
+    var ws_name = "SheetJS";
+    console.log(data);
+
+    var wb = new Workbook(), ws = sheet_from_array_of_arrays(data);
+
+    /* add ranges to worksheet */
+    // ws['!cols'] = ['apple', 'banan'];
+    ws['!merges'] = ranges;
+
+    /* add worksheet to workbook */
+    wb.SheetNames.push(ws_name);
+    wb.Sheets[ws_name] = ws;
+
+    var wbout = XLSX.write(wb, {bookType: 'xlsx', bookSST: false, type: 'binary'});
+
+    saveAs(new Blob([s2ab(wbout)], {type: "application/octet-stream"}), "test.xlsx")
+}
+
+function formatJson(jsonData) {
+    console.log(jsonData)
+}
+export function export_json_to_excel(th, jsonData, defaultTitle) {
+
+    /* original data */
+
+    var data = jsonData;
+    data.unshift(th);
+    var ws_name = "SheetJS";
+
+    var wb = new Workbook(), ws = sheet_from_array_of_arrays(data);
+
+
+    /* add worksheet to workbook */
+    wb.SheetNames.push(ws_name);
+    wb.Sheets[ws_name] = ws;
+
+    var wbout = XLSX.write(wb, {bookType: 'xlsx', bookSST: false, type: 'binary'});
+    var title = defaultTitle || '鍒楄〃'
+    saveAs(new Blob([s2ab(wbout)], {type: "application/octet-stream"}), title + ".xlsx")
+}
+export default class Export2Excel {}
\ No newline at end of file
diff --git "a/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/language/ar.js" "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/language/ar.js"
new file mode 100644
index 0000000..5dcc507
--- /dev/null
+++ "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/language/ar.js"
@@ -0,0 +1,432 @@
+export default {
+  // 鬲爻噩賷賱 丕賱丿禺賵賱
+  login: {
+    lang: '丕賱賱睾丞',
+    systemname: '丿禺賵賱',
+    username: '丕賱賲爻鬲禺丿賲',
+    username_label: '賷乇噩賶 廿丿禺丕賱 丕爻賲 丕賱賲爻鬲禺丿賲',
+    pwd: '賰賱賲丞 丕賱賲乇賵乇',
+    pwd_label: '賷乇噩賶 廿丿禺丕賱 賰賱賲丞 丕賱賲乇賵乇',
+    pwd_info: '兀丿禺賱 氐賷睾丞 賰賱賲丞 賲乇賵乇 氐丨賷丨丞',
+    success_msg: '鬲賲 鬲爻噩賷賱 丕賱丿禺賵賱 亘賳噩丕丨',
+    error_name: '賰賱賲丞 丕賱賲乇賵乇 睾賷乇 氐丨賷丨丞',
+    error_res: '賱丕 賷賱亘賷 賲鬲胤賱亘丕鬲 丕賱丿禺賵賱',
+    login: '鬲爻噩賷賱 丕賱丿禺賵賱',
+  },
+  // 丕賱卮乇賷胤 丕賱噩丕賳亘賷
+  aside: {
+    systemname: '賱賵丨丞',
+    quit: '鬲爻噩賷賱 丕賱禺乇賵噩',
+    deviceControl: '丕賱鬲丨賰賲',
+    basicSetting: '丕賱廿毓丿丕丿丕鬲',
+    workerSetting: '丕賱兀賮乇丕丿',
+    deviceMonitoring: '丕賱賲乇丕賯亘丞',
+    recordManagement: '丕賱爻噩賱丕鬲',
+    securityManagement: "廿丿丕乇丞 丕賱賲賮丕鬲賷丨",
+    tips: '鬲賳亘賷賴',
+    tips_msg: '賴賱 鬲乇賷丿 鬲爻噩賷賱 丕賱禺乇賵噩責',
+  },
+  control: {
+    remoteControl: '毓賳 亘毓丿',
+    restart: '廿毓丕丿丞 鬲卮睾賷賱',
+    clickToRestart: '丕囟睾胤 賱廿毓丕丿丞 丕賱鬲卮睾賷賱',
+    restartConfirm: '鬲兀賰賷丿 廿毓丕丿丞 丕賱鬲卮睾賷賱責',
+    restartSuccess: '鬲賲鬲 廿毓丕丿丞 丕賱鬲卮睾賷賱',
+    restartFailed: '賮卮賱鬲 廿毓丕丿丞 丕賱鬲卮睾賷賱',
+    remoteOpen: '賮鬲丨 丕賱亘丕亘 毓賳 亘毓丿',
+    clickToOpen: '丕囟睾胤 賱賱賮鬲丨',
+    openConfirm: '鬲兀賰賷丿 丕賱賮鬲丨 毓賳 亘毓丿責',
+    remoteOpenSuccess: '鬲賲 丕賱賮鬲丨 亘賳噩丕丨',
+    remoteOpenFailed: '賮卮賱 丕賱賮鬲丨',
+    reset: '廿毓丕丿丞 囟亘胤 丕賱噩賴丕夭',
+    clickToReset: '丕囟睾胤 賱廿毓丕丿丞 丕賱囟亘胤',
+    resetConfirm: '鬲兀賰賷丿 廿毓丕丿丞 丕賱囟亘胤責',
+    resetWillOut: "亘毓丿 丕賱乇賷爻鬲 禺乇賵噩",
+    resetSuccess: '鬲賲鬲 廿毓丕丿丞 丕賱囟亘胤',
+    resetFailed: '賮卮賱鬲 廿毓丕丿丞 丕賱囟亘胤',
+    firmwareUpgrade: '鬲丨丿賷孬 丕賱亘乇賳丕賲噩 丕賱孬丕亘鬲',
+    upgradeConfig: '廿毓丿丕丿丕鬲 丕賱鬲丨丿賷孬',
+    firmwareUrl: '乇丕亘胤 丕賱亘乇賳丕賲噩',
+    md5Checksum: '賯賷賲丞 md5',
+    startUpgrade: '亘丿亍 丕賱鬲丨丿賷孬',
+    urlRequired: '丕賱乇丕亘胤 賲胤賱賵亘',
+    md5Required: '賯賷賲丞 md5 賲胤賱賵亘丞',
+    urlInvalid: '賷乇噩賶 廿丿禺丕賱 乇丕亘胤 氐丨賷丨',
+    md5Invalid: '賷乇噩賶 廿丿禺丕賱 md5 氐丨賷丨',
+    upgradeConfirm: '鬲兀賰賷丿 丕賱鬲丨丿賷孬責',
+    upgradeSuccess: '鬲賲 丕賱鬲丨丿賷孬 亘賳噩丕丨',
+    clearFile: "賲爻丨 丕賱賲賱賮",
+    uploading: '噩丕乇賷 丕賱乇賮毓...',
+    uploadAndUpgrade: '乇賮毓 賵鬲丨丿賷孬',
+    restartTips: '廿毓丕丿丞 鬲卮睾賷賱 丌賲賳丞 丿賵賳 賮賯丿丕賳 丕賱亘賷丕賳丕鬲',
+    restarting: '噩丕乇賷 廿毓丕丿丞 丕賱鬲卮睾賷賱...',
+    remoteTips: '鬲丨賰賲 毓賳 亘毓丿 亘丕賱賵氐賵賱',
+    opening: '噩丕乇賷 丕賱賮鬲丨...',
+    resetTips: '廿乇噩丕毓 廿毓丿丕丿丕鬲 丕賱賲氐賳毓貙 爻賷丨匕賮 丕賱亘賷丕賳丕鬲',
+    reseting: '噩丕乇賷 丕賱廿毓丕丿丞...',
+    urlUpgrade: '鬲丨丿賷孬 毓亘乇 丕賱乇丕亘胤',
+    fileUpgrade: '鬲丨丿賷孬 毓亘乇 賲賱賮',
+    uploadFile: '丕囟睾胤 賱乇賮毓 賲賱賮 丕賱亘乇賳丕賲噩',
+    formatFile: '賷丿毓賲 .zip 兀賵 .dpk貙 丕賱丨丿 20MB',
+    fileName: '丕爻賲 丕賱賲賱賮',
+    size: '丕賱丨噩賲',
+  },
+  config: {
+    second: '孬',
+    millisecond: '賲賱孬',
+    min: '丿賯丕卅賯',
+    notsave: '賱丕 鬲丨賮馗',
+    save: '丨賮馗',
+    noVoice: '亘丿賵賳 氐賵鬲',
+    no: '賱丕',
+    yes: '賳毓賲',
+    basicConfiguration: '丕賱廿毓丿丕丿丕鬲 丕賱兀爻丕爻賷丞',
+    displaySettings: '廿毓丿丕丿丕鬲 丕賱毓乇囟',
+    informationDisplay: '毓乇囟 丕賱賲毓賱賵賲丕鬲',
+    audioSettings: '廿毓丿丕丿丕鬲 丕賱氐賵鬲',
+    languageAndThemes: '丕賱賱睾丞 賵丕賱爻賲丕鬲',
+    autoAdjustScreenBrightness: '爻胤賵毓 鬲賱賯丕卅賷',
+    screenBrightness: '爻胤賵毓 丕賱卮丕卮丞',
+    autoTurnOffScreen: '廿賷賯丕賮 丕賱卮丕卮丞 鬲賱賯丕卅賷丕賸',
+    autoTurnOffScreenTime: '夭賲賳 丕賱廿賷賯丕賮',
+    autoScreenSaver: '丨丕賮馗丞 卮丕卮丞 鬲賱賯丕卅賷丞',
+    autoScreenSaverTime: '夭賲賳 丕賱丨丕賮馗丞',
+    displayDeviceSn: '毓乇囟 SN',
+    displayIp: '毓乇囟 IP',
+    displayIdentityCard: '毓乇囟 卮賴丕丿丞 丕賱爻丨丕亘丞',
+    volume: '賲爻鬲賵賶 丕賱氐賵鬲',
+    language: '丕賱賱睾丞',
+    displayCode: "毓乇囟 乇賲夭 丕賱鬲胤亘賷賯 丕賱賲氐睾乇",
+    themeMode: "賳賲胤 丕賱毓賲賱",
+    cn: '丕賱氐賷賳賷丞',
+    en: '丕賱廿賳噩賱賷夭賷丞',
+    es: '丕賱廿爻亘丕賳賷丞',
+    fr: '丕賱賮乇賳爻賷丞',
+    de: '丕賱兀賱賲丕賳賷丞',
+    ru: '丕賱乇賵爻賷丞',
+    ar: '丕賱毓乇亘賷丞',
+    pt: '丕賱亘乇鬲睾丕賱',
+    ko: '丕賱賰賵乇賷丞',
+    standardMode: '丕賱賵囟毓 丕賱賯賷丕爻賷',
+    simpleMode: '丕賱賵囟毓 丕賱賲亘爻胤',
+    firstLogin: '兀賵賱 鬲爻噩賷賱 丿禺賵賱',
+    backlight: '廿囟丕亍丞 禺賱賮賷丞 丕賱卮丕卮丞',
+    brightness: '丕賱廿囟丕亍丞 丕賱亘賷囟丕亍',
+    nirBrightness: '廿囟丕亍丞 丕賱兀卮毓丞 鬲丨鬲 丕賱丨賲乇丕亍',
+    never: '兀亘丿丕賸',
+    min1: '丿賯賷賯丞',
+    min2: '丿賯賷賯鬲丕賳',
+    min3: '3 丿賯丕卅賯',
+    min4: '4 丿賯丕卅賯',
+    min5: '5 丿賯丕卅賯',
+    networkConfiguration: '廿毓丿丕丿丕鬲 丕賱卮亘賰丞',
+    otherConfiguration: '廿毓丿丕丿丕鬲 兀禺乇賶',
+    ipConfiguration: '鬲賰賵賷賳 IP',
+    devicePassword: '賰賱賲丞 賲乇賵乇 丕賱噩賴丕夭',
+    protocolPassword: '賰賱賲丞 賲乇賵乇 丕賱亘乇賵鬲賵賰賵賱',
+    networkType: '賳賵毓 丕賱卮亘賰丞',
+    ethernet: '廿賷孬乇賳鬲',
+    wifiName: '丕爻賲 Wi鈥慒i',
+    wifiPassword: '賰賱賲丞 賲乇賵乇 Wi鈥慒i',
+    dhcpModeSelection: '賵囟毓 DHCP',
+    dhcpMode: '鬲賱賯丕卅賷',
+    customNetworkConfiguration: '賷丿賵賷',
+    ipAddress: '毓賳賵丕賳 IP',
+    gateway: '丕賱亘賵丕亘丞',
+    subnetMask: '賯賳丕毓 丕賱卮亘賰丞',
+    dnsServer: '禺丕丿賲 DNS',
+    mac: '毓賳賵丕賳 MAC',
+    mqttRelatedConfiguration: '廿毓丿丕丿丕鬲 MQTT',
+    mqttConnectionInformation: '賲毓賱賵賲丕鬲 丕鬲氐丕賱 MQTT',
+    sessionConfiguration: '廿毓丿丕丿丕鬲 丕賱噩賱爻丞',
+    serverAddress: '毓賳賵丕賳 丕賱禺丕丿賲',
+    clientID: '賲毓乇賾賮 丕賱毓賲賷賱',
+    userName: '丕爻賲 丕賱賲爻鬲禺丿賲',
+    userPassword: '賰賱賲丞 丕賱賲乇賵乇',
+    topicPrefix: '亘丕丿卅丞 丕賱賲賵囟賵毓',
+    onlineChecking: '鬲丨賯賯 毓亘乇 丕賱廿賳鬲乇賳鬲',
+    onlineCheckingTimeout: '賲賴賱丞 丕賱鬲丨賯賯',
+    cleanSession: '鬲賳馗賷賮 丕賱噩賱爻丞',
+    clientIdSuffix: '賱丕丨賯丞 丕賱賲毓乇賾賮',
+    willTopic: '賲賵囟賵毓 Will',
+    enterpriseWechat:'賵囟毓 Enterprise WeChat 睾賷乇 賲賮毓賱',
+    faceRelatedConfiguration: '廿毓丿丕丿丕鬲 丕賱賵噩賴',
+    functionalInformation: '賲毓賱賵賲丕鬲 丕賱賵馗賷賮丞',
+    prompt: '鬲賳亘賷賴',
+    faceSimilarityThreshold: '毓鬲亘丞 丕賱鬲卮丕亘賴',
+    livenessDetectionFunction: '賰卮賮 丕賱丨賷賵賷丞',
+    livenessDetectionThreshold: '毓鬲亘丞 丕賱丨賷賵賷丞',
+    infraredImageDisplay: "毓乇囟 丕賱兀卮毓丞 鬲丨鬲 丕賱丨賲乇丕亍",
+    maskRecognition: "丕賱鬲毓乇賮 毓賱賶 丕賱賯賳丕毓",
+    strangerVoice: "氐賵鬲 丕賱睾乇賷亘",
+    voiceMode: "賵囟毓 丕賱氐賵鬲",
+    voiceModeDate: '鬲丨賷丞 賲禺氐氐丞',
+    imageSaveType: "賳賵毓 丕賱丨賮馗",
+    saveStrangerImage: "丨賮馗 氐賵乇丞 丕賱睾乇賷亘",
+    fullView: "亘丕賳賵乇丕賲丕",
+    face: "丕賱賵噩賴",
+    broadcastPleaseRegisterFirst: '鬲卮睾賷賱 "爻噩賱 兀賵賱丕賸"',
+    broadcastHelloStranger: '鬲卮睾賷賱 "睾乇賷亘"',
+    broadcastName: '鬲卮睾賷賱 丕賱丕爻賲',
+    broadcastGreeting: '鬲卮睾賷賱 鬲丨賷丞 賲禺氐氐丞',
+    greeting: '鬲丨賷丞',
+    broadcastWelcome: '鬲卮睾賷賱 "賲乇丨亘丕賸"',
+    recognitionSwitch: '賲賮鬲丕丨 廿毓丕丿丞 丕賱賰卮賮',
+    systemRelatedConfiguration: '廿毓丿丕丿丕鬲 丕賱賳馗丕賲',
+    functionSwitch: '賲賮丕鬲賷丨 丕賱賵馗丕卅賮',
+    cardSwipingSwitch: '丕賱亘胤丕賯丞',
+    passwordSwitch: '賰賱賲丞 丕賱賲乇賵乇',
+    strangerImage: '氐賵乇丞 丕賱睾乇賷亘',
+    cloudCertificateSwitch: '卮賴丕丿丞 丕賱爻丨丕亘丞',
+    physicalCardNumber: '乇賯賲 丕賱亘胤丕賯丞 丕賱賮賷夭賷丕卅賷丞',
+    cloudCertificateAcquisition: '丕賱丨氐賵賱 毓賱賶 卮賴丕丿丞 丕賱爻丨丕亘丞',
+    heartbeatConfig: '賳亘囟丕鬲 丕賱賯賱亘',
+    heartbeatSwitch: '鬲賮毓賷賱 丕賱賳亘囟丕鬲',
+    heartRateInterval: '丕賱賮丕氐賱 丕賱夭賲賳賷',
+    heartbeatTopic: '賲賵囟賵毓 丕賱賳亘囟',
+    heartbeatContent: '賲丨鬲賵賶 丕賱賳亘囟',
+    basicInformation: '賲毓賱賵賲丕鬲 兀爻丕爻賷丞',
+    deviceMac: '毓賳賵丕賳 MAC',
+    uuid: 'UUID',
+    sn: 'SN',
+    model: '丕賱胤乇丕夭',
+    version: "丕賱廿氐丿丕乇",
+    appVersion: "廿氐丿丕乇 丕賱亘乇賳丕賲噩",
+    releaseTime: "賵賯鬲 丕賱鬲丨丿賷孬",
+    totaldisk: '丕賱賲爻丕丨丞 丕賱廿噩賲丕賱賷丞',
+    freedisk: '丕賱賲爻丕丨丞 丕賱賲鬲亘賯賷丞',
+    passageConfiguration: '廿毓丿丕丿丕鬲 丕賱賲乇賵乇',
+    functionConfiguration: '廿毓丿丕丿丕鬲 丕賱賵馗丕卅賮',
+    numberOfPassageRecords: '丕賱丨丿 丕賱兀賯氐賶 賱賱爻噩賱丕鬲',
+    durationOfRelayOpening: '賲丿丞 賮鬲丨 丕賱賲乇丨賱',
+    alarmSwitch: '廿賳匕丕乇',
+    fireAlarmSwitch: '廿賳匕丕乇 丨乇賷賯',
+    fireAlarmStatus: '丨丕賱丞 丕賱丨乇賷賯',
+    normal: '胤亘賷毓賷',
+    warning: '鬲丨匕賷乇',
+    tamperSwitch: '廿賳匕丕乇 丕賱毓亘孬',
+    uploadToCloudSwitch: '賲賮鬲丕丨 鬲丨賲賷賱 丕賱賵噩賴',
+    clockConfiguration: '廿毓丿丕丿丕鬲 丕賱賵賯鬲',
+    timeSynchronizationSwitch: '賲夭丕賲賳丞 丕賱賵賯鬲',
+    timeSynchronizationServerIP: '禺丕丿賲 丕賱賵賯鬲',
+    timedSynchronizationTime: '賵賯鬲 丕賱賲夭丕賲賳丞',
+    timeZone: '丕賱賲賳胤賯丞 丕賱夭賲賳賷丞',
+    setDeviceTime: '囟亘胤 賵賯鬲 丕賱噩賴丕夭',
+    restartAfterSetting: '爻賷購毓丕丿 鬲卮睾賷賱 丕賱噩賴丕夭 亘毓丿 丕賱囟亘胤',
+    cloudCertificateActivation: '鬲賮毓賷賱 卮賴丕丿丞 丕賱爻丨丕亘丞',
+    activationKey: '賲賮鬲丕丨 丕賱鬲賮毓賷賱',
+    cloudTips1: '兀丿禺賱 丕賱賲賮鬲丕丨 亘丿賵賳 賲爻丕賮丕鬲',
+    cloudTips2: '亘毓丿 丕賱鬲賮毓賷賱 爻賷鬲氐賱 亘禺丿賲丞 丕賱爻丨丕亘丞',
+    confirmActivation: '鬲兀賰賷丿 丕賱鬲賮毓賷賱',
+    activationInProgress: '噩丕乇賷 丕賱鬲賮毓賷賱...',
+    activationFailed: '賮卮賱 丕賱鬲賮毓賷賱',
+    activationSuccessful: '鬲賲 丕賱鬲賮毓賷賱 亘賳噩丕丨',
+    passwordModification: '鬲睾賷賷乇 賰賱賲丞 丕賱賲乇賵乇',
+    password: '賰賱賲丞 丕賱賲乇賵乇',
+    oldPassword: '賰賱賲丞 丕賱賲乇賵乇 丕賱賯丿賷賲丞',
+    newPassword: '賰賱賲丞 丕賱賲乇賵乇 丕賱噩丿賷丿丞',
+    confirmPassword: '鬲兀賰賷丿 賰賱賲丞 丕賱賲乇賵乇',
+    passwordRule: '鬲賵氐賷丕鬲 賰賱賲丞 丕賱賲乇賵乇',
+    passwordLength: '丕賱胤賵賱 鈮�6',
+    cannotBeTheSame: '賱丕 賷賲賰賳 兀賳 鬲賰賵賳 賰賱 丕賱兀丨乇賮 賲鬲胤丕亘賯丞',
+    cannotOrder: '賱丕 賷卮賲賱 3+ 兀乇賯丕賲/丨乇賵賮 賲鬲鬲丕賱賷丞',
+    cannotWeakPassword: '賱丕 鬲爻鬲禺丿賲 賰賱賲丕鬲 賲乇賵乇 囟毓賷賮丞 卮丕卅毓丞',
+    submit: '廿乇爻丕賱',
+    saveConfig: '丨賮馗 丕賱廿毓丿丕丿丕鬲',
+    msg_please_enter: '賷乇噩賶 丕賱廿丿禺丕賱',
+    msg_inputPassword: '賷乇噩賶 廿丿禺丕賱 賰賱賲丞 丕賱賲乇賵乇',
+    msg_oldPasswordError: '賰賱賲丞 丕賱賲乇賵乇 丕賱賯丿賷賲丞 睾賷乇 氐丨賷丨丞',
+    msg_password_mismatch: '賰賱賲鬲丕 丕賱賲乇賵乇 睾賷乇 賲鬲胤丕亘賯鬲賷賳',
+    msg_password_min_length: '丕賱丨丿 丕賱兀丿賳賶 6 兀丨乇賮',
+    msg_is_weak_password: '賰賱賲丞 賲乇賵乇 囟毓賷賮丞貙 賷乇噩賶 丕賱鬲睾賷賷乇',
+    msg_pswChangeSuccessAndLogin: '鬲賲 鬲睾賷賷乇 賰賱賲丞 丕賱賲乇賵乇貙 賷乇噩賶 鬲爻噩賷賱 丕賱丿禺賵賱',
+    msg_pswChangeSuccess: '鬲賲 鬲睾賷賷乇 賰賱賲丞 丕賱賲乇賵乇',
+    msg_pswChangeFail: '賮卮賱 鬲睾賷賷乇 賰賱賲丞 丕賱賲乇賵乇',
+    msg_saveSuccess: '鬲賲 丕賱丨賮馗 亘賳噩丕丨',
+    msg_saveFail: '賮卮賱 丕賱丨賮馗',
+    msg_formFilled: '鬲丨賯賯 賲賳 鬲毓亘卅丞 丕賱賳賲賵匕噩',
+    msg_number_0_23: '賷丿毓賲 賮賯胤 0 廿賱賶 23',
+    msg_number_0_24: '賷丿毓賲 賮賯胤 0 廿賱賶 24',
+    msg_noChange: '賱丕 鬲賵噩丿 鬲睾賷賷乇丕鬲 賮賷 丕賱廿毓丿丕丿丕鬲 賱賱丨賮馗',
+    resourceConfiguration: '廿毓丿丕丿丕鬲 丕賱賲賵丕乇丿',
+    backgroundImage: '氐賵乇丞 丕賱禺賱賮賷丞',
+    selectImage: '丕禺鬲乇 氐賵乇丞',
+    uploadBackground: '乇賮毓 丕賱禺賱賮賷丞',
+    uploading: '噩丕乇賺 丕賱乇賮毓...',
+    backgroundUploadTip: '賷乇噩賶 鬲丨賲賷賱 氐賵乇丞 亘氐賷睾丞 PNG 亘丨噩賲 丕賱亘賰爻賱丕鬲 {n}貙 賵爻賷鬲賲 鬲丨賵賷賱 丕賱氐賵乇丞 廿賱賶 氐賷睾丞 Base64 孬賲 賳賯賱賴丕 廿賱賶 丕賱噩賴丕夭',
+    backgroundResolutionMismatch: '賷噩亘 兀賳 鬲賰賵賳 丿賯丞 丕賱氐賵乇丞 {n}',
+    backgroundRequired: '賷乇噩賶 丕禺鬲賷丕乇 氐賵乇丞 禺賱賮賷丞',
+    backgroundImageOnlyPNG: 'PNG 賮賯胤',
+    backgroundSizeLimit: '丕賱丨噩賲 賱丕 賷鬲噩丕賵夭 5MB',
+    backgroundParseFailed: '賮卮賱 賯乇丕亍丞 丕賱氐賵乇丞',
+    backgroundImageSelected: '鬲賲 丕禺鬲賷丕乇 丕賱氐賵乇丞',
+    backgroundSuccess: '鬲賲 乇賮毓 丕賱禺賱賮賷丞',
+    backgroundFailed: '賮卮賱 乇賮毓 丕賱禺賱賮賷丞',
+    scanSettings: '廿毓丿丕丿丕鬲 丕賱賲爻丨',
+    scanSwitch: '賲賮鬲丕丨 丕賱賲爻丨',
+    scanInterval: '賮丕氐賱 丕賱賲爻丨'
+  },
+  person: {
+    idCard: '乇賯賲 丕賱賴賵賷丞',
+    userType: '賳賵毓 丕賱賲爻鬲禺丿賲',
+    administrator: '賲爻丐賵賱',
+    userId: 'ID',
+    user: '賲爻鬲禺丿賲',
+    voucher: '亘賷丕賳 丕毓鬲賲丕丿',
+    permission: '丕賱氐賱丕丨賷丞',
+    addUser: '廿囟丕賮丞 賲爻鬲禺丿賲',
+    name: '丕賱丕爻賲',
+    editUser: '鬲毓丿賷賱 丕賱賲爻鬲禺丿賲',
+    placeholderUserId: '兀丿禺賱 賲毓乇賮 丕賱賲爻鬲禺丿賲',
+    placeholderName: '兀丿禺賱 丕賱丕爻賲',
+    userNotExist: '丕賱賲爻鬲禺丿賲 睾賷乇 賲賵噩賵丿',
+    oneClickClear: '賲爻丨 丕賱賰賱',
+    clearTips: '爻賷鬲賲 丨匕賮 噩賲賷毓 丕賱亘賷丕賳丕鬲貙 丕賱賲鬲丕亘毓丞責',
+    clearSuccess: '鬲賲 丕賱賲爻丨 亘賳噩丕丨',
+    clearFailed: '賮卮賱 丕賱賲爻丨',
+  },
+  voucher: {
+    password: '賰賱賲丞 丕賱賲乇賵乇',
+    card: '亘胤丕賯丞',
+    face: '賵噩賴',
+    finger: '亘氐賲丞',
+    code: "丕賱乇賲夭",
+    codeType: "賳賵毓 丕賱乇賲夭",
+    passthroughCode: "乇賲夭 丕賱鬲賲乇賷乇",
+    staticCode: "乇賲夭 孬丕亘鬲",
+    dynamicCode: "乇賲夭 丿賷賳丕賲賷賰賷",
+    credentialId: '賲毓乇賾賮 亘賷丕賳丕鬲 丕賱丕毓鬲賲丕丿',
+    credentialValue: '賯賷賲丞 亘賷丕賳丕鬲 丕賱丕毓鬲賲丕丿',
+    placeholderCode: "丕賱乇噩丕亍 廿丿禺丕賱 乇賲夭 丕賱卮賴丕丿丞",
+    placeholderPwd: '兀丿禺賱 賰賱賲丞 丕賱賲乇賵乇',
+    placeholderCard: '兀丿禺賱 丕賱亘胤丕賯丞',
+    validPassword: '兀丿禺賱 6 兀乇賯丕賲',
+    validCard: '兀丿禺賱 8 兀乇賯丕賲 兀賵 兀丨乇賮',
+    photoRegistration: '鬲爻噩賷賱 氐賵乇丞',
+    featureValueRegistration: '鬲爻噩賷賱 丕賱爻賲丕鬲',
+    fingerRegistration: '鬲爻噩賷賱 丕賱亘氐賲丞',
+    fingerFeatureRegistration: '鬲爻噩賷賱 賯賷賲丞 丕賱爻賲丞',
+    fingerInput: '賷乇噩賶 賵囟毓 廿氐亘毓賰 毓賱賶 賲丕爻丨 丕賱亘氐賲丞',
+    fingerRemainingTime: '丕賱賵賯鬲 丕賱賲鬲亘賯賷',
+    fingerInputting: '噩丕乇賺 丕賱鬲爻噩賷賱...',
+    startFingerInput: '亘丿亍 鬲爻噩賷賱 丕賱亘氐賲丞',
+    fingerInputTips: '賷乇噩賶 廿丿禺丕賱 賯賷賲丞 爻賲丞 丕賱亘氐賲丞',
+    fingerWaitInput: '亘丕賳鬲馗丕乇 丕賱鬲爻噩賷賱',
+    fingerInputNow: '噩丕乇賺 鬲爻噩賷賱 丕賱亘氐賲丞...',
+    fingerInputSuccess: '鬲賲 丕賱鬲爻噩賷賱 亘賳噩丕丨',
+    fingerInputFailed: '賮卮賱 亘丿亍 鬲爻噩賷賱 丕賱亘氐賲丞',
+    fingerReTry: '賮卮賱 鬲爻噩賷賱 丕賱亘氐賲丞貙 賷乇噩賶 丕賱賲丨丕賵賱丞 賲乇丞 兀禺乇賶',
+    fingerFilled: '鬲賲 鬲爻噩賷賱 丕賱亘氐賲丞 亘賳噩丕丨 賵鬲賲 鬲毓亘卅丞 賯賷賲丞 丕賱爻賲丞 鬲賱賯丕卅賷賸丕',
+    fingerFailed: '賮卮賱 鬲爻噩賷賱 丕賱亘氐賲丞',
+    fingerTimeout: '丕賳鬲賴鬲 丕賱賲賴賱丞',
+    fingerInputTimeout: '丕賳鬲賴鬲 賲賴賱丞 鬲爻噩賷賱 丕賱亘氐賲丞貙 賷乇噩賶 丕賱賲丨丕賵賱丞 賲乇丞 兀禺乇賶',
+    fingerError: '賮卮賱 丕賱鬲爻噩賷賱',
+    fingerInputError: '賮卮賱 鬲爻噩賷賱 丕賱亘氐賲丞貙 賷乇噩賶 丕賱賲丨丕賵賱丞 賲乇丞 兀禺乇賶',
+    fingerInputed: '鬲賲 鬲爻噩賷賱 丕賱亘氐賲丞',
+    fingerReInput: '廿毓丕丿丞 鬲爻噩賷賱 丕賱亘氐賲丞',
+  
+  },
+  permission: {
+    deletePermission: '丨匕賮 丕賱氐賱丕丨賷丞',
+    addPermission: '廿囟丕賮丞 氐賱丕丨賷丞',
+    permissionId: '賲毓乇賾賮 丕賱氐賱丕丨賷丞',
+    userId: '賲毓乇賾賮 丕賱賲爻鬲禺丿賲',
+    timeRange: '丕賱賳胤丕賯 丕賱夭賲賳賷',
+    extra: '廿囟丕賮賷',
+    effectiveType: '賳賵毓 丕賱賮毓丕賱賷丞',
+    effectiveTime: '賵賯鬲 丕賱賮毓丕賱賷丞',
+    effectiveWeek: '丕賱兀爻亘賵毓 丕賱賮毓丕賱',
+    timePeriod: '丕賱賮鬲乇丞 丕賱夭賲賳賷丞',
+    addTimePeriod: '廿囟丕賮丞 賮鬲乇丞',
+    modify_previous_time: '毓丿賾賱 丕賱賮鬲乇丞 丕賱爻丕亘賯丞 兀賵賱丕賸',
+    cannot_be_earlier: '賱丕 賷賲賰賳 兀賳 鬲賰賵賳 丕賱賳賴丕賷丞 賯亘賱 丕賱亘丿丕賷丞',
+    times_cannot_overlap: '賱丕 賷賲賰賳 鬲丿丕禺賱 丕賱兀賵賯丕鬲',
+    choose_time_range: '丕禺鬲乇 賳胤丕賯 丕賱夭賲賳',
+    unlimitedMode: '睾賷乇 賲丨丿賵丿',
+    usualMode: '丕賱賵囟毓 丕賱賲毓鬲丕丿',
+    dailyMode: '賵囟毓 賷賵賲賷',
+    weeklyRepetitionMode: '鬲賰乇丕乇 兀爻亘賵毓賷',
+    time_range: '丕賱賳胤丕賯 丕賱夭賲賳賷',
+  },
+  common: {
+    startDate: '鬲丕乇賷禺 丕賱亘丿亍',
+    endDate: '鬲丕乇賷禺 丕賱丕賳鬲賴丕亍',
+    to: '廿賱賶',
+    cancel: '廿賱睾丕亍',
+    confirm: '鬲兀賰賷丿',
+    close: '廿睾賱丕賯',
+    delete: '丨匕賮',
+    edit: '鬲毓丿賷賱',
+    batchDelete: '丨匕賮 丿賮毓丞',
+    startTime: '賵賯鬲 丕賱亘丿亍',
+    endTime: '賵賯鬲 丕賱丕賳鬲賴丕亍',
+    monday: '丕賱丕孬賳賷賳',
+    tuseday: '丕賱孬賱丕孬丕亍',
+    wednesday: '丕賱兀乇亘毓丕亍',
+    thursday: '丕賱禺賲賷爻',
+    friday: '丕賱噩賲毓丞',
+    saterday: '丕賱爻亘鬲',
+    sunday: '丕賱兀丨丿',
+    placeholder: '賷乇噩賶 丕賱廿丿禺丕賱',
+    placeholderSelect: '賷乇噩賶 丕賱丕禺鬲賷丕乇',
+    closeTips: '鬲兀賰賷丿 丕賱廿睾賱丕賯責',
+    deleteTips: '鬲兀賰賷丿 丕賱丨匕賮責',
+    deleteSuccess: '鬲賲 丕賱丨匕賮 亘賳噩丕丨',
+    addSuccess: '鬲賲鬲 丕賱廿囟丕賮丞 亘賳噩丕丨',
+    editSuccess: '鬲賲 丕賱鬲毓丿賷賱 亘賳噩丕丨',
+    saveSuccess: '鬲賲 丕賱丨賮馗',
+    tips: '鬲賳亘賷賴',
+    operation: '毓賲賱賷丞',
+    query: '丕爻鬲毓賱丕賲',
+    reset: '廿毓丕丿丞',
+    noData: '賱丕 鬲賵噩丿 亘賷丕賳丕鬲',
+    export: '鬲氐丿賷乇',
+    success: '賳噩丕丨',
+    failure: '賮卮賱',
+    incorrectFormat: '氐賷睾丞 睾賷乇 氐丨賷丨丞',
+    integerFormat: '賷噩亘 兀賳 賷賰賵賳 毓丿丿丕賸 氐丨賷丨丕賸 鈮�0',
+    positiveIntegerFormat: '賷噩亘 兀賳 賷賰賵賳 毓丿丿丕賸 氐丨賷丨丕賸 >0',
+    noDataSaved: '賱丕 鬲賵噩丿 亘賷丕賳丕鬲 賱賱丨賮馗',
+    chinese: '丕賱氐賷賳賷丞',
+    english: '丕賱廿賳噩賱賷夭賷丞',
+    spanish: '丕賱廿爻亘丕賳賷丞',
+    french: '丕賱賮乇賳爻賷丞',
+    german: '丕賱兀賱賲丕賳賷丞',
+    russian: '丕賱乇賵爻賷丞',
+    arabic: '丕賱毓乇亘賷丞',
+    portuguese: '丕賱亘乇鬲睾丕賱賷丞',
+    korean: '丕賱賰賵乇賷丞',
+    detail: "丕賱鬲賮丕氐賷賱",
+    clearTips: "賴賱 兀賳鬲 賲鬲兀賰丿 賲賳 丕賱賲爻丨責",
+    clearSuccess: "鬲賲 丕賱賲爻丨 亘賳噩丕丨",
+  },
+  log: {
+    accessMethod: '胤乇賷賯丞 丕賱丿禺賵賱',
+    passingTime: '賵賯鬲 丕賱賲乇賵乇',
+    accessPass: '丕毓鬲賲丕丿 丕賱丿禺賵賱',
+    accessResult: '丕賱賳鬲賷噩丞',
+    accessPhoto: '氐賵乇丞',
+    viewPhotos: '毓乇囟 丕賱氐賵乇'
+  },
+  error: {
+    networkError: '賮卮賱 丕賱卮亘賰丞貙 鬲丨賯賯 賲賳 丕賱丕鬲氐丕賱',
+    timeout: '丕賳鬲賴賶 丕賱賵賯鬲貙 丨丕賵賱 賱丕丨賯丕賸',
+    serverError: '禺胤兀 丿丕禺賱賷 賮賷 丕賱禺丕丿賲',
+    notFound: '丕賱賲賵乇丿 睾賷乇 賲賵噩賵丿',
+    unauthorized: '睾賷乇 賲氐乇丨貙 賷乇噩賶 鬲爻噩賷賱 丕賱丿禺賵賱',
+    noResponse: '賱丕 賷賵噩丿 丕爻鬲噩丕亘丞 賲賳 丕賱禺丕丿賲',
+    unknownError: '賮卮賱 丕賱胤賱亘貙 丕賱乇賲夭:',
+    requestFailed: '賮卮賱 丕賱胤賱亘'
+  },
+  security: {
+    keyId: "賲毓乇賮 丕賱賲賮鬲丕丨",
+    keyType: "賳賵毓 丕賱賲賮鬲丕丨",
+    keyEncoding: "鬲乇賲賷夭 丕賱賲賮鬲丕丨",
+    keyValue: "賯賷賲丞 丕賱賲賮鬲丕丨",
+    startTime: "賵賯鬲 丕賱亘丿亍",
+    expirationTime: "賵賯鬲 丕賱丕賳鬲賴丕亍",
+    newKey: "廿囟丕賮丞 賲賮鬲丕丨 噩丿賷丿",
+    clearKey: "賲爻丨 丕賱賲賮鬲丕丨",
+    validTime: "丕賱賵賯鬲 丕賱氐丕賱丨",
+  }
+}
diff --git "a/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/language/de.js" "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/language/de.js"
new file mode 100644
index 0000000..5de1b4d
--- /dev/null
+++ "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/language/de.js"
@@ -0,0 +1,433 @@
+export default {
+  // Login
+  login: {
+    lang: 'Sprache',
+    systemname: 'Login',
+    username: 'Benutzername',
+    username_label: 'Bitte Benutzername eingeben',
+    pwd: 'Passwort',
+    pwd_label: 'Bitte Passwort eingeben',
+    pwd_info: 'Bitte korrektes Passwortformat eingeben',
+    success_msg: 'Erfolgreich angemeldet',
+    error_name: 'Falsches Passwort',
+    error_res: 'Anmeldeanforderungen nicht erf眉llt',
+    login: 'Anmelden',
+  },
+  // Sidebar
+  aside: {
+    systemname: 'Konsole',
+    quit: 'Abmelden',
+    deviceControl: 'Steuerung',
+    basicSetting: 'Einstellungen',
+    workerSetting: 'Personen',
+    deviceMonitoring: '脺berwachung',
+    recordManagement: 'Aufzeichnungen',
+    securityManagement: 'Schl眉sselverwaltung',
+    tips: 'Hinweis',
+    tips_msg: 'M枚chten Sie sich abmelden?',
+  },
+  control: {
+    remoteControl: 'Fern',
+    restart: 'Neustart',
+    clickToRestart: 'Zum Neustart klicken',
+    restartConfirm: 'Neustart best盲tigen?',
+    restartSuccess: 'Neustart erfolgreich',
+    restartFailed: 'Neustart fehlgeschlagen',
+    remoteOpen: 'T眉r fern枚ffnen',
+    clickToOpen: 'Zum 脰ffnen klicken',
+    openConfirm: 'Fern枚ffnung best盲tigen?',
+    remoteOpenSuccess: '脰ffnen erfolgreich',
+    remoteOpenFailed: '脰ffnen fehlgeschlagen',
+    reset: 'Ger盲t zur眉cksetzen',
+    clickToReset: 'Zum Zur眉cksetzen klicken',
+    resetConfirm: 'Zur眉cksetzen best盲tigen?',
+    resetWillOut: "Nach Reset abmelden",
+    resetSuccess: 'Zur眉cksetzen erfolgreich',
+    resetFailed: 'Zur眉cksetzen fehlgeschlagen',
+    firmwareUpgrade: 'Firmware-Update',
+    upgradeConfig: 'Update-Konfiguration',
+    firmwareUrl: 'Firmware-URL',
+    md5Checksum: 'md5-Wert',
+    startUpgrade: 'Update starten',
+    urlRequired: 'URL ist erforderlich',
+    md5Required: 'md5 ist erforderlich',
+    urlInvalid: 'Bitte g眉ltige URL eingeben',
+    md5Invalid: 'Bitte g眉ltiges md5 eingeben',
+    upgradeConfirm: 'Update best盲tigen?',
+    upgradeSuccess: 'Update erfolgreich',
+    clearFile: "Datei l枚schen",
+    uploading: 'Hochladen...',
+    uploadAndUpgrade: 'Hochladen & Aktualisieren',
+    restartTips: 'Sicherer Neustart, keine Daten gehen verloren',
+    restarting: 'Neustart...',
+    remoteTips: 'Fernsteuerung der Zugangst眉r',
+    opening: '脰ffnet...',
+    resetTips: 'Werksreset, l枚scht alle Daten',
+    reseting: 'Setzt zur眉ck...',
+    urlUpgrade: 'Update per URL',
+    fileUpgrade: 'Update per Datei',
+    uploadFile: 'Firmware-Datei hochladen',
+    formatFile: 'Unterst眉tzt .zip oder .dpk, max 20MB',
+    fileName: 'Dateiname',
+    size: 'Gr枚脽e',
+  },
+  config: {
+    second: 's',
+    millisecond: 'ms',
+    min: 'Minuten',
+    notsave: 'Nicht speichern',
+    save: 'Speichern',
+    noVoice: 'Keine Stimme',
+    no: 'Nein',
+    yes: 'Ja',
+    basicConfiguration: 'Grundkonfiguration',
+    displaySettings: 'Anzeige',
+    informationDisplay: 'Infoanzeige',
+    audioSettings: 'Audio',
+    languageAndThemes: 'Sprache & Thema',
+    autoAdjustScreenBrightness: 'Auto-Helligkeit',
+    screenBrightness: 'Bildschirmhelligkeit',
+    autoTurnOffScreen: 'Auto-Bildschirm aus',
+    autoTurnOffScreenTime: 'Zeit bis Ausschalten',
+    autoScreenSaver: 'Auto-Bildschirmschoner',
+    autoScreenSaverTime: 'Zeit Bildschirmschoner',
+    displayDeviceSn: 'SN anzeigen',
+    displayIp: 'IP anzeigen',
+    displayIdentityCard: 'Cloud-Zertifikat anzeigen',
+    volume: 'Lautst盲rke',
+    language: 'Sprache',
+    displayCode: "Mini-App-Code anzeigen",
+    themeMode: "Thema",
+    cn: 'Chinesisch',
+    en: 'Englisch',
+    es: 'Spanisch',
+    fr: 'Franz枚sisch',
+    de: 'Deutsch',
+    ru: 'Russisch',
+    ar: 'Arabisch',
+    pt: 'Port.',
+    ko: 'Koreanisch',
+    standardMode: 'Standardmodus',
+    simpleMode: 'Einfacher Modus',
+    firstLogin: 'Erste Anmeldung',
+    backlight: 'Hintergrundlicht',
+    brightness: 'Wei脽licht',
+    nirBrightness: 'IR-Licht',
+    never: 'Nie',
+    min1: '1 Minute',
+    min2: '2 Minuten',
+    min3: '3 Minuten',
+    min4: '4 Minuten',
+    min5: '5 Minuten',
+    networkConfiguration: 'Netzwerk',
+    otherConfiguration: 'Andere',
+    ipConfiguration: 'IP-Konfiguration',
+    devicePassword: 'Ger盲tepasswort',
+    protocolPassword: 'Protokollpasswort',
+    networkType: 'Netzwerktyp',
+    ethernet: 'Ethernet',
+    wifiName: 'Wi鈥慒i',
+    wifiPassword: 'Wi鈥慒i-Passwort',
+    dhcpModeSelection: 'DHCP-Modus',
+    dhcpMode: 'Automatisch',
+    customNetworkConfiguration: 'Manuell',
+    ipAddress: 'IP-Adresse',
+    gateway: 'Gateway',
+    subnetMask: 'Subnetzmaske',
+    dnsServer: 'DNS-Server',
+    mac: 'Netzwerk-MAC',
+    mqttRelatedConfiguration: 'MQTT',
+    mqttConnectionInformation: 'MQTT-Verbindung',
+    sessionConfiguration: 'Sitzung',
+    serverAddress: 'Serveradresse',
+    clientID: 'Client-ID',
+    userName: 'Benutzername',
+    userPassword: 'Passwort',
+    topicPrefix: 'Topic-Pr盲fix',
+    onlineChecking: 'Online-Pr眉fung',
+    onlineCheckingTimeout: 'Zeit眉berschreitung',
+    cleanSession: 'Saubere Sitzung',
+    clientIdSuffix: 'Client-ID-Suffix',
+    willTopic: 'Will-Topic',
+    enterpriseWechat:'Enterprise WeChat Modus ohne Wirkung',
+    faceRelatedConfiguration: 'Gesichtskonfiguration',
+    functionalInformation: 'Funktion',
+    prompt: 'Hinweis',
+    faceSimilarityThreshold: '脛hnlichkeitsschwelle',
+    livenessDetectionFunction: 'Lebenderkennung',
+    livenessDetectionThreshold: 'Schwelle Lebendigkeit',
+    infraredImageDisplay: "Infrarotbild",
+    maskRecognition: "Maskenerkennung",
+    strangerVoice: "Stimme Unbekannt",
+    voiceMode: "Sprachmodus",
+    voiceModeDate: 'Benutzerdefinierter Gru脽',
+    imageSaveType: "Speichertyp",
+    saveStrangerImage: "Bild von Unbekannt speichern",
+    fullView: "Panorama",
+    face: "Gesicht",
+    broadcastPleaseRegisterFirst: 'Spiele "Bitte zuerst registrieren"',
+    broadcastHelloStranger: 'Spiele "Unbekannt"',
+    broadcastName: 'Namen abspielen',
+    broadcastGreeting: 'Benutzerdefinierten Gru脽 abspielen',
+    greeting: 'Gru脽',
+    broadcastWelcome: '"Willkommen" abspielen',
+    recognitionSwitch: 'Erneute Erkennung Schalter',
+    systemRelatedConfiguration: 'System',
+    functionSwitch: 'Funktionsschalter',
+    cardSwipingSwitch: 'Karte',
+    passwordSwitch: 'Passwort',
+    strangerImage: 'Bild Unbekannter',
+    cloudCertificateSwitch: 'Cloud-Zertifikat',
+    physicalCardNumber: 'Physische Kartennr.',
+    cloudCertificateAcquisition: 'Cloud-Zertifikat Bezug',
+    heartbeatConfig: 'Heartbeat',
+    heartbeatSwitch: 'Heartbeat Schalter',
+    heartRateInterval: 'Intervall',
+    heartbeatTopic: 'Heartbeat-Topic',
+    heartbeatContent: 'Heartbeat-Inhalt',
+    basicInformation: 'Basisinfo',
+    deviceMac: 'MAC-Adresse',
+    uuid: 'UUID',
+    sn: 'SN',
+    model: 'Modell',
+    version: "Version",
+    appVersion: "Firmware-Version",
+    releaseTime: "Aktualisierungszeit",
+    totaldisk: 'Gesamtbereich',
+    freedisk: 'Verbleibender Platz',
+    passageConfiguration: 'Passage',
+    functionConfiguration: 'Funktionen',
+    numberOfPassageRecords: 'Max. Durchgangsaufzeichnungen',
+    durationOfRelayOpening: 'Relais-脰ffnungsdauer',
+    alarmSwitch: 'Alarm',
+    fireAlarmSwitch: 'Brandalarm',
+    fireAlarmStatus: 'Brandstatus',
+    normal: 'Normal',
+    warning: 'Warnung',
+    tamperSwitch: 'Sabotageschutz',
+    uploadToCloudSwitch: 'Gesicht-Upload-Schalter',
+    clockConfiguration: 'Uhr',
+    timeSynchronizationSwitch: 'Zeitsynchronisation',
+    timeSynchronizationServerIP: 'Zeitserver-IP',
+    timedSynchronizationTime: 'Synchronisationszeit',
+    timeZone: 'Zeitzone',
+    setDeviceTime: 'Ger盲tezeit setzen',
+    restartAfterSetting: 'Ger盲t startet neu',
+    cloudCertificateActivation: 'Cloud-Zertifikat Aktivierung',
+    activationKey: 'Aktivierungsschl眉ssel',
+    cloudTips1: 'Schl眉ssel ohne Leerzeichen eingeben',
+    cloudTips2: 'Nach Aktivierung verbindet sich das Ger盲t mit dem Cloud-Service',
+    confirmActivation: 'Aktivierung best盲tigen',
+    activationInProgress: 'Aktivierung l盲uft...',
+    activationFailed: 'Aktivierung fehlgeschlagen',
+    activationSuccessful: 'Aktivierung erfolgreich',
+    passwordModification: 'Passwort 盲ndern',
+    password: 'Passwort',
+    oldPassword: 'Altes Passwort',
+    newPassword: 'Neues Passwort',
+    confirmPassword: 'Passwort best盲tigen',
+    passwordRule: 'Passwortempfehlung',
+    passwordLength: 'L盲nge 鈮�6',
+    cannotBeTheSame: 'Alle Zeichen d眉rfen nicht gleich sein',
+    cannotOrder: 'Keine 3+ aufeinanderfolgende Zahlen/Buchstaben',
+    cannotWeakPassword: 'Kein schwaches Passwort',
+    submit: 'Senden',
+    saveConfig: 'Einstellungen speichern',
+    msg_please_enter: 'Bitte eingeben',
+    msg_inputPassword: 'Bitte Passwort eingeben',
+    msg_oldPasswordError: 'Altes Passwort falsch',
+    msg_password_mismatch: 'Passw枚rter stimmen nicht 眉berein',
+    msg_password_min_length: 'Mindestens 6 Zeichen',
+    msg_is_weak_password: 'Schwaches Passwort, bitte 盲ndern',
+    msg_pswChangeSuccessAndLogin: 'Passwort ge盲ndert, bitte neu anmelden',
+    msg_pswChangeSuccess: 'Passwort ge盲ndert',
+    msg_pswChangeFail: 'Passwort盲nderung fehlgeschlagen',
+    msg_saveSuccess: 'Erfolgreich gespeichert',
+    msg_saveFail: 'Speichern fehlgeschlagen',
+    msg_formFilled: 'Bitte Formular pr眉fen',
+    msg_number_0_23: 'Nur 0 bis 23',
+    msg_number_0_24: 'Nur 0 bis 24',
+    msg_noChange: 'Keine Konfigurations盲nderungen zu speichern',
+    resourceConfiguration: 'Ressourcenkonfiguration',
+    backgroundImage: 'Hintergrundbild',
+    selectImage: 'Bild ausw盲hlen',
+    uploadBackground: 'Hintergrund hochladen',
+    uploading: 'L盲dt hoch...',
+    backgroundUploadTip: 'Bitte laden Sie ein PNG-Bild mit einer Aufl枚sung von {n} Pixeln hoch. Das Bild wird in Base64-Format konvertiert und auf das Ger盲t hochgeladen',
+    backgroundResolutionMismatch: 'Die Bildaufl枚sung muss {n} sein',
+    backgroundRequired: 'Bitte ein Hintergrundbild w盲hlen',
+    backgroundImageOnlyPNG: 'Nur PNG-Bilder',
+    backgroundSizeLimit: 'Bild darf 5MB nicht 眉berschreiten',
+    backgroundParseFailed: 'Bild konnte nicht gelesen werden',
+    backgroundImageSelected: 'Bild ausgew盲hlt',
+    backgroundSuccess: 'Hintergrund hochgeladen',
+    backgroundFailed: 'Upload fehlgeschlagen',
+    scanSettings: 'Scan-Einstellungen',
+    scanSwitch: 'Scan-Schalter',
+    scanInterval: 'Scan-Intervall',
+  },
+  person: {
+    idCard: 'Ausweisnummer',
+    userType: 'Personentyp',
+    administrator: 'Administrator',
+    userId: 'ID',
+    user: 'Benutzer',
+    voucher: 'Nachweis',
+    permission: 'Berechtigung',
+    addUser: 'Person hinzuf眉gen',
+    name: 'Name',
+    editUser: 'Person bearbeiten',
+    placeholderUserId: 'Benutzer-ID eingeben',
+    placeholderName: 'Name eingeben',
+    userNotExist: 'Person existiert nicht',
+    oneClickClear: 'Alles l枚schen',
+    clearTips: 'Dies l枚scht alle Daten, fortfahren?',
+    clearSuccess: 'L枚schen erfolgreich',
+    clearFailed: 'L枚schen fehlgeschlagen',
+  },
+  voucher: {
+    password: 'Passwort',
+    card: 'Karte',
+    face: 'Gesicht',
+    finger: 'Fingerabdruck',
+    code: 'Code',
+    codeType: 'Codetyp',
+    passthroughCode: 'Durchgangscode',
+    staticCode: 'Statischer Code',
+    dynamicCode: 'Dynamischer Code',
+    credentialId: 'Anmelde-ID',
+    credentialValue: 'Anmeldewert',
+    placeholderCode: 'Bitte Codezertifikat eingeben',
+    placeholderPwd: 'Passwortnachweis eingeben',
+    placeholderCard: 'Kartennachweis eingeben',
+    validPassword: 'Bitte 6 Ziffern eingeben',
+    validCard: 'Bitte 8 Ziffern oder Buchstaben eingeben',
+    photoRegistration: 'Foto-Registrierung',
+    featureValueRegistration: 'Merkmals-Registrierung',
+    fingerRegistration: 'Fingerabdruck-Registrierung',
+    fingerFeatureRegistration: 'Registrierung 眉ber Merkmalswert',
+    fingerInput: 'Bitte legen Sie den Finger auf den Fingerabdruckscanner',
+    fingerRemainingTime: 'Verbleibende Zeit',
+    fingerInputting: 'Wird erfasst...',
+    startFingerInput: 'Fingerabdruck erfassen',
+    fingerInputTips: 'Bitte Fingerabdruck-Merkmalswert eingeben',
+    fingerWaitInput: 'Warten auf Erfassung',
+    fingerInputNow: 'Fingerabdruck wird erfasst...',
+    fingerInputSuccess: 'Erfassung erfolgreich',
+    fingerInputFailed: 'Start der Fingerabdruckerfassung fehlgeschlagen',
+    fingerReTry: 'Fingerabdruckerfassung fehlgeschlagen, bitte erneut versuchen',
+    fingerFilled: 'Erfassung erfolgreich, Merkmalswert wurde automatisch eingetragen',
+    fingerFailed: 'Fingerabdruckerfassung fehlgeschlagen',
+    fingerTimeout: 'Zeit眉berschreitung',
+    fingerInputTimeout: 'Zeit眉berschreitung bei der Fingerabdruckerfassung, bitte erneut versuchen',
+    fingerError: 'Erfassung fehlgeschlagen',
+    fingerInputError: 'Fingerabdruckerfassung fehlgeschlagen, bitte erneut versuchen',
+    fingerInputed: 'Fingerabdruck bereits erfasst',
+    fingerReInput: 'Fingerabdruck erneut erfassen',
+  },
+  permission: {
+    deletePermission: 'Berechtigung l枚schen',
+    addPermission: 'Berechtigung hinzuf眉gen',
+    permissionId: 'Berechtigungs-ID',
+    userId: 'Benutzer-ID',
+    timeRange: 'Zeitraum',
+    extra: 'Extra',
+    effectiveType: 'G眉ltigkeitstyp',
+    effectiveTime: 'G眉ltige Zeit',
+    effectiveWeek: 'G眉ltige Woche',
+    timePeriod: 'Zeitabschnitt',
+    addTimePeriod: 'Zeitabschnitt hinzuf眉gen',
+    modify_previous_time: 'Vorherigen Abschnitt zuerst 盲ndern',
+    cannot_be_earlier: 'Endzeit darf nicht vor Startzeit liegen',
+    times_cannot_overlap: 'Zeiten d眉rfen sich nicht 眉berschneiden',
+    choose_time_range: 'Zeitraum w盲hlen',
+    unlimitedMode: 'Unbegrenzt',
+    usualMode: 'Normalmodus',
+    dailyMode: 'T盲glich',
+    weeklyRepetitionMode: 'W枚chentliche Wiederholung',
+    time_range: 'Zeitbereich',
+  },
+  common: {
+    startDate: 'Startdatum',
+    endDate: 'Enddatum',
+    to: 'bis',
+    cancel: 'Abbrechen',
+    confirm: 'Best盲tigen',
+    close: 'Schlie脽en',
+    delete: 'L枚schen',
+    edit: 'Bearbeiten',
+    batchDelete: 'Stapel l枚schen',
+    startTime: 'Startzeit',
+    endTime: 'Endzeit',
+    monday: 'Montag',
+    tuseday: 'Dienstag',
+    wednesday: 'Mittwoch',
+    thursday: 'Donnerstag',
+    friday: 'Freitag',
+    saterday: 'Samstag',
+    sunday: 'Sonntag',
+    placeholder: 'Bitte eingeben',
+    placeholderSelect: 'Bitte w盲hlen',
+    closeTips: 'Schlie脽en best盲tigen?',
+    deleteTips: 'L枚schen best盲tigen?',
+    deleteSuccess: 'Erfolgreich gel枚scht',
+    addSuccess: 'Erfolgreich hinzugef眉gt',
+    editSuccess: 'Erfolgreich bearbeitet',
+    saveSuccess: 'Erfolgreich gespeichert',
+    tips: 'Hinweis',
+    operation: 'Operation',
+    query: 'Abfrage',
+    reset: 'Reset',
+    noData: 'Keine Daten',
+    export: 'Exportieren',
+    success: 'Erfolg',
+    failure: 'Fehler',
+    incorrectFormat: 'Falsches Format',
+    integerFormat: 'Ganzzahl 鈮�0 erforderlich',
+    positiveIntegerFormat: 'Ganzzahl >0 erforderlich',
+    noDataSaved: 'Keine Daten zu speichern',
+    chinese: 'Chinesisch',
+    english: 'Englisch',
+    spanish: 'Spanisch',
+    french: 'Franz枚sisch',
+    german: 'Deutsch',
+    russian: 'Russisch',
+    arabic: 'Arabisch',
+    portuguese: 'Portugiesisch',
+    korean: 'Koreanisch',
+    detail: 'Details',
+    clearTips: 'Wirklich leeren?鈥�',
+    clearSuccess: 'Erfolgreich gel枚scht',
+  },
+  log: {
+    accessMethod: 'Zugriffsmethode',
+    passingTime: 'Durchgangszeit',
+    accessPass: 'Zugangsnachweis',
+    accessResult: 'Ergebnis',
+    accessPhoto: 'Foto',
+    viewPhotos: 'Fotos ansehen'
+  },
+  error: {
+    networkError: 'Netzwerkfehler, Verbindung pr眉fen',
+    timeout: 'Zeit眉berschreitung, bitte erneut versuchen',
+    serverError: 'Serverfehler, sp盲ter erneut versuchen',
+    notFound: 'Ressource nicht gefunden',
+    unauthorized: 'Nicht autorisiert, bitte neu anmelden',
+    noResponse: 'Keine Serverantwort, Netzwerk pr眉fen',
+    unknownError: 'Anfrage fehlgeschlagen, Code:',
+    requestFailed: 'Anfrage fehlgeschlagen'
+  },
+  security: {
+    keyId: 'Schl眉ssel-ID',
+    keyType: 'Schl眉sseltyp',
+    keyEncoding: 'Schl眉sselkodierung',
+    keyValue: 'Schl眉sselwert',
+    startTime: 'Startzeit',
+    expirationTime: 'Ablaufzeit',
+    newKey: 'Neuer Schl眉ssel',
+    clearKey: 'Schl眉ssel l枚schen',
+    validTime: 'G眉ltigkeitsdauer',
+  }
+}
+
+
diff --git "a/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/language/en.js" "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/language/en.js"
new file mode 100644
index 0000000..96402e2
--- /dev/null
+++ "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/language/en.js"
@@ -0,0 +1,450 @@
+export default {
+  // 鐧诲綍椤�
+  login: {
+    lang: 'language',
+    systemname: 'Face Login',
+    username: 'username',
+    username_label: 'Please input one user name',
+    pwd: 'password',
+    pwd_label: 'Please input a password',
+    pwd_info: 'Please enter the correct password format',
+    success_msg: 'Login successfully',
+    error_name: 'Wrong password',
+    error_res: 'Does not meet the login requirements',
+    login: 'Login',
+  },
+  // 渚ц竟鏍忛儴鍒�
+  aside: {
+    systemname: 'Face System',
+    help: 'Help',
+    administrator: 'Administrator',
+    quit: 'Quit',
+    deviceControl: 'Control',
+    basicSetting: 'Settings',
+    workerSetting: 'Personnel',
+    deviceMonitoring: 'Monitoring',
+    recordManagement: 'Records',
+    securityManagement: 'Key',
+    tips: 'Tips',
+    tips_msg: 'Do you want to log out',
+  },
+  // 璁惧鎺у埗椤甸潰
+  control: {
+    remoteControl: 'Remote',
+    restart: 'Restart',
+    clickToRestart: 'Click to restart the device',
+    restartConfirm: 'Are you sure you want to restart the device?',
+    restartSuccess: 'Successful restart',
+    restartFailed: 'Failed to restart',
+    remoteOpen: 'Remote door opening',
+    clickToOpen: 'Click remote door opening',
+    openConfirm: 'Are you sure you want to open the door remotely?',
+    remoteOpenSuccess: 'Remote door opening successful',
+    remoteOpenFailed: 'Remote door opening failed',
+    reset: 'Device reset',
+    clickToReset: 'Click reset device',
+    resetConfirm: 'Are you sure you want to reset the device?',
+    resetWillOut: "Log out after reset.",
+    resetSuccess: 'The device reset was successful',
+    resetFailed: 'Device reset failed',
+    firmwareUpgrade: 'Equipment upgrade',
+    upgradeConfig: 'Upgrade configuration',
+    firmwareUrl: 'Firmware address',
+    md5Checksum: 'md5 value',
+    startUpgrade: 'Start upgrading',
+    urlRequired: 'The file address is mandatory',
+    md5Required: 'The md5 value is required',
+    urlInvalid: 'Please enter the correct address',
+    md5Invalid: 'Please enter the correct md5',
+    upgradeConfirm: 'Are you sure you want to upgrade the equipment?',
+    upgradeSuccess: 'The equipment upgrade was successful.',
+    clearFile: "Clear the file",
+    uploading: 'Uploading',
+    uploadAndUpgrade: 'Upload and upgrade',
+    restartTips: 'Safely restart the device system without losing data',
+    restarting: 'Restarting...',
+    remoteTips: 'Remotely control the access control device to open',
+    opening: 'Opening...',
+    resetTips: 'Restore factory Settings and clear all data',
+    reseting: 'Reseting...',
+    urlUpgrade: 'URL upgrade method',
+    fileUpgrade: 'File upload upgrade',
+    uploadFile: 'Click to upload the firmware file',
+    formatFile: 'Supports.zip or.dpk format files, with a maximum size of 20MB',
+    fileName: 'File name',
+    size: 'Size',
+  },
+  config: {
+    second: 's',
+    millisecond: 'Milliseconds',
+    min: 'Minutes',
+    notsave: 'Not saved',
+    save: 'Save',
+    noVoice: 'No voice',
+    no: 'NO',
+    yes: 'YES',
+    // 鍩虹閰嶇疆
+    basicConfiguration: 'Basic configuration',
+    informationDisplay: 'Information display',
+    audioSettings: 'Audio Settings',
+    displaySettings: 'Display Settings',
+    languageAndThemes: 'Language and Themes',
+    autoAdjustScreenBrightness: 'Automatically adjust the screen brightness',
+    screenBrightness: 'Screen brightness',
+    autoTurnOffScreen: 'Automatic screen-off',
+    autoTurnOffScreenTime: 'Automatic screen-off time',
+    autoScreenSaver: 'Automatic screen saver',
+    autoScreenSaverTime: 'Automatic screen saver time',
+    displayDeviceSn: 'Display SN',
+    displayIp: 'Display IP',
+    displayIdentityCard: 'Display Cloud Certificate',
+    volume: 'Volume',
+    language: 'Language',
+    displayCode: "Display the mini-program code",
+    themeMode: "Work theme",
+    cn: 'Chinese',
+    en: 'English',
+    es: 'Spanish',
+    fr: 'French',
+    de: 'German',
+    ru: 'Russian',
+    ar: 'Arabic',
+    pt: 'Port.',
+    ko: 'Korean',
+    standardMode: 'Standard Mode',
+    simpleMode: 'Simple Mode',
+    firstLogin: 'This is my first time logging into the backend',
+    backlight: 'Screen backlight',
+    brightness: 'White fill light',
+    nirBrightness: 'Infrared supplementary light',
+    never: 'Never',
+    min1: '1 Min',
+    min2: '2 Min',
+    min3: '3 Min',
+    min4: '4 Min',
+    min5: '5 Min',
+    // 缃戠粶閰嶇疆
+    networkConfiguration: 'Network configuration',
+    otherConfiguration: 'Other configurations',
+    ipConfiguration: 'IP configuration',
+    devicePassword: 'Device password ',
+    protocolPassword: 'Communication protocol password',
+    networkType: 'Network type ',
+    ethernet: 'Ethernet',
+    wifiName: 'Wi-Fi name',
+    wifiPassword: 'Wi-Fi password',
+    dhcpModeSelection: 'DHCP mode',
+    dhcpMode: 'Automatic acquisition',
+    customNetworkConfiguration: 'Manual configuration',
+    ipAddress: 'IP address',
+    gateway: 'Gateway',
+    subnetMask: 'Subnet mask',
+    dnsServer: 'DNS server',
+    mac: 'Mac address',
+    // MQTT閰嶇疆
+    mqttRelatedConfiguration: 'MQTT configuration',
+    mqttConnectionInformation: 'MQTT connection information',
+    sessionConfiguration: 'Session configuration',
+    serverAddress: 'Server address',
+    clientID: 'Client ID',
+    userName: 'User name',
+    userPassword: 'User password',
+    topicPrefix: 'Theme prefix',
+    onlineChecking: 'Online verification',
+    onlineCheckingTimeout: "Online verification timeout",
+    cleanSession: 'Clear the session',
+    clientIdSuffix: 'ClientId suffix',
+    willTopic: 'WillTopic',
+    enterpriseWechat:'The Enterprise wechat mode is ineffective',
+    // 浜鸿劯閰嶇疆
+    faceRelatedConfiguration: 'Face configuration',
+    functionalInformation: 'Functional information',
+    prompt: 'Prompt',
+    faceSimilarityThreshold: 'Face similarity threshold',
+    livenessDetectionFunction: 'Live detection function',
+    livenessDetectionThreshold: 'Live detection threshold',
+    infraredImageDisplay: "Infrared image display",
+    maskRecognition: "Mask recognition",
+    strangerVoice: "Stranger's voice",
+    voiceMode: "Voice mode",
+    voiceModeDate: 'Customized greeting',
+    imageSaveType: "Image saving type",
+    saveStrangerImage: "Save images of strangers",
+    fullView: "Panoramic view",
+    face: "Face",
+    broadcastPleaseRegisterFirst: 'Play please register for a facial recognition voucher',
+    broadcastHelloStranger: 'Play unregistered personnel',
+    broadcastName: 'Play the name',
+    broadcastGreeting: 'Play a custom greeting',
+    greeting: 'Greeting',
+    broadcastWelcome: 'Play welcome',
+    recognitionSwitch: 'Re-detection switch',
+    // 绯荤粺閰嶇疆
+    systemRelatedConfiguration: 'System configuration',
+    functionSwitch: 'Function switch',
+    cardSwipingSwitch: 'Card swiping switch',
+    passwordSwitch: 'Password switch',
+    cloudCertificateSwitch: 'Cloud Certificate switch',
+    strangerImage: 'Stranger save picture switch',
+    physicalCardNumber: 'Physical card number',
+    cloudCertificateAcquisition: 'Cloud Certificate Acquisition',
+    heartbeatConfig: 'Heartbeat config',
+    heartbeatSwitch: 'Heartbeat switch',
+    heartRateInterval: 'Heart rate interval',
+    heartbeatTopic: 'Heartbeat Topic',
+    heartbeatContent: 'Heartbeat content',
+    basicInformation: 'Basic information',
+    deviceMac: 'Device Mac',
+    uuid: 'UUID',
+    sn: 'SN',
+    model: 'Model',
+    version: "Version",
+    appVersion: "Firmware version",
+    releaseTime: "Update time",
+    totaldisk: 'Total storage space',
+    freedisk: 'Remaining space',
+    // 閫氳閰嶇疆
+    passageConfiguration: 'Passage configuration',
+    functionConfiguration: 'Function Configuration',
+    numberOfPassageRecords: 'The maximum number of passage records',
+    durationOfRelayOpening: 'Duration of relay opening',
+    alarmSwitch: 'Alarm switch',
+    fireAlarmSwitch: 'Fire alarm switch',
+    fireAlarmStatus: 'Fire alarm status',
+    normal: 'Normal',
+    warning: 'Warning',
+    tamperSwitch: 'Tamper switch',
+    uploadToCloudSwitch: 'Face upload switch',
+    // 鏃堕挓閰嶇疆
+    clockConfiguration: 'Clock configuration',
+    timeSynchronizationSwitch: 'Time synchronization switch',
+    timeSynchronizationServerIP: 'Time synchronization server IP',
+    timedSynchronizationTime: 'Timed synchronization time',
+    timeZone: 'Time zone',
+    setDeviceTime: 'Set device time',
+    restartAfterSetting: 'After setting, the device will automatically restart',
+    // 浜戣瘉婵�娲�
+    cloudCertificateActivation: 'Cloud Certificate Activation',
+    activationKey: 'Activation key',
+    cloudTips1: 'Please enter the activation key and make sure there are no Spaces',
+    cloudTips2: 'After successful activation, the device will connect to the cloud authentication service',
+    confirmActivation: 'Confirm activation',
+    activationInProgress: 'Activation in progress...',
+    activationFailed: 'Activation failed',
+    activationSuccessful: 'Activation successful',
+    // 瀵嗙爜淇敼
+    passwordModification: 'Password modification',
+    password: 'Password',
+    oldPassword: 'Old password',
+    newPassword: 'New password',
+    confirmPassword: 'Confirm password',
+    passwordRule: 'Password rule recommendation',
+    passwordLength: 'Length 鈮�6',
+    cannotBeTheSame: 'All characters cannot be the same',
+    cannotOrder: 'It cannot contain at least three consecutive numbers or sequences of lowercase letters (in ascending or descending order).',
+    cannotWeakPassword: 'It cannot be common weak passwords, including',
+    submit: 'Submit',
+    saveConfig: 'Save config',
+    msg_please_enter: 'Please enter the content',
+    msg_inputPassword: 'Please enter the password.',
+    msg_oldPasswordError: 'The old password is incorrect',
+    msg_password_mismatch: 'The passwords entered twice are inconsistent',
+    msg_password_min_length: 'The password length should be at least 6 characters',
+    msg_is_weak_password: 'This is a weak password. Please reset it',
+    msg_pswChangeSuccessAndLogin: 'Your password has been modified successfully. Please log in again',
+    msg_pswChangeSuccess: 'The password has been modified successfully.',
+    msg_pswChangeFail: 'Password modification failed.',
+    msg_saveSuccess: 'Saved successfully',
+    msg_saveFail: 'Save failed',
+    msg_formFilled: 'Please check whether the form is filled out correctly',
+    msg_number_0_23: 'Only supports 0 to 23',
+    msg_number_0_24: 'Only supports 0 to 24',
+    msg_noChange: 'No configuration changes need to be saved',
+    // Resource configuration
+    resourceConfiguration: 'Resource configuration',
+    backgroundImage: 'Background image',
+    selectImage: 'Select image',
+    uploadBackground: 'Upload background',
+    uploading: 'Uploading...',
+    backgroundUploadTip: 'Please upload a PNG image with pixel size of {n}. The image will be converted to Base64 format and then uploaded to the device',
+    backgroundResolutionMismatch: 'Image resolution must be {n}',
+    backgroundRequired: 'Please select a background image first',
+    backgroundImageOnlyPNG: 'Please upload a PNG image',
+    backgroundSizeLimit: 'Image size cannot exceed 5MB',
+    backgroundParseFailed: 'Failed to read image, please retry',
+    backgroundImageSelected: 'Image selected successfully',
+    backgroundSuccess: 'Background uploaded successfully',
+    backgroundFailed: 'Background upload failed',
+    scanSettings: 'Scan Settings',
+    scanSwitch: 'Scan Switch',
+    scanInterval: 'Scan Interval',
+  },
+  // 浜哄憳璁剧疆 
+  person: {
+    idCard: 'Id number',
+    userType: 'Type',
+    userId: 'ID',
+    name: 'name',
+    user: 'User',
+    administrator: 'Administrator',
+    voucher: 'Voucher',
+    permission: 'Permission',
+    placeholderUserId: 'Please enter the userId',
+    placeholderName: 'Please enter the name',
+    addUser: 'Add user',
+    editUser: 'Edit user',
+    userNotExist: 'The personnel do not exist',
+    oneClickClear: 'One-click clear',
+    clearTips: 'This operation will permanently delete all personnel, credentials and permission data. Do you want to continue?',
+    clearSuccess: 'Cleared successfully',
+    clearFailed: 'Failed to clear',
+  },
+  voucher: {
+    password: 'Password',
+    card: 'Card',
+    face: 'Face',
+    finger: 'Finger',
+    code: 'Code',
+    codeType: 'Code Type',
+    passthroughCode: 'Passthrough Code',
+    staticCode: 'Static Code',
+    dynamicCode: 'Dynamic Code',
+    credentialId: 'Credential ID',
+    credentialValue: 'Credential Value',
+    placeholderCode: 'Please enter code certificate',
+    placeholderPwd: 'Please enter the password credential',
+    placeholderCard: 'Please enter the card voucher',
+    validPassword: 'Please enter six digits',
+    validCard: 'Please enter 8 digits or letters',
+    photoRegistration: 'Photo registration',
+    featureValueRegistration: 'Feature value registration',
+    fingerRegistration: 'Finger registration',
+    fingerFeatureRegistration: 'Feature value registration',
+    fingerInput: 'Please put your finger on the fingerprint scanner',
+    fingerRemainingTime: 'Remaining time',
+    fingerInputting: 'Inputting...',
+    startFingerInput: 'Start inputting fingerprint',
+    fingerInputTips: 'Please enter the fingerprint feature value',
+    fingerWaitInput: 'Waiting for input',
+    fingerInputNow: 'Inputting fingerprint...',
+    fingerInputSuccess: 'Input success',
+    fingerInputFailed: 'Finger input failed',
+    fingerReTry: 'Finger input failed, please try again',
+    fingerFilled: 'Finger input success, feature value has been automatically filled',
+    fingerFailed: 'Finger input failed',
+    fingerTimeout: 'Input timeout',
+    fingerInputTimeout: 'Finger input timeout, please try again',
+    fingerError: 'Input failed',
+    fingerInputError: 'Finger input failed, please try again',
+    fingerInputed: 'Fingerprint has been entered',
+    fingerReInput: 'Re enter fingerprint',
+  },
+
+  permission: {
+    deletePermission: 'Delete permission',
+    addPermission: 'Add permissions',
+    permissionId: 'Permission ID',
+    userId: 'User ID',
+    timeRange: 'Time interval',
+    extra: 'Extra',
+    effectiveType: 'Effective Type',
+    effectiveTime: 'Effective Time',
+    effectiveWeek: 'Effective Week',
+    timePeriod: 'Time period',
+    addTimePeriod: 'Add a time period',
+    modify_previous_time: 'Please modify the previously added time period first',
+    cannot_be_earlier: 'The end time must not be less than the start time',
+    times_cannot_overlap: 'The selected times cannot overlap',
+    choose_time_range: 'Please select the effective time range',
+    unlimitedMode: 'Unlimited mode',
+    usualMode: 'Usual mode',
+    dailyMode: 'Daily mode',
+    weeklyRepetitionMode: 'Weekly repetition mode',
+    time_range: 'Time range',
+  },
+
+  common: {
+    startDate: 'Start date',
+    endDate: 'End date',
+    to: 'to',
+    cancel: 'Cancel',
+    confirm: 'Confirm',
+    close: 'Close',
+    delete: 'Delete',
+    edit: 'Edit',
+    batchDelete: 'Batch Delete',
+    startTime: 'Start time',
+    endTime: 'End time',
+    monday: 'Monday',
+    tuseday: 'Tuseday',
+    wednesday: 'Wednesday',
+    thursday: 'Thursday',
+    friday: 'Friday',
+    saterday: 'Saterday',
+    sunday: 'Sunday',
+    placeholder: 'Please enter',
+    placeholderSelect: 'Please select',
+    closeTips: 'Is it confirmed to be closed?',
+    deleteTips: 'Are you sure to delete it?',
+    deleteSuccess: 'Deleted successfully',
+    addSuccess: 'Added successfully',
+    editSuccess: 'Edited successfully',
+    saveSuccess: 'Saved successfully',
+    tips: 'Tips',
+    operation: 'Operation',
+    query: 'Query',
+    reset: 'Reset',
+    noData: 'No data available for the time being.',
+    export: 'Export',
+    success: 'success',
+    failure: 'failure',
+    incorrectFormat: 'Incorrect format',
+    integerFormat: 'Should be an integer greater than or equal to 0',
+    positiveIntegerFormat: 'Should be an integer greater than 0',
+    noDataSaved: 'No data needs to be saved',
+    chinese: 'Chinese',
+    english: 'English',
+    spanish: 'Spanish',
+    french: 'French',
+    german: 'German',
+    russian: 'Russian',
+    arabic: 'Arabic',
+    portuguese: 'Portuguese',
+    korean: 'Korean',
+    detail: 'Detail',
+    clearTips: 'Confirm clear?',
+    clearSuccess: 'Cleared successfully',
+  },
+
+  log: {
+    accessMethod: 'Access method',
+    passingTime: 'Passing time',
+    accessPass: 'Access pass',
+    accessResult: 'Access result',
+    accessPhoto: 'Access photo',
+    viewPhotos: 'View photos'
+  },
+
+  error: {
+    networkError: 'Network request failed, please check your connection',
+    timeout: 'Request timeout, please check your network or try again later',
+    serverError: 'Server internal error, please try again later',
+    notFound: 'Requested resource does not exist',
+    unauthorized: 'Unauthorized, please login again',
+    noResponse: 'Unable to connect to server, please check network or server status',
+    unknownError: 'Request failed, error code:',
+    requestFailed: 'Request failed'
+  },
+  
+  security: {
+    keyId: 'Key ID',
+    keyType: 'Key Type',
+    keyEncoding: 'Key Encoding',
+    keyValue: 'Key Value',
+    startTime: 'Start Time',
+    expirationTime: 'Expiration Time',
+    newKey: 'Add Key',
+    clearKey: 'Clear Key',
+    validTime: 'Valid Time',
+  }
+}
\ No newline at end of file
diff --git "a/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/language/es.js" "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/language/es.js"
new file mode 100644
index 0000000..7243d06
--- /dev/null
+++ "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/language/es.js"
@@ -0,0 +1,452 @@
+
+export default {
+  // Inicio de sesi贸n
+  login: {
+    lang: 'Idioma',
+    systemname: 'Login Facial',
+    username: 'Usuario',
+    username_label: 'Por favor ingrese el usuario',
+    pwd: 'Contrase帽a',
+    pwd_label: 'Por favor ingrese la contrase帽a',
+    pwd_info: 'Ingrese el formato correcto de contrase帽a',
+    success_msg: 'Inicio de sesi贸n exitoso',
+    error_name: 'Contrase帽a incorrecta',
+    error_res: 'No cumple con los requisitos de inicio de sesi贸n',
+    login: 'Iniciar sesi贸n',
+  },
+  // Barra lateral
+  aside: {
+    systemname: 'Panel Facial',
+    quit: 'Salir',
+    deviceControl: 'Control',
+    basicSetting: 'Config.',
+    workerSetting: 'Personal',
+    deviceMonitoring: 'Monitor',
+    recordManagement: 'Registros',
+    securityManagement: 'La clave',
+    tips: 'Aviso',
+    tips_msg: '驴Desea cerrar sesi贸n?',
+  },
+  // Control de dispositivo
+  control: {
+    remoteControl: 'Remoto',
+    restart: 'Reiniciar',
+    clickToRestart: 'Clic para reiniciar',
+    restartConfirm: '驴Seguro que desea reiniciar?',
+    restartSuccess: 'Reinicio exitoso',
+    restartFailed: 'Reinicio fallido',
+    remoteOpen: 'Abrir puerta de forma remota',
+    clickToOpen: 'Clic para abrir',
+    openConfirm: '驴Seguro que desea abrir remotamente?',
+    remoteOpenSuccess: 'Apertura exitosa',
+    remoteOpenFailed: 'Apertura fallida',
+    reset: 'Restablecer dispositivo',
+    clickToReset: 'Clic para restablecer',
+    resetConfirm: '驴Seguro que desea restablecer?',
+    resetWillOut: "Reinicio = cierre sesi贸n",
+    resetSuccess: 'Restablecimiento exitoso',
+    resetFailed: 'Restablecimiento fallido',
+    firmwareUpgrade: 'Actualizaci贸n de firmware',
+    upgradeConfig: 'Config. de actualizaci贸n',
+    firmwareUrl: 'URL del firmware',
+    md5Checksum: 'Valor md5',
+    startUpgrade: 'Iniciar actualizaci贸n',
+    urlRequired: 'La URL es obligatoria',
+    md5Required: 'El md5 es obligatorio',
+    urlInvalid: 'Ingrese una URL v谩lida',
+    md5Invalid: 'Ingrese un md5 v谩lido',
+    upgradeConfirm: '驴Confirmar actualizaci贸n?',
+    upgradeSuccess: 'Actualizaci贸n exitosa',
+    clearFile: "Borrar archivo",
+    uploading: 'Subiendo...',
+    uploadAndUpgrade: 'Subir y actualizar',
+    restartTips: 'Reinicio seguro, no se perder谩n datos',
+    restarting: 'Reiniciando...',
+    remoteTips: 'Control remoto de acceso',
+    opening: 'Abriendo...',
+    resetTips: 'Restaurar de f谩brica, borrar谩 datos',
+    reseting: 'Restableciendo...',
+    urlUpgrade: 'Actualizaci贸n por URL',
+    fileUpgrade: 'Subida de archivo',
+    uploadFile: 'Clic para subir firmware',
+    formatFile: 'Soporta .zip o .dpk, m谩x 20MB',
+    fileName: 'Nombre',
+    size: 'Tama帽o',
+  },
+  // Configuraci贸n
+  config: {
+    second: 's',
+    millisecond: 'ms',
+    min: 'minutos',
+    notsave: 'No guardar',
+    save: 'Guardar',
+    noVoice: 'Sin voz',
+    no: 'No',
+    yes: 'S铆',
+    // B谩sico
+    basicConfiguration: 'Configuraci贸n b谩sica',
+    displaySettings: 'Pantalla',
+    informationDisplay: 'Mostrar informaci贸n',
+    audioSettings: 'Audio',
+    languageAndThemes: 'Idioma y tema',
+    autoAdjustScreenBrightness: 'Brillo autom谩tico',
+    screenBrightness: 'Brillo de pantalla',
+    autoTurnOffScreen: 'Apagado autom谩tico',
+    autoTurnOffScreenTime: 'Tiempo de apagado',
+    autoScreenSaver: 'Salvapantallas autom谩tico',
+    autoScreenSaverTime: 'Tiempo de salvapantallas',
+    displayDeviceSn: 'Mostrar SN',
+    displayIp: 'Mostrar IP',
+    displayIdentityCard: 'Mostrar credencial en la nube',
+    volume: 'Volumen',
+    language: 'Idioma',
+    displayCode: "Mostrar c贸digo de miniapp",
+    themeMode: "Tema",
+    cn: 'Chino',
+    en: 'Ingl茅s',
+    es: 'Espa帽ol',
+    fr: 'Franc茅s',
+    de: 'Alem谩n',
+    ru: 'Ruso',
+    ar: '脕rabe',
+    pt: 'Port.',
+    ko: 'Coreano',
+    standardMode: 'Modo est谩ndar',
+    simpleMode: 'Modo simple',
+    firstLogin: 'Primer inicio de sesi贸n',
+    backlight: 'Luz de fondo',
+    brightness: 'Luz blanca',
+    nirBrightness: 'Luz IR',
+    never: 'Nunca',
+    min1: '1 minuto',
+    min2: '2 minutos',
+    min3: '3 minutos',
+    min4: '4 minutos',
+    min5: '5 minutos',
+    // Red
+    networkConfiguration: 'Red',
+    otherConfiguration: 'Otros',
+    ipConfiguration: 'IP',
+    devicePassword: 'Contrase帽a del dispositivo',
+    protocolPassword: 'Contrase帽a de protocolo',
+    networkType: 'Tipo de red',
+    ethernet: 'Ethernet',
+    wifiName: 'Wi鈥慒i',
+    wifiPassword: 'Contrase帽a Wi鈥慒i',
+    dhcpModeSelection: 'Modo DHCP',
+    dhcpMode: 'Autom谩tico',
+    customNetworkConfiguration: 'Manual',
+    ipAddress: 'IP',
+    gateway: 'Puerta de enlace',
+    subnetMask: 'M谩scara de subred',
+    dnsServer: 'DNS',
+    mac: 'MAC de red',
+    // MQTT
+    mqttRelatedConfiguration: 'MQTT',
+    mqttConnectionInformation: 'Conexi贸n MQTT',
+    sessionConfiguration: 'Sesi贸n',
+    serverAddress: 'Servidor',
+    clientID: 'ID de cliente',
+    userName: 'Usuario',
+    userPassword: 'Contrase帽a',
+    topicPrefix: 'Prefijo de tema',
+    onlineChecking: 'Verificaci贸n en l铆nea',
+    onlineCheckingTimeout: "Tiempo de espera",
+    cleanSession: 'Limpiar sesi贸n',
+    clientIdSuffix: 'Sufijo de ID',
+    willTopic: 'Tema de voluntad',
+    enterpriseWechat:'Modo WeChat Enterprise sin efecto',
+    // Rostro
+    faceRelatedConfiguration: 'Configuraci贸n facial',
+    functionalInformation: 'Funci贸n',
+    prompt: 'Mensaje',
+    faceSimilarityThreshold: 'Umbral de similitud',
+    livenessDetectionFunction: 'Detecci贸n de vivacidad',
+    livenessDetectionThreshold: 'Umbral de vivacidad',
+    infraredImageDisplay: "Mostrar infrarrojo",
+    maskRecognition: "Reconocer mascarilla",
+    strangerVoice: "Voz de desconocido",
+    voiceMode: "Modo de voz",
+    voiceModeDate: 'Saludo personalizado',
+    imageSaveType: "Tipo de guardado",
+    saveStrangerImage: "Guardar imagen de desconocido",
+    fullView: "Panor谩mica",
+    face: "Rostro",
+    broadcastPleaseRegisterFirst: 'Reproducir 鈥淩egistre primero鈥�',
+    broadcastHelloStranger: 'Reproducir 鈥淒esconocido鈥�',
+    broadcastName: 'Reproducir nombre',
+    broadcastGreeting: 'Reproducir saludo personalizado',
+    greeting: 'Saludo',
+    broadcastWelcome: 'Reproducir "Bienvenido"',
+    recognitionSwitch: 'Interruptor de re-detecci贸n',
+    // Sistema
+    systemRelatedConfiguration: 'Sistema',
+    functionSwitch: 'Interruptores',
+    cardSwipingSwitch: 'Tarjeta',
+    passwordSwitch: 'Contrase帽a',
+    strangerImage: 'Imagen de desconocido',
+    cloudCertificateSwitch: 'Certificado en la nube',
+    physicalCardNumber: 'N煤mero de tarjeta f铆sica',
+    cloudCertificateAcquisition: 'Obtenci贸n de certificado en la nube',
+    heartbeatConfig: 'Heartbeat',
+    heartbeatSwitch: 'Heartbeat on/off',
+    heartRateInterval: 'Intervalo',
+    heartbeatTopic: 'Tema heartbeat',
+    heartbeatContent: 'Contenido',
+    basicInformation: 'Informaci贸n b谩sica',
+    deviceMac: 'MAC',
+    uuid: 'UUID',
+    sn: 'SN',
+    model: 'Modelo',
+    version: "Versi贸n",
+    appVersion: "Versi贸n de firmware",
+    releaseTime: "Hora de actualizaci贸n",
+    totaldisk: 'Espacio total',
+    freedisk: 'Espacio restante',
+    // Paso
+    passageConfiguration: 'Paso',
+    functionConfiguration: 'Funciones',
+    numberOfPassageRecords: 'M谩x. registros',
+    durationOfRelayOpening: 'Duraci贸n del rel茅',
+    alarmSwitch: 'Alarma',
+    fireAlarmSwitch: 'Alarma de incendios',
+    fireAlarmStatus: 'Estado de incendios',
+    normal: 'Normal',
+    warning: 'Aviso',
+    tamperSwitch: 'Antimanipulaci贸n',
+    uploadToCloudSwitch: 'Interruptor de carga facial',
+    // Reloj
+    clockConfiguration: 'Reloj',
+    timeSynchronizationSwitch: 'Sincronizaci贸n horaria',
+    timeSynchronizationServerIP: 'Servidor de tiempo',
+    timedSynchronizationTime: 'Hora de sincronizaci贸n',
+    timeZone: 'Zona horaria',
+    setDeviceTime: 'Configurar hora',
+    restartAfterSetting: 'El dispositivo se reiniciar谩',
+    // Activaci贸n de certificado en la nube
+    cloudCertificateActivation: 'Activaci贸n de certificado',
+    activationKey: 'Clave de activaci贸n',
+    cloudTips1: 'Ingrese la clave sin espacios',
+    cloudTips2: 'Tras activar, conectar谩 al servicio de autenticaci贸n',
+    confirmActivation: 'Confirmar activaci贸n',
+    activationInProgress: 'Activando...',
+    activationFailed: 'Activaci贸n fallida',
+    activationSuccessful: 'Activaci贸n exitosa',
+    // Cambio de contrase帽a
+    passwordModification: 'Cambiar contrase帽a',
+    password: 'Contrase帽a',
+    oldPassword: 'Contrase帽a anterior',
+    newPassword: 'Nueva contrase帽a',
+    confirmPassword: 'Confirmar contrase帽a',
+    passwordRule: 'Recomendaci贸n de contrase帽a',
+    passwordLength: 'Longitud 鈮�6',
+    cannotBeTheSame: 'No puede ser todos los caracteres iguales',
+    cannotOrder: 'No incluir 3+ n煤meros/letras consecutivos',
+    cannotWeakPassword: 'No usar contrase帽as d茅biles comunes',
+    submit: 'Enviar',
+    saveConfig: 'Guardar',
+    // Mensajes
+    msg_please_enter: 'Ingrese contenido',
+    msg_inputPassword: 'Ingrese contrase帽a',
+    msg_oldPasswordError: 'Contrase帽a anterior incorrecta',
+    msg_password_mismatch: 'Las contrase帽as no coinciden',
+    msg_password_min_length: 'M铆nimo 6 caracteres',
+    msg_is_weak_password: 'Contrase帽a d茅bil, cambie',
+    msg_pswChangeSuccessAndLogin: 'Cambio exitoso, inicie sesi贸n',
+    msg_pswChangeSuccess: 'Cambio de contrase帽a exitoso',
+    msg_pswChangeFail: 'Cambio de contrase帽a fallido',
+    msg_saveSuccess: 'Guardado exitoso',
+    msg_saveFail: 'Guardado fallido',
+    msg_formFilled: 'Revise el formulario',
+    msg_number_0_23: 'Solo 0-23',
+    msg_number_0_24: 'Solo 0-24',
+    msg_noChange: 'No hay cambios de configuraci贸n para guardar',
+    // Configuraci贸n de recursos
+    resourceConfiguration: 'Configuraci贸n de recursos',
+    backgroundImage: 'Imagen de fondo',
+    selectImage: 'Seleccionar imagen',
+    uploadBackground: 'Subir fondo',
+    uploading: 'Subiendo...',
+    backgroundUploadTip: 'Suba una imagen PNG; se convertir谩 a Base64 y se enviar谩 al dispositivo',
+    backgroundResolutionMismatch: 'La resoluci贸n de la imagen debe ser {n}',
+    backgroundRequired: 'Seleccione una imagen de fondo',
+    backgroundImageOnlyPNG: 'Solo im谩genes PNG',
+    backgroundSizeLimit: 'La imagen no debe exceder 5MB',
+    backgroundParseFailed: 'Error al leer imagen, reintente',
+    backgroundImageSelected: 'Imagen seleccionada',
+    backgroundSuccess: 'Fondo subido',
+    backgroundFailed: 'Error al subir fondo',
+    scanSettings: 'Configuraci贸n de escaneo',
+    scanSwitch: 'Interruptor de Escaneo',
+    scanInterval: 'Intervalo de escaneo',
+  },
+  // Gesti贸n de personal
+  person: {
+    idCard: 'N煤mero de ID',
+    userType: 'Tipo de persona',
+    administrator: 'Administrador',
+    userId: 'ID',
+    user: 'Usuario',
+    voucher: 'Credencial',
+    permission: 'Permiso',
+    addUser: 'A帽adir persona',
+    name: 'Nombre',
+    editUser: 'Editar persona',
+    placeholderUserId: 'Ingrese ID de usuario',
+    placeholderName: 'Ingrese nombre',
+    userNotExist: 'La persona no existe',
+    oneClickClear: 'Borrar todo',
+    clearTips: 'Se borrar谩n todos los datos, 驴continuar?',
+    clearSuccess: 'Borrado exitoso',
+    clearFailed: 'Borrado fallido',
+  },
+  voucher: {
+    password: 'Contrase帽a',
+    card: 'Tarjeta',
+    face: 'Rostro',
+    finger: 'Huella',
+    code: 'C贸digo',
+    codeType: 'Tipo de c贸digo',
+    passthroughCode: 'C贸digo de paso',
+    staticCode: 'C贸digo est谩tico',
+    dynamicCode: 'C贸digo din谩mico',
+    credentialId: 'ID de credencial',
+    credentialValue: 'Valor de credencial',
+    placeholderCode: 'Por favor ingrese certificado de c贸digo',
+    placeholderPwd: 'Ingrese la credencial de contrase帽a',
+    placeholderCard: 'Ingrese la credencial de tarjeta',
+    validPassword: 'Ingrese 6 d铆gitos',
+    validCard: 'Ingrese 8 d铆gitos o letras',
+    photoRegistration: 'Registro de foto',
+    featureValueRegistration: 'Registro de rasgos',
+    fingerRegistration: 'Registro de huella',
+    fingerFeatureRegistration: 'Registro por valor de caracter铆stica',
+    fingerInput: 'Coloque el dedo en el lector de huellas',
+    fingerRemainingTime: 'Tiempo restante',
+    fingerInputting: 'Registrando...',
+    startFingerInput: 'Iniciar registro de huella',
+    fingerInputTips: 'Ingrese el valor de caracter铆stica de la huella',
+    fingerWaitInput: 'En espera de registro',
+    fingerInputNow: 'Registrando huella...',
+    fingerInputSuccess: 'Registro exitoso',
+    fingerInputFailed: 'No se pudo iniciar el registro de huella',
+    fingerReTry: 'Fallo en el registro de huella, int茅ntelo de nuevo',
+    fingerFilled: 'Registro de huella exitoso, el valor de caracter铆stica se ha rellenado autom谩ticamente',
+    fingerFailed: 'Fallo en el registro de huella',
+    fingerTimeout: 'Tiempo de espera agotado',
+    fingerInputTimeout: 'Tiempo de espera del registro de huella, int茅ntelo de nuevo',
+    fingerError: 'Registro fallido',
+    fingerInputError: 'Fallo en el registro de huella, int茅ntelo de nuevo',
+    fingerInputed: 'Huella registrada',
+    fingerReInput: 'Volver a registrar la huella',
+  },
+
+  permission: {
+    deletePermission: 'Eliminar permiso',
+    addPermission: 'A帽adir permiso',
+    permissionId: 'ID de permiso',
+    userId: 'ID de usuario',
+    timeRange: 'Intervalo de tiempo',
+    extra: 'Extra',
+    effectiveType: 'Tipo de vigencia',
+    effectiveTime: 'Tiempo efectivo',
+    effectiveWeek: 'Semana efectiva',
+    timePeriod: 'Periodo',
+    addTimePeriod: 'A帽adir periodo',
+    modify_previous_time: 'Primero modifique el periodo previo',
+    cannot_be_earlier: 'La hora final no puede ser menor que la inicial',
+    times_cannot_overlap: 'Los tiempos no pueden superponerse',
+    choose_time_range: 'Seleccione rango de tiempo',
+    unlimitedMode: 'Sin l铆mite',
+    usualMode: 'Modo habitual',
+    dailyMode: 'Modo diario',
+    weeklyRepetitionMode: 'Repetici贸n semanal',
+    time_range: 'Rango',
+  },
+
+  common: {
+    startDate: 'Fecha inicio',
+    endDate: 'Fecha fin',
+    to: 'a',
+    cancel: 'Cancelar',
+    confirm: 'Confirmar',
+    close: 'Cerrar',
+    delete: 'Eliminar',
+    edit: 'Editar',
+    batchDelete: 'Eliminaci贸n masiva',
+    startTime: 'Hora inicio',
+    endTime: 'Hora fin',
+    monday: 'Lunes',
+    tuseday: 'Martes',
+    wednesday: 'Mi茅rcoles',
+    thursday: 'Jueves',
+    friday: 'Viernes',
+    saterday: 'S谩bado',
+    sunday: 'Domingo',
+    placeholder: 'Por favor ingrese',
+    placeholderSelect: 'Por favor seleccione',
+    closeTips: '驴Confirmar cierre?',
+    deleteTips: '驴Confirmar eliminaci贸n?',
+    deleteSuccess: 'Eliminado con 茅xito',
+    addSuccess: 'A帽adido con 茅xito',
+    editSuccess: 'Editado con 茅xito',
+    saveSuccess: 'Guardado con 茅xito',
+    tips: 'Aviso',
+    operation: 'Operaci贸n',
+    query: 'Consulta',
+    reset: 'Reset',
+    noData: 'Sin datos por ahora',
+    export: 'Exportar',
+    success: '脡xito',
+    failure: 'Fallo',
+    incorrectFormat: 'Formato incorrecto',
+    integerFormat: 'Debe ser entero 鈮�0',
+    positiveIntegerFormat: 'Debe ser entero >0',
+    noDataSaved: 'No hay datos para guardar',
+    chinese: 'Chino',
+    english: 'Ingl茅s',
+    spanish: 'Espa帽ol',
+    french: 'Franc茅s',
+    german: 'Alem谩n',
+    russian: 'Ruso',
+    arabic: '脕rabe',
+    portuguese: 'Portugu茅s',
+    korean: 'Coreano',
+    detail: 'Detalle',
+    clearTips: '驴Confirmar borrado?',
+    clearSuccess: 'Borrado exitosamente',
+  },
+
+  log: {
+    accessMethod: 'M茅todo de acceso',
+    passingTime: 'Hora de paso',
+    accessPass: 'Credencial de paso',
+    accessResult: 'Resultado',
+    accessPhoto: 'Foto',
+    viewPhotos: 'Ver fotos'
+  },
+
+  error: {
+    networkError: 'Error de red, verifique su conexi贸n',
+    timeout: 'Tiempo de espera agotado, reintente',
+    serverError: 'Error interno del servidor, reintente',
+    notFound: 'El recurso no existe',
+    unauthorized: 'No autorizado, inicie sesi贸n',
+    noResponse: 'No hay respuesta del servidor',
+    unknownError: 'Error de solicitud, c贸digo:',
+    requestFailed: 'Solicitud fallida'
+  },
+
+  security: {
+    keyId: 'ID de clave',
+    keyType: 'Tipo de clave',
+    keyEncoding: 'Codificaci贸n de clave',
+    keyValue: 'Valor de clave',
+    startTime: 'Hora de inicio',
+    expirationTime: 'Hora de expiraci贸n',
+    newKey: 'Agregar clave',
+    clearKey: 'Borrar clave',
+    validTime: 'Tiempo v谩lido',
+  }
+}
+
diff --git "a/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/language/fr.js" "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/language/fr.js"
new file mode 100644
index 0000000..bef0752
--- /dev/null
+++ "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/language/fr.js"
@@ -0,0 +1,435 @@
+export default {
+  // Connexion
+  login: {
+    lang: 'Langue',
+    systemname: 'Login Facial',
+    username: 'Utilisateur',
+    username_label: "Veuillez saisir l'utilisateur",
+    pwd: 'Mot de passe',
+    pwd_label: 'Veuillez saisir le mot de passe',
+    pwd_info: 'Entrez un mot de passe valide',
+    success_msg: 'Connexion r茅ussie',
+    error_name: 'Mot de passe incorrect',
+    error_res: "Ne r茅pond pas aux exigences de connexion",
+    login: 'Se connecter',
+  },
+  // Barre lat茅rale
+  aside: {
+    systemname: 'Console',
+    quit: 'Quitter',
+    deviceControl: 'Contr么le',
+    basicSetting: 'R茅glages',
+    workerSetting: 'Personnel',
+    deviceMonitoring: 'Surveillance',
+    recordManagement: 'Journal',
+    securityManagement: 'Des cl茅s',
+    tips: 'Conseil',
+    tips_msg: 'Voulez-vous vous d茅connecter ?',
+  },
+  // Contr么le
+  control: {
+    remoteControl: 'Distance',
+    restart: 'Red茅marrer',
+    clickToRestart: 'Cliquer pour red茅marrer',
+    restartConfirm: 'Confirmer le red茅marrage ?',
+    restartSuccess: 'Red茅marrage r茅ussi',
+    restartFailed: 'Red茅marrage 茅chou茅',
+    remoteOpen: 'Ouverture 脿 distance',
+    clickToOpen: 'Cliquer pour ouvrir',
+    openConfirm: "Confirmer l'ouverture 脿 distance ?",
+    remoteOpenSuccess: 'Ouverture r茅ussie',
+    remoteOpenFailed: "Ouverture 茅chou茅e",
+    reset: 'R茅initialiser',
+    clickToReset: 'Cliquer pour r茅initialiser',
+    resetConfirm: 'Confirmer la r茅initialisation ?',
+    resetWillOut: "D茅co apr猫s r茅init.",
+    resetSuccess: 'R茅initialisation r茅ussie',
+    resetFailed: 'R茅initialisation 茅chou茅e',
+    firmwareUpgrade: 'Mise 脿 jour du firmware',
+    upgradeConfig: 'Config. mise 脿 jour',
+    firmwareUrl: 'URL du firmware',
+    md5Checksum: 'Valeur md5',
+    startUpgrade: 'D茅marrer la mise 脿 jour',
+    urlRequired: "L'URL est requise",
+    md5Required: 'Le md5 est requis',
+    urlInvalid: 'Entrez une URL valide',
+    md5Invalid: 'Entrez un md5 valide',
+    upgradeConfirm: 'Confirmer la mise 脿 jour ?',
+    upgradeSuccess: 'Mise 脿 jour r茅ussie',
+    clearFile: "Effacer le fichier",
+    uploading: 'T茅l茅versement...',
+    uploadAndUpgrade: 'T茅l茅verser et mettre 脿 jour',
+    restartTips: 'Red茅marrage s茅curis茅, sans perte de donn茅es',
+    restarting: 'Red茅marrage...',
+    remoteTips: 'Contr么le distant de la porte',
+    opening: 'Ouverture...',
+    resetTips: 'Restauration usine, effacera les donn茅es',
+    reseting: 'R茅initialisation...',
+    urlUpgrade: 'Mise 脿 jour par URL',
+    fileUpgrade: 'Mise 脿 jour par fichier',
+    uploadFile: 'Cliquez pour t茅l茅verser le firmware',
+    formatFile: 'Supporte .zip ou .dpk, max 20MB',
+    fileName: 'Nom du fichier',
+    size: 'Taille',
+  },
+  // Configuration
+  config: {
+    second: 's',
+    millisecond: 'ms',
+    min: 'minutes',
+    notsave: 'Ne pas enregistrer',
+    save: 'Enregistrer',
+    noVoice: 'Sans voix',
+    no: 'Non',
+    yes: 'Oui',
+    basicConfiguration: 'Configuration de base',
+    displaySettings: 'Affichage',
+    informationDisplay: "Affichage d'information",
+    audioSettings: 'Audio',
+    languageAndThemes: 'Langue et th猫me',
+    autoAdjustScreenBrightness: 'Luminosit茅 auto',
+    screenBrightness: 'Luminosit茅 茅cran',
+    autoTurnOffScreen: 'Extinction auto',
+    autoTurnOffScreenTime: "Temps d'extinction",
+    autoScreenSaver: '脡conomiseur auto',
+    autoScreenSaverTime: 'D茅lai 茅conomiseur',
+    displayDeviceSn: 'Afficher SN',
+    displayIp: 'Afficher IP',
+    displayIdentityCard: 'Afficher certificat cloud',
+    volume: 'Volume',
+    language: 'Langue',
+    displayCode: "Afficher code miniapp",
+    themeMode: "Th猫me",
+    cn: 'Chinois',
+    en: 'Anglais',
+    es: 'Espagnol',
+    fr: 'Fran莽ais',
+    de: 'Allemand',
+    ru: 'Russe',
+    ar: 'Arabe',
+    pt: 'Port.',
+    ko: 'Cor茅en',
+    standardMode: 'Mode standard',
+    simpleMode: 'Mode simple',
+    firstLogin: 'Premi猫re connexion',
+    backlight: 'R茅tro茅clairage',
+    brightness: 'Lumi猫re blanche',
+    nirBrightness: 'Lumi猫re IR',
+    never: 'Jamais',
+    min1: '1 minute',
+    min2: '2 minutes',
+    min3: '3 minutes',
+    min4: '4 minutes',
+    min5: '5 minutes',
+    networkConfiguration: 'R茅seau',
+    otherConfiguration: 'Autres',
+    ipConfiguration: 'Adresse IP',
+    devicePassword: 'Mot de passe appareil',
+    protocolPassword: 'Mot de passe protocole',
+    networkType: 'Type de r茅seau',
+    ethernet: 'Ethernet',
+    wifiName: 'Wi鈥慒i',
+    wifiPassword: 'Mot de passe Wi鈥慒i',
+    dhcpModeSelection: 'Mode DHCP',
+    dhcpMode: 'Automatique',
+    customNetworkConfiguration: 'Manuel',
+    ipAddress: 'IP',
+    gateway: 'Passerelle',
+    subnetMask: 'Masque',
+    dnsServer: 'DNS',
+    mac: 'MAC',
+    mqttRelatedConfiguration: 'MQTT',
+    mqttConnectionInformation: 'Connexion MQTT',
+    sessionConfiguration: 'Session',
+    serverAddress: 'Serveur',
+    clientID: 'ID client',
+    userName: "Nom d'utilisateur",
+    userPassword: 'Mot de passe',
+    topicPrefix: 'Pr茅fixe de topic',
+    onlineChecking: 'V茅rification en ligne',
+    onlineCheckingTimeout: "D茅lai d'attente",
+    cleanSession: 'Session propre',
+    clientIdSuffix: "Suffixe d'ID client",
+    willTopic: 'Topic Will',
+    enterpriseWechat:'Mode WeChat Entreprise sans effet',
+    faceRelatedConfiguration: 'Configuration faciale',
+    functionalInformation: 'Fonction',
+    prompt: 'Invite',
+    faceSimilarityThreshold: 'Seuil de similarit茅',
+    livenessDetectionFunction: 'D茅tection de vivacit茅',
+    livenessDetectionThreshold: 'Seuil de vivacit茅',
+    infraredImageDisplay: "Affichage infrarouge",
+    maskRecognition: "Reconnaissance de masque",
+    strangerVoice: "Voix d'inconnu",
+    voiceMode: "Mode voix",
+    voiceModeDate: 'Salutation personnalis茅e',
+    imageSaveType: "Type de sauvegarde",
+    saveStrangerImage: "Sauver image d'inconnu",
+    fullView: "Panorama",
+    face: "Visage",
+    broadcastPleaseRegisterFirst: 'Diffuser "Veuillez vous enregistrer"',
+    broadcastHelloStranger: 'Diffuser "Inconnu"',
+    broadcastName: 'Diffuser le nom',
+    broadcastGreeting: 'Diffuser salutation personnalis茅e',
+    greeting: 'Salutation',
+    broadcastWelcome: 'Diffuser "Bienvenue"',
+    recognitionSwitch: 'Interrupteur de re-d茅tection',
+    systemRelatedConfiguration: 'Syst猫me',
+    functionSwitch: 'Commutateurs',
+    cardSwipingSwitch: 'Carte',
+    passwordSwitch: 'Mot de passe',
+    strangerImage: 'Image inconnue',
+    cloudCertificateSwitch: 'Certificat cloud',
+    physicalCardNumber: 'Num茅ro de carte physique',
+    cloudCertificateAcquisition: 'Obtention certificat cloud',
+    heartbeatConfig: 'Heartbeat',
+    heartbeatSwitch: 'Activer heartbeat',
+    heartRateInterval: 'Intervalle',
+    heartbeatTopic: 'Topic heartbeat',
+    heartbeatContent: 'Contenu',
+    basicInformation: 'Infos de base',
+    deviceMac: 'MAC',
+    uuid: 'UUID',
+    sn: 'SN',
+    model: 'Mod猫le',
+    version: "Version",
+    appVersion: "Version firmware",
+    releaseTime: "Date de mise 脿 jour",
+    totaldisk: 'Volume total',
+    freedisk: 'Espace restant',
+    passageConfiguration: 'Passage',
+    functionConfiguration: 'Fonctions',
+    numberOfPassageRecords: 'Nb. max de passages',
+    durationOfRelayOpening: "Dur茅e d'ouverture du relais",
+    alarmSwitch: 'Alarme',
+    fireAlarmSwitch: "Alarme incendie",
+    fireAlarmStatus: '脡tat incendie',
+    normal: 'Normal',
+    warning: 'Alerte',
+    tamperSwitch: 'Anti-sabotage',
+    uploadToCloudSwitch: 'Interrupteur de t茅l茅versement facial',
+    clockConfiguration: 'Horloge',
+    timeSynchronizationSwitch: 'Synchronisation horaire',
+    timeSynchronizationServerIP: 'Serveur de temps',
+    timedSynchronizationTime: 'Heure de synchro',
+    timeZone: 'Fuseau horaire',
+    setDeviceTime: "R茅gler l'heure",
+    restartAfterSetting: "L'appareil red茅marrera",
+    cloudCertificateActivation: 'Activation du certificat',
+    activationKey: "Cl茅 d'activation",
+    cloudTips1: 'Entrez la cl茅 sans espaces',
+    cloudTips2: "Apr猫s activation, connexion au service cloud",
+    confirmActivation: "Confirmer l'activation",
+    activationInProgress: 'Activation...',
+    activationFailed: '脡chec activation',
+    activationSuccessful: 'Activation r茅ussie',
+    passwordModification: 'Modifier le mot de passe',
+    password: 'Mot de passe',
+    oldPassword: 'Ancien mot de passe',
+    newPassword: 'Nouveau mot de passe',
+    confirmPassword: 'Confirmer mot de passe',
+    passwordRule: 'Recommandations',
+    passwordLength: 'Longueur 鈮�6',
+    cannotBeTheSame: 'Tous les caract猫res ne peuvent 锚tre identiques',
+    cannotOrder: 'Pas de 3+ nombres/lettres cons茅cutifs',
+    cannotWeakPassword: 'Pas de mot de passe faible',
+    submit: 'Soumettre',
+    saveConfig: 'Enregistrer',
+    msg_please_enter: 'Veuillez saisir',
+    msg_inputPassword: 'Veuillez saisir le mot de passe',
+    msg_oldPasswordError: 'Ancien mot de passe incorrect',
+    msg_password_mismatch: 'Les mots de passe ne correspondent pas',
+    msg_password_min_length: 'Au moins 6 caract猫res',
+    msg_is_weak_password: 'Mot de passe faible, changez-le',
+    msg_pswChangeSuccessAndLogin: 'Mot de passe chang茅, reconnectez-vous',
+    msg_pswChangeSuccess: 'Mot de passe modifi茅',
+    msg_pswChangeFail: '脡chec de modification',
+    msg_saveSuccess: 'Enregistr茅',
+    msg_saveFail: "脡chec de l'enregistrement",
+    msg_formFilled: 'V茅rifiez le formulaire',
+    msg_number_0_23: 'Supporte seulement 0-23',
+    msg_number_0_24: 'Supporte seulement 0-24',
+    msg_noChange: 'Aucun changement de configuration 脿 enregistrer',
+    resourceConfiguration: 'Configuration des ressources',
+    backgroundImage: 'Image de fond',
+    selectImage: 'Choisir une image',
+    uploadBackground: 'T茅l茅verser le fond',
+    uploading: 'T茅l茅versement...',
+    backgroundUploadTip: 'T茅l茅versez une image PNG avec un nombre de pixels 茅gal 脿 {n}; convertie en Base64 puis envoy茅e',
+    backgroundResolutionMismatch: "La r茅solution de l'image doit 锚tre {n}",
+    backgroundRequired: "Veuillez choisir l'image de fond",
+    backgroundImageOnlyPNG: 'Seulement PNG',
+    backgroundSizeLimit: "La taille ne doit pas d茅passer 5MB",
+    backgroundParseFailed: "脡chec de lecture de l'image",
+    backgroundImageSelected: 'Image s茅lectionn茅e',
+    backgroundSuccess: 'Fond t茅l茅vers茅',
+    backgroundFailed: '脡chec du t茅l茅versement',
+    scanSettings: 'Param猫tres de scan',
+    scanSwitch: 'Interrupteur de Scan',
+    scanInterval: 'Intervalle de scan',
+  },
+  person: {
+    idCard: "Num茅ro d'identit茅",
+    userType: 'Type de personne',
+    administrator: 'Administrateur',
+    userId: 'ID',
+    user: 'Utilisateur',
+    voucher: 'Credential',
+    permission: 'Permission',
+    addUser: 'Ajouter une personne',
+    name: 'Nom',
+    editUser: 'Modifier personne',
+    placeholderUserId: "Entrez l'ID utilisateur",
+    placeholderName: 'Entrez le nom',
+    userNotExist: "La personne n'existe pas",
+    oneClickClear: 'Tout effacer',
+    clearTips: 'Cette action effacera toutes les donn茅es, continuer ?',
+    clearSuccess: 'Effac茅 avec succ猫s',
+    clearFailed: '脡chec de suppression',
+  },
+  voucher: {
+    password: 'Mot de passe',
+    card: 'Carte',
+    face: 'Visage',
+    finger: 'Empreinte',
+    code: 'Code',
+    codeType: 'Type de code',
+    passthroughCode: 'Code de transit',
+    staticCode: 'Code statique',
+    dynamicCode: 'Code dynamique',
+    credentialId: 'ID d鈥檌dentifiant',
+    credentialValue: 'Valeur d鈥檌dentifiant',
+    placeholderCode: 'Veuillez saisir le certificat de code',
+    placeholderPwd: 'Entrez le mot de passe',
+    placeholderCard: 'Entrez la carte',
+    validPassword: 'Entrez 6 chiffres',
+    validCard: 'Entrez 8 chiffres ou lettres',
+    photoRegistration: "Enregistrement d'image",
+    featureValueRegistration: 'Enregistrement de caract茅ristiques',
+    fingerRegistration: "Enregistrement d'empreinte",
+    fingerFeatureRegistration: 'Enregistrement par valeur de caract茅ristique',
+    fingerInput: "Veuillez poser votre doigt sur le lecteur d'empreintes",
+    fingerRemainingTime: 'Temps restant',
+    fingerInputting: 'En cours...',
+    startFingerInput: "D茅marrer l'enregistrement d'empreinte",
+    fingerInputTips: "Veuillez saisir la valeur de caract茅ristique de l'empreinte",
+    fingerWaitInput: 'En attente',
+    fingerInputNow: "Enregistrement de l'empreinte...",
+    fingerInputSuccess: 'Enregistrement r茅ussi',
+    fingerInputFailed: "脡chec du d茅marrage de l'enregistrement d'empreinte",
+    fingerReTry: "脡chec de l'enregistrement d'empreinte, veuillez r茅essayer",
+    fingerFilled: "Enregistrement r茅ussi, la valeur de caract茅ristique a 茅t茅 remplie automatiquement",
+    fingerFailed: "脡chec de l'enregistrement d'empreinte",
+    fingerTimeout: 'D茅lai d茅pass茅',
+    fingerInputTimeout: "D茅lai d茅pass茅 pour l'enregistrement d'empreinte, veuillez r茅essayer",
+    fingerError: '脡chec de la saisie',
+    fingerInputError: "脡chec de l'enregistrement d'empreinte, veuillez r茅essayer",
+    fingerInputed: 'Empreinte d茅j脿 enregistr茅e',
+    fingerReInput: "R茅enregistrer l'empreinte",
+  },
+  permission: {
+    deletePermission: 'Supprimer permission',
+    addPermission: 'Ajouter permission',
+    permissionId: 'ID permission',
+    userId: 'ID utilisateur',
+    timeRange: 'Plage horaire',
+    extra: 'Extra',
+    effectiveType: 'Type de validit茅',
+    effectiveTime: 'Temps effectif',
+    effectiveWeek: 'Semaine effective',
+    timePeriod: 'P茅riode',
+    addTimePeriod: 'Ajouter une p茅riode',
+    modify_previous_time: 'Modifiez la p茅riode pr茅c茅dente',
+    cannot_be_earlier: "L'heure de fin ne peut 锚tre avant le d茅but",
+    times_cannot_overlap: 'Les horaires ne peuvent se chevaucher',
+    choose_time_range: 'Choisissez une plage horaire',
+    unlimitedMode: 'Illimit茅',
+    usualMode: 'Mode habituel',
+    dailyMode: 'Mode quotidien',
+    weeklyRepetitionMode: 'R茅p茅tition hebdo',
+    time_range: 'Plage horaire',
+  },
+  common: {
+    startDate: 'Date d茅but',
+    endDate: 'Date fin',
+    to: '脿',
+    cancel: 'Annuler',
+    confirm: 'Confirmer',
+    close: 'Fermer',
+    delete: 'Supprimer',
+    edit: 'Modifier',
+    batchDelete: 'Suppression multiple',
+    startTime: 'Heure d茅but',
+    endTime: 'Heure fin',
+    monday: 'Lundi',
+    tuseday: 'Mardi',
+    wednesday: 'Mercredi',
+    thursday: 'Jeudi',
+    friday: 'Vendredi',
+    saterday: 'Samedi',
+    sunday: 'Dimanche',
+    placeholder: 'Veuillez saisir',
+    placeholderSelect: 'Veuillez s茅lectionner',
+    closeTips: 'Confirmer la fermeture ?',
+    deleteTips: 'Confirmer la suppression ?',
+    deleteSuccess: 'Suppression r茅ussie',
+    addSuccess: 'Ajout r茅ussi',
+    editSuccess: 'Modification r茅ussie',
+    saveSuccess: 'Enregistr茅 avec succ猫s',
+    tips: 'Conseil',
+    operation: 'Op茅ration',
+    query: 'Rechercher',
+    reset: 'Reset',
+    noData: 'Pas de donn茅es',
+    export: 'Exporter',
+    success: 'Succ猫s',
+    failure: '脡chec',
+    incorrectFormat: 'Format incorrect',
+    integerFormat: 'Doit 锚tre un entier 鈮�0',
+    positiveIntegerFormat: 'Doit 锚tre un entier >0',
+    noDataSaved: 'Aucune donn茅e 脿 enregistrer',
+    chinese: 'Chinois',
+    english: 'Anglais',
+    spanish: 'Espagnol',
+    french: 'Fran莽ais',
+    german: 'Allemand',
+    russian: 'Russe',
+    arabic: 'Arabe',
+    portuguese: 'Portugais',
+    korean: 'Cor茅en',
+    detail: 'D茅tail',
+    clearTips: 'Confirmer l\'effacement?',
+    clearSuccess: 'Effac茅 avec succ猫s',
+  },
+  log: {
+    accessMethod: "M茅thode d'acc猫s",
+    passingTime: 'Heure de passage',
+    accessPass: 'Credential',
+    accessResult: 'R茅sultat',
+    accessPhoto: 'Photo',
+    viewPhotos: 'Voir photos'
+  },
+  error: {
+    networkError: '脡chec r茅seau, v茅rifiez la connexion',
+    timeout: 'D茅lai d茅pass茅, r茅essayez',
+    serverError: 'Erreur interne serveur, r茅essayez',
+    notFound: "La ressource n'existe pas",
+    unauthorized: 'Non autoris茅, reconnectez-vous',
+    noResponse: 'Impossible de contacter le serveur',
+    unknownError: '脡chec de la requ锚te, code :',
+    requestFailed: 'Requ锚te 茅chou茅e'
+  },
+  security: {
+    keyId: 'ID de cl茅',
+    keyType: 'Type de cl茅',
+    keyEncoding: 'Encodage de cl茅',
+    keyValue: 'Valeur de cl茅',
+    startTime: 'Heure de d茅but',
+    expirationTime: 'Heure d\'expiration',
+    newKey: 'Ajouter une cl茅',
+    clearKey: 'Effacer la cl茅',
+    validTime: 'Dur茅e de validit茅',
+  }
+}
+
+
diff --git "a/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/language/index.js" "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/language/index.js"
new file mode 100644
index 0000000..a1df497
--- /dev/null
+++ "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/language/index.js"
@@ -0,0 +1,64 @@
+import Vue from 'vue' // 寮曞叆vue
+import VueI18n from 'vue-i18n' // 寮曞叆i18n妯″潡
+import elementEnLocale from 'element-ui/lib/locale/lang/en' // element-ui鑻辨枃鍖�
+import elementZhLocale from 'element-ui/lib/locale/lang/zh-CN' // element-ui涓枃鍖�
+import locale from 'element-ui/lib/locale' // 寮曞叆elementuiui璇█鍖呮ā鍧�
+import enLocale from './en' // 鏈湴鑻辨枃鍖�
+import zhLocale from './zh' // 鏈湴涓枃鍖�
+import esLocale from './es'
+import frLocale from './fr'
+import deLocale from './de'
+import ruLocale from './ru'
+import arLocale from './ar'
+import ptLocale from './pt'
+import koLocale from './ko'
+
+Vue.use(VueI18n) // vue浣跨敤i18n妯″潡
+// 寮曞叆鏈湴
+const messages = {
+  EN: {
+    ...enLocale, // es6鐨勬嫇灞曡繍绠楃锛岀浉褰撲簬瑙f瀽鍑烘瘡涓璞�
+    ...elementEnLocale
+  },
+  CN: {
+    ...zhLocale,
+    ...elementZhLocale
+  },
+  ES: {
+    ...esLocale,
+    ...elementEnLocale
+  },
+  FR: {
+    ...frLocale,
+    ...elementEnLocale
+  },
+  DE: {
+    ...deLocale,
+    ...elementEnLocale
+  },
+  RU: {
+    ...ruLocale,
+    ...elementEnLocale
+  },
+  AR: {
+    ...arLocale,
+    ...elementEnLocale
+  },
+  PT: {
+    ...ptLocale,
+    ...elementEnLocale
+  },
+  KO: {
+    ...koLocale,
+    ...elementEnLocale
+  }
+}
+let publicConfig = sessionStorage.getItem('publicConfig')
+let { language } = publicConfig ? JSON.parse(publicConfig) : {}
+// 鍒涘缓鍥介檯鍖栧疄渚�
+const i18n = new VueI18n({
+  locale: language, // set locale锛岄粯璁や腑鏂�
+  messages // set locale messages銆傝瑷�鍖�
+})
+locale.i18n((key, value) => i18n.t(key, value))
+export default i18n
\ No newline at end of file
diff --git "a/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/language/ko.js" "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/language/ko.js"
new file mode 100644
index 0000000..0f6a0d9
--- /dev/null
+++ "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/language/ko.js"
@@ -0,0 +1,431 @@
+export default {
+  // 搿滉犯鞚�
+  login: {
+    lang: '鞏胳柎',
+    systemname: '搿滉犯鞚�',
+    username: '靷毄鞛�',
+    username_label: '靷毄鞛愲獏鞚� 鞛呺牓頃橃劯鞖�',
+    pwd: '牍勲皜氩堩樃',
+    pwd_label: '牍勲皜氩堩樃毳� 鞛呺牓頃橃劯鞖�',
+    pwd_info: '鞓皵毳� 牍勲皜氩堩樃 順曥嫕鞚� 鞛呺牓頃橃劯鞖�',
+    success_msg: '搿滉犯鞚� 靹标车',
+    error_name: '牍勲皜氩堩樃臧� 鞓皵毳挫 鞎婌姷雼堧嫟',
+    error_res: '搿滉犯鞚� 鞖旉惮靷暛鞚� 於╈”頃橃 鞎婌姷雼堧嫟',
+    login: '搿滉犯鞚�',
+  },
+  // 靷澊霌滊皵
+  aside: {
+    systemname: '甏�毽�',
+    quit: '搿滉犯鞎勳泝',
+    deviceControl: '鞝滌柎',
+    basicSetting: '靹れ爼',
+    workerSetting: '鞚胳洂',
+    deviceMonitoring: '氇媹韯半',
+    recordManagement: '旮半',
+    securityManagement: '韨� 甏�毽�',
+    tips: '鞎岆',
+    tips_msg: '搿滉犯鞎勳泝頃橃嫓瓴犾姷雼堦箤?',
+  },
+  control: {
+    remoteControl: '鞗愱博',
+    restart: '鞛秬韺�',
+    clickToRestart: '韥措Ν頃橃棳 鞛秬韺�',
+    restartConfirm: '鞛秬韺呾潉 頇曥澑頃橃嫓瓴犾姷雼堦箤?',
+    restartSuccess: '鞛秬韺� 靹标车',
+    restartFailed: '鞛秬韺� 鞁ろ尐',
+    remoteOpen: '鞗愱博 臧滊癌',
+    clickToOpen: '韥措Ν頃橃棳 臧滊癌',
+    openConfirm: '鞗愱博 臧滊癌鞚� 頇曥澑頃橃嫓瓴犾姷雼堦箤?',
+    remoteOpenSuccess: '臧滊癌 靹标车',
+    remoteOpenFailed: '臧滊癌 鞁ろ尐',
+    reset: '鞛レ箻 齑堦赴頇�',
+    clickToReset: '韥措Ν頃橃棳 齑堦赴頇�',
+    resetConfirm: '齑堦赴頇旊ゼ 頇曥澑頃橃嫓瓴犾姷雼堦箤?',
+    resetWillOut: "毽厠 頉� 搿滉犯鞎勳泝",
+    resetSuccess: '齑堦赴頇� 靹标车',
+    resetFailed: '齑堦赴頇� 鞁ろ尐',
+    firmwareUpgrade: '韼岇洦鞏� 鞐呹犯霠堨澊霌�',
+    upgradeConfig: '鞐呹犯霠堨澊霌� 靹れ爼',
+    firmwareUrl: '韼岇洦鞏� URL',
+    md5Checksum: 'md5 臧�',
+    startUpgrade: '鞐呹犯霠堨澊霌� 鞁滌瀾',
+    urlRequired: 'URL鞚� 頃勳垬鞛呺媹雼�',
+    md5Required: 'md5電� 頃勳垬鞛呺媹雼�',
+    urlInvalid: '鞓皵毳� URL鞚� 鞛呺牓頃橃劯鞖�',
+    md5Invalid: '鞓皵毳� md5毳� 鞛呺牓頃橃劯鞖�',
+    upgradeConfirm: '鞐呹犯霠堨澊霌滊ゼ 歆勴枆頃犼箤鞖�?',
+    upgradeSuccess: '鞐呹犯霠堨澊霌� 靹标车',
+    clearFile: "韺岇澕 歆�鞖瓣赴",
+    uploading: '鞐呺霌� 欷�...',
+    uploadAndUpgrade: '鞐呺霌� 頉� 鞐呹犯霠堨澊霌�',
+    restartTips: '鞎堨爠頃� 鞛秬韺�, 雿办澊韯� 靻愳嫟 鞐嗢潓',
+    restarting: '鞛秬韺� 欷�...',
+    remoteTips: '於滌瀰 鞗愱博 鞝滌柎',
+    opening: '臧滊癌 欷�...',
+    resetTips: '瓿奠灔 齑堦赴頇�, 氇摖 雿办澊韯� 靷牅',
+    reseting: '齑堦赴頇� 欷�...',
+    urlUpgrade: 'URL 鞐呹犯霠堨澊霌�',
+    fileUpgrade: '韺岇澕 鞐呹犯霠堨澊霌�',
+    uploadFile: '韼岇洦鞏� 韺岇澕 鞐呺霌�',
+    formatFile: '.zip 霕愲姅 .dpk 歆�鞗�, 斓滊寑 20MB',
+    fileName: '韺岇澕氇�',
+    size: '韥赴',
+  },
+  config: {
+    second: '齑�',
+    millisecond: '氚�毽磮',
+    min: '攵�',
+    notsave: '鞝�鞛� 鞎� 頃�',
+    save: '鞝�鞛�',
+    noVoice: '鞚岇劚 鞐嗢潓',
+    no: '鞎勲媹鞓�',
+    yes: '鞓�',
+    basicConfiguration: '旮半掣 靹れ爼',
+    displaySettings: '霐旍姢頂岆爤鞚� 靹れ爼',
+    informationDisplay: '鞝曤炒 響滌嫓',
+    audioSettings: '鞓る敂鞓� 靹れ爼',
+    languageAndThemes: '鞏胳柎 氚� 韰岆',
+    autoAdjustScreenBrightness: '鞛愲彊 氚濌赴 臁办爤',
+    screenBrightness: '頇旊┐ 氚濌赴',
+    autoTurnOffScreen: '鞛愲彊 頇旊┐ 雭勱赴',
+    autoTurnOffScreenTime: '頇旊┐ 雭勱赴 鞁滉皠',
+    autoScreenSaver: '鞛愲彊 頇旊┐氤错樃旮�',
+    autoScreenSaverTime: '頇旊┐氤错樃旮� 鞁滉皠',
+    displayDeviceSn: 'SN 響滌嫓',
+    displayIp: 'IP 響滌嫓',
+    displayIdentityCard: '韥措澕鞖半摐 鞚胳 響滌嫓',
+    volume: '氤茧エ',
+    language: '鞏胳柎',
+    displayCode: "氙鸽媹鞎� 旖旊摐 響滌嫓",
+    themeMode: "韰岆",
+    cn: '欷戧淡鞏�',
+    en: '鞓侅柎',
+    es: '鞀ろ帢鞚胳柎',
+    fr: '頂勲瀾鞀れ柎',
+    de: '霃呾澕鞏�',
+    ru: '霟嫓鞎勳柎',
+    ar: '鞎勲瀺鞏�',
+    pt: '韽ゴ韴皥',
+    ko: '頃滉淡鞏�',
+    standardMode: '響滌 氇摐',
+    simpleMode: '鞁攲 氇摐',
+    firstLogin: '觳� 搿滉犯鞚�',
+    backlight: '氚瓣步 臁半獏',
+    brightness: '頇旍澊韸� 霛检澊韸�',
+    nirBrightness: '鞝侅櫢靹� 霛检澊韸�',
+    never: '鞎� 頃�',
+    min1: '1攵�',
+    min2: '2攵�',
+    min3: '3攵�',
+    min4: '4攵�',
+    min5: '5攵�',
+    networkConfiguration: '雱ろ姼鞗岉伂 靹れ爼',
+    otherConfiguration: '旮绊儉 靹れ爼',
+    ipConfiguration: 'IP 靹れ爼',
+    devicePassword: '鞛レ箻 牍勲皜氩堩樃',
+    protocolPassword: '頂勲韱犾綔 牍勲皜氩堩樃',
+    networkType: '雱ろ姼鞗岉伂 鞙犿槙',
+    ethernet: '鞚措崝雱�',
+    wifiName: 'Wi鈥慒i 鞚措',
+    wifiPassword: 'Wi鈥慒i 牍勲皜氩堩樃',
+    dhcpModeSelection: 'DHCP 氇摐',
+    dhcpMode: '鞛愲彊',
+    customNetworkConfiguration: '靾橂彊 靹れ爼',
+    ipAddress: 'IP 欤检唽',
+    gateway: '瓴岇澊韸胳洦鞚�',
+    subnetMask: '靹滊笇雱� 毵堨姢韥�',
+    dnsServer: 'DNS 靹滊矂',
+    mac: '雱ろ姼鞗岉伂 MAC',
+    mqttRelatedConfiguration: 'MQTT 靹れ爼',
+    mqttConnectionInformation: 'MQTT 鞐瓣舶 鞝曤炒',
+    sessionConfiguration: '靹胳厴 靹れ爼',
+    serverAddress: '靹滊矂 欤检唽',
+    clientID: '韥措澕鞚挫柛韸� ID',
+    userName: '靷毄鞛愲獏',
+    userPassword: '牍勲皜氩堩樃',
+    topicPrefix: '韱犿斀 鞝戨憪靷�',
+    onlineChecking: '鞓澕鞚� 頇曥澑',
+    onlineCheckingTimeout: '韮�鞛勳晞鞗�',
+    cleanSession: '韥措Π 靹胳厴',
+    clientIdSuffix: '韥措澕鞚挫柛韸� ID 鞝戨靷�',
+    willTopic: 'Will 韱犿斀',
+    enterpriseWechat:'Enterprise WeChat 氇摐 鞝侅毄 鞎� 霅�',
+    faceRelatedConfiguration: '鞏缄荡 靹れ爼',
+    functionalInformation: '旮半姤 鞝曤炒',
+    prompt: '頂勲‖頂勴姼',
+    faceSimilarityThreshold: '鞙犾偓霃� 鞛勱硠臧�',
+    livenessDetectionFunction: '霛检澊敫岆媹鞀� 臧愳',
+    livenessDetectionThreshold: '霛检澊敫岆媹鞀� 鞛勱硠臧�',
+    infraredImageDisplay: "鞝侅櫢靹� 鞚措歆� 響滌嫓",
+    maskRecognition: "毵堨姢韥� 鞚胳嫕",
+    strangerVoice: "雮劆鞚� 鞚岇劚",
+    voiceMode: "鞚岇劚 氇摐",
+    voiceModeDate: '毵烄钉 鞚胳偓',
+    imageSaveType: "鞚措歆� 鞝�鞛� 鞙犿槙",
+    saveStrangerImage: "雮劆鞚� 鞚措歆� 鞝�鞛�",
+    fullView: "鞝勱步",
+    face: "鞏缄荡",
+    broadcastPleaseRegisterFirst: '"霌彪 頉� 鞚挫毄" 鞛儩',
+    broadcastHelloStranger: '"雮劆鞚�" 鞛儩',
+    broadcastName: '鞚措 鞛儩',
+    broadcastGreeting: '毵烄钉 鞚胳偓 鞛儩',
+    greeting: '鞚胳偓毵�',
+    broadcastWelcome: '"頇橃榿頃╇媹雼�" 鞛儩',
+    recognitionSwitch: '鞛瞼靷� 鞀れ渼旃�',
+    systemRelatedConfiguration: '鞁滌姢韰� 靹れ爼',
+    functionSwitch: '旮半姤 鞀れ渼旃�',
+    cardSwipingSwitch: '旃措摐',
+    passwordSwitch: '牍勲皜氩堩樃',
+    strangerImage: '雮劆鞚� 鞚措歆�',
+    cloudCertificateSwitch: '韥措澕鞖半摐 鞚胳',
+    physicalCardNumber: '氍茧Μ 旃措摐 氩堩樃',
+    cloudCertificateAcquisition: '韥措澕鞖半摐 鞚胳 須嶋摑',
+    heartbeatConfig: '頃橅姼牍勴姼',
+    heartbeatSwitch: '頃橅姼牍勴姼 鞀れ渼旃�',
+    heartRateInterval: '鞚疙劙氩�',
+    heartbeatTopic: '頃橅姼牍勴姼 韱犿斀',
+    heartbeatContent: '頃橅姼牍勴姼 雮挫毄',
+    basicInformation: '旮半掣 鞝曤炒',
+    deviceMac: 'MAC 欤检唽',
+    uuid: 'UUID',
+    sn: 'SN',
+    model: '氇嵏',
+    version: "氩勳爠",
+    appVersion: "韼岇洦鞏� 氩勳爠",
+    releaseTime: "鞐呺嵃鞚错姼 鞁滉皠",
+    totaldisk: '齑� 瓿店皠',
+    freedisk: '鞛旍棳 瓿店皠',
+    passageConfiguration: '於滌瀰 靹れ爼',
+    functionConfiguration: '旮半姤 靹れ爼',
+    numberOfPassageRecords: '斓滊寑 於滌瀰 旮半 靾�',
+    durationOfRelayOpening: '毽措爤鞚� 臧滊癌 鞁滉皠',
+    alarmSwitch: '瓴诫炒',
+    fireAlarmSwitch: '頇旍灛 瓴诫炒',
+    fireAlarmStatus: '頇旍灛 靸來儨',
+    normal: '鞝曥儊',
+    warning: '瓴疥碃',
+    tamperSwitch: '氚╇矓 鞎岆瀸',
+    uploadToCloudSwitch: '鞏缄荡 鞐呺霌� 鞀れ渼旃�',
+    clockConfiguration: '鞁滉硠 靹れ爼',
+    timeSynchronizationSwitch: '鞁滉皠 霃欔赴頇�',
+    timeSynchronizationServerIP: '鞁滉皠 靹滊矂 IP',
+    timedSynchronizationTime: '霃欔赴頇� 鞁滉皠',
+    timeZone: '鞁滉皠雽�',
+    setDeviceTime: '鞛レ箻 鞁滉皠 靹れ爼',
+    restartAfterSetting: '靹れ爼 頉� 鞛レ箻 鞛秬韺�',
+    cloudCertificateActivation: '韥措澕鞖半摐 鞚胳 頇滌劚頇�',
+    activationKey: '頇滌劚頇� 韨�',
+    cloudTips1: '瓿惦氨 鞐嗢澊 韨るゼ 鞛呺牓頃橃劯鞖�',
+    cloudTips2: '頇滌劚頇� 頉� 韥措澕鞖半摐 靹滊箘鞀れ棎 鞐瓣舶霅╇媹雼�',
+    confirmActivation: '頇滌劚頇� 頇曥澑',
+    activationInProgress: '頇滌劚頇� 欷�...',
+    activationFailed: '頇滌劚頇� 鞁ろ尐',
+    activationSuccessful: '頇滌劚頇� 靹标车',
+    passwordModification: '牍勲皜氩堩樃 氤�瓴�',
+    password: '牍勲皜氩堩樃',
+    oldPassword: '順勳灛 牍勲皜氩堩樃',
+    newPassword: '靸� 牍勲皜氩堩樃',
+    confirmPassword: '牍勲皜氩堩樃 頇曥澑',
+    passwordRule: '牍勲皜氩堩樃 甓岇灔 靷暛',
+    passwordLength: '旮胳澊 鈮�6',
+    cannotBeTheSame: '氇憪 臧欖潃 氍胳瀽 攵堦皜',
+    cannotOrder: '鞐办啀 3臧� 鞚挫儊 靾瀽/靻岆鞛� 攵堦皜',
+    cannotWeakPassword: '鞚茧皹鞝侅澑 鞎巾暅 牍勲皜氩堩樃 旮堨',
+    submit: '鞝滌稖',
+    saveConfig: '靹れ爼 鞝�鞛�',
+    msg_please_enter: '雮挫毄鞚� 鞛呺牓頃橃劯鞖�',
+    msg_inputPassword: '牍勲皜氩堩樃毳� 鞛呺牓頃橃劯鞖�',
+    msg_oldPasswordError: '順勳灛 牍勲皜氩堩樃臧� 韹�霠胳姷雼堧嫟',
+    msg_password_mismatch: '牍勲皜氩堩樃臧� 鞚检箻頃橃 鞎婌姷雼堧嫟',
+    msg_password_min_length: '牍勲皜氩堩樃電� 斓滌唽 6鞛�',
+    msg_is_weak_password: '鞎巾暅 牍勲皜氩堩樃鞛呺媹雼�. 氤�瓴巾晿靹胳殧',
+    msg_pswChangeSuccessAndLogin: '牍勲皜氩堩樃 氤�瓴� 鞕勲, 雼れ嫓 搿滉犯鞚疙晿靹胳殧',
+    msg_pswChangeSuccess: '牍勲皜氩堩樃 氤�瓴� 靹标车',
+    msg_pswChangeFail: '牍勲皜氩堩樃 氤�瓴� 鞁ろ尐',
+    msg_saveSuccess: '鞝�鞛� 靹标车',
+    msg_saveFail: '鞝�鞛� 鞁ろ尐',
+    msg_formFilled: '鞏戩嫕 鞛呺牓鞚� 頇曥澑頃橃劯鞖�',
+    msg_number_0_23: '0~23毵� 歆�鞗�',
+    msg_number_0_24: '0~24毵� 歆�鞗�',
+    msg_noChange: '鞝�鞛ロ暊 甑劚 氤�瓴� 靷暛鞚� 鞐嗢姷雼堧嫟',
+    resourceConfiguration: '毽唽鞀� 靹れ爼',
+    backgroundImage: '氚瓣步 鞚措歆�',
+    selectImage: '鞚措歆� 靹犿儩',
+    uploadBackground: '氚瓣步 鞐呺霌�',
+    uploading: '鞐呺霌� 欷�...',
+    backgroundUploadTip: '頂届厐 靾橁皜 {n}鞚� PNG 順曥嫕鞚� 鞚措歆�毳� 鞐呺霌滍晿靹胳殧. 鞚措歆�電� Base64 順曥嫕鞙茧 氤�頇橂悳 頉� 旮瓣赴搿� 鞐呺霌滊惄雼堧嫟.',
+    backgroundResolutionMismatch: '鞚措歆� 頃挫儊霃勲姅 {n} 鞚挫柎鞎� 頃╇媹雼�',
+    backgroundRequired: '氚瓣步 鞚措歆�毳� 靹犿儩頃橃劯鞖�',
+    backgroundImageOnlyPNG: 'PNG 鞚措歆�毵� 項堨毄',
+    backgroundSizeLimit: '鞚措歆� 韥赴電� 5MB 鞚错晿',
+    backgroundParseFailed: '鞚措歆� 鞚疥赴 鞁ろ尐, 雼れ嫓 鞁滊弰',
+    backgroundImageSelected: '鞚措歆�臧� 靹犿儩霅橃棃鞀惦媹雼�',
+    backgroundSuccess: '氚瓣步 鞐呺霌� 靹标车',
+    backgroundFailed: '氚瓣步 鞐呺霌� 鞁ろ尐',
+    scanSettings: '鞀れ簲 靹れ爼',
+    scanSwitch: '鞀れ簲 鞀れ渼旃�',
+    scanInterval: '鞀れ簲 臧勱博',
+  },
+  person: {
+    idCard: '鞁犽秳歃� 氩堩樃',
+    userType: '靷毄鞛� 鞙犿槙',
+    administrator: '甏�毽瀽',
+    userId: 'ID',
+    user: '靷毄鞛�',
+    voucher: '鞛愱博 歃濍獏',
+    permission: '甓岉暅',
+    addUser: '靷毄鞛� 於旉皜',
+    name: '鞚措',
+    editUser: '靷毄鞛� 靾橃爼',
+    placeholderUserId: '靷毄鞛� ID毳� 鞛呺牓頃橃劯鞖�',
+    placeholderName: '鞚措鞚� 鞛呺牓頃橃劯鞖�',
+    userNotExist: '靷毄鞛愱皜 臁挫灛頃橃 鞎婌姷雼堧嫟',
+    oneClickClear: '氇憪 靷牅',
+    clearTips: '氇摖 雿办澊韯瓣皜 靷牅霅╇媹雼�. 瓿勳啀頃橃嫓瓴犾姷雼堦箤?',
+    clearSuccess: '靷牅 鞕勲',
+    clearFailed: '靷牅 鞁ろ尐',
+  },
+  voucher: {
+    password: '牍勲皜氩堩樃',
+    card: '旃措摐',
+    face: '鞏缄荡',
+    finger: '歆�氍�',
+    code: '旖旊摐',
+    codeType: '旖旊摐 鞙犿槙',
+    passthroughCode: '韱店臣 旖旊摐',
+    staticCode: '鞝曥爜 旖旊摐',
+    dynamicCode: '霃欖爜 旖旊摐',
+    credentialId: '鞛愱博 歃濍獏 ID',
+    credentialValue: '鞛愱博 歃濍獏 臧�',
+    placeholderCode: '旖旊摐 鞚胳靹滊ゼ 鞛呺牓頃橃劯鞖�',
+    placeholderPwd: '牍勲皜氩堩樃 鞛愱博鞚� 鞛呺牓',
+    placeholderCard: '旃措摐 鞛愱博鞚� 鞛呺牓',
+    validPassword: '6鞛愲Μ 靾瀽毳� 鞛呺牓',
+    validCard: '8鞛愲Μ 靾瀽 霕愲姅 氍胳瀽 鞛呺牓',
+    photoRegistration: '靷 霌彪',
+    featureValueRegistration: '韸轨臧� 霌彪',
+    fingerRegistration: '歆�氍� 霌彪',
+    fingerFeatureRegistration: '韸轨臧� 霌彪',
+    fingerInput: '靻愱皜霛届潉 歆�氍� 靹检劀鞐� 鞓牑欤检劯鞖�',
+    fingerRemainingTime: '雮潃 鞁滉皠',
+    fingerInputting: '霌彪 欷�...',
+    startFingerInput: '歆�氍� 霌彪 鞁滌瀾',
+    fingerInputTips: '歆�氍� 韸轨臧掛潉 鞛呺牓頃橃劯鞖�',
+    fingerWaitInput: '霌彪 雽�旮�',
+    fingerInputNow: '歆�氍胳潉 霌彪頃橂姅 欷�...',
+    fingerInputSuccess: '霌彪 靹标车',
+    fingerInputFailed: '歆�氍� 霌彪 鞁滌瀾 鞁ろ尐',
+    fingerReTry: '歆�氍� 霌彪 鞁ろ尐, 雼れ嫓 鞁滊弰頃� 欤检劯鞖�',
+    fingerFilled: '歆�氍� 霌彪 靹标车, 韸轨臧掛澊 鞛愲彊鞙茧 鞛呺牓霅橃棃鞀惦媹雼�',
+    fingerFailed: '歆�氍� 霌彪 鞁ろ尐',
+    fingerTimeout: '鞁滉皠 齑堦臣',
+    fingerInputTimeout: '歆�氍� 霌彪 鞁滉皠 齑堦臣, 雼れ嫓 鞁滊弰頃� 欤检劯鞖�',
+    fingerError: '霌彪 鞁ろ尐',
+    fingerInputError: '歆�氍� 霌彪 鞁ろ尐, 雼れ嫓 鞁滊弰頃� 欤检劯鞖�',
+    fingerInputed: '歆�氍胳澊 鞚措 霌彪霅橃棃鞀惦媹雼�',
+    fingerReInput: '歆�氍� 鞛摫搿�',
+  },
+  permission: {
+    deletePermission: '甓岉暅 靷牅',
+    addPermission: '甓岉暅 於旉皜',
+    permissionId: '甓岉暅 ID',
+    userId: '靷毄鞛� ID',
+    timeRange: '鞁滉皠 氩旍渼',
+    extra: '於旉皜',
+    effectiveType: '鞙犿毃 鞙犿槙',
+    effectiveTime: '鞙犿毃 鞁滉皠',
+    effectiveWeek: '鞙犿毃 欤�',
+    timePeriod: '鞁滉皠雽�',
+    addTimePeriod: '鞁滉皠雽� 於旉皜',
+    modify_previous_time: '毹检爛 鞚挫爠 鞁滉皠雽�毳� 靾橃爼頃橃劯鞖�',
+    cannot_be_earlier: '膦呺 鞁滉皠鞚� 鞁滌瀾 鞁滉皠氤措嫟 牍犽ゼ 靾� 鞐嗢姷雼堧嫟',
+    times_cannot_overlap: '鞁滉皠雽�臧� 瓴轨範 靾� 鞐嗢姷雼堧嫟',
+    choose_time_range: '鞁滉皠 氩旍渼毳� 靹犿儩頃橃劯鞖�',
+    unlimitedMode: '氍挫牅頃� 氇摐',
+    usualMode: '鞚茧皹 氇摐',
+    dailyMode: '鞚检澕 氇摐',
+    weeklyRepetitionMode: '欤缄皠 氚橂车 氇摐',
+    time_range: '鞁滉皠 氩旍渼',
+  },
+  common: {
+    startDate: '鞁滌瀾 雮犾',
+    endDate: '膦呺 雮犾',
+    to: '攵�韯�',
+    cancel: '旆唽',
+    confirm: '頇曥澑',
+    close: '雼赴',
+    delete: '靷牅',
+    edit: '靾橃爼',
+    batchDelete: '鞚缄磩 靷牅',
+    startTime: '鞁滌瀾 鞁滉皠',
+    endTime: '膦呺 鞁滉皠',
+    monday: '鞗旍殧鞚�',
+    tuseday: '頇旍殧鞚�',
+    wednesday: '靾橃殧鞚�',
+    thursday: '氇╈殧鞚�',
+    friday: '旮堨殧鞚�',
+    saterday: '韱犾殧鞚�',
+    sunday: '鞚检殧鞚�',
+    placeholder: '鞛呺牓頃橃劯鞖�',
+    placeholderSelect: '靹犿儩頃橃劯鞖�',
+    closeTips: '雼赴毳� 頇曥澑頃橃嫓瓴犾姷雼堦箤?',
+    deleteTips: '靷牅毳� 頇曥澑頃橃嫓瓴犾姷雼堦箤?',
+    deleteSuccess: '靷牅 靹标车',
+    addSuccess: '於旉皜 靹标车',
+    editSuccess: '靾橃爼 靹标车',
+    saveSuccess: '鞝�鞛� 靹标车',
+    tips: '鞎岆',
+    operation: '鞛戩梾',
+    query: '臁绊殞',
+    reset: '齑堦赴頇�',
+    noData: '雿办澊韯� 鞐嗢潓',
+    export: '雮措炒雮搓赴',
+    success: '靹标车',
+    failure: '鞁ろ尐',
+    incorrectFormat: '順曥嫕鞚� 鞓皵毳挫 鞎婌姷雼堧嫟',
+    integerFormat: '0 鞚挫儊鞚� 鞝曥垬鞐暭 頃╇媹雼�',
+    positiveIntegerFormat: '0氤措嫟 韥� 鞝曥垬鞐暭 頃╇媹雼�',
+    noDataSaved: '鞝�鞛ロ暊 雿办澊韯瓣皜 鞐嗢姷雼堧嫟',
+    chinese: '欷戧淡鞏�',
+    english: '鞓侅柎',
+    spanish: '鞀ろ帢鞚胳柎',
+    french: '頂勲瀾鞀れ柎',
+    german: '霃呾澕鞏�',
+    russian: '霟嫓鞎勳柎',
+    arabic: '鞎勲瀺鞏�',
+    portuguese: '韽ゴ韴皥鞏�',
+    korean: '頃滉淡鞏�',
+    detail: '靹鸽秬 鞝曤炒',
+    clearTips: '歆�鞖办嫓瓴犾姷雼堦箤?',
+    clearSuccess: '靹标车鞝侅溂搿� 歆�鞗岇',
+  },
+  log: {
+    accessMethod: '於滌瀰 氚╈嫕',
+    passingTime: '於滌瀰 鞁滉皠',
+    accessPass: '於滌瀰 歃濍獏',
+    accessResult: '瓴瓣臣',
+    accessPhoto: '靷',
+    viewPhotos: '靷 氤搓赴'
+  },
+  error: {
+    networkError: '雱ろ姼鞗岉伂 鞓る, 鞐瓣舶鞚� 頇曥澑頃橃劯鞖�',
+    timeout: '鞖旍箔 鞁滉皠 齑堦臣, 雼れ嫓 鞁滊弰頃橃劯鞖�',
+    serverError: '靹滊矂 雮措秬 鞓る, 雮橃鞐� 雼れ嫓 鞁滊弰',
+    notFound: '鞖旍箔頃� 鞛愳洂鞚� 鞐嗢姷雼堧嫟',
+    unauthorized: '鞚胳霅橃 鞎婌晿鞀惦媹雼�. 雼れ嫓 搿滉犯鞚疙晿靹胳殧',
+    noResponse: '靹滊矂 鞚戨嫷鞚� 鞐嗢姷雼堧嫟',
+    unknownError: '鞖旍箔 鞁ろ尐, 鞓る 旖旊摐:',
+    requestFailed: '鞖旍箔鞐� 鞁ろ尐頄堨姷雼堧嫟'
+  },
+  security: {
+    keyId: '韨� ID',
+    keyType: '韨� 鞙犿槙',
+    keyEncoding: '韨� 鞚胳綌霐�',
+    keyValue: '韨� 臧�',
+    startTime: '鞁滌瀾 鞁滉皠',
+    expirationTime: '毵岆 鞁滉皠',
+    newKey: '韨� 於旉皜',
+    clearKey: '韨� 歆�鞖瓣赴',
+    validTime: '鞙犿毃 鞁滉皠',
+  }
+}
diff --git "a/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/language/pt.js" "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/language/pt.js"
new file mode 100644
index 0000000..f1838a9
--- /dev/null
+++ "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/language/pt.js"
@@ -0,0 +1,430 @@
+export default {
+  // Login
+  login: {
+    lang: 'Idioma',
+    systemname: 'Login',
+    username: 'Usu谩rio',
+    username_label: 'Digite o usu谩rio',
+    pwd: 'Senha',
+    pwd_label: 'Digite a senha',
+    pwd_info: 'Insira uma senha v谩lida',
+    success_msg: 'Login bem-sucedido',
+    error_name: 'Senha incorreta',
+    error_res: 'N茫o atende aos requisitos de login',
+    login: 'Entrar',
+  },
+  aside: {
+    systemname: 'Painel',
+    quit: 'Sair',
+    deviceControl: 'Controle',
+    basicSetting: 'Config.',
+    workerSetting: 'Pessoas',
+    deviceMonitoring: 'Monitor',
+    recordManagement: 'Registros',
+    securityManagement: 'Chaves',
+    tips: 'Aviso',
+    tips_msg: 'Deseja sair?',
+  },
+  control: {
+    remoteControl: 'Remoto',
+    restart: 'Reiniciar',
+    clickToRestart: 'Clique para reiniciar',
+    restartConfirm: 'Confirmar rein铆cio?',
+    restartSuccess: 'Rein铆cio bem-sucedido',
+    restartFailed: 'Rein铆cio falhou',
+    remoteOpen: 'Abrir porta remotamente',
+    clickToOpen: 'Clique para abrir',
+    openConfirm: 'Confirmar abertura remota?',
+    remoteOpenSuccess: 'Abertura bem-sucedida',
+    remoteOpenFailed: 'Abertura falhou',
+    reset: 'Redefinir dispositivo',
+    clickToReset: 'Clique para redefinir',
+    resetConfirm: 'Confirmar redefini莽茫o?',
+    resetWillOut: "Ap贸s reset, sair",
+    resetSuccess: 'Redefini莽茫o conclu铆da',
+    resetFailed: 'Redefini莽茫o falhou',
+    firmwareUpgrade: 'Atualizar firmware',
+    upgradeConfig: 'Config. de atualiza莽茫o',
+    firmwareUrl: 'URL do firmware',
+    md5Checksum: 'Valor md5',
+    startUpgrade: 'Iniciar atualiza莽茫o',
+    urlRequired: 'URL 茅 obrigat贸ria',
+    md5Required: 'md5 茅 obrigat贸rio',
+    urlInvalid: 'Informe uma URL v谩lida',
+    md5Invalid: 'Informe um md5 v谩lido',
+    upgradeConfirm: 'Confirmar atualiza莽茫o?',
+    upgradeSuccess: 'Atualiza莽茫o bem-sucedida',
+    clearFile: "Limpar arquivo",
+    uploading: 'Enviando...',
+    uploadAndUpgrade: 'Enviar e atualizar',
+    restartTips: 'Rein铆cio seguro, sem perder dados',
+    restarting: 'Reiniciando...',
+    remoteTips: 'Controle remoto de acesso',
+    opening: 'Abrindo...',
+    resetTips: 'Restaurar padr茫o, apagar谩 dados',
+    reseting: 'Redefinindo...',
+    urlUpgrade: 'Atualiza莽茫o por URL',
+    fileUpgrade: 'Atualiza莽茫o por arquivo',
+    uploadFile: 'Clique para enviar firmware',
+    formatFile: 'Suporta .zip ou .dpk, at茅 20MB',
+    fileName: 'Nome do arquivo',
+    size: 'Tamanho',
+  },
+  config: {
+    second: 's',
+    millisecond: 'ms',
+    min: 'minutos',
+    notsave: 'N茫o salvar',
+    save: 'Salvar',
+    noVoice: 'Sem voz',
+    no: 'N茫o',
+    yes: 'Sim',
+    basicConfiguration: 'Configura莽茫o b谩sica',
+    displaySettings: 'Exibi莽茫o',
+    informationDisplay: 'Mostrar informa莽玫es',
+    audioSettings: '脕udio',
+    languageAndThemes: 'Idioma e tema',
+    autoAdjustScreenBrightness: 'Brilho autom谩tico',
+    screenBrightness: 'Brilho da tela',
+    autoTurnOffScreen: 'Desligar tela automaticamente',
+    autoTurnOffScreenTime: 'Tempo para desligar',
+    autoScreenSaver: 'Protetor de tela autom谩tico',
+    autoScreenSaverTime: 'Tempo do protetor',
+    displayDeviceSn: 'Mostrar SN',
+    displayIp: 'Mostrar IP',
+    displayIdentityCard: 'Mostrar certificado em nuvem',
+    volume: 'Volume',
+    language: 'Idioma',
+    displayCode: "Mostrar c贸digo da miniapp",
+    themeMode: "Tema",
+    cn: 'Chin锚s',
+    en: 'Ingl锚s',
+    es: 'Espanhol',
+    fr: 'Franc锚s',
+    de: 'Alem茫o',
+    ru: 'Russo',
+    ar: '脕rabe',
+    pt: 'Portugu锚s',
+    ko: 'Coreano',
+    standardMode: 'Modo padr茫o',
+    simpleMode: 'Modo simples',
+    firstLogin: 'Primeiro login',
+    backlight: 'Luz de fundo',
+    brightness: 'Luz branca',
+    nirBrightness: 'Luz IR',
+    never: 'Nunca',
+    min1: '1 minuto',
+    min2: '2 minutos',
+    min3: '3 minutos',
+    min4: '4 minutos',
+    min5: '5 minutos',
+    networkConfiguration: 'Rede',
+    otherConfiguration: 'Outros',
+    ipConfiguration: 'IP',
+    devicePassword: 'Senha do dispositivo',
+    protocolPassword: 'Senha do protocolo',
+    networkType: 'Tipo de rede',
+    ethernet: 'Ethernet',
+    wifiName: 'Wi鈥慒i',
+    wifiPassword: 'Senha Wi鈥慒i',
+    dhcpModeSelection: 'Modo DHCP',
+    dhcpMode: 'Autom谩tico',
+    customNetworkConfiguration: 'Manual',
+    ipAddress: 'Endere莽o IP',
+    gateway: 'Gateway',
+    subnetMask: 'M谩scara de sub-rede',
+    dnsServer: 'Servidor DNS',
+    mac: 'MAC de rede',
+    mqttRelatedConfiguration: 'MQTT',
+    mqttConnectionInformation: 'Conex茫o MQTT',
+    sessionConfiguration: 'Sess茫o',
+    serverAddress: 'Servidor',
+    clientID: 'ID do cliente',
+    userName: 'Usu谩rio',
+    userPassword: 'Senha',
+    topicPrefix: 'Prefixo do t贸pico',
+    onlineChecking: 'Verifica莽茫o online',
+    onlineCheckingTimeout: 'Tempo limite',
+    cleanSession: 'Sess茫o limpa',
+    clientIdSuffix: 'Sufixo do ID',
+    willTopic: 'T贸pico Will',
+    enterpriseWechat:'Modo WeChat Enterprise sem efeito',
+    faceRelatedConfiguration: 'Config. de rosto',
+    functionalInformation: 'Fun莽茫o',
+    prompt: 'Aviso',
+    faceSimilarityThreshold: 'Limite de similaridade',
+    livenessDetectionFunction: 'Detec莽茫o de vivacidade',
+    livenessDetectionThreshold: 'Limite de vivacidade',
+    infraredImageDisplay: "Exibir infravermelho",
+    maskRecognition: "Reconhecimento de m谩scara",
+    strangerVoice: "Voz de desconhecido",
+    voiceMode: "Modo de voz",
+    voiceModeDate: 'Sauda莽茫o personalizada',
+    imageSaveType: "Tipo de salvamento",
+    saveStrangerImage: "Salvar imagem de desconhecido",
+    fullView: "Panor芒mico",
+    face: "Rosto",
+    broadcastPleaseRegisterFirst: 'Reproduzir "Registre-se primeiro"',
+    broadcastHelloStranger: 'Reproduzir "Desconhecido"',
+    broadcastName: 'Reproduzir nome',
+    broadcastGreeting: 'Reproduzir sauda莽茫o personalizada',
+    greeting: 'Sauda莽茫o',
+    broadcastWelcome: 'Reproduzir "Bem-vindo"',
+    recognitionSwitch: 'Interruptor de re-detec莽茫o',
+    systemRelatedConfiguration: 'Sistema',
+    functionSwitch: 'Interruptores',
+    cardSwipingSwitch: 'Cart茫o',
+    passwordSwitch: 'Senha',
+    strangerImage: 'Imagem de desconhecido',
+    cloudCertificateSwitch: 'Certificado em nuvem',
+    physicalCardNumber: 'N煤mero do cart茫o f铆sico',
+    cloudCertificateAcquisition: 'Obter certificado em nuvem',
+    heartbeatConfig: 'Heartbeat',
+    heartbeatSwitch: 'Ativar heartbeat',
+    heartRateInterval: 'Intervalo',
+    heartbeatTopic: 'T贸pico heartbeat',
+    heartbeatContent: 'Conte煤do',
+    basicInformation: 'Informa莽玫es b谩sicas',
+    deviceMac: 'MAC',
+    uuid: 'UUID',
+    sn: 'SN',
+    model: 'Modelo',
+    version: "Vers茫o",
+    appVersion: "Vers茫o do firmware",
+    releaseTime: "Hora da atualiza莽茫o",
+    totaldisk: 'Espa莽o total',
+    freedisk: 'Espa莽o restante',
+    passageConfiguration: 'Passagem',
+    functionConfiguration: 'Fun莽玫es',
+    numberOfPassageRecords: 'M谩x. registros',
+    durationOfRelayOpening: 'Dura莽茫o do rel茅',
+    alarmSwitch: 'Alarme',
+    fireAlarmSwitch: 'Alarme de inc锚ndio',
+    fireAlarmStatus: 'Status de inc锚ndio',
+    normal: 'Normal',
+    warning: 'Alerta',
+    tamperSwitch: 'Anti-viola莽茫o',
+    uploadToCloudSwitch: 'Interruptor de upload facial',
+    clockConfiguration: 'Rel贸gio',
+    timeSynchronizationSwitch: 'Sincronizar hora',
+    timeSynchronizationServerIP: 'Servidor de tempo',
+    timedSynchronizationTime: 'Hora de sincroniza莽茫o',
+    timeZone: 'Fuso hor谩rio',
+    setDeviceTime: 'Ajustar hora',
+    restartAfterSetting: 'O dispositivo reiniciar谩',
+    cloudCertificateActivation: 'Ativar certificado',
+    activationKey: 'Chave de ativa莽茫o',
+    cloudTips1: 'Digite a chave sem espa莽os',
+    cloudTips2: 'Ap贸s ativar, conectar谩 ao servi莽o em nuvem',
+    confirmActivation: 'Confirmar ativa莽茫o',
+    activationInProgress: 'Ativando...',
+    activationFailed: 'Falha na ativa莽茫o',
+    activationSuccessful: 'Ativa莽茫o bem-sucedida',
+    passwordModification: 'Alterar senha',
+    password: 'Senha',
+    oldPassword: 'Senha antiga',
+    newPassword: 'Nova senha',
+    confirmPassword: 'Confirmar senha',
+    passwordRule: 'Recomenda莽茫o de senha',
+    passwordLength: 'Comprimento 鈮�6',
+    cannotBeTheSame: 'Todos caracteres n茫o podem ser iguais',
+    cannotOrder: 'Sem 3+ n煤meros/letras consecutivos',
+    cannotWeakPassword: 'N茫o usar senhas fracas comuns',
+    submit: 'Enviar',
+    saveConfig: 'Salvar',
+    msg_please_enter: 'Por favor, insira',
+    msg_inputPassword: 'Digite a senha',
+    msg_oldPasswordError: 'Senha antiga incorreta',
+    msg_password_mismatch: 'Senhas n茫o coincidem',
+    msg_password_min_length: 'M铆nimo 6 caracteres',
+    msg_is_weak_password: 'Senha fraca, altere',
+    msg_pswChangeSuccessAndLogin: 'Senha alterada, fa莽a login',
+    msg_pswChangeSuccess: 'Senha alterada',
+    msg_pswChangeFail: 'Falha ao alterar senha',
+    msg_saveSuccess: 'Salvo com sucesso',
+    msg_saveFail: 'Falha ao salvar',
+    msg_formFilled: 'Verifique o formul谩rio',
+    msg_number_0_23: 'Apenas 0-23',
+    msg_number_0_24: 'Apenas 0-24',
+    msg_noChange: 'Nenhuma altera莽茫o de configura莽茫o para salvar',
+    resourceConfiguration: 'Configura莽茫o de recursos',
+    backgroundImage: 'Imagem de fundo',
+    selectImage: 'Selecionar imagem',
+    uploadBackground: 'Enviar fundo',
+    uploading: 'Enviando...',
+    backgroundUploadTip: 'Por favor, envie uma imagem em formato PNG com pixels de {n}, que ser谩 convertida para o formato Base64 e enviada ao dispositivo',
+    backgroundResolutionMismatch: 'A resolu莽茫o da imagem deve ser {n}',
+    backgroundRequired: 'Selecione uma imagem de fundo',
+    backgroundImageOnlyPNG: 'Apenas PNG',
+    backgroundSizeLimit: 'Imagem n茫o pode exceder 5MB',
+    backgroundParseFailed: 'Falha ao ler imagem',
+    backgroundImageSelected: 'Imagem selecionada',
+    backgroundSuccess: 'Fundo enviado',
+    backgroundFailed: 'Falha ao enviar fundo',
+    scanSettings: 'Configura莽玫es de digitaliza莽茫o',
+    scanSwitch: 'Interruptor de Digitaliza莽茫o',
+    scanInterval: 'Intervalo de digitaliza莽茫o',
+  },
+  person: {
+    idCard: 'N煤mero de identifica莽茫o',
+    userType: 'Tipo de pessoa',
+    administrator: 'Administrador',
+    userId: 'ID',
+    user: 'Usu谩rio',
+    voucher: 'Credencial',
+    permission: 'Permiss茫o',
+    addUser: 'Adicionar pessoa',
+    name: 'Nome',
+    editUser: 'Editar pessoa',
+    placeholderUserId: 'Informe o ID do usu谩rio',
+    placeholderName: 'Informe o nome',
+    userNotExist: 'Pessoa n茫o existe',
+    oneClickClear: 'Limpar tudo',
+    clearTips: 'Isto apagar谩 todos os dados, continuar?',
+    clearSuccess: 'Limpo com sucesso',
+    clearFailed: 'Falha ao limpar',
+  },
+  voucher: {
+    password: 'Senha',
+    card: 'Cart茫o',
+    face: 'Rosto',
+    finger: 'Impress茫o digital',
+    code: 'C贸digo',
+    codeType: 'Tipo de c贸digo',
+    passthroughCode: 'C贸digo de passagem',
+    staticCode: 'C贸digo est谩tico',
+    dynamicCode: 'C贸digo din芒mico',
+    credentialId: 'ID da credencial',
+    credentialValue: 'Valor da credencial',
+    placeholderCode: 'Por favor insira o certificado de c贸digo',
+    placeholderPwd: 'Informe a senha',
+    placeholderCard: 'Informe o cart茫o',
+    validPassword: 'Insira 6 d铆gitos',
+    validCard: 'Insira 8 d铆gitos ou letras',
+    photoRegistration: 'Registro de foto',
+    featureValueRegistration: 'Registro de caracter铆sticas',
+    fingerRegistration: 'Cadastro de digital',
+    fingerFeatureRegistration: 'Cadastro por valor de caracter铆stica',
+    fingerInput: 'Coloque o dedo no leitor de digitais',
+    fingerRemainingTime: 'Tempo restante',
+    fingerInputting: 'Cadastrando...',
+    startFingerInput: 'Iniciar cadastro de digital',
+    fingerInputTips: 'Informe o valor de caracter铆stica da digital',
+    fingerWaitInput: 'Aguardando cadastro',
+    fingerInputNow: 'Cadastrando digital...',
+    fingerInputSuccess: 'Cadastro bem-sucedido',
+    fingerInputFailed: 'Falha ao iniciar o cadastro de digital',
+    fingerReTry: 'Falha no cadastro de digital, tente novamente',
+    fingerFilled: 'Cadastro de digital bem-sucedido, o valor de caracter铆stica foi preenchido automaticamente',
+    fingerFailed: 'Falha no cadastro de digital',
+    fingerTimeout: 'Tempo esgotado',
+    fingerInputTimeout: 'Tempo esgotado no cadastro de digital, tente novamente',
+    fingerError: 'Cadastro falhou',
+    fingerInputError: 'Falha no cadastro de digital, tente novamente',
+    fingerInputed: 'Digital j谩 cadastrada',
+    fingerReInput: 'Cadastrar digital novamente',
+  },
+  permission: {
+    deletePermission: 'Excluir permiss茫o',
+    addPermission: 'Adicionar permiss茫o',
+    permissionId: 'ID da permiss茫o',
+    userId: 'ID do usu谩rio',
+    timeRange: 'Intervalo de tempo',
+    extra: 'Extra',
+    effectiveType: 'Tipo de vig锚ncia',
+    effectiveTime: 'Tempo efetivo',
+    effectiveWeek: 'Semana efetiva',
+    timePeriod: 'Per铆odo',
+    addTimePeriod: 'Adicionar per铆odo',
+    modify_previous_time: 'Altere primeiro o per铆odo anterior',
+    cannot_be_earlier: 'Hora final n茫o pode ser menor que inicial',
+    times_cannot_overlap: 'Hor谩rios n茫o podem se sobrepor',
+    choose_time_range: 'Selecione o intervalo',
+    unlimitedMode: 'Ilimitado',
+    usualMode: 'Modo usual',
+    dailyMode: 'Modo di谩rio',
+    weeklyRepetitionMode: 'Repeti莽茫o semanal',
+    time_range: 'Faixa de tempo',
+  },
+  common: {
+    startDate: 'Data inicial',
+    endDate: 'Data final',
+    to: 'a',
+    cancel: 'Cancelar',
+    confirm: 'Confirmar',
+    close: 'Fechar',
+    delete: 'Excluir',
+    edit: 'Editar',
+    batchDelete: 'Excluir em lote',
+    startTime: 'Hora inicial',
+    endTime: 'Hora final',
+    monday: 'Segunda',
+    tuseday: 'Ter莽a',
+    wednesday: 'Quarta',
+    thursday: 'Quinta',
+    friday: 'Sexta',
+    saterday: 'S谩bado',
+    sunday: 'Domingo',
+    placeholder: 'Por favor insira',
+    placeholderSelect: 'Por favor selecione',
+    closeTips: 'Confirmar fechamento?',
+    deleteTips: 'Confirmar exclus茫o?',
+    deleteSuccess: 'Exclu铆do com sucesso',
+    addSuccess: 'Adicionado com sucesso',
+    editSuccess: 'Editado com sucesso',
+    saveSuccess: 'Salvo com sucesso',
+    tips: 'Dica',
+    operation: 'Opera莽茫o',
+    query: 'Consulta',
+    reset: 'Reset',
+    noData: 'Sem dados',
+    export: 'Exportar',
+    success: 'Sucesso',
+    failure: 'Falha',
+    incorrectFormat: 'Formato incorreto',
+    integerFormat: 'Deve ser inteiro 鈮�0',
+    positiveIntegerFormat: 'Deve ser inteiro >0',
+    noDataSaved: 'Sem dados para salvar',
+    chinese: 'Chin锚s',
+    english: 'Ingl锚s',
+    spanish: 'Espanhol',
+    french: 'Franc锚s',
+    german: 'Alem茫o',
+    russian: 'Russo',
+    arabic: '脕rabe',
+    portuguese: 'Portugu锚s',
+    korean: 'Coreano',
+    detail: 'Detalhe',
+    clearTips: 'Confirmar limpeza?',
+    clearSuccess: 'Limpo com sucesso',
+  },
+  log: {
+    accessMethod: 'M茅todo de acesso',
+    passingTime: 'Hora de passagem',
+    accessPass: 'Credencial de acesso',
+    accessResult: 'Resultado',
+    accessPhoto: 'Foto',
+    viewPhotos: 'Ver fotos'
+  },
+  error: {
+    networkError: 'Falha de rede, verifique a conex茫o',
+    timeout: 'Tempo esgotado, tente novamente',
+    serverError: 'Erro interno, tente mais tarde',
+    notFound: 'Recurso n茫o existe',
+    unauthorized: 'N茫o autorizado, fa莽a login',
+    noResponse: 'Sem resposta do servidor',
+    unknownError: 'Falha na solicita莽茫o, c贸digo:',
+    requestFailed: 'Solicita莽茫o falhou'
+  },
+  security: {
+    keyId: 'ID da chave',
+    keyType: 'Tipo de chave',
+    keyEncoding: 'Codifica莽茫o da chave',
+    keyValue: 'Valor da chave',
+    startTime: 'Hora de in铆cio',
+    expirationTime: 'Hora de expira莽茫o',
+    newKey: 'Adicionar chave',
+    clearKey: 'Limpar chave',
+    validTime: 'Tempo v谩lido',
+  }
+}
diff --git "a/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/language/ru.js" "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/language/ru.js"
new file mode 100644
index 0000000..6917fa5
--- /dev/null
+++ "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/language/ru.js"
@@ -0,0 +1,430 @@
+export default {
+  // 袙褏芯写
+  login: {
+    lang: '携蟹褘泻',
+    systemname: '袙褏芯写',
+    username: '袩芯谢褜蟹芯胁邪褌械谢褜',
+    username_label: '袙胁械写懈褌械 懈屑褟 锌芯谢褜蟹芯胁邪褌械谢褟',
+    pwd: '袩邪褉芯谢褜',
+    pwd_label: '袙胁械写懈褌械 锌邪褉芯谢褜',
+    pwd_info: '袙胁械写懈褌械 泻芯褉褉械泻褌薪褘泄 锌邪褉芯谢褜',
+    success_msg: '袙褏芯写 胁褘锌芯谢薪械薪',
+    error_name: '袧械胁械褉薪褘泄 锌邪褉芯谢褜',
+    error_res: '袧械 褋芯芯褌胁械褌褋褌胁褍械褌 褌褉械斜芯胁邪薪懈褟屑 胁褏芯写邪',
+    login: '袙芯泄褌懈',
+  },
+  aside: {
+    systemname: '袩邪薪械谢褜',
+    quit: '袙褘泄褌懈',
+    deviceControl: '校锌褉邪胁谢械薪懈械',
+    basicSetting: '袧邪褋褌褉芯泄泻懈',
+    workerSetting: '袩械褉褋芯薪邪谢',
+    deviceMonitoring: '袦芯薪懈褌芯褉懈薪谐',
+    recordManagement: '袞褍褉薪邪谢褘',
+    securityManagement: '泻谢褞褔邪屑懈',
+    tips: '袩芯写褋泻邪蟹泻邪',
+    tips_msg: '袙褘泄褌懈 懈蟹 褋懈褋褌械屑褘?',
+  },
+  control: {
+    remoteControl: '校写邪谢褢薪薪芯械',
+    restart: '袩械褉械蟹邪锌褍褋泻',
+    clickToRestart: '袧邪卸屑懈褌械 写谢褟 锌械褉械蟹邪锌褍褋泻邪',
+    restartConfirm: '袩芯写褌胁械褉写懈褌褜 锌械褉械蟹邪锌褍褋泻?',
+    restartSuccess: '袩械褉械蟹邪锌褍褋泻 褍褋锌械褕械薪',
+    restartFailed: '袩械褉械蟹邪锌褍褋泻 薪械褍写邪褔械薪',
+    remoteOpen: '校写邪谢褢薪薪芯械 芯褌泻褉褘褌懈械',
+    clickToOpen: '袧邪卸屑懈褌械 写谢褟 芯褌泻褉褘褌懈褟',
+    openConfirm: '袩芯写褌胁械褉写懈褌褜 褍写邪谢褢薪薪芯械 芯褌泻褉褘褌懈械?',
+    remoteOpenSuccess: '袨褌泻褉褘褌芯 褍褋锌械褕薪芯',
+    remoteOpenFailed: '袨褌泻褉褘褌褜 薪械 褍写邪谢芯褋褜',
+    reset: '小斜褉芯褋 褍褋褌褉芯泄褋褌胁邪',
+    clickToReset: '袧邪卸屑懈褌械 写谢褟 褋斜褉芯褋邪',
+    resetConfirm: '袩芯写褌胁械褉写懈褌褜 褋斜褉芯褋?',
+    resetWillOut: "袙褘褏芯写 锌芯褋谢械 褋斜褉芯褋邪",
+    resetSuccess: '小斜褉芯褋 褍褋锌械褕械薪',
+    resetFailed: '小斜褉芯褋 薪械褍写邪褔械薪',
+    firmwareUpgrade: '袨斜薪芯胁谢械薪懈械 锌褉芯褕懈胁泻懈',
+    upgradeConfig: '袧邪褋褌褉芯泄泻懈 芯斜薪芯胁谢械薪懈褟',
+    firmwareUrl: 'URL 锌褉芯褕懈胁泻懈',
+    md5Checksum: 'md5',
+    startUpgrade: '袧邪褔邪褌褜 芯斜薪芯胁谢械薪懈械',
+    urlRequired: 'URL 芯斜褟蟹邪褌械谢械薪',
+    md5Required: 'md5 芯斜褟蟹邪褌械谢械薪',
+    urlInvalid: '袙胁械写懈褌械 泻芯褉褉械泻褌薪褘泄 URL',
+    md5Invalid: '袙胁械写懈褌械 泻芯褉褉械泻褌薪褘泄 md5',
+    upgradeConfirm: '袩芯写褌胁械褉写懈褌褜 芯斜薪芯胁谢械薪懈械?',
+    upgradeSuccess: '袨斜薪芯胁谢械薪懈械 褍褋锌械褕薪芯',
+    clearFile: "袨褔懈褋褌懈褌褜 褎邪泄谢",
+    uploading: '袟邪谐褉褍蟹泻邪...',
+    uploadAndUpgrade: '袟邪谐褉褍蟹懈褌褜 懈 芯斜薪芯胁懈褌褜',
+    restartTips: '袘械蟹芯锌邪褋薪褘泄 锌械褉械蟹邪锌褍褋泻, 写邪薪薪褘械 薪械 锌芯褌械褉褟褞褌褋褟',
+    restarting: '袩械褉械蟹邪锌褍褋泻...',
+    remoteTips: '校写邪谢褢薪薪褘泄 泻芯薪褌褉芯谢褜 写芯褋褌褍锌邪',
+    opening: '袨褌泻褉褘胁邪械褌褋褟...',
+    resetTips: '小斜褉芯褋 泻 蟹邪胁芯写褋泻懈屑, 写邪薪薪褘械 褍写邪谢褟褌褋褟',
+    reseting: '小斜褉邪褋褘胁邪械褌褋褟...',
+    urlUpgrade: '袨斜薪芯胁谢械薪懈械 锌芯 URL',
+    fileUpgrade: '袨斜薪芯胁谢械薪懈械 褎邪泄谢芯屑',
+    uploadFile: '袣谢懈泻薪懈褌械 写谢褟 蟹邪谐褉褍蟹泻懈 锌褉芯褕懈胁泻懈',
+    formatFile: '袩芯写写械褉卸泻邪 .zip 懈谢懈 .dpk, 写芯 20MB',
+    fileName: '袠屑褟 褎邪泄谢邪',
+    size: '袪邪蟹屑械褉',
+  },
+  config: {
+    second: '褋',
+    millisecond: '屑褋',
+    min: '屑懈薪褍褌',
+    notsave: '袧械 褋芯褏褉邪薪褟褌褜',
+    save: '小芯褏褉邪薪懈褌褜',
+    noVoice: '袘械蟹 谐芯谢芯褋邪',
+    no: '袧械褌',
+    yes: '袛邪',
+    basicConfiguration: '袘邪蟹芯胁邪褟 泻芯薪褎懈谐褍褉邪褑懈褟',
+    displaySettings: '袧邪褋褌褉芯泄泻懈 褝泻褉邪薪邪',
+    informationDisplay: '袨褌芯斜褉邪卸械薪懈械 懈薪褎芯',
+    audioSettings: '袗褍写懈芯',
+    languageAndThemes: '携蟹褘泻 懈 褌械屑邪',
+    autoAdjustScreenBrightness: '袗胁褌芯褟褉泻芯褋褌褜',
+    screenBrightness: '携褉泻芯褋褌褜 褝泻褉邪薪邪',
+    autoTurnOffScreen: '袗胁褌芯胁褘泻谢褞褔械薪懈械 褝泻褉邪薪邪',
+    autoTurnOffScreenTime: '袙褉械屑褟 芯褌泻谢褞褔械薪懈褟',
+    autoScreenSaver: '袗胁褌芯 蟹邪褋褌邪胁泻邪',
+    autoScreenSaverTime: '袙褉械屑褟 蟹邪褋褌邪胁泻懈',
+    displayDeviceSn: '袩芯泻邪蟹邪褌褜 SN',
+    displayIp: '袩芯泻邪蟹邪褌褜 IP',
+    displayIdentityCard: '袩芯泻邪蟹邪褌褜 芯斜谢邪褔薪褘泄 褋械褉褌懈褎懈泻邪褌',
+    volume: '袚褉芯屑泻芯褋褌褜',
+    language: '携蟹褘泻',
+    displayCode: "袩芯泻邪蟹邪褌褜 泻芯写 屑懈薪懈-锌褉懈谢芯卸械薪懈褟",
+    themeMode: "孝械屑邪",
+    cn: '袣懈褌邪泄褋泻懈泄',
+    en: '袗薪谐谢懈泄褋泻懈泄',
+    es: '袠褋锌邪薪褋泻懈泄',
+    fr: '肖褉邪薪褑褍蟹褋泻懈泄',
+    de: '袧械屑械褑泻懈泄',
+    ru: '袪褍褋褋泻懈泄',
+    ar: '袗褉邪斜褋泻懈泄',
+    pt: '袩芯褉褌.',
+    ko: '袣芯褉械泄褋泻懈泄',
+    standardMode: '小褌邪薪写邪褉褌薪褘泄 褉械卸懈屑',
+    simpleMode: '袩褉芯褋褌芯泄 褉械卸懈屑',
+    firstLogin: '袩械褉胁褘泄 胁褏芯写',
+    backlight: '袩芯写褋胁械褌泻邪',
+    brightness: '袘械谢邪褟 锌芯写褋胁械褌泻邪',
+    nirBrightness: '袠袣-锌芯写褋胁械褌泻邪',
+    never: '袧懈泻芯谐写邪',
+    min1: '1 屑懈薪褍褌邪',
+    min2: '2 屑懈薪褍褌褘',
+    min3: '3 屑懈薪褍褌褘',
+    min4: '4 屑懈薪褍褌褘',
+    min5: '5 屑懈薪褍褌',
+    networkConfiguration: '小械褌褜',
+    otherConfiguration: '袩褉芯褔械械',
+    ipConfiguration: 'IP 薪邪褋褌褉芯泄泻懈',
+    devicePassword: '袩邪褉芯谢褜 褍褋褌褉芯泄褋褌胁邪',
+    protocolPassword: '袩邪褉芯谢褜 锌褉芯褌芯泻芯谢邪',
+    networkType: '孝懈锌 褋械褌懈',
+    ethernet: 'Ethernet',
+    wifiName: 'Wi鈥慒i',
+    wifiPassword: '袩邪褉芯谢褜 Wi鈥慒i',
+    dhcpModeSelection: '袪械卸懈屑 DHCP',
+    dhcpMode: '袗胁褌芯',
+    customNetworkConfiguration: '袪褍褔薪芯泄',
+    ipAddress: 'IP-邪写褉械褋',
+    gateway: '楔谢褞蟹',
+    subnetMask: '袦邪褋泻邪 锌芯写褋械褌懈',
+    dnsServer: 'DNS 褋械褉胁械褉',
+    mac: 'MAC',
+    mqttRelatedConfiguration: 'MQTT',
+    mqttConnectionInformation: '袩芯写泻谢褞褔械薪懈械 MQTT',
+    sessionConfiguration: '小械褋褋懈褟',
+    serverAddress: '袗写褉械褋 褋械褉胁械褉邪',
+    clientID: 'ID 泻谢懈械薪褌邪',
+    userName: '袠屑褟 锌芯谢褜蟹芯胁邪褌械谢褟',
+    userPassword: '袩邪褉芯谢褜',
+    topicPrefix: '袩褉械褎懈泻褋 褌芯锌懈泻邪',
+    onlineChecking: '袨薪谢邪泄薪-锌褉芯胁械褉泻邪',
+    onlineCheckingTimeout: '孝邪泄屑-邪褍褌',
+    cleanSession: '袨褔懈褋褌懈褌褜 褋械褋褋懈褞',
+    clientIdSuffix: '小褍褎褎懈泻褋 ID',
+    willTopic: 'Will-褌芯锌懈泻',
+    enterpriseWechat:'袪械卸懈屑 Enterprise WeChat 薪械 写械泄褋褌胁褍械褌',
+    faceRelatedConfiguration: '袧邪褋褌褉芯泄泻懈 谢懈褑邪',
+    functionalInformation: '肖褍薪泻褑懈褟',
+    prompt: '袩芯写褋泻邪蟹泻邪',
+    faceSimilarityThreshold: '袩芯褉芯谐 褋褏芯卸械褋褌懈',
+    livenessDetectionFunction: '袩褉芯胁械褉泻邪 卸懈胁芯褋褌懈',
+    livenessDetectionThreshold: '袩芯褉芯谐 卸懈胁芯褋褌懈',
+    infraredImageDisplay: "袩芯泻邪蟹 袠袣-懈蟹芯斜褉邪卸械薪懈褟",
+    maskRecognition: "袪邪褋锌芯蟹薪邪胁邪薪懈械 屑邪褋泻懈",
+    strangerVoice: "袚芯谢芯褋 薪械蟹薪邪泻芯屑褑邪",
+    voiceMode: "袪械卸懈屑 谐芯谢芯褋邪",
+    voiceModeDate: '袩芯谢褜蟹芯胁邪褌械谢褜褋泻芯械 锌褉懈胁械褌褋褌胁懈械',
+    imageSaveType: "孝懈锌 褋芯褏褉邪薪械薪懈褟",
+    saveStrangerImage: "小芯褏褉邪薪褟褌褜 谢懈褑芯 薪械蟹薪邪泻芯屑褑邪",
+    fullView: "袩邪薪芯褉邪屑邪",
+    face: "袥懈褑芯",
+    broadcastPleaseRegisterFirst: '袩褉芯懈谐褉褘胁邪褌褜 "小薪邪褔邪谢邪 蟹邪褉械谐懈褋褌褉懈褉褍泄褌械褋褜"',
+    broadcastHelloStranger: '袩褉芯懈谐褉褘胁邪褌褜 "袧械蟹薪邪泻芯屑械褑"',
+    broadcastName: '袩褉芯懈谐褉褘胁邪褌褜 懈屑褟',
+    broadcastGreeting: '袩褉芯懈谐褉褘胁邪褌褜 褋胁芯褢 锌褉懈胁械褌褋褌胁懈械',
+    greeting: '袩褉懈胁械褌褋褌胁懈械',
+    broadcastWelcome: '袩褉芯懈谐褉褘胁邪褌褜 "袛芯斜褉芯 锌芯卸邪谢芯胁邪褌褜"',
+    recognitionSwitch: '袩械褉械泻谢褞褔邪褌械谢褜 锌芯胁褌芯褉薪芯泄 锌褉芯胁械褉泻懈',
+    systemRelatedConfiguration: '小懈褋褌械屑邪',
+    functionSwitch: '袩械褉械泻谢褞褔邪褌械谢懈',
+    cardSwipingSwitch: '袣邪褉褌邪',
+    passwordSwitch: '袩邪褉芯谢褜',
+    strangerImage: '肖芯褌芯 薪械蟹薪邪泻芯屑褑邪',
+    cloudCertificateSwitch: '袨斜谢邪褔薪褘泄 褋械褉褌懈褎懈泻邪褌',
+    physicalCardNumber: '袧芯屑械褉 泻邪褉褌褘',
+    cloudCertificateAcquisition: '袩芯谢褍褔械薪懈械 芯斜谢邪褔薪芯谐芯 褋械褉褌懈褎懈泻邪褌邪',
+    heartbeatConfig: 'Heartbeat',
+    heartbeatSwitch: '袙泻谢./胁褘泻谢. heartbeat',
+    heartRateInterval: '袠薪褌械褉胁邪谢',
+    heartbeatTopic: '孝芯锌懈泻 heartbeat',
+    heartbeatContent: '小芯写械褉卸懈屑芯械',
+    basicInformation: '袘邪蟹芯胁邪褟 懈薪褎芯褉屑邪褑懈褟',
+    deviceMac: 'MAC',
+    uuid: 'UUID',
+    sn: 'SN',
+    model: '袦芯写械谢褜',
+    version: "袙械褉褋懈褟",
+    appVersion: "袙械褉褋懈褟 锌褉芯褕懈胁泻懈",
+    releaseTime: "袙褉械屑褟 芯斜薪芯胁谢械薪懈褟",
+    totaldisk: '袨斜褖邪褟 锌谢芯褖邪写褜',
+    freedisk: '袨褋褌邪胁褕械械褋褟 锌褉芯褋褌褉邪薪褋褌胁芯',
+    passageConfiguration: '袩褉芯褏芯写',
+    functionConfiguration: '肖褍薪泻褑懈懈',
+    numberOfPassageRecords: '袦邪泻褋. 蟹邪锌懈褋械泄 锌褉芯褏芯写邪',
+    durationOfRelayOpening: '袙褉械屑褟 褉械谢械',
+    alarmSwitch: '小懈谐薪邪谢懈蟹邪褑懈褟',
+    fireAlarmSwitch: '袩芯卸邪褉薪邪褟 褋懈谐薪邪谢懈蟹邪褑懈褟',
+    fireAlarmStatus: '小褌邪褌褍褋 锌芯卸邪褉邪',
+    normal: '袧芯褉屑邪',
+    warning: '袩褉械写褍锌褉械卸写械薪懈械',
+    tamperSwitch: '孝邪屑锌械褉芯胁泻邪',
+    uploadToCloudSwitch: '袩械褉械泻谢褞褔邪褌械谢褜 蟹邪谐褉褍蟹泻懈 谢懈褑邪',
+    clockConfiguration: '效邪褋褘',
+    timeSynchronizationSwitch: '小懈薪褏褉芯薪懈蟹邪褑懈褟 胁褉械屑械薪懈',
+    timeSynchronizationServerIP: '小械褉胁械褉 胁褉械屑械薪懈',
+    timedSynchronizationTime: '袙褉械屑褟 褋懈薪褏褉芯薪懈蟹邪褑懈懈',
+    timeZone: '效邪褋芯胁芯泄 锌芯褟褋',
+    setDeviceTime: '校褋褌邪薪芯胁懈褌褜 胁褉械屑褟',
+    restartAfterSetting: '袩芯褋谢械 褍褋褌邪薪芯胁泻懈 褍褋褌褉芯泄褋褌胁芯 锌械褉械蟹邪锌褍褋褌懈褌褋褟',
+    cloudCertificateActivation: '袗泻褌懈胁邪褑懈褟 褋械褉褌懈褎懈泻邪褌邪',
+    activationKey: '袣谢褞褔 邪泻褌懈胁邪褑懈懈',
+    cloudTips1: '袙胁械写懈褌械 泻谢褞褔 斜械蟹 锌褉芯斜械谢芯胁',
+    cloudTips2: '袩芯褋谢械 邪泻褌懈胁邪褑懈懈 锌芯写泻谢褞褔懈褌褋褟 泻 芯斜谢邪褔薪芯屑褍 褋械褉胁懈褋褍',
+    confirmActivation: '袩芯写褌胁械褉写懈褌褜 邪泻褌懈胁邪褑懈褞',
+    activationInProgress: '袗泻褌懈胁邪褑懈褟...',
+    activationFailed: '小斜芯泄 邪泻褌懈胁邪褑懈懈',
+    activationSuccessful: '袗泻褌懈胁邪褑懈褟 褍褋锌械褕薪邪',
+    passwordModification: '袠蟹屑械薪械薪懈械 锌邪褉芯谢褟',
+    password: '袩邪褉芯谢褜',
+    oldPassword: '小褌邪褉褘泄 锌邪褉芯谢褜',
+    newPassword: '袧芯胁褘泄 锌邪褉芯谢褜',
+    confirmPassword: '袩芯写褌胁械褉写懈褌械 锌邪褉芯谢褜',
+    passwordRule: '袪械泻芯屑械薪写邪褑懈懈 锌芯 锌邪褉芯谢褞',
+    passwordLength: '袛谢懈薪邪 鈮�6',
+    cannotBeTheSame: '袙褋械 褋懈屑胁芯谢褘 薪械 屑芯谐褍褌 斜褘褌褜 芯写懈薪邪泻芯胁褘屑懈',
+    cannotOrder: '袧械 屑械薪械械 3 锌芯写褉褟写 褑懈褎褉/斜褍泻胁',
+    cannotWeakPassword: '袧械 懈褋锌芯谢褜蟹芯胁邪褌褜 褋谢邪斜褘械 锌邪褉芯谢懈',
+    submit: '袨褌锌褉邪胁懈褌褜',
+    saveConfig: '小芯褏褉邪薪懈褌褜',
+    msg_please_enter: '袙胁械写懈褌械 褋芯写械褉卸邪薪懈械',
+    msg_inputPassword: '袙胁械写懈褌械 锌邪褉芯谢褜',
+    msg_oldPasswordError: '小褌邪褉褘泄 锌邪褉芯谢褜 薪械胁械褉械薪',
+    msg_password_mismatch: '袩邪褉芯谢懈 薪械 褋芯胁锌邪写邪褞褌',
+    msg_password_min_length: '袦懈薪懈屑褍屑 6 褋懈屑胁芯谢芯胁',
+    msg_is_weak_password: '小谢邪斜褘泄 锌邪褉芯谢褜, 褋屑械薪懈褌械',
+    msg_pswChangeSuccessAndLogin: '袩邪褉芯谢褜 懈蟹屑械薪褢薪, 胁芯泄写懈褌械 褋薪芯胁邪',
+    msg_pswChangeSuccess: '袩邪褉芯谢褜 懈蟹屑械薪褢薪',
+    msg_pswChangeFail: '袧械 褍写邪谢芯褋褜 懈蟹屑械薪懈褌褜 锌邪褉芯谢褜',
+    msg_saveSuccess: '校褋锌械褕薪芯 褋芯褏褉邪薪械薪芯',
+    msg_saveFail: '小芯褏褉邪薪械薪懈械 薪械 褍写邪谢芯褋褜',
+    msg_formFilled: '袩褉芯胁械褉褜褌械 褎芯褉屑褍',
+    msg_number_0_23: '孝芯谢褜泻芯 0-23',
+    msg_number_0_24: '孝芯谢褜泻芯 0-24',
+    msg_noChange: '袧械褌 懈蟹屑械薪械薪懈泄 泻芯薪褎懈谐褍褉邪褑懈懈 写谢褟 褋芯褏褉邪薪械薪懈褟',
+    resourceConfiguration: '袧邪褋褌褉芯泄泻懈 褉械褋褍褉褋芯胁',
+    backgroundImage: '肖芯薪芯胁芯械 懈蟹芯斜褉邪卸械薪懈械',
+    selectImage: '袙褘斜褉邪褌褜 懈蟹芯斜褉邪卸械薪懈械',
+    uploadBackground: '袟邪谐褉褍蟹懈褌褜 褎芯薪',
+    uploading: '袟邪谐褉褍蟹泻邪...',
+    backgroundUploadTip: '袟邪谐褉褍蟹懈褌械 懈蟹芯斜褉邪卸械薪懈械 胁 褎芯褉屑邪褌械 PNG 褋 褉邪蟹褉械褕械薪懈械屑 {n} 锌懈泻褋械谢械泄, 懈蟹芯斜褉邪卸械薪懈械 斜褍写械褌 锌褉械芯斜褉邪蟹芯胁邪薪芯 胁 Base64 懈 蟹邪谐褉褍卸械薪芯 薪邪 褍褋褌褉芯泄褋褌胁芯',
+    backgroundResolutionMismatch: '袪邪蟹褉械褕械薪懈械 懈蟹芯斜褉邪卸械薪懈褟 写芯谢卸薪芯 斜褘褌褜 {n}',
+    backgroundRequired: '袙褘斜械褉懈褌械 褎芯薪芯胁芯械 懈蟹芯斜褉邪卸械薪懈械',
+    backgroundImageOnlyPNG: '孝芯谢褜泻芯 PNG',
+    backgroundSizeLimit: '袪邪蟹屑械褉 鈮� 5MB',
+    backgroundParseFailed: '袧械 褍写邪谢芯褋褜 锌褉芯褔懈褌邪褌褜 懈蟹芯斜褉邪卸械薪懈械',
+    backgroundImageSelected: '袠蟹芯斜褉邪卸械薪懈械 胁褘斜褉邪薪芯',
+    backgroundSuccess: '肖芯薪 蟹邪谐褉褍卸械薪',
+    backgroundFailed: '袨褕懈斜泻邪 蟹邪谐褉褍蟹泻懈 褎芯薪邪',
+    scanSettings: '袧邪褋褌褉芯泄泻懈 褋泻邪薪懈褉芯胁邪薪懈褟',
+    scanSwitch: '袩械褉械泻谢褞褔邪褌械谢褜 褋泻邪薪懈褉芯胁邪薪懈褟',
+    scanInterval: '袠薪褌械褉胁邪谢 褋泻邪薪懈褉芯胁邪薪懈褟',
+  },
+  person: {
+    idCard: '袧芯屑械褉 褍写芯褋褌芯胁械褉械薪懈褟',
+    userType: '孝懈锌 锌芯谢褜蟹芯胁邪褌械谢褟',
+    administrator: '袗写屑懈薪懈褋褌褉邪褌芯褉',
+    userId: 'ID',
+    user: '袩芯谢褜蟹芯胁邪褌械谢褜',
+    voucher: '校写芯褋褌芯胁械褉械薪懈械',
+    permission: '袪邪蟹褉械褕械薪懈械',
+    addUser: '袛芯斜邪胁懈褌褜 锌芯谢褜蟹芯胁邪褌械谢褟',
+    name: '袠屑褟',
+    editUser: '袪械写邪泻褌懈褉芯胁邪褌褜',
+    placeholderUserId: '袙胁械写懈褌械 ID',
+    placeholderName: '袙胁械写懈褌械 懈屑褟',
+    userNotExist: '袩芯谢褜蟹芯胁邪褌械谢褜 薪械 薪邪泄写械薪',
+    oneClickClear: '袨褔懈褋褌懈褌褜 胁褋械',
+    clearTips: '袘褍写褍褌 褍写邪谢械薪褘 胁褋械 写邪薪薪褘械, 锌褉芯写芯谢卸懈褌褜?',
+    clearSuccess: '校褋锌械褕薪芯 芯褔懈褖械薪芯',
+    clearFailed: '袧械 褍写邪谢芯褋褜 芯褔懈褋褌懈褌褜',
+  },
+  voucher: {
+    password: '袩邪褉芯谢褜',
+    card: '袣邪褉褌邪',
+    face: '袥懈褑芯',
+    finger: '袨褌锌械褔邪褌芯泻',
+    code: '袣芯写',
+    codeType: '孝懈锌 泻芯写邪',
+    passthroughCode: '小泻胁芯蟹薪芯泄 泻芯写',
+    staticCode: '小褌邪褌懈褔械褋泻懈泄 泻芯写',
+    dynamicCode: '袛懈薪邪屑懈褔械褋泻懈泄 泻芯写',
+    credentialId: 'ID 褍褔械褌薪褘褏 写邪薪薪褘褏',
+    credentialValue: '袟薪邪褔械薪懈械 褍褔械褌薪褘褏 写邪薪薪褘褏',
+    placeholderCode: '袩芯卸邪谢褍泄褋褌邪, 胁胁械写懈褌械 泻芯写 褋械褉褌懈褎懈泻邪褌邪',
+    placeholderPwd: '袙胁械写懈褌械 锌邪褉芯谢褜',
+    placeholderCard: '袙胁械写懈褌械 泻邪褉褌褍',
+    validPassword: '袙胁械写懈褌械 6 褑懈褎褉',
+    validCard: '袙胁械写懈褌械 8 褑懈褎褉 懈谢懈 斜褍泻胁',
+    photoRegistration: '袪械谐懈褋褌褉邪褑懈褟 褎芯褌芯',
+    featureValueRegistration: '袪械谐懈褋褌褉邪褑懈褟 锌褉懈蟹薪邪泻芯胁',
+    fingerRegistration: '袪械谐懈褋褌褉邪褑懈褟 芯褌锌械褔邪褌泻邪',
+    fingerFeatureRegistration: '袪械谐懈褋褌褉邪褑懈褟 锌芯 蟹薪邪褔械薪懈褞 锌褉懈蟹薪邪泻邪',
+    fingerInput: '袩褉懈谢芯卸懈褌械 锌邪谢械褑 泻 褋泻邪薪械褉褍 芯褌锌械褔邪褌泻芯胁',
+    fingerRemainingTime: '袨褋褌邪胁褕械械褋褟 胁褉械屑褟',
+    fingerInputting: '袠写褢褌 胁胁芯写...',
+    startFingerInput: '袧邪褔邪褌褜 胁胁芯写 芯褌锌械褔邪褌泻邪',
+    fingerInputTips: '袙胁械写懈褌械 蟹薪邪褔械薪懈械 锌褉懈蟹薪邪泻邪 芯褌锌械褔邪褌泻邪',
+    fingerWaitInput: '袨卸懈写邪薪懈械 胁胁芯写邪',
+    fingerInputNow: '袠写褢褌 胁胁芯写 芯褌锌械褔邪褌泻邪...',
+    fingerInputSuccess: '袙胁芯写 褍褋锌械褕械薪',
+    fingerInputFailed: '袧械 褍写邪谢芯褋褜 蟹邪锌褍褋褌懈褌褜 胁胁芯写 芯褌锌械褔邪褌泻邪',
+    fingerReTry: '袨褕懈斜泻邪 胁胁芯写邪 芯褌锌械褔邪褌泻邪, 锌芯锌褉芯斜褍泄褌械 械褖褢 褉邪蟹',
+    fingerFilled: '袙胁芯写 芯褌锌械褔邪褌泻邪 褍褋锌械褕械薪, 蟹薪邪褔械薪懈械 锌褉懈蟹薪邪泻邪 蟹邪锌芯谢薪械薪芯 邪胁褌芯屑邪褌懈褔械褋泻懈',
+    fingerFailed: '袨褕懈斜泻邪 胁胁芯写邪 芯褌锌械褔邪褌泻邪',
+    fingerTimeout: '袙褉械屑褟 胁褘褕谢芯',
+    fingerInputTimeout: '袙褉械屑褟 胁胁芯写邪 芯褌锌械褔邪褌泻邪 懈褋褌械泻谢芯, 锌芯锌褉芯斜褍泄褌械 械褖褢 褉邪蟹',
+    fingerError: '袙胁芯写 薪械 胁褘锌芯谢薪械薪',
+    fingerInputError: '袨褕懈斜泻邪 胁胁芯写邪 芯褌锌械褔邪褌泻邪, 锌芯锌褉芯斜褍泄褌械 械褖褢 褉邪蟹',
+    fingerInputed: '袨褌锌械褔邪褌芯泻 褍卸械 蟹邪褉械谐懈褋褌褉懈褉芯胁邪薪',
+    fingerReInput: '袩芯胁褌芯褉薪芯 胁胁械褋褌懈 芯褌锌械褔邪褌芯泻',
+  },
+  permission: {
+    deletePermission: '校写邪谢懈褌褜 褉邪蟹褉械褕械薪懈械',
+    addPermission: '袛芯斜邪胁懈褌褜 褉邪蟹褉械褕械薪懈械',
+    permissionId: 'ID 褉邪蟹褉械褕械薪懈褟',
+    userId: 'ID 锌芯谢褜蟹芯胁邪褌械谢褟',
+    timeRange: '袙褉械屑械薪薪芯泄 写懈邪锌邪蟹芯薪',
+    extra: '袛芯锌芯谢薪懈褌械谢褜薪芯',
+    effectiveType: '孝懈锌 写械泄褋褌胁懈褟',
+    effectiveTime: '袙褉械屑褟 写械泄褋褌胁懈褟',
+    effectiveWeek: '袧械写械谢褟 写械泄褋褌胁懈褟',
+    timePeriod: '袩械褉懈芯写',
+    addTimePeriod: '袛芯斜邪胁懈褌褜 锌械褉懈芯写',
+    modify_previous_time: '小薪邪褔邪谢邪 懈蟹屑械薪懈褌械 锌褉械写褘写褍褖懈泄 锌械褉懈芯写',
+    cannot_be_earlier: '袣芯薪械褑 薪械 屑芯卸械褌 斜褘褌褜 褉邪薪褜褕械 薪邪褔邪谢邪',
+    times_cannot_overlap: '袙褉械屑褟 薪械 写芯谢卸薪芯 锌械褉械褋械泻邪褌褜褋褟',
+    choose_time_range: '袙褘斜械褉懈褌械 写懈邪锌邪蟹芯薪',
+    unlimitedMode: '袘械蟹 芯谐褉邪薪懈褔械薪懈泄',
+    usualMode: '袨斜褘褔薪褘泄 褉械卸懈屑',
+    dailyMode: '袝卸械写薪械胁薪褘泄',
+    weeklyRepetitionMode: '袝卸械薪械写械谢褜薪褘泄',
+    time_range: '袛懈邪锌邪蟹芯薪 胁褉械屑械薪懈',
+  },
+  common: {
+    startDate: '袛邪褌邪 薪邪褔邪谢邪',
+    endDate: '袛邪褌邪 芯泻芯薪褔邪薪懈褟',
+    to: '写芯',
+    cancel: '袨褌屑械薪邪',
+    confirm: '袩芯写褌胁械褉写懈褌褜',
+    close: '袟邪泻褉褘褌褜',
+    delete: '校写邪谢懈褌褜',
+    edit: '袠蟹屑械薪懈褌褜',
+    batchDelete: '袩邪泻械褌薪芯械 褍写邪谢械薪懈械',
+    startTime: '袙褉械屑褟 薪邪褔邪谢邪',
+    endTime: '袙褉械屑褟 芯泻芯薪褔邪薪懈褟',
+    monday: '袩芯薪械写械谢褜薪懈泻',
+    tuseday: '袙褌芯褉薪懈泻',
+    wednesday: '小褉械写邪',
+    thursday: '效械褌胁械褉谐',
+    friday: '袩褟褌薪懈褑邪',
+    saterday: '小褍斜斜芯褌邪',
+    sunday: '袙芯褋泻褉械褋械薪褜械',
+    placeholder: '袩芯卸邪谢褍泄褋褌邪, 胁胁械写懈褌械',
+    placeholderSelect: '袩芯卸邪谢褍泄褋褌邪, 胁褘斜械褉懈褌械',
+    closeTips: '袩芯写褌胁械褉写懈褌褜 蟹邪泻褉褘褌懈械?',
+    deleteTips: '袩芯写褌胁械褉写懈褌褜 褍写邪谢械薪懈械?',
+    deleteSuccess: '校写邪谢械薪芯 褍褋锌械褕薪芯',
+    addSuccess: '校褋锌械褕薪芯 写芯斜邪胁谢械薪芯',
+    editSuccess: '校褋锌械褕薪芯 懈蟹屑械薪械薪芯',
+    saveSuccess: '小芯褏褉邪薪械薪芯',
+    tips: '袩芯写褋泻邪蟹泻邪',
+    operation: '袨锌械褉邪褑懈褟',
+    query: '袟邪锌褉芯褋',
+    reset: '小斜褉芯褋',
+    noData: '袧械褌 写邪薪薪褘褏',
+    export: '协泻褋锌芯褉褌',
+    success: '校褋锌械褏',
+    failure: '袧械褍写邪褔邪',
+    incorrectFormat: '袧械胁械褉薪褘泄 褎芯褉屑邪褌',
+    integerFormat: '笑械谢芯械 褔懈褋谢芯 鈮�0',
+    positiveIntegerFormat: '笑械谢芯械 褔懈褋谢芯 >0',
+    noDataSaved: '袧械褌 写邪薪薪褘褏 写谢褟 褋芯褏褉邪薪械薪懈褟',
+    chinese: '袣懈褌邪泄褋泻懈泄',
+    english: '袗薪谐谢懈泄褋泻懈泄',
+    spanish: '袠褋锌邪薪褋泻懈泄',
+    french: '肖褉邪薪褑褍蟹褋泻懈泄',
+    german: '袧械屑械褑泻懈泄',
+    russian: '袪褍褋褋泻懈泄',
+    arabic: '袗褉邪斜褋泻懈泄',
+    portuguese: '袩芯褉褌褍谐邪谢褜褋泻懈泄',
+    korean: '袣芯褉械泄褋泻懈泄',
+    detail: '袩芯写褉芯斜薪芯褋褌懈',
+    clearTips: '袩芯写褌胁械褉写懈褌褜 芯褔懈褋褌泻褍?',
+    clearSuccess: '校褋锌械褕薪芯 芯褔懈褖械薪芯',
+  },
+  log: {
+    accessMethod: '小锌芯褋芯斜 写芯褋褌褍锌邪',
+    passingTime: '袙褉械屑褟 锌褉芯褏芯写邪',
+    accessPass: '校写芯褋褌芯胁械褉械薪懈械',
+    accessResult: '袪械蟹褍谢褜褌邪褌',
+    accessPhoto: '肖芯褌芯',
+    viewPhotos: '袩褉芯褋屑芯褌褉 褎芯褌芯'
+  },
+  error: {
+    networkError: '小斜芯泄 褋械褌懈, 锌褉芯胁械褉褜褌械 锌芯写泻谢褞褔械薪懈械',
+    timeout: '孝邪泄屑-邪褍褌, 锌芯锌褉芯斜褍泄褌械 褋薪芯胁邪',
+    serverError: '袙薪褍褌褉械薪薪褟褟 芯褕懈斜泻邪 褋械褉胁械褉邪',
+    notFound: '袪械褋褍褉褋 薪械 薪邪泄写械薪',
+    unauthorized: '袧械 邪胁褌芯褉懈蟹芯胁邪薪, 胁芯泄写懈褌械 褋薪芯胁邪',
+    noResponse: '袧械褌 芯褌胁械褌邪 褋械褉胁械褉邪',
+    unknownError: '袨褕懈斜泻邪 蟹邪锌褉芯褋邪, 泻芯写:',
+    requestFailed: '袟邪锌褉芯褋 薪械 胁褘锌芯谢薪械薪'
+  },
+  security: {
+    keyId: 'ID 泻谢褞褔邪',
+    keyType: '孝懈锌 泻谢褞褔邪',
+    keyEncoding: '袣芯写懈褉芯胁泻邪 泻谢褞褔邪',
+    keyValue: '袟薪邪褔械薪懈械 泻谢褞褔邪',
+    startTime: '袙褉械屑褟 薪邪褔邪谢邪',
+    expirationTime: '袙褉械屑褟 懈褋褌械褔械薪懈褟',
+    newKey: '袛芯斜邪胁懈褌褜 泻谢褞褔',
+    clearKey: '袨褔懈褋褌懈褌褜 泻谢褞褔',
+    validTime: '小褉芯泻 写械泄褋褌胁懈褟',
+  }
+}
diff --git "a/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/language/zh.js" "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/language/zh.js"
new file mode 100644
index 0000000..e899b56
--- /dev/null
+++ "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/language/zh.js"
@@ -0,0 +1,452 @@
+export default {
+  // 鐧诲綍椤�
+  login: {
+    lang: '璇█',
+    systemname: '浜鸿劯璁惧鍚庡彴鐧诲綍',
+    username: '鐢ㄦ埛鍚�',
+    username_label: '璇疯緭鍏ョ敤鎴峰悕',
+    pwd: '瀵嗙爜',
+    pwd_label: '璇疯緭鍏ュ瘑鐮�',
+    pwd_info: '璇疯緭鍏ユ纭瘑鐮佹牸寮�',
+    success_msg: '鐧诲綍鎴愬姛',
+    error_name: '瀵嗙爜閿欒',
+    error_res: '涓嶇鍚堢櫥褰曡姹�',
+    login: '鐧诲綍',
+  },
+  // 渚ц竟鏍忛儴鍒�
+  aside: {
+    systemname: '浜鸿劯璁惧鍚庡彴',
+    quit: '閫�鍑�',
+    deviceControl: '璁惧鎺у埗',
+    basicSetting: '鍩虹璁剧疆',
+    workerSetting: '浜哄憳璁剧疆',
+    deviceMonitoring: '璁惧鐩戞帶',
+    recordManagement: '璁板綍绠$悊',
+    securityManagement: '瀵嗛挜绠$悊',
+    tips: '鎻愮ず',
+    tips_msg: '鏄惁閫�鍑虹櫥褰�',
+  },
+  // 璁惧鎺у埗椤甸潰
+  control: {
+    remoteControl: '杩滅▼鎺у埗',
+    restart: '璁惧閲嶅惎',
+    clickToRestart: '鐐瑰嚮閲嶅惎璁惧',
+    restartConfirm: '纭畾瑕侀噸鍚澶囧悧锛�',
+    restartSuccess: '閲嶅惎鎴愬姛',
+    restartFailed: '閲嶅惎澶辫触',
+    remoteOpen: '杩滅▼寮�闂�',
+    clickToOpen: '鐐瑰嚮杩滅▼寮�闂�',
+    openConfirm: '纭畾瑕佽繙绋嬪紑闂ㄥ悧锛�',
+    remoteOpenSuccess: '杩滅▼寮�闂ㄦ垚鍔�',
+    remoteOpenFailed: '杩滅▼寮�闂ㄥけ璐�',
+    reset: '璁惧閲嶇疆',
+    clickToReset: '鐐瑰嚮閲嶇疆璁惧',
+    resetConfirm: '纭畾瑕侀噸缃澶囧悧锛�',
+    resetWillOut: "閲嶇疆鍚庡皢閫�鍑虹櫥褰�",
+    resetSuccess: '璁惧閲嶇疆鎴愬姛',
+    resetFailed: '璁惧閲嶇疆澶辫触',
+    firmwareUpgrade: '璁惧鍗囩骇',
+    upgradeConfig: '鍗囩骇閰嶇疆',
+    firmwareUrl: '鍥轰欢鍦板潃',
+    md5Checksum: 'md5鍊�',
+    startUpgrade: '寮�濮嬪崌绾�',
+    urlRequired: '鏂囦欢鍦板潃蹇呭~',
+    md5Required: 'md5鍊煎繀濉�',
+    urlInvalid: '璇疯緭鍏ユ纭殑鍦板潃',
+    md5Invalid: '璇疯緭鍏ユ纭殑md5',
+    upgradeConfirm: '纭畾鍗囩骇璁惧鍚楋紵',
+    upgradeSuccess: '璁惧鍗囩骇鎴愬姛',
+    clearFile: "娓呴櫎鏂囦欢",
+    uploading: '涓婁紶鍗囩骇涓�...',
+    uploadAndUpgrade: '涓婁紶骞跺崌绾�',
+    restartTips: '瀹夊叏閲嶅惎璁惧绯荤粺锛屼笉浼氫涪澶辨暟鎹�',
+    restarting: '閲嶅惎涓�...',
+    remoteTips: '杩滅▼鎺у埗闂ㄧ璁惧寮�鍚�',
+    opening: '寮�闂ㄤ腑...',
+    resetTips: '鎭㈠鍑哄巶璁剧疆锛屾竻闄ゆ墍鏈夋暟鎹�',
+    reseting: '閲嶇疆涓�...',
+    urlUpgrade: 'URL鍗囩骇鏂瑰紡',
+    fileUpgrade: '鏂囦欢涓婁紶鍗囩骇',
+    uploadFile: '鐐瑰嚮涓婁紶鍥轰欢鏂囦欢',
+    formatFile: '鏀寔 .zip 鎴� .dpk 鏍煎紡鏂囦欢锛屾渶澶� 20MB',
+    fileName: '鏂囦欢鍚�',
+    size: '澶у皬',
+  },
+  // 鍩虹璁剧疆椤甸潰
+  config: {
+    second: '绉�',
+    millisecond: '姣',
+    min: '鍒嗛挓',
+    notsave: '涓嶄繚瀛�',
+    save: '淇濆瓨',
+    noVoice: '鏃犺闊�',
+    no: '鍚�',
+    yes: '鏄�',
+    // 鍩虹閰嶇疆
+    basicConfiguration: '鍩虹閰嶇疆',
+    displaySettings: '鏄剧ず璁剧疆',
+    informationDisplay: '淇℃伅鏄剧ず',
+    audioSettings: '闊抽璁剧疆',
+    languageAndThemes: '璇█涓庝富棰�',
+    autoAdjustScreenBrightness: '鑷姩璋冭妭灞忓箷浜害',
+    screenBrightness: '灞忓箷浜害',
+    autoTurnOffScreen: '鑷姩鎭睆',
+    autoTurnOffScreenTime: '鑷姩鎭睆鏃堕棿',
+    autoScreenSaver: '鑷姩灞忎繚',
+    autoScreenSaverTime: '鑷姩灞忎繚鏃堕棿',
+    displayDeviceSn: '鏄剧ずSN',
+    displayIp: '鏄剧ずIP',
+    displayIdentityCard: '鏄剧ず浜戣瘉',
+    volume: '闊抽噺',
+    language: '璇█',
+    displayCode: "鏄剧ず灏忕▼搴忕爜",
+    themeMode: "宸ヤ綔涓婚",
+    cn: '涓枃',
+    en: '鑻辨枃',
+    es: '瑗跨彮鐗欒',
+    fr: '娉曡',
+    de: '寰疯',
+    ru: '淇勮',
+    ar: '闃挎媺浼',
+    pt: '钁¤悇鐗欒',
+    ko: '闊╄',
+    standardMode: '鏍囧噯妯″紡',
+    simpleMode: '绠�绾︽ā寮�',
+    firstLogin: '绗竴娆$櫥褰曞悗鍙�',
+    backlight: '灞忓箷鑳屽厜',
+    brightness: '鐧借壊琛ュ厜鐏�',
+    nirBrightness: '绾㈠琛ュ厜鐏�',
+    never: '姘镐笉',
+    min1: '1鍒嗛挓',
+    min2: '2鍒嗛挓',
+    min3: '3鍒嗛挓',
+    min4: '4鍒嗛挓',
+    min5: '5鍒嗛挓',
+    // 缃戠粶閰嶇疆
+    networkConfiguration: '缃戠粶閰嶇疆',
+    otherConfiguration: '鍏朵粬閰嶇疆',
+    ipConfiguration: 'IP閰嶇疆',
+    devicePassword: '璁惧瀵嗙爜 ',
+    protocolPassword: '閫氫俊鍗忚瀵嗙爜',
+    networkType: '缃戠粶绫诲瀷 ',
+    ethernet: '浠ュお缃�',
+    wifiName: 'Wi-Fi鍚�',
+    wifiPassword: 'Wi-Fi瀵嗙爜',
+    dhcpModeSelection: 'DHCP妯″紡',
+    dhcpMode: '鑷姩鑾峰彇',
+    customNetworkConfiguration: '鎵嬪姩閰嶇疆',
+    ipAddress: 'ip鍦板潃',
+    gateway: '缃戝叧',
+    subnetMask: '瀛愮綉鎺╃爜',
+    dnsServer: 'DNS鏈嶅姟鍣�',
+    mac: '缃戠粶mac',
+    // MQTT閰嶇疆
+    mqttRelatedConfiguration: 'MQTT閰嶇疆',
+    mqttConnectionInformation: 'MQTT杩炴帴淇℃伅',
+    sessionConfiguration: '浼氳瘽閰嶇疆',
+    serverAddress: '鏈嶅姟鍣ㄥ湴鍧�',
+    clientID: '瀹㈡埛绔疘D',
+    userName: '鐢ㄦ埛鍚�',
+    userPassword: '鐢ㄦ埛瀵嗙爜',
+    topicPrefix: '涓婚鍓嶇紑',
+    onlineChecking: '鍦ㄧ嚎楠岃瘉',
+    onlineCheckingTimeout: "鍦ㄧ嚎楠岃瘉瓒呮椂",
+    cleanSession: '娓呴櫎浼氳瘽',
+    clientIdSuffix: '瀹㈡埛绔疘D鍚庣紑',
+    willTopic: '閬楀槺涓婚',
+    enterpriseWechat:'浼佸井妯″紡鏃犳晥',
+    // 浜鸿劯閰嶇疆
+    faceRelatedConfiguration: '浜鸿劯閰嶇疆',
+    functionalInformation: '鍔熻兘淇℃伅',
+    prompt: '鎻愮ず璇�',
+    faceSimilarityThreshold: '浜鸿劯鐩镐技搴﹂槇鍊�',
+    livenessDetectionFunction: '娲讳綋妫�娴嬪姛鑳�',
+    livenessDetectionThreshold: '娲讳綋妫�娴嬮槇鍊�',
+    infraredImageDisplay: "绾㈠鍥惧儚鏄剧ず",
+    maskRecognition: "鍙g僵璇嗗埆",
+    strangerVoice: "闄岀敓浜鸿闊�",
+    voiceMode: "璇煶妯″紡",
+    voiceModeDate: '鑷畾涔夐棶鍊欒',
+    imageSaveType: "鍥惧儚淇濆瓨绫诲瀷",
+    saveStrangerImage: "淇濆瓨闄岀敓浜哄浘鍍�",
+    fullView: "鍏ㄦ櫙",
+    face: "浜鸿劯",
+    broadcastPleaseRegisterFirst: '鎾斁璇峰厛娉ㄥ唽鍒疯劯鍑瘉',
+    broadcastHelloStranger: '鎾斁鏈櫥璁颁汉鍛�',
+    broadcastName: '鎾斁鍚嶅瓧',
+    broadcastGreeting: '鎾斁鑷畾涔夐棶鍊欒',
+    greeting: '闂�欒  ',
+    broadcastWelcome: '鎾斁娆㈣繋鍏変复',
+    recognitionSwitch: '閲嶆寮�鍏�',
+    // 绯荤粺閰嶇疆
+    systemRelatedConfiguration: '绯荤粺閰嶇疆',
+    functionSwitch: '鍔熻兘寮�鍏�',
+    cardSwipingSwitch: '鍒峰崱寮�鍏�',
+    passwordSwitch: '瀵嗙爜寮�鍏�',
+    strangerImage: '闄岀敓浜哄浘鐗囧紑鍏�',
+    cloudCertificateSwitch: '浜戣瘉寮�鍏�',
+    physicalCardNumber: '鐗╃悊鍗″彿',
+    cloudCertificateAcquisition: '浜戣瘉鑾峰彇',
+    heartbeatConfig: '蹇冭烦璁剧疆',
+    heartbeatSwitch: '蹇冭烦寮�鍏�',
+    heartRateInterval: '蹇冭烦闂撮殧',
+    heartbeatTopic: '蹇冭烦涓婚',
+    heartbeatContent: '蹇冭烦鍐呭',
+    basicInformation: '鍩虹淇℃伅',
+    deviceMac: 'mac鍦板潃',
+    uuid: '璁惧uuid', 
+    sn: '璁惧sn鍙�',
+    model: '璁惧鍨嬪彿',
+    version: "鐗堟湰鍙�",
+    appVersion: "鍥轰欢鐗堟湰鍙�",
+    releaseTime: "鏇存柊鏃堕棿",
+    totaldisk: '璁惧鎬荤┖闂�',
+    freedisk: '鍓╀綑绌洪棿',
+    // 閫氳閰嶇疆
+    passageConfiguration: '閫氳閰嶇疆',
+    functionConfiguration: '鍔熻兘閰嶇疆',
+    numberOfPassageRecords: '閫氳璁板綍鏈�澶ф暟閲�',
+    durationOfRelayOpening: '缁х數鍣ㄦ墦寮�鏃堕暱',
+    alarmSwitch: '鎶ヨ寮�鍏�',
+    fireAlarmSwitch: '鐏寮�鍏�',
+    fireAlarmStatus: '鐏鐘舵��',
+    normal: '姝e父',
+    warning: '棰勮',
+    tamperSwitch: '闃叉媶鎶ヨ寮�鍏�',
+    uploadToCloudSwitch: '浜鸿劯涓婃姤寮�鍏�',
+    // 鏃堕挓閰嶇疆
+    clockConfiguration: '鏃堕挓閰嶇疆',
+    timeSynchronizationSwitch: '瀵规椂寮�鍏�',
+    timeSynchronizationServerIP: '瀵规椂鏈嶅姟鍣↖P',
+    timedSynchronizationTime: '瀹氭椂鍚屾鏃堕棿',
+    timeZone: '鏃跺尯',
+    setDeviceTime: '璁剧疆璁惧鏃堕棿',
+    restartAfterSetting: '鎿嶄綔鍚庤澶囪嚜鍔ㄩ噸鍚�',
+    // 浜戣瘉婵�娲�
+    cloudCertificateActivation: '浜戣瘉婵�娲�',
+    activationKey: '婵�娲诲瘑閽�',
+    cloudTips1: '璇疯緭鍏ユ縺娲诲瘑閽ワ紝纭繚娌℃湁绌烘牸',
+    cloudTips2: '婵�娲绘垚鍔熷悗璁惧灏嗚繛鎺ュ埌浜戣璇佹湇鍔�',
+    confirmActivation: '纭婵�娲�',
+    activationInProgress: '婵�娲讳腑...',
+    activationFailed: '婵�娲诲け璐�',
+    activationSuccessful: '婵�娲绘垚鍔�',
+    // 瀵嗙爜淇敼
+    passwordModification: '瀵嗙爜淇敼',
+    password: '瀵嗙爜',
+    oldPassword: '鏃у瘑鐮�',
+    newPassword: '鏂板瘑鐮�',
+    confirmPassword: '纭瀵嗙爜',
+    passwordRule: '瀵嗙爜瑙勫垯鎺ㄨ崘',
+    passwordLength: '闀垮害鈮�6',
+    cannotBeTheSame: '涓嶈兘鎵�鏈夊瓧绗︾浉鍚�',
+    cannotOrder: '涓嶈兘鍖呭惈鑷冲皯3涓繛缁暟瀛楁垨灏忓啓瀛楁瘝搴忓垪锛堝崌搴忔垨闄嶅簭锛�',
+    cannotWeakPassword: '涓嶈兘鏄父瑙佸急瀵嗙爜锛屽寘鎷�',
+    submit: '鎻愪氦',
+    saveConfig: '淇濆瓨璁剧疆',
+    // js涓璵sg鎻愮ず璇�
+    msg_please_enter: '璇疯緭鍏ュ唴瀹�',
+    msg_inputPassword: '璇疯緭鍏ュ瘑鐮�',
+    msg_oldPasswordError: '鏃у瘑鐮侀敊璇�',
+    msg_password_mismatch: '涓ゆ杈撳叆鐨勫瘑鐮佷笉涓�鑷�',
+    msg_password_min_length: '瀵嗙爜闀垮害鑷冲皯涓�6浣�',
+    msg_is_weak_password: '姝ゅ瘑鐮佷负寮卞瘑鐮侊紝璇烽噸鏂拌缃�',
+    msg_pswChangeSuccessAndLogin: '瀵嗙爜淇敼鎴愬姛,璇烽噸鏂扮櫥褰�',
+    msg_pswChangeSuccess: '瀵嗙爜淇敼鎴愬姛',
+    msg_pswChangeFail: '瀵嗙爜淇敼澶辫触',
+    msg_saveSuccess: '淇濆瓨鎴愬姛',
+    msg_saveFail: '淇濆瓨澶辫触',
+    msg_formFilled: '璇锋鏌ヨ〃鍗曞~鍐欐槸鍚︽纭�',
+    msg_number_0_23: '浠呮敮鎸�0鍒�23',
+    msg_number_0_24: '浠呮敮鎸�0鍒�24',
+    msg_noChange: '娌℃湁闇�瑕佷繚瀛樼殑閰嶇疆鍙樻洿',
+    // 璧勬簮閰嶇疆
+    resourceConfiguration: '璧勬簮閰嶇疆',
+    backgroundImage: '鑳屾櫙鍥剧墖',
+    selectImage: '閫夋嫨鍥剧墖',
+    uploadBackground: '涓婁紶鑳屾櫙',
+    uploading: '涓婁紶涓�...',
+    backgroundUploadTip: '璇蜂笂浼� 鍍忕礌涓簕n}鐨凱NG鏍煎紡 鐨勫浘鐗囷紝鍥剧墖灏嗚浆鎹负 Base64 鏍煎紡鍚庝笂浼犲埌璁惧',
+    backgroundResolutionMismatch: '鍥剧墖鍒嗚鲸鐜囬渶涓� {n}',
+    backgroundRequired: '璇峰厛閫夋嫨鑳屾櫙鍥剧墖',
+    backgroundImageOnlyPNG: '璇蜂笂浼� PNG 鏍煎紡鐨勫浘鐗�',
+    backgroundSizeLimit: '鍥剧墖澶у皬涓嶈兘瓒呰繃 5MB',
+    backgroundParseFailed: '鍥剧墖璇诲彇澶辫触锛岃閲嶈瘯',
+    backgroundImageSelected: '鍥剧墖閫夋嫨鎴愬姛',
+    backgroundSuccess: '鑳屾櫙涓婁紶鎴愬姛',
+    backgroundFailed: '鑳屾櫙涓婁紶澶辫触',
+    // 鎵爜璁剧疆
+    scanSettings: '鎵爜璁剧疆',
+    scanSwitch: '鎵爜寮�鍏�',
+    scanInterval: '鎵爜闂撮殧',
+  },
+  // 浜哄憳璁剧疆 
+  person: {
+    idCard: '韬唤璇佸彿',
+    userType: '浜哄憳绫诲瀷',
+    administrator: '绠$悊鍛�',
+    userId: '浜哄憳ID',
+    user: '浜哄憳',
+    voucher: '鍑瘉',
+    permission: '鏉冮檺',
+    addUser: '娣诲姞浜哄憳',
+    name: '濮撳悕',
+    editUser: '缂栬緫浜哄憳',
+    placeholderUserId: '璇疯緭鍏ヤ汉鍛業D',
+    placeholderName: '璇疯緭鍏ヤ汉鍛樺鍚�',
+    userNotExist: '浜哄憳涓嶅瓨鍦�',
+    oneClickClear: '涓�閿竻绌�',
+    clearTips: '姝ゆ搷浣滃皢姘镐箙鍒犻櫎鎵�鏈変汉鍛樸�佸嚟璇佸拰鏉冮檺鏁版嵁锛屾槸鍚︾户缁紵',
+    clearSuccess: '娓呯┖鎴愬姛',
+    clearFailed: '娓呯┖澶辫触',
+  },
+  
+  voucher: {
+    password: '瀵嗙爜',
+    card: '鍗$墖',
+    face: '浜鸿劯',
+    finger: '鎸囩汗',
+    code: '鐮�',
+    codeType: '鐮佺被鍨�',
+    passthroughCode: '閫忎紶鐮�',
+    staticCode: '闈欐�佺爜',
+    dynamicCode: '鍔ㄦ�佺爜',
+    credentialId: '鍑瘉ID',
+    credentialValue: '鍑瘉鍊�',
+    placeholderCode: '璇疯緭鍏ョ爜鍑瘉',
+    placeholderPwd: '璇疯緭鍏ュ瘑鐮佸嚟璇�',
+    placeholderCard: '璇疯緭鍏ュ崱鐗囧嚟璇�',
+    validPassword: '璇疯緭鍏�6浣嶆暟瀛�',
+    validCard: '璇疯緭鍏ユ暟瀛楁垨瀛楁瘝',
+    photoRegistration: '鐓х墖娉ㄥ唽',
+    featureValueRegistration: '鐗瑰緛鍊兼敞鍐�',
+    fingerRegistration: '鎸囩汗娉ㄥ唽',
+    fingerFeatureRegistration: '鐗瑰緛鍊兼敞鍐�',
+    fingerInput: '璇峰皢鎵嬫寚鏀惧湪鎸囩汗閲囬泦鍣ㄤ笂',
+    fingerRemainingTime: '鍓╀綑鏃堕棿',
+    fingerInputting: '褰曞叆涓�...',
+    startFingerInput: '寮�濮嬪綍鍏ユ寚绾�',
+    fingerInputTips: '璇疯緭鍏ユ寚绾圭壒寰佸��',
+    fingerWaitInput: '绛夊緟褰曞叆',
+    fingerInputNow: '姝e湪褰曞叆鎸囩汗...',
+    fingerInputSuccess: '褰曞叆鎴愬姛',
+    fingerInputFailed: '鎸囩汗褰曞叆鍚姩澶辫触',
+    fingerReTry: '鎸囩汗褰曞叆澶辫触,璇烽噸璇�',
+    fingerFilled: '鎸囩汗褰曞叆鎴愬姛锛岀壒寰佸�煎凡鑷姩濉厖',
+    fingerFailed: '鎸囩汗褰曞叆澶辫触',
+    fingerTimeout: '褰曞叆瓒呮椂',
+    fingerInputTimeout: '鎸囩汗褰曞叆瓒呮椂,璇烽噸璇�',
+    fingerError: '褰曞叆澶辫触',
+    fingerInputError: '鎸囩汗褰曞叆澶辫触,璇烽噸璇�',
+    fingerInputed: '鎸囩汗宸插綍鍏�',
+    fingerReInput: '閲嶆柊褰曞叆鎸囩汗',
+  },
+  
+  permission: {
+    deletePermission: '鍒犻櫎鏉冮檺',
+    addPermission: '娣诲姞鏉冮檺',
+    permissionId: '鏉冮檺ID',
+    userId: '浜哄憳ID',
+    timeRange: '鏃堕棿鍖洪棿',
+    extra: '棰濆灞炴��',
+    effectiveType: '鏈夋晥绫诲瀷',
+    effectiveTime: '鐢熸晥鏃舵',
+    effectiveWeek: '鐢熸晥鍛ㄦ湡',
+    timePeriod: '鏃堕棿娈�',
+    addTimePeriod: '娣诲姞鏃堕棿娈�',
+    modify_previous_time: '璇峰厛淇敼涓婁竴涓坊鍔犵殑鏃堕棿娈�',
+    cannot_be_earlier: '缁撴潫鏃堕棿涓嶅彲灏忎簬寮�濮嬫椂闂�',
+    times_cannot_overlap: '鎵�閫夋椂闂翠笉鍙噸鍙�',
+    choose_time_range: '璇烽�夋嫨鐢熸晥鏃堕棿鑼冨洿',
+    unlimitedMode: '鏃犻檺鍒�',
+    usualMode: '閫氬父妯″紡',
+    dailyMode: '姣忔棩妯″紡',
+    weeklyRepetitionMode: '鍛ㄩ噸澶嶆ā寮�',
+    time_range: '鏃舵',
+  },
+  
+  common: {
+    startDate: '寮�濮嬫棩鏈�',
+    endDate: '缁撴潫鏃ユ湡',
+    to: '鑷�',
+    cancel: '鍙栨秷',
+    confirm: '纭',
+    close: '鍏抽棴',
+    delete: '鍒犻櫎',
+    edit: '缂栬緫',
+    batchDelete: '鎵归噺鍒犻櫎',
+    startTime: '寮�濮嬫椂闂�',
+    endTime: '缁撴潫鏃堕棿',
+    monday: '鏄熸湡涓�',
+    tuseday: '鏄熸湡浜�',
+    wednesday: '鏄熸湡涓�',
+    thursday: '鏄熸湡鍥�',
+    friday: '鏄熸湡浜�',
+    saterday: '鏄熸湡鍏�',
+    sunday: '鏄熸湡鏃�',
+    placeholder: '璇疯緭鍏�',
+    placeholderSelect: '璇烽�夋嫨',
+    closeTips: '纭鍏抽棴鍚楋紵',
+    deleteTips: '纭鍒犻櫎鍚楋紵',
+    deleteSuccess: '鍒犻櫎鎴愬姛',
+    addSuccess: '鏂板鎴愬姛',
+    editSuccess: '缂栬緫鎴愬姛',
+    saveSuccess: '淇濆瓨鎴愬姛',
+    tips: '鎻愮ず',
+    operation: '鎿嶄綔',
+    query: '鏌ヨ',
+    reset: '閲嶇疆',
+    noData: '鏆傛棤鏁版嵁',
+    export: '瀵煎嚭',
+    success: '鎴愬姛',
+    failure: '澶辫触',
+    incorrectFormat: '鏍煎紡涓嶆纭�',
+    integerFormat: '鍙兘涓哄ぇ浜庣瓑浜�0鐨勬暣鏁�',
+    positiveIntegerFormat: '鍙兘涓哄ぇ浜�0鐨勬暣鏁�',
+    noDataSaved: '娌℃湁鏁版嵁闇�瑕佷繚瀛�',
+    chinese: '涓枃',
+    english: '鑻辨枃',
+    spanish: '瑗跨彮鐗欒',
+    french: '娉曡',
+    german: '寰疯',
+    russian: '淇勮',
+    arabic: '闃挎媺浼',
+    portuguese: '钁¤悇鐗欒',
+    korean: '闊╄',
+    detail: '璇︽儏',
+    clearTips: '纭娓呯┖鍚�?',
+    clearSuccess: '娓呯┖鎴愬姛',
+  },
+  
+  log: {
+    accessMethod: '閫氳鏂瑰紡',
+    passingTime: '閫氳鏃堕棿',
+    accessPass: '閫氳鍑瘉',
+    accessResult: '閫氳缁撴灉',
+    accessPhoto: '閫氳鐓х墖',
+    viewPhotos: '鏌ョ湅鐓х墖'
+  },
+
+  error: {
+    networkError: '缃戠粶璇锋眰澶辫触锛岃妫�鏌ョ綉缁滆繛鎺�',
+    timeout: '璇锋眰瓒呮椂锛岃妫�鏌ョ綉缁滆繛鎺ユ垨绋嶅悗閲嶈瘯',
+    serverError: '鏈嶅姟鍣ㄥ唴閮ㄩ敊璇紝璇风◢鍚庨噸璇�',
+    notFound: '璇锋眰鐨勮祫婧愪笉瀛樺湪',
+    unauthorized: '鏈巿鏉冿紝璇烽噸鏂扮櫥褰�',
+    noResponse: '鏃犳硶杩炴帴鍒版湇鍔″櫒锛岃妫�鏌ョ綉缁滆繛鎺ユ垨鏈嶅姟鍣ㄧ姸鎬�',
+    unknownError: '璇锋眰澶辫触锛岄敊璇唬鐮�:',
+    requestFailed: '璇锋眰澶辫触'
+  },
+  // 瀵嗛挜绠$悊
+  security: {
+    keyId: '瀵嗛挜ID',
+    keyType: '瀵嗛挜绫诲瀷',
+    keyEncoding: '瀵嗛挜缂栫爜',
+    keyValue: '瀵嗛挜鍊�',
+    startTime: '寮�濮嬫椂闂�',
+    expirationTime: '杩囨湡鏃堕棿',
+    newKey: '鏂板瀵嗛挜',
+    clearKey: '娓呯┖瀵嗛挜',
+    validTime: '鏈夋晥鏃堕棿',
+  }
+}
\ No newline at end of file
diff --git "a/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/main.js" "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/main.js"
new file mode 100644
index 0000000..41e912e
--- /dev/null
+++ "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/main.js"
@@ -0,0 +1,42 @@
+import Vue from 'vue'
+import App from './App.vue'
+import router from './router'
+import http from './utils/request'
+import i18n from './language'
+import ElementUI from 'element-ui';
+import 'element-ui/lib/theme-chalk/index.css';
+// 寮曞叆瀛椾綋鍥炬爣
+// fontclass
+import './assets/font/iconfont.css'
+// Symbol
+import './assets/font/iconfont'
+
+import Blob from '@/excel/Blob.js'
+import Export2Excel from '@/excel/Export2Excel.js'
+import modelPermission from '@/directives/model-permission'
+// 寮规鎸夐挳
+import {
+  Message
+} from 'element-ui';
+let publicConfig = sessionStorage.getItem('publicConfig')
+let { language } = publicConfig ? JSON.parse(publicConfig) : {}
+if (language === 'CN' && document.title !== '浜鸿劯绯荤粺') {
+  document.title = '浜鸿劯绯荤粺'
+}
+if (language === 'EN' && document.title !== 'Face device system') {
+  document.title = 'Face device system'
+}
+Vue.prototype.$Message = Message
+
+Vue.use(ElementUI);
+Vue.config.productionTip = false
+Vue.prototype.$http = http
+Vue.directive('model-permission', modelPermission)
+
+new Vue({
+  Export2Excel,
+  Blob,
+  i18n,
+  router,
+  render: h => h(App),
+}).$mount('#app')
\ No newline at end of file
diff --git "a/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/router.js" "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/router.js"
new file mode 100644
index 0000000..71044e9
--- /dev/null
+++ "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/router.js"
@@ -0,0 +1,57 @@
+import Vue from 'vue'
+import Router from 'vue-router'
+import login from './views/login/index.vue'
+import home from './views/home/index.vue'
+import config from './views/config/index.vue'
+import control from './views/control/index.vue'
+import person from './views/person/index.vue'
+import monitor from './views/monitor/index.vue'
+import record from './views/record/index.vue'
+import security from './views/security/index.vue'
+Vue.use(Router)
+
+export default new Router({
+    routes: [{
+        path: '/',
+        name: 'login',
+        redirect: "login"
+    },
+    {
+        path: '/login',
+        name: 'login',
+        component: login
+    },
+    {
+        path: '/home',
+        name: 'home',
+        component: home,
+        redirect: '/config',
+        children: [
+            {
+                path: '/monitor',
+                name: 'monitor',
+                component: monitor
+            }, {
+                path: '/config',
+                name: 'config',
+                component: config,
+            }, {
+                path: '/control',
+                name: 'control',
+                component: control,
+            }, {
+                path: '/person',
+                name: 'person',
+                component: person,
+            }, {
+                path: '/record',
+                name: 'record',
+                component: record,
+            }, {
+                path: '/security',
+                name: 'security',
+                component: security,
+            }], 
+    },
+    ]
+})
diff --git "a/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/utils/bus.js" "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/utils/bus.js"
new file mode 100644
index 0000000..91eee5a
--- /dev/null
+++ "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/utils/bus.js"
@@ -0,0 +1,5 @@
+//鍏ㄥ眬鐨別vent bus锛岀敤浜庡彂閫佸拰鎺ユ敹娑堟伅
+import Vue from 'vue'
+
+const bus = new Vue()
+export default bus
\ No newline at end of file
diff --git "a/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/utils/export.js" "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/utils/export.js"
new file mode 100644
index 0000000..305fe40
--- /dev/null
+++ "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/utils/export.js"
@@ -0,0 +1,99 @@
+/*
+ * @Author: your name
+ * @Date: 2020-09-14 15:13:28
+ * @LastEditTime: 2020-09-24 11:39:53
+ * @LastEditors: Please set LastEditors
+ * @Description: In User Settings Edit
+ * @FilePath: \webadmin\src\utils\export.js
+ */
+import {
+  MessageBox,
+  Message,
+  Notification
+} from 'element-ui'
+import axios from 'axios'
+// 瀵煎嚭
+export function outExcel(name, url, data, info) {
+  MessageBox.confirm(name, "鎻愮ず", {
+      type: "warning"
+    }).then(async () => {
+      Notification.info({
+        title: '鎻愮ず',
+        message: '姝e湪瀵煎嚭锛岃绋嶅悗 <i class="el-icon-loading" style="font-size:20px"></i>',
+        dangerouslyUseHTMLString: true,
+        position: 'bottom-left',
+        duration: 0
+      })
+      const time = data;
+      let formData = new FormData();
+      if (time != null) {
+        for (var p in time) {
+          formData.append(p, time[p]);
+        }
+      }
+      axios({
+          method: "post",
+          url: process.env.VUE_APP_BASE_API + url,
+          data: formData,
+          headers: {
+            Authorization: "token " + JSON.parse(sessionStorage.getItem("UserInfo")).token,
+            "Content-Type": "multipart/form-data"
+          },
+          responseType: "blob"
+        })
+        .then(data => {
+
+          if (data.data.type === "application/json") {
+            var reader = new FileReader();
+            reader.onloadend = function () {
+              let res = JSON.parse(reader.result);
+              if (res && res.msg) {
+                Message.warning(res.msg + "," + res.data);
+                setTimeout(() => {
+                  Notification.closeAll()
+                }, 1000);
+              }
+            };
+            reader.readAsText(data.data);
+            return;
+          }
+
+          let url = window.URL.createObjectURL(new Blob([data.data]));
+          let link = document.createElement("a");
+          link.style.display = "none";
+          link.href = url;
+          link.setAttribute("download", info);
+          document.body.appendChild(link);
+          link.click();
+          if (info.indexOf('妯℃澘') !== -1) {
+            Message.success('妯℃澘涓嬭浇鎴愬姛')
+            setTimeout(() => {
+              Notification.closeAll()
+            }, 1000);
+          } else {
+            Notification.closeAll()
+            Notification.success({
+              title: '鎻愮ず',
+              message: '瀵煎嚭鎴愬姛',
+              position: 'bottom-left',
+              duration: 2000
+            })
+            setTimeout(() => {
+              Notification.closeAll()
+            }, 2000);
+            // Message.success('瀵煎嚭鎴愬姛')
+          }
+        })
+        .catch(() => {
+          if (info.indexOf('妯℃澘') !== -1) {
+            Message.error('妯℃澘涓嬭浇澶辫触')
+          } else {
+            Message.error('瀵煎嚭澶辫触')
+           
+          }
+        });
+    })
+    .catch(() => {
+      return false;
+    });
+}
\ No newline at end of file
diff --git "a/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/utils/index.js" "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/utils/index.js"
new file mode 100644
index 0000000..2c80c96
--- /dev/null
+++ "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/utils/index.js"
@@ -0,0 +1,118 @@
+
+export function parseTime (time) {
+  if (time) {
+    var date = new Date(time)
+    var year = date.getFullYear()
+    /* 鍦ㄦ棩鏈熸牸寮忎腑锛屾湀浠芥槸浠�0寮�濮嬬殑锛屽洜姝よ鍔�0
+     * 浣跨敤涓夊厓琛ㄨ揪寮忓湪灏忎簬10鐨勫墠闈㈠姞0锛屼互杈惧埌鏍煎紡缁熶竴  濡� 09:11:05
+     * */
+    var month = date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1
+    var day = date.getDate() < 10 ? '0' + date.getDate() : date.getDate()
+    var hours = date.getHours() < 10 ? '0' + date.getHours() : date.getHours()
+    var minutes = date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes()
+    var seconds = date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds()
+    // 鎷兼帴
+    return year + '-' + month + '-' + day + ' ' + hours + ':' + minutes + ':' + seconds
+  } else {
+    return ''
+  }
+}
+
+export function removeEmptyValues(obj) {
+  const result = {};
+  for (const key in obj) {
+    if (obj[key] != null && obj[key] !== '') {
+      result[key] = obj[key];
+    }
+  }
+  return result;
+}
+
+export function resetObjectValues(obj) {
+  Object.keys(obj).forEach(key => {
+    obj[key] = '';
+  });
+  return obj;
+}
+
+export function generateRandomString(length = 16) {
+  const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
+  let result = '';
+  for (let i = 0; i < length; i++) {
+    result += chars.charAt(Math.floor(Math.random() * chars.length));
+  }
+  return result;
+}
+
+/**
+ * 鑺傛祦鍑芥暟浼樺寲鐗�
+ * @param {Function} func 闇�瑕佽妭娴佺殑鍑芥暟
+ * @param {number} wait 鑺傛祦鏃堕棿闂撮殧(姣)
+ * @param {Object} [options={}] 閰嶇疆閫夐」
+ * @param {boolean} [options.leading=true] 鏄惁鍏佽棣栨绔嬪嵆鎵ц
+ * @param {boolean} [options.trailing=true] 鏄惁鍏佽鏈�鍚庝竴娆″欢杩熸墽琛�
+ */
+export function throttle(func, wait, options = {}) {
+  let timeout, context, args;
+  let previous = 0;
+  
+  const later = () => {
+    previous = options.leading === false ? 0 : Date.now();
+    timeout = null;
+    func.apply(context, args);
+    if (!timeout) context = args = null;
+  };
+
+  const throttled = function() {
+    const now = Date.now();
+    if (!previous && options.leading === false) previous = now;
+    
+    const remaining = wait - (now - previous);
+    context = this;
+    args = arguments;
+    
+    if (remaining <= 0 || remaining > wait) {
+      if (timeout) {
+        clearTimeout(timeout);
+        timeout = null;
+      }
+      previous = now;
+      func.apply(context, args);
+      if (!timeout) context = args = null;
+    } else if (!timeout && options.trailing !== false) {
+      timeout = setTimeout(later, remaining);
+    }
+  };
+
+  return throttled;
+}
+
+/**
+* 鏍规嵁娴忚鍣ㄨ瑷�锛屾槧灏勫埌 messages 涓搴旂殑閿紙EN, CN, ES, ...锛�
+* @returns {string} 璇█閿紝濡� 'EN', 'CN'
+*/
+export function getBrowserLocale() {
+  const navLang = navigator.language
+  console.log('娴忚鍣ㄨ瑷�:', navLang)
+  // 鎻愬彇璇█鍓嶇紑锛堝墠涓や釜瀛楁瘝锛�
+  let langPrefix = navLang.substring(0, 2).toLowerCase()
+  // 鐗规畩澶勭悊涓枃锛氭棤璁� zh-CN / zh-TW / zh-HK 閮芥槧灏勪负 CN
+  if (langPrefix === 'zh') {
+    return 'CN'
+  }
+  // 鍏朵粬璇█鏄犲皠锛堟敮鎸佹墍鏈変綘宸查厤缃殑璇█锛�
+  const map = {
+    en: 'EN',
+    es: 'ES',
+    fr: 'FR',
+    de: 'DE',
+    ru: 'RU',
+    ar: 'AR',
+    pt: 'PT',
+    ko: 'KO'
+  }
+  // 濡傛灉鍓嶇紑鍦ㄦ槧灏勮〃涓紝杩斿洖瀵瑰簲鐨勫ぇ鍐欓敭锛屽惁鍒欒繑鍥為粯璁よ瑷�锛堣繖閲岄粯璁よ嫳鏂囷級
+  return map[langPrefix] || 'EN'
+}
+
+
diff --git "a/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/utils/request.js" "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/utils/request.js"
new file mode 100644
index 0000000..6d851fd
--- /dev/null
+++ "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/utils/request.js"
@@ -0,0 +1,91 @@
+// src/api/request.js
+import axios from 'axios'
+import { Message } from 'element-ui'
+import router from '../router'
+import i18n from '../language/index'
+
+// // 鏈湴璋冭瘯
+// const baseURL = '/api'
+
+// 鐢熶骇鎵撳寘
+const baseURL = (() => {
+  const { protocol, hostname } = window.location;
+  return `${protocol}//${hostname}:8080`; // 鍥哄畾鍚庣绔彛
+})();
+
+// 鍒涘缓axios瀹炰緥
+const service = axios.create({
+  baseURL,
+  timeout: 100000
+})
+
+// 璇锋眰鎷︽埅鍣�
+service.interceptors.request.use(
+  config => {
+    // 鍙互鍦ㄨ繖閲屾坊鍔爐oken绛�
+    let token = sessionStorage.getItem("token")
+    if (token) {
+      config.headers['Authorization'] = token
+    }
+    return config
+  },
+  error => {
+    return Promise.reject(error)
+  }
+)
+
+// 鍝嶅簲鎷︽埅鍣�
+service.interceptors.response.use(
+  response => {
+    const res = response.data
+    if (res.code == 401) {
+      Message.error(i18n.t('error.unauthorized'))
+      // 瑙﹀彂鐧诲嚭鎿嶄綔
+      sessionStorage.removeItem('token')
+      router.push('/login')
+    } else {
+      return res
+    }
+  },
+  error => {
+    console.error('璇锋眰閿欒:', error)
+    let errorMessage = i18n.t('error.networkError')
+    if (error.code === 'ECONNABORTED' || error.message.includes('timeout')) {
+      errorMessage = i18n.t('error.timeout')
+      // 瑙﹀彂鐧诲嚭鎿嶄綔
+      sessionStorage.removeItem('token')
+      router.push('/login')
+    } else if (error.response) {
+      const status = error.response.status
+      switch (status) {
+        case 500:
+          errorMessage = i18n.t('error.serverError')
+          // 瑙﹀彂鐧诲嚭鎿嶄綔
+          sessionStorage.removeItem('token')
+          router.push('/login')
+          break
+        case 404:
+          errorMessage = i18n.t('error.notFound')
+          break
+        case 401:
+          errorMessage = i18n.t('error.unauthorized')
+          // 瑙﹀彂鐧诲嚭鎿嶄綔
+          sessionStorage.removeItem('token')
+          router.push('/login')
+          break
+        default:
+          errorMessage = i18n.t('error.unknownError') + `: ${status}`
+      }
+
+      if (error.response.data && error.response.data.message) {
+        errorMessage = error.response.data.message
+      }
+    } else if (error.request) {
+      errorMessage = i18n.t('error.noResponse')
+    }
+    Message.error(errorMessage)
+    return Promise.reject(error)
+  }
+)
+
+export default service
\ No newline at end of file
diff --git "a/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/utils/timezones.js" "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/utils/timezones.js"
new file mode 100644
index 0000000..0a420dc
--- /dev/null
+++ "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/utils/timezones.js"
@@ -0,0 +1,790 @@
+const timezones = {
+  "Pacific/Midway": {
+      "utc_offset": "-11:00",
+      "name": {
+          "zh": "钀ㄦ懇浜氭爣鍑嗘椂闂达紙涓�斿矝锛�",
+          "en": "Samoa Standard Time (Midway)",
+          "ja": "銈点儮銈㈡婧栨檪锛堛儫銉冦儔銈︺偋銈わ級",
+          "ko": "靷鞎� 響滌鞁� (氙鸽摐鞗澊)",
+          "es": "Hora Est谩ndar de Samoa (Midway)",
+          "fr": "Heure Standard de Samoa (Midway)",
+          "de": "Samoa-Standardzeit (Midway)",
+          "ru": "小邪屑芯邪薪褋泻芯械 褋褌邪薪写邪褉褌薪芯械 胁褉械屑褟 (袦懈写褍褝泄)",
+          "ar": "丕賱鬲賵賯賷鬲 丕賱賯賷丕爻賷 賱爻丕賲賵丕 (賲賷丿賵丕賷)",
+          "pt": "Hora Padr茫o de Samoa (Midway)"
+      }
+  },
+  "America/Adak": {
+      "utc_offset": "-10:00",
+      "name": {
+          "zh": "澶忓▉澶�-闃跨暀鐢虫爣鍑嗘椂闂达紙闃胯揪鍏嬶級",
+          "en": "Hawaii-Aleutian Standard Time (Adak)",
+          "ja": "銉忋儻銈ゃ兓銈€儶銉ャ兗銈枫儯銉虫婧栨檪锛堛偄銉�銉冦偗锛�",
+          "ko": "頃橃檧鞚�-鞎岆靸� 響滌鞁� (鞎勲嫢)",
+          "es": "Hora Est谩ndar de Haw谩i-Aleutianas (Adak)",
+          "fr": "Heure Standard d'Hawa茂-Al茅outiennes (Adak)",
+          "de": "Hawaii-Aleuten-Standardzeit (Adak)",
+          "ru": "袚邪胁邪泄褋泻芯-袗谢械褍褌褋泻芯械 褋褌邪薪写邪褉褌薪芯械 胁褉械屑褟 (袗写邪泻)",
+          "ar": "丕賱鬲賵賯賷鬲 丕賱賯賷丕爻賷 賱賴丕賵丕賷-兀賱賵卮賷丕賳 (兀丿丕賰)",
+          "pt": "Hora Padr茫o do Hava铆-Aleutas (Adak)"
+      }
+  },
+  "Pacific/Honolulu": {
+      "utc_offset": "-10:00",
+      "name": {
+          "zh": "澶忓▉澶锋爣鍑嗘椂闂�",
+          "en": "Hawaii Standard Time",
+          "ja": "銉忋儻銈ゆ婧栨檪",
+          "ko": "頃橃檧鞚� 響滌鞁�",
+          "es": "Hora Est谩ndar de Haw谩i",
+          "fr": "Heure Standard d'Hawa茂",
+          "de": "Hawaii-Standardzeit",
+          "ru": "袚邪胁邪泄褋泻芯械 褋褌邪薪写邪褉褌薪芯械 胁褉械屑褟",
+          "ar": "丕賱鬲賵賯賷鬲 丕賱賯賷丕爻賷 賱賴丕賵丕賷",
+          "pt": "Hora Padr茫o do Hava铆"
+      }
+  },
+  "America/Anchorage": {
+      "utc_offset": "-09:00",
+      "name": {
+          "zh": "闃挎媺鏂姞鏍囧噯鏃堕棿",
+          "en": "Alaska Standard Time",
+          "ja": "銈€儵銈广偒妯欐簴鏅�",
+          "ko": "鞎岆灅鞀れ勾 響滌鞁�",
+          "es": "Hora Est谩ndar de Alaska",
+          "fr": "Heure Standard de l'Alaska",
+          "de": "Alaska-Standardzeit",
+          "ru": "袗谢褟褋泻懈薪褋泻芯械 褋褌邪薪写邪褉褌薪芯械 胁褉械屑褟",
+          "ar": "丕賱鬲賵賯賷鬲 丕賱賯賷丕爻賷 賱兀賱丕爻賰丕",
+          "pt": "Hora Padr茫o do Alasca"
+      }
+  },
+  "America/Los_Angeles": {
+      "utc_offset": "-08:00",
+      "name": {
+          "zh": "澶钩娲嬫爣鍑嗘椂闂达紙娲涙潐鐭讹級",
+          "en": "Pacific Standard Time (Los Angeles)",
+          "ja": "澶钩娲嬫婧栨檪锛堛儹銈点兂銈笺儷銈癸級",
+          "ko": "韮滍弶鞏� 響滌鞁� (搿滌姢鞎れ牑霠堨姢)",
+          "es": "Hora Est谩ndar del Pac铆fico (Los 脕ngeles)",
+          "fr": "Heure Standard du Pacifique (Los Angeles)",
+          "de": "Pazifische Standardzeit (Los Angeles)",
+          "ru": "孝懈褏芯芯泻械邪薪褋泻芯械 褋褌邪薪写邪褉褌薪芯械 胁褉械屑褟 (袥芯褋-袗薪写卸械谢械褋)",
+          "ar": "鬲賵賯賷鬲 丕賱賲丨賷胤 丕賱賴丕丿卅 (賱賵爻 兀賳噩賱賵爻)",
+          "pt": "Hora Padr茫o do Pac铆fico (Los Angeles)"
+      }
+  },
+  "America/Denver": {
+      "utc_offset": "-07:00",
+      "name": {
+          "zh": "灞卞湴鏍囧噯鏃堕棿锛堜腹浣涳級",
+          "en": "Mountain Standard Time (Denver)",
+          "ja": "灞卞渤閮ㄦ婧栨檪锛堛儑銉炽儛銉硷級",
+          "ko": "靷办晠 響滌鞁� (雿措矂)",
+          "es": "Hora Est谩ndar de la Monta帽a (Denver)",
+          "fr": "Heure Standard des Rocheuses (Denver)",
+          "de": "Rocky-Mountain-Standardzeit (Denver)",
+          "ru": "袚芯褉薪芯械 褋褌邪薪写邪褉褌薪芯械 胁褉械屑褟 (袛械薪胁械褉)",
+          "ar": "丕賱鬲賵賯賷鬲 丕賱噩亘賱賷 (丿賳賮乇)",
+          "pt": "Hora Padr茫o das Montanhas (Denver)"
+      }
+  },
+  "America/Chicago": {
+      "utc_offset": "-06:00",
+      "name": {
+          "zh": "涓儴鏍囧噯鏃堕棿锛堣姖鍔犲摜锛�",
+          "en": "Central Standard Time (Chicago)",
+          "ja": "涓儴妯欐簴鏅傦紙銈枫偒銈达級",
+          "ko": "欷戨秬 響滌鞁� (鞁滌勾瓿�)",
+          "es": "Hora Est谩ndar Central (Chicago)",
+          "fr": "Heure Standard du Centre (Chicago)",
+          "de": "Central-Standardzeit (Chicago)",
+          "ru": "笑械薪褌褉邪谢褜薪芯械 褋褌邪薪写邪褉褌薪芯械 胁褉械屑褟 (效懈泻邪谐芯)",
+          "ar": "丕賱鬲賵賯賷鬲 丕賱賲乇賰夭賷 (卮賷賰丕睾賵)",
+          "pt": "Hora Padr茫o Central (Chicago)"
+      }
+  },
+  "America/New_York": {
+      "utc_offset": "-05:00",
+      "name": {
+          "zh": "涓滈儴鏍囧噯鏃堕棿锛堢航绾︼級",
+          "en": "Eastern Standard Time (New York)",
+          "ja": "鏉遍儴妯欐簴鏅傦紙銉嬨儱銉笺儴銉笺偗锛�",
+          "ko": "霃欕秬 響滌鞁� (雺挫殨)",
+          "es": "Hora Est谩ndar del Este (Nueva York)",
+          "fr": "Heure Standard de l'Est (New York)",
+          "de": "脰stliche Standardzeit (New York)",
+          "ru": "袙芯褋褌芯褔薪芯械 褋褌邪薪写邪褉褌薪芯械 胁褉械屑褟 (袧褜褞-袡芯褉泻)",
+          "ar": "丕賱鬲賵賯賷鬲 丕賱卮乇賯賷 (賳賷賵賷賵乇賰)",
+          "pt": "Hora Padr茫o do Leste (Nova York)"
+      }
+  },
+  "America/Toronto": {
+      "utc_offset": "-05:00",
+      "name": {
+          "zh": "涓滈儴鏍囧噯鏃堕棿锛堝浼﹀锛�",
+          "en": "Eastern Standard Time (Toronto)",
+          "ja": "鏉遍儴妯欐簴鏅傦紙銉堛儹銉炽儓锛�",
+          "ko": "霃欕秬 響滌鞁� (韱犽韱�)",
+          "es": "Hora Est谩ndar del Este (Toronto)",
+          "fr": "Heure Standard de l'Est (Toronto)",
+          "de": "脰stliche Standardzeit (Toronto)",
+          "ru": "袙芯褋褌芯褔薪芯械 褋褌邪薪写邪褉褌薪芯械 胁褉械屑褟 (孝芯褉芯薪褌芯)",
+          "ar": "丕賱鬲賵賯賷鬲 丕賱卮乇賯賷 (鬲賵乇賵賳鬲賵)",
+          "pt": "Hora Padr茫o do Leste (Toronto)"
+      }
+  },
+  "America/Mexico_City": {
+      "utc_offset": "-06:00",
+      "name": {
+          "zh": "澧ㄨタ鍝ヤ腑閮ㄦ椂闂达紙澧ㄨタ鍝ュ煄锛�",
+          "en": "Central Time (Mexico City)",
+          "ja": "涓儴鏅傞枔锛堛儭銈偡銈炽偡銉嗐偅锛�",
+          "ko": "欷戨秬 鞁滉皠 (氅曥嫓旖旍嫓韹�)",
+          "es": "Hora Central (Ciudad de M茅xico)",
+          "fr": "Heure du Centre (Mexico)",
+          "de": "Zentralzeit (Mexiko-Stadt)",
+          "ru": "笑械薪褌褉邪谢褜薪芯械 胁褉械屑褟 (袦械褏懈泻芯)",
+          "ar": "丕賱鬲賵賯賷鬲 丕賱賲乇賰夭賷 (賲賰爻賷賰賵 爻賷鬲賷)",
+          "pt": "Hora Central (Cidade do M茅xico)"
+      }
+  },
+  "America/Bogota": {
+      "utc_offset": "-05:00",
+      "name": {
+          "zh": "鍝ヤ鸡姣斾簹鏃堕棿锛堟尝鍝ュぇ锛�",
+          "en": "Colombia Time (Bogot谩)",
+          "ja": "銈炽儹銉炽儞銈㈡檪闁擄紙銉溿偞銈匡級",
+          "ko": "旖滊‖牍勳晞 鞁滉皠 (氤搓碃韮�)",
+          "es": "Hora de Colombia (Bogot谩)",
+          "fr": "Heure de Colombie (Bogot谩)",
+          "de": "Kolumbianische Zeit (Bogot谩)",
+          "ru": "袣芯谢褍屑斜懈泄褋泻芯械 胁褉械屑褟 (袘芯谐芯褌邪)",
+          "ar": "鬲賵賯賷鬲 賰賵賱賵賲亘賷丕 (亘賵睾賵鬲丕)",
+          "pt": "Hora da Col么mbia (Bogot谩)"
+      }
+  },
+  "America/Lima": {
+      "utc_offset": "-05:00",
+      "name": {
+          "zh": "绉橀瞾鏃堕棿锛堝埄椹級",
+          "en": "Peru Time (Lima)",
+          "ja": "銉氥儷銉兼檪闁擄紙銉優锛�",
+          "ko": "韼橂( 鞁滉皠 (毽)",
+          "es": "Hora de Per煤 (Lima)",
+          "fr": "Heure du P茅rou (Lima)",
+          "de": "Peruanische Zeit (Lima)",
+          "ru": "袩械褉褍邪薪褋泻芯械 胁褉械屑褟 (袥懈屑邪)",
+          "ar": "鬲賵賯賷鬲 亘賷乇賵 (賱賷賲丕)",
+          "pt": "Hora do Peru (Lima)"
+      }
+  },
+  "America/Santiago": {
+      "utc_offset": "-04:00",
+      "name": {
+          "zh": "鏅哄埄鏃堕棿锛堝湥鍦颁簹鍝ワ級",
+          "en": "Chile Time (Santiago)",
+          "ja": "銉併儶鏅傞枔锛堛偟銉炽儐銈c偄銈达級",
+          "ko": "旃犽爤 鞁滉皠 (靷绊嫲鞎勱碃)",
+          "es": "Hora de Chile (Santiago)",
+          "fr": "Heure du Chili (Santiago)",
+          "de": "Chilenische Zeit (Santiago)",
+          "ru": "效懈谢懈泄褋泻芯械 胁褉械屑褟 (小邪薪褌褜褟谐芯)",
+          "ar": "鬲賵賯賷鬲 鬲卮賷賱賷 (爻丕賳鬲賷丕睾賵)",
+          "pt": "Hora do Chile (Santiago)"
+      }
+  },
+  "America/Argentina/Buenos_Aires": {
+      "utc_offset": "-03:00",
+      "name": {
+          "zh": "闃挎牴寤锋椂闂达紙甯冨疁璇烘柉鑹惧埄鏂級",
+          "en": "Argentina Time (Buenos Aires)",
+          "ja": "銈€儷銈笺兂銉併兂鏅傞枔锛堛儢銈ㄣ儙銈广偄銈ゃ儸銈癸級",
+          "ko": "鞎勲ゴ項嫲雮� 鞁滉皠 (攵�鞐愲吀鞀れ晞鞚措爤鞀�)",
+          "es": "Hora de Argentina (Buenos Aires)",
+          "fr": "Heure d'Argentine (Buenos Aires)",
+          "de": "Argentinische Zeit (Buenos Aires)",
+          "ru": "袗褉谐械薪褌懈薪褋泻芯械 胁褉械屑褟 (袘褍褝薪芯褋-袗泄褉械褋)",
+          "ar": "鬲賵賯賷鬲 丕賱兀乇噩賳鬲賷賳 (亘賵賷賳爻 丌賷乇爻)",
+          "pt": "Hora da Argentina (Buenos Aires)"
+      }
+  },
+  "America/Sao_Paulo": {
+      "utc_offset": "-03:00",
+      "name": {
+          "zh": "宸磋タ鏃堕棿锛堝湥淇濈綏锛�",
+          "en": "Brazil Time (S茫o Paulo)",
+          "ja": "銉栥儵銈搞儷鏅傞枔锛堛偟銉炽儜銈︺儹锛�",
+          "ko": "敫岆澕歆� 鞁滉皠 (靸來寣鞖鸽()",
+          "es": "Hora de Brasil (S茫o Paulo)",
+          "fr": "Heure du Br茅sil (S茫o Paulo)",
+          "de": "Brasilianische Zeit (S茫o Paulo)",
+          "ru": "袘褉邪蟹懈谢褜褋泻芯械 胁褉械屑褟 (小邪薪-袩邪褍谢褍)",
+          "ar": "鬲賵賯賷鬲 丕賱亘乇丕夭賷賱 (爻丕賵 亘丕賵賱賵)",
+          "pt": "Hora do Brasil (S茫o Paulo)"
+      }
+  },
+  "Atlantic/Azores": {
+      "utc_offset": "-01:00",
+      "name": {
+          "zh": "浜氶�熷皵缇ゅ矝鏃堕棿",
+          "en": "Azores Time",
+          "ja": "銈€偩銉偣鏅傞枔",
+          "ko": "鞎勳“霠堨姢 鞁滉皠",
+          "es": "Hora de las Azores",
+          "fr": "Heure des A莽ores",
+          "de": "Azoren-Zeit",
+          "ru": "袗蟹芯褉褋泻芯械 胁褉械屑褟",
+          "ar": "鬲賵賯賷鬲 丕賱兀夭賵乇",
+          "pt": "Hora dos A莽ores"
+      }
+  },
+  "Europe/London": {
+      "utc_offset": "+00:00",
+      "name": {
+          "zh": "鏍兼灄灏兼不鏍囧噯鏃堕棿锛堜鸡鏁︼級",
+          "en": "Greenwich Mean Time (London)",
+          "ja": "銈般儶銉嬨儍銈告婧栨檪锛堛儹銉炽儔銉筹級",
+          "ko": "攴鸽Μ雼堨箻 響滌鞁� (霟半崢)",
+          "es": "Hora del Meridiano de Greenwich (Londres)",
+          "fr": "Heure de Greenwich (Londres)",
+          "de": "Mittlere Greenwich-Zeit (London)",
+          "ru": "小褉械写薪械械 胁褉械屑褟 锌芯 袚褉懈薪胁懈褔褍 (袥芯薪写芯薪)",
+          "ar": "鬲賵賯賷鬲 睾乇賷賳鬲卮 (賱賳丿賳)",
+          "pt": "Hora M茅dia de Greenwich (Londres)"
+      }
+  },
+  "Europe/Lisbon": {
+      "utc_offset": "+00:00",
+      "name": {
+          "zh": "钁¤悇鐗欐椂闂达紙閲屾柉鏈級",
+          "en": "Portugal Time (Lisbon)",
+          "ja": "銉濄儷銉堛偓銉檪闁擄紙銉偣銉溿兂锛�",
+          "ko": "韽ゴ韴皥 鞁滉皠 (毽姢氤�)",
+          "es": "Hora de Portugal (Lisboa)",
+          "fr": "Heure du Portugal (Lisbonne)",
+          "de": "Portugiesische Zeit (Lissabon)",
+          "ru": "袩芯褉褌褍谐邪谢褜褋泻芯械 胁褉械屑褟 (袥懈褋褋邪斜芯薪)",
+          "ar": "鬲賵賯賷鬲 丕賱亘乇鬲睾丕賱 (賱卮亘賵賳丞)",
+          "pt": "Hora de Portugal (Lisboa)"
+      }
+  },
+  "Europe/Berlin": {
+      "utc_offset": "+01:00",
+      "name": {
+          "zh": "涓鏃堕棿锛堟煆鏋楋級",
+          "en": "Central European Time (Berlin)",
+          "ja": "涓ぎ銉ㄣ兗銉儍銉戞檪闁擄紙銉欍儷銉兂锛�",
+          "ko": "欷戩暀鞙犽熃 鞁滉皠 (氩犽ゼ毽�)",
+          "es": "Hora Central Europea (Berl铆n)",
+          "fr": "Heure d'Europe Centrale (Berlin)",
+          "de": "Mitteleurop盲ische Zeit (Berlin)",
+          "ru": "笑械薪褌褉邪谢褜薪芯械胁褉芯锌械泄褋泻芯械 胁褉械屑褟 (袘械褉谢懈薪)",
+          "ar": "鬲賵賯賷鬲 賵爻胤 兀賵乇賵亘丕 (亘乇賱賷賳)",
+          "pt": "Hora da Europa Central (Berlim)"
+      }
+  },
+  "Europe/Paris": {
+      "utc_offset": "+01:00",
+      "name": {
+          "zh": "涓鏃堕棿锛堝反榛庯級",
+          "en": "Central European Time (Paris)",
+          "ja": "涓ぎ銉ㄣ兗銉儍銉戞檪闁擄紙銉戙儶锛�",
+          "ko": "欷戩暀鞙犽熃 鞁滉皠 (韺岆Μ)",
+          "es": "Hora Central Europea (Par铆s)",
+          "fr": "Heure d'Europe Centrale (Paris)",
+          "de": "Mitteleurop盲ische Zeit (Paris)",
+          "ru": "笑械薪褌褉邪谢褜薪芯械胁褉芯锌械泄褋泻芯械 胁褉械屑褟 (袩邪褉懈卸)",
+          "ar": "鬲賵賯賷鬲 賵爻胤 兀賵乇賵亘丕 (亘丕乇賷爻)",
+          "pt": "Hora da Europa Central (Paris)"
+      }
+  },
+  "Europe/Madrid": {
+      "utc_offset": "+01:00",
+      "name": {
+          "zh": "涓鏃堕棿锛堥┈寰烽噷锛�",
+          "en": "Central European Time (Madrid)",
+          "ja": "涓ぎ銉ㄣ兗銉儍銉戞檪闁擄紙銉炪儔銉兗銉夛級",
+          "ko": "欷戩暀鞙犽熃 鞁滉皠 (毵堧摐毽摐)",
+          "es": "Hora Central Europea (Madrid)",
+          "fr": "Heure d'Europe Centrale (Madrid)",
+          "de": "Mitteleurop盲ische Zeit (Madrid)",
+          "ru": "笑械薪褌褉邪谢褜薪芯械胁褉芯锌械泄褋泻芯械 胁褉械屑褟 (袦邪写褉懈写)",
+          "ar": "鬲賵賯賷鬲 賵爻胤 兀賵乇賵亘丕 (賲丿乇賷丿)",
+          "pt": "Hora da Europa Central (Madri)"
+      }
+  },
+  "Europe/Rome": {
+      "utc_offset": "+01:00",
+      "name": {
+          "zh": "涓鏃堕棿锛堢綏椹級",
+          "en": "Central European Time (Rome)",
+          "ja": "涓ぎ銉ㄣ兗銉儍銉戞檪闁擄紙銉兗銉烇級",
+          "ko": "欷戩暀鞙犽熃 鞁滉皠 (搿滊)",
+          "es": "Hora Central Europea (Roma)",
+          "fr": "Heure d'Europe Centrale (Rome)",
+          "de": "Mitteleurop盲ische Zeit (Rom)",
+          "ru": "笑械薪褌褉邪谢褜薪芯械胁褉芯锌械泄褋泻芯械 胁褉械屑褟 (袪懈屑)",
+          "ar": "鬲賵賯賷鬲 賵爻胤 兀賵乇賵亘丕 (乇賵賲丕)",
+          "pt": "Hora da Europa Central (Roma)"
+      }
+  },
+  "Europe/Amsterdam": {
+      "utc_offset": "+01:00",
+      "name": {
+          "zh": "涓鏃堕棿锛堥樋濮嗘柉鐗逛腹锛�",
+          "en": "Central European Time (Amsterdam)",
+          "ja": "涓ぎ銉ㄣ兗銉儍銉戞檪闁擄紙銈€儬銈广儐銉儉銉狅級",
+          "ko": "欷戩暀鞙犽熃 鞁滉皠 (鞎旍姢韰岆ゴ雼�)",
+          "es": "Hora Central Europea (脕msterdam)",
+          "fr": "Heure d'Europe Centrale (Amsterdam)",
+          "de": "Mitteleurop盲ische Zeit (Amsterdam)",
+          "ru": "笑械薪褌褉邪谢褜薪芯械胁褉芯锌械泄褋泻芯械 胁褉械屑褟 (袗屑褋褌械褉写邪屑)",
+          "ar": "鬲賵賯賷鬲 賵爻胤 兀賵乇賵亘丕 (兀賲爻鬲乇丿丕賲)",
+          "pt": "Hora da Europa Central (Amsterd茫)"
+      }
+  },
+  "Europe/Stockholm": {
+      "utc_offset": "+01:00",
+      "name": {
+          "zh": "涓鏃堕棿锛堟柉寰峰摜灏旀懇锛�",
+          "en": "Central European Time (Stockholm)",
+          "ja": "涓ぎ銉ㄣ兗銉儍銉戞檪闁擄紙銈广儓銉冦偗銉涖儷銉狅級",
+          "ko": "欷戩暀鞙犽熃 鞁滉皠 (鞀ろ啞頇�毽�)",
+          "es": "Hora Central Europea (Estocolmo)",
+          "fr": "Heure d'Europe Centrale (Stockholm)",
+          "de": "Mitteleurop盲ische Zeit (Stockholm)",
+          "ru": "笑械薪褌褉邪谢褜薪芯械胁褉芯锌械泄褋泻芯械 胁褉械屑褟 (小褌芯泻谐芯谢褜屑)",
+          "ar": "鬲賵賯賷鬲 賵爻胤 兀賵乇賵亘丕 (爻鬲賵賰賴賵賱賲)",
+          "pt": "Hora da Europa Central (Estocolmo)"
+      }
+  },
+  "Europe/Athens": {
+      "utc_offset": "+02:00",
+      "name": {
+          "zh": "涓滄鏃堕棿锛堥泤鍏革級",
+          "en": "Eastern European Time (Athens)",
+          "ja": "鏉便儴銉笺儹銉冦儜鏅傞枔锛堛偄銉嗐儘锛�",
+          "ko": "霃欖湢霟� 鞁滉皠 (鞎勴厡雱�)",
+          "es": "Hora de Europa Oriental (Atenas)",
+          "fr": "Heure d'Europe de l'Est (Ath猫nes)",
+          "de": "Osteurop盲ische Zeit (Athen)",
+          "ru": "袙芯褋褌芯褔薪芯械胁褉芯锌械泄褋泻芯械 胁褉械屑褟 (袗褎懈薪褘)",
+          "ar": "鬲賵賯賷鬲 卮乇賯 兀賵乇賵亘丕 (兀孬賷賳丕)",
+          "pt": "Hora da Europa Oriental (Atenas)"
+      }
+  },
+  "Europe/Istanbul": {
+      "utc_offset": "+03:00",
+      "name": {
+          "zh": "鍦熻�冲叾鏃堕棿锛堜紛鏂潶甯冨皵锛�",
+          "en": "Turkey Time (Istanbul)",
+          "ja": "銉堛儷銈虫檪闁擄紙銈ゃ偣銈裤兂銉栥兗銉級",
+          "ko": "韯绊偆 鞁滉皠 (鞚挫姢韮勲秷)",
+          "es": "Hora de Turqu铆a (Estambul)",
+          "fr": "Heure de Turquie (Istanbul)",
+          "de": "T眉rkische Zeit (Istanbul)",
+          "ru": "孝褍褉械褑泻芯械 胁褉械屑褟 (小褌邪屑斜褍谢)",
+          "ar": "鬲賵賯賷鬲 鬲乇賰賷丕 (廿爻胤賳亘賵賱)",
+          "pt": "Hora da Turquia (Istambul)"
+      }
+  },
+  "Asia/Dubai": {
+      "utc_offset": "+04:00",
+      "name": {
+          "zh": "娴锋咕鏍囧噯鏃堕棿锛堣开鎷滐級",
+          "en": "Gulf Standard Time (Dubai)",
+          "ja": "婀惧哺妯欐簴鏅傦紙銉夈儛銈わ級",
+          "ko": "瓯疙攧 響滌鞁� (霊愲皵鞚�)",
+          "es": "Hora Est谩ndar del Golfo (Dub谩i)",
+          "fr": "Heure Standard du Golfe (Duba茂)",
+          "de": "Golf-Standardzeit (Dubai)",
+          "ru": "小褌邪薪写邪褉褌薪芯械 胁褉械屑褟 袩械褉褋懈写褋泻芯谐芯 蟹邪谢懈胁邪 (袛褍斜邪泄)",
+          "ar": "丕賱鬲賵賯賷鬲 丕賱賯賷丕爻賷 丕賱禺賱賷噩賷 (丿亘賷)",
+          "pt": "Hora Padr茫o do Golfo (Dubai)"
+      }
+  },
+  "Asia/Karachi": {
+      "utc_offset": "+05:00",
+      "name": {
+          "zh": "宸村熀鏂潶鏍囧噯鏃堕棿锛堝崱鎷夊锛�",
+          "en": "Pakistan Standard Time (Karachi)",
+          "ja": "銉戙偔銈广偪銉虫婧栨檪锛堛偒銉┿儊锛�",
+          "ko": "韺岉偆鞀ろ儎 響滌鞁� (旃措澕旃�)",
+          "es": "Hora Est谩ndar de Pakist谩n (Karachi)",
+          "fr": "Heure Standard du Pakistan (Karachi)",
+          "de": "Pakistanische Standardzeit (Karatschi)",
+          "ru": "袩邪泻懈褋褌邪薪褋泻芯械 褋褌邪薪写邪褉褌薪芯械 胁褉械屑褟 (袣邪褉邪褔懈)",
+          "ar": "丕賱鬲賵賯賷鬲 丕賱賯賷丕爻賷 丕賱亘丕賰爻鬲丕賳賷 (賰乇丕鬲卮賷)",
+          "pt": "Hora Padr茫o do Paquist茫o (Carachi)"
+      }
+  },
+  "Asia/Kolkata": {
+      "utc_offset": "+05:30",
+      "name": {
+          "zh": "鍗板害鏍囧噯鏃堕棿锛堝姞灏斿悇绛旓級",
+          "en": "India Standard Time (Kolkata)",
+          "ja": "銈ゃ兂銉夋婧栨檪锛堛偝銉偒銈匡級",
+          "ko": "鞚鸽弰 響滌鞁� (旖滌勾韮�)",
+          "es": "Hora Est谩ndar de India (Calcuta)",
+          "fr": "Heure Standard de l'Inde (Calcutta)",
+          "de": "Indische Standardzeit (Kalkutta)",
+          "ru": "袠薪写懈泄褋泻芯械 褋褌邪薪写邪褉褌薪芯械 胁褉械屑褟 (袣邪谢褜泻褍褌褌邪)",
+          "ar": "丕賱鬲賵賯賷鬲 丕賱賯賷丕爻賷 丕賱賴賳丿賷 (賰賵賱賰丕鬲丕)",
+          "pt": "Hora Padr茫o da 脥ndia (Calcut谩)"
+      }
+  },
+  "Asia/Dhaka": {
+      "utc_offset": "+06:00",
+      "name": {
+          "zh": "瀛熷姞鎷夋爣鍑嗘椂闂达紙杈惧崱锛�",
+          "en": "Bangladesh Standard Time (Dhaka)",
+          "ja": "銉愩兂銈般儵銉囥偡銉ユ婧栨檪锛堛儉銉冦偒锛�",
+          "ko": "氚╆竴霛茧嵃鞁� 響滌鞁� (雼れ勾)",
+          "es": "Hora Est谩ndar de Banglad茅s (Daca)",
+          "fr": "Heure Standard du Bangladesh (Dacca)",
+          "de": "Bangladeschische Standardzeit (Dhaka)",
+          "ru": "袘邪薪谐谢邪写械褕褋泻芯械 褋褌邪薪写邪褉褌薪芯械 胁褉械屑褟 (袛邪泻泻邪)",
+          "ar": "丕賱鬲賵賯賷鬲 丕賱賯賷丕爻賷 賱亘賳睾賱丕丿賷卮 (丿賰丕)",
+          "pt": "Hora Padr茫o de Bangladesh (Daca)"
+      }
+  },
+  "Asia/Bangkok": {
+      "utc_offset": "+07:00",
+      "name": {
+          "zh": "涓崡鍗婂矝鏃堕棿锛堟浖璋凤級",
+          "en": "Indochina Time (Bangkok)",
+          "ja": "銈ゃ兂銉夈偡銉婃檪闁擄紙銉愩兂銈炽偗锛�",
+          "ko": "鞚鸽弰彀澊雮� 鞁滉皠 (氚╈綍)",
+          "es": "Hora de Indochina (Bangkok)",
+          "fr": "Heure d'Indochine (Bangkok)",
+          "de": "Indochina-Zeit (Bangkok)",
+          "ru": "袠薪写芯泻懈褌邪泄褋泻芯械 胁褉械屑褟 (袘邪薪谐泻芯泻)",
+          "ar": "鬲賵賯賷鬲 丕賱賴賳丿 丕賱氐賷賳賷丞 (亘丕賳賰賵賰)",
+          "pt": "Hora da Indochina (Bangcoc)"
+      }
+  },
+  "Asia/Jakarta": {
+      "utc_offset": "+07:00",
+      "name": {
+          "zh": "鍗板害灏艰タ浜氳タ閮ㄦ椂闂达紙闆呭姞杈撅級",
+          "en": "Western Indonesia Time (Jakarta)",
+          "ja": "瑗裤偆銉炽儔銉嶃偡銈㈡檪闁擄紙銈搞儯銈儷銈匡級",
+          "ko": "靹滌澑霃勲劋鞁滌晞 鞁滉皠 (鞛愳勾毳错儉)",
+          "es": "Hora de Indonesia Occidental (Yakarta)",
+          "fr": "Heure de l'Indon茅sie Occidentale (Jakarta)",
+          "de": "Westindonesische Zeit (Jakarta)",
+          "ru": "袟邪锌邪写薪芯懈薪写芯薪械蟹懈泄褋泻芯械 胁褉械屑褟 (袛卸邪泻邪褉褌邪)",
+          "ar": "鬲賵賯賷鬲 睾乇亘 廿賳丿賵賳賷爻賷丕 (噩丕賰乇鬲丕)",
+          "pt": "Hora da Indon茅sia Ocidental (Jacarta)"
+      }
+  },
+  "Asia/Shanghai": {
+      "utc_offset": "+08:00",
+      "name": {
+          "zh": "涓浗鏍囧噯鏃堕棿锛堝寳浜級",
+          "en": "China Standard Time (Beijing)",
+          "ja": "涓浗妯欐簴鏅傦紙鍖椾含锛�",
+          "ko": "欷戧淡 響滌鞁� (氩犾澊歆�)",
+          "es": "Hora Est谩ndar de China (Pek铆n)",
+          "fr": "Heure Standard de Chine (P茅kin)",
+          "de": "Chinesische Standardzeit (Peking)",
+          "ru": "袣懈褌邪泄褋泻芯械 褋褌邪薪写邪褉褌薪芯械 胁褉械屑褟 (袩械泻懈薪)",
+          "ar": "丕賱鬲賵賯賷鬲 丕賱賯賷丕爻賷 丕賱氐賷賳賷 (亘賰賷賳)",
+          "pt": "Hora Padr茫o da China (Pequim)"
+      }
+  },
+  "Asia/Taipei": {
+      "utc_offset": "+08:00",
+      "name": {
+          "zh": "鍙版咕鏍囧噯鏃堕棿锛堝彴鍖楋級",
+          "en": "Taiwan Standard Time (Taipei)",
+          "ja": "鍙版咕妯欐簴鏅傦紙鍙板寳锛�",
+          "ko": "雽�毵� 響滌鞁� (韮�鞚措矤鞚�)",
+          "es": "Hora Est谩ndar de Taiw谩n (Taip茅i)",
+          "fr": "Heure Standard de Ta茂wan (Taipei)",
+          "de": "Taiwanesische Standardzeit (Taipeh)",
+          "ru": "孝邪泄胁邪薪褜褋泻芯械 褋褌邪薪写邪褉褌薪芯械 胁褉械屑褟 (孝邪泄斜褝泄)",
+          "ar": "丕賱鬲賵賯賷鬲 丕賱賯賷丕爻賷 賱鬲丕賷賵丕賳 (鬲丕賷亘賷賴)",
+          "pt": "Hora Padr茫o de Taiwan (Taipei)"
+      }
+  },
+  "Asia/Hong_Kong": {
+      "utc_offset": "+08:00",
+      "name": {
+          "zh": "棣欐腐鏃堕棿",
+          "en": "Hong Kong Time",
+          "ja": "棣欐腐鏅傞枔",
+          "ko": "頇嶌僵 鞁滉皠",
+          "es": "Hora de Hong Kong",
+          "fr": "Heure de Hong Kong",
+          "de": "Hongkong-Zeit",
+          "ru": "袚芯薪泻芯薪谐褋泻芯械 胁褉械屑褟",
+          "ar": "鬲賵賯賷鬲 賴賵賳睾 賰賵賳睾",
+          "pt": "Hora de Hong Kong"
+      }
+  },
+  "Asia/Singapore": {
+      "utc_offset": "+08:00",
+      "name": {
+          "zh": "鏂板姞鍧℃爣鍑嗘椂闂�",
+          "en": "Singapore Standard Time",
+          "ja": "銈枫兂銈儩銉笺儷妯欐簴鏅�",
+          "ko": "鞁标皜韽ゴ 響滌鞁�",
+          "es": "Hora Est谩ndar de Singapur",
+          "fr": "Heure Standard de Singapour",
+          "de": "Singapur-Standardzeit",
+          "ru": "小懈薪谐邪锌褍褉褋泻芯械 褋褌邪薪写邪褉褌薪芯械 胁褉械屑褟",
+          "ar": "丕賱鬲賵賯賷鬲 丕賱賯賷丕爻賷 賱爻賳睾丕賮賵乇丞",
+          "pt": "Hora Padr茫o de Cingapura"
+      }
+  },
+  "Asia/Seoul": {
+      "utc_offset": "+09:00",
+      "name": {
+          "zh": "闊╁浗鏍囧噯鏃堕棿锛堥灏旓級",
+          "en": "Korea Standard Time (Seoul)",
+          "ja": "闊撳浗妯欐簴鏅傦紙銈姐偊銉級",
+          "ko": "頃滉淡 響滌鞁� (靹滌毟)",
+          "es": "Hora Est谩ndar de Corea (Se煤l)",
+          "fr": "Heure Standard de Cor茅e (S茅oul)",
+          "de": "Koreanische Standardzeit (Seoul)",
+          "ru": "袣芯褉械泄褋泻芯械 褋褌邪薪写邪褉褌薪芯械 胁褉械屑褟 (小械褍谢)",
+          "ar": "丕賱鬲賵賯賷鬲 丕賱賯賷丕爻賷 丕賱賰賵乇賷 (爻賷賵賱)",
+          "pt": "Hora Padr茫o da Coreia (Seul)"
+      }
+  },
+  "Asia/Tokyo": {
+      "utc_offset": "+09:00",
+      "name": {
+          "zh": "鏃ユ湰鏍囧噯鏃堕棿锛堜笢浜級",
+          "en": "Japan Standard Time (Tokyo)",
+          "ja": "鏃ユ湰妯欐簴鏅傦紙鏉变含锛�",
+          "ko": "鞚茧掣 響滌鞁� (霃勳縿)",
+          "es": "Hora Est谩ndar de Jap贸n (Tokio)",
+          "fr": "Heure Standard du Japon (Tokyo)",
+          "de": "Japanische Standardzeit (Tokio)",
+          "ru": "携锌芯薪褋泻芯械 褋褌邪薪写邪褉褌薪芯械 胁褉械屑褟 (孝芯泻懈芯)",
+          "ar": "丕賱鬲賵賯賷鬲 丕賱賯賷丕爻賷 丕賱賷丕亘丕賳賷 (胤賵賰賷賵)",
+          "pt": "Hora Padr茫o do Jap茫o (T贸quio)"
+      }
+  },
+  "Australia/Perth": {
+      "utc_offset": "+08:00",
+      "name": {
+          "zh": "婢冲ぇ鍒╀簹瑗块儴鏃堕棿锛堢弨鏂級",
+          "en": "Australian Western Standard Time (Perth)",
+          "ja": "銈兗銈广儓銉┿儶銈㈣タ閮ㄦ婧栨檪锛堛儜銉笺偣锛�",
+          "ko": "順胳< 靹滊秬 響滌鞁� (韻检姢)",
+          "es": "Hora Est谩ndar Occidental de Australia (Perth)",
+          "fr": "Heure Standard de l'Ouest Australien (Perth)",
+          "de": "Westaustralische Standardzeit (Perth)",
+          "ru": "袟邪锌邪写薪芯邪胁褋褌褉邪谢懈泄褋泻芯械 褋褌邪薪写邪褉褌薪芯械 胁褉械屑褟 (袩械褉褌)",
+          "ar": "丕賱鬲賵賯賷鬲 丕賱賯賷丕爻賷 賱睾乇亘 兀爻鬲乇丕賱賷丕 (亘賷乇孬)",
+          "pt": "Hora Padr茫o da Austr谩lia Ocidental (Perth)"
+      }
+  },
+  "Australia/Sydney": {
+      "utc_offset": "+10:00",
+      "name": {
+          "zh": "婢冲ぇ鍒╀簹涓滈儴鏃堕棿锛堟倝灏硷級",
+          "en": "Australian Eastern Standard Time (Sydney)",
+          "ja": "銈兗銈广儓銉┿儶銈㈡澅閮ㄦ婧栨檪锛堛偡銉夈儖銉硷級",
+          "ko": "順胳< 霃欕秬 響滌鞁� (鞁滊摐雼�)",
+          "es": "Hora Est谩ndar Oriental de Australia (S铆dney)",
+          "fr": "Heure Standard de l'Est Australien (Sydney)",
+          "de": "Ostaustralische Standardzeit (Sydney)",
+          "ru": "袙芯褋褌芯褔薪芯邪胁褋褌褉邪谢懈泄褋泻芯械 褋褌邪薪写邪褉褌薪芯械 胁褉械屑褟 (小懈写薪械泄)",
+          "ar": "丕賱鬲賵賯賷鬲 丕賱賯賷丕爻賷 賱卮乇賯 兀爻鬲乇丕賱賷丕 (爻賷丿賳賷)",
+          "pt": "Hora Padr茫o da Austr谩lia Oriental (Sydney)"
+      }
+  },
+  "Pacific/Guam": {
+      "utc_offset": "+10:00",
+      "name": {
+          "zh": "鍏冲矝鏃堕棿",
+          "en": "Guam Time",
+          "ja": "銈般偄銉犳檪闁�",
+          "ko": "甏� 鞁滉皠",
+          "es": "Hora de Guam",
+          "fr": "Heure de Guam",
+          "de": "Guam-Zeit",
+          "ru": "袙褉械屑褟 袚褍邪屑邪",
+          "ar": "鬲賵賯賷鬲 睾賵丕賲",
+          "pt": "Hora de Guam"
+      }
+  },
+  "Pacific/Noumea": {
+      "utc_offset": "+11:00",
+      "name": {
+          "zh": "鏂板杸閲屽灏间簹鏃堕棿锛堝姫缇庨樋锛�",
+          "en": "New Caledonia Time (Noumea)",
+          "ja": "銉嬨儱銉笺偒銉儔銉嬨偄鏅傞枔锛堛儗銉°偄锛�",
+          "ko": "雺挫辜霠堧弰雼堨晞 鞁滉皠 (雸勲鞎�)",
+          "es": "Hora de Nueva Caledonia (Numea)",
+          "fr": "Heure de Nouvelle-Cal茅donie (Noum茅a)",
+          "de": "Neukaledonische Zeit (Noumea)",
+          "ru": "袧芯胁芯泻邪谢械写芯薪褋泻芯械 胁褉械屑褟 (袧褍屑械邪)",
+          "ar": "鬲賵賯賷鬲 賰丕賱賷丿賵賳賷丕 丕賱噩丿賷丿丞 (賳賵賲賷丕)",
+          "pt": "Hora da Nova Caled么nia (Nume谩)"
+      }
+  },
+  "Pacific/Auckland": {
+      "utc_offset": "+12:00",
+      "name": {
+          "zh": "鏂拌タ鍏版爣鍑嗘椂闂达紙濂ュ厠鍏帮級",
+          "en": "New Zealand Standard Time (Auckland)",
+          "ja": "銉嬨儱銉笺偢銉笺儵銉炽儔妯欐簴鏅傦紙銈兗銈儵銉炽儔锛�",
+          "ko": "雺挫霝滊摐 響滌鞁� (鞓ろ伌霝滊摐)",
+          "es": "Hora Est谩ndar de Nueva Zelanda (Auckland)",
+          "fr": "Heure Standard de Nouvelle-Z茅lande (Auckland)",
+          "de": "Neuseel盲ndische Standardzeit (Auckland)",
+          "ru": "袧芯胁芯蟹械谢邪薪写褋泻芯械 褋褌邪薪写邪褉褌薪芯械 胁褉械屑褟 (袨泻谢械薪写)",
+          "ar": "丕賱鬲賵賯賷鬲 丕賱賯賷丕爻賷 賱賳賷賵夭賷賱賳丿丕 (兀賵賰賱丕賳丿)",
+          "pt": "Hora Padr茫o da Nova Zel芒ndia (Auckland)"
+      }
+  },
+  "Pacific/Fiji": {
+      "utc_offset": "+12:00",
+      "name": {
+          "zh": "鏂愭祹鏃堕棿",
+          "en": "Fiji Time",
+          "ja": "銉曘偅銈搞兗鏅傞枔",
+          "ko": "頂检 鞁滉皠",
+          "es": "Hora de Fiyi",
+          "fr": "Heure de Fidji",
+          "de": "Fidschi-Zeit",
+          "ru": "袙褉械屑褟 肖懈写卸懈",
+          "ar": "鬲賵賯賷鬲 賮賷噩賷",
+          "pt": "Hora de Fiji"
+      }
+  },
+  "Pacific/Tongatapu": {
+      "utc_offset": "+13:00",
+      "name": {
+          "zh": "姹ゅ姞鏃堕棿锛堟堡鍔犲鏅級",
+          "en": "Tonga Time (Tongatapu)",
+          "ja": "銉堛兂銈檪闁擄紙銉堛兂銈偪銉楋級",
+          "ko": "韱店皜 鞁滉皠 (韱店皜韮�響�)",
+          "es": "Hora de Tonga (Tongatapu)",
+          "fr": "Heure de Tonga (Tongatapu)",
+          "de": "Tonga-Zeit (Tongatapu)",
+          "ru": "袙褉械屑褟 孝芯薪谐邪 (孝芯薪谐邪褌邪锌褍)",
+          "ar": "鬲賵賯賷鬲 鬲賵賳睾丕 (鬲賵賳睾丕鬲丕亘賵)",
+          "pt": "Hora de Tonga (Tongatapu)"
+      }
+  }
+}
+
+const timezoneRegionNames = {
+zh: {
+  Africa: '闈炴床',
+  America: '缇庢床',
+  Antarctica: '鍗楁瀬娲�',
+  Arctic: '鍖楁瀬',
+  Asia: '浜氭床',
+  Atlantic: '澶цタ娲�',
+  Australia: '婢冲ぇ鍒╀簹',
+  Europe: '娆ф床',
+  Indian: '鍗板害娲�',
+  Pacific: '澶钩娲�'
+},
+en: {
+  Africa: 'Africa',
+  America: 'America',
+  Antarctica: 'Antarctica',
+  Arctic: 'Arctic',
+  Asia: 'Asia',
+  Atlantic: 'Atlantic',
+  Australia: 'Australia',
+  Europe: 'Europe',
+  Indian: 'Indian',
+  Pacific: 'Pacific'
+},
+es: {
+  Africa: '脕frica',
+  America: 'Am茅rica',
+  Antarctica: 'Ant谩rtida',
+  Arctic: '脕rtico',
+  Asia: 'Asia',
+  Atlantic: 'Atl谩ntico',
+  Australia: 'Australia',
+  Europe: 'Europa',
+  Indian: '脥ndico',
+  Pacific: 'Pac铆fico'
+},
+fr: {
+  Africa: 'Afrique',
+  America: 'Am茅rique',
+  Antarctica: 'Antarctique',
+  Arctic: 'Arctique',
+  Asia: 'Asie',
+  Atlantic: 'Atlantique',
+  Australia: 'Australie',
+  Europe: 'Europe',
+  Indian: 'Indien',
+  Pacific: 'Pacifique'
+},
+de: {
+  Africa: 'Afrika',
+  America: 'Amerika',
+  Antarctica: 'Antarktis',
+  Arctic: 'Arktis',
+  Asia: 'Asien',
+  Atlantic: 'Atlantik',
+  Australia: 'Australien',
+  Europe: 'Europa',
+  Indian: 'Indischer Ozean',
+  Pacific: 'Pazifik'
+},
+ru: {
+  Africa: '袗褎褉懈泻邪',
+  America: '袗屑械褉懈泻邪',
+  Antarctica: '袗薪褌邪褉泻褌懈写邪',
+  Arctic: '袗褉泻褌懈泻邪',
+  Asia: '袗蟹懈褟',
+  Atlantic: '袗褌谢邪薪褌懈泻邪',
+  Australia: '袗胁褋褌褉邪谢懈褟',
+  Europe: '袝胁褉芯锌邪',
+  Indian: '袠薪写懈泄褋泻懈泄 芯泻械邪薪',
+  Pacific: '孝懈褏懈泄 芯泻械邪薪'
+},
+ar: {
+  Africa: '兀賮乇賷賯賷丕',
+  America: '丕賱兀賲乇賷賰鬲丕賳',
+  Antarctica: '兀賳鬲丕乇賰鬲賷賰丕',
+  Arctic: '丕賱賯胤亘 丕賱卮賲丕賱賷',
+  Asia: '丌爻賷丕',
+  Atlantic: '丕賱兀胤賱爻賷',
+  Australia: '兀爻鬲乇丕賱賷丕',
+  Europe: '兀賵乇賵亘丕',
+  Indian: '丕賱賲丨賷胤 丕賱賴賳丿賷',
+  Pacific: '丕賱賲丨賷胤 丕賱賴丕丿卅'
+},
+pt: {
+  Africa: '脕frica',
+  America: 'Am茅rica',
+  Antarctica: 'Ant谩rtida',
+  Arctic: '脕rtico',
+  Asia: '脕sia',
+  Atlantic: 'Atl芒ntico',
+  Australia: 'Austr谩lia',
+  Europe: 'Europa',
+  Indian: '脥ndico',
+  Pacific: 'Pac铆fico'
+},
+ko: {
+  Africa: '鞎勴攧毽勾',
+  America: '鞎勲毽勾',
+  Antarctica: '雮饭',
+  Arctic: '攵侁饭',
+  Asia: '鞎勳嫓鞎�',
+  Atlantic: '雽�靹滌枒',
+  Australia: '鞓れ姢韸鸽爤鞚茧Μ鞎�',
+  Europe: '鞙犽熃',
+  Indian: '鞚鸽弰鞏�',
+  Pacific: '韮滍弶鞏�'
+}
+}
+
+export { timezones, timezoneRegionNames }
\ No newline at end of file
diff --git "a/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/views/config/index.vue" "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/views/config/index.vue"
new file mode 100644
index 0000000..9c16193
--- /dev/null
+++ "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/views/config/index.vue"
@@ -0,0 +1,2241 @@
+<template>
+  <div id="configMain">
+    <div class="config-container">
+      <div class="config-tabs">
+        <el-tabs v-model="activeTab" type="card" @tab-click="handleClick">
+          <!-- 鍩虹閰嶇疆 -->
+          <el-tab-pane :label="$t('config.basicConfiguration')" name="base">
+            <div class="config-grid">
+              <!-- 鏄剧ず璁剧疆鍗$墖 -->
+              <el-card class="config-card card-theme-display">
+                <div class="config-card__header">
+                  <i class="el-icon-monitor config-card__header-icon"></i>
+                  {{ $t('config.displaySettings') }}
+                </div>
+                <div class="config-card__body">
+                  <el-form ref="displayForm" :model="base" :rules="baseRules" label-width="140px">
+                    <!-- 鑷姩璋冭妭浜害 -->
+                    <!-- <div class="config-form-item">
+                      <el-form-item :label="$t('config.autoAdjustScreenBrightness')">
+                        <el-switch v-model="base.brightnessAuto" :active-value="1" :inactive-value="0"
+                          active-color="#1890ff" inactive-color="#ff4949">
+                        </el-switch>
+                      </el-form-item>
+                    </div> -->
+                    <!-- 灞忓箷浜害 -->
+                    <div class="config-form-item">
+                      <el-form-item :label="$t('config.screenBrightness')">
+                        <div class="compact-controls">
+                          <el-slider v-model="base.backlight" :max="100" :min="1" style="width:60%;"></el-slider>
+                          <span class="value-display">{{ base.backlight }}%</span>
+                        </div>
+                      </el-form-item>
+                    </div>
+                    <!-- 鑷姩鎭睆 -->
+                    <div class="config-form-item">
+                      <el-form-item :label="$t('config.autoTurnOffScreenTime')" prop="screenOff">
+                        <el-select v-model="base.screenOff" placeholder="璇烽�夋嫨">
+                          <!-- <el-option v-for="(item, index) in idleData" :key="index" :label="item" :value="index">
+                          </el-option> -->
+                          <el-option :label="$t('config.never')" :value="0"></el-option>
+                          <el-option :label="$t('config.min1')" :value="1"></el-option>
+                          <el-option :label="$t('config.min2')" :value="2"></el-option>
+                          <el-option :label="$t('config.min3')" :value="3"></el-option>
+                          <el-option :label="$t('config.min4')" :value="4"></el-option>
+                          <el-option :label="$t('config.min5')" :value="5"></el-option>
+                        </el-select>
+                        <!-- <el-input v-model="base.screenOff" type="number" :min="0"
+                          :placeholder="$t('config.msg_please_enter')"></el-input><span>
+                          {{ $t('config.min') }}</span> -->
+                      </el-form-item>
+                    </div>
+                    <!-- 鑷姩灞忎繚 -->
+                    <div class="config-form-item">
+                      <el-form-item :label="$t('config.autoScreenSaverTime')" prop="screensaver">
+                        <el-select v-model="base.screensaver" placeholder="璇烽�夋嫨">
+                          <!-- <el-option v-for="(item, index) in idleData" :key="index" :label="item" :value="index">
+                          </el-option> -->
+                          <el-option :label="$t('config.never')" :value="0"></el-option>
+                          <el-option :label="$t('config.min1')" :value="1"></el-option>
+                          <el-option :label="$t('config.min2')" :value="2"></el-option>
+                          <el-option :label="$t('config.min3')" :value="3"></el-option>
+                          <el-option :label="$t('config.min4')" :value="4"></el-option>
+                          <el-option :label="$t('config.min5')" :value="5"></el-option>
+                        </el-select>
+                      </el-form-item>
+                    </div>
+                    <!-- 鐧借壊琛ュ厜鐏� -->
+                    <div class="config-form-item"
+                      v-if="sys.model == 'vf105' || sys.model == 'vf107' || sys.model == 'vf114' || sys.model == 'vf124' || sys.model == 'vf202'">
+                      <el-form-item :label="$t('config.brightness')">
+                        <div class="compact-controls">
+                          <el-slider v-model="base.brightness" :max="100" :min="0" style="width:60%;"></el-slider>
+                          <span class="value-display">{{ base.brightness }}%</span>
+                        </div>
+                      </el-form-item>
+                    </div>
+                    <!-- 绾㈠琛ュ厜鐏� -->
+                    <!-- <div class="config-form-item">
+                      <el-form-item :label="$t('config.nirBrightness')">
+                        <div class="compact-controls">
+                          <el-slider v-model="base.nirBrightness" :max="100" :min="0" style="width:60%;"></el-slider>
+                          <span class="value-display">{{ base.nirBrightness }}%</span>
+                        </div>
+                      </el-form-item>
+                    </div> -->
+                  </el-form>
+                </div>
+              </el-card>
+              <!-- 淇℃伅鏄剧ず鍗$墖 -->
+              <el-card class="config-card card-theme-display">
+                <div class="config-card__header">
+                  <i class="el-icon-info config-card__header-icon"></i>
+                  {{ $t('config.informationDisplay') }}
+                </div>
+                <div class="config-card__body">
+                  <el-form ref="infoForm" :model="base" label-width="140px">
+                    <!-- 鏄剧ずSN -->
+                    <div class="config-form-item">
+                      <el-form-item :label="$t('config.displayDeviceSn')">
+                        <el-switch v-model="base.showSn" :active-value="1" :inactive-value="0" active-color="#1890ff"
+                          inactive-color="#ff4949">
+                        </el-switch>
+                      </el-form-item>
+                    </div>
+                    <!-- 鏄剧ずIP -->
+                    <div class="config-form-item">
+                      <el-form-item :label="$t('config.displayIp')">
+                        <el-switch v-model="base.showIp" :active-value="1" :inactive-value="0" active-color="#1890ff"
+                          inactive-color="#ff4949">
+                        </el-switch>
+                      </el-form-item>
+                    </div>
+                    <!-- 鏄剧ず灏忕▼搴忕爜 -->
+                    <!-- <div class="config-form-item">
+                      <el-form-item :label="$t('config.displayCode')">
+                        <el-switch v-model="base.showProgramCode" :active-value="1" :inactive-value="0"
+                          active-color="#1890ff" inactive-color="#ff4949">
+                        </el-switch>
+                      </el-form-item>
+                    </div> -->
+                    <!-- 浜戣瘉鍔熻兘鑿滃崟 -->
+                    <!-- <div class="config-form-item">
+                      <el-form-item :label="$t('config.displayIdentityCard')">
+                        <el-switch v-model="base.showIdentityCard" :active-value="1" :inactive-value="0"
+                          active-color="#1890ff" inactive-color="#ff4949">
+                        </el-switch>
+                      </el-form-item>
+                    </div> -->
+                  </el-form>
+                </div>
+              </el-card>
+              <!-- 闊抽璁剧疆鍗$墖 -->
+              <el-card class="config-card card-theme-display">
+                <div class="config-card__header">
+                  <i class="el-icon-mic config-card__header-icon"></i>
+                  {{ $t('config.audioSettings') }}
+                </div>
+                <div class="config-card__body">
+                  <el-form ref="audioForm" :model="base" label-width="140px">
+                    <!-- 闊抽噺 -->
+                    <div class="config-form-item">
+                      <el-form-item :label="$t('config.volume')" prop="volume">
+                        <div class="compact-controls">
+                          <el-slider v-model="base.volume" :max="10" :min="0" style="flex: 1"></el-slider>
+                          <span class="value-display">{{ base.volume }}</span>
+                        </div>
+                      </el-form-item>
+                    </div>
+                  </el-form>
+                </div>
+              </el-card>
+              <!-- 璇█涓庝富棰樺崱鐗� -->
+              <el-card class="config-card card-theme-display">
+                <div class="config-card__header">
+                  <i class="el-icon-s-operation config-card__header-icon"></i>
+                  {{ $t('config.languageAndThemes') }}
+                </div>
+                <div class="config-card__body">
+                  <el-form ref="systemForm" :model="base" label-width="140px">
+                    <div class="config-form-item">
+                      <el-form-item :label="$t('config.language')" prop="language">
+                        <el-radio-group v-model="base.language" class="language-radio-group"
+                          :style="{ 'margin-bottom': version == 0 ? '0px' : '12px' }">
+                          <el-radio v-if="version == 0" label="CN">{{ $t('config.cn') }}</el-radio>
+                          <div v-else>
+                            <el-radio label="EN">{{ $t('config.en') }}</el-radio>
+                            <el-radio label="ES">{{ $t('config.es') }}</el-radio>
+                            <el-radio label="FR">{{ $t('config.fr') }}</el-radio>
+                            <el-radio label="DE">{{ $t('config.de') }}</el-radio>
+                            <el-radio label="RU">{{ $t('config.ru') }}</el-radio>
+                            <el-radio label="AR">{{ $t('config.ar') }}</el-radio>
+                            <el-radio label="PT">{{ $t('config.pt') }}</el-radio>
+                            <el-radio label="KO">{{ $t('config.ko') }}</el-radio>
+                          </div>
+                        </el-radio-group>
+                      </el-form-item>
+                    </div>
+                    <!-- 宸ヤ綔涓婚 -->
+                    <div class="config-form-item">
+                      <el-form-item :label="$t('config.themeMode')">
+                        <el-radio-group v-model="base.appMode">
+                          <el-radio :label="0">{{ $t('config.standardMode') }}</el-radio>
+                          <el-radio :label="1">{{ $t('config.simpleMode') }}</el-radio>
+                        </el-radio-group>
+                      </el-form-item>
+                    </div>
+                    <!-- 鏄惁绗竴娆$櫥褰曞悗鍙� -->
+                    <!-- <div class="config-form-item">
+                      <el-form-item :label="$t('config.firstLogin')">
+                        <el-radio-group v-model="base.firstLogin">
+                          <el-radio :label="0">{{ $t('config.no') }}</el-radio>
+                          <el-radio :label="1">{{ $t('config.yes') }}</el-radio>
+                        </el-radio-group>
+                      </el-form-item>
+                    </div> -->
+                  </el-form>
+                </div>
+              </el-card>
+            </div>
+          </el-tab-pane>
+          <!-- 缃戠粶閰嶇疆 -->
+          <el-tab-pane :label="$t('config.networkConfiguration')" name="net">
+            <div class="config-grid">
+              <!-- 缃戠粶绫诲瀷鍗$墖 -->
+              <el-card class="config-card card-theme-display">
+                <div class="config-card__header">
+                  <i class="el-icon-connection config-card__header-icon"></i>
+                  {{ $t('config.networkType') }}
+                </div>
+                <div class="config-card__body">
+                  <el-form ref="networkForm" :model="net" :rules="netRules" label-width="140px">
+                    <div class="config-form-item">
+                      <el-form-item :label="$t('config.networkType')">
+                        <el-radio-group v-model="net.type">
+                          <el-radio :label="1">{{ $t('config.ethernet') }}</el-radio>
+                          <el-radio :label="2"
+                            v-model-permission="['vf203', 'vf105', 'vf107', 'vf114', 'vf124', 'vf205']">WiFi</el-radio>
+                          <el-radio :label="4" v-model-permission="['vf203']">4G</el-radio>
+                        </el-radio-group>
+                      </el-form-item>
+                    </div>
+                    <template v-if="net.type === 2">
+                      <div class="config-form-item">
+                        <el-form-item :label="$t('config.wifiName')">
+                          <el-input v-model="net.ssid" type="text"
+                            :placeholder="$t('config.msg_please_enter')"></el-input>
+                        </el-form-item>
+                      </div>
+                      <div class="config-form-item">
+                        <el-form-item :label="$t('config.wifiPassword')">
+                          <el-input v-model="net.psk" type="text"
+                            :placeholder="$t('config.msg_please_enter')"></el-input>
+                        </el-form-item>
+                      </div>
+                    </template>
+                  </el-form>
+                </div>
+              </el-card>
+              <el-card class="config-card card-zhanwei"></el-card>
+              <!-- IP閰嶇疆鍗$墖 -->
+              <el-card class="config-card card-theme-display">
+                <div class="config-card__header">
+                  <i class="el-icon-s-platform config-card__header-icon"></i>
+                  {{ $t('config.ipConfiguration') }}
+                </div>
+                <div class="config-card__body">
+                  <el-form ref="ipForm" :model="net" :rules="netRules" label-width="140px">
+                    <div class="config-form-item">
+                      <el-form-item :label="$t('config.dhcpModeSelection')">
+                        <el-radio-group v-model="net.dhcp">
+                          <el-radio :label="1">{{ $t('config.customNetworkConfiguration') }}</el-radio>
+                          <el-radio :label="2">{{ $t('config.dhcpMode') }}</el-radio>
+                        </el-radio-group>
+                      </el-form-item>
+                    </div>
+                    <template v-if="net.dhcp === 1">
+                      <div class="config-form-item">
+                        <el-form-item :label="$t('config.ipAddress')" prop="ip">
+                          <el-input v-model="net.ip" placeholder="192.168.10.99"></el-input>
+                        </el-form-item>
+                      </div>
+                      <div class="config-form-item">
+                        <el-form-item :label="$t('config.gateway')" prop="gateway">
+                          <el-input v-model="net.gateway" placeholder="192.168.1.1"></el-input>
+                        </el-form-item>
+                      </div>
+                      <div class="config-form-item">
+                        <el-form-item :label="$t('config.subnetMask')" prop="mask">
+                          <el-input v-model="net.mask" placeholder="255.255.255.0"></el-input>
+                        </el-form-item>
+                      </div>
+                      <div class="config-form-item">
+                        <el-form-item :label="$t('config.dnsServer')" prop="dns">
+                          <el-input v-model="net.dns" placeholder="8.8.8.8"></el-input>
+                        </el-form-item>
+                      </div>
+                    </template>
+                  </el-form>
+                </div>
+              </el-card>
+              <!-- 鍏朵粬閰嶇疆 -->
+              <el-card class="config-card card-theme-display">
+                <div class="config-card__header">
+                  <i class="el-icon-s-platform config-card__header-icon"></i>
+                  {{ $t('config.otherConfiguration') }}
+                </div>
+                <div class="config-card__body">
+                  <el-form ref="ipForm" label-width="140px">
+                    <div class="config-form-item">
+                      <el-form-item :label="$t('config.mac')">
+                        <el-input v-model="net.mac" placeholder="D6:18:6C:CE:B4:60" :disabled="true"></el-input>
+                      </el-form-item>
+                    </div>
+                  </el-form>
+                </div>
+              </el-card>
+              <el-card class="config-card card-zhanwei"></el-card>
+            </div>
+          </el-tab-pane>
+          <!-- mqtt閰嶇疆 -->
+          <el-tab-pane :label="$t('config.mqttRelatedConfiguration')" name="mqtt" v-if="!isWeCom">
+            <div class="config-grid">
+              <!-- mqtt淇℃伅閰嶇疆 -->
+              <el-card class="config-card card-theme-display">
+                <div class="config-card__header">
+                  <i class="el-icon-connection config-card__header-icon"></i>
+                  {{ $t('config.mqttConnectionInformation') }}({{ ($t('config.enterpriseWechat')) }})
+                </div>
+                <div class="config-card__body">
+                  <el-form ref="mqttForm" :model="mqtt" :rules="mqttRules" label-width="140px">
+                    <!-- 鏈嶅姟鍣ㄥ湴鍧� -->
+                    <div class="config-form-item">
+                      <el-form-item :label="$t('config.serverAddress')" prop="addr">
+                        <el-input v-model="mqtt.addr" :placeholder="$t('config.msg_please_enter')"></el-input>
+                      </el-form-item>
+                    </div>
+                    <!-- 鐢ㄦ埛鍚� -->
+                    <div class="config-form-item">
+                      <el-form-item :label="$t('config.userName')">
+                        <el-input v-model="mqtt.username" type="text"
+                          :placeholder="$t('config.msg_please_enter')"></el-input>
+                      </el-form-item>
+                    </div>
+                    <!-- 鐢ㄦ埛瀵嗙爜 -->
+                    <div class="config-form-item">
+                      <el-form-item :label="$t('config.userPassword')">
+                        <el-input v-model="mqtt.password" type="text"
+                          :placeholder="$t('config.msg_please_enter')"></el-input>
+                      </el-form-item>
+                    </div>
+                    <!-- qos -->
+                    <div class="config-form-item">
+                      <el-form-item label="Qos">
+                        <el-radio-group v-model="mqtt.qos">
+                          <el-radio :label="0">Qos0</el-radio>
+                          <el-radio :label="1">Qos1</el-radio>
+                          <el-radio :label="2">Qos2</el-radio>
+                        </el-radio-group>
+                      </el-form-item>
+                    </div>
+                    <!-- 瀹㈡埛绔疘d -->
+                    <div class="config-form-item">
+                      <el-form-item :label="$t('config.clientID')">
+                        <el-input v-model="mqtt.clientId" type="text" :placeholder="$t('config.msg_please_enter')"
+                          disabled></el-input>
+                      </el-form-item>
+                    </div>
+                    <!-- 鏄惁鍔犻殢鏈烘暟 -->
+                    <div class="config-form-item">
+                      <el-form-item :label="$t('config.clientIdSuffix')">
+                        <el-radio-group v-model="mqtt.clientIdSuffix">
+                          <el-radio :label="0">{{ $t('config.no') }}</el-radio>
+                          <el-radio :label="1">{{ $t('config.yes') }}</el-radio>
+                        </el-radio-group>
+                      </el-form-item>
+                    </div>
+                    <!-- 娓呴櫎浼氳瘽 -->
+                    <!-- <div class="config-form-item">
+                      <el-form-item :label="$t('config.cleanSession')">
+                        <el-radio-group v-model="mqtt.cleanSession">
+                          <el-radio :label="0">{{ $t('config.no') }}</el-radio>
+                          <el-radio :label="1">{{ $t('config.yes') }}</el-radio>
+                        </el-radio-group>
+                      </el-form-item>
+                    </div> -->
+                  </el-form>
+                </div>
+              </el-card>
+              <!-- 浼氳瘽閰嶇疆 -->
+              <el-card class="config-card card-theme-display">
+                <div class="config-card__header">
+                  <i class="el-icon-s-operation config-card__header-icon"></i>
+                  {{ $t('config.sessionConfiguration') }}
+                </div>
+                <div class="config-card__body">
+                  <el-form ref="onlineCheckingForm" :model="mqtt" :rules="mqttRules" label-width="140px">
+                    <!-- 涓婚鍓嶇紑 -->
+                    <div class="config-form-item">
+                      <el-form-item :label="$t('config.topicPrefix')">
+                        <el-input v-model="mqtt.prefix" type="text"
+                          :placeholder="$t('config.msg_please_enter')"></el-input>
+                      </el-form-item>
+                    </div>
+                    <!-- 閬楀槺 -->
+                    <!-- <div class="config-form-item">
+                      <el-form-item :label="$t('config.willTopic')">
+                        <el-input v-model="mqtt.willTopic" type="text"
+                          :placeholder="$t('config.msg_please_enter')"></el-input>
+                      </el-form-item>
+                    </div> -->
+                  </el-form>
+                </div>
+              </el-card>
+              <!-- <el-card class="config-card card-zhanwei"></el-card> -->
+              <!-- 鍦ㄧ嚎楠岃瘉鍗$墖 -->
+              <el-card class="config-card card-theme-display">
+                <div class="config-card__header">
+                  <i class="el-icon-link config-card__header-icon"></i>
+                  {{ $t('config.onlineChecking') }}
+                </div>
+                <div class="config-card__body">
+                  <el-form ref="onlineCheckingForm" :model="mqtt" :rules="mqttRules" label-width="140px">
+                    <!-- 鍦ㄧ嚎楠岃瘉 -->
+                    <div class="config-form-item">
+                      <el-form-item :label="$t('config.onlineChecking')">
+                        <el-switch v-model="mqtt.onlinecheck" active-color="#1890ff" inactive-color="#ff4949"
+                          :active-value="1" :inactive-value="0">
+                        </el-switch>
+                      </el-form-item>
+                    </div>
+                    <!-- 鍦ㄧ嚎楠岃瘉瓒呮椂鏃堕棿 -->
+                    <div class="config-form-item">
+                      <el-form-item :label="$t('config.onlineCheckingTimeout')" prop="timeout">
+                        <el-input v-model="mqtt.timeout" :placeholder="$t('config.msg_please_enter')"></el-input><span>
+                          {{ $t('config.second') }}</span>
+                      </el-form-item>
+                    </div>
+                  </el-form>
+                </div>
+              </el-card>
+            </div>
+          </el-tab-pane>
+          <!-- 浜鸿劯閰嶇疆 -->
+          <el-tab-pane :label="$t('config.faceRelatedConfiguration')" name="face">
+            <div class="config-grid">
+              <!-- mqtt淇℃伅閰嶇疆 -->
+              <el-card class="config-card card-theme-display">
+                <div class="config-card__header">
+                  <i class="el-icon-info config-card__header-icon"></i>
+                  {{ $t('config.functionalInformation') }}
+                </div>
+                <div class="config-card__body">
+                  <el-form ref="faceForm" :model="face" label-width="140px">
+                    <!-- 浜鸿劯璇嗗埆鐩镐技搴� -->
+                    <div class="config-form-item">
+                      <el-form-item :label="$t('config.faceSimilarityThreshold')">
+                        <div class="compact-controls">
+                          <el-slider v-model="face.similarity" :max="100" :min="0" style="width:60%;"></el-slider>
+                          <span class="value-display">{{ face.similarity }}%</span>
+                        </div>
+                      </el-form-item>
+                    </div>
+                    <!-- 娲讳綋妫�娴� -->
+                    <div class="config-form-item">
+                      <el-form-item :label="$t('config.livenessDetectionFunction')">
+                        <el-switch v-model="face.livenessOff" :active-value="1" :inactive-value="0"
+                          active-color="#1890ff" inactive-color="#ff4949">
+                        </el-switch>
+                      </el-form-item>
+                    </div>
+                    <!-- 娲讳綋妫�娴嬮槇鍊� -->
+                    <div class="config-form-item">
+                      <el-form-item :label="$t('config.livenessDetectionThreshold')">
+                        <div class="compact-controls">
+                          <el-slider v-model="face.livenessVal" :max="100" :min="0" style="width:60%;"></el-slider>
+                          <span class="value-display">{{ face.livenessVal }}</span>
+                        </div>
+                      </el-form-item>
+                    </div>
+                    <!-- 绾㈠妗嗗紑鍏� -->
+                    <div class="config-form-item">
+                      <el-form-item :label="$t('config.infraredImageDisplay')">
+                        <el-switch v-model="face.showNir" :active-value="1" :inactive-value="0" active-color="#1890ff"
+                          inactive-color="#ff4949">
+                        </el-switch>
+                      </el-form-item>
+                    </div>
+                    <!-- 鍙g僵妫�娴嬪紑鍏� -->
+                    <!-- <div class="config-form-item">
+                      <el-form-item :label="$t('config.maskRecognition')">
+                        <el-switch v-model="face.detectMask" :active-value="1" :inactive-value="0"
+                          active-color="#1890ff" inactive-color="#ff4949">
+                        </el-switch>
+                      </el-form-item>
+                    </div> -->
+                    <!-- 閲嶆寮�鍏� -->
+                    <div class="config-form-item">
+                      <el-form-item :label="$t('config.recognitionSwitch')">
+                        <el-switch v-model="face.recheck" :active-value="1" :inactive-value="0" active-color="#1890ff"
+                          inactive-color="#ff4949">
+                        </el-switch>
+                      </el-form-item>
+                    </div>
+                  </el-form>
+                </div>
+              </el-card>
+              <el-card class="config-card card-zhanwei"></el-card>
+              <!-- 鎻愮ず璇� -->
+              <el-card class="config-card card-theme-display">
+                <div class="config-card__header">
+                  <i class="el-icon-s-grid config-card__header-icon"></i>
+                  {{ $t('config.prompt') }}
+                </div>
+                <div class="config-card__body">
+                  <el-form ref="faceMsgForm" :model="face" :rules="faceRules" label-width="140px">
+                    <!-- 鏈敞鍐屼汉鑴告彁绀� -->
+                    <div class="config-form-item">
+                      <el-form-item :label="$t('config.strangerVoice')">
+                        <el-radio-group v-model="face.stranger">
+                          <el-radio :label="0">{{ $t('config.noVoice') }}</el-radio>
+                          <el-radio :label="1">{{ $t('config.broadcastPleaseRegisterFirst') }}</el-radio>
+                          <el-radio :label="2">{{ $t('config.broadcastHelloStranger') }}</el-radio>
+                        </el-radio-group>
+                      </el-form-item>
+                    </div>
+                    <!-- 璇嗗埆鎴愬姛鎾斁璇煶 -->
+                    <div class="config-form-item">
+                      <el-form-item :label="$t('config.voiceMode')">
+                        <el-radio-group v-model="face.voiceMode">
+                          <el-radio :label="0">{{ $t('config.noVoice') }}</el-radio>
+                          <el-radio :label="1">{{ $t('config.broadcastName') }}</el-radio>
+                          <el-radio :label="2">{{ $t('config.broadcastGreeting') }}</el-radio>
+                        </el-radio-group>
+                      </el-form-item>
+                    </div>
+                    <!-- 鑷畾涔夋杩庤 -->
+                    <div class="config-form-item" v-if="face.voiceMode == 2">
+                      <el-form-item :label="$t('config.voiceModeDate')">
+                        <el-input v-model="face.voiceModeDate" :placeholder="$t('config.msg_please_enter')"></el-input>
+                      </el-form-item>
+                    </div>
+                  </el-form>
+                </div>
+              </el-card>
+            </div>
+          </el-tab-pane>
+          <!-- 绯荤粺閰嶇疆 -->
+          <el-tab-pane :label="$t('config.systemRelatedConfiguration')" name="sys">
+            <div class="config-grid">
+              <!-- 鍔熻兘寮�鍏抽厤缃� -->
+              <el-card class="config-card card-theme-display">
+                <div class="config-card__header">
+                  <i class="el-icon-video-play config-card__header-icon"></i>
+                  {{ $t('config.functionSwitch') }}
+                </div>
+                <div class="config-card__body">
+                  <el-form ref="sysForm" :model="sys" label-width="140px">
+                    <!-- 鍒峰崱鏍搁獙 -->
+                    <div class="config-form-item">
+                      <el-form-item :label="$t('config.cardSwipingSwitch')">
+                        <el-switch v-model="sys.nfc" :active-value="1" :inactive-value="0" active-color="#1890ff"
+                          inactive-color="#ff4949">
+                        </el-switch>
+                      </el-form-item>
+                    </div>
+                    <!-- 瀵嗙爜寮�闂� -->
+                    <div class="config-form-item">
+                      <el-form-item :label="$t('config.passwordSwitch')">
+                        <el-switch v-model="sys.pwd" :active-value="1" :inactive-value="0" active-color="#1890ff"
+                          inactive-color="#ff4949">
+                        </el-switch>
+                      </el-form-item>
+                    </div>
+                    <!-- 闄岀敓浜轰繚瀛樺浘鐗� -->
+                    <div class="config-form-item">
+                      <el-form-item :label="$t('config.strangerImage')">
+                        <el-radio-group v-model="sys.strangerImage">
+                          <el-radio :label="0">{{ $t('config.notsave') }}</el-radio>
+                          <el-radio :label="1">{{ $t('config.save') }}</el-radio>
+                        </el-radio-group>
+                      </el-form-item>
+                    </div>
+                    <!-- 浜戣瘉寮�鍏� -->
+                    <div class="config-form-item">
+                      <el-form-item :label="$t('config.cloudCertificateSwitch')">
+                        <el-switch v-model="sys.nfcIdentityCardEnable" :active-value="3" :inactive-value="1"
+                          active-color="#1890ff" inactive-color="#ff4949">
+                        </el-switch>
+                      </el-form-item>
+                    </div>
+                  </el-form>
+                </div>
+              </el-card>
+              <!-- 蹇冭烦璁剧疆 -->
+              <el-card class="config-card card-theme-display">
+                <div class="config-card__header">
+                  <i class="el-icon-setting config-card__header-icon"></i>
+                  {{ $t('config.heartbeatConfig') }}
+                </div>
+                <div class="config-card__body">
+                  <el-form ref="sysForm" :model="sys" label-width="140px">
+                    <!-- 蹇冭烦寮�鍏� -->
+                    <div class="config-form-item">
+                      <el-form-item :label="$t('config.heartbeatSwitch')">
+                        <el-switch v-model="sys.heart_en" :active-value="1" :inactive-value="0" active-color="#1890ff"
+                          inactive-color="#ff4949">
+                        </el-switch>
+                      </el-form-item>
+                    </div>
+                    <!-- 蹇冭烦闂撮殧 -->
+                    <div class="config-form-item">
+                      <el-form-item :label="$t('config.heartRateInterval')" prop="heart_time">
+                        <el-input v-model="sys.heart_time" :placeholder="$t('config.msg_please_enter')" type="number"
+                          :min="1"></el-input><span>
+                          {{ $t('config.second') }}</span>
+                      </el-form-item>
+                    </div>
+                    <!-- 蹇冭烦涓婚 -->
+                    <!-- <div class="config-form-item">
+                      <el-form-item :label="$t('config.heartbeatTopic')" prop="heart_topic">
+                        <el-input v-model="sys.heart_topic" :placeholder="$t('config.msg_please_enter')"></el-input>
+                      </el-form-item>
+                    </div> -->
+                    <!-- 蹇冭烦鍐呭 -->
+                    <!-- <div class="config-form-item">
+                      <el-form-item :label="$t('config.heartbeatContent')" prop="heart_payload">
+                        <el-input v-model="sys.heart_payload" :placeholder="$t('config.msg_please_enter')"></el-input>
+                      </el-form-item>
+                    </div> -->
+                  </el-form>
+                </div>
+              </el-card>
+              <!-- 鎵爜璁剧疆 -->
+              <el-card class="config-card card-theme-display" v-model-permission="['vf105', 'vf114']">
+                <div class="config-card__header">
+                  <i class="el-icon-full-screen config-card__header-icon"></i>
+                  {{ $t('config.scanSettings') }}
+                </div>
+                <div class="config-card__body">
+                  <el-form ref="sysForm" :model="sys" label-width="140px">
+                    <!-- 鎵爜寮�鍏� -->
+                    <!-- <div class="config-form-item">
+                      <el-form-item :label="$t('config.scanSwitch')">
+                        <el-switch v-model="sys.scan" :active-value="1" :inactive-value="0" active-color="#1890ff"
+                          inactive-color="#ff4949">
+                        </el-switch>
+                      </el-form-item>
+                    </div> -->
+                    <!-- 鎵爜闂撮殧 -->
+                    <div class="config-form-item">
+                      <el-form-item :label="$t('config.scanInterval')" prop="scanInterval">
+                        <el-input v-model="sys.scanInterval"
+                          :placeholder="$t('config.msg_please_enter')"></el-input><span>
+                          {{ $t('config.second') }}</span>
+                      </el-form-item>
+                    </div>
+                  </el-form>
+                </div>
+              </el-card>
+              <!-- 鍩烘湰淇℃伅 -->
+              <el-card class="config-card card-theme-display">
+                <div class="config-card__header">
+                  <i class="el-icon-info config-card__header-icon"></i>
+                  {{ $t('config.basicInformation') }}
+                </div>
+                <div class="config-card__body">
+                  <el-form ref="accessForm" :model="sys" label-width="140px">
+                    <div class="config-form-item">
+                      <el-form-item :label="$t('config.deviceMac')">
+                        <el-input v-model="sys.mac" :placeholder="$t('config.msg_please_enter')" disabled></el-input>
+                      </el-form-item>
+                    </div>
+                    <div class="config-form-item">
+                      <el-form-item :label="$t('config.uuid')">
+                        <el-input v-model="sys.uuid" :placeholder="$t('config.msg_please_enter')" disabled></el-input>
+                      </el-form-item>
+                    </div>
+                    <div class="config-form-item">
+                      <el-form-item :label="$t('config.sn')">
+                        <el-input v-model="sys.sn" :placeholder="$t('config.msg_please_enter')" disabled></el-input>
+                      </el-form-item>
+                    </div>
+                    <div class="config-form-item">
+                      <el-form-item :label="$t('config.model')">
+                        <el-input v-model="sys.model" :placeholder="$t('config.msg_please_enter')" disabled></el-input>
+                      </el-form-item>
+                    </div>
+                    <div class="config-form-item">
+                      <el-form-item :label="$t('config.version')">
+                        <el-input v-model="sys.version" :placeholder="$t('config.msg_please_enter')"
+                          disabled></el-input>
+                      </el-form-item>
+                    </div>
+                    <div class="config-form-item">
+                      <el-form-item :label="$t('config.appVersion')">
+                        <el-input v-model="sys.appVersion" :placeholder="$t('config.msg_please_enter')"
+                          disabled></el-input>
+                      </el-form-item>
+                    </div>
+                    <div class="config-form-item">
+                      <el-form-item :label="$t('config.releaseTime')">
+                        <el-input v-model="sys.releaseTime" :placeholder="$t('config.msg_please_enter')"
+                          disabled></el-input>
+                      </el-form-item>
+                    </div>
+                    <div class="config-form-item">
+                      <el-form-item :label="$t('config.totaldisk')">
+                        <el-input v-model="sys.totaldisk" :placeholder="$t('config.msg_please_enter')"
+                          disabled></el-input>
+                      </el-form-item>
+                    </div>
+                    <div class="config-form-item">
+                      <el-form-item :label="$t('config.freedisk')">
+                        <el-input v-model="sys.freedisk" :placeholder="$t('config.msg_please_enter')"
+                          disabled></el-input>
+                      </el-form-item>
+                    </div>
+                  </el-form>
+                </div>
+              </el-card>
+            </div>
+          </el-tab-pane>
+          <!-- 閫氳閰嶇疆 -->
+          <el-tab-pane :label="$t('config.passageConfiguration')" name="access">
+            <div class="config-grid">
+              <el-card class="config-card card-theme-display">
+                <div class="config-card__header">
+                  <i class="el-icon-connection config-card__header-icon"></i>
+                  {{ $t('config.functionConfiguration') }}
+                </div>
+                <div class="config-card__body">
+                  <el-form ref="accessForm" :model="access" :rules="accessRules" label-width="140px">
+                    <div class="config-form-item">
+                      <el-form-item :label="$t('config.numberOfPassageRecords')">
+                        <el-input v-model="access.offlineAccessNum"
+                          :placeholder="$t('config.msg_please_enter')"></el-input>
+                      </el-form-item>
+                    </div>
+                    <div class="config-form-item">
+                      <el-form-item :label="$t('config.durationOfRelayOpening')">
+                        <el-input v-model="access.relayTime" :placeholder="$t('config.msg_please_enter')"></el-input>
+                        <span> {{ $t('config.second') }}</span>
+                      </el-form-item>
+                    </div>
+                    <div class="config-form-item">
+                      <el-form-item :label="$t('config.fireAlarmSwitch')">
+                        <el-switch v-model="access.fire" :active-value="1" :inactive-value="0" active-color="#1890ff"
+                          inactive-color="#ff4949">
+                        </el-switch>
+                      </el-form-item>
+                    </div>
+                    <div class="config-form-item">
+                      <el-form-item :label="$t('config.fireAlarmStatus')">
+                        <el-radio-group v-model="access.fireStatus">
+                          <el-radio :label="0">{{ $t('config.normal') }}</el-radio>
+                          <el-radio :label="1">{{ $t('config.warning') }}</el-radio>
+                        </el-radio-group>
+                      </el-form-item>
+                    </div>
+                    <div class="config-form-item">
+                      <el-form-item :label="$t('config.tamperSwitch')">
+                        <el-switch v-model="access.tamper" :active-value="1" :inactive-value="0" active-color="#1890ff"
+                          inactive-color="#ff4949">
+                        </el-switch>
+                      </el-form-item>
+                    </div>
+                    <div class="config-form-item">
+                      <el-form-item :label="$t('config.uploadToCloudSwitch')">
+                        <el-switch v-model="access.uploadToCloud" :active-value="1" :inactive-value="0"
+                          active-color="#1890ff" inactive-color="#ff4949">
+                        </el-switch>
+                      </el-form-item>
+                    </div>
+                  </el-form>
+                </div>
+              </el-card>
+            </div>
+          </el-tab-pane>
+          <!-- 鏃堕挓閰嶇疆 -->
+          <el-tab-pane :label="$t('config.clockConfiguration')" name="ntp">
+            <div class="config-grid">
+              <el-card class="config-card card-theme-display">
+                <div class="config-card__header">
+                  <i class="el-icon-connection config-card__header-icon"></i>
+                  {{ $t('config.clockConfiguration') }}({{ $t('config.restartAfterSetting') }})
+                </div>
+                <div class="config-card__body">
+                  <el-form ref="ntpForm" :model="ntp" :rules="ntpRules" label-width="140px">
+                    <div class="config-form-item">
+                      <el-form-item :label="$t('config.timeSynchronizationServerIP')" prop="server">
+                        <el-input v-model="ntp.server" :placeholder="$t('config.msg_please_enter')"></el-input>
+                      </el-form-item>
+                    </div>
+                    <div class="config-form-item">
+                      <el-form-item :label="$t('config.timeZone')" prop="gmt">
+                        <div class="timezone-selects">
+                          <el-select v-model="selectedTimezoneRegion" :placeholder="$t('config.msg_please_enter')"
+                            @change="handleRegionChange">
+                            <el-option v-for="region in timezoneRegions" :key="region.value" :label="region.label"
+                              :value="region.value"></el-option>
+                          </el-select>
+                          <el-select v-model="selectedTimezoneCity" :placeholder="$t('config.msg_please_enter')"
+                            @change="handleCityChange">
+                            <el-option v-for="city in timezoneCities" :key="city.value" :label="city.label"
+                              :value="city.value"></el-option>
+                          </el-select>
+                        </div>
+                      </el-form-item>
+                    </div>
+                  </el-form>
+                </div>
+              </el-card>
+            </div>
+          </el-tab-pane>
+          <!-- 浜戣瘉婵�娲� -->
+          <el-tab-pane :label="$t('config.cloudCertificateActivation')" name="cloud">
+            <div class="config-grid">
+              <el-card class="config-card card-theme-display">
+                <div class="config-card__header cloud-card-header">
+                  <i class="el-icon-cloudy config-card__header-icon cloud-icon"></i>
+                  {{ $t('config.cloudCertificateActivation') }}
+                  <!-- <div class="cloud-status" :class="cloudStatusClass">
+                    {{ cloudStatusText }}
+                  </div> -->
+                </div>
+                <div class="config-card__body">
+                  <el-form ref="cloudForm" :model="cloudForm" :rules="cloudRules" label-position="top">
+                    <div class="activation-container">
+                      <!-- 婵�娲诲瘑閽ヨ緭鍏ュ尯鍩� -->
+                      <div class="activation-input-section">
+                        <el-form-item :label="$t('config.activationKey')" prop="activationKey"
+                          class="activation-form-item">
+                          <el-input v-model="cloudForm.activationKey" type="textarea"
+                            :placeholder="$t('config.msg_please_enter')" class="activation-input" clearable>
+                            <template #prefix>
+                              <i class="el-icon-key"></i>
+                            </template>
+                          </el-input>
+                          <!-- 杈撳叆鎻愮ず -->
+                          <div class="activation-tips">
+                            <div class="tip-item">
+                              <i class="el-icon-info"></i>
+                              <span>{{ $t('config.cloudTips1') }}</span>
+                            </div>
+                            <div class="tip-item">
+                              <i class="el-icon-warning-outline"></i>
+                              <span>{{ $t('config.cloudTips2') }}</span>
+                            </div>
+                          </div>
+                        </el-form-item>
+                      </div>
+                      <!-- 婵�娲绘寜閽尯鍩� -->
+                      <div class="activation-action-section">
+                        <el-button type="primary" class="activation-btn" :loading="activating"
+                          :disabled="!cloudForm.activationKey" @click="handleActivate">
+                          <i class="el-icon-check"></i>
+                          {{ activating ? $t('config.activationInProgress') : $t('config.confirmActivation') }}
+                        </el-button>
+                      </div>
+                      <!-- 婵�娲荤姸鎬佹樉绀� -->
+                      <!-- <div v-if="activationResult" class="activation-result" :class="activationResultClass">
+                        <i :class="resultIcon"></i>
+                        <span>{{ activationResult.message }}</span>
+                        <span v-if="activationResult.details" class="result-details">{{ activationResult.details
+                        }}</span>
+                      </div> -->
+                    </div>
+                  </el-form>
+                </div>
+              </el-card>
+            </div>
+          </el-tab-pane>
+          <!-- 瀵嗙爜閰嶇疆 -->
+          <el-tab-pane :label="$t('config.passwordModification')" name="pwd">
+            <div class="config-grid">
+              <el-card class="config-card card-theme-display">
+                <div class="config-card__header">
+                  <i class="el-icon-connection config-card__header-icon"></i>
+                  {{ $t('config.password') }}
+                </div>
+                <div class="config-card__body">
+                  <el-form ref="pwdForm" :model="pwd" :rules="pwdRules" label-width="140px">
+                    <div class="config-form-item">
+                      <el-form-item :label="$t('config.oldPassword')" prop="oldPwd">
+                        <el-input style="border:1px solid #eee; width:370px;border-radius: 10px;" v-model="pwd.oldPwd"
+                          autocomplete="off"></el-input>
+                      </el-form-item>
+                    </div>
+                    <div class="config-form-item" style="clear: both;">
+                      <el-form-item :label="$t('config.newPassword')" prop="newPwd">
+                        <el-input style="border:1px solid #eee; width:370px;border-radius: 10px;" v-model="pwd.newPwd"
+                          autocomplete="off"></el-input>
+                      </el-form-item>
+                    </div>
+                    <div class="config-form-item">
+                      <el-form-item :label="$t('config.confirmPassword')" prop="quePwd">
+                        <el-input style="border:1px solid #eee; width:370px;border-radius: 10px;" v-model="pwd.quePwd"
+                          autocomplete="off"></el-input>
+                      </el-form-item>
+                    </div>
+                  </el-form>
+                  <!-- 瀵嗙爜瑙勫垯鎻愮ず璇� -->
+                  <div class="password-rules-tip">
+                    <div class="rules-title">{{ $t('config.passwordRule') }}锛�</div>
+                    <ul class="rules-list">
+                      <li>{{ $t('config.passwordLength') }}</li>
+                      <li>{{ $t('config.cannotBeTheSame') }}</li>
+                      <li>{{ $t('config.cannotOrder') }}</li>
+                      <li>{{ $t('config.cannotWeakPassword') }}锛�</li>
+                      <li class="weak-passwords">"password", "admin", "qwerty", "iloveyou"<br>
+                        "letmein", "welcome", "sunshine", "monkey"</li>
+                    </ul>
+                  </div>
+                </div>
+              </el-card>
+            </div>
+          </el-tab-pane>
+          <!-- 璧勬簮閰嶇疆 -->
+          <el-tab-pane :label="$t('config.resourceConfiguration')" name="resource">
+            <div class="config-grid">
+              <el-card class="config-card card-theme-display">
+                <div class="config-card__header">
+                  <i class="el-icon-picture-outline config-card__header-icon"></i>
+                  {{ $t('config.backgroundImage') }}
+                </div>
+                <div class="config-card__body">
+                  <div class="background-upload-section">
+                    <div class="upload-area">
+                      <el-upload class="background-upload" action="#" :show-file-list="false" accept="image/png"
+                        :before-upload="handleBackgroundSelect">
+                        <el-button type="primary" icon="el-icon-folder-opened">
+                          {{ $t('config.selectImage') }}
+                        </el-button>
+                      </el-upload>
+                      <div v-if="background.name" class="file-info">
+                        <i class="el-icon-document"></i>
+                        <span>{{ background.name }}</span>
+                      </div>
+                    </div>
+                    <div class="upload-actions">
+                      <el-button type="primary" icon="el-icon-upload" :disabled="!background.base64"
+                        :loading="loading.background" @click="uploadBackground">
+                        {{ loading.background ? $t('config.uploading') : $t('config.uploadBackground') }}
+                      </el-button>
+                    </div>
+                    <div class="upload-tips">
+                      <p v-if="model == 'vf202'">{{ $t('config.backgroundUploadTip').replace('{n}', '480*854') }}</p>
+                      <p v-if="model == 'vf105' || model == 'vf107' || model == 'vf205'">{{
+                        $t('config.backgroundUploadTip').replace('{n}', '800*1280') }}</p>
+                      <p v-if="model == 'vf114' || model == 'vf124'">{{ $t('config.backgroundUploadTip').replace('{n}',
+                        '720*1280') }}</p>
+                      <p v-if="model == 'vf203'">{{ $t('config.backgroundUploadTip').replace('{n}', '600*1024') }}</p>
+                    </div>
+                  </div>
+                </div>
+              </el-card>
+            </div>
+          </el-tab-pane>
+        </el-tabs>
+      </div>
+      <el-button v-if="activeTab != 'cloud' && activeTab != 'resource'" class="config-save-btn" type="primary"
+        icon="el-icon-check" size="large" @click="saveAll">{{
+          $t('config.saveConfig') }}</el-button>
+    </div>
+  </div>
+</template>
+<script>
+import { throttle } from '@/utils/index.js'
+import { timezones, timezoneRegionNames } from '@/utils/timezones.js'
+export default {
+  data() {
+    // 瀵嗙爜楠岃瘉瑙勫垯
+    const validatePassword = (rule, value, callback) => {
+      if (!value || value.trim() === '') {
+        callback(new Error(this.$t('config.msg_inputPassword')));
+      } else {
+        callback();
+      }
+    };
+    // 纭瀵嗙爜楠岃瘉瑙勫垯锛堝繀椤讳笌鏂板瘑鐮佷竴鑷达級
+    const validateConfirmPassword = (rule, value, callback) => {
+      if (value !== this.pwd.newPwd) {
+        callback(new Error(this.$t('config.msg_password_mismatch')));
+      } else {
+        callback();
+      }
+    };
+    return {
+      activeTab: 'base',
+      isWeCom: false,
+      base: {
+        screenOff: 0,
+        screensaver: 0,
+        brightness: 70,
+        // brightnessAuto: 1,
+        volume: 50,
+        showIp: 1,
+        showSn: 1,
+        // showProgramCode: 1,
+        // showIdentityCard: 1,
+        language: 'CN',
+        appMode: 1,
+        // nirBrightness: 80,
+        backlight: 70,
+        // firstLogin: 0
+      },
+      idleData: [this.$t('config.never'), this.$t('config.min1'), this.$t('config.min2'), this.$t('config.min3'), this.$t('config.min4'), this.$t('config.min5')],
+      baseRules: {
+        screenOff: [{
+          message: this.$t("common.integerFormat"),
+          trigger: ["blur"],
+          pattern: /^[0-9]+$/
+        }],
+        screensaver: [{
+          message: this.$t("common.integerFormat"),
+          trigger: ["blur"],
+          pattern: /^[0-9]+$/
+        }]
+      },
+      net: {
+        type: 1,
+        ssid: '',
+        psk: '',
+        dhcp: 2,
+        ip: '',
+        gateway: '',
+        mask: '',
+        dns: '',
+        mac: ''
+      },
+      netRules: {
+        ip: [
+          {
+            message: this.$t("common.incorrectFormat"),
+            trigger: ["blur"],
+            pattern: /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/
+          }
+        ],
+        gateway: [
+          {
+            message: this.$t("common.incorrectFormat"),
+            trigger: ["blur"],
+            pattern: /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/
+          }
+        ],
+        mask: [
+          {
+            message: this.$t("common.incorrectFormat"),
+            trigger: ["blur"],
+            pattern: /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/
+          }
+        ],
+        dns: [
+          {
+            message: this.$t("common.incorrectFormat"),
+            trigger: ["blur"],
+            pattern: /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/
+          }
+        ]
+      },
+      mqtt: {
+        addr: '',
+        username: '',
+        password: '',
+        prefix: '',
+        qos: 0,
+        onlinecheck: '',
+        timeout: '',
+        // cleanSession: 0,
+        clientId: '',
+        clientIdSuffix: '',
+        // willTopic: '',
+      },
+      mqttRules: {
+        addr: [
+          {
+            validator: (rule, value, callback) => {
+              const supportedProtocols = ['tcp://', 'ssl://', 'mqtt://', 'mqtts://'];
+              const ipOrDomainWithPort = /^(?:(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)|(?:[a-zA-Z0-9-]+\.)+[a-zA-Z]{2,})(:\d{1,5})?$/
+              let hostPort = value;
+              let hasSupportedProtocol = false;
+              for (const protocol of supportedProtocols) {
+                if (value.startsWith(protocol)) {
+                  hasSupportedProtocol = true;
+                  hostPort = value.slice(protocol.length); // 鍘绘帀鍗忚鍓嶇紑
+                  break;
+                }
+              }
+              if (!hasSupportedProtocol && value.includes('://')) callback(new Error(this.$t("common.incorrectFormat")));
+              if (!hostPort) {
+                callback();
+                return;
+              }
+              if (!ipOrDomainWithPort.test(hostPort)) callback(new Error(this.$t("common.incorrectFormat")));
+              const portMatch = hostPort.match(/:(\d{1,5})$/);
+              if (portMatch) {
+                const port = parseInt(portMatch[1], 10);
+                if (port < 1 || port > 65535) callback(new Error(this.$t("common.incorrectFormat")));
+              }
+              callback();
+            },
+            trigger: ["blur"]
+          }],
+        timeout: [
+          {
+            message: this.$t("common.incorrectFormat"),
+            trigger: ["blur"],
+            pattern: /^[1-9]\d*$/
+          }
+        ],
+      },
+      face: {
+        similarity: 60,
+        livenessOff: 1,
+        livenessVal: 0,
+        showNir: 0,
+        stranger: 0,
+        voiceMode: 0,
+        voiceModeDate: "",
+        recheck: 0
+      },
+      faceRules: {
+        // voiceModeDate: [
+        //   {
+        //     message: this.$t("config.msg_charactersAndNumbers"),
+        //     trigger: ["blur"],
+        //     pattern: /^[\u4e00-\u9fa5]*([1-9]\d*)?[\u4e00-\u9fa5]*$/
+        //   }
+        // ],
+      },
+      sys: {
+        nfc: 1,
+        pwd: 1,
+        strangerImage: 1,
+        heart_en: 0,
+        heart_time: 30,
+        // heart_topic: '',
+        // heart_payload: '',
+        mac: '',
+        uuid: '',
+        sn: '',
+        model: '',
+        version: '',
+        appVersion: '',
+        releaseTime: '',
+        nfcIdentityCardEnable: 1,
+        // scan: '',
+        scanInterval: '',
+        totaldisk: '',
+        freedisk: '',
+      },
+      sysRules: {
+        heart_time: [{
+          message: this.$t("common.positiveIntegerFormat"),
+          trigger: ["blur"],
+          pattern: /^[1-9]\d*$/
+        }],
+        scanInterval: [
+          {
+            message: this.$t("common.incorrectFormat"),
+            trigger: ["blur"],
+            pattern: /^[1-9]\d*$/
+          }
+        ],
+      },
+      access: {
+        offlineAccessNum: 2000,
+        relayTime: 2000,
+        fire: 0,
+        fireStatus: 0,
+        tamper: 0,
+        uploadToCloud: 0,
+      },
+      accessRules: {},
+      ntp: {
+        server: '182.92.12.11',
+        gmt: 'Asia/Shanghai'
+      },
+      selectedTimezoneRegion: '',
+      selectedTimezoneCity: '',
+      ntpRules: {
+        ip: [
+          {
+            message: this.$t("common.incorrectFormat"),
+            trigger: ["blur"],
+            pattern: /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/
+          }
+        ],
+        gmt: [
+          {
+            required: true,
+            message: this.$t("config.msg_please_enter"),
+            trigger: ["change"]
+          }
+        ],
+      },
+      pwd: {
+        orignPwd: '',
+        oldPwd: '',
+        newPwd: '',
+        quePwd: ''
+      },
+      pwdRules: {
+        oldPwd: [
+          {
+            required: true,
+            validator: validatePassword,
+            trigger: ["blur"]
+          }
+        ],
+        newPwd: [
+          { required: true, validator: validatePassword, trigger: ["blur"] },
+        ],
+        quePwd: [
+          { required: true, validator: validatePassword, trigger: ["blur"] },
+          { validator: validateConfirmPassword, trigger: ["blur"] }
+        ]
+      },
+      passwordStrength: 0, // 瀵嗙爜寮哄害绛夌骇 0-4
+      isWeakPassword: false,
+      cloudForm: {
+        activationKey: ''
+      },
+      cloudRules: {
+        activationKey: [
+          { required: true, message: '璇疯緭鍏ユ縺娲诲瘑閽�', trigger: 'blur' },
+          {
+            message: this.$t("common.incorrectFormat"),
+            trigger: ["blur"],
+            pattern: /^___VBAR_ID_ACTIVE_V/
+          }
+        ]
+      },
+      activating: false,
+      activationResult: null,
+      cloudStatus: 'inactive', // 'active' 鎴� 'inactive'
+      background: {
+        base64: '',
+        name: ''
+      },
+      loading: {
+        background: false
+      },
+      reboot: {
+        language: ''
+      },
+      originalBase: null, // 淇濆瓨浠庢湇鍔″櫒鑾峰彇鐨勫師濮媌ase閰嶇疆
+      version: 0, // 鐗堟湰锛�1-鍥介檯鐗堟湰锛�0-鍥藉唴鐗堟湰
+      model: ''
+    }
+  },
+  created() {
+    // 浠巗essionStorage鑾峰彇version锛岄粯璁や负0锛堝浗鍐呯増鏈級
+    let publicConfig = sessionStorage.getItem('publicConfig')
+    let { version, isWeCom, model } = publicConfig ? JSON.parse(publicConfig) : {}
+    if (version == null || version == undefined || version == "CN") {
+      this.version = 0
+    } else {
+      this.version = 1
+    }
+    this.isWeCom = isWeCom
+    this.model = model
+    this.getConfig()
+  },
+  watch: {
+    'ntp.gmt': function () {
+      this.initTimezone()
+    }
+  },
+  computed: {
+    activeConfig() {
+      let config = this[this.activeTab] || {};
+      if (this.activeTab == 'base') {
+        if (this.reboot.language == config.language) {
+          config = { ...config }
+          delete config.language
+        }
+      }
+      if (this.activeTab == 'face') {
+        config.similarity = config.similarity / 100
+        config.livenessVal = config.livenessVal / 10
+      }
+      if (this.activeTab == 'pwd') {
+        config = {
+          password: config.newPwd
+        }
+      }
+      if (this.activeTab == 'ntp') {
+        const { gmt, ...rest } = config
+        config = {
+          ...rest,
+          timeZone: gmt
+        }
+      }
+      if (this.activeTab == 'sys') {
+        let { nfc, pwd, strangerImage, heart_en, heart_time, nfcIdentityCardEnable, scanInterval } = config
+        config = { nfc, pwd, strangerImage, heart_en, heart_time, nfcIdentityCardEnable }
+        if (scanInterval) {
+          config.scanInterval = scanInterval
+        }
+      }
+      if (this.activeTab == 'mqtt') {
+        config = { ...config }
+        delete config.clientId
+      }
+      if (this.activeTab == 'net') {
+        delete config.mac
+      }
+      return config
+    },
+    cloudStatusClass() {
+      return this.cloudStatus === 'active' ? 'active' : 'inactive'
+    },
+    cloudStatusText() {
+      return this.cloudStatus === 'active' ? '宸叉縺娲�' : '鏈縺娲�'
+    },
+    activationResultClass() {
+      return this.activationResult?.type || 'success'
+    },
+    resultIcon() {
+      return this.activationResult?.type === 'error' ? 'el-icon-close' : 'el-icon-check'
+    },
+    timezoneRegions() {
+      const regions = new Set()
+      Object.keys(timezones).forEach(key => {
+        const [region] = key.split('/')
+        regions.add(region)
+      })
+      const locale = this.$i18n.locale || 'en'
+      return Array.from(regions).map(r => ({ label: this.getRegionLabel(r, locale), value: r }))
+    },
+    timezoneCities() {
+      return this.getCitiesByRegion(this.selectedTimezoneRegion || 'Asia')
+    },
+  },
+  methods: {
+    initTimezone() {
+      const current = this.ntp.gmt && typeof this.ntp.gmt === 'string' ? this.ntp.gmt : 'Asia/Shanghai'
+      const parts = current.split('/')
+      const region = parts[0]
+      const city = parts.slice(1).join('/')
+      this.selectedTimezoneRegion = region || 'Asia'
+      const cities = this.getCitiesByRegion(this.selectedTimezoneRegion)
+      const defaultCity = city && cities.find(c => c.value === city) ? city : (cities[0] && cities[0].value)
+      this.selectedTimezoneCity = defaultCity || ''
+      if (this.selectedTimezoneRegion && this.selectedTimezoneCity) {
+        this.ntp.gmt = `${this.selectedTimezoneRegion}/${this.selectedTimezoneCity}`
+      }
+    },
+    getCitiesByRegion(region) {
+      const locale = this.$i18n.locale || 'en'
+      return Object.keys(timezones)
+        .filter(key => key.startsWith(region + '/'))
+        .map(key => {
+          const city = key.split('/')[1]
+          const tz = timezones[key]
+          const label = (tz.name && (tz.name[locale] || tz.name.en)) || city
+          return { value: city, label }
+        })
+    },
+    getRegionLabel(region) {
+      const locale = this.$i18n.locale || 'en'
+      const map = timezoneRegionNames[locale] || timezoneRegionNames.en || {}
+      return map[region] || region
+    },
+    handleRegionChange(region) {
+      const cities = this.getCitiesByRegion(region)
+      if (cities.length) {
+        this.selectedTimezoneCity = cities[0].value
+        this.ntp.gmt = `${region}/${this.selectedTimezoneCity}`
+      } else {
+        this.selectedTimezoneCity = ''
+        this.ntp.gmt = ''
+      }
+    },
+    handleCityChange(city) {
+      if (this.selectedTimezoneRegion && city) {
+        this.ntp.gmt = `${this.selectedTimezoneRegion}/${city}`
+      }
+    },
+    handleActivate() {
+      this.$refs['cloudForm'].validate(async (valid) => {
+        if (valid) {
+          let data = {
+            code: this.cloudForm.activationKey
+          }
+          try {
+            const res = await this.$http.post('/eidActive', { data })
+            if (res.code == 200) {
+              this.$message.success(this.$t('config.activationSuccessful'))
+              this.cloudForm.activationKey = ''
+            } else {
+              this.$message.error(res.message)
+            }
+          } catch (error) {
+            console.log(error)
+          }
+        }
+      })
+    },
+    handleClick() {
+      if (this.activeTab !== 'pwd') {
+        this.getConfig()
+        this.pwd = {
+          orignPwd: '',
+          oldPwd: '',
+          newPwd: '',
+          quePwd: ''
+        }
+      }
+      if (this.activeTab !== 'cloud' && this.cloudForm.activationKey) {
+        this.cloudForm.activationKey = ''
+      }
+      if (this.$refs.displayForm) {
+        this.$refs.displayForm.clearValidate();
+      }
+      if (this.$refs.infoForm) {
+        this.$refs.infoForm.clearValidate();
+      }
+      if (this.$refs.audioForm) {
+        this.$refs.audioForm.clearValidate();
+      }
+      if (this.$refs.systemForm) {
+        this.$refs.systemForm.clearValidate();
+      }
+      if (this.$refs.networkForm) {
+        this.$refs.networkForm.clearValidate();
+      }
+      if (this.$refs.ipForm) {
+        this.$refs.ipForm.clearValidate();
+      }
+      if (this.$refs.mqttForm) {
+        this.$refs.mqttForm.clearValidate();
+      }
+      if (this.$refs.onlineCheckingForm) {
+        this.$refs.onlineCheckingForm.clearValidate();
+      }
+      if (this.$refs.faceForm) {
+        this.$refs.faceForm.clearValidate();
+      }
+      if (this.$refs.faceMsgForm) {
+        this.$refs.faceMsgForm.clearValidate();
+      }
+      if (this.$refs.sysForm) {
+        this.$refs.sysForm.clearValidate();
+      }
+      if (this.$refs.accessForm) {
+        this.$refs.accessForm.clearValidate();
+      }
+      if (this.$refs.ntpForm) {
+        this.$refs.ntpForm.clearValidate();
+      }
+      if (this.$refs.pwdForm) {
+        this.$refs.pwdForm.clearValidate();
+      }
+      if (this.$refs.cloudForm) {
+        this.$refs.cloudForm.clearValidate();
+      }
+    },
+    async getConfig() {
+      const res = await this.$http.post(
+        "/getConfig",
+        {
+          data: ""
+        }
+      );
+      console.log(res)
+      if (res.code == 200) {
+        let { base, mqtt, sys, face, ntp, access, net } = res.data || {}
+        if (base) {
+          this.base = this.mergeWithBase(this.base, base);
+          // 淇濆瓨鍘熷base閰嶇疆锛岀敤浜庡悗缁瘮杈�
+          this.originalBase = { ...base };
+          this.pwd.orignPwd = base.password
+          this.reboot.language = base.language
+        }
+        if (mqtt) {
+          this.mqtt = this.mergeWithBase(this.mqtt, mqtt);
+        }
+        if (sys) {
+          sys.totaldisk = sys.totaldisk + ' M'
+          sys.freedisk = sys.freedisk + ' M'
+          this.sys = this.mergeWithBase(this.sys, sys);
+        }
+        if (face) {
+          face.similarity = Math.round(face.similarity * 100)
+          face.livenessVal = face.livenessVal * 10
+          this.face = this.mergeWithBase(this.face, face);
+        }
+        if (ntp) {
+          const mergedNtp = this.mergeWithBase(this.ntp, ntp)
+          if (ntp.timeZone) {
+            mergedNtp.gmt = ntp.timeZone
+          }
+          this.ntp = mergedNtp
+          this.initTimezone()
+        } else {
+          this.initTimezone()
+        }
+        if (access) this.access = this.mergeWithBase(this.access, access);
+        if (net) this.net = this.mergeWithBase(this.net, net);
+      } else {
+        this.$message.error(res.message)
+      }
+    },
+    saveAll: throttle(async function () {
+      try {
+        // 鍒嗗埆楠岃瘉姣忎釜琛ㄥ崟
+        if (this.activeTab == 'base') {
+          await this.$refs.displayForm.validate();
+        }
+        if (this.activeTab == 'pwd') {
+          await this.$refs.pwdForm.validate();
+          console.log(this.pwd.orignPwd, this.pwd.oldPwd)
+          if (this.pwd.orignPwd != this.pwd.oldPwd) {
+            this.$message.error(this.$t('config.msg_oldPasswordError'));
+            return
+          }
+        }
+        if (this.activeTab == 'face') {
+          await this.$refs.faceMsgForm.validate();
+        }
+        await this.submitData();
+      } catch (error) {
+        console.log(error)
+      }
+    }, 2000),
+    async submitData() {
+      const res = await this.$http.post(
+        "/setConfig",
+        {
+          data: {
+            [this.activeTab == 'pwd' ? 'base' : this.activeTab]: this.activeConfig
+          }
+        }
+      );
+      if (res.code == 200) {
+        this.$message.success(this.$t('config.msg_saveSuccess'))
+        if (this.activeTab == 'pwd') {
+          this.pwd = {
+            orignPwd: '',
+            oldPwd: '',
+            newPwd: '',
+            quePwd: ''
+          }
+        }
+        this.getConfig()
+      } else {
+        this.$message.error(res.message)
+      }
+    },
+    // 鍙悎骞剁洰鏍囧璞′腑瀛樺湪鐨勫睘鎬�
+    mergeWithBase(target, source) {
+      if (!source || typeof source !== 'object') {
+        return { ...target };
+      }
+      const result = { ...target };
+      const targetKeys = Object.keys(target);
+      for (let i = 0; i < targetKeys.length; i++) {
+        const key = targetKeys[i];
+        if (Object.prototype.hasOwnProperty.call(source, key)) {
+          result[key] = source[key];
+        }
+      }
+      return result;
+    },
+    // 澶勭悊鑳屾櫙鍥剧墖閫夋嫨
+    async handleBackgroundSelect(file) {
+      if (file.type !== 'image/png') {
+        this.$message.error(this.$t('config.backgroundImageOnlyPNG'));
+        return false;
+      }
+      if (file.size > 5 * 1024 * 1024) {
+        this.$message.error(this.$t('config.backgroundSizeLimit'));
+        return false;
+      }
+      const targetResolution = this.getBackgroundResolutionByModel();
+      if (targetResolution) {
+        try {
+          const { width, height } = await this.getImageSize(file);
+          if (width !== targetResolution.width || height !== targetResolution.height) {
+            this.$message.error(this.$t('config.backgroundResolutionMismatch').replace('{n}', `${targetResolution.width}*${targetResolution.height}`));
+            return false;
+          }
+        } catch (error) {
+          this.$message.error(this.$t('config.backgroundParseFailed'));
+          return false;
+        }
+      }
+      try {
+        const base64 = await this.readFileAsBase64(file);
+        this.background = {
+          base64,
+          name: file.name
+        };
+        this.$message.success(this.$t('config.backgroundImageSelected'));
+      } catch (error) {
+        this.$message.error(this.$t('config.backgroundParseFailed'));
+      }
+      return false;
+    },
+    getBackgroundResolutionByModel() {
+      const resolutionMap = {
+        vf202: { width: 480, height: 854 },
+        vf105: { width: 800, height: 1280 },
+        vf107: { width: 800, height: 1280 },
+        vf205: { width: 800, height: 1280 },
+        vf114: { width: 720, height: 1280 },
+        vf124: { width: 720, height: 1280 },
+        vf203: { width: 600, height: 1024 }
+      };
+      return resolutionMap[this.model] || null;
+    },
+    getImageSize(file) {
+      return new Promise((resolve, reject) => {
+        const image = new Image();
+        const imageUrl = URL.createObjectURL(file);
+        image.onload = () => {
+          URL.revokeObjectURL(imageUrl);
+          resolve({ width: image.width, height: image.height });
+        };
+        image.onerror = () => {
+          URL.revokeObjectURL(imageUrl);
+          reject(new Error('image read failed'));
+        };
+        image.src = imageUrl;
+      });
+    },
+    // 璇诲彇鏂囦欢涓築ase64
+    readFileAsBase64(file) {
+      return new Promise((resolve, reject) => {
+        const reader = new FileReader();
+        reader.onload = () => {
+          const result = reader.result || '';
+          const base64 = typeof result === 'string' ? result.split(',').pop() : '';
+          if (!base64) {
+            reject(new Error('empty result'));
+            return;
+          }
+          resolve(base64);
+        };
+        reader.onerror = () => reject(new Error('read failed'));
+        reader.readAsDataURL(file);
+      });
+    },
+    // 涓婁紶鑳屾櫙鍥剧墖
+    async uploadBackground() {
+      if (!this.background.base64) {
+        this.$message.warning(this.$t('config.backgroundRequired'));
+        return;
+      }
+      this.loading.background = true;
+      try {
+        const res = await this.$http.post("/control", { data: { command: 13, extra: { wallpaperBase64: this.background.base64 } } });
+        if (res.code == 200) {
+          this.$message.success(this.$t('config.backgroundSuccess'));
+          this.background = {
+            base64: '',
+            name: ''
+          };
+        } else {
+          this.$message.error(res.message || this.$t('config.backgroundFailed'));
+        }
+      } catch (error) {
+        this.$message.error(this.$t('config.backgroundFailed'));
+      } finally {
+        this.loading.background = false;
+      }
+    },
+  }
+}
+</script>
+<style lang="less" scoped>
+.config-container {
+  padding: 20px;
+  background-color: #f5f7fa;
+  min-height: 100vh;
+  max-width: 100vw;
+  /* 闄愬埗鏈�澶у搴︿负瑙嗗彛瀹藉害 */
+  overflow-x: hidden;
+  /* 闅愯棌妯悜婧㈠嚭 */
+}
+.config-grid {
+  column-count: 2;
+  /* 涓ゅ垪 */
+  column-gap: 20px;
+  /* 鍒楅棿璺� */
+  margin-bottom: 80px;
+  box-sizing: border-box;
+  width: 100%;
+}
+.config-card {
+  break-inside: avoid;
+  /* 闃叉鍗$墖璺ㄥ垪鍒嗗壊 */
+  display: inline-block;
+  /* 鍏抽敭灞炴�� */
+  width: 100%;
+  /* 鍗犳弧鍒楀 */
+  margin-bottom: 20px;
+  /* 鍗$墖闂磋窛 */
+  border-radius: 12px;
+  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
+  background: white;
+  transition: transform 0.3s ease;
+  vertical-align: top;
+  /* 椤堕儴瀵归綈 */
+}
+.config-card:hover {
+  transform: translateY(-2px);
+  box-shadow: 0 6px 16px rgba(0, 0, 0, 0.12);
+}
+.config-card__header {
+  background: linear-gradient(90deg, #ecf5ff, #f0f9ff);
+  border-bottom: 1px solid #ebeef5;
+  padding: 16px 20px;
+  border-top-left-radius: 12px;
+  border-top-right-radius: 12px;
+  font-weight: 600;
+  color: #409EFF;
+  display: flex;
+  align-items: center;
+}
+.config-card__header-icon {
+  margin-right: 8px;
+  font-size: 18px;
+}
+.config-card__body {
+  padding: 20px;
+  display: flex;
+  flex-direction: column;
+}
+/* 纭繚鎵�鏈夊崱鐗囧唴瀹硅嚜鐒堕珮搴� */
+.card-content {
+  display: flex;
+  flex-direction: column;
+  height: auto !important;
+}
+.config-form-item {
+  display: flex;
+  align-items: center;
+  margin-bottom: 8px;
+  padding-bottom: 8px;
+  border-bottom: 1px dashed #ebeef5;
+}
+/* 纭繚el-form-item鐨刲abel瀵归綈 */
+.config-card__body ::v-deep .el-form-item {
+  display: flex;
+  align-items: center;
+  width: 100%;
+  margin-bottom: 0;
+}
+.config-card__body ::v-deep .el-form-item__label {
+  // width: 140px;
+  text-align: right;
+  padding-right: 15px;
+  color: #606266;
+  font-weight: 500;
+  flex-shrink: 0;
+}
+.config-card__body ::v-deep .el-form-item__content {
+  flex: 1;
+  margin-left: 0 !important;
+}
+/* 璇█閫夐」姣忚3涓竷灞� */
+.language-radio-group {
+  display: flex;
+  flex-wrap: wrap;
+  width: 100%;
+}
+.language-radio-group ::v-deep .el-radio {
+  width: calc(33.333% - 10px);
+  margin-right: 15px;
+  margin-left: 0;
+}
+.language-radio-group ::v-deep .el-radio:nth-child(3n) {
+  margin-right: 0;
+}
+.config-form-item:last-child {
+  border-bottom: none;
+  margin-bottom: 0;
+  padding-bottom: 0;
+}
+.config-form-control {
+  flex: 1;
+}
+.config-save-btn {
+  position: fixed;
+  bottom: 30px;
+  right: 30px;
+  z-index: 100;
+  box-shadow: 0 4px 12px rgba(32, 160, 255, 0.4);
+}
+.config-tabs {
+  background: transparent;
+}
+.config-tabs ::v-deep .el-tabs__header {
+  background: #fff;
+  border-radius: 8px;
+  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
+  margin-bottom: 20px;
+  border: none;
+}
+.config-tabs ::v-deep .el-tabs__item {
+  font-weight: 500;
+  height: 50px;
+  line-height: 50px;
+}
+.compact-controls {
+  display: flex;
+  align-items: center;
+  gap: 15px;
+  flex-wrap: wrap;
+}
+.value-display {
+  min-width: 40px;
+  text-align: center;
+  color: #409EFF;
+  font-weight: 500;
+}
+.divider {
+  height: 1px;
+  background: linear-gradient(90deg, transparent, #dcdfe6, transparent);
+  margin: 20px 0;
+}
+/* 鍝嶅簲寮忚璁� */
+@media (max-width: 1200px) {
+  .config-grid {
+    grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
+  }
+}
+@media (max-width: 768px) {
+  .config-container {
+    padding: 10px;
+  }
+  .config-grid {
+    grid-template-columns: 1fr;
+    gap: 15px;
+  }
+  .config-form-item {
+    flex-direction: column;
+    align-items: flex-start;
+    gap: 8px;
+  }
+  .config-form-control {
+    width: 100%;
+  }
+  .compact-controls {
+    width: 100%;
+    justify-content: space-between;
+  }
+  /* 灏忓睆骞曚笅璇█閫夐」姣忚2涓� */
+  .language-radio-group ::v-deep .el-radio {
+    width: calc(50% - 8px);
+  }
+  .language-radio-group ::v-deep .el-radio:nth-child(3n) {
+    margin-right: 15px;
+  }
+  .language-radio-group ::v-deep .el-radio:nth-child(2n) {
+    margin-right: 0;
+  }
+}
+@media (max-width: 480px) {
+  .config-card__body {
+    padding: 15px;
+  }
+  .config-form-item {
+    margin-bottom: 15px;
+    padding-bottom: 15px;
+  }
+  /* 瓒呭皬灞忓箷涓嬭瑷�閫夐」姣忚1涓� */
+  .language-radio-group ::v-deep .el-radio {
+    width: 100%;
+    margin-right: 0;
+  }
+  .language-radio-group ::v-deep .el-radio:nth-child(2n) {
+    margin-right: 0;
+  }
+}
+/* 鍗$墖棰滆壊涓婚 */
+.card-theme-display {
+  --card-header-bg: linear-gradient(90deg, #ecf5ff, #f0f9ff);
+  --card-header-color: #409EFF;
+}
+.card-theme-network {
+  --card-header-bg: linear-gradient(90deg, #f0f9eb, #f9fbe7);
+  --card-header-color: #67C23A;
+}
+.card-theme-audio {
+  --card-header-bg: linear-gradient(90deg, #fef0f0, #fef6f6);
+  --card-header-color: #F56C6C;
+}
+.card-theme-system {
+  --card-header-bg: linear-gradient(90deg, #f4f4f5, #f9f9fa);
+  --card-header-color: #909399;
+}
+.card-theme-security {
+  --card-header-bg: linear-gradient(90deg, #fdf6ec, #fefcef);
+  --card-header-color: #E6A23C;
+}
+.card-theme-display .config-card__header {
+  background: var(--card-header-bg);
+  color: var(--card-header-color);
+}
+.card-theme-network .config-card__header {
+  background: var(--card-header-bg);
+  color: var(--card-header-color);
+}
+.card-theme-audio .config-card__header {
+  background: var(--card-header-bg);
+  color: var(--card-header-color);
+}
+.card-theme-system .config-card__header {
+  background: var(--card-header-bg);
+  color: var(--card-header-color);
+}
+.card-theme-security .config-card__header {
+  background: var(--card-header-bg);
+  color: var(--card-header-color);
+}
+.card-zhanwei {
+  height: 0;
+  border: none;
+}
+/deep/.el-form-item__label {
+  text-align: center;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+}
+/deep/.el-form-item__content>.el-input {
+  width: 60%;
+}
+.password-strength-container {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  margin-top: 2px;
+  width: 400px;
+}
+.password-strength-bar {
+  width: 90%;
+  height: 6px;
+  background-color: #f0f0f0;
+  border-radius: 3px;
+  overflow: hidden;
+  margin-bottom: 4px;
+}
+.password-strength-progress {
+  height: 100%;
+  transition: all 0.3s ease;
+  width: 0%;
+}
+/* 淇閫夋嫨鍣� - 鐩存帴搴旂敤浜庤繘搴︽潯鍏冪礌 */
+.password-strength-progress.strength-weak {
+  width: 25%;
+  background-color: #ff4d4f;
+}
+.password-strength-progress.strength-medium {
+  width: 50%;
+  background-color: #faad14;
+}
+.password-strength-progress.strength-good {
+  width: 75%;
+  background-color: #1890ff;
+}
+.password-strength-progress.strength-strong {
+  width: 100%;
+  background-color: #52c41a;
+}
+.password-strength-text {
+  line-height: 20px;
+}
+/* 淇閫夋嫨鍣� - 鐩存帴搴旂敤浜庢枃鏈厓绱� */
+.password-strength-text.strength-weak {
+  color: #ff4d4f;
+}
+.password-strength-text.strength-medium {
+  color: #faad14;
+}
+.password-strength-text.strength-good {
+  color: #1890ff;
+}
+.password-strength-text.strength-strong {
+  color: #52c41a;
+}
+.password-weak-warning {
+  font-size: 12px;
+  color: #faad14;
+  margin-top: 4px;
+  display: flex;
+  align-items: center;
+}
+.password-weak-warning i {
+  margin-right: 4px;
+}
+.password-rules-tip {
+  margin-top: 20px;
+  padding: 12px 16px;
+  background: #f8f9fa;
+  border: 1px solid #e9ecef;
+  border-radius: 8px;
+  font-size: 12px;
+  line-height: 1.5;
+  color: #495057;
+}
+.rules-title {
+  font-weight: 600;
+  color: #343a40;
+  margin-bottom: 8px;
+  font-size: 13px;
+}
+.rules-list {
+  margin: 0;
+  padding-left: 16px;
+  list-style: none;
+}
+.rules-list li {
+  margin-bottom: 4px;
+  position: relative;
+}
+.rules-list li:before {
+  content: "路";
+  position: absolute;
+  left: -12px;
+  color: #6c757d;
+}
+.weak-passwords {
+  color: #dc3545;
+  font-style: italic;
+  margin-top: 4px;
+  line-height: 1.4;
+  background: rgba(220, 53, 69, 0.05);
+  padding: 6px 8px;
+  border-radius: 4px;
+  border-left: 3px solid #dc3545;
+}
+/* 浜戣瘉婵�娲婚〉闈㈡牱寮� */
+.cloud-card-header {
+  display: flex;
+  align-items: center;
+  position: relative;
+}
+.cloud-icon {
+  color: #409EFF;
+  font-size: 18px;
+}
+.cloud-status {
+  margin-left: auto;
+  padding: 4px 12px;
+  border-radius: 12px;
+  font-size: 12px;
+  font-weight: 500;
+}
+.cloud-status.active {
+  background: #f0f9ff;
+  color: #1890ff;
+  border: 1px solid #91d5ff;
+}
+.cloud-status.inactive {
+  background: #fff2f0;
+  color: #ff4d4f;
+  border: 1px solid #ffccc7;
+}
+.activation-container {
+  max-width: 600px;
+  margin: 0 auto;
+}
+.activation-form-item {
+  margin-bottom: 24px;
+}
+.activation-form-item .el-form-item__label {
+  font-weight: 600;
+  color: #303133;
+  font-size: 14px;
+  margin-bottom: 8px;
+  padding: 0;
+}
+.activation-input {
+  width: 100% !important;
+}
+/deep/.activation-input .el-textarea__inner {
+  height: 100px !important;
+  border-radius: 8px;
+  border: 2px solid #e6e8eb;
+  font-size: 14px;
+  transition: all 0.3s ease;
+  padding-left: 10px;
+}
+.activation-input .el-textarea__inner:focus {
+  border-color: #409EFF;
+  box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.1);
+}
+.activation-input .el-input__prefix {
+  display: flex;
+  align-items: center;
+  left: 12px;
+  color: #909399;
+}
+.activation-tips {
+  margin-top: 12px;
+  padding: 16px;
+  background: #f8f9fa;
+  border-radius: 8px;
+  border-left: 4px solid #409EFF;
+}
+.tip-item {
+  display: flex;
+  align-items: flex-start;
+  margin-bottom: 8px;
+  font-size: 13px;
+  color: #606266;
+  line-height: 1.4;
+}
+.tip-item:last-child {
+  margin-bottom: 0;
+}
+.tip-item i {
+  margin-right: 8px;
+  margin-top: 2px;
+  color: #409EFF;
+  font-size: 14px;
+}
+.activation-action-section {
+  text-align: center;
+  padding: 24px 0;
+  border-top: 1px solid #f0f0f0;
+  border-bottom: 1px solid #f0f0f0;
+  margin: 20px 0;
+}
+.background-upload-section {
+  padding: 20px 0;
+}
+.upload-area {
+  margin-bottom: 20px;
+}
+.background-upload {
+  display: inline-block;
+}
+.file-info {
+  margin-top: 12px;
+  padding: 8px 12px;
+  background: #f5f7fa;
+  border-radius: 6px;
+  display: flex;
+  align-items: center;
+  gap: 8px;
+  color: #606266;
+  font-size: 13px;
+}
+.file-info i {
+  color: #409EFF;
+}
+.upload-actions {
+  margin-bottom: 16px;
+}
+.upload-tips {
+  padding: 12px;
+  background: #f0f9ff;
+  border-radius: 6px;
+  border-left: 3px solid #409EFF;
+}
+.upload-tips p {
+  margin: 0;
+  color: #606266;
+  font-size: 13px;
+  line-height: 1.5;
+}
+.activation-btn {
+  height: 44px;
+  padding: 0 32px;
+  font-size: 14px;
+  font-weight: 600;
+  border-radius: 8px;
+  background: linear-gradient(135deg, #409EFF, #66b1ff);
+  border: none;
+  box-shadow: 0 2px 8px rgba(64, 158, 255, 0.3);
+  transition: all 0.3s ease;
+}
+.activation-btn:hover:not(.is-disabled) {
+  transform: translateY(-2px);
+  box-shadow: 0 4px 12px rgba(64, 158, 255, 0.4);
+}
+.activation-btn:active:not(.is-disabled) {
+  transform: translateY(0);
+}
+.action-helpers {
+  margin-top: 16px;
+  display: flex;
+  justify-content: center;
+  gap: 16px;
+}
+.helper-btn {
+  color: #606266;
+  font-size: 13px;
+  transition: color 0.3s ease;
+}
+.helper-btn:hover {
+  color: #409EFF;
+}
+.activation-result {
+  padding: 16px;
+  border-radius: 8px;
+  margin-top: 20px;
+  display: flex;
+  align-items: center;
+  flex-direction: column;
+  text-align: center;
+  animation: fadeIn 0.5s ease;
+}
+.activation-result.success {
+  background: #f6ffed;
+  border: 1px solid #b7eb8f;
+  color: #52c41a;
+}
+.activation-result.error {
+  background: #fff2f0;
+  border: 1px solid #ffccc7;
+  color: #ff4d4f;
+}
+.activation-result i {
+  font-size: 24px;
+  margin-bottom: 8px;
+}
+.result-details {
+  margin-top: 8px;
+  font-size: 12px;
+  color: #8c8c8c;
+  line-height: 1.4;
+}
+.timezone-selects {
+  display: flex;
+  gap: 12px;
+}
+.timezone-selects .el-select {
+  flex: 1;
+}
+@keyframes fadeIn {
+  from {
+    opacity: 0;
+    transform: translateY(-10px);
+  }
+  to {
+    opacity: 1;
+    transform: translateY(0);
+  }
+}
+/* 鍝嶅簲寮忚璁� */
+@media (max-width: 768px) {
+  .activation-container {
+    max-width: 100%;
+  }
+  .action-helpers {
+    flex-direction: column;
+    gap: 8px;
+  }
+  .activation-btn {
+    width: 100%;
+    max-width: 280px;
+  }
+}
+</style>
diff --git "a/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/views/control/index.vue" "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/views/control/index.vue"
new file mode 100644
index 0000000..254e439
--- /dev/null
+++ "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/views/control/index.vue"
@@ -0,0 +1,982 @@
+<template>
+  <div id="device-control-panel">
+    <!-- 鏍囩椤� -->
+    <el-tabs v-model="activeTab" type="border-card" class="main-tabs" @tab-click="handleClick">
+      <!-- 杩滅▼鎺у埗鏍囩 -->
+      <el-tab-pane :label="$t('control.remoteControl')" name="remote">
+        <div class="remote-control">
+          <el-row :gutter="20">
+            <!-- 閲嶅惎璁惧 -->
+            <el-col :span="8">
+              <div class="control-card restart-card" @click="handleRestart" :class="{ 'loading': loading.restart }">
+                <div class="card-content">
+                  <div class="card-icon">
+                    <i class="el-icon-refresh"></i>
+                  </div>
+                  <h3>{{ $t('control.restart') }}</h3>
+                  <p class="card-description">{{ $t('control.restartTips') }}</p>
+                  <div class="card-hover-effect">
+                    <span>{{ $t('control.clickToRestart') }}</span>
+                  </div>
+                  <div v-if="loading.restart" class="loading-overlay">
+                    <i class="fas fa-spinner"></i>
+                    <div class="loading-text">{{ $t('control.restarting') }}</div>
+                  </div>
+                </div>
+              </div>
+            </el-col>
+
+            <!-- 杩滅▼寮�闂� -->
+            <el-col :span="8">
+              <div class="control-card open-card" @click="handleRemoteOpen" :class="{ 'loading': loading.remoteOpen }">
+                <div class="card-content">
+                  <div class="card-icon">
+                    <i class="el-icon-unlock"></i>
+                  </div>
+                  <h3>{{ $t('control.remoteOpen') }}</h3>
+                  <p class="card-description">{{ $t('control.remoteTips') }}</p>
+                  <div class="card-hover-effect">
+                    <span>{{ $t('control.clickToOpen') }}</span>
+                  </div>
+                  <div v-if="loading.remoteOpen" class="loading-overlay">
+                    <i class="fas fa-spinner"></i>
+                    <div class="loading-text">{{ $t('control.opening') }}</div>
+                  </div>
+                </div>
+              </div>
+            </el-col>
+
+            <!-- 璁惧閲嶇疆 -->
+            <el-col :span="8">
+              <div class="control-card reset-card" @click="handleReset" :class="{ 'loading': loading.reset }">
+                <div class="card-content">
+                  <div class="card-icon">
+                    <i class="el-icon-delete"></i>
+                  </div>
+                  <h3>{{ $t('control.reset') }}</h3>
+                  <p class="card-description">{{ $t('control.resetTips') }}</p>
+                  <div class="card-hover-effect">
+                    <span>{{ $t('control.clickToReset') }}</span>
+                  </div>
+                  <div v-if="loading.reset" class="loading-overlay">
+                    <i class="fas fa-spinner"></i>
+                    <div class="loading-text">{{ $t('control.reseting') }}</div>
+                  </div>
+                </div>
+              </div>
+            </el-col>
+          </el-row>
+        </div>
+      </el-tab-pane>
+
+      <!-- 璁惧鍗囩骇鏍囩 -->
+      <el-tab-pane :label="$t('control.firmwareUpgrade')" name="upgrade">
+        <div class="firmware-upgrade">
+          <el-row :gutter="30">
+            <el-col :span="12">
+              <el-card class="upgrade-card" shadow="never">
+                <h3><i class="fas fa-cloud-download-alt"></i>{{ $t('control.urlUpgrade') }}</h3>
+                <el-form ref="upgradeForm" :model="upgradeForm" :rules="upgradeRules" label-position="top"
+                  class="upgrade-form">
+
+                  <el-form-item :label="$t('control.firmwareUrl')" prop="url">
+                    <el-input v-model="upgradeForm.url" placeholder="https://example.com/firmware.dpk" clearable>
+                      <i slot="prefix" class="el-input__icon el-icon-link"></i>
+                    </el-input>
+                  </el-form-item>
+
+                  <el-form-item :label="$t('control.md5Checksum')" prop="md5">
+                    <el-input v-model="upgradeForm.md5" :placeholder="$t('common.placeholder')" clearable>
+                      <i slot="prefix" class="el-input__icon el-icon-key"></i>
+                    </el-input>
+                  </el-form-item>
+
+                  <el-form-item>
+                    <el-button type="primary" @click="submitUpgrade" :loading="loading.upgrade" style="width: 100%">
+                      {{ $t('control.startUpgrade') }}
+                    </el-button>
+                  </el-form-item>
+                </el-form>
+              </el-card>
+            </el-col>
+            <el-col :span="12">
+              <el-card class="upgrade-card" shadow="never">
+                <h3><i class="fas fa-info-circle"></i> {{ $t('control.fileUpgrade') }}</h3>
+                <div class="upload-area" @click="triggerFileUpload">
+                  <div class="upload-icon">
+                    <i class="el-icon-upload"></i>
+                  </div>
+                  <div class="upload-text">{{ $t('control.uploadFile') }}</div>
+                  <div class="upload-hint">{{ $t('control.formatFile') }}</div>
+                  <input type="file" ref="fileInput" style="display: none" accept=".zip,.dpk"
+                    @change="handleFileUpload">
+                </div>
+                <el-form>
+                  <el-form-item :label="$t('control.md5Checksum')">
+                    <el-input v-model="fileMd5" :placeholder="$t('common.placeholder')" clearable>
+                      <i slot="prefix" class="el-input__icon el-icon-key"></i>
+                    </el-input>
+                  </el-form-item>
+                </el-form>
+                <div v-if="uploadedFile" class="file-info">
+                  <div class="file-info-item">
+                    <div class="file-label">{{ $t('control.fileName') }}:</div>
+                    <div class="file-value">{{ uploadedFile.name }}</div>
+                  </div>
+                  <div class="file-info-item">
+                    <div class="file-label">{{ $t('control.size') }}:</div>
+                    <div class="file-value">{{ formatFileSize(uploadedFile.size) }}</div>
+                  </div>
+                  <!-- <div class="file-info-item">
+                    <div class="file-label">绫诲瀷:</div>
+                    <div class="file-value">{{ uploadedFile.type || '鏈煡绫诲瀷' }}</div>
+                  </div>
+                  <div class="file-info-item">
+                    <div class="file-label">MD5:</div>
+                    <div class="file-value">{{ fileMd5 || '璁$畻涓�...' }}</div>
+                  </div>
+                  <div class="file-info-item">
+                    <div class="file-label">URL:</div>
+                    <div class="file-value">{{ fileUrl || '寰呯敓鎴�...' }}</div>
+                  </div> -->
+                </div>
+
+                <div v-if="uploadedFile" class="upload-actions">
+                  <el-button @click="clearUpload">{{ $t('control.clearFile') }}</el-button>
+                  <el-button type="primary" @click="submitFileUpgrade" :loading="loading.fileUpgrade">
+                    {{ loading.fileUpgrade ? $t('control.uploading') : $t('control.uploadAndUpgrade') }}
+                  </el-button>
+                </div>
+              </el-card>
+            </el-col>
+          </el-row>
+        </div>
+      </el-tab-pane>
+    </el-tabs>
+
+    <!-- 閲嶇疆纭瀵硅瘽妗� -->
+    <el-dialog :title="$t('control.resetConfirm')" :visible.sync="resetDialogVisible" width="30%"
+      :close-on-click-modal="false" custom-class="reset-dialog">
+
+      <div class="reset-warning">
+        <el-alert :title="$t('control.resetWarningTitle')" type="warning" :description="$t('control.resetWarningDesc')"
+          show-icon>
+        </el-alert>
+
+        <el-form ref="resetForm" :model="resetForm" :rules="resetRules" style="margin-top: 20px">
+          <el-form-item :label="$t('control.resetPassword')" prop="password">
+            <el-input v-model="resetForm.password" type="password" show-password
+              :placeholder="$t('control.passwordPlaceholder')">
+            </el-input>
+          </el-form-item>
+        </el-form>
+      </div>
+
+      <span slot="footer" class="dialog-footer">
+        <el-button @click="resetDialogVisible = false">{{ $t('basicSetting.cancelButton') }}</el-button>
+        <el-button type="danger" @click="confirmReset" :loading="loading.reset">{{ $t('control.confirmResetBtn')
+          }}</el-button>
+      </span>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { resetObjectValues, throttle } from '@/utils/index.js'
+export default {
+  name: 'Control',
+  data () {
+    return {
+      activeTab: 'remote',
+      // 琛ㄥ崟鏁版嵁
+      upgradeForm: {
+        type: 0,
+        url: '',
+        md5: ''
+      },
+
+      fileMd5: '',
+
+      resetForm: {
+        password: ''
+      },
+
+      // 瀵硅瘽妗嗙姸鎬�
+      resetDialogVisible: false,
+
+      // 鍔犺浇鐘舵��
+      loading: {
+        restart: false,
+        remoteOpen: false,
+        upgrade: false,
+        reset: false,
+        fileUpgrade: false,
+      },
+
+      // 琛ㄥ崟楠岃瘉瑙勫垯
+      upgradeRules: {
+        url: [
+          { required: true, message: this.$t('control.urlRequired'), trigger: 'blur' },
+          { type: 'url', message: this.$t('control.urlInvalid'), trigger: 'blur' }
+        ],
+        md5: [
+          { required: true, message: this.$t('control.md5Required'), trigger: 'blur' },
+          { pattern: /^[a-fA-F0-9]{32}$/, message: this.$t('control.md5Invalid'), trigger: 'blur' }
+        ],
+        password: [
+          { required: true, message: this.$t('control.passwordRequired'), trigger: 'blur' }
+        ]
+      },
+
+      resetRules: {
+        password: [
+          { required: true, message: this.$t('control.passwordRequired'), trigger: 'blur' }
+        ]
+      },
+
+      uploadedFile: ''
+    }
+  },
+
+  methods: {
+    // 澶勭悊閲嶅惎
+    handleRestart () {
+      this.$confirm(
+        this.$t('control.restartConfirm'),
+        this.$t('control.restart'),
+        {
+          confirmButtonText: this.$t('common.confirm'),
+          cancelButtonText: this.$t('common.cancel'),
+          type: 'warning'
+        }
+      ).then(async () => {
+        this.loading.restart = true;
+        const res = await this.$http.post("/control", { data: { command: 0 } });
+        if (res.code == 200) {
+          this.loading.restart = false;
+          this.$message.success(this.$t('control.restartSuccess'));
+        } else {
+          this.loading.restart = false;
+          this.$message.success(this.$t('control.restartFailed'));
+        }
+      }).catch(() => {
+        // 鍙栨秷鎿嶄綔
+        this.loading.restart = false;
+      });
+    },
+
+    // 澶勭悊杩滅▼寮�闂�
+    handleRemoteOpen () {
+      this.$confirm(
+        this.$t('control.openConfirm'),
+        this.$t('control.remoteOpen'),
+        {
+          confirmButtonText: this.$t('common.confirm'),
+          cancelButtonText: this.$t('common.cancel'),
+          type: 'warning'
+        }
+      ).then(async () => {
+        this.loading.remoteOpen = true;
+        const res = await this.$http.post("/control", { data: { command: 1 } });
+        if (res.code == 200) {
+          this.loading.remoteOpen = false;
+          this.$message.success(this.$t('control.remoteOpenSuccess'));
+        } else {
+          this.loading.remoteOpen = false;
+          this.$message.success(this.$t('control.remoteOpenFailed'));
+        }
+      }).catch(() => {
+        // 鍙栨秷鎿嶄綔
+        this.loading.remoteOpen = false
+      });
+    },
+
+    // 澶勭悊璁惧閲嶇疆
+    handleReset () {
+      let that = this
+      this.$confirm(
+        this.$t('control.resetConfirm') + this.$t('control.resetWillOut'),
+        this.$t('control.reset'),
+        {
+          confirmButtonText: this.$t('common.confirm'),
+          cancelButtonText: this.$t('common.cancel'),
+          type: 'warning'
+        }
+      ).then(async () => {
+        this.loading.reset = true;
+        const res = await this.$http.post("/control", { data: { command: 4 } });
+        if (res.code == 200) {
+          this.loading.reset = false;
+          this.$message.success(this.$t('control.resetSuccess'));
+          setTimeout(() => {
+            that.$router.push('/login')
+            sessionStorage.removeItem("token")
+            sessionStorage.removeItem("publicConfig")
+          }, 1000)
+        } else {
+          this.loading.reset = false;
+          this.$message.success(this.$t('control.resetFailed'));
+        }
+      }).catch(() => {
+        // 鍙栨秷鎿嶄綔
+        this.loading.reset = false;
+      });
+    },
+
+    handleClick () {
+      if (this.$refs.upgradeForm) {
+        this.$refs.upgradeForm.clearValidate();
+      }
+    },
+
+    // 鎻愪氦鍗囩骇
+    submitUpgrade: throttle(function () {
+      let that = this
+      this.$refs.upgradeForm.validate((valid) => {
+        if (valid) {
+          this.$confirm(
+            this.$t('control.upgradeConfirm'),
+            this.$t('control.firmwareUpgrade'),
+            {
+              confirmButtonText: this.$t('common.confirm'),
+              cancelButtonText: this.$t('common.cancel'),
+              type: 'primary'
+            }
+          ).then(async () => {
+            that.loading.upgrade = true;
+            const res = await that.$http.post("/upgradeFirmware", { data: that.upgradeForm });
+            if (res.code == 200) {
+              that.loading.upgrade = false;
+              that.$message.success(that.$t('control.upgradeSuccess'));
+              resetObjectValues(that.upgradeForm)
+            } else {
+              that.$message.error(res.message)
+            }
+          }).catch(() => {
+            // 鍙栨秷鎿嶄綔
+            that.loading.upgrade = false;
+          });
+        }
+      });
+    }, 2000),
+
+    confirmReset () { },
+
+    triggerFileUpload () {
+      this.$refs.fileInput.click();
+    },
+
+    handleFileUpload (event) {
+      const file = event.target.files[0];
+      if (!file) return;
+
+      // 妫�鏌ユ枃浠剁被鍨�
+      const validTypes = ['.zip', '.dpk'];
+      const fileExtension = '.' + file.name.split('.').pop().toLowerCase();
+
+      if (!validTypes.includes(fileExtension)) {
+        this.$message.error(this.$t('control.formatFile'));
+        return;
+      }
+
+      // 妫�鏌ユ枃浠跺ぇ灏� (500MB)
+      if (file.size > 20 * 1024 * 1024) {
+        this.$message.error(this.$t('control.formatFile'));
+        return;
+      }
+      this.uploadedFile = file;
+    },
+
+    formatFileSize (bytes) {
+      if (bytes === 0) return '0 Bytes';
+      const k = 1024;
+      const sizes = ['Bytes', 'KB', 'MB', 'GB'];
+      const i = Math.floor(Math.log(bytes) / Math.log(k));
+      return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
+    },
+
+    clearUpload () {
+      this.uploadedFile = null;
+      this.fileMd5 = '';
+      this.fileUrl = '';
+      this.$refs.fileInput.value = '';
+    },
+
+    async submitFileUpgrade () {
+      if (!this.uploadedFile) {
+        this.$message.warning('璇峰厛閫夋嫨瑕佷笂浼犵殑鏂囦欢');
+        return;
+      }
+      if (!this.fileMd5) {
+        this.$message.warning(this.$t('control.md5Required'));
+        return;
+      }
+      this.loading.fileUpgrade = true;
+      let formData = new FormData()
+      // 娣诲姞鏂囦欢
+      formData.append('file', this.uploadedFile)
+      formData.append('md5', this.fileMd5)
+      const res = await this.$http.post("/upload", formData);
+      if (res.code == 200) {
+        this.loading.fileUpgrade = false;
+        this.$message.success(this.$t('control.upgradeSuccess'));
+        this.uploadedFile = null
+        this.fileMd5 = ''
+      } else {
+        this.$message.error(res.message)
+        this.loading.fileUpgrade = false;
+      }
+
+    }
+  }
+}
+</script>
+
+<style scoped>
+#device-control-panel {
+  padding: 20px;
+  max-width: 100vw;
+}
+
+.device-status {
+  display: flex;
+  align-items: center;
+  background: rgba(16, 16, 48, 0.7);
+  padding: 10px 20px;
+  border-radius: 30px;
+  border: 1px solid rgba(24, 144, 255, 0.3);
+  box-shadow: 0 0 15px rgba(24, 144, 255, 0.2);
+}
+
+.status-indicator {
+  width: 12px;
+  height: 12px;
+  border-radius: 50%;
+  margin-right: 10px;
+  background: var(--themeColor);
+  box-shadow: 0 0 10px var(--themeColor);
+  animation: pulse 2s infinite;
+}
+
+@keyframes pulse {
+  0% {
+    box-shadow: 0 0 0 0 rgba(24, 144, 255, 0.7);
+  }
+
+  70% {
+    box-shadow: 0 0 0 10px rgba(64, 224, 208, 0);
+  }
+
+  100% {
+    box-shadow: 0 0 0 0 rgba(64, 224, 208, 0);
+  }
+}
+
+.main-tabs {
+  background: rgba(16, 16, 48, 0.7);
+  border-radius: 15px;
+  border: 1px solid rgba(24, 144, 255, 0.2);
+  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
+  overflow: hidden;
+}
+
+.main-tabs::before {
+  content: '';
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 4px;
+  background: linear-gradient(90deg, var(--themeColor), #ff8c00, #ff0080);
+}
+
+.el-tabs__header {
+  background: rgba(32, 32, 64, 0.5);
+  margin: 0;
+  border-bottom: 1px solid rgba(24, 144, 255, 0.2);
+}
+
+.el-tabs__item {
+  color: #a0a0ff;
+  font-weight: 500;
+  padding: 0 25px;
+  height: 50px;
+  line-height: 50px;
+}
+
+.el-tabs__item.is-active {
+  color: var(--themeColor);
+  background: rgba(24, 144, 255, 0.1);
+}
+
+.el-tabs__active-bar {
+  background-color: var(--themeColor);
+  height: 3px;
+  box-shadow: 0 0 10px var(--themeColor);
+}
+
+.el-tabs__content {
+  padding: 30px;
+}
+
+/* 杩滅▼鎺у埗鍗$墖鏍峰紡 */
+.remote-control {
+  padding: 10px 0;
+}
+
+.control-card {
+  height: 220px;
+  border-radius: 16px;
+  cursor: pointer;
+  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+  position: relative;
+  overflow: hidden;
+  box-shadow: 0 8px 25px rgba(0, 0, 0, 0.2);
+  border: 1px solid transparent;
+  background: rgba(32, 32, 64, 0.5);
+}
+
+.control-card::before {
+  content: '';
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 4px;
+  background: linear-gradient(90deg, var(--themeColor), #ff8c00, #ff0080);
+}
+
+.control-card:hover {
+  transform: translateY(-8px) scale(1.02);
+  box-shadow: 0 15px 35px rgba(0, 0, 0, 0.4);
+  border-color: rgba(24, 144, 255, 0.5);
+}
+
+.control-card:active {
+  transform: translateY(-2px) scale(0.98);
+}
+
+.control-card.loading {
+  cursor: not-allowed;
+  opacity: 0.7;
+}
+
+/* 鍗$墖鑳屾櫙娓愬彉 */
+.restart-card {
+  background: linear-gradient(135deg, rgba(255, 214, 102, 0.1) 0%, rgba(255, 169, 64, 0.1) 100%);
+}
+
+.open-card {
+  background: linear-gradient(135deg, rgba(149, 222, 100, 0.1) 0%, rgba(82, 196, 26, 0.1) 100%);
+}
+
+.reset-card {
+  background: linear-gradient(135deg, rgba(255, 156, 110, 0.1) 0%, rgba(255, 77, 79, 0.1) 100%);
+}
+
+.card-content {
+  height: 100%;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: center;
+  position: relative;
+  z-index: 2;
+  padding: 20px;
+}
+
+.card-icon {
+  width: 70px;
+  height: 70px;
+  border-radius: 50%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  margin-bottom: 20px;
+  background: rgba(255, 255, 255, 0.1);
+  backdrop-filter: blur(10px);
+  box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
+  border: 1px solid rgba(255, 255, 255, 0.2);
+}
+
+.restart-card .card-icon {
+  background: linear-gradient(135deg, rgba(255, 214, 102, 0.3) 0%, rgba(255, 169, 64, 0.3) 100%);
+  border-color: rgba(255, 214, 102, 0.5);
+}
+
+.open-card .card-icon {
+  background: linear-gradient(135deg, rgba(149, 222, 100, 0.3) 0%, rgba(82, 196, 26, 0.3) 100%);
+  border-color: rgba(149, 222, 100, 0.5);
+}
+
+.reset-card .card-icon {
+  background: linear-gradient(135deg, rgba(255, 156, 110, 0.3) 0%, rgba(255, 77, 79, 0.3) 100%);
+  border-color: rgba(255, 156, 110, 0.5);
+}
+
+.card-icon i {
+  font-size: 32px;
+  color: white;
+  text-shadow: 0 0 10px rgba(255, 255, 255, 0.5);
+}
+
+.control-card h3 {
+  color: white;
+  font-size: 20px;
+  font-weight: 600;
+  margin: 0 0 10px;
+  text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
+}
+
+.card-description {
+  color: rgba(255, 255, 255, 0.8);
+  font-size: 14px;
+  text-align: center;
+  line-height: 1.2;
+}
+
+.card-hover-effect {
+  position: absolute;
+  bottom: 5px;
+  opacity: 0;
+  transform: translateY(20px);
+  transition: all 0.3s ease;
+}
+
+.control-card:hover .card-hover-effect {
+  opacity: 1;
+  transform: translateY(0);
+}
+
+.card-hover-effect span {
+  color: rgba(255, 255, 255, 0.9);
+  font-size: 12px;
+  font-weight: 500;
+  background: rgba(0, 0, 0, 0.3);
+  padding: 6px 15px;
+  border-radius: 20px;
+  backdrop-filter: blur(10px);
+  border: 1px solid rgba(255, 255, 255, 0.2);
+}
+
+.loading-overlay {
+  position: absolute;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  background: rgba(0, 0, 0, 0.7);
+  backdrop-filter: blur(4px);
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  z-index: 3;
+  border-radius: 16px;
+}
+
+.loading-overlay i {
+  font-size: 40px;
+  color: var(--themeColor);
+  margin-bottom: 10px;
+  animation: spin 1s linear infinite;
+  text-shadow: 0 0 10px var(--themeColor);
+}
+
+.loading-text {
+  color: #a0a0ff;
+  font-size: 14px;
+}
+
+@keyframes spin {
+  0% {
+    transform: rotate(0deg);
+  }
+
+  100% {
+    transform: rotate(360deg);
+  }
+}
+
+/* 璁惧鍗囩骇鏍峰紡 */
+.firmware-upgrade {
+  padding: 10px 0;
+}
+
+.upgrade-card {
+  background: rgba(32, 32, 64, 0.5);
+  border-radius: 12px;
+  border: 1px solid rgba(24, 144, 255, 0.2);
+  box-shadow: 0 8px 25px rgba(0, 0, 0, 0.2);
+}
+
+/* .upgrade-card::before {
+  content: '';
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 4px;
+  background: linear-gradient(90deg, var(--themeColor), #ff8c00, #ff0080);
+  border-radius: 12px 12px 0 0;
+} */
+
+.upgrade-card h3 {
+  margin: 0 0 25px;
+  color: var(--themeColor);
+  font-weight: 500;
+  font-size: 16px;
+  display: flex;
+  align-items: center;
+}
+
+.upgrade-card h3 i {
+  margin-right: 10px;
+  font-size: 24px;
+}
+
+.upgrade-form {
+  margin-top: 10px;
+}
+
+.el-form-item__label {
+  color: #a0a0ff;
+  font-weight: 500;
+}
+
+.el-input__inner {
+  background: rgba(16, 16, 48, 0.7);
+  border: 1px solid rgba(24, 144, 255, 0.3);
+  color: #e0e0ff;
+  border-radius: 8px;
+}
+
+.el-input__inner:focus {
+  border-color: var(--themeColor);
+  box-shadow: 0 0 0 1px rgba(24, 144, 255, 0.2);
+}
+
+.el-input__prefix i {
+  color: var(--themeColor);
+}
+
+.el-button {
+  border-radius: 8px;
+  font-weight: 500;
+  transition: all 0.3s ease;
+}
+
+.el-button--primary {
+  background: var(--themeColor);
+  border: none;
+  box-shadow: 0 4px 15px rgba(24, 144, 255, 0.3);
+}
+
+.el-button--primary:hover {
+  transform: translateY(-2px);
+  box-shadow: 0 6px 20px rgba(24, 144, 255, 0.4);
+}
+
+/* 閲嶇疆瀵硅瘽妗嗘牱寮� */
+.reset-dialog .el-dialog {
+  background: rgba(16, 16, 48, 0.9);
+  border-radius: 15px;
+  border: 1px solid rgba(24, 144, 255, 0.3);
+  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.4);
+  backdrop-filter: blur(10px);
+}
+
+.reset-dialog .el-dialog__header {
+  background: rgba(32, 32, 64, 0.7);
+  border-bottom: 1px solid rgba(24, 144, 255, 0.2);
+  padding: 15px 20px;
+  border-radius: 15px 15px 0 0;
+}
+
+.reset-dialog .el-dialog__title {
+  color: #ff8c00;
+  font-weight: 600;
+}
+
+.reset-dialog .el-dialog__body {
+  padding: 20px;
+}
+
+.reset-warning {
+  margin-bottom: 20px;
+}
+
+.el-alert {
+  background: rgba(255, 154, 110, 0.1);
+  border: 1px solid rgba(255, 154, 110, 0.3);
+  color: #ff8c00;
+}
+
+.el-alert__title {
+  color: #ff8c00;
+  font-weight: 600;
+}
+
+.reset-dialog .el-dialog__footer {
+  background: rgba(32, 32, 64, 0.7);
+  border-top: 1px solid rgba(24, 144, 255, 0.2);
+  padding: 15px 20px;
+  border-radius: 0 0 15px 15px;
+}
+
+.el-button--danger {
+  background: linear-gradient(135deg, #ff6b6b, #ff4757);
+  border: none;
+  box-shadow: 0 4px 15px rgba(255, 107, 107, 0.3);
+}
+
+.el-button--danger:hover {
+  transform: translateY(-2px);
+  box-shadow: 0 6px 20px rgba(255, 107, 107, 0.4);
+}
+
+/* 鏂囦欢涓婁紶鏍峰紡 */
+.upload-card {
+  background: rgba(32, 32, 64, 0.5);
+  border-radius: 12px;
+  border: 1px solid rgba(64, 224, 208, 0.2);
+  box-shadow: 0 8px 25px rgba(0, 0, 0, 0.2);
+  padding: 25px;
+}
+
+.upload-card::before {
+  content: '';
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 4px;
+  background: linear-gradient(90deg, #ff8c00, #ff0080, var(--themeColor));
+  border-radius: 12px 12px 0 0;
+}
+
+.upload-area {
+  border: 2px dashed rgba(24, 144, 255, 0.4);
+  border-radius: 12px;
+  padding: 40px 20px;
+  text-align: center;
+  transition: all 0.3s ease;
+  background: rgba(16, 16, 48, 0.3);
+  cursor: pointer;
+}
+
+.upload-area:hover {
+  border-color: var(--themeColor);
+  background: rgba(16, 16, 48, 0.5);
+}
+
+.upload-icon {
+  font-size: 48px;
+  color: var(--themeColor);
+  margin-bottom: 15px;
+  text-shadow: 0 0 10px rgba(24, 144, 255, 0.5);
+}
+
+.upload-text {
+  color: #a0a0ff;
+  margin-bottom: 10px;
+}
+
+.upload-hint {
+  color: #8080cc;
+  font-size: 12px;
+  margin-top: 10px;
+}
+
+.file-info {
+  margin-top: 20px;
+  padding: 15px;
+  background: rgba(16, 16, 48, 0.7);
+  border-radius: 8px;
+  border: 1px solid rgba(64, 224, 208, 0.2);
+}
+
+.file-info-item {
+  display: flex;
+  margin-bottom: 8px;
+  font-size: 14px;
+}
+
+.file-info-item:last-child {
+  margin-bottom: 0;
+}
+
+.file-label {
+  color: #a0a0ff;
+  width: 80px;
+  flex-shrink: 0;
+}
+
+.file-value {
+  color: #e0e0ff;
+  word-break: break-all;
+}
+
+.upload-actions {
+  margin-top: 20px;
+  display: flex;
+  gap: 10px;
+}
+
+.upload-actions .el-button {
+  flex: 1;
+}
+
+/* 鍝嶅簲寮忚璁� */
+@media (max-width: 768px) {
+  #device-control-panel {
+    padding: 15px;
+  }
+
+  .el-tabs__content {
+    padding: 20px 15px;
+  }
+
+  .control-card {
+    height: 180px;
+    margin-bottom: 20px;
+  }
+
+  .card-icon {
+    width: 60px;
+    height: 60px;
+  }
+
+  .card-icon i {
+    font-size: 28px;
+  }
+
+  .control-card h3 {
+    font-size: 18px;
+  }
+}
+
+@media (max-width: 480px) {
+  .control-card {
+    height: 160px;
+  }
+
+  .card-icon {
+    width: 50px;
+    height: 50px;
+    margin-bottom: 15px;
+  }
+
+  .card-icon i {
+    font-size: 24px;
+  }
+
+  .control-card h3 {
+    font-size: 16px;
+  }
+
+  .card-description {
+    font-size: 12px;
+  }
+}
+</style>
\ No newline at end of file
diff --git "a/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/views/home/index.vue" "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/views/home/index.vue"
new file mode 100644
index 0000000..3153efc
--- /dev/null
+++ "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/views/home/index.vue"
@@ -0,0 +1,535 @@
+<template>
+  <div class="index">
+    <el-container direction="vertical">
+      <!-- 宸︿晶瀵艰埅鏍� -->
+      <el-aside class="modern-sidebar asideL">
+        <div class="sidebar-header">
+          <div class="system-logo">
+            <i class="el-icon-monitor"></i>
+            <span class="system-name">{{ $t('aside.systemname') }}</span>
+          </div>
+        </div>
+
+        <el-menu v-if="num == 1" router unique-opened :default-active="activeIndex" class="modern-menu">
+          <el-menu-item class="modern-menu-item" :index="item.path" v-for="item in filteredMenu" :key="item.name"
+            @click="changeItem(item)">
+            <i :class="getMenuIcon(item.path)" class="menu-icon"></i>
+            <span class="menu-title">{{ item.name }}</span>
+            <div class="menu-indicator"></div>
+          </el-menu-item>
+        </el-menu>
+
+        <el-menu v-if="num == 2" router unique-opened :default-active="activeIndex2" class="modern-menu">
+          <el-menu-item class="modern-menu-item" :index="item.path" v-for="item in personMenuList" :key="item.name"
+            @click="changeItem(item)">
+            <i :class="getMenuIcon(item.path)" class="menu-icon"></i>
+            <span class="menu-title">{{ item.name }}</span>
+            <div class="menu-indicator"></div>
+          </el-menu-item>
+        </el-menu>
+      </el-aside>
+
+      <el-container class="asideR">
+        <!-- 澶撮儴瀵艰埅鏍� -->
+        <el-header class="modern-header rightTop">
+          <div class="header-left">
+            <div class="page-title">
+              <span>{{ getCurrentPageTitle() }}</span>
+            </div>
+          </div>
+
+          <div class="header-right">
+            <!-- <div class="lang-box">
+              <el-select v-model="language" size="mini" @change="changeLang">
+                <el-option :label="$t('common.chinese')" value="zh"></el-option>
+                <el-option :label="$t('common.english')" value="en"></el-option>
+                <el-option :label="$t('common.spanish')" value="es"></el-option>
+                <el-option :label="$t('common.french')" value="fr"></el-option>
+                <el-option :label="$t('common.german')" value="de"></el-option>
+                <el-option :label="$t('common.russian')" value="ru"></el-option>
+                <el-option :label="$t('common.arabic')" value="ar"></el-option>
+                <el-option :label="$t('common.portuguese')" value="pt"></el-option>
+                <el-option :label="$t('common.korean')" value="ko"></el-option>
+              </el-select>
+            </div> -->
+            <div class="header-actions">
+              <el-button class="logout-btn" type="text" @click="logout">
+                <i class="el-icon-switch-button"></i>
+                {{ $t('aside.quit') }}
+              </el-button>
+            </div>
+          </div>
+        </el-header>
+
+        <!-- 涓讳綋閮ㄥ垎 -->
+        <el-main class="modern-main pagemain">
+          <router-view></router-view>
+        </el-main>
+      </el-container>
+    </el-container>
+  </div>
+</template>
+<script>
+export default {
+  name: "Home",
+  computed: {
+    // 璁$畻灞炴�ц繃婊よ彍鍗�
+    filteredMenu() {
+      let publicConfig = sessionStorage.getItem('publicConfig')
+      let { model } = publicConfig ? JSON.parse(publicConfig) : {}
+      return this.systemMenuList.filter(item => {
+        // 妫�鏌ュ瀷鍙�
+        if (item.allowedModels && !item.allowedModels.includes(model)) {
+          return false
+        }
+        return true
+      })
+    }
+  },
+  data () {
+    return {
+      num: '',
+      systemMenuList: [
+        // {
+        //   path: "/monitor",
+        //   name: this.$t('aside.deviceMonitoring')
+        // },
+        {
+          path: "/config",
+          name: this.$t('aside.basicSetting')
+        },
+        {
+          path: "/control",
+          name: this.$t('aside.deviceControl')
+        },
+        {
+          path: "/person",
+          name: this.$t('aside.workerSetting')
+        },
+        {
+          path: "/record",
+          name: this.$t('aside.recordManagement')
+        },
+        {
+          path: "/security",
+          name: this.$t('aside.securityManagement'),
+          allowedModels: ['vf105', 'vf114']
+        }
+      ],
+      activeIndex: "/",
+      activeIndex2: "/",
+      indexx: '/',
+      language: "zh"
+    };
+  },
+  // 妫�娴嬭矾鐢卞彉鍖�
+  watch: {
+    $route () {
+      this.setCurrentRoute();
+    },
+  },
+  created () {
+    this.setCurrentRoute();
+    this.num = 1
+  },
+  mounted () {
+    document.getElementsByTagName('body')[0].style.setProperty('--themeColor', "#1890ff");
+  },
+  methods: {
+    // 鑾峰彇鑿滃崟鍥炬爣
+    getMenuIcon (path) {
+      const iconMap = {
+        // '/monitor': 'el-icon-video-camera',
+        '/config': 'el-icon-setting',
+        '/person': 'el-icon-user-solid',
+        '/control': 'el-icon-key',
+        '/record': 'el-icon-tickets',
+        '/security': 'el-icon-connection'
+      }
+      return iconMap[path] || 'el-icon-menu'
+    },
+
+    // 鑾峰彇褰撳墠椤甸潰鏍囬
+    getCurrentPageTitle () {
+      const titleMap = {
+        // '/monitor': this.$t('aside.deviceMonitoring'),
+        '/config': this.$t('aside.basicSetting'),
+        '/person': this.$t('aside.workerSetting'),
+        '/control': this.$t('aside.deviceControl'),
+        '/record': this.$t('aside.recordManagement'),
+        '/security': this.$t('aside.securityManagement'),
+      }
+      return titleMap[this.$route.path] || this.$t('aside.basicSetting')
+    },
+
+    changeItem (item) {
+      this.indexx = item.path
+      this.activeIndex = item.path
+      console.log(this.indexx);
+    },
+
+    setCurrentRoute () {
+      this.activeIndex = this.$route.path; // 閫氳繃浠栧氨鍙互鐩戝惉鍒板綋鍓嶈矾鐢辩姸鎬佸苟婵�娲诲綋鍓嶈彍鍗�
+      this.activeIndex2 = this.$route.path;
+      this.indexx = this.$route.path;
+    },
+
+    // 閫�鍑虹櫥褰�
+    logout () {
+      const that = this
+      that.$confirm(this.$t('aside.tips_msg'), this.$t('aside.tips'), {
+        type: "warning"
+      }).then(async () => {
+        that.toDoLogout()
+      }).catch(() => {
+        return false
+      })
+    },
+
+    toDoLogout () {
+      this.$router.push('/login')
+      sessionStorage.removeItem("token")
+      sessionStorage.removeItem("publicConfig")
+    },
+
+    changeLang () {
+      this.$i18n.locale = this.language
+      sessionStorage.setItem('language', this.language)
+      this.systemMenuList = [
+        // {
+        //   path: "/monitor",
+        //   name: this.$t('aside.deviceMonitoring')
+        // },
+        {
+          path: "/config",
+          name: this.$t('aside.basicSetting')
+        },
+        {
+          path: "/control",
+          name: this.$t('aside.deviceControl')
+        },
+        {
+          path: "/person",
+          name: this.$t('aside.workerSetting')
+        },
+        {
+          path: "/record",
+          name: this.$t('aside.recordManagement')
+        },
+        {
+          path: "/security",
+          name: this.$t('aside.securityManagement'),
+          allowedModels: ['vf105', 'vf114']
+        }
+      ]
+    }
+  },
+};
+</script>
+<style lang="less" scoped>
+@import '../../assets/styles/theme.css';
+
+html,
+#app,
+body {
+  height: 100%;
+}
+
+.index {
+  height: 100vh;
+  background: var(--bg-secondary);
+}
+
+.el-container {
+  height: 100%;
+}
+
+/* 渚ц竟鏍忔牱寮� */
+.asideL {
+  width: 260px !important;
+  height: 100%;
+  position: fixed;
+  left: 0;
+  background: linear-gradient(180deg, var(--bg-sidebar) 0%, #0c1426 100%);
+  box-shadow: var(--shadow-lg);
+  z-index: 1000;
+  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+}
+
+.sidebar-header {
+  padding: var(--spacing-lg);
+  border-bottom: 1px solid rgba(255, 255, 255, 0.1);
+  margin-bottom: var(--spacing-md);
+}
+
+.system-logo {
+  display: flex;
+  align-items: center;
+  gap: var(--spacing-md);
+  color: var(--text-white);
+  font-size: 18px;
+  font-weight: 600;
+
+  i {
+    font-size: 24px;
+    color: var(--primary-color);
+  }
+}
+
+.system-name {
+  font-size: 16px;
+  letter-spacing: 0.5px;
+}
+
+/* 鑿滃崟鏍峰紡 */
+.modern-menu {
+  background: transparent !important;
+  border: none !important;
+  padding: 0 var(--spacing-md);
+}
+
+.modern-menu-item {
+  height: 48px !important;
+  line-height: 48px !important;
+  margin-bottom: var(--spacing-xs) !important;
+  border-radius: var(--radius-md) !important;
+  color: rgba(255, 255, 255, 0.7) !important;
+  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important;
+  position: relative !important;
+  overflow: hidden !important;
+
+  &:hover {
+    color: var(--text-white) !important;
+    background: rgba(255, 255, 255, 0.1) !important;
+    transform: translateX(4px);
+  }
+
+  &.is-active {
+    color: var(--text-white) !important;
+    background: var(--primary-color) !important;
+    box-shadow: var(--shadow-md);
+
+    .menu-indicator {
+      opacity: 1;
+      transform: scaleY(1);
+    }
+  }
+}
+
+.menu-icon {
+  font-size: 18px;
+  margin-right: var(--spacing-md);
+  width: 20px;
+  text-align: center;
+}
+
+.menu-title {
+  font-size: 14px;
+  font-weight: 500;
+  flex: 1;
+}
+
+.menu-indicator {
+  position: absolute;
+  right: 0;
+  top: 50%;
+  transform: translate(0, -50%) !important;
+  width: 3px;
+  height: 20px;
+  background: var(--text-white);
+  border-radius: 2px;
+  opacity: 0;
+  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+}
+
+/* 涓诲唴瀹瑰尯鍩� */
+.asideR {
+  margin-left: 260px;
+  height: 100%;
+  display: flex;
+  flex-direction: column;
+}
+
+/* 澶撮儴鏍峰紡 */
+.rightTop {
+  height: 64px !important;
+  padding: 0 var(--spacing-lg);
+  background: var(--bg-header);
+  border-bottom: 1px solid var(--border-light);
+  box-shadow: var(--shadow-sm);
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  z-index: 999;
+}
+
+.header-left {
+  flex: 1;
+}
+
+.page-title {
+  font-size: 20px;
+  font-weight: 600;
+  color: var(--text-primary);
+  display: flex;
+  align-items: center;
+  gap: var(--spacing-sm);
+
+  &::before {
+    content: '';
+    width: 4px;
+    height: 20px;
+    background: var(--primary-color);
+    border-radius: 2px;
+  }
+}
+
+.header-right {
+  display: flex;
+  align-items: center;
+}
+
+.header-actions {
+  display: flex;
+  align-items: center;
+  gap: var(--spacing-lg);
+}
+
+.lang-selector {
+  display: flex;
+  align-items: center;
+  gap: var(--spacing-sm);
+  padding: var(--spacing-sm) var(--spacing-md);
+  border-radius: var(--radius-md);
+  color: var(--text-secondary);
+  cursor: pointer;
+  transition: all 0.3s ease;
+
+  &:hover {
+    background: var(--bg-tertiary);
+    color: var(--text-primary);
+  }
+}
+
+.user-info {
+  display: flex;
+  align-items: center;
+  gap: var(--spacing-sm);
+  padding: var(--spacing-sm) var(--spacing-md);
+  border-radius: var(--radius-md);
+  cursor: pointer;
+  transition: all 0.3s ease;
+
+  &:hover {
+    background: var(--bg-tertiary);
+  }
+}
+
+.user-avatar {
+  border: 2px solid var(--border-light);
+}
+
+.user-name {
+  font-size: 14px;
+  color: var(--text-primary);
+  font-weight: 500;
+}
+
+.logout-btn {
+  color: var(--error-color) !important;
+  font-weight: 500;
+  padding: var(--spacing-sm) var(--spacing-md) !important;
+  border-radius: var(--radius-md) !important;
+  transition: all 0.3s ease !important;
+
+  &:hover {
+    background: rgba(255, 77, 79, 0.1) !important;
+    color: var(--error-color) !important;
+  }
+}
+
+/* 涓诲唴瀹瑰尯鍩� */
+.modern-main {
+  flex: 1;
+  padding: var(--spacing-xs) !important;
+  background: var(--bg-secondary);
+  overflow: auto;
+}
+
+.pagemain {
+  height: calc(100vh - 64px) !important;
+}
+
+/* 鍝嶅簲寮忚璁� */
+@media (max-width: 768px) {
+  .asideL {
+    width: 240px !important;
+    transform: translateX(-100%);
+
+    &.mobile-open {
+      transform: translateX(0);
+    }
+  }
+
+  .asideR {
+    margin-left: 0;
+  }
+
+  .header-actions {
+    gap: var(--spacing-md);
+  }
+
+  .user-name {
+    display: none;
+  }
+}
+
+/* 鍔ㄧ敾鏁堟灉 */
+.fade-in-up {
+  animation: fadeInUp 0.6s cubic-bezier(0.4, 0, 0.2, 1);
+}
+
+@keyframes fadeInUp {
+  from {
+    opacity: 0;
+    transform: translateY(30px);
+  }
+
+  to {
+    opacity: 1;
+    transform: translateY(0);
+  }
+}
+
+/* Element UI 缁勪欢鏍峰紡瑕嗙洊 */
+/deep/ .el-menu {
+  border-right: none !important;
+}
+
+/deep/ .el-menu-item {
+  border-left: none !important;
+}
+
+/deep/ .el-dropdown-menu {
+  border-radius: var(--radius-md);
+  box-shadow: var(--shadow-lg);
+  border: 1px solid var(--border-light);
+}
+
+/deep/ .el-dropdown-menu__item {
+  padding: var(--spacing-sm) var(--spacing-md);
+  transition: all 0.3s ease;
+
+  &:hover {
+    background: var(--bg-tertiary);
+    color: var(--primary-color);
+  }
+}
+
+/deep/ .el-tooltip__popper {
+  background: var(--bg-dark);
+  color: var(--text-white);
+  border-radius: var(--radius-md);
+  box-shadow: var(--shadow-lg);
+}
+</style>
\ No newline at end of file
diff --git "a/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/views/login/index.vue" "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/views/login/index.vue"
new file mode 100644
index 0000000..6a76c9e
--- /dev/null
+++ "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/views/login/index.vue"
@@ -0,0 +1,348 @@
+<template>
+  <div id="login">
+    <!-- 瑁呴グ鍏冪礌 -->
+    <div class="decoration decoration-1"></div>
+    <div class="decoration decoration-2"></div>
+    <!-- <div class="lang-box">{{ $t('login.lang') }}
+      <el-select v-model="language" size="mini" @change="changeLang">
+        <el-option :label="$t('common.chinese')" value="zh"></el-option>
+        <el-option :label="$t('common.english')" value="en"></el-option>
+        <el-option :label="$t('common.spanish')" value="es"></el-option>
+        <el-option :label="$t('common.french')" value="fr"></el-option>
+        <el-option :label="$t('common.german')" value="de"></el-option>
+        <el-option :label="$t('common.russian')" value="ru"></el-option>
+        <el-option :label="$t('common.arabic')" value="ar"></el-option>
+        <el-option :label="$t('common.portuguese')" value="pt"></el-option>
+        <el-option :label="$t('common.korean')" value="ko"></el-option>
+      </el-select>
+    </div> -->
+    <div class="loginMain">
+      <div class="loginForm">
+        <div class="formTop">{{ $t('login.systemname') }}</div>
+        <div class="formMain">
+          <el-form :model="loginForm" status-icon :rules="rulesForm" ref="loginForm">
+            <!-- 瀵嗙爜  -->
+            <el-form-item prop="userPassword" :label="$t('login.pwd')" :label-width="language == 'zh' ? '40px' : '70px'">
+              <el-input type="password" v-model="loginForm.userPassword" :placeholder="$t('login.pwd_label')"
+                prefix-icon="iconfont icon-mima"></el-input>
+            </el-form-item>
+
+            <el-form-item>
+              <el-button type="primary" @click="submitForm" class="loginFormBut">
+                {{ $t('login.login') }}
+              </el-button>
+            </el-form-item>
+          </el-form>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+<script>
+export default {
+  data () {
+    // 瀵嗙爜
+    var userPassword = (rule, value, callback) => {
+      if (value === "") {
+        callback(new Error(this.$t('login.pwd_label')));
+      } else {
+        callback();
+      }
+    };
+    return {
+      language: 'zh',
+      loginForm: {
+        userPassword: "",
+      },
+      // input楠岃瘉
+      rulesForm: {
+        userPassword: [{ validator: userPassword, trigger: "blur" }],
+      },
+    };
+  },
+  created () {
+    this.getPublicConfig()
+  },
+  mounted () {
+    window.addEventListener('keydown', this.keyDown, false);
+  },
+  methods: {
+    async getPublicConfig() {
+      try {
+        const res = await this.$http.post('/getPublicConfig', {})
+        if (res.code == 200) {
+          sessionStorage.setItem("publicConfig", JSON.stringify(res.data))
+          let { language} = res.data
+          this.language = language
+          this.$i18n.locale = language
+        } else {
+          this.$message.error(res.message)
+        }
+      } catch (even) {
+        console.log(even)
+      }
+    },
+
+
+    keyDown (e) {
+      //濡傛灉鏄洖杞﹀垯鎵ц鐧诲綍鏂规硶
+      if (e.keyCode == 13) {
+        e.preventDefault()
+        this.submitForm();
+      }
+    },
+
+    submitForm () {
+      this.$refs.loginForm.validate(async (valid) => {
+        if (valid) {
+          const res = await this.$http.post("/login", this.loginForm);
+          if (res.code == 200) {
+            this.$message({
+              message: this.$t('login.success_msg'),
+              type: 'success'
+            });
+            this.$router.push({ path: "/config" }),
+            sessionStorage.setItem("token", res.data.accessToken)
+          } else {
+            this.$message.error(this.$t('login.error_name'));
+            return false
+          }
+        } else {
+          this.$message.error(this.$t('login.error_res'));
+          return false
+        }
+      });
+    }
+
+  },
+  destroyed () {
+    window.removeEventListener('keydown', this.keyDown, false);
+  }
+};
+</script>
+<style lang="less" scoped>
+#login {
+  width: 100%;
+  height: 100%;
+  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+  background-image: url(../../assets/bg.png);
+  background-repeat: no-repeat;
+  background-size: cover;
+  background-position: center;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  position: relative;
+  font-family: 'Helvetica Neue', Arial, sans-serif;
+
+  .lang-box {
+    position: absolute;
+    top: 30px;
+    right: 30px;
+    font-size: 14px;
+    color: white;
+    z-index: 10;
+    display: flex;
+    align-items: center;
+    gap: 8px;
+  }
+
+  .loginMain {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    z-index: 2;
+    width: 100%;
+
+    .loginForm {
+      width: 430px;
+      background-color: rgba(255, 255, 255, 0.95);
+      border-radius: 16px;
+      box-shadow: 0 15px 35px rgba(0, 0, 0, 0.2);
+      overflow: hidden;
+      backdrop-filter: blur(10px);
+      border: 1px solid rgba(255, 255, 255, 0.2);
+      animation: fadeIn 0.8s ease-out;
+
+      .formTop {
+        width: 100%;
+        font-size: 32px;
+        font-weight: 700;
+        text-align: center;
+        padding: 40px 0 30px;
+        color: #333;
+        background: linear-gradient(to right, #667eea, #764ba2);
+        letter-spacing: 1px;
+      }
+
+      .formMain {
+        width: 80%;
+        margin: 0 auto;
+        padding-bottom: 40px;
+
+        .el-form {
+          margin-top: 20px;
+
+          .el-form-item {
+            margin-bottom: 28px;
+
+            .el-form-item__label {
+              font-weight: 600;
+              color: #555;
+              font-size: 14px;
+              padding-bottom: 8px;
+              display: block;
+            }
+
+            .el-input {
+              width: 100%;
+            }
+
+            .el-input__inner {
+              height: 50px;
+              border-radius: 10px;
+              border: 2px solid #e1e5e9;
+              font-size: 16px;
+              padding-left: 45px;
+              transition: all 0.3s ease;
+              background-color: #f8f9fa;
+            }
+
+            .el-input__inner:focus {
+              border-color: #667eea;
+              box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
+              background-color: white;
+            }
+
+            .el-input__prefix {
+              left: 15px;
+              display: flex;
+              align-items: center;
+            }
+
+            .iconfont {
+              font-size: 20px;
+              color: #7b8a9b;
+            }
+
+            .el-input__inner:focus+.el-input__prefix .iconfont {
+              color: #667eea;
+            }
+
+            .loginFormBut {
+              width: 100%;
+              height: 50px;
+              border-radius: 10px;
+              font-size: 16px;
+              font-weight: 600;
+              background: linear-gradient(to right, #667eea, #764ba2);
+              color: white;
+              border: none;
+              transition: all 0.3s ease;
+              margin-top: 10px;
+              letter-spacing: 1px;
+            }
+
+            .loginFormBut:hover {
+              transform: translateY(-2px);
+              box-shadow: 0 7px 14px rgba(102, 126, 234, 0.3);
+            }
+
+            .loginFormBut:active {
+              transform: translateY(0);
+            }
+          }
+        }
+      }
+    }
+
+    @keyframes fadeIn {
+      from {
+        opacity: 0;
+        transform: translateY(20px);
+      }
+
+      to {
+        opacity: 1;
+        transform: translateY(0);
+      }
+    }
+  }
+}
+
+#login::before {
+  content: '';
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  background: rgba(0, 0, 0, 0.4);
+  z-index: 1;
+}
+
+/* 鍝嶅簲寮忚璁� */
+@media (max-width: 768px) {
+  .loginForm {
+    width: 90%;
+    max-width: 400px;
+  }
+
+  .formTop {
+    font-size: 28px;
+    padding: 30px 0 20px;
+  }
+
+  .formMain {
+    width: 85%;
+  }
+
+  .el-input__inner {
+    height: 46px;
+    font-size: 15px;
+  }
+
+  .loginFormBut {
+    height: 46px;
+  }
+}
+
+@media (max-width: 480px) {
+  .loginForm {
+    width: 95%;
+  }
+
+  .formMain {
+    width: 90%;
+  }
+
+  .lang-box {
+    top: 20px;
+    right: 20px;
+  }
+}
+
+/* 娣诲姞涓�浜涜楗板厓绱� */
+.decoration {
+  position: absolute;
+  z-index: 1;
+}
+
+.decoration-1 {
+  top: 10%;
+  left: 10%;
+  width: 80px;
+  height: 80px;
+  border-radius: 50%;
+  background: rgba(255, 255, 255, 0.1);
+}
+
+.decoration-2 {
+  bottom: 15%;
+  right: 12%;
+  width: 120px;
+  height: 120px;
+  border-radius: 50%;
+  background: rgba(255, 255, 255, 0.05);
+}
+</style>
\ No newline at end of file
diff --git "a/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/views/monitor/index.vue" "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/views/monitor/index.vue"
new file mode 100644
index 0000000..e710728
--- /dev/null
+++ "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/views/monitor/index.vue"
@@ -0,0 +1,715 @@
+<template>
+  <div class="container">
+    <div class="dashboard">
+      <div class="card">
+        <div class="card-header">
+          <h2 class="card-title">璁惧姒傝</h2>
+          <i class="fas fa-microchip card-icon"></i>
+        </div>
+        <div class="stats-grid">
+          <div class="stat-item">
+            <div class="stat-label">璁惧鐘舵��</div>
+            <div class="stat-value">{{ deviceStatus.online ? '鍦ㄧ嚎' : '绂荤嚎' }}</div>
+            <div class="stat-label">{{ deviceStatus.online ? '杩愯姝e父' : '璁惧寮傚父' }}</div>
+          </div>
+          <div class="stat-item">
+            <div class="stat-label">娉ㄥ唽浜烘暟</div>
+            <div class="stat-value">{{ deviceStats.recognitions }}</div>
+            <div class="stat-label">浜烘</div>
+          </div>
+          <div class="stat-item">
+            <div class="stat-label">鐧藉悕鍗曟暟</div>
+            <div class="stat-value">{{ whitelist.face }} / {{ whitelist.password }} / {{ whitelist.card }}</div>
+            <div class="stat-label">浜鸿劯/瀵嗙爜/鍗$墖</div>
+          </div>
+          <div class="stat-item">
+            <div class="stat-label">閫氳璁板綍鎬绘暟</div>
+            <div class="stat-value">{{ systemStatus.memory }}</div>
+            <div class="stat-label">鏉℃暟</div>
+          </div>
+        </div>
+      </div>
+
+      <div class="card">
+        <div class="card-header">
+          <h2 class="card-title">CPU浣跨敤鐜�</h2>
+          <i class="fas fa-tachometer-alt card-icon"></i>
+        </div>
+        <div class="chart-container" id="cpuChart"></div>
+      </div>
+
+      <div class="card">
+        <div class="card-header">
+          <h2 class="card-title">鍐呭瓨浣跨敤鐜�</h2>
+          <i class="fas fa-memory card-icon"></i>
+        </div>
+        <div class="chart-container" id="memoryChart"></div>
+      </div>
+    </div>
+
+    <div class="main-content">
+      <div class="card">
+        <div class="card-header">
+          <h2 class="card-title">璁惧杩愯鏃ュ織</h2>
+          <i class="fas fa-clipboard-list card-icon"></i>
+        </div>
+        <div class="logs-container">
+          <div v-for="log in logs" :key="log.id" :class="['log-item', log.type]">
+            <div class="log-time">{{ log.time }}</div>
+            <div class="log-message">{{ log.message }}</div>
+          </div>
+        </div>
+      </div>
+
+      <div class="card">
+        <div class="card-header">
+          <h2 class="card-title">璁惧淇℃伅</h2>
+          <i class="fas fa-server card-icon"></i>
+        </div>
+        <div class="device-info-container">
+          <div class="device-status">
+            <div :class="['status-indicator', deviceStatus.online ? 'status-online pulse' : 'status-offline']"></div>
+            <div class="device-details">
+              <!-- <div class="device-name">{{ deviceInfo.name }}</div> -->
+              <div class="device-id">璁惧SN: {{ deviceInfo.id }} | IP: {{ deviceInfo.ip }}</div>
+            </div>
+          </div>
+
+          <div class="info-grid">
+            <div class="info-item">
+              <div class="info-label">璁惧鍨嬪彿</div>
+              <div class="info-value">{{ deviceInfo.model }}</div>
+            </div>
+            <div class="info-item">
+              <div class="info-label">鍥轰欢鐗堟湰</div>
+              <div class="info-value">{{ deviceInfo.firmware }}</div>
+            </div>
+            <div class="info-item">
+              <div class="info-label">杩愯鏃堕棿</div>
+              <div class="info-value">{{ deviceInfo.uptime }}</div>
+            </div>
+            <div class="info-item">
+              <div class="info-label">瀛樺偍绌洪棿</div>
+              <div class="info-value">{{ deviceInfo.storage }}</div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+<script>
+import * as echarts from "echarts";
+export default {
+  data () {
+    return {
+      currentTime: '',
+      deviceStatus: {
+        online: true
+      },
+      userCount: 888,
+      whitelist: {
+        face: 99,
+        password: 88,
+        card: 66
+      },
+      deviceStats: {
+        recognitions: 1247
+      },
+      systemStatus: {
+        cpu: 45,
+        memory: 62
+      },
+      deviceInfo: {
+        name: '浜鸿劯璇嗗埆缁堢-A01',
+        id: 'FRD-2023-A01',
+        ip: '192.168.1.101',
+        model: 'FRD-X3000',
+        firmware: 'v2.5.3',
+        uptime: '15澶� 8灏忔椂 32鍒嗛挓',
+        storage: '78% (128GB/164GB)',
+        network: '绋冲畾',
+        lastMaintenance: '2023-10-28'
+      },
+      logs: [
+        { id: 1, time: '2023-11-15 14:23:45', message: '浜鸿劯璇嗗埆鎴愬姛 - 鐢ㄦ埛: 寮犱笁', type: 'normal' },
+        { id: 2, time: '2023-11-15 14:22:30', message: 'CPU浣跨敤鐜囪秴杩�80%', type: 'warning' },
+        { id: 3, time: '2023-11-15 14:21:15', message: '缃戠粶杩炴帴鐭殏涓柇锛屽凡鎭㈠', type: 'error' },
+        { id: 4, time: '2023-11-15 14:20:05', message: '绯荤粺閲嶅惎瀹屾垚', type: 'normal' },
+        { id: 5, time: '2023-11-15 14:19:50', message: '鍐呭瓨浣跨敤鐜囪秴杩囬槇鍊�', type: 'warning' },
+        { id: 6, time: '2023-11-15 14:18:30', message: '璇嗗埆寮曟搸鏇存柊瀹屾垚', type: 'normal' },
+        { id: 7, time: '2023-11-15 14:17:15', message: '浜鸿劯璇嗗埆鎴愬姛 - 鐢ㄦ埛: 鏉庡洓', type: 'normal' },
+        { id: 8, time: '2023-11-15 14:16:20', message: '鏁版嵁搴撳浠藉畬鎴�', type: 'normal' }
+      ],
+      cpuChart: null,
+      memoryChart: null,
+      cpuData: [],
+      memoryData: [],
+      timeData: []
+    }
+  },
+  mounted () {
+    this.updateTime();
+    setInterval(this.updateTime, 1000);
+    this.initCharts();
+    this.simulateDataUpdate();
+    // 妯℃嫙瀹炴椂鏁版嵁鏇存柊
+    setInterval(this.updateCharts, 2000);
+    setInterval(this.addRandomLog, 5000);
+    setInterval(this.updateDeviceStats, 3000);
+  },
+  methods: {
+    updateTime () {
+      const now = new Date();
+      this.currentTime = now.toLocaleString('zh-CN', {
+        year: 'numeric',
+        month: '2-digit',
+        day: '2-digit',
+        hour: '2-digit',
+        minute: '2-digit',
+        second: '2-digit',
+        hour12: false
+      });
+    },
+    initCharts () {
+      // 鍒濆鍖朇PU鍥捐〃
+      this.cpuChart = echarts.init(document.getElementById('cpuChart'));
+      const cpuOption = {
+        tooltip: {
+          trigger: 'axis',
+          formatter: '{b}<br/>CPU: {c}%'
+        },
+        grid: {
+          top: '15%',
+          left: '3%',
+          right: '4%',
+          bottom: '10%',
+          containLabel: true
+        },
+        xAxis: {
+          type: 'category',
+          boundaryGap: false,
+          data: this.timeData,
+          axisLine: {
+            lineStyle: {
+              color: '#a0a0ff'
+            }
+          }
+        },
+        yAxis: {
+          type: 'value',
+          max: 100,
+          axisLine: {
+            lineStyle: {
+              color: '#a0a0ff'
+            }
+          },
+          splitLine: {
+            lineStyle: {
+              color: 'rgba(160, 160, 255, 0.1)'
+            }
+          }
+        },
+        series: [{
+          name: 'CPU浣跨敤鐜�',
+          type: 'line',
+          smooth: true,
+          symbol: 'circle',
+          symbolSize: 8,
+          lineStyle: {
+            width: 3,
+            color: '#1890ff'
+          },
+          itemStyle: {
+            color: '#1890ff',
+            borderColor: '#fff',
+            borderWidth: 2
+          },
+          areaStyle: {
+            color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+              { offset: 0, color: 'rgba(24, 144, 255, 0.5)' },
+              { offset: 1, color: 'rgba(24, 144, 255, 0.1)' }
+            ])
+          },
+          data: this.cpuData
+        }]
+      };
+      this.cpuChart.setOption(cpuOption);
+
+      // 鍒濆鍖栧唴瀛樺浘琛�
+      this.memoryChart = echarts.init(document.getElementById('memoryChart'));
+      const memoryOption = {
+        tooltip: {
+          formatter: '{a} <br/>{b} : {c}%'
+        },
+        series: [
+          {
+            name: '鍐呭瓨浣跨敤鐜�',
+            type: 'gauge',
+            radius: '90%',
+            center: ['50%', '60%'],
+            progress: {
+              show: true,
+              width: 20,
+              itemStyle: {
+                color: {
+                  type: 'linear',
+                  x: 0,
+                  y: 0,
+                  x2: 0,
+                  y2: 1,
+                  colorStops: [{
+                    offset: 0, color: '#40e0d0'
+                  }, {
+                    offset: 1, color: '#ff0080'
+                  }]
+                }
+              }
+            },
+            axisLine: {
+              lineStyle: {
+                width: 20,
+                color: [
+                  [0.3, '#40e0d0'],
+                  [0.7, '#ff8c00'],
+                  [1, '#ff0080']
+                ]
+              }
+            },
+            axisTick: {
+              distance: -20,
+              length: 8,
+              lineStyle: {
+                color: '#fff',
+                width: 2
+              }
+            },
+            splitLine: {
+              distance: -20,
+              length: 20,
+              lineStyle: {
+                color: '#fff',
+                width: 3
+              }
+            },
+            axisLabel: {
+              distance: -20,
+              color: '#fff',
+              fontSize: 14
+            },
+            anchor: {
+              show: true,
+              size: 15,
+              showAbove: true,
+              itemStyle: {
+                borderWidth: 4,
+                borderColor: '#1890ff'
+              }
+            },
+            detail: {
+              valueAnimation: true,
+              formatter: '{value}%',
+              color: '#fff',
+              fontSize: 24,
+              offsetCenter: [0, '30%']
+            },
+            title: {
+              // 鍗曠嫭璁剧疆鍚嶇О鐨勬牱寮�
+              show: true,
+              offsetCenter: [0, '50%'],  // 鍚嶇О浣嶇疆 [姘村钩鍋忕Щ, 鍨傜洿鍋忕Щ]
+              color: '#fff',  // 鍚嶇О棰滆壊鏀逛负鐧借壊
+              fontSize: 12,
+              fontWeight: 'bold'
+            },
+            data: [
+              {
+                value: this.systemStatus.memory,
+                name: '宸茬敤/鎬�(M)锛�353/780'
+              }
+            ]
+          }
+        ]
+      };
+      this.memoryChart.setOption(memoryOption);
+    },
+    simulateDataUpdate () {
+      // 鍒濆鍖栦竴浜涙ā鎷熸暟鎹� - 浣跨敤鐪熷疄鏃堕棿
+      const now = new Date();
+      for (let i = 10; i >= 0; i--) {
+        const time = new Date(now.getTime() - i * 2000);
+        this.timeData.push(this.formatTime(time));
+        this.cpuData.push(Math.floor(Math.random() * 30) + 30);
+        this.memoryData.push(Math.floor(Math.random() * 20) + 50);
+      }
+    },
+    updateCharts () {
+      // 鏇存柊CPU鍥捐〃鏁版嵁 - 浣跨敤褰撳墠鐪熷疄鏃堕棿
+      const now = new Date();
+      const currentTime = this.formatTime(now);
+
+      this.timeData.push(currentTime);
+      this.timeData.shift();
+
+      const newCpuValue = Math.floor(Math.random() * 30) + 30;
+      this.cpuData.push(newCpuValue);
+      this.cpuData.shift();
+      this.systemStatus.cpu = newCpuValue;
+
+      // 鏇存柊鍐呭瓨鍥捐〃鏁版嵁
+      const newMemoryValue = Math.floor(Math.random() * 20) + 50;
+      this.systemStatus.memory = newMemoryValue;
+
+      this.cpuChart.setOption({
+        xAxis: {
+          data: this.timeData
+        },
+        series: [{
+          data: this.cpuData
+        }]
+      });
+
+      this.memoryChart.setOption({
+        series: [{
+          data: [{
+            value: newMemoryValue,
+            name: '宸茬敤/鎬�(M)锛�353/780'
+          }]
+        }]
+      });
+    },
+    // 鏍煎紡鍖栨椂闂翠负 HH:MM:SS 鏍煎紡
+    formatTime (date) {
+      const hours = date.getHours().toString().padStart(2, '0');
+      const minutes = date.getMinutes().toString().padStart(2, '0');
+      const seconds = date.getSeconds().toString().padStart(2, '0');
+      return `${hours}:${minutes}:${seconds}`;
+    },
+    addRandomLog () {
+      const logTypes = ['normal', 'warning', 'error'];
+      const messages = [
+        '浜鸿劯璇嗗埆鎴愬姛 - 鐢ㄦ埛: 鐜嬩簲',
+        '璁惧娓╁害寮傚父',
+        '缃戠粶杩炴帴鎭㈠',
+        '瀛樺偍绌洪棿涓嶈冻璀﹀憡',
+        '璇嗗埆鍑嗙‘鐜囦笅闄�',
+        '绯荤粺澶囦唤瀹屾垚',
+        '瀹夊叏绛栫暐宸叉洿鏂�',
+        '璁惧鍥轰欢鍗囩骇鍙敤',
+        '鏁版嵁搴撲紭鍖栧畬鎴�',
+        '浜鸿劯搴撴洿鏂板畬鎴�'
+      ];
+
+      const now = new Date();
+      const timeStr = now.getFullYear() + '-' +
+        (now.getMonth() + 1).toString().padStart(2, '0') + '-' +
+        now.getDate().toString().padStart(2, '0') + ' ' +
+        now.getHours().toString().padStart(2, '0') + ':' +
+        now.getMinutes().toString().padStart(2, '0') + ':' +
+        now.getSeconds().toString().padStart(2, '0');
+
+      const randomType = logTypes[Math.floor(Math.random() * logTypes.length)];
+      const randomMessage = messages[Math.floor(Math.random() * messages.length)];
+
+      this.logs.unshift({
+        id: this.logs.length + 1,
+        time: timeStr,
+        message: randomMessage,
+        type: randomType
+      });
+
+      // 淇濇寔鏃ュ織鏁伴噺涓嶈秴杩�15鏉�
+      if (this.logs.length > 15) {
+        this.logs.pop();
+      }
+    },
+    updateDeviceStats () {
+      // 闅忔満澧炲姞璇嗗埆娆℃暟
+      if (Math.random() > 0.7) {
+        this.deviceStats.recognitions += Math.floor(Math.random() * 3) + 1;
+      }
+
+      // 闅忔満鏀瑰彉璁惧鍦ㄧ嚎鐘舵�侊紙灏忔鐜囷級
+      if (Math.random() > 0.95) {
+        this.deviceStatus.online = !this.deviceStatus.online;
+      }
+    },
+    beforeDestroy () {
+      if (this.cpuChart) {
+        this.cpuChart.dispose();
+      }
+      if (this.memoryChart) {
+        this.memoryChart.dispose();
+      }
+    }
+  }
+};
+</script>
+<style lang="less">
+.container {
+  max-width: 1400px;
+  margin: 0 auto;
+  padding: 20px;
+}
+
+.dashboard {
+  display: grid;
+  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
+  gap: 25px;
+  margin-bottom: 30px;
+}
+
+.card {
+  background: rgba(16, 16, 48, 0.7);
+  border-radius: 15px;
+  padding: 25px;
+  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
+  border: 1px solid rgba(64, 224, 208, 0.2);
+  transition: all 0.3s ease;
+  position: relative;
+  overflow: hidden;
+}
+
+.card::before {
+  content: '';
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 4px;
+  background: linear-gradient(90deg, var(--themeColor), #ff8c00, #ff0080);
+}
+
+.card:hover {
+  transform: translateY(-10px);
+  box-shadow: 0 15px 35px rgba(0, 0, 0, 0.4);
+  border-color: rgba(24, 144, 255, 0.5);
+}
+
+.card-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 20px;
+}
+
+.card-title {
+  font-size: 20px;
+  font-weight: 600;
+  color: var(--themeColor);
+}
+
+.card-icon {
+  font-size: 24px;
+  color: #ff8c00;
+}
+
+.stats-grid {
+  display: grid;
+  grid-template-columns: repeat(2, 1fr);
+  gap: 15px;
+}
+
+.stat-item {
+  text-align: center;
+  padding: 15px;
+  background: rgba(32, 32, 64, 0.5);
+  border-radius: 10px;
+  transition: all 0.3s ease;
+}
+
+.stat-item:hover {
+  background: rgba(32, 32, 64, 0.8);
+  transform: scale(1.05);
+}
+
+.stat-value {
+  font-size: 24px;
+  font-weight: 700;
+  margin: 10px 0;
+  color: #ff8c00;
+}
+
+.stat-label {
+  font-size: 14px;
+  color: #a0a0ff;
+}
+
+.chart-container {
+  height: 300px;
+  margin-top: 10px;
+}
+
+.main-content {
+  display: grid;
+  grid-template-columns: 2fr 1fr;
+  gap: 25px;
+}
+
+.logs-container {
+  max-height: 400px;
+  overflow-y: auto;
+  padding-right: 10px;
+}
+
+.logs-container::-webkit-scrollbar {
+  width: 8px;
+}
+
+.logs-container::-webkit-scrollbar-track {
+  background: rgba(32, 32, 64, 0.5);
+  border-radius: 10px;
+}
+
+.logs-container::-webkit-scrollbar-thumb {
+  background: linear-gradient(180deg, var(--themeColor), #ff8c00);
+  border-radius: 10px;
+}
+
+.log-item {
+  padding: 15px;
+  margin-bottom: 15px;
+  background: rgba(32, 32, 64, 0.5);
+  border-radius: 10px;
+  border-left: 4px solid var(--themeColor);;
+  transition: all 0.3s ease;
+}
+
+.log-item:hover {
+  background: rgba(32, 32, 64, 0.8);
+  transform: translateX(5px);
+}
+
+.log-item.warning {
+  border-left-color: #ff8c00;
+}
+
+.log-item.error {
+  border-left-color: #ff0080;
+}
+
+.log-time {
+  font-size: 12px;
+  color: #a0a0ff;
+  margin-bottom: 5px;
+}
+
+.log-message {
+  font-size: 14px;
+  color: #ffffff;
+}
+
+.device-info-container {
+  display: flex;
+  flex-direction: column;
+  gap: 15px;
+}
+
+.device-status {
+  display: flex;
+  align-items: center;
+  padding: 15px;
+  background: rgba(32, 32, 64, 0.5);
+  border-radius: 10px;
+  transition: all 0.3s ease;
+}
+
+.device-status:hover {
+  background: rgba(32, 32, 64, 0.8);
+  transform: translateX(5px);
+}
+
+.status-indicator {
+  width: 12px;
+  height: 12px;
+  border-radius: 50%;
+  margin-right: 15px;
+}
+
+.status-online {
+  background: var(--themeColor);
+  box-shadow: 0 0 10px var(--themeColor);
+}
+
+.status-offline {
+  background: #ff0080;
+  box-shadow: 0 0 10px #ff0080;
+}
+
+.device-details {
+  flex: 1;
+}
+
+.device-name {
+  font-weight: 600;
+  margin-bottom: 5px;
+  font-size: 18px;
+}
+
+.device-id {
+  font-size: 14px;
+  color: #a0a0ff;
+}
+
+@media (max-width: 992px) {
+  .main-content {
+    grid-template-columns: 1fr;
+  }
+}
+
+@media (max-width: 768px) {
+  .dashboard {
+    grid-template-columns: 1fr;
+  }
+
+  header {
+    flex-direction: column;
+    gap: 15px;
+  }
+}
+
+.pulse {
+  animation: pulse 2s infinite;
+}
+
+@keyframes pulse {
+  0% {
+    box-shadow: 0 0 0 0 rgba(24, 144, 255, 0.7);
+  }
+
+  70% {
+    box-shadow: 0 0 0 10px rgba(64, 224, 208, 0);
+  }
+
+  100% {
+    box-shadow: 0 0 0 0 rgba(64, 224, 208, 0);
+  }
+}
+
+.glow {
+  text-shadow: 0 0 10px currentColor;
+}
+
+.info-grid {
+  display: grid;
+  grid-template-columns: repeat(2, 1fr);
+  gap: 15px;
+  margin-top: 15px;
+}
+
+.info-item {
+  padding: 12px;
+  background: rgba(32, 32, 64, 0.5);
+  border-radius: 8px;
+  font-size: 14px;
+}
+
+.info-label {
+  color: #a0a0ff;
+  margin-bottom: 5px;
+}
+
+.info-value {
+  font-weight: 600;
+  color: #ff8c00;
+}
+</style>
diff --git "a/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/views/person/addOrEdit.vue" "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/views/person/addOrEdit.vue"
new file mode 100644
index 0000000..1ebebb6
--- /dev/null
+++ "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/views/person/addOrEdit.vue"
@@ -0,0 +1,132 @@
+<!-- 浜哄憳鏂板鎴栫紪杈� -->
+<template>
+  <div>
+    <el-drawer size="50%" :with-header="false" :visible.sync="visible" :before-close="handleAddClose">
+      <div class="config-tabs">
+        <el-menu :default-active="activeTab" mode="horizontal" class="quanxian-menu">
+          <el-menu-item index="info" @click="activeTab = 'info'">{{ $t('person.user') }}</el-menu-item>
+          <el-menu-item index="vourcher" @click="activeTab = 'vourcher'">{{ $t('person.voucher') }}</el-menu-item>
+          <el-menu-item index="permission" @click="activeTab = 'permission'">{{ $t('person.permission') }}</el-menu-item>
+        </el-menu>
+        <!-- 鍔熻兘椤甸潰 -->
+        <el-scrollbar>
+          <div style="padding: 20px;">
+            <component
+              :is="currentComponent"
+              :key="componentKey"
+              :form-data="form"
+              :add-or-edit-type="addOrEditType"
+              @close-drawer="handleAddClose"
+              @operation-success="operationSuccess"
+            />
+          </div>
+        </el-scrollbar>
+      </div>
+    </el-drawer>
+  </div>
+</template>
+
+<script>
+import Info from '@/views/person/info'
+import Vourcher from '@/views/person/vourcher'
+import Permission from '@/views/person/permission'
+export default {
+  components: { Info, Vourcher, Permission },
+  data () {
+    return {
+      form: {
+        userId: "",
+        name: "",
+        permissionIds: "",
+        extra: ""
+      },
+      addOrEditType: 'add',
+      visible: false,
+      activeTab: 'info',
+      componentKey: 0,  // 缁勪欢閲嶆柊娓叉煋鐨刱ey
+      deviceModel: '',
+    }
+  },
+  computed: {
+    currentComponent () {
+      return this.activeTab;
+    }
+  },
+  created () {
+    this.initialForm = JSON.parse(JSON.stringify(this.form));
+  },
+  mounted () {
+
+  },
+  methods: {
+    open (type, row) {
+      console.log(type, row)
+      this.visible = true
+      this.addOrEditType = type
+      this.activeTab = 'info';
+      if (row) {
+        let extra = row.extra ? JSON.parse(row.extra) : ""
+        this.form = { ...row, extra }
+      }
+      // 寮哄埗閲嶆柊娓叉煋瀛愮粍浠�
+      this.componentKey += 1;
+    },
+
+    handleAddClose (showConfirm = true) {
+      const closeAction = () => {
+        this.visible = false;
+        this.form = { ...this.initialForm };
+        // 寮哄埗閲嶆柊娓叉煋瀛愮粍浠讹紝纭繚涓嬫鎵撳紑鏄共鍑�鐨�
+        this.componentKey += 1;
+      };
+      if (showConfirm) {
+        this.$confirm(this.$t('common.closeTips'))
+          .then(closeAction)
+          .catch(() => { });
+      } else {
+        closeAction();
+      }
+    },
+
+    operationSuccess (param) {
+      this.form = {...param}
+      this.$emit('addOrEditSuccess')
+    },
+  }
+}
+</script>
+<style lang='less' scoped>
+.config-tabs {
+  background: transparent;
+}
+
+.config-tabs ::v-deep .el-tabs__header {
+  background: #fff;
+  border-radius: 8px;
+  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
+  margin-bottom: 20px;
+  border: none;
+}
+
+.config-tabs ::v-deep .el-tabs__item {
+  font-weight: 500;
+  height: 50px;
+  line-height: 50px;
+}
+
+.drawerHeader {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  margin: 50px 10px 30px 10px;
+  font-size: 20px;
+}
+
+.drawerImg {
+  height: 20px;
+  margin-right: 20px;
+}
+
+// .el-drawer__wrapper {
+//   z-index: 3000 !important;
+// }</style>
\ No newline at end of file
diff --git "a/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/views/person/index.vue" "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/views/person/index.vue"
new file mode 100644
index 0000000..f580b7c
--- /dev/null
+++ "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/views/person/index.vue"
@@ -0,0 +1,254 @@
+<template>
+  <el-main>
+    <el-row>
+      <el-form class="el-InputForm" :inline="true" :model="searchForm" ref="ruleForm">
+        <el-form-item :label="$t('person.userId')" label-width="60px">
+          <el-input v-model="searchForm.userId" :placeholder="$t('person.placeholderUserId')" clearable></el-input>
+        </el-form-item>
+        <el-form-item :label="$t('person.name')" label-width="80px">
+          <el-input v-model="searchForm.name" :placeholder="$t('person.placeholderName')" clearable></el-input>
+        </el-form-item>
+        <div style="position: absolute; right: 25px; bottom: 25px;">
+          <el-button type="info" style="margin-left:10px;border:none;" size='medium' icon="el-icon-search"
+            @click="search">{{ $t('common.query') }}</el-button>
+          <el-button type="warning" style="border:none;" size='medium' icon="el-icon-refresh-right" @click="doReset">{{
+            $t('common.reset') }}</el-button>
+        </div>
+      </el-form>
+      <el-col :span="24" style="margin:20px 0">
+        <el-button type="primary" style="border:none;" size='mini' icon="el-icon-plus" @click="doAdd">{{
+          $t('person.addUser') }}</el-button>
+        <el-button type="warning" style="border:none;" size='mini' icon="el-icon-delete" @click="batchDelete">{{
+          $t('common.batchDelete') }}</el-button>
+        <el-button type="danger" style="border:none;" size='mini' icon="el-icon-delete-solid" @click="doClear">{{
+          $t('person.oneClickClear') }}</el-button>
+      </el-col>
+      <!-- 鏂板浜哄憳 -->
+      <AddOrEdit ref="addOrEdit" @addOrEditSuccess='fetchData'></AddOrEdit>
+      <!-- Table -->
+      <el-col :span="24" style="padding: 0">
+        <Table :table-label="tableHeader" v-loading="isSubmitLoading" :table-data="tableData"
+          :table-option="tableOption" :table-selection="tableSelection"
+          @onHandleSelectionChange="handleSelectionChange"></Table>
+      </el-col>
+      <!-- 鍒嗛〉 -->
+      <el-col :span="24" style="text-align: center">
+        <Pagination ref="page" :total="total" @pageChange="pageChange"></Pagination>
+      </el-col>
+    </el-row>
+  </el-main>
+</template>
+<script>
+import Table from "@/components/table/tableList";
+import Pagination from "@/components/table/pagination";
+import AddOrEdit from "./addOrEdit.vue"
+import { removeEmptyValues, resetObjectValues } from '@/utils/index.js'
+export default {
+  components: {
+    Pagination,
+    Table,
+    AddOrEdit
+  },
+  data () {
+    return {
+      tableHeader: [
+        { label: this.$t('person.userId'), list: 'userId', overflowShow: 'hidden' },
+        { label: this.$t('person.name'), list: 'name', overflowShow: 'hidden' },
+      ],
+      tableSelection: {
+        key: true,
+        type: "selection",
+        detaile: false,
+      },
+      tableOption: {
+        label: this.$t('common.operation'),
+        width: "300px",
+        value: 0,
+        options: [
+          {
+            label: this.$t('common.edit'),
+            key: 0,
+            type: "text",
+            State: true,
+            method: (row) => {
+              this.$refs.addOrEdit.open('edit', { ...row })
+            },
+          },
+          {
+            label: this.$t('common.delete'),
+            key: 1,
+            type: "text",
+            State: true,
+            method: (row) => {
+              this.handleDelete(row.userId)
+            },
+          }
+        ]
+      },
+      tableHeight: 450,
+      currentPage: 0,
+      pageSize: 20,
+      total: 0,
+      tableData: [],
+      searchForm: {
+        userId: '',
+        name: '',
+      },
+      selectIdList: [],
+      isSubmitLoading: false,
+    };
+  },
+  created () {
+    this.fetchData()
+  },
+  methods: {
+    async fetchData () {
+      let searchForm = removeEmptyValues({ ...this.searchForm })
+      searchForm.page = this.currentPage
+      searchForm.size = this.pageSize
+      try {
+        const res = await this.$http.post("/getUser", { data: searchForm });
+        if (res.code == 200) {
+          this.tableData = res.data.content
+          this.total = res.data.total
+        } else {
+          this.$message.error(res.message);
+        }
+      } catch (even) {
+        console.log(even)
+      }
+    },
+
+    doAdd () {
+      this.$refs.addOrEdit.open('add')
+    },
+
+    doReset () {
+      resetObjectValues(this.searchForm)
+      this.fetchData()
+    },
+
+    handleDelete (userId) {
+      let that = this
+      this.$confirm(
+        this.$t('common.deleteTips'),
+        this.$t('common.tips'),
+        {
+          confirmButtonText: this.$t('common.confirm'),
+          cancelButtonText: this.$t('common.cancel'),
+          type: 'warning'
+        }
+      ).then(async () => {
+        try {
+          const res = await that.$http.post("delUser", { data: [userId] })
+          if (res.code == 200) {
+            that.$message.success(this.$t('common.deleteSuccess'))
+            that.fetchData()
+          } else {
+            that.$message.error(res.message)
+          }
+        } catch (even) {
+          console.log(even)
+        }
+      }).catch(() => { })
+    },
+
+    batchDelete () {
+      let that = this
+      if (this.selectIdList.length <= 0) {
+        this.$message.warning(this.$t('common.placeholderSelect'));
+        return;
+      }
+      this.$confirm(this.$t('common.deleteTips'),
+        this.$t('common.tips'),
+        {
+          confirmButtonText: this.$t('common.confirm'),
+          cancelButtonText: this.$t('common.cancel'),
+          type: 'warning'
+        })
+        .then(async () => {
+          that.isSubmitLoading = true;
+          const res = await this.$http.post("delUser", { data: this.selectIdList });
+          that.isSubmitLoading = false;
+          if (res.code == 200) {
+            that.$message.success(this.$t('common.deleteSuccess'))
+            that.fetchData()
+          } else {
+            that.$message.error(res.message)
+          }
+        })
+        .catch(() => {
+          return false;
+        });
+    },
+
+    doClear () {
+      let that = this
+      this.$confirm(this.$t('person.clearTips'),
+        this.$t('common.tips'),
+        {
+          confirmButtonText: this.$t('common.confirm'),
+          cancelButtonText: this.$t('common.cancel'),
+          type: 'warning'
+        })
+        .then(async () => {
+          that.isSubmitLoading = true;
+          try {
+            const res = await this.$http.post("/clearUser", {});
+            that.isSubmitLoading = false;
+            if (res.code == 200) {
+              that.$message.success(this.$t('person.clearSuccess'))
+              that.fetchData()
+            } else {
+              that.$message.error(that.$t('person.clearFailed'))
+            }
+          } catch (error) {
+            console.log(error)
+          }
+
+        })
+        .catch(() => {
+          return false;
+        });
+    },
+
+    handleSelectionChange (vals) {
+      this.selectIdList = [];
+      vals.map(v => {
+        this.selectIdList.push(v.userId);
+      });
+    },
+
+    pageChange (item) {
+      this.pageSize = item.limit;
+      this.currentPage = item.page - 1;
+      this.fetchData()
+    },
+
+    search () {
+      this.currentPage = 0
+      this.$refs.page.Page(1);
+      this.fetchData();
+    },
+  },
+};
+</script>
+<style lang="less" scoped>
+.el-InputForm {
+  position: relative;
+  background-color: #fff;
+  padding: 10px 20px;
+  box-shadow: 0px 4px 16px 0px rgba(0, 0, 0, 0.16);
+  border-radius: 15px;
+}
+
+.card {
+  width: 96%;
+  height: 85%;
+  border-radius: 5px;
+  box-shadow: 0px 10px 30px 10px rgba(211, 215, 221, 0.4);
+  padding: 20px;
+  margin: 20px auto;
+  font-size: 14px;
+}
+</style>
\ No newline at end of file
diff --git "a/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/views/person/info.vue" "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/views/person/info.vue"
new file mode 100644
index 0000000..75f300e
--- /dev/null
+++ "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/views/person/info.vue"
@@ -0,0 +1,140 @@
+<!-- 浜哄憳鏂板鎴栫紪杈� -->
+<template>
+  <div>
+    <el-form ref="localForm" :model="localForm" label-width="100px" :rules="rules" style="width: 90%;margin: 0 auto;">
+      <el-form-item :label="$t('person.userId')" v-if="addOrEditType == 'edit'">
+        <el-input v-model="localForm.userId" :disabled=true :placeholder="$t('common.placeholder')"></el-input>
+      </el-form-item>
+      <el-form-item :label="$t('person.name')" prop="name">
+        <el-input v-model="localForm.name" :placeholder="$t('common.placeholder')"></el-input>
+      </el-form-item>
+      <el-form-item :label="$t('person.idCard')">
+        <el-input v-model="localForm.idCard" :placeholder="$t('common.placeholder')"></el-input>
+      </el-form-item>
+      <el-form-item :label="$t('person.userType')">
+        <el-checkbox v-model="localForm.type">{{ $t('person.administrator') }}</el-checkbox>
+      </el-form-item>
+    </el-form>
+    <div class="dialog-footer">
+      <el-button type="warning" @click="handleAddClose()">{{ $t('common.cancel') }}</el-button>
+      <el-button type="primary" @click="updata()">{{ $t('common.confirm') }}</el-button>
+    </div>
+  </div>
+</template>
+
+<script>
+import { generateRandomString, throttle } from '@/utils/index.js'
+export default {
+  props: {
+    formData: {
+      type: Object,
+      default: () => ({})
+    },
+    addOrEditType: {
+      type: String,
+      default: 'add'
+    }
+  },
+  data () {
+    return {
+      localForm: {
+        userId: "",
+        name: "",
+        type: false,
+        idCard: "",
+        permissionIds: ""
+      },
+      localFormCopy: {},
+      rules: {
+        name: [{ required: true, message: this.$t('common.placeholder'), trigger: ["blur"] },],
+        userId: [{ required: true, message: this.$t('common.placeholder'), trigger: ["blur"] },],
+      },
+    }
+  },
+  created () {
+    if (this.addOrEditType == 'edit') {
+      this.getUser()
+    }
+    this.localFormCopy = { ...this.localForm }
+  },
+  mounted () {
+
+  },
+  methods: {
+    async getUser () {
+      try {
+        let data = {
+          userId: this.formData.userId,
+          page: 0,
+          size: 99
+        }
+        const res = await this.$http.post('/getUser', { data })
+        if (res.code == 200) {
+          console.log(res)
+          let { userId, name, extra, permissionIds } = res.data.content[0]
+          let { type, idCard } = JSON.parse(extra)
+          this.localForm.userId = userId
+          this.localForm.name = name
+          this.localForm.type = type == 1 ? true : false
+          this.localForm.idCard = idCard
+          this.localForm.permissionIds = permissionIds
+        } else {
+          this.$message.error(res.message);
+        }
+      } catch (even) {
+        console.log(even)
+      }
+    },
+
+    handleAddClose () {
+      this.$emit('close-drawer', false);
+    },
+
+    updata: throttle(function () {
+      let data = {
+        name: this.localForm.name,
+        extra: {
+          type: this.localForm.type ? 1 : 0,
+          idCard: this.localForm.idCard
+        },
+      }
+      if (this.localForm.permissionIds) {
+        data.permissionIds = this.localForm.permissionIds.split(',')
+      }
+      this.$refs['localForm'].validate(async (valid) => {
+        if (valid) {
+          if (this.addOrEditType == 'add') {
+            data.userId = generateRandomString()
+            const res = await this.$http.post(
+              "/insertUser",
+              { data: [data] }
+            );
+            if (res.code == 200) {
+              this.$message.success(this.$t('common.addSuccess'))
+              this.$emit("operation-success", { ...data, permissionIds: data.permissionIds ? data.permissionIds.join(',') : '' })
+            } else {
+              if (res.data && res.data[0]) {
+                this.$message.error(res.data[0].errmsg)
+              }
+            }
+          } else {
+            data.userId = this.localForm.userId
+            const res = await this.$http.post(
+              "/modifyUser",
+              { data: [data] }
+            );
+            if (res.code == 200) {
+              this.$message.success(this.$t('common.editSuccess'))
+              this.$emit("operation-success", { ...data, permissionIds: data.permissionIds ? data.permissionIds.join(',') : '' })
+            } else {
+              if (res.data && res.data[0]) {
+                this.$message.error(res.data[0].errmsg)
+              }
+            }
+          }
+        }
+      })
+    }, 2000)
+  }
+}
+</script>
\ No newline at end of file
diff --git "a/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/views/person/permission.vue" "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/views/person/permission.vue"
new file mode 100644
index 0000000..df67e9c
--- /dev/null
+++ "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/views/person/permission.vue"
@@ -0,0 +1,702 @@
+<!-- 鏉冮檺  -->
+<template>
+  <div>
+    <div style="position: absolute; right: 25px; top: 65px;">
+      <!-- <el-button type="danger" style="margin-left:10px;border:none;" size='medium' icon="el-icon-delete">{{
+          $t('permission.deletePermission') }}</el-button> -->
+      <el-button type="primary" style="border:none;" size='medium' icon="el-icon-plus" @click="openTimeDialog">{{
+        $t('permission.addPermission') }}</el-button>
+    </div>
+    <div style="margin-top: 150px;">
+      <Table :table-label="tableHeader" :table-data="tableData" :table-option="tableOption"></Table>
+    </div>
+    <div class="dialog-footer" style="margin-top: 50px;">
+      <el-button type="warning" @click="doClose">{{ $t('common.close') }}</el-button>
+    </div>
+    <!-- 娣诲姞鏉冮檺 -->
+    <el-dialog :title="$t('permission.timeRange')" append-to-body modal-append-to-body :visible.sync="timeVisible"
+      width="800px" :before-close="handleClose" class="time-range-dialog">
+      <el-form label-position="right" style="width:80%;margin:0 auto;">
+        <el-form-item>
+          <div> {{ $t('permission.effectiveType') }}</div>
+          <el-radio v-model="radio" :label="0">{{ $t('permission.unlimitedMode') }}</el-radio>
+          <el-radio v-model="radio" :label="1">{{ $t('permission.usualMode') }}</el-radio>
+          <el-radio v-model="radio" :label="2">{{ $t('permission.dailyMode') }}</el-radio>
+          <el-radio v-model="radio" :label="3">{{ $t('permission.weeklyRepetitionMode') }}</el-radio>
+        </el-form-item>
+        <el-form-item v-if="radio === 1">
+          <div>{{ $t('permission.effectiveTime') }}</div>
+          <el-date-picker :clearable="false" v-model="dateTimes" value-format="timestamp"
+            :default-time="['00:00:00', '23:59:59']" type="datetimerange" :range-separator="$t('common.to')"
+            :start-placeholder="$t('common.startDate')" :end-placeholder="$t('common.endDate')">
+          </el-date-picker>
+        </el-form-item>
+
+        <!-- <el-form-item v-if="radio === 2">
+          <div>{{ $t('permission.effectiveTime') }}</div>
+          <el-time-picker :default-value="['00:00', '23:59']" :clearable="false" is-range value-format="HH:mm"
+            format="HH:mm" v-model="timeRange" :range-separator="$t('common.to')"
+            :start-placeholder="$t('common.startTime')" :end-placeholder="$t('common.endTime')"
+            :placeholder="$t('placeholder.placeholder_choose_time_priod')">
+          </el-time-picker>
+          <div style="margin-top:30px">{{ $t('permission.effectiveWeek') }}</div>
+          <el-date-picker :clearable="false" v-model="dateTimes" value-format="timestamp"
+            :default-time="['00:00:00', '23:59:59']" type="datetimerange" :range-separator="$t('common.to')"
+            :start-placeholder="$t('common.startDate')" :end-placeholder="$t('common.endDate')">
+          </el-date-picker>
+        </el-form-item> -->
+
+        <el-form-item v-if="radio === 2 || radio == 3">
+          <div>{{ $t('permission.effectiveTime') }}</div>
+          <el-date-picker style="width:400px;" v-model="dateTimes" value-format="timestamp"
+            :default-time="['00:00:00', '23:59:59']" :clearable="false" type="datetimerange"
+            :range-separator="$t('common.to')" :start-placeholder="$t('common.startDate')"
+            :end-placeholder="$t('common.endDate')">
+          </el-date-picker>
+          <div style="margin-top:30px">{{ $t('permission.effectiveWeek') }}</div>
+          <el-row class="the-week-box" v-if="radio == 2">
+            <el-col :span="24">
+              <div @click="goSetTime(dayInfo)">
+                <el-col :span="3">{{ $t('permission.time_range') }}</el-col>
+                <el-col :span="20">{{ dayInfo.timeArr ? dayInfo.timeArr : '-' }}</el-col>
+                <el-col :span="1"><img src="../../assets/right.png" alt=""></el-col>
+              </div>
+            </el-col>
+          </el-row>
+          <el-row class="the-week-box" v-if="radio == 3">
+            <el-col :span="24" v-for="theDay in weeks" :key="theDay.id">
+              <div @click="goSetTime(theDay)">
+                <el-col :span="3">{{ theDay.label }}</el-col>
+                <el-col :span="20">{{ theDay.timeArr ? theDay.timeArr : '-' }}</el-col>
+                <el-col :span="1"><img src="../../assets/right.png" alt=""></el-col>
+              </div>
+            </el-col>
+          </el-row>
+        </el-form-item>
+      </el-form>
+      <div class="dialog-footer">
+        <el-button @click="handleClose" style="color:#1D2129;">{{ $t('common.cancel') }}</el-button>
+        <el-button type="primary" @click="doSubmit">{{ $t('common.confirm') }}</el-button>
+      </div>
+    </el-dialog>
+    <!-- 璁剧疆鏃堕棿娈� -->
+    <el-dialog append-to-body modal-append-to-body :title="title" :visible.sync="timeAreaVisible" width="500px"
+      :before-close="cancelTimeAdd">
+      <el-form label-position="right" label-width="30px">
+        <div>{{ $t('permission.timePeriod') }}
+          <el-button type="success" :disabled="timeArr.length >= 5" style="float: right;" size="mini"
+            icon="el-icon-s-grid" @click="addTime">{{ $t('permission.addTimePeriod') }}</el-button>
+        </div>
+        <el-form-item v-for="(item, index) in timeArr" :key="index" :label="index + 1 + ''">
+          <el-time-picker :data-num="index" :default-value="['00:00', '23:59']" :clearable="false" :key="index"
+            @focus="onTimePicker" @change="theTimeChange" size="mini" style="width:75%;" is-range value-format="HH:mm"
+            format="HH:mm" v-model="item.theTime" :range-separator="$t('common.to')"
+            :start-placeholder="$t('common.startTime')" :end-placeholder="$t('common.endTime')"
+            :placeholder="$t('placeholder.placeholder_choose_time_priod')">
+          </el-time-picker>
+          <el-button style="margin-left:20px" type="text" icon="el-icon-circle-close"
+            @click.prevent="removeTime(index)">{{ $t('common.delete') }}</el-button>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button style="color:#1D2129;" @click="cancelTimeAdd">{{ $t('common.cancel') }}</el-button>
+        <el-button type="primary" @click="confirmTimeAdd">{{ $t('common.confirm') }}</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import Table from "@/components/table/tableList";
+import { parseTime, generateRandomString } from "@/utils/index.js"
+export default {
+  props: {
+    formData: {
+      type: Object,
+      default: () => ({})
+    },
+    addOrEditType: {
+      type: String,
+      default: 'add'
+    }
+  },
+  components: {
+    Table
+  },
+  data () {
+    return {
+      localForm: {},
+      permissionIds: [],
+      curPermissionId: '',
+      tableHeader: [
+        {
+          label: this.$t('permission.permissionId'),
+          list: 'permissionId',
+          overflowShow: 'hidden',
+          width: '150px'
+        },
+        {
+          label: this.$t('permission.effectiveType'),
+          type: 'html',
+          overflowShow: 'hidden',
+          width: '100px',
+          code: (row) => {
+            let type = row.time.type
+            switch (type) {
+              case 0:
+                return this.$t('permission.unlimitedMode')
+              case 1:
+                return this.$t('permission.usualMode')
+              case 2:
+                return this.$t('permission.dailyMode')
+              case 3:
+                return this.$t('permission.weeklyRepetitionMode')
+            }
+          }
+        },
+        {
+          label: this.$t('permission.effectiveTime'),
+          type: 'html',
+          overflowShow: 'hidden',
+          code: (row) => {
+            let type = row.time.type
+            if (type == 0) {
+              return '-'
+            } else {
+              let { beginTime, endTime } = row.time.range
+              return `${parseTime(beginTime * 1000)} ~ ${parseTime(endTime * 1000)}`
+            }
+          }
+        },
+        {
+          label: this.$t('permission.effectiveWeek'),
+          type: 'html',
+          overflowShow: 'hidden',
+          code: (row) => {
+            let type = row.time.type
+            switch (type) {
+              case 0:
+                return '-'
+              case 1: {
+                return '-'
+              }
+              case 2: {
+                let dayPeriodTime = row.time.dayPeriodTime
+                let times = dayPeriodTime.split('|')
+                if (times.length === 0) return '-';
+                times = times.map(v => `<div>${v}<div>`)
+                return times.join("");
+              }
+              case 3: {
+                let weekPeriodTime = row.time.weekPeriodTime
+                const weekDays = [this.$t('common.monday'), this.$t('common.tuseday'), this.$t('common.wednesday'), this.$t('common.thursday'), this.$t('common.friday'), this.$t('common.saterday'), this.$t('common.sunday')];
+                let days = [];
+                for (let i = 1; i <= 7; i++) {
+                  const dayKey = String(i);
+                  if (weekPeriodTime[dayKey]) {
+                    days.push(`${weekDays[i - 1]}锛� ${weekPeriodTime[dayKey]}`);
+                  }
+                }
+                if (days.length === 0) return '-';
+                days = days.map(v => `<div>${v}<div>`)
+                return days.join("");
+              }
+              default:
+                break;
+            }
+          }
+        },
+        // {
+        //   label: this.$t('permission.extra'),
+        //   type: 'html',
+        //   overflowShow: 'hidden',
+        //   code: (row) => {
+        //     if (row.extra) {
+        //       return row.extra
+        //     } else {
+        //       return '-'
+        //     }
+        //   }
+        // },
+      ],
+      tableOption: {
+        label: this.$t('common.operation'),
+        width: "100px",
+        value: 0,
+        options: [
+          {
+            label: this.$t('common.edit'),
+            key: 1,
+            type: "text",
+            State: true,
+            method: (row) => {
+              this.operationType = 'edit'
+              this.handleEdit({ ...row })
+            },
+          },
+          {
+            label: this.$t('common.delete'),
+            key: 1,
+            type: "text",
+            State: true,
+            method: (row) => {
+              this.handleDelete(row.permissionId)
+            },
+          }
+        ]
+      },
+      tableData: [],
+      timeRange: ['00:00', '23:59'],
+      visible: false,
+      timeVisible: false,
+      timeAreaVisible: false,
+      chooseWeeks: [],
+      radio: 0,
+      title: "",
+      currentId: "",
+      dateTimes: [],
+      times: [],
+      nowTimeVal: [],
+      nowTimeIndex: 9,
+      count: '',
+      timeType: 'day',
+      dayInfo: {
+        timeArr: '',
+      },
+      initWeeks: [
+        { label: this.$t('common.monday'), id: '1', timeArr: '' },
+        { label: this.$t('common.tuseday'), id: '2', timeArr: '' },
+        { label: this.$t('common.wednesday'), id: '3', timeArr: '' },
+        { label: this.$t('common.thursday'), id: '4', timeArr: '' },
+        { label: this.$t('common.friday'), id: '5', timeArr: '' },
+        { label: this.$t('common.saterday'), id: '6', timeArr: '' },
+        { label: this.$t('common.sunday'), id: '7', timeArr: '' }
+      ],
+      weeks: [],
+      timeArr: [],
+      operationType: 'add'
+    }
+  },
+  created () {
+    this.weeks = [...this.initWeeks]
+    this.getUser()
+  },
+  mounted () { },
+  methods: {
+    openTimeDialog () {
+      this.timeVisible = true
+      this.operationType = 'add'
+    },
+
+    handleClose () {
+      this.weeks = [...this.initWeeks]
+      this.chooseWeeks.splice(0)
+      this.radio = 0
+      this.dateTimes.splice(0)
+      this.times.splice(0)
+      this.timeVisible = false
+    },
+
+    doClose () {
+      this.$emit('close-drawer', false);
+    },
+
+    async getUser () {
+      try {
+        let data = {
+          userId: this.formData.userId,
+          page: 0,
+          size: 99
+        }
+        const res = await this.$http.post('/getUser', { data })
+        if (res.code == 200) {
+          console.log(res)
+          let { userId, name, extra, permissionIds } = res.data.content[0]
+          this.localForm.userId = userId
+          this.localForm.name = name
+          this.localForm.extra = extra ? JSON.parse(extra) : ""
+          this.permissionIds = permissionIds ? permissionIds.split(',') : []
+          this.getPermission()
+        } else {
+          this.$message.error(res.message);
+        }
+      } catch (even) {
+        console.log(even)
+      }
+    },
+
+    getPermission () {
+      let that = this
+      this.tableData = []
+      if (this.permissionIds) {
+        this.permissionIds.forEach(async v => {
+          let data = {
+            page: 0,
+            size: 100,
+            permissionId: v
+          }
+          try {
+            const res = await that.$http.post('/getPermission', { data })
+            if (res.code == 200) {
+              that.tableData = that.tableData.concat(res.data.content)
+            } else {
+              that.$message.error(res.message)
+            }
+          } catch (even) {
+            console.log(even);
+          }
+        })
+      }
+    },
+
+    handleEdit (row) {
+      console.log(row)
+      this.curPermissionId = row.permissionId
+      this.radio = row.time.type
+      if (row.time.type != 0) {
+        let { beginTime, endTime } = row.time.range
+        this.dateTimes = [beginTime * 1000, endTime * 1000]
+      }
+      if (row.time.type == 2) {
+        this.dayInfo.timeArr = row.time.dayPeriodTime
+      }
+      if (row.time.type == 3) {
+        let weekPeriodTime = row.time.weekPeriodTime
+        this.weeks = this.initWeeks.map(week => ({
+          ...week,
+          timeArr: weekPeriodTime[week.id] || ''
+        }))
+      }
+      this.timeVisible = true
+    },
+
+    handleDelete (permissionId) {
+      let that = this
+      this.$confirm(
+        this.$t('common.deleteTips'),
+        this.$t('common.tips'),
+        {
+          confirmButtonText: this.$t('common.confirm'),
+          cancelButtonText: this.$t('common.cancel'),
+          type: 'warning'
+        }
+      ).then(async () => {
+        try {
+          const res = await that.$http.post("delPermission", {
+            data: {
+              permissionIds: [permissionId]
+            }
+          })
+          if (res.code == 200) {
+            that.$message.success(this.$t('common.deleteSuccess'))
+            that.updatePerson('delete', permissionId)
+          } else {
+            that.$message.error(res.message)
+          }
+        } catch (even) {
+          console.log(even)
+        }
+      }).catch(() => { })
+    },
+
+    handleAddClose () {
+      this.$emit('close-drawer', false);
+    },
+
+    async doSubmit () {
+      if (!this.formData.userId) {
+        this.$message.error(this.$t('person.userNotExist'))
+        return false
+      }
+      const that = this
+      let theData = {
+        time: {
+          type: this.radio
+        }
+      }
+      switch (that.radio) {
+        case 1:
+          if (!that.dateTimes.length) {
+            that.$message.warning(this.$t('permission.choose_time_range'));
+            return false
+          }
+          theData.time.range = {
+            beginTime: new Date(that.dateTimes[0]).getTime() / 1000,
+            endTime: new Date(that.dateTimes[1]).getTime() / 1000
+          }
+          console.log(theData);
+
+          break;
+        case 2:
+          if (that.dateTimes.length === 0) {
+            that.$message.warning(this.$t('power.choose_time_range'));
+            return false
+          }
+          theData.time.range = {
+            beginTime: new Date(that.dateTimes[0]).getTime() / 1000,
+            endTime: new Date(that.dateTimes[1]).getTime() / 1000
+          }
+          theData.time.dayPeriodTime = that.dayInfo.timeArr
+          console.log(theData);
+          break
+        case 3: {
+          if (that.dateTimes.length === 0) {
+            that.$message.warning(this.$t('power.choose_time_range'));
+            return false
+          }
+          theData.time.range = {
+            beginTime: new Date(that.dateTimes[0]).getTime() / 1000,
+            endTime: new Date(that.dateTimes[1]).getTime() / 1000
+          }
+          let obj = {}
+          this.weeks.forEach(item => {
+            if (item?.timeArr) {
+              obj[item.id] = item.timeArr
+            }
+          })
+          theData.time.weekPeriodTime = obj
+          console.log(theData);
+          break;
+        }
+      }
+      if (this.operationType == 'add') {
+        try {
+          theData.permissionId = generateRandomString()
+          const res = await this.$http.post('/insertPermission', { data: [theData] })
+          if (res.code == 200) {
+            this.$message.success(this.$t('common.addSuccess'))
+            this.timeVisible = false
+            this.updatePerson('add', theData.permissionId)
+          } else {
+            if (res.data && res.data[0]) {
+              this.$message.error(res.data[0].errmsg)
+            }
+          }
+        } catch (even) {
+          console.log(even);
+        }
+      } else if (this.operationType == 'edit') {
+        try {
+          theData.permissionId = this.curPermissionId
+          const res = await this.$http.post('/modifyPermission', { data: [theData] })
+          if (res.code == 200) {
+            this.$message.success(this.$t('common.editSuccess'))
+            this.timeVisible = false
+            this.getPermission()
+          } else {
+            if (res.data && res.data[0]) {
+              this.$message.error(res.data[0].errmsg)
+            }
+          }
+        } catch (even) {
+          console.log(even);
+        }
+      }
+    },
+
+    async updatePerson (type, permissionId) {
+      let data = {}
+      data.userId = this.localForm.userId
+      data.name = this.localForm.name
+      data.extra = this.localForm.extra
+      if (type == 'add') {
+        data.permissionIds = this.permissionIds && this.permissionIds.length ? this.permissionIds.concat([permissionId]) : [permissionId]
+      } else if (type == 'delete') {
+        data.permissionIds = this.permissionIds && this.permissionIds.length ? this.permissionIds.filter(v => v != permissionId) : []
+      }
+      const res = await this.$http.post(
+        "/modifyUser",
+        { data: [data] }
+      );
+      if (res.code == 200) {
+        this.permissionIds = [...data.permissionIds]
+        this.getPermission()
+        this.$emit("operation-success", {...data, permissionIds: data.permissionIds ? data.permissionIds.join(',') : ''})
+      } else {
+        this.$message.error(res.message)
+      }
+    },
+
+    getSecondsFromMidnight (timeStr) {
+      const [hours, minutes] = timeStr.split(':').map(Number);
+      return hours * 3600 + minutes * 60;
+    },
+
+    // 璁剧疆鏃堕棿娈�
+    goSetTime (theDay) {
+      this.timeAreaVisible = true
+      this.timeArr.splice(0)
+      if (theDay.timeArr !== '') {
+        let aaa = theDay.timeArr.split('|')
+        aaa.forEach(item => {
+          this.timeArr.push({
+            theTime: [item.split('-')[0], item.split('-')[1]]
+          })
+        })
+      }
+      this.currentId = theDay.id
+      this.title = theDay.label
+    },
+
+    // 娣诲姞鏃舵
+    addTime () {
+      if (this.timeArr.length > 0) {
+        let lastTime = this.timeArr[this.timeArr.length - 1].theTime
+        if (lastTime[0] === '00:00' && lastTime[1] === '23:59') {
+          this.$message.warning(this.$t('permission.modify_previous_time'))
+          return false
+        }
+      }
+      this.timeArr.push({ theTime: ['00:00', '23:59'] })
+    },
+
+    // 鍒犻櫎鏃舵
+    removeTime (index) {
+      this.timeArr.splice(index, 1)
+    },
+
+    onTimePicker (val) {
+      if (val.$attrs['data-num'] !== this.nowTimeIndex) {
+        setTimeout(() => {
+          this.nowTimeIndex = val.$attrs['data-num']
+          this.nowTimeVal = val.value
+        }, 300)
+      }
+    },
+
+    // 鏃堕棿娈垫牎楠�
+    async theTimeChange (val) {
+      const [startTime, endTime] = val;
+      // 鏍¢獙寮�濮嬫椂闂翠笉鑳芥櫄浜庢垨绛変簬缁撴潫鏃堕棿
+      if (this.toChangeNumber(startTime) >= this.toChangeNumber(endTime)) {
+        this.timeArr[this.nowTimeIndex].theTime = this.nowTimeVal;
+        this.$message.warning(this.$t('permission.cannot_be_earlier'));
+        this.resetTimeSelection();
+        return;
+      }
+      // 妫�鏌ユ椂闂存鏄惁涓庡叾浠栨椂闂存閲嶅彔
+      const hasOverlap = this.timeArr.some((item, index) =>
+        index !== this.nowTimeIndex && this.isCross(item.theTime, val)
+      );
+      if (hasOverlap) {
+        this.timeArr[this.nowTimeIndex].theTime = this.nowTimeVal;
+        this.$message.warning(this.$t('permission.times_cannot_overlap'));
+      }
+      this.$nextTick(() => {
+        this.nowTimeIndex = 9
+        this.nowTimeVal = []
+      })
+    },
+
+    // 杞崲涓烘暟瀛�
+    toChangeNumber (str) {
+      let theList = str.split(':')
+      return theList[0] * 60 + (theList[1] - 0)
+    },
+
+    // 鍒ゆ柇鏄惁浜ゅ弶
+    isCross (data1, data2) {
+      const toMinutes = (str) => {
+        const [hours, minutes] = str.split(':').map(Number);
+        return hours * 60 + minutes;
+      };
+      const [start1, end1] = data1.map(toMinutes);
+      const [start2, end2] = data2.map(toMinutes);
+      // 鐩存帴鍒ゆ柇閲嶅彔鏉′欢锛氫袱涓尯闂存湁浜ら泦
+      return start1 < end2 && start2 < end1;
+    },
+
+    // 鍙栨秷娣诲姞鏃舵
+    cancelTimeAdd () {
+      this.timeArr.splice(0)
+      this.timeAreaVisible = false
+    },
+
+    confirmTimeAdd () {
+      let that = this
+      if (that.timeArr.length > 1) {
+        // 妫�鏌ユ渶鍚庝竴缁勬槸鍚︿笌鍓嶉潰浠讳綍涓�缁勫瓨鍦ㄤ氦鍙�
+        let lastTime = that.timeArr[that.timeArr.length - 1].theTime
+        const hasCrossWithAnyPrevious = that.timeArr
+          .slice(0, -1)  // 鎺掗櫎鏈�鍚庝竴缁�
+          .some(item => that.isCross(item.theTime, lastTime));
+        if (hasCrossWithAnyPrevious) {
+          that.$message.warning(this.$t('permission.times_cannot_overlap'));
+          return false;
+        }
+      }
+      if (this.radio == 2) {
+        this.dayInfo.timeArr = this.timeArr.map(item => item.theTime.join('-')).join('|')
+      } else {
+        let timeLabel = []
+        if (that.timeArr.length > 0) {
+          that.timeArr.forEach(item => {
+            timeLabel.push(item.theTime[0] + '-' + item.theTime[1])
+          })
+        }
+        that.weeks.map(item => {
+          if (item.id === that.currentId) {
+            item.timeArr = timeLabel.join('|')
+          }
+        })
+      }
+      that.cancelTimeAdd()
+    },
+  }
+}
+</script>
+<style lang='less' scoped>
+::v-deep .el-dialog__header {
+  text-align: center !important;
+}
+
+.dialog-footer {
+  text-align: center;
+}
+
+.tagStyle {
+  cursor: pointer;
+}
+
+::v-deep .el-tag--plain,
+.el-tag--dark {
+  width: 60px;
+  height: 40px;
+  font-size: 16px;
+  text-align: center;
+  line-height: 40px;
+}
+
+.the-week-box {
+  position: relative;
+
+  .el-col-24 {
+    padding: 0 10px;
+    background-color: #eeeeee80;
+    height: 50px;
+    line-height: 50px;
+    margin-top: 10px;
+    overflow: hidden;
+    border-radius: 6px;
+    cursor: pointer;
+
+    &:hover {
+      background-color: #eeeeee;
+    }
+  }
+
+  img {
+    margin-top: 15px;
+    width: 20px;
+    height: 20px;
+  }
+}
+
+.weeks:hover {
+  background: #f5f7fa;
+}
+
+::v-deep .el-range-separator {
+  width: 8% !important;
+}
+</style>
\ No newline at end of file
diff --git "a/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/views/person/vourcher.vue" "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/views/person/vourcher.vue"
new file mode 100644
index 0000000..6123137
--- /dev/null
+++ "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/views/person/vourcher.vue"
@@ -0,0 +1,1026 @@
+<template>
+  <div>
+    <div class="drawContent">
+      <!-- 鍑瘉绫诲瀷閫夋嫨 -->
+      <el-tabs v-model="activeTab" class="voucher-tabs">
+        <!-- 瀵嗙爜鍑瘉 -->
+        <el-tab-pane name="password" :label="$t('voucher.password')">
+          <div class="tab-content">
+            <el-form ref="passwordForm" :model="form" :rules="rules">
+              <el-form-item prop="password">
+                <el-input v-model="form.password" type="text" :placeholder="$t('voucher.validPassword')" maxlength="6"
+                  show-word-limit clearable>
+                </el-input>
+              </el-form-item>
+            </el-form>
+          </div>
+        </el-tab-pane>
+
+        <!-- 鍗$墖鍑瘉 -->
+        <el-tab-pane name="card" :label="$t('voucher.card')">
+          <div class="tab-content">
+            <el-form ref="cardForm" :model="form" :rules="rules">
+              <el-form-item prop="card">
+                <el-input v-model="form.card" :placeholder="$t('voucher.validCard')" clearable></el-input>
+              </el-form-item>
+            </el-form>
+          </div>
+        </el-tab-pane>
+
+        <!-- 浜鸿劯鍑瘉 -->
+        <el-tab-pane name="face" :label="$t('voucher.face')">
+          <div class="tab-content face-tab">
+            <!-- 娉ㄥ唽鏂瑰紡閫夋嫨 -->
+            <div class="register-type-selector">
+              <el-radio-group v-model="faceType" @change="handleRegisterTypeChange">
+                <el-radio-button :label="0">{{ $t('voucher.photoRegistration') }}</el-radio-button>
+                <el-radio-button :label="1">{{ $t('voucher.featureValueRegistration') }}</el-radio-button>
+              </el-radio-group>
+            </div>
+
+            <!-- 鐓х墖涓婁紶娉ㄥ唽 -->
+            <div v-if="faceType == 0" class="photo-register">
+              <div class="upload-area">
+                <el-upload class="avatar-uploader" action="#" :show-file-list="false" accept=".jpg,.jpeg" :on-change="handleUploadChange"
+                  :auto-upload="false">
+                  <img v-if="faceImage" :src="faceImage" class="avatar" />
+                  <i v-else class="el-icon-plus avatar-uploader-icon"></i>
+                  <!-- 娓呴櫎鎸夐挳 -->
+                  <el-button v-if="faceImage" class="clear-btn" type="danger" icon="el-icon-delete" circle
+                    @click.stop="clearImage"></el-button>
+                </el-upload>
+              </div>
+            </div>
+
+            <!-- 鐗瑰緛鍊兼敞鍐� -->
+            <div v-if="faceType == 1" class="feature-register">
+              <div class="feature-input-area">
+                <el-input type="textarea" clearable :rows="6" :placeholder="$t('common.placeholder')"
+                  v-model="faceFeature" class="feature-textarea">
+                </el-input>
+              </div>
+            </div>
+          </div>
+        </el-tab-pane>
+
+        <!-- 鎸囩汗鍑瘉 -->
+        <el-tab-pane v-if="fingerprintEnabled" name="fingerprint" :label="$t('voucher.finger')">
+          <div class="tab-content fingerprint-tab">
+            <!-- 娉ㄥ唽鏂瑰紡閫夋嫨 -->
+            <div class="register-type-selector">
+              <el-radio-group v-model="fingerprintType" @change="handleFingerprintTypeChange">
+                <el-radio-button :label="0">{{ $t('voucher.fingerRegistration') }}</el-radio-button>
+                <el-radio-button :label="1">{{ $t('voucher.fingerFeatureRegistration') }}</el-radio-button>
+              </el-radio-group>
+            </div>
+
+            <!-- 鎸囩汗褰曞叆 -->
+            <div v-if="fingerprintType == 0" class="fingerprint-capture">
+              <div class="capture-area">
+                <div class="fingerprint-status">
+                  <i :class="fingerprintStatusIcon" class="status-icon"></i>
+                  <p class="status-text">{{ fingerprintStatusText }}</p>
+                </div>
+                <el-button 
+                  type="primary" 
+                  :loading="fingerprintLoading" 
+                  :disabled="fingerprintLoading"
+                  @click="enrollFinger">
+                  {{ fingerprintLoading ? $t('voucher.fingerInputting') : (hasFingerprint ? $t('voucher.fingerReInput') : $t('voucher.startFingerInput')) }}
+                </el-button>
+                <div v-if="fingerprintLoading" class="capture-tips">
+                  <p>{{ $t('voucher.fingerInput') }}</p>
+                  <p class="timeout-text">{{ $t('voucher.fingerRemainingTime') }}: {{ fingerprintTimeout }}S</p>
+                </div>
+              </div>
+            </div>
+
+            <!-- 鐗瑰緛鍊兼敞鍐� -->
+            <div v-if="fingerprintType == 1" class="feature-register">
+              <div class="feature-input-area">
+                <el-input type="textarea" clearable :rows="6" :placeholder="$t('voucher.fingerInputTips')"
+                  v-model="fingerprintFeature" class="feature-textarea">
+                </el-input>
+              </div>
+            </div>
+          </div>
+        </el-tab-pane>
+
+        <!-- PIN鐮佸嚟璇� -->
+        <el-tab-pane name="code" :label="$t('voucher.code')" v-if="model == 'vf105' || model == 'vf114'">
+          <Table :table-label="tableHeader" :table-data="tableData" :table-option="tableOption"></Table>
+        </el-tab-pane>
+      </el-tabs>
+    </div>
+
+    <!-- 鎿嶄綔鎸夐挳 -->
+    <div class="dialog-footer">
+      <el-button type="warning" @click="handleAddClose">
+        {{ $t('common.cancel') }}
+      </el-button>
+      <el-button v-if="activeTab != 'code'" type="primary" :loading="isLoading" :disabled="isLoading" @click="addConfirm">
+        {{ $t('common.confirm') }}
+      </el-button>
+    </div>
+  </div>
+</template>
+
+<script>
+import Table from "@/components/table/tableList";
+import { generateRandomString, throttle } from '@/utils/index.js'
+export default {
+  props: {
+    formData: {
+      type: Object,
+      default: () => ({})
+    },
+    addOrEditType: {
+      type: String,
+      default: 'add'
+    },
+  },
+  components: {
+    Table
+  },
+  data () {
+    return {
+      visible: false,
+      userId: '',
+      name: '',
+      form: {
+        password: '',
+        card: '',
+        face: '',
+        fingerprint: '',
+        // code100: '',
+        // code101: '',
+        // code103: '',
+        oldPassword: '',
+        oldCard: '',
+        oldFace: '',
+        oldFingerprint: '',
+        // oldCode100: '',
+        // oldCode101: '',
+        // oldCode103: ''
+      },
+      keyId: {
+        password: '',
+        card: '',
+        face: '',
+        fingerprint: '',
+        // code100: '',
+        // code101: '',
+        // code103: '',
+      },
+      rules: {
+        password: [{ message: this.$t('voucher.validPassword'), trigger: ["blur"], pattern: /^\d{6}$/ }],
+        card: [{ message: this.$t('voucher.validCard'), trigger: ["blur"], pattern: /^[0-9a-zA-Z]+$/ },],
+      },
+      model: '',
+      isLoading: false,
+      // 鍑瘉鏁版嵁
+      activeTab: 'password',
+      faceType: 0, // 娉ㄥ唽鏂瑰紡:0-鐓х墖娉ㄥ唽,1-鐗瑰緛鍊兼敞鍐�
+      faceImage: '', // 浜鸿劯鍥剧墖 base64 鎴� URL
+      faceFeature: '', // 浜鸿劯鐗瑰緛鍊�
+      originalFaceData: null, // 瀛樺偍鍘熷浜鸿劯鏁版嵁,鐢ㄤ簬鍒ゆ柇鏄惁淇敼
+      
+      // 鎸囩汗鐩稿叧鏁版嵁
+      fingerprintType: 0, // 娉ㄥ唽鏂瑰紡:0-鎸囩汗褰曞叆,1-鐗瑰緛鍊兼敞鍐�
+      fingerprintFeature: '', // 鎸囩汗鐗瑰緛鍊�
+      fingerprintLoading: false, // 鎸囩汗褰曞叆鍔犺浇鐘舵��
+      fingerprintTimeout: 60, // 鎸囩汗褰曞叆瓒呮椂鏃堕棿
+      fingerprintTimer: null, // 鎸囩汗褰曞叆瀹氭椂鍣�
+      fingerprintPollTimer: null, // 鎸囩汗褰曞叆杞瀹氭椂鍣�
+      fingerprintStatusText: '绛夊緟褰曞叆', // 鎸囩汗鐘舵�佹枃鏈�
+      fingerprintStatusIcon: 'el-icon-fingerprint', // 鎸囩汗鐘舵�佸浘鏍�
+      originalFingerprintData: null, // 瀛樺偍鍘熷鎸囩汗鏁版嵁,鐢ㄤ簬鍒ゆ柇鏄惁淇敼
+      hasFingerprint: false, // 鏄惁宸叉湁鎸囩汗鍑瘉
+      tableHeader: [
+        {
+          label: this.$t('voucher.credentialId'),
+          list: 'keyId',
+        },
+        {
+          label: this.$t('voucher.codeType'),
+          list: 'type',
+        },
+        {
+          label: this.$t('voucher.credentialValue'),
+          list: 'code',
+        },
+      ],
+      tableOption: {
+        label: this.$t('common.operation'),
+        width: "100px",
+        value: 0,
+        options: [
+          {
+            label: this.$t('common.delete'),
+            key: 1,
+            type: "text",
+            State: true,
+            method: (row) => {
+              this.handleDeleteCode(row.keyId)
+            },
+          }
+        ]
+      },
+      tableData: [],
+    };
+  },
+  created () {
+    this.initialForm = JSON.parse(JSON.stringify(this.form));
+    this.initialKeyId = JSON.parse(JSON.stringify(this.keyId));
+    this.userId = this.formData.userId
+    let publicConfig = sessionStorage.getItem('publicConfig')
+    let { finger, model } = publicConfig ? JSON.parse(publicConfig) : {}
+    this.fingerprintEnabled = finger
+    this.model = model
+    this.getVoucher()
+  },
+  beforeDestroy() {
+    // 娓呯悊瀹氭椂鍣�
+    this.interruptFinger()
+    this.clearFingerprintTimers()
+  },
+  methods: {
+    // 鏌ヨ鍑瘉
+    async getVoucher () {
+      let data = {
+        page: 0,
+        size: 100,
+        userId: this.userId
+      }
+      try {
+        const res = await this.$http.post('/getKey', { data })
+        if (res.code == 200) {
+          console.log(res)
+          let content = res.data.content
+          let card = content.filter(v => v.type == 200)[0]
+          if (card) {
+            this.form.card = card.code
+            this.form.oldCard = card.code
+            this.keyId.card = card.keyId
+          } else {
+            this.keyId.card = ''
+          }
+          let face = content.filter(v => v.type == 300)[0]
+          if (face) {
+            // 淇濆瓨鍘熷浜鸿劯鏁版嵁
+            let faceType = face.extra ? JSON.parse(face.extra).faceType : 0
+            this.originalFaceData = {
+              keyId: face.keyId,
+              code: face.code,
+              faceType
+            }
+            if (face.extra) {
+              if (faceType == 0) {
+                this.faceImage = "data:image/jpeg;base64," + face.code
+              } else if (faceType == 1) {
+                this.faceFeature = face.code
+              }
+              this.faceType = faceType
+            }
+            this.form.face = face.code
+            this.form.oldFace = face.code
+            this.keyId.face = face.keyId
+          } else {
+            this.keyId.face = ''
+            this.originalFaceData = null
+          }
+          let password = content.filter(v => v.type == 400)[0]
+          if (password) {
+            this.form.password = password.code
+            this.form.oldPassword = password.code
+            this.keyId.password = password.keyId
+          } else {
+            this.keyId.password = ''
+          }
+          
+          // 澶勭悊鎸囩汗鍑瘉
+          let fingerprint = content.filter(v => v.type == 500)[0]
+          if (fingerprint) {
+            let fingerprintType = fingerprint.extra ? JSON.parse(fingerprint.extra).fingerprintType : 0
+            this.originalFingerprintData = {
+              keyId: fingerprint.keyId,
+              code: fingerprint.code,
+              fingerprintType
+            }
+            // 濡傛灉宸叉湁鎸囩汗鍑瘉锛岄粯璁ゆ樉绀烘寚绾瑰綍鍏ラ〉闈紙fingerprintType = 0锛�
+            // 浣嗕繚鐣欏師濮� fingerprintType 鐢ㄤ簬鍒ゆ柇鏄惁淇敼
+            this.fingerprintType = 0
+            this.hasFingerprint = true
+            // 濡傛灉鍘熷鏄壒寰佸�兼敞鍐岋紝淇濆瓨鐗瑰緛鍊肩敤浜庢樉绀�
+            if (fingerprint.extra && fingerprintType == 1) {
+              this.fingerprintFeature = fingerprint.code
+            }
+            this.form.fingerprint = fingerprint.code
+            this.form.oldFingerprint = fingerprint.code
+            this.keyId.fingerprint = fingerprint.keyId
+            // 璁剧疆鐘舵�佹枃鏈负"鎸囩汗宸插綍鍏�"
+            this.fingerprintStatusText = this.$t('voucher.fingerInputed')
+            this.fingerprintStatusIcon = 'el-icon-success'
+          } else {
+            this.keyId.fingerprint = ''
+            this.originalFingerprintData = null
+            this.hasFingerprint = false
+            // 閲嶇疆鐘舵�佹枃鏈�
+            this.fingerprintStatusText = this.$t('voucher.fingerWaitInput')
+            this.fingerprintStatusIcon = 'el-icon-fingerprint'
+          }
+
+          this.tableData = content.filter(v => v.type == 100 || v.type == 101 || v.type == 103)
+          console.log(this.tableData)
+        } else {
+          this.$message.error(res.message)
+        }
+      } catch (even) {
+        console.log(even);
+      }
+    },
+
+    // 澶勭悊娉ㄥ唽鏂瑰紡鍙樺寲
+    handleRegisterTypeChange (value) {
+      console.log('鍒囨崲娉ㄥ唽鏂瑰紡:', value);
+    },
+
+    // 澶勭悊鎸囩汗娉ㄥ唽鏂瑰紡鍙樺寲
+    handleFingerprintTypeChange (value) {
+      console.log('鍒囨崲鎸囩汗娉ㄥ唽鏂瑰紡:', value);
+      // 娓呯悊瀹氭椂鍣�
+      this.clearFingerprintTimers()
+      // 鏍规嵁鏄惁宸叉湁鎸囩汗鍑瘉璁剧疆鐘舵�佹枃鏈�
+      if (value === 0) {
+        this.fingerprintStatusText = this.hasFingerprint ? this.$t('voucher.fingerInputed') : this.$t('voucher.fingerWaitInput')
+        this.fingerprintStatusIcon = this.hasFingerprint ? 'el-icon-success' : 'el-icon-fingerprint'
+      } else {
+        this.fingerprintStatusText = this.$t('voucher.fingerWaitInput')
+        this.fingerprintStatusIcon = 'el-icon-fingerprint'
+      }
+    },
+
+    // 娓呴櫎瀹氭椂鍣�
+    clearFingerprintTimers() {
+      if (this.fingerprintTimer) {
+        clearInterval(this.fingerprintTimer)
+        this.fingerprintTimer = null
+      }
+      if (this.fingerprintPollTimer) {
+        clearInterval(this.fingerprintPollTimer)
+        this.fingerprintPollTimer = null
+      }
+    },
+
+    // 寮�濮嬫寚绾瑰綍鍏�
+    async enrollFinger() {
+      if (!this.fingerprintEnabled) {
+        this.$message.warning('褰撳墠璁惧涓嶆敮鎸佹寚绾规搷浣�')
+        return
+      }
+      if (!this.userId) {
+        this.$message.error(this.$t('person.userNotExist'))
+        return false
+      }
+      this.fingerprintLoading = true
+      this.fingerprintTimeout = 60
+      this.fingerprintStatusText = this.$t('voucher.fingerInputNow')
+      this.fingerprintStatusIcon = 'el-icon-loading'
+
+      try {
+        // 鍙戦�佹寚绾瑰綍鍏ユ寚浠�
+        const startRes = await this.$http.post('/control', {
+          data: {
+            command: 12,
+            extra: {
+              userId: this.userId,
+              fingerprintAction: 0,
+              isRemote: false
+            },  
+          }
+        })
+
+        if (startRes.code !== 200) {
+          this.$message.error(startRes.message || this.$t('voucher.fingerInputFailed'))
+          this.resetFingerprintStatus()
+          return
+        }
+
+        // 寮�濮嬪�掕鏃�
+        this.fingerprintTimer = setInterval(() => {
+          this.fingerprintTimeout--
+          if (this.fingerprintTimeout <= 0) {
+            this.handleFingerprintTimeout()
+          }
+        }, 1000)
+
+        // 寮�濮嬭疆璇㈡煡璇㈡寚绾瑰綍鍏ョ粨鏋�
+        this.fingerprintPollTimer = setInterval(async () => {
+          await this.checkFingerprintResult()
+        }, 500) // 姣�0.5绉掓煡璇竴娆�
+
+      } catch (error) {
+        console.error('鎸囩汗褰曞叆澶辫触:', error)
+        this.$message.error(this.$t('voucher.fingerReTry'))
+        this.resetFingerprintStatus()
+      }
+    },
+
+    // 涓柇鎸囩汗褰曞叆
+    async interruptFinger () {
+      if (!this.fingerprintLoading) return
+      try {
+        await this.$http.post('/control', {
+          data: {
+            command: 12,
+            extra: {
+              fingerprintAction: 1
+            }
+          }
+        })
+      } catch (error) {
+        console.error('涓柇鎸囩汗閲囬泦澶辫触:', error)
+      } finally {
+        this.fingerprintLoading = false
+        this.clearFingerprintTimers()
+      }
+    },
+
+    // 鏌ヨ鎸囩汗褰曞叆缁撴灉
+    async checkFingerprintResult() {
+      try {
+        const res = await this.$http.post('/getFingerChar', {
+          data: {
+            userId: this.userId
+          }
+        })
+
+        if (res.code === 200 && res.data && typeof res.data.ret == 'string') {
+          // 褰曞叆鎴愬姛锛屽皢鐗瑰緛鍊煎~鍏呭埌form.fingerprint鍜宖ingerprintFeature
+          const featureValue = res.data.ret
+          this.form.fingerprint = featureValue
+          this.fingerprintFeature = featureValue
+          
+          this.fingerprintStatusText = this.$t('voucher.fingerInputSuccess')
+          this.fingerprintStatusIcon = 'el-icon-success'
+          this.$message.success(this.$t('voucher.fingerFilled'))
+          this.resetFingerprintStatus(false)
+          
+          // 鏍囪宸叉湁鎸囩汗鍑瘉
+          this.hasFingerprint = true
+          
+          // 褰曞叆鎴愬姛鍚庯紝鑷姩鍒囨崲鍒扮壒寰佸�兼敞鍐屾ā寮忥紝灞曠ず閲囬泦鍒扮殑鐗瑰緛鍊�
+          // 鏃犺鏄娆″綍鍏ヨ繕鏄噸鏂板綍鍏ワ紝閮借鍒囨崲鍒扮壒寰佸�兼敞鍐岄〉闈�
+          this.fingerprintType = 1
+        }else if (res.code === 200 && res.data && res.data.ret == -1) {
+          this.$message.error(this.$t('voucher.fingerFailed'))
+          this.handleFingerprintError()
+        }
+      } catch (error) {
+        console.error('鏌ヨ鎸囩汗缁撴灉澶辫触:', error)
+      }
+    },
+
+    // 澶勭悊鎸囩汗褰曞叆瓒呮椂
+    handleFingerprintTimeout() {
+      this.$message.error(this.$t('voucher.fingerInputTimeout'))
+      this.fingerprintStatusText = this.$t('voucher.fingerTimeout')
+      this.fingerprintStatusIcon = 'el-icon-error'
+      this.resetFingerprintStatus()
+    },
+
+    // 澶勭悊鎸囩汗褰曞叆澶辫触
+    handleFingerprintError() {
+      this.$message.error(this.$t('voucher.fingerInputError'))
+      this.fingerprintStatusText = this.$t('voucher.fingerError')
+      this.fingerprintStatusIcon = 'el-icon-error'
+      this.resetFingerprintStatus()
+    },
+
+    // 閲嶇疆鎸囩汗褰曞叆鐘舵��
+    resetFingerprintStatus(resetText = true) {
+      this.fingerprintLoading = false
+      this.clearFingerprintTimers()
+      if (resetText) {
+        setTimeout(() => {
+          // 鏍规嵁鏄惁宸叉湁鎸囩汗鍑瘉璁剧疆鐘舵�佹枃鏈�
+          this.fingerprintStatusText = this.hasFingerprint ? this.$t('voucher.fingerInputed') : this.$t('voucher.fingerWaitInput')
+          this.fingerprintStatusIcon = this.hasFingerprint ? 'el-icon-success' : 'el-icon-fingerprint'
+        }, 2000)
+      }
+    },
+
+    clearImage () {
+      this.faceImage = ""
+      this.form.face = ""
+    },
+
+    handleUploadChange (file) {
+      const reader = new FileReader();
+      reader.onload = (e) => {
+        console.log(e);
+        let result = e.target.result
+        this.faceImage = result
+        this.form.face = result.split(',').pop()
+      };
+      reader.readAsDataURL(file.raw);
+    },
+
+    addConfirm: throttle (async function() {
+      if (this.isLoading) return
+      // 鎻愪氦鍑瘉閫昏緫
+      try {
+        // 濡傛灉鏄汉鑴稿嚟璇�,闇�瑕佹牴鎹綋鍓嶇被鍨嬭缃暟鎹�
+        if (this.activeTab === 'face') {
+          if (this.faceType === 1) {
+            // 鐗瑰緛鍊兼敞鍐�,鐩存帴浣跨敤鐗瑰緛鍊�
+            this.form.face = this.faceFeature
+          }
+          // 鐓х墖娉ㄥ唽宸茬粡鍦╤andleUploadChange涓缃ソ浜唂orm.face
+        }
+        
+        // 濡傛灉鏄寚绾瑰嚟璇�,闇�瑕佹牴鎹綋鍓嶇被鍨嬭缃暟鎹�
+        if (this.activeTab === 'fingerprint') {
+          if (this.fingerprintType === 1) {
+            // 鐗瑰緛鍊兼敞鍐�,鐩存帴浣跨敤鐗瑰緛鍊�
+            this.form.fingerprint = this.fingerprintFeature
+          }
+          // 鎸囩汗褰曞叆宸茬粡鍦╟heckFingerprintResult涓缃ソ浜唂orm.fingerprint
+        }
+        
+        await this.$refs.passwordForm.validate();
+        await this.$refs.cardForm.validate();
+        this.submitData();
+      } catch (error) {
+        console.log(error)
+      }
+    }, 2000),
+
+    handleAddClose () {
+      this.interruptFinger()
+      this.clearFingerprintTimers()
+      this.$emit('close-drawer', false);
+    },
+
+    async submitData () {
+      this.isLoading = true
+      try {
+        if (!this.userId) {
+        this.$message.error(this.$t('person.userNotExist'))
+        return false
+        }
+        let keyAddList = []
+        let keyEditList = []
+        let keyDeleteList = []
+        // 澶勭悊瀵嗙爜鍑瘉
+        this.processPasswordVoucher(keyAddList, keyEditList, keyDeleteList)
+        // 澶勭悊鍗$墖鍑瘉
+        this.processCardVoucher(keyAddList, keyEditList, keyDeleteList)
+        // 澶勭悊浜鸿劯鍑瘉
+        this.processFaceVoucher(keyAddList, keyEditList, keyDeleteList)
+        // 澶勭悊鎸囩汗鍑瘉
+        if (this.fingerprintEnabled) {
+          this.processFingerprintVoucher(keyAddList, keyEditList, keyDeleteList)
+        }
+        
+        if (keyAddList.length) {
+          const res = await this.$http.post(
+            "/insertKey",
+            {
+              data: keyAddList
+            }
+          );
+          if (res.code == 200) {
+            this.$message.success(this.$t('common.saveSuccess'))
+            this.getVoucher()
+          } else {
+            if (res.data && res.data[0]) {
+              this.$message.error(res.data[0].errmsg)
+            }
+          }
+        }
+        if (keyEditList.length) {
+          const res = await this.$http.post(
+            "/modifyKey",
+            {
+              data: keyEditList
+            }
+          );
+          if (res.code == 200) {
+            this.$message.success(this.$t('common.saveSuccess'))
+            this.getVoucher()
+          } else {
+            if (res.data && res.data[0]) {
+              this.$message.error(res.data[0].errmsg)
+            }
+          }
+        }
+        if (keyDeleteList.length) {
+          const res = await this.$http.post(
+            "/delKey",
+            {
+              data: { keyIds: keyDeleteList }
+            }
+          );
+          if (res.code == 200) {
+            this.$message.success(this.$t('common.saveSuccess'))
+            this.getVoucher()
+          } else {
+            if (res.data && res.data[0]) {
+              this.$message.error(res.data[0].errmsg)
+            }
+          }
+        }
+        // 濡傛灉娌℃湁鏁版嵁鍙樺寲
+        if (!keyAddList.length && !keyEditList.length && !keyDeleteList.length) {
+          this.$message.info(this.$t('common.noDataSaved'))
+        }
+      } catch (error) {
+        console.error('submitData error:', error)
+      } finally {
+        this.isLoading = false
+      }
+    },
+
+    // 澶勭悊瀵嗙爜鍑瘉
+    processPasswordVoucher (keyAddList, keyEditList, keyDeleteList) {
+      // 濡傛灉瀛樺湪瀵嗙爜鍑瘉,涓斿瘑鐮佹湁鍙樺寲,鍒欎慨鏀�
+      if (this.keyId.password) {
+        if (this.form.password) {
+          if (this.form.password !== this.form.oldPassword) {
+            keyEditList.push({
+              keyId: this.keyId.password,
+              userId: this.userId,
+              type: '400',
+              code: this.form.password
+            })
+          }
+        } else {
+          keyDeleteList.push(this.keyId.password)
+        }
+      } else {
+        // 涓嶅瓨鍦ㄥ瘑鐮佸嚟璇�,鏂板
+        // 濡傛灉瀵嗙爜涓虹┖,涓嶅鐞�
+        if (!this.form.password) return
+        keyAddList.push({
+          keyId: generateRandomString(),
+          userId: this.userId,
+          type: '400',
+          code: this.form.password
+        })
+      }
+    },
+
+    // 澶勭悊鍗$墖鍑瘉
+    processCardVoucher (keyAddList, keyEditList, keyDeleteList) {
+      // 濡傛灉瀛樺湪鍗$墖鍑瘉,涓斿崱鐗囧彿鏈夊彉鍖�,鍒欎慨鏀�
+      if (this.keyId.card) {
+        if (this.form.card) {
+          if (this.form.card !== this.form.oldCard) {
+            keyEditList.push({
+              keyId: this.keyId.card,
+              userId: this.userId,
+              type: '200',
+              code: this.form.card
+            })
+          }
+        } else {
+          keyDeleteList.push(this.keyId.card)
+        }
+      } else {
+        // 涓嶅瓨鍦ㄥ崱鐗囧嚟璇�,鏂板
+        // 濡傛灉鍗$墖鍙蜂负绌�,涓嶅鐞�
+        if (!this.form.card) return
+        keyAddList.push({
+          keyId: generateRandomString(),
+          userId: this.userId,
+          type: '200',
+          code: this.form.card
+        })
+      }
+    },
+
+    // 澶勭悊浜鸿劯鍑瘉
+    processFaceVoucher (keyAddList, keyEditList, keyDeleteList) {
+      // 濡傛灉浜鸿劯鏁版嵁涓虹┖,涓嶅鐞�
+      const hasFaceVoucher = this.originalFaceData !== null
+      // 濡傛灉瀛樺湪浜鸿劯鍑瘉,涓斾汉鑴告暟鎹湁鍙樺寲,鍒欎慨鏀�
+      if (hasFaceVoucher) {
+        // 鍒ゆ柇鏁版嵁鏄惁鏈夊彉鍖�
+        const isDataChanged =
+          this.form.face !== this.form.oldFace ||
+          this.faceType !== this.originalFaceData.faceType
+
+        if (isDataChanged) {
+          if (this.form.face) {
+            keyEditList.push({
+              keyId: this.keyId.face,
+              userId: this.userId,
+              type: '300',
+              code: this.form.face,
+              extra: {
+                faceType: this.faceType
+              }
+            })
+          } else {
+            keyDeleteList.push(this.keyId.face)
+          }
+        }
+      } else {
+        // 涓嶅瓨鍦ㄤ汉鑴稿嚟璇�,鏂板
+        if (!this.form.face) return
+        // 鍒ゆ柇鏄惁宸插瓨鍦ㄤ汉鑴稿嚟璇�
+        keyAddList.push({
+          keyId: generateRandomString(),
+          userId: this.userId,
+          type: '300',
+          code: this.form.face,
+          extra: {
+            faceType: this.faceType
+          }
+        })
+      }
+    },
+
+    // 澶勭悊鎸囩汗鍑瘉
+    processFingerprintVoucher (keyAddList, keyEditList, keyDeleteList) {
+      // 濡傛灉鎸囩汗鏁版嵁涓虹┖,涓嶅鐞�
+      const hasFingerprintVoucher = this.originalFingerprintData !== null
+      // 濡傛灉瀛樺湪鎸囩汗鍑瘉,涓旀寚绾规暟鎹湁鍙樺寲,鍒欎慨鏀�
+      if (hasFingerprintVoucher) {
+        // 纭畾瑕佷娇鐢ㄧ殑 fingerprintType
+        let finalFingerprintType = this.fingerprintType
+        // 濡傛灉褰撳墠鍦ㄦ寚绾瑰綍鍏ラ〉闈紙fingerprintType === 0锛変笖鎸囩汗鏁版嵁娌℃湁鍙樺寲锛岃鏄庢病鏈夐噸鏂板綍鍏ワ紝淇濇寔鍘熷鐨� fingerprintType
+        if (this.fingerprintType === 0 && this.form.fingerprint === this.form.oldFingerprint) {
+          finalFingerprintType = this.originalFingerprintData.fingerprintType
+        }
+        // 濡傛灉褰撳墠鍦ㄧ壒寰佸�兼敞鍐岄〉闈紙fingerprintType === 1锛夛紝浣跨敤鐗瑰緛鍊兼敞鍐岀被鍨�
+        // 鍒ゆ柇鏁版嵁鏄惁鏈夊彉鍖�
+        const isDataChanged =
+          this.form.fingerprint !== this.form.oldFingerprint ||
+          finalFingerprintType !== this.originalFingerprintData.fingerprintType
+
+        if (isDataChanged) {
+          if (this.form.fingerprint) {
+            keyEditList.push({
+              keyId: this.keyId.fingerprint,
+              userId: this.userId,
+              type: '500',
+              code: this.form.fingerprint,
+              extra: {
+                fingerprintType: finalFingerprintType
+              }
+            })
+          } else {
+            keyDeleteList.push(this.keyId.fingerprint)
+          }
+        }
+      } else {
+        // 涓嶅瓨鍦ㄦ寚绾瑰嚟璇�,鏂板
+        if (!this.form.fingerprint) return
+        keyAddList.push({
+          keyId: generateRandomString(),
+          userId: this.userId,
+          type: '500',
+          code: this.form.fingerprint,
+          extra: {
+            fingerprintType: this.fingerprintType
+          }
+        })
+      }
+    },
+
+    handleDeleteCode (keyId) {
+      let that = this
+      this.$confirm(
+        this.$t('common.deleteTips'),
+        this.$t('common.tips'),
+        {
+          confirmButtonText: this.$t('common.confirm'),
+          cancelButtonText: this.$t('common.cancel'),
+          type: 'warning'
+        }
+      ).then(async () => {
+        try {
+          const res = await that.$http.post("/delKey", {
+            data: {
+              keyIds: [keyId]
+            }
+          })
+          if (res.code == 200) {
+            that.$message.success(this.$t('common.deleteSuccess'))
+            that.getVoucher()
+          } else {
+            that.$message.error(res.message)
+          }
+        } catch (even) {
+          console.log(even)
+        }
+      }).catch(() => { })
+    },
+
+  },
+};
+</script>
+
+<style lang='less' scoped>
+.voucher-tabs {
+  margin-top: 10px;
+}
+
+.tab-content {
+  padding: 10px 0;
+}
+
+/* 涓婁紶鍖哄煙 */
+.avatar-uploader {
+  border: 2px dashed #d9d9d9;
+  border-radius: 8px;
+  cursor: pointer;
+  width: 150px;
+  height: 150px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  overflow: hidden;
+  background-color: #fafafa;
+}
+
+.avatar-uploader:hover {
+  border-color: #409eff;
+}
+
+.avatar {
+  width: 100%;
+  height: 100%;
+  object-fit: cover;
+}
+
+.avatar-uploader-icon {
+  font-size: 28px;
+  color: #999;
+}
+
+.upload-tip {
+  margin-top: 8px;
+  font-size: 12px;
+  color: #999;
+}
+
+/* 鍗$墖鎻愮ず */
+.card-scan-tip {
+  font-size: 13px;
+  color: #666;
+  margin-top: 10px;
+  padding: 10px;
+  background: #e6f7ff;
+  border-radius: 4px;
+  border-left: 4px solid #1890ff;
+}
+
+.face-register-container {
+  max-width: 800px;
+  margin: 0 auto;
+  padding: 20px;
+}
+
+.register-type-selector {
+  margin-bottom: 20px;
+  text-align: center;
+}
+
+.upload-area {
+  text-align: center;
+  margin-bottom: 20px;
+}
+
+.avatar-uploader {
+  position: relative;
+  display: inline-block;
+}
+
+.avatar-uploader .el-upload {
+  border: 1px dashed #d9d9d9;
+  border-radius: 6px;
+  cursor: pointer;
+  position: relative;
+  overflow: hidden;
+  width: 150px;
+  height: 150px;
+}
+
+.avatar-uploader .el-upload:hover {
+  border-color: #409EFF;
+}
+
+/deep/.clear-btn {
+  position: absolute;
+  top: -10px;
+  left: 5px;
+  width: 24px !important;
+  height: 24px !important;
+  font-size: 12px;
+  z-index: 10;
+}
+
+.avatar-uploader-icon {
+  font-size: 28px;
+  color: #8c939d;
+  width: 150px;
+  height: 150px;
+  line-height: 150px;
+  text-align: center;
+}
+
+.avatar {
+  width: 150px;
+  height: 150px;
+  display: block;
+}
+
+.feature-input-area {
+  margin-top: 20px;
+}
+
+.feature-textarea {
+  width: 100%;
+}
+
+.feature-tips {
+  margin-top: 10px;
+  font-size: 12px;
+  color: #909399;
+}
+
+.action-buttons {
+  margin-top: 20px;
+  text-align: center;
+}
+
+.el-button {
+  margin: 0 10px;
+}
+
+/* 鎸囩汗鐩稿叧鏍峰紡 */
+.fingerprint-tab {
+  min-height: 200px;
+}
+
+.capture-area {
+  text-align: center;
+  padding: 20px;
+}
+
+.fingerprint-status {
+  margin-bottom: 20px;
+}
+
+.status-icon {
+  font-size: 64px;
+  color: #409EFF;
+  display: block;
+  margin-bottom: 10px;
+}
+
+.status-icon.el-icon-loading {
+  animation: rotating 2s linear infinite;
+}
+
+.status-icon.el-icon-success {
+  color: #67C23A;
+}
+
+.status-icon.el-icon-error {
+  color: #F56C6C;
+}
+
+@keyframes rotating {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+.status-text {
+  font-size: 16px;
+  color: #606266;
+  margin: 10px 0;
+}
+
+.capture-tips {
+  margin-top: 20px;
+  font-size: 14px;
+  color: #909399;
+}
+
+.capture-tips p {
+  margin: 5px 0;
+}
+
+.timeout-text {
+  color: #F56C6C;
+  font-weight: bold;
+}
+</style>
\ No newline at end of file
diff --git "a/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/views/record/index.vue" "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/views/record/index.vue"
new file mode 100644
index 0000000..d2f3187
--- /dev/null
+++ "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/views/record/index.vue"
@@ -0,0 +1,314 @@
+<template>
+  <el-main>
+    <el-row>
+      <el-col :span="24">
+        <el-form :inline="true" class="el-InputForm">
+          <!-- <el-form-item :label="$t('log.accessMethod')">
+            <el-select v-model="searchForm.type" :placeholder="$t('common.placeholderSelect')" clearable>
+              <el-option :label="$t('voucher.password')" value="400"></el-option>
+              <el-option :label="$t('voucher.card')" value="200"></el-option>
+              <el-option :label="$t('voucher.face')" value="300"></el-option>
+            </el-select>
+          </el-form-item>
+          
+          <el-form-item label="閫氳缁撴灉">
+            <el-select v-model="searchItem.result" placeholder="璇烽�夋嫨閫氳缁撴灉" clearable>
+              <el-option label="鎴愬姛" value="1"></el-option>
+              <el-option label="澶辫触" value="0"></el-option>
+            </el-select>
+          </el-form-item> -->
+          <el-form-item :label="$t('person.name')" label-width="80px">
+            <el-input v-model="searchForm.name" :placeholder="$t('person.placeholderName')" clearable></el-input>
+          </el-form-item>
+          <el-form-item :label="$t('log.passingTime')" label-width="100px">
+            <el-date-picker v-model="time" value-format="yyyy-MM-dd HH:mm:ss" type="datetimerange" :range-separator="$t('common.to')"
+              :start-placeholder="$t('common.startTime')" :end-placeholder="$t('common.endTime')">
+            </el-date-picker>
+          </el-form-item>
+          <div style="position: absolute; right: 25px; bottom: 25px;">
+            <el-button type="info" size="medium" icon="el-icon-search" @click="search()"
+              style="margin-left:10px;border:none;">{{ $t('common.query') }}</el-button>
+            <el-button type="warning" size="medium" icon="el-icon-refresh-right" @click="doReset()">{{
+              $t('common.reset')
+            }}</el-button>
+          </div>
+        </el-form>
+        <el-col :span="24" style="margin:20px 0">
+          <el-button type="danger" size="mini" style="font-size:12px;" icon="el-icon-delete" @click="batchDelete()">{{
+            $t('common.batchDelete') }}</el-button>
+        </el-col>
+      </el-col>
+    </el-row>
+
+    <el-col :span="24">
+      <Table :table-label="tableHeader" v-loading="isSubmitLoading" :table-data="tableData" :table-option="tableOption"
+        :table-selection="tableSelection" @onHandleSelectionChange="handleSelectionChange"></Table>
+      <pagination ref="page" :total="total" @pageChange="pageChange"></pagination>
+
+    </el-col>
+
+    <!-- 閫氳鍥剧墖棰勮 -->
+    <el-dialog :visible.sync="dialogTableVisible" width="30%">
+      <div class="imgDiv"><img :src="urlImg" alt=""></div>
+    </el-dialog>
+  </el-main>
+</template>
+
+<script>
+import Pagination from "@/components/table/pagination.vue"
+import Table from "@/components/table/tableList.vue"
+import { removeEmptyValues, resetObjectValues, parseTime } from '@/utils/index.js'
+export default {
+  name: 'Record',
+  components: { Table, Pagination },
+  data () {
+    return {
+      tableHeader: [
+        { label: this.$t('person.userId'), list: "userId", overflowShow: 'hidden' },
+        {
+          type: "html",
+          label: this.$t('person.name'),
+          code: (row) => {
+            return row.name ? row.name : '-'
+          }
+        },
+        {
+          label: this.$t('log.passingTime'),
+          type: "html",
+          overflowShow: 'hidden',
+          code: (row) => {
+            return parseTime(row.timeStamp * 1000)
+          }
+        },
+        {
+          type: "html",
+          label: this.$t('log.accessMethod'),
+          code: (row) => {
+            if (row.type == 200) {
+              return this.$t('voucher.card')
+            } else if (row.type == 300) {
+              return this.$t('voucher.face')
+            } else if (row.type == 400) {
+              return this.$t('voucher.password')
+            } else if (row.type == 500) {
+              return this.$t('voucher.finger')
+            } else if (row.type == 100 || row.type == 101 || row.type == 103 || row.type == 104) {
+              return this.$t('voucher.code')
+            }
+          }
+        },
+        {
+          type: "html",
+          label: this.$t('log.accessPass'),
+          overflowShow: 'hidden',
+          code: (row) => {
+            return row.type == 300 ? '-' : row.code
+          }
+        },
+        {
+          type: "html",
+          label: this.$t('log.accessResult'),
+          code: (row) => {
+            if (row.result === 1) {
+              return `<span style="color:#ff5722;font-weight:600">${this.$t('common.failure')}</span>`
+            } else if (row.result === 0) {
+              return `<span style="color:#1fab89;font-weight:600">${this.$t('common.success')}</span>`
+            }
+          }
+        },
+      ],
+      tableSelection: {
+        key: true,
+        type: "selection",
+        detaile: false,
+      },
+      tableOption: {
+        label: this.$t('common.operation'),
+        width: "180px",
+        value: 0,
+        options: [
+          {
+            label: this.$t('common.delete'),
+            key: 0,
+            type: "text",
+            State: true,
+            method: (row) => {
+              this.handleDelete(row.id)
+            },
+          },
+          {
+            label: this.$t('log.viewPhotos'),
+            key: 0,
+            type: "text",
+            State: true,
+            show: (row) => {
+              return row.type == 300
+            },
+            method: (row) => {
+              this.getPhoto(row.code)
+            },
+          },
+        ]
+      },
+      tableData: [],
+      isSubmitLoading: false,
+      dialogTableVisible: false,
+      urlImg: "",
+      total: 0,
+      pageSize: 20,
+      currentPage: 0,
+      searchForm: {
+        name: ''
+      },
+      time: [],
+      selectIdList: [],
+    };
+  },
+  created () {
+    this.fetchData()
+  },
+  mounted () { },
+  methods: {
+
+    search () {
+      let that = this
+      that.currentPage = 0;
+      that.$refs.page.Page(1);
+      that.fetchData();
+    },
+
+    pageChange (item) {
+      this.pageSize = item.limit;
+      this.currentPage = item.page - 1;
+      this.fetchData();
+    },
+
+    handleSelectionChange (vals) {
+      this.selectIdList = [];
+      vals.map(v => {
+        this.selectIdList.push(v.id);
+      });
+    },
+
+    // 鑾峰彇閫氳璁板綍
+    async fetchData () {
+      let searchForm = removeEmptyValues({ ...this.searchForm })
+      if (this.time.length) {
+        searchForm.startTime = new Date(this.time[0]).getTime() / 1000
+        searchForm.endTime = new Date(this.time[1]).getTime() / 1000
+      }
+      searchForm.page = this.currentPage
+      searchForm.size = this.pageSize
+      searchForm.flag = false
+      try {
+        const res = await this.$http.post('/getRecord', { data: searchForm })
+        if (res.code === 200) {
+          this.tableData = res.data.content
+          this.total = res.data.total
+        } else {
+          this.$message.error(res.message)
+        }
+      } catch (even) {
+        console.log(even)
+      }
+    },
+
+    handleDelete (id) {
+      let that = this
+      this.$confirm(
+        this.$t('common.deleteTips'),
+        this.$t('common.tips'),
+        {
+          confirmButtonText: this.$t('common.confirm'),
+          cancelButtonText: this.$t('common.cancel'),
+          type: 'warning'
+        }
+      ).then(async () => {
+        try {
+          const res = await that.$http.post("delRecord", { data: { recordId: [id] } })
+          if (res.code == 200) {
+            that.$message.success(this.$t('common.deleteSuccess'))
+            that.fetchData()
+          } else {
+            that.$message.error(res.message)
+          }
+        } catch (even) {
+          console.log(even)
+        }
+      }).catch(() => { })
+    },
+
+    batchDelete () {
+      let that = this
+      if (this.selectIdList.length <= 0) {
+        this.$message.warning(this.$t('common.placeholderSelect'));
+        return;
+      }
+      this.$confirm(this.$t('common.deleteTips'),
+        this.$t('common.tips'),
+        {
+          confirmButtonText: this.$t('common.confirm'),
+          cancelButtonText: this.$t('common.cancel'),
+          type: 'warning'
+        })
+        .then(async () => {
+          that.isSubmitLoading = true;
+          const res = await this.$http.post("delRecord", { data: { recordId: this.selectIdList }});
+          that.isSubmitLoading = false;
+          if (res.code == 200) {
+            that.$message.success(this.$t('common.deleteSuccess'))
+            that.fetchData()
+          } else {
+            that.$message.error(res.message)
+          }
+        })
+        .catch(() => {
+          return false;
+        });
+    },
+
+    doReset () {
+      resetObjectValues(this.searchForm)
+      this.time = []
+      this.fetchData()
+    },
+
+    async getPhoto (code) {
+      try {
+        const res = await this.$http.post('/getRecordMsg', { data: code })
+        if (res.code == 200) {
+          console.log(res);
+          this.urlImg = 'data:image/png;base64,' + res.data
+          this.dialogTableVisible = true
+        } else {
+          this.$message.error(res.message)
+        }
+      } catch (even) {
+        console.log(even)
+      }
+    },
+
+    // 鍥剧墖鏌ョ湅
+    handleCellClick (e, column) {
+      if (JSON.parse(e.extra).pic && column.label === "閫氳鐓х墖") {
+        this.dialogTableVisible = true
+        let imgUrl = JSON.parse(e.extra).pic
+        this.urlImg = imgUrl.split('&imageView')[0]
+      }
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.el-main {
+  .imgDiv {
+    width: 100%;
+    text-align: center;
+
+    img {
+      height: 100%;
+    }
+  }
+}
+</style>
\ No newline at end of file
diff --git "a/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/views/security/add.vue" "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/views/security/add.vue"
new file mode 100644
index 0000000..d7af31f
--- /dev/null
+++ "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/views/security/add.vue"
@@ -0,0 +1,132 @@
+<!-- 鏂板瀵嗛挜 -->
+<template>
+  <div>
+    <el-drawer size="40%" :with-header="false" :visible.sync="visible" :before-close="handleAddClose">
+      <el-form ref="form" :model="form" label-width="100px" :rules="rules" style="width: 90%;margin: 50px auto;">
+        <el-form-item :label="$t('security.keyId')" v-if="type == 'detail'">
+          <el-input v-model="form.securityId" :placeholder="$t('common.placeholder')"></el-input>
+        </el-form-item>
+        <el-form-item :label="$t('security.keyType')">
+          <el-radio-group v-model="form.type">
+            <el-radio label="RSA">RSA</el-radio>
+            <el-radio label="AES">AES</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item :label="$t('security.keyEncoding')" prop="key">
+          <el-input v-model="form.key" :placeholder="$t('common.placeholder')"></el-input>
+        </el-form-item>
+        <el-form-item :label="$t('security.keyValue')" prop="value">
+          <el-input type="textarea" clearable :rows="5" v-model="form.value"
+            :placeholder="$t('common.placeholder')"></el-input>
+        </el-form-item>
+        <el-form-item :label="$t('security.validTime')">
+          <el-date-picker :clearable="false" v-model="dateTimes" value-format="timestamp"
+            :default-time="['00:00:00', '23:59:59']" type="datetimerange" :range-separator="$t('common.to')"
+            :start-placeholder="$t('common.startTime')" :end-placeholder="$t('common.endTime')">
+          </el-date-picker>
+        </el-form-item>
+      </el-form>
+      <div class="dialog-footer">
+        <el-button type="warning" @click="handleAddClose(false)">{{ $t('common.cancel') }}</el-button>
+        <el-button v-if="type == 'add'" type="primary" @click="updata()">{{ $t('common.confirm') }}</el-button>
+      </div>
+    </el-drawer>
+  </div>
+</template>
+
+<script>
+import { generateRandomString, resetObjectValues } from '@/utils/index.js'
+export default {
+  data () {
+    return {
+      form: {
+        securityId: "",
+        type: "",
+        key: "",
+        value: ""
+      },
+      rules: {
+        key: [{ required: true, message: this.$t('common.placeholder'), trigger: ["blur"] },],
+        value: [{ required: true, message: this.$t('common.placeholder'), trigger: ["blur"] },],
+      },
+      dateTimes: [],
+      visible: false,
+      type: 'info'
+    }
+  },
+  created () {
+    this.initialForm = JSON.parse(JSON.stringify(this.form));
+  },
+  mounted () {
+
+  },
+  methods: {
+    open (type, row) {
+      if (type == 'add') {
+        this.form.type = 'RSA'
+        console.log('add')
+      } else {
+        this.form.securityId = row.securityId
+        this.form.type = row.type
+        this.form.key = row.key
+        this.form.value = row.value
+        this.dateTimes = [row.startTime * 1000, row.endTime * 1000]
+      }
+      this.type = type
+      this.visible = true
+    },
+
+    handleAddClose (showConfirm = true) {
+      const closeAction = () => {
+        if (this.$refs.form) {
+          this.$refs.form.clearValidate();
+        }
+        this.visible = false;
+        this.form = { ...this.initialForm };
+        this.dateTimes = []
+      };
+      if (showConfirm) {
+        this.$confirm(this.$t('common.closeTips'))
+          .then(closeAction)
+          .catch(() => { });
+      } else {
+        closeAction();
+      }
+    },
+
+    updata () {
+      let that = this
+      this.$refs['form'].validate(async (valid) => {
+        if (valid) {
+          if (!that.dateTimes.length) {
+            that.$message.warning(this.$t('permission.choose_time_range'));
+            return false
+          }
+          let data = {
+            securityId: generateRandomString(),
+            type: that.form.type,
+            key: that.form.key,
+            value: that.form.value,
+            startTime: new Date(that.dateTimes[0]).getTime() / 1000,
+            endTime: new Date(that.dateTimes[1]).getTime() / 1000
+          }
+          const res = await this.$http.post(
+            "/insertSecurity",
+            { data: [data] }
+          );
+          if (res.code == 200) {
+            this.$message.success(this.$t('common.addSuccess'))
+            this.visible = false
+            resetObjectValues(this.form)
+            this.$emit("operation-success")
+          } else {
+            if (res.data && res.data[0]) {
+              this.$message.error(res.data[0].errmsg)
+            }
+          }
+        }
+      })
+    }
+  }
+}
+</script>
\ No newline at end of file
diff --git "a/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/views/security/index.vue" "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/views/security/index.vue"
new file mode 100644
index 0000000..4c3f407
--- /dev/null
+++ "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/src/views/security/index.vue"
@@ -0,0 +1,217 @@
+<template>
+  <el-main>
+    <el-row>
+      <el-col :span="24">
+        <el-form :inline="true" class="el-InputForm">
+          <el-form-item :label="$t('security.keyId')" label-width="80px">
+            <el-input v-model="searchForm.securityId" :placeholder="$t('common.placeholder')" clearable></el-input>
+          </el-form-item>
+          <div style="position: absolute; right: 25px; bottom: 25px;">
+            <el-button type="info" size="medium" icon="el-icon-search" @click="search()"
+              style="margin-left:10px;border:none;">{{ $t('common.query') }}</el-button>
+            <el-button type="warning" size="medium" icon="el-icon-refresh-right" @click="doReset()">{{
+              $t('common.reset')
+              }}</el-button>
+          </div>
+        </el-form>
+        <el-col :span="24" style="margin:20px 0">
+          <el-button type="primary" style="border:none;" size='mini' icon="el-icon-plus" @click="doAdd">{{
+            $t('security.newKey') }}</el-button>
+          <el-button type="danger" size="mini" style="font-size:12px;" icon="el-icon-delete" @click="batchDelete()">{{
+            $t('security.clearKey') }}</el-button>
+        </el-col>
+      </el-col>
+    </el-row>
+
+    <el-col :span="24">
+      <Table :table-label="tableHeader" v-loading="isSubmitLoading" :table-data="tableData" :table-option="tableOption">
+      </Table>
+      <pagination ref="page" :total="total" @pageChange="pageChange"></pagination>
+    </el-col>
+
+    <add ref="add" @operation-success="fetchData"></add>
+  </el-main>
+</template>
+
+<script>
+import Pagination from "@/components/table/pagination.vue"
+import Table from "@/components/table/tableList.vue"
+import Add from "./add.vue"
+import { removeEmptyValues, resetObjectValues, parseTime } from '@/utils/index.js'
+export default {
+  name: 'Record',
+  components: { Table, Pagination, Add },
+  data () {
+    return {
+      tableHeader: [
+        { label: this.$t('security.keyId'), list: "securityId", overflowShow: 'hidden' },
+        { label: this.$t('security.keyType'), list: "type", overflowShow: 'hidden' },
+        { label: this.$t('security.keyEncoding'), list: "key", overflowShow: 'hidden' },
+        { label: this.$t('security.keyValue'), list: "value", overflowShow: 'hidden' },
+        {
+          label: this.$t('security.startTime'),
+          type: "html",
+          overflowShow: 'hidden',
+          code: (row) => {
+            return parseTime(row.startTime * 1000)
+          }
+        },
+        {
+          label: this.$t('security.expirationTime'),
+          type: "html",
+          overflowShow: 'hidden',
+          code: (row) => {
+            return parseTime(row.endTime * 1000)
+          }
+        }
+      ],
+      tableOption: {
+        label: this.$t('common.operation'),
+        width: "180px",
+        value: 0,
+        options: [
+          {
+            label: this.$t('common.delete'),
+            key: 0,
+            type: "text",
+            State: true,
+            method: (row) => {
+              this.handleDelete(row.securityId)
+            },
+          },
+          {
+            label: this.$t('common.detail'),
+            key: 0,
+            type: "text",
+            State: true,
+            method: (row) => {
+              this.$refs.add.open("detail", { ...row })
+            },
+          },
+        ]
+      },
+      tableData: [],
+      isSubmitLoading: false,
+      total: 0,
+      pageSize: 20,
+      currentPage: 0,
+      searchForm: {
+        securityId: ''
+      },
+      time: [],
+      selectIdList: [],
+    };
+  },
+  created () {
+    this.fetchData()
+  },
+  mounted () { },
+  methods: {
+    search () {
+      let that = this
+      that.currentPage = 0;
+      that.$refs.page.Page(1);
+      that.fetchData();
+    },
+
+    pageChange (item) {
+      this.pageSize = item.limit;
+      this.currentPage = item.page - 1;
+      this.fetchData();
+    },
+
+    // 鑾峰彇瀵嗛挜
+    async fetchData () {
+      let searchForm = removeEmptyValues({ ...this.searchForm })
+      searchForm.page = this.currentPage
+      searchForm.size = this.pageSize
+      try {
+        const res = await this.$http.post('/getSecurity', { data: searchForm })
+        if (res.code === 200) {
+          this.tableData = res.data.content
+          this.total = res.data.total
+        } else {
+          this.$message.error(res.message)
+        }
+      } catch (even) {
+        console.log(even)
+      }
+    },
+
+    doAdd () {
+      this.$refs.add.open('add')
+    },
+
+    handleDelete (id) {
+      let that = this
+      this.$confirm(
+        this.$t('common.deleteTips'),
+        this.$t('common.tips'),
+        {
+          confirmButtonText: this.$t('common.confirm'),
+          cancelButtonText: this.$t('common.cancel'),
+          type: 'warning'
+        }
+      ).then(async () => {
+        try {
+          const res = await that.$http.post("/delSecurity", { data: [id] })
+          if (res.code == 200) {
+            that.$message.success(this.$t('common.deleteSuccess'))
+            that.fetchData()
+          } else {
+            if (res.data && res.data[0]) {
+              that.$message.error(res.data[0].errmsg)
+            }
+          }
+        } catch (even) {
+          console.log(even)
+        }
+      }).catch(() => { })
+    },
+
+    batchDelete () {
+      let that = this
+      this.$confirm(this.$t('common.clearTips'),
+        this.$t('common.tips'),
+        {
+          confirmButtonText: this.$t('common.confirm'),
+          cancelButtonText: this.$t('common.cancel'),
+          type: 'warning'
+        })
+        .then(async () => {
+          that.isSubmitLoading = true;
+          const res = await this.$http.post("/clearSecurity", { data: {} });
+          that.isSubmitLoading = false;
+          if (res.code == 200) {
+            that.$message.success(this.$t('common.clearSuccess'))
+            that.fetchData()
+          } else {
+            that.$message.error(res.message)
+          }
+        })
+        .catch(() => {
+          return false;
+        });
+    },
+
+    doReset () {
+      resetObjectValues(this.searchForm)
+      this.time = []
+      this.fetchData()
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.el-main {
+  .imgDiv {
+    width: 100%;
+    text-align: center;
+
+    img {
+      height: 100%;
+    }
+  }
+}
+</style>
\ No newline at end of file
diff --git "a/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/vue.config.js" "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/vue.config.js"
new file mode 100644
index 0000000..af5fd53
--- /dev/null
+++ "b/face_webserver/face_webserver-\344\277\256\345\244\2152.0.2\347\211\210\346\234\254\345\222\214\344\274\201\345\276\256bug_20260302-ca91388fcbac2fc1005beb7fb78ec5f434495242/vue.config.js"
@@ -0,0 +1,39 @@
+const http = require('http');
+
+// 鑷畾涔変唬鐞嗕腑闂翠欢锛屽畬鍏ㄦ帶鍒惰姹傚ご
+module.exports = {
+  devServer: {
+    port: 8080,
+    open: true, 
+    before: function(app) {
+      app.post('/api/*', (req, res) => {
+        const options = {
+          hostname: '192.168.10.132',
+          port: 8080,
+          path: req.url.replace('/api', ''),
+          method: 'POST',
+          headers: {
+            // 鍙鍒跺繀瑕佺殑澶撮儴锛屽畬鍏ㄦā鎷烶ostman
+            'Content-Type': req.headers['content-type'],
+            'Content-Length': req.headers['content-length'],
+            'Host': '192.168.10.132:8080',
+            'Connection': 'keep-alive',
+            'User-Agent': 'Mozilla/5.0'
+          }
+        };
+        
+        const proxyReq = http.request(options, (proxyRes) => {
+          res.writeHead(proxyRes.statusCode, proxyRes.headers);
+          proxyRes.pipe(res);
+        });
+        
+        proxyReq.on('error', (err) => {
+          console.error('浠g悊璇锋眰澶辫触:', err);
+          res.status(500).json({ error: '璁惧杩炴帴澶辫触' });
+        });
+        
+        req.pipe(proxyReq);
+      });
+    }
+  }
+};
\ No newline at end of file
diff --git a/vf107/.temp/dxide_debug.log b/vf107/.temp/dxide_debug.log
index e41e64f..56ca057 100644
--- a/vf107/.temp/dxide_debug.log
+++ b/vf107/.temp/dxide_debug.log
@@ -1,10 +1,10 @@
-[2026/4/11 13:35:44] --- Start runUsb ---
-[2026/4/11 13:35:44] Platform: win32
-[2026/4/11 13:35:44] Kill command defined: wmic process where "name='node.exe' and commandline like '%device_manager.js%'" delete || powershell -NoProfile -ExecutionPolicy Bypass -Command "Get-CimInstance Win32_Process | Where-Object { $_.Name -eq 'node.exe' -and $_.CommandLine -like '*device_manager.js*' } | ForEach-Object { Stop-Process -Id $_.ProcessId -Force }"
-[2026/4/11 13:35:44] Node.js check passed
-[2026/4/11 13:35:45] Process exited with code: 0, signal: null
-[2026/4/11 13:35:45] Kill stdout: 删锟斤拷实锟斤拷 \\ACER-LGQ\ROOT\CIMV2:Win32_Process.Handle="31720"

+[2026/4/20 13:31:51] --- Start runUsb ---
+[2026/4/20 13:31:51] Platform: win32
+[2026/4/20 13:31:51] Kill command defined: wmic process where "name='node.exe' and commandline like '%device_manager.js%'" delete || powershell -NoProfile -ExecutionPolicy Bypass -Command "Get-CimInstance Win32_Process | Where-Object { $_.Name -eq 'node.exe' -and $_.CommandLine -like '*device_manager.js*' } | ForEach-Object { Stop-Process -Id $_.ProcessId -Force }"
+[2026/4/20 13:31:54] Node.js check passed
+[2026/4/20 13:31:54] Process exited with code: 0, signal: null
+[2026/4/20 13:31:54] Kill stdout: 删锟斤拷实锟斤拷 \\ACER-LGQ\ROOT\CIMV2:Win32_Process.Handle="39096"

 实锟斤拷删锟斤拷锟缴癸拷锟斤拷
-[2026/4/11 13:35:45] Manager script path: c:\Users\lgq10\.vscode\extensions\dxide.dxide-1.0.41\src\device\device_manager.js
-[2026/4/11 13:35:45] Spawning child process...
-[2026/4/11 13:35:45] Sending connect command: {"cmd":"connect","lang":"zh","model":"VF105_V12"}
+[2026/4/20 13:31:54] Manager script path: c:\Users\lgq10\.vscode\extensions\dxide.dxide-1.0.41\src\device\device_manager.js
+[2026/4/20 13:31:54] Spawning child process...
+[2026/4/20 13:31:55] Sending connect command: {"cmd":"connect","lang":"zh","model":"VF105_V12"}
diff --git a/vf107/.temp/md5s.json b/vf107/.temp/md5s.json
index e50cb99..e3b7657 100644
--- a/vf107/.temp/md5s.json
+++ b/vf107/.temp/md5s.json
@@ -45,7 +45,7 @@
   "dxmodules\\dxCommonUtils.js": "9d408cedb29cce9838c10ae5d1a8c2aa",
   "dxmodules\\dxConfig.js": "24072559b3cb1ec5c206cb358eaaaaae",
   "dxmodules\\dxDisplay.js": "5c80ee7de62e3f7b08eed6e3e0a8b3c1",
-  "dxmodules\\dxDriver.js": "1e27304f7ecc691ac66293cd065e6a14",
+  "dxmodules\\dxDriver.js": "63c8348a2a4a31911ce8a1626aa8f5c4",
   "dxmodules\\dxEventBus.js": "075ac9f2d465c92a9446ea07a6e2bfe6",
   "dxmodules\\dxFacial.js": "08f40369fd06cb3f5f69cd035d4ecab2",
   "dxmodules\\dxFacialBarcode.js": "67508897203cf7382f4bb20c4044dc17",
@@ -63,7 +63,7 @@
   "dxmodules\\dxNfcCard.js": "689161d840c1ee82107e55b3e43da5c3",
   "dxmodules\\dxNtp.js": "54a83064faa67f8f4991e1da56a3caf4",
   "dxmodules\\dxOs.js": "8171120055734e75dd6c878862ae965a",
-  "dxmodules\\dxOta.js": "a4bf84aaead7298c5da10161644f2b1f",
+  "dxmodules\\dxOta.js": "2dd095485717018eb451e5110aca4934",
   "dxmodules\\dxPwm.js": "d8238b43ef7c0d77a33108290394e12c",
   "dxmodules\\dxQrRule.js": "bfa9e2b4725c4fa358a2988f63c67210",
   "dxmodules\\dxSqliteDB.js": "4762a29fb74d837d43d1d19415f77536",
@@ -2465,7 +2465,7 @@
   "resource\\image\\voiceBroadcast.png": "e6f1a31ba7159962d18b77deef71c106",
   "resource\\image\\wifi.png": "fd668b648ac984ed92fad8e40e151283",
   "resource\\image\\wifi_dark.png": "37505f892ac6a43cb8dc5ea685de9740",
-  "resource\\langPack.js": "956b0d902f723e4817319436ee7df117",
+  "resource\\langPack.js": "72c5238aa93a1dc6a79b9466b5ebcf44",
   "resource\\wav\\alarm.wav": "fe9d43cfb930f873973cc31fd6e8c132",
   "resource\\wav\\AR\\calibration_1s.wav": "a5ed7bdf10f5c0bec1f964cbaf8d7c59",
   "resource\\wav\\AR\\calibration_2s.wav": "1a533e06dd209b7b87d48947357a0ca0",
@@ -2670,23 +2670,24 @@
   "src\\common\\utils\\stringUtils.js": "425d9cd0390ab8a60f1507544c2cb00a",
   "src\\common\\utils\\tokenUtil.js": "b7abd3698644aadb7d3e936fb6f7fc8b",
   "src\\common\\utils\\utils.js": "bbee074a060e962a570dddc4d586504d",
-  "src\\config.json": "6619f6367ac0230030de3131160a2178",
-  "src\\controller.js": "954bd6baaf4a7f91b7534f71b0e2365b",
-  "src\\driver.js": "42e819e90d7d5b00191447edb06e928c",
-  "src\\main.js": "51de780e61133a6f39ba5554dacf7644",
-  "src\\screen.js": "b8a256f4f3ba51b4c1e49fcb69e06b28",
-  "src\\service\\accessService.js": "304718a9a06ded28947373c3d9a21295",
-  "src\\service\\api.js": "def5b52441ccc827913a73478cc7c32a",
+  "src\\config.json": "53cf90582fedb3aca8e3ac2848386f36",
+  "src\\controller.js": "35dd417593c4510119576717c717e20b",
+  "src\\driver.js": "b0c3958d69f7e0021a70d8537077ff5d",
+  "src\\main.js": "d455a38100d386fc2eed8bef4c92e7ba",
+  "src\\screen.js": "01812eb2816143c98595939d2c54f2ff",
+  "src\\service\\accessService.js": "e242b879cf8d1e4f326aee9168e9d4d5",
+  "src\\service\\api.js": "24a45cb2acc4306a1f4dd54de559f9f0",
   "src\\service\\codeService.js": "e3f53b983c37a91d85a3de95fab7745d",
-  "src\\service\\configService.js": "d1c3c533c1d451c2eaf46758b4efeb19",
+  "src\\service\\configService.js": "c45b2005ba236b74be9f04ab76635abf",
+  "src\\service\\demo.js": "1f9a570135f63aa5b607743bb5a9e7f4",
   "src\\service\\faceService.js": "cfc3cf7d510f2ba6d6fcedb1251e0795",
   "src\\service\\fingerService.js": "0fee47e46ded411c2da21eb508d8f9ba",
   "src\\service\\gpiokeyService.js": "7aeb81b1577df935f147f3817a0a144b",
-  "src\\service\\grainService.js": "3ec28482d55059fd09d091145fad041c",
-  "src\\service\\httpService.js": "567d6f52d5392e3d95a54264e631944e",
-  "src\\service\\mqttService.js": "eafd4b82b1d5a7d02b32d046bf492ac9",
+  "src\\service\\grainService.js": "940788cbc2aea5b20789b752641df6a7",
+  "src\\service\\httpService.js": "6c62661a42e45226f3f82df3d7e0a37e",
+  "src\\service\\mqttService.js": "b7f598ec25422433bccd821b8b29d5f3",
   "src\\service\\nfcService.js": "fff19d7f08d3a499455ed93a5376c0fd",
-  "src\\service\\sqliteService.js": "9dd93a7afd36b50e6be015e950aaff83",
+  "src\\service\\sqliteService.js": "f1816a98a378b3ed2fbd759f6965a8df",
   "src\\service\\uartBleService.js": "f8816894598283c7114b4d8708bb65aa",
   "src\\service\\uartCodeService.js": "ed1952645c055885c78bc6c02699906f",
   "src\\service\\weComService.js": "14896c15403107f7225fce6db9b8a049",
@@ -2700,21 +2701,21 @@
   "src\\view\\config\\menu\\deviceInfo\\dataCapacityInfoView.js": "81fbf258e0ba70c126f850658981469e",
   "src\\view\\config\\menu\\deviceInfo\\systemInfoView.js": "95a96c6d8586410be1fe085dfa61db9f",
   "src\\view\\config\\menu\\deviceInfoView.js": "b703a2f9053c1b089294b3dffdf6a449",
-  "src\\view\\config\\menu\\doorControlView.js": "2b29eff26537ab92171a40110b8e8c0e",
+  "src\\view\\config\\menu\\doorControlView.js": "f2476da5f529cac859dd24776b210bf6",
   "src\\view\\config\\menu\\helpView.js": "b3cf2078efe3a274740276b550b68b63",
   "src\\view\\config\\menu\\localUser\\faceEnterView.js": "f6dc4e020a4eddba902820d4b2444ee3",
   "src\\view\\config\\menu\\localUser\\fingerApplyView.js": "b2b5a46109f7ac768ae6d18131a33fbe",
   "src\\view\\config\\menu\\localUser\\fingerEnterView.js": "46dd45fe0e8d06410a5f2bcbeb7be5ad",
-  "src\\view\\config\\menu\\localUser\\localUserAddView.js": "8266626bf9cadde968e2b439ef9073b0",
-  "src\\view\\config\\menu\\localUserView.js": "f7881e4a47fe06648d0934f286d59775",
-  "src\\view\\config\\menu\\networkSettingView.js": "7cb7b7ef6c1d49f819f509de43e49a56",
-  "src\\view\\config\\menu\\recordQuery\\recordQueryDetailView.js": "79e15d726de5146bab15a3dba533a82b",
+  "src\\view\\config\\menu\\localUser\\localUserAddView.js": "e9991161a3e5d4344b22f7c4ad3dac4c",
+  "src\\view\\config\\menu\\localUserView.js": "2533606f36feba75efe922cc6b6f883a",
+  "src\\view\\config\\menu\\networkSettingView.js": "740f7a643a0fb4c3caa3eb85482d85cc",
+  "src\\view\\config\\menu\\recordQuery\\recordQueryDetailView.js": "b3ef27a7b02bc59a5c2aa4d977efc30d",
   "src\\view\\config\\menu\\recordQueryView.js": "f640c2f2d560213c44633d7ea36c6960",
-  "src\\view\\config\\menu\\systemSetting\\displaySettingView.js": "1a376eaccd07b12bd80773be83e080fc",
+  "src\\view\\config\\menu\\systemSetting\\displaySettingView.js": "c92914b05b2353c446fa66c519b95f2f",
   "src\\view\\config\\menu\\systemSetting\\faceRecognitionSettingView.js": "8ac866907bd817d51cde8d757e33b852",
   "src\\view\\config\\menu\\systemSetting\\passLogSettingView.js": "b3fb57b54b5079075c331aceab74a052",
   "src\\view\\config\\menu\\systemSetting\\passwordManagementView.js": "720e32768be124d5591cc0914c9ba340",
-  "src\\view\\config\\menu\\systemSetting\\passwordOpenDoorSettingView.js": "a56728c84d37129fbae06c3a23b01092",
+  "src\\view\\config\\menu\\systemSetting\\passwordOpenDoorSettingView.js": "36107f1e81acd1f711fcb44b246981a5",
   "src\\view\\config\\menu\\systemSetting\\swipeCardRecognitionSettingView.js": "d23ab8015ac4dc7f316fc7ca4b852f6f",
   "src\\view\\config\\menu\\systemSetting\\timeSettingView.js": "7c5744868ad7e40b3d9ce0708e3f7b85",
   "src\\view\\config\\menu\\systemSettingView.js": "91aa4b58c5da0ba01e7a56ee348fee11",
@@ -2724,7 +2725,7 @@
   "src\\view\\gasDetailView.js": "e7f705f9b89459726064e51d57ed9d7c",
   "src\\view\\i18n.js": "94f43798d35026189125bf2534d1bffd",
   "src\\view\\idleView.js": "a1a6f9fb0ec44c59330a7461298aec46",
-  "src\\view\\mainView.js": "0c49e5905a87a5cfd33062df8531e421",
+  "src\\view\\mainView.js": "1a0d51f7ece88d821f4ba9938a505cd9",
   "src\\view\\pinyin\\dict.js": "a7812c30b956099fd248271ad6fd5ac9",
   "src\\view\\pinyin\\pinyin.js": "84e7c2ac116f5c22cf07b563ba230c68",
   "src\\view\\pwdView.js": "e46813353af5b4cd9f9b776328aa1987",
@@ -2733,8 +2734,8 @@
   "src\\view\\wechatBindView.js": "6d0239d71de3c1cf4c2e0817cd65ce3f",
   "src\\view\\wechatFaceView.js": "65f5edfbe0ef402c66bd62bd3eebec49",
   "src\\view\\wechatNetView.js": "84d8dd397ed6483a25ab99174e652362",
-  "src\\worker\\mqttWorker.js": "2dda93d129f1edd9f8a52aceddb0079d",
-  "src\\worker\\netWorker.js": "e38b00c21c77dc5b98425f12068f85ff",
-  "src\\worker\\passRecordWorker.js": "ad27fa58b7de2b8155bb3517e601bef4",
+  "src\\worker\\mqttWorker.js": "611a50d831add8ca508fc69dbef69905",
+  "src\\worker\\netWorker.js": "6ee5ea8dedc2a330974d72a448175d45",
+  "src\\worker\\passRecordWorker.js": "8b2ce900d926878f65db8fdc69b1eb3a",
   "src\\worker\\screenWorker.js": "57a6f54f05c57e186e44892c97e36647"
 }
\ No newline at end of file
diff --git a/vf107/.temp/md5snew.json b/vf107/.temp/md5snew.json
index e50cb99..e3b7657 100644
--- a/vf107/.temp/md5snew.json
+++ b/vf107/.temp/md5snew.json
@@ -45,7 +45,7 @@
   "dxmodules\\dxCommonUtils.js": "9d408cedb29cce9838c10ae5d1a8c2aa",
   "dxmodules\\dxConfig.js": "24072559b3cb1ec5c206cb358eaaaaae",
   "dxmodules\\dxDisplay.js": "5c80ee7de62e3f7b08eed6e3e0a8b3c1",
-  "dxmodules\\dxDriver.js": "1e27304f7ecc691ac66293cd065e6a14",
+  "dxmodules\\dxDriver.js": "63c8348a2a4a31911ce8a1626aa8f5c4",
   "dxmodules\\dxEventBus.js": "075ac9f2d465c92a9446ea07a6e2bfe6",
   "dxmodules\\dxFacial.js": "08f40369fd06cb3f5f69cd035d4ecab2",
   "dxmodules\\dxFacialBarcode.js": "67508897203cf7382f4bb20c4044dc17",
@@ -63,7 +63,7 @@
   "dxmodules\\dxNfcCard.js": "689161d840c1ee82107e55b3e43da5c3",
   "dxmodules\\dxNtp.js": "54a83064faa67f8f4991e1da56a3caf4",
   "dxmodules\\dxOs.js": "8171120055734e75dd6c878862ae965a",
-  "dxmodules\\dxOta.js": "a4bf84aaead7298c5da10161644f2b1f",
+  "dxmodules\\dxOta.js": "2dd095485717018eb451e5110aca4934",
   "dxmodules\\dxPwm.js": "d8238b43ef7c0d77a33108290394e12c",
   "dxmodules\\dxQrRule.js": "bfa9e2b4725c4fa358a2988f63c67210",
   "dxmodules\\dxSqliteDB.js": "4762a29fb74d837d43d1d19415f77536",
@@ -2465,7 +2465,7 @@
   "resource\\image\\voiceBroadcast.png": "e6f1a31ba7159962d18b77deef71c106",
   "resource\\image\\wifi.png": "fd668b648ac984ed92fad8e40e151283",
   "resource\\image\\wifi_dark.png": "37505f892ac6a43cb8dc5ea685de9740",
-  "resource\\langPack.js": "956b0d902f723e4817319436ee7df117",
+  "resource\\langPack.js": "72c5238aa93a1dc6a79b9466b5ebcf44",
   "resource\\wav\\alarm.wav": "fe9d43cfb930f873973cc31fd6e8c132",
   "resource\\wav\\AR\\calibration_1s.wav": "a5ed7bdf10f5c0bec1f964cbaf8d7c59",
   "resource\\wav\\AR\\calibration_2s.wav": "1a533e06dd209b7b87d48947357a0ca0",
@@ -2670,23 +2670,24 @@
   "src\\common\\utils\\stringUtils.js": "425d9cd0390ab8a60f1507544c2cb00a",
   "src\\common\\utils\\tokenUtil.js": "b7abd3698644aadb7d3e936fb6f7fc8b",
   "src\\common\\utils\\utils.js": "bbee074a060e962a570dddc4d586504d",
-  "src\\config.json": "6619f6367ac0230030de3131160a2178",
-  "src\\controller.js": "954bd6baaf4a7f91b7534f71b0e2365b",
-  "src\\driver.js": "42e819e90d7d5b00191447edb06e928c",
-  "src\\main.js": "51de780e61133a6f39ba5554dacf7644",
-  "src\\screen.js": "b8a256f4f3ba51b4c1e49fcb69e06b28",
-  "src\\service\\accessService.js": "304718a9a06ded28947373c3d9a21295",
-  "src\\service\\api.js": "def5b52441ccc827913a73478cc7c32a",
+  "src\\config.json": "53cf90582fedb3aca8e3ac2848386f36",
+  "src\\controller.js": "35dd417593c4510119576717c717e20b",
+  "src\\driver.js": "b0c3958d69f7e0021a70d8537077ff5d",
+  "src\\main.js": "d455a38100d386fc2eed8bef4c92e7ba",
+  "src\\screen.js": "01812eb2816143c98595939d2c54f2ff",
+  "src\\service\\accessService.js": "e242b879cf8d1e4f326aee9168e9d4d5",
+  "src\\service\\api.js": "24a45cb2acc4306a1f4dd54de559f9f0",
   "src\\service\\codeService.js": "e3f53b983c37a91d85a3de95fab7745d",
-  "src\\service\\configService.js": "d1c3c533c1d451c2eaf46758b4efeb19",
+  "src\\service\\configService.js": "c45b2005ba236b74be9f04ab76635abf",
+  "src\\service\\demo.js": "1f9a570135f63aa5b607743bb5a9e7f4",
   "src\\service\\faceService.js": "cfc3cf7d510f2ba6d6fcedb1251e0795",
   "src\\service\\fingerService.js": "0fee47e46ded411c2da21eb508d8f9ba",
   "src\\service\\gpiokeyService.js": "7aeb81b1577df935f147f3817a0a144b",
-  "src\\service\\grainService.js": "3ec28482d55059fd09d091145fad041c",
-  "src\\service\\httpService.js": "567d6f52d5392e3d95a54264e631944e",
-  "src\\service\\mqttService.js": "eafd4b82b1d5a7d02b32d046bf492ac9",
+  "src\\service\\grainService.js": "940788cbc2aea5b20789b752641df6a7",
+  "src\\service\\httpService.js": "6c62661a42e45226f3f82df3d7e0a37e",
+  "src\\service\\mqttService.js": "b7f598ec25422433bccd821b8b29d5f3",
   "src\\service\\nfcService.js": "fff19d7f08d3a499455ed93a5376c0fd",
-  "src\\service\\sqliteService.js": "9dd93a7afd36b50e6be015e950aaff83",
+  "src\\service\\sqliteService.js": "f1816a98a378b3ed2fbd759f6965a8df",
   "src\\service\\uartBleService.js": "f8816894598283c7114b4d8708bb65aa",
   "src\\service\\uartCodeService.js": "ed1952645c055885c78bc6c02699906f",
   "src\\service\\weComService.js": "14896c15403107f7225fce6db9b8a049",
@@ -2700,21 +2701,21 @@
   "src\\view\\config\\menu\\deviceInfo\\dataCapacityInfoView.js": "81fbf258e0ba70c126f850658981469e",
   "src\\view\\config\\menu\\deviceInfo\\systemInfoView.js": "95a96c6d8586410be1fe085dfa61db9f",
   "src\\view\\config\\menu\\deviceInfoView.js": "b703a2f9053c1b089294b3dffdf6a449",
-  "src\\view\\config\\menu\\doorControlView.js": "2b29eff26537ab92171a40110b8e8c0e",
+  "src\\view\\config\\menu\\doorControlView.js": "f2476da5f529cac859dd24776b210bf6",
   "src\\view\\config\\menu\\helpView.js": "b3cf2078efe3a274740276b550b68b63",
   "src\\view\\config\\menu\\localUser\\faceEnterView.js": "f6dc4e020a4eddba902820d4b2444ee3",
   "src\\view\\config\\menu\\localUser\\fingerApplyView.js": "b2b5a46109f7ac768ae6d18131a33fbe",
   "src\\view\\config\\menu\\localUser\\fingerEnterView.js": "46dd45fe0e8d06410a5f2bcbeb7be5ad",
-  "src\\view\\config\\menu\\localUser\\localUserAddView.js": "8266626bf9cadde968e2b439ef9073b0",
-  "src\\view\\config\\menu\\localUserView.js": "f7881e4a47fe06648d0934f286d59775",
-  "src\\view\\config\\menu\\networkSettingView.js": "7cb7b7ef6c1d49f819f509de43e49a56",
-  "src\\view\\config\\menu\\recordQuery\\recordQueryDetailView.js": "79e15d726de5146bab15a3dba533a82b",
+  "src\\view\\config\\menu\\localUser\\localUserAddView.js": "e9991161a3e5d4344b22f7c4ad3dac4c",
+  "src\\view\\config\\menu\\localUserView.js": "2533606f36feba75efe922cc6b6f883a",
+  "src\\view\\config\\menu\\networkSettingView.js": "740f7a643a0fb4c3caa3eb85482d85cc",
+  "src\\view\\config\\menu\\recordQuery\\recordQueryDetailView.js": "b3ef27a7b02bc59a5c2aa4d977efc30d",
   "src\\view\\config\\menu\\recordQueryView.js": "f640c2f2d560213c44633d7ea36c6960",
-  "src\\view\\config\\menu\\systemSetting\\displaySettingView.js": "1a376eaccd07b12bd80773be83e080fc",
+  "src\\view\\config\\menu\\systemSetting\\displaySettingView.js": "c92914b05b2353c446fa66c519b95f2f",
   "src\\view\\config\\menu\\systemSetting\\faceRecognitionSettingView.js": "8ac866907bd817d51cde8d757e33b852",
   "src\\view\\config\\menu\\systemSetting\\passLogSettingView.js": "b3fb57b54b5079075c331aceab74a052",
   "src\\view\\config\\menu\\systemSetting\\passwordManagementView.js": "720e32768be124d5591cc0914c9ba340",
-  "src\\view\\config\\menu\\systemSetting\\passwordOpenDoorSettingView.js": "a56728c84d37129fbae06c3a23b01092",
+  "src\\view\\config\\menu\\systemSetting\\passwordOpenDoorSettingView.js": "36107f1e81acd1f711fcb44b246981a5",
   "src\\view\\config\\menu\\systemSetting\\swipeCardRecognitionSettingView.js": "d23ab8015ac4dc7f316fc7ca4b852f6f",
   "src\\view\\config\\menu\\systemSetting\\timeSettingView.js": "7c5744868ad7e40b3d9ce0708e3f7b85",
   "src\\view\\config\\menu\\systemSettingView.js": "91aa4b58c5da0ba01e7a56ee348fee11",
@@ -2724,7 +2725,7 @@
   "src\\view\\gasDetailView.js": "e7f705f9b89459726064e51d57ed9d7c",
   "src\\view\\i18n.js": "94f43798d35026189125bf2534d1bffd",
   "src\\view\\idleView.js": "a1a6f9fb0ec44c59330a7461298aec46",
-  "src\\view\\mainView.js": "0c49e5905a87a5cfd33062df8531e421",
+  "src\\view\\mainView.js": "1a0d51f7ece88d821f4ba9938a505cd9",
   "src\\view\\pinyin\\dict.js": "a7812c30b956099fd248271ad6fd5ac9",
   "src\\view\\pinyin\\pinyin.js": "84e7c2ac116f5c22cf07b563ba230c68",
   "src\\view\\pwdView.js": "e46813353af5b4cd9f9b776328aa1987",
@@ -2733,8 +2734,8 @@
   "src\\view\\wechatBindView.js": "6d0239d71de3c1cf4c2e0817cd65ce3f",
   "src\\view\\wechatFaceView.js": "65f5edfbe0ef402c66bd62bd3eebec49",
   "src\\view\\wechatNetView.js": "84d8dd397ed6483a25ab99174e652362",
-  "src\\worker\\mqttWorker.js": "2dda93d129f1edd9f8a52aceddb0079d",
-  "src\\worker\\netWorker.js": "e38b00c21c77dc5b98425f12068f85ff",
-  "src\\worker\\passRecordWorker.js": "ad27fa58b7de2b8155bb3517e601bef4",
+  "src\\worker\\mqttWorker.js": "611a50d831add8ca508fc69dbef69905",
+  "src\\worker\\netWorker.js": "6ee5ea8dedc2a330974d72a448175d45",
+  "src\\worker\\passRecordWorker.js": "8b2ce900d926878f65db8fdc69b1eb3a",
   "src\\worker\\screenWorker.js": "57a6f54f05c57e186e44892c97e36647"
 }
\ No newline at end of file
diff --git a/vf107/src/config.json b/vf107/src/config.json
index 0ca3c00..446f016 100644
--- a/vf107/src/config.json
+++ b/vf107/src/config.json
@@ -139,5 +139,7 @@
     // HTTP鎺ュ彛璺緞
     "http.safeInputAccess": "http://192.168.1.227:80/cgi-bin/safeInputAccess",
     // 鏄惁寮�鍚皵浣撴祿搴﹂獙璇� 1:鏄� 0:鍚�
-    "gas.verification": 1
+    "gas.verification": 0,
+    //鏄惁寮�鍚畨鍏ㄥ叆浠撹仈鍔ㄦ帶鍒� 1锛氭槸 0锛氬惁
+    "safeInputControl": 0
 }
\ No newline at end of file
diff --git a/vf107/src/service/grainService.js b/vf107/src/service/grainService.js
index a182a10..83dc0dc 100644
--- a/vf107/src/service/grainService.js
+++ b/vf107/src/service/grainService.js
@@ -13,21 +13,25 @@
 const grainService = {}
 
 // 浠庨厤缃腑鑾峰彇涓氬姟缂栫爜瀹氫箟
-const functionId = {
-    gasDetection: config.get('functionId.gasDetection') || "1000",
-    safeInputControl: config.get('functionId.safeInputControl') || "2000",
-    lightControl: config.get('functionId.lightControl') || "3000",
-    doorStatus: config.get('functionId.doorStatus') || "4000"
+function getFunctionId() {
+    return {
+        gasDetection: config.get('functionId.gasDetection') || "1000",
+        safeInputControl: config.get('functionId.safeInputControl') || "2000",
+        lightControl: config.get('functionId.lightControl') || "3000",
+        doorStatus: config.get('functionId.doorStatus') || "4000"
+    }
 }
 
 // 浠庨厤缃腑鑾峰彇鎺ュ彛杩斿洖缂栫爜
-const respCode = {
-    success: config.get('respCode.success') || "200",
-    badRequest: config.get('respCode.badRequest') || "400",
-    unauthorized: config.get('respCode.unauthorized') || "401",
-    forbidden: config.get('respCode.forbidden') || "403",
-    notFound: config.get('respCode.notFound') || "404",
-    serverError: config.get('respCode.serverError') || "500"
+function getRespCode() {
+    return {
+        success: config.get('getRespCode().success') || "200",
+        badRequest: config.get('respCode.badRequest') || "400",
+        unauthorized: config.get('respCode.unauthorized') || "401",
+        forbidden: config.get('respCode.forbidden') || "403",
+        notFound: config.get('respCode.notFound') || "404",
+        serverError: config.get('respCode.serverError') || "500"
+    }
 }
 
 // 閿欒鐮佸搴旂殑閿欒淇℃伅
@@ -120,6 +124,17 @@
  * @returns {boolean} true琛ㄧず姘斾綋娴撳害鍚堟牸锛宖alse琛ㄧず姘斾綋娴撳害涓嶅悎鏍�
  */
 grainService.checkGasConcentration = function(callback) {
+    // 妫�鏌ユ槸鍚﹀紑鍚皵浣撴祿搴﹂獙璇�
+    const isGasDetectionEnabled = config.get('gas.verification') !== 0
+    if (!isGasDetectionEnabled) {
+        logger.info('[grain]: 姘斾綋娴撳害楠岃瘉鏈惎鐢紝鐩存帴杩斿洖')
+        // 璋冪敤鍥炶皟鍑芥暟
+        if (callback) {
+            callback()
+        }
+        return true
+    }
+    
     // 浣跨敤setTimeout灏咹TTP璇锋眰鏀惧叆鍚庡彴鎵ц锛岄伩鍏嶉樆濉炰富绾跨▼
     std.setTimeout(() => {
         try {
@@ -138,7 +153,7 @@
                 sn: config.get("sys.sn") || " ", // 璁惧搴忓垪鍙凤紝浠庨厤缃腑鑾峰彇
                 houseId: "0000", // 浠撳粧缂栫爜锛岄粯璁ゅ~鍏�"0000"
                 outId: "0000", // 鑷畾涔夌紪鐮侊紝榛樿濉厖"0000"
-                functionId: functionId.gasDetection, // 姘斾綋娴撳害妫�娴嬪姛鑳界爜
+                functionId: getFunctionId().gasDetection, // 姘斾綋娴撳害妫�娴嬪姛鑳界爜
                 timestamp: Date.now().toString() // 鏃堕棿鎴�
             }
             
@@ -163,7 +178,7 @@
                     logger.info(`[grain]: 瑙f瀽鍚庣殑姘斾綋娴撳害鏁版嵁: ${JSON.stringify(gasData)}`)
                     
                     // 鏍规嵁鎺ュ彛杩斿洖缂栫爜杩涜鏃ュ織杈撳嚭
-                    if (gasData.respCode === respCode.success) {
+                    if (gasData.respCode === getRespCode().success) {
                         logger.info(`[grain]: 姘斾綋娴撳害妫�娴嬫帴鍙h皟鐢ㄦ垚鍔焋)
                     } else {
                         logger.error(`[grain]: 姘斾綋娴撳害妫�娴嬫帴鍙h皟鐢ㄥけ璐ワ紝杩斿洖缂栫爜: ${gasData.respCode}, 杩斿洖淇℃伅: ${gasData.respMsg}`)
@@ -178,7 +193,7 @@
                         logger.info(`[grain]: 娓呯悊鍚庤В鏋愮殑姘斾綋娴撳害鏁版嵁: ${JSON.stringify(gasData)}`)
                         
                         // 鏍规嵁鎺ュ彛杩斿洖缂栫爜杩涜鏃ュ織杈撳嚭
-                        if (gasData.respCode === respCode.success) {
+                        if (gasData.respCode === getRespCode().success) {
                             logger.info(`[grain]: 姘斾綋娴撳害妫�娴嬫帴鍙h皟鐢ㄦ垚鍔焋)
                         } else {
                             logger.error(`[grain]: 姘斾綋娴撳害妫�娴嬫帴鍙h皟鐢ㄥけ璐ワ紝杩斿洖缂栫爜: ${gasData.respCode}, 杩斿洖淇℃伅: ${gasData.respMsg}`)
@@ -259,6 +274,13 @@
  * @returns {boolean} true琛ㄧず鐘舵�佷俊鎭幏鍙栨垚鍔燂紝false琛ㄧず澶辫触
  */
 grainService.checkDevConcentration = function(params) {
+    // 妫�鏌ユ槸鍚﹀紑鍚畨鍏ㄥ叆浠撹仈鍔ㄦ帶鍒�
+    const isSafeInputControlEnabled = config.get('safeInputControl') === 1
+    if (!isSafeInputControlEnabled) {
+        logger.info('[grain]: 瀹夊叏鍏ヤ粨鑱斿姩鎺у埗鍔熻兘鏈惎鐢�')
+        return false
+    }
+    
     // 浣跨敤setTimeout灏咹TTP璇锋眰鏀惧叆鍚庡彴鎵ц锛岄伩鍏嶉樆濉炰富绾跨▼
     std.setTimeout(() => {
         try {
@@ -277,7 +299,7 @@
                 sn: config.get("sys.sn") || " ", // 璁惧搴忓垪鍙凤紝浠庨厤缃腑鑾峰彇
                 houseId: "0000", // 浠撳粧缂栫爜锛岄粯璁ゅ~鍏�"0000"
                 outId: "0000", // 鑷畾涔夌紪鐮侊紝榛樿濉厖"0000"
-                functionId: params && params.functionId ? params.functionId : functionId.safeInputControl, // 鍔熻兘鐮侊紝榛樿涓哄畨鍏ㄥ叆浠撹仈鍔ㄦ帶鍒�
+                functionId: params && params.functionId ? params.functionId : getFunctionId().safeInputControl, // 鍔熻兘鐮侊紝榛樿涓哄畨鍏ㄥ叆浠撹仈鍔ㄦ帶鍒�
                 timestamp: Date.now().toString(), // 鏃堕棿鎴�
                 data: {}
             }
@@ -311,7 +333,7 @@
                     logger.info(`[grain]: 瑙f瀽鍚庣殑鐘舵�佷俊鎭暟鎹�: ${JSON.stringify(statusData)}`)
                     
                     // 鏍规嵁鎺ュ彛杩斿洖缂栫爜杩涜鏃ュ織杈撳嚭
-                    if (statusData.respCode === respCode.success) {
+                    if (statusData.respCode === getRespCode().success) {
                         logger.info(`[grain]: 鐘舵�佷俊鎭帴鍙h皟鐢ㄦ垚鍔焋)
                         // 妫�鏌ata鏄惁涓虹┖锛屼笉涓虹┖鎵嶈Е鍙戦�氱煡
                         if (Object.keys(postData.data).length > 0) {
@@ -364,7 +386,7 @@
                         logger.info(`[grain]: 娓呯悊鍚庤В鏋愮殑鐘舵�佷俊鎭暟鎹�: ${JSON.stringify(statusData)}`)
                         
                         // 鏍规嵁鎺ュ彛杩斿洖缂栫爜杩涜鏃ュ織杈撳嚭
-                        if (statusData.respCode === respCode.success) {
+                        if (statusData.respCode === getRespCode().success) {
                             logger.info(`[grain]: 鐘舵�佷俊鎭帴鍙h皟鐢ㄦ垚鍔焋)
                             // 妫�鏌ata鏄惁涓虹┖锛屼笉涓虹┖鎵嶈Е鍙戦�氱煡
                             if (Object.keys(postData.data).length > 0) {
@@ -458,7 +480,7 @@
                 sn: config.get("sys.sn") || " ", // 璁惧搴忓垪鍙凤紝浠庨厤缃腑鑾峰彇
                 houseId: "0000", // 浠撳粧缂栫爜锛岄粯璁ゅ~鍏�"0000"
                 outId: "0000", // 鑷畾涔夌紪鐮侊紝榛樿濉厖"0000"
-                functionId: functionId.lightControl, // 浠撳唴鐓ф槑鑱斿姩鎺у埗鍔熻兘鐮�
+                functionId: getFunctionId().lightControl, // 浠撳唴鐓ф槑鑱斿姩鎺у埗鍔熻兘鐮�
                 timestamp: Date.now().toString(), // 鏃堕棿鎴�
                 data: {}
             }
@@ -489,7 +511,7 @@
                     logger.info(`[grain]: 瑙f瀽鍚庣殑浠撳唴鐓ф槑鑱斿姩鎺у埗鍝嶅簲鏁版嵁: ${JSON.stringify(statusData)}`)
                     
                     // 鏍规嵁鎺ュ彛杩斿洖缂栫爜杩涜鏃ュ織杈撳嚭
-                    if (statusData.respCode === respCode.success) {
+                    if (statusData.respCode === getRespCode().success) {
                         logger.info(`[grain]: 浠撳唴鐓ф槑鑱斿姩鎺у埗鎺ュ彛璋冪敤鎴愬姛`)
                         // 瑙﹀彂鎴愬姛寮圭獥
                         bus.fire('showAccessResult', {
@@ -536,7 +558,7 @@
                         logger.info(`[grain]: 娓呯悊鍚庤В鏋愮殑浠撳唴鐓ф槑鑱斿姩鎺у埗鍝嶅簲鏁版嵁: ${JSON.stringify(statusData)}`)
                         
                         // 鏍规嵁鎺ュ彛杩斿洖缂栫爜杩涜鏃ュ織杈撳嚭
-                        if (statusData.respCode === respCode.success) {
+                        if (statusData.respCode === getRespCode().success) {
                             logger.info(`[grain]: 浠撳唴鐓ф槑鑱斿姩鎺у埗鎺ュ彛璋冪敤鎴愬姛`)
                             // 瑙﹀彂鎴愬姛寮圭獥
                             bus.fire('showAccessResult', {
@@ -625,7 +647,7 @@
                     sn: config.get("sys.sn") || " ", // 璁惧搴忓垪鍙凤紝浠庨厤缃腑鑾峰彇
                     houseId: "0000", // 浠撳粧缂栫爜锛岄粯璁ゅ~鍏�"0000"
                     outId: "0000", // 鑷畾涔夌紪鐮侊紝榛樿濉厖"0000"
-                    functionId: functionId.doorStatus, // 闂ㄧ鐘舵�佸姛鑳界爜
+                    functionId: getFunctionId().doorStatus, // 闂ㄧ鐘舵�佸姛鑳界爜
                     timestamp: Date.now().toString(), // 鏃堕棿鎴�
                     data: {
                         doorStatus: doorStatusData.status // 闂ㄧ鐘舵��
diff --git a/vf107/src/view/config/menu/doorControlView.js b/vf107/src/view/config/menu/doorControlView.js
index 04e9cb1..4cf5e58 100644
--- a/vf107/src/view/config/menu/doorControlView.js
+++ b/vf107/src/view/config/menu/doorControlView.js
@@ -27,6 +27,7 @@
         onlineCheckingSettingSwitch.select(configAll['mqtt.onlinecheck'] == 1)
         onlineCheckingTimeoutSettingInput.text(configAll['mqtt.timeout'] + '')
         gasVerificationSwitch.select(configAll['gas.verification'] == 1)
+        safeInputControlSwitch.select(configAll['safeInputControl'] == 1)
     })
 
     const titleBox = viewUtils.title(screenMain, configView.screenMain, 'doorControlViewTitle', 'doorControlView.title')
@@ -243,6 +244,25 @@
     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 safeInputControlBox = dxui.View.build('safeInputControlBox', screenMain)
+    viewUtils._clearStyle(safeInputControlBox)
+    safeInputControlBox.align(dxui.Utils.ALIGN.TOP_MID, 0, screen.screenSize.height * (956 / 1280))
+    safeInputControlBox.setSize(screen.screenSize.width * (550 / 600), screen.screenSize.height * (76 / 1280))
+    safeInputControlBox.borderWidth(1)
+    safeInputControlBox.setBorderColor(0xDEDEDE)
+    safeInputControlBox.obj.setStyleBorderSide(dxui.Utils.ENUM.LV_BORDER_SIDE_BOTTOM, 0)
+
+    const safeInputControlLbl = dxui.Label.build('safeInputControlLbl', safeInputControlBox)
+    safeInputControlLbl.text('瀹夊叏鍏ヤ粨鑱斿姩鎺у埗')
+    safeInputControlLbl.align(dxui.Utils.ALIGN.LEFT_MID, 0, 0)
+    safeInputControlLbl.textFont(viewUtils.font(26))
+
+    const safeInputControlSwitch = dxui.Switch.build('safeInputControlSwitch', safeInputControlBox)
+    safeInputControlSwitch.align(dxui.Utils.ALIGN.RIGHT_MID, 0, 0)
+    safeInputControlSwitch.setSize(screen.screenSize.width * (70 / 600), screen.screenSize.height * (35 / 1280))
+    safeInputControlSwitch.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: {
@@ -257,6 +277,7 @@
             gas: {
                 verification: gasVerificationSwitch.isSelect() ? 1 : 0
             },
+            safeInputControl: safeInputControlSwitch.isSelect() ? 1 : 0,
             mqtt: {
                 addr: mqttSettingInput.text(),
                 username: mqttUserSettingInput.text(),
diff --git a/vf107/src/view/mainView.js b/vf107/src/view/mainView.js
index 7fd7566..3680c43 100644
--- a/vf107/src/view/mainView.js
+++ b/vf107/src/view/mainView.js
@@ -21,7 +21,8 @@
 const mainView = {
     authComplete: false, // 璁よ瘉鏄惁瀹屾垚锛岀敤浜庢帶鍒禪I鏇存柊
     verifiedUsers: {}, // 瀛樺偍宸叉牳楠屾垚鍔熺殑鐢ㄦ埛淇℃伅
-    eventListenersRegistered: false // 浜嬩欢鐩戝惉鍣ㄦ槸鍚﹀凡娉ㄥ唽
+    eventListenersRegistered: false, // 浜嬩欢鐩戝惉鍣ㄦ槸鍚﹀凡娉ㄥ唽
+    resetTimerId: null // 瀛樺偍閲嶇疆鐢ㄦ埛UI鐨勫畾鏃跺櫒ID
 }
 
 // 鍔犺浇涓昏鍥剧殑鏂规硶
@@ -30,8 +31,8 @@
     // 渚嬪鏇存柊璁惧淇℃伅銆佹皵浣撴祿搴︽暟鎹瓑
     try {
         // 鏇存柊璁惧淇℃伅
-        let config = screen.getConfig()
-        let sn = config["sys.sn"] || ""
+        let screenConfig = screen.getConfig()
+        let sn = screenConfig["sys.sn"] || ""
         // 鐩存帴浠巒et妯″潡鑾峰彇IP鍦板潃锛岀‘淇濊幏鍙栧埌鏈�鏂扮殑IP
         let ip = ""
         try {
@@ -41,8 +42,8 @@
                 ip = param.ip
             }
         } catch (error) {
-            // 鍑洪敊鏃朵娇鐢╟onfig涓殑IP
-            ip = config["net.ip"] || ""
+            // 鍑洪敊鏃朵娇鐢╯creenConfig涓殑IP
+            ip = screenConfig["net.ip"] || ""
         }
         // 閫氳繃mainView瀵硅薄璁块棶鏍囩
         if (mainView.snInfoLbl && mainView.ipInfoLbl) {
@@ -81,8 +82,8 @@
 
     // 鏇存柊璁惧淇℃伅锛圫N鍜孖P锛�
     function updateDeviceInfo() {
-        let config = screen.getConfig()
-        let sn = config["sys.sn"] || ""
+        let screenConfig = screen.getConfig()
+        let sn = screenConfig["sys.sn"] || ""
         // 鐩存帴浠巒et妯″潡鑾峰彇IP鍦板潃锛岀‘淇濊幏鍙栧埌鏈�鏂扮殑IP
         let ip = ""
         try {
@@ -92,8 +93,8 @@
                 ip = param.ip
             }
         } catch (error) {
-            // 鍑洪敊鏃朵娇鐢╟onfig涓殑IP
-            ip = config["net.ip"] || ""
+            // 鍑洪敊鏃朵娇鐢╯creenConfig涓殑IP
+            ip = screenConfig["net.ip"] || ""
         }
         // 閫氳繃mainView瀵硅薄璁块棶鏍囩
         if (mainView.snInfoLbl && mainView.ipInfoLbl) {
@@ -109,11 +110,11 @@
 
     // 鏇存柊搴撳尯鍚嶇О鍜屼粨鍙凤紙鍙湪绋嬪簭鍚姩鍜岄厤缃慨鏀规椂璋冪敤锛�
     function updateWarehouseInfo() {
-        let config = screen.getConfig()
+        let screenConfig = screen.getConfig()
         // 鑾峰彇浠撳彿淇℃伅
-        let houseName = config["houseName"] || "01鍙蜂粨"
+        let houseName = screenConfig["houseName"] || "01鍙蜂粨"
         // 鑾峰彇搴撳尯鍚嶇О
-        let GranaryName = config["GranaryName"] || "涓ぎ鍌ㄥ绮煇鏌愮洿灞炲簱"
+        let GranaryName = screenConfig["GranaryName"] || "涓ぎ鍌ㄥ绮煇鏌愮洿灞炲簱"
         logger.info(`[mainView]: 鏇存柊搴撳尯鍚嶇О鍜屼粨鍙�: 浠撳彿=${houseName}, 搴撳尯鍚嶇О=${GranaryName}`)
         // 鏇存柊椤堕儴鏍囬鏍忕殑搴撳尯鍚嶇О
         if (mainView.headerLbl) {
@@ -131,8 +132,8 @@
     // 鏇存柊缃戠粶鍥炬爣
     function updateNetworkIcon() {
         try {
-            let config = screen.getConfig()
-            let netType = config["net.type"] || 1
+            let screenConfig = screen.getConfig()
+            let netType = screenConfig["net.type"] || 1
             let isConnected = net.isConnected()
             
             // 闅愯棌鎵�鏈夌綉缁滃浘鏍�
@@ -293,9 +294,9 @@
                 logger.info('[mainView]: accessRes浜嬩欢瑙﹀彂, result=' + result + ', data=' + JSON.stringify(data))
                 
                 // 娓呴櫎涔嬪墠鐨勫畾鏃跺櫒
-                if (resetTimerId) {
-                    std.clearTimeout(resetTimerId)
-                    resetTimerId = null
+                if (mainView.resetTimerId) {
+                    std.clearTimeout(mainView.resetTimerId)
+                    mainView.resetTimerId = null
                     logger.info('[mainView]: 娓呴櫎涔嬪墠鐨勯噸缃畾鏃跺櫒')
                 }
                 
@@ -415,7 +416,7 @@
                 }
                 
                 // 璁剧疆1鍒嗛挓鍚庨噸缃敤鎴稶I鐨勫畾鏃跺櫒
-                resetTimerId = std.setTimeout(() => {
+                mainView.resetTimerId = std.setTimeout(() => {
                     logger.info('[mainView]: 1鍒嗛挓瀹氭椂鍣ㄨЕ鍙戯紝閲嶇疆鐢ㄦ埛UI')
                     // 瑙﹀彂閫氳瑙i攣瀹屾垚浜嬩欢锛岄�氱煡UI閲嶇疆
                     bus.fire("accessUnlockComplete")
@@ -439,6 +440,11 @@
                             let dualAuthInfo = data.dualAuthInfo
                             logger.info('[mainView]: 鍙屼汉璁よ瘉鎴愬姛锛屾洿鏂扮敤鎴稶I, user1=' + dualAuthInfo.firstUserId + ', user2=' + dualAuthInfo.secondUserId)
                             
+                            // 瀛樺偍宸叉牳楠屾垚鍔熺殑鐢ㄦ埛淇℃伅
+                            mainView.verifiedUsers[1] = dualAuthInfo.firstUserId
+                            mainView.verifiedUsers[2] = dualAuthInfo.secondUserId
+                            logger.info('[mainView]: 瀛樺偍鍙屼汉璁よ瘉鐢ㄦ埛淇℃伅, user1=' + dualAuthInfo.firstUserId + ', user2=' + dualAuthInfo.secondUserId)
+                            
                             // 鏇存柊鐢ㄦ埛1鐨刄I
                             mainView.updateUserUI(1, dualAuthInfo.firstUserId, true, data.firstUserFileName || fileName)
                             
@@ -449,12 +455,21 @@
                             let dualAuthInfo = data.dualAuthInfo
                             logger.info('[mainView]: 绗竴鐢ㄦ埛璁よ瘉鎴愬姛锛岀瓑寰呯浜岀敤鎴疯璇侊紝鏇存柊鐢ㄦ埛UI, user1=' + dualAuthInfo.firstUserId)
                             
+                            // 瀛樺偍宸叉牳楠屾垚鍔熺殑鐢ㄦ埛淇℃伅
+                            mainView.verifiedUsers[1] = dualAuthInfo.firstUserId
+                            logger.info('[mainView]: 瀛樺偍绗竴鐢ㄦ埛璁よ瘉淇℃伅, user1=' + dualAuthInfo.firstUserId)
+                            
                             // 鏇存柊鐢ㄦ埛1鐨刄I
                             mainView.updateUserUI(1, dualAuthInfo.firstUserId, true, data.firstUserFileName || fileName)
                         } else {
                             // 鍗曚汉璁よ瘉锛屾洿鏂扮敤鎴�1鐨刄I
                             if (data.userId) {
                                 logger.info('[mainView]: 鍗曚汉璁よ瘉鎴愬姛锛屾洿鏂扮敤鎴稶I, userId=' + data.userId)
+                                
+                                // 瀛樺偍宸叉牳楠屾垚鍔熺殑鐢ㄦ埛淇℃伅
+                                mainView.verifiedUsers[1] = data.userId
+                                logger.info('[mainView]: 瀛樺偍鍗曚汉璁よ瘉鐢ㄦ埛淇℃伅, user1=' + data.userId)
+                                
                                 mainView.updateUserUI(1, data.userId, true, fileName)
                             }
                         }
@@ -653,8 +668,7 @@
             logger.info('[mainView]: 浜嬩欢鐩戝惉鍣ㄦ敞鍐屽畬鎴�')
         }
 
-        // 瀛樺偍瀹氭椂鍣↖D
-        let resetTimerId = null
+
 
         // 鑾峰彇姘斾綋娴撳害鍜岀姸鎬佷俊鎭�
         grainService.checkGasConcentration()
@@ -785,8 +799,8 @@
         const headerLbl = dxui.Label.build('headerLbl', headerBox)
         mainView.headerLbl = headerLbl
         // 浠庨厤缃腑鑾峰彇搴撳尯鍚嶇О
-        const config = screen.getConfig()
-        const GranaryName = config['GranaryName'] || '涓ぎ鍌ㄥ绮煇鏌愮洿灞炲簱'
+        const screenConfig = screen.getConfig()
+        const GranaryName = screenConfig['GranaryName'] || '涓ぎ鍌ㄥ绮煇鏌愮洿灞炲簱'
         headerLbl.text(GranaryName)
         headerLbl.textFont(viewUtils.font(30)) // 澧炲ぇ瀛椾綋
         headerLbl.textColor(0xffffff)
@@ -795,7 +809,7 @@
         const warehouseLbl = dxui.Label.build('warehouseLbl', overlayBox)
         mainView.warehouseLbl = warehouseLbl
         // 浠庨厤缃腑鑾峰彇浠撳彿淇℃伅
-        const houseName = config['houseName'] || '01鍙蜂粨'
+        const houseName = screenConfig['houseName'] || '01鍙蜂粨'
         warehouseLbl.text(houseName)
         warehouseLbl.textFont(viewUtils.font(30, dxui.Utils.FONT_STYLE.BOLD))
         warehouseLbl.textColor(0x000000)
@@ -1385,6 +1399,18 @@
         // 璁剧疆鎸夐挳鐐瑰嚮浜嬩欢
         mode1Btn.on(dxui.Utils.EVENT.CLICK, () => {
             logger.info('鍏佽杩涗粨妯″紡鎸夐挳鐐瑰嚮')
+            const isSafeInputControlEnabled = config.get('safeInputControl') === 1
+            if (!isSafeInputControlEnabled) {
+                logger.info('[grain]: 瀹夊叏鍏ヤ粨鑱斿姩鎺у埗鍔熻兘鏈惎鐢�')
+                // 瑙﹀彂鏈惎鐢ㄥ脊绐�
+                bus.fire('showAccessResult', {
+                faceAuth: true,
+                gasConcentration: true,
+                accessAllowed: false,
+                message: "*瀹夊叏鍏ヤ粨鑱斿姩鎺у埗鍔熻兘鏈惎鐢�*"
+                })
+                return false
+            }
             // 妫�鏌ユ槸鍚︽湁鐢ㄦ埛宸叉牳楠屾垚鍔�
             if (!mainView.verifiedUsers[1] && !mainView.verifiedUsers[2]) {
                 // 鏄剧ず寮圭獥閫氱煡
@@ -1410,6 +1436,18 @@
     
         inBtn.on(dxui.Utils.EVENT.CLICK, () => {
             logger.info('鍏ヤ粨鎸夐挳鐐瑰嚮')
+            const isSafeInputControlEnabled = config.get('safeInputControl') === 1
+            if (!isSafeInputControlEnabled) {
+                logger.info('[grain]: 瀹夊叏鍏ヤ粨鑱斿姩鎺у埗鍔熻兘鏈惎鐢�')
+                // 瑙﹀彂鏈惎鐢ㄥ脊绐�
+                bus.fire('showAccessResult', {
+                faceAuth: true,
+                gasConcentration: true,
+                accessAllowed: false,
+                message: "*瀹夊叏鍏ヤ粨鑱斿姩鎺у埗鍔熻兘鏈惎鐢�*"
+                })
+                return false
+            }
             // 妫�鏌ユ槸鍚︽湁鐢ㄦ埛宸叉牳楠屾垚鍔�
             if (!mainView.verifiedUsers[1] && !mainView.verifiedUsers[2]) {
                 // 鏄剧ず寮圭獥閫氱煡
@@ -1436,6 +1474,18 @@
     
         outBtn.on(dxui.Utils.EVENT.CLICK, () => {
             logger.info('鍑轰粨鎸夐挳鐐瑰嚮')
+            const isSafeInputControlEnabled = config.get('safeInputControl') === 1
+            if (!isSafeInputControlEnabled) {
+                logger.info('[grain]: 瀹夊叏鍏ヤ粨鑱斿姩鎺у埗鍔熻兘鏈惎鐢�')
+                // 瑙﹀彂鏈惎鐢ㄥ脊绐�
+                bus.fire('showAccessResult', {
+                faceAuth: true,
+                gasConcentration: true,
+                accessAllowed: false,
+                message: "*瀹夊叏鍏ヤ粨鑱斿姩鎺у埗鍔熻兘鏈惎鐢�*"
+                })
+                return false
+            }
             // 妫�鏌ユ槸鍚︽湁鐢ㄦ埛宸叉牳楠屾垚鍔�
             if (!mainView.verifiedUsers[1] && !mainView.verifiedUsers[2]) {
                 // 鏄剧ず寮圭獥閫氱煡
@@ -1462,6 +1512,18 @@
     
         mode2Btn.on(dxui.Utils.EVENT.CLICK, () => {
             logger.info('鍐閫氶妯″紡鎸夐挳鐐瑰嚮')
+            const isSafeInputControlEnabled = config.get('safeInputControl') === 1
+            if (!isSafeInputControlEnabled) {
+                logger.info('[grain]: 瀹夊叏鍏ヤ粨鑱斿姩鎺у埗鍔熻兘鏈惎鐢�')
+                // 瑙﹀彂鏈惎鐢ㄥ脊绐�
+                bus.fire('showAccessResult', {
+                faceAuth: true,
+                gasConcentration: true,
+                accessAllowed: false,
+                message: "*瀹夊叏鍏ヤ粨鑱斿姩鎺у埗鍔熻兘鏈惎鐢�*"
+                })
+                return false
+            }
             // 妫�鏌ユ槸鍚︽湁鐢ㄦ埛宸叉牳楠屾垚鍔�
             if (!mainView.verifiedUsers[1] && !mainView.verifiedUsers[2]) {
                 // 鏄剧ず寮圭獥閫氱煡
@@ -1470,6 +1532,49 @@
                     gasConcentration: true,
                     accessAllowed: false,
                     message: "*鑱斿姩鎺у埗鎿嶄綔鏃犳潈闄�*"
+                })
+                // 鎾斁璇煶鎻愮ず
+                driver.audio.play('/app/code/resource/CN/wav/control_f.wav')
+                return
+            }
+            // 妫�鏌ユ槸鍚︽湁绉戦暱鏉冮檺
+            let hasSectionChief = false
+            // 妫�鏌ョ敤鎴�1
+            if (mainView.verifiedUsers[1]) {
+                let user1 = sqliteService.d1_person.find({ userId: mainView.verifiedUsers[1] })
+                if (user1 && user1.length > 0) {
+                    try {
+                        let userType = JSON.parse(user1[0].extra).type || 0
+                        if (userType === 1) {
+                            hasSectionChief = true
+                        }
+                    } catch (error) {
+                        logger.error("瑙f瀽鐢ㄦ埛1绫诲瀷澶辫触")
+                    }
+                }
+            }
+            // 妫�鏌ョ敤鎴�2
+            if (!hasSectionChief && mainView.verifiedUsers[2]) {
+                let user2 = sqliteService.d1_person.find({ userId: mainView.verifiedUsers[2] })
+                if (user2 && user2.length > 0) {
+                    try {
+                        let userType = JSON.parse(user2[0].extra).type || 0
+                        if (userType === 1) {
+                            hasSectionChief = true
+                        }
+                    } catch (error) {
+                        logger.error("瑙f瀽鐢ㄦ埛2绫诲瀷澶辫触")
+                    }
+                }
+            }
+            // 濡傛灉娌℃湁绉戦暱鏉冮檺锛屾樉绀烘牳楠屽け璐�
+            if (!hasSectionChief) {
+                // 鏄剧ず寮圭獥閫氱煡
+                bus.fire('showAccessResult', {
+                    faceAuth: false,
+                    gasConcentration: true,
+                    accessAllowed: false,
+                    message: "*鏃犵闀挎潈闄愶紝绂佹鎿嶄綔*"
                 })
                 // 鎾斁璇煶鎻愮ず
                 driver.audio.play('/app/code/resource/CN/wav/control_f.wav')
@@ -1487,6 +1592,18 @@
     
         startBtn.on(dxui.Utils.EVENT.CLICK, () => {
             logger.info('鍚姩鎸夐挳鐐瑰嚮')
+            const isSafeInputControlEnabled = config.get('safeInputControl') === 1
+            if (!isSafeInputControlEnabled) {
+                logger.info('[grain]: 瀹夊叏鍏ヤ粨鑱斿姩鎺у埗鍔熻兘鏈惎鐢�')
+                // 瑙﹀彂鏈惎鐢ㄥ脊绐�
+                bus.fire('showAccessResult', {
+                faceAuth: true,
+                gasConcentration: true,
+                accessAllowed: false,
+                message: "*瀹夊叏鍏ヤ粨鑱斿姩鎺у埗鍔熻兘鏈惎鐢�*"
+                })
+                return false
+            }
             // 妫�鏌ユ槸鍚︽湁鐢ㄦ埛宸叉牳楠屾垚鍔�
             if (!mainView.verifiedUsers[1] && !mainView.verifiedUsers[2]) {
                 // 鏄剧ず寮圭獥閫氱煡
@@ -1513,6 +1630,18 @@
     
         stopBtn.on(dxui.Utils.EVENT.CLICK, () => {
             logger.info('鍏抽棴鎸夐挳鐐瑰嚮')
+            const isSafeInputControlEnabled = config.get('safeInputControl') === 1
+            if (!isSafeInputControlEnabled) {
+                logger.info('[grain]: 瀹夊叏鍏ヤ粨鑱斿姩鎺у埗鍔熻兘鏈惎鐢�')
+                // 瑙﹀彂鏈惎鐢ㄥ脊绐�
+                bus.fire('showAccessResult', {
+                faceAuth: true,
+                gasConcentration: true,
+                accessAllowed: false,
+                message: "*瀹夊叏鍏ヤ粨鑱斿姩鎺у埗鍔熻兘鏈惎鐢�*"
+                })
+                return false
+            }
             // 妫�鏌ユ槸鍚︽湁鐢ㄦ埛宸叉牳楠屾垚鍔�
             if (!mainView.verifiedUsers[1] && !mainView.verifiedUsers[2]) {
                 // 鏄剧ず寮圭獥閫氱煡
@@ -1539,6 +1668,18 @@
     
         mode3Btn.on(dxui.Utils.EVENT.CLICK, () => {
             logger.info('绂佹杩涗粨妯″紡鎸夐挳鐐瑰嚮')
+            const isSafeInputControlEnabled = config.get('safeInputControl') === 1
+            if (!isSafeInputControlEnabled) {
+                logger.info('[grain]: 瀹夊叏鍏ヤ粨鑱斿姩鎺у埗鍔熻兘鏈惎鐢�')
+                // 瑙﹀彂鏈惎鐢ㄥ脊绐�
+                bus.fire('showAccessResult', {
+                faceAuth: true,
+                gasConcentration: true,
+                accessAllowed: false,
+                message: "*瀹夊叏鍏ヤ粨鑱斿姩鎺у埗鍔熻兘鏈惎鐢�*"
+                })
+                return false
+            }
             // 妫�鏌ユ槸鍚︽湁鐢ㄦ埛宸叉牳楠屾垚鍔�
             if (!mainView.verifiedUsers[1] && !mainView.verifiedUsers[2]) {
                 // 鏄剧ず寮圭獥閫氱煡
@@ -1547,6 +1688,49 @@
                     gasConcentration: true,
                     accessAllowed: false,
                     message: "*鑱斿姩鎺у埗鎿嶄綔鏃犳潈闄�*"
+                })
+                // 鎾斁璇煶鎻愮ず
+                driver.audio.play('/app/code/resource/CN/wav/control_f.wav')
+                return
+            }
+            // 妫�鏌ユ槸鍚︽湁绉戦暱鏉冮檺
+            let hasSectionChief = false
+            // 妫�鏌ョ敤鎴�1
+            if (mainView.verifiedUsers[1]) {
+                let user1 = sqliteService.d1_person.find({ userId: mainView.verifiedUsers[1] })
+                if (user1 && user1.length > 0) {
+                    try {
+                        let userType = JSON.parse(user1[0].extra).type || 0
+                        if (userType === 1) {
+                            hasSectionChief = true
+                        }
+                    } catch (error) {
+                        logger.error("瑙f瀽鐢ㄦ埛1绫诲瀷澶辫触")
+                    }
+                }
+            }
+            // 妫�鏌ョ敤鎴�2
+            if (!hasSectionChief && mainView.verifiedUsers[2]) {
+                let user2 = sqliteService.d1_person.find({ userId: mainView.verifiedUsers[2] })
+                if (user2 && user2.length > 0) {
+                    try {
+                        let userType = JSON.parse(user2[0].extra).type || 0
+                        if (userType === 1) {
+                            hasSectionChief = true
+                        }
+                    } catch (error) {
+                        logger.error("瑙f瀽鐢ㄦ埛2绫诲瀷澶辫触")
+                    }
+                }
+            }
+            // 濡傛灉娌℃湁绉戦暱鏉冮檺锛屾樉绀烘牳楠屽け璐�
+            if (!hasSectionChief) {
+                // 鏄剧ず寮圭獥閫氱煡
+                bus.fire('showAccessResult', {
+                    faceAuth: false,
+                    gasConcentration: true,
+                    accessAllowed: false,
+                    message: "*鏃犵闀挎潈闄愶紝绂佹鎿嶄綔*"
                 })
                 // 鎾斁璇煶鎻愮ず
                 driver.audio.play('/app/code/resource/CN/wav/control_f.wav')
@@ -1564,6 +1748,18 @@
     
         emergencyInBtn.on(dxui.Utils.EVENT.CLICK, () => {
             logger.info('绱ф�ュ叆浠撴寜閽偣鍑�')
+            const isSafeInputControlEnabled = config.get('safeInputControl') === 1
+            if (!isSafeInputControlEnabled) {
+                logger.info('[grain]: 瀹夊叏鍏ヤ粨鑱斿姩鎺у埗鍔熻兘鏈惎鐢�')
+                // 瑙﹀彂鏈惎鐢ㄥ脊绐�
+                bus.fire('showAccessResult', {
+                faceAuth: true,
+                gasConcentration: true,
+                accessAllowed: false,
+                message: "*瀹夊叏鍏ヤ粨鑱斿姩鎺у埗鍔熻兘鏈惎鐢�*"
+                })
+                return false
+            }
             // 妫�鏌ユ槸鍚︽湁鐢ㄦ埛宸叉牳楠屾垚鍔�
             if (!mainView.verifiedUsers[1] && !mainView.verifiedUsers[2]) {
                 // 鏄剧ず寮圭獥閫氱煡
@@ -1590,6 +1786,18 @@
     
         emergencyOutBtn.on(dxui.Utils.EVENT.CLICK, () => {
             logger.info('鍑轰粨鎸夐挳鐐瑰嚮')
+            const isSafeInputControlEnabled = config.get('safeInputControl') === 1
+            if (!isSafeInputControlEnabled) {
+                logger.info('[grain]: 瀹夊叏鍏ヤ粨鑱斿姩鎺у埗鍔熻兘鏈惎鐢�')
+                // 瑙﹀彂鏈惎鐢ㄥ脊绐�
+                bus.fire('showAccessResult', {
+                faceAuth: true,
+                gasConcentration: true,
+                accessAllowed: false,
+                message: "*瀹夊叏鍏ヤ粨鑱斿姩鎺у埗鍔熻兘鏈惎鐢�*"
+                })
+                return false
+            }
             // 妫�鏌ユ槸鍚︽湁鐢ㄦ埛宸叉牳楠屾垚鍔�
             if (!mainView.verifiedUsers[1] && !mainView.verifiedUsers[2]) {
                 // 鏄剧ず寮圭獥閫氱煡
@@ -1616,6 +1824,18 @@
     
         lightOnBtn.on(dxui.Utils.EVENT.CLICK, () => {
             logger.info('寮�鐏寜閽偣鍑�')
+            const isSafeInputControlEnabled = config.get('safeInputControl') === 1
+            if (!isSafeInputControlEnabled) {
+                logger.info('[grain]: 瀹夊叏鍏ヤ粨鑱斿姩鎺у埗鍔熻兘鏈惎鐢�')
+                // 瑙﹀彂鏈惎鐢ㄥ脊绐�
+                bus.fire('showAccessResult', {
+                faceAuth: true,
+                gasConcentration: true,
+                accessAllowed: false,
+                message: "*瀹夊叏鍏ヤ粨鑱斿姩鎺у埗鍔熻兘鏈惎鐢�*"
+                })
+                return false
+            }
             // 妫�鏌ユ槸鍚︽湁鐢ㄦ埛宸叉牳楠屾垚鍔�
             if (!mainView.verifiedUsers[1] && !mainView.verifiedUsers[2]) {
                 // 鏄剧ず寮圭獥閫氱煡
@@ -1642,6 +1862,18 @@
     
         lightOffBtn.on(dxui.Utils.EVENT.CLICK, () => {
             logger.info('鍏崇伅鎸夐挳鐐瑰嚮')
+            const isSafeInputControlEnabled = config.get('safeInputControl') === 1
+            if (!isSafeInputControlEnabled) {
+                logger.info('[grain]: 瀹夊叏鍏ヤ粨鑱斿姩鎺у埗鍔熻兘鏈惎鐢�')
+                // 瑙﹀彂鏈惎鐢ㄥ脊绐�
+                bus.fire('showAccessResult', {
+                faceAuth: true,
+                gasConcentration: true,
+                accessAllowed: false,
+                message: "*瀹夊叏鍏ヤ粨鑱斿姩鎺у埗鍔熻兘鏈惎鐢�*"
+                })
+                return false
+            }
             // 妫�鏌ユ槸鍚︽湁鐢ㄦ埛宸叉牳楠屾垚鍔�
             if (!mainView.verifiedUsers[1] && !mainView.verifiedUsers[2]) {
                 // 鏄剧ず寮圭獥閫氱煡

--
Gitblit v1.9.3