From 0db50921e776525ac6d35fe50e64c605b6be1374 Mon Sep 17 00:00:00 2001
From: zhangchen <1652267879@qq.com>
Date: 星期四, 04 九月 2025 14:59:11 +0800
Subject: [PATCH] Merge branch 'ID1766-添加推送登录功能' into test

---
 src/components/QrCode/index.vue                                       |   89 +++++
 src/views/mobile/bedsideAuxiliaryScreen/components/Login/userInfo.vue |   55 +++
 package-lock.json                                                     |  562 +++++++++++++++++++++++++++++++++
 src/views/mobile/bedsideAuxiliaryScreen/components/Header.vue         |   14 
 src/views/mobile/bedsideAuxiliaryScreen/components/Login/index.vue    |  224 +++++++++++++
 package.json                                                          |    2 
 src/store/bedsideAuxiliaryScreen.ts                                   |   32 +
 src/store/type/user.type.ts                                           |   11 
 8 files changed, 985 insertions(+), 4 deletions(-)

diff --git a/package-lock.json b/package-lock.json
index f103eff..d30e6db 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -18,6 +18,7 @@
         "event-source-polyfill": "^1.0.31",
         "pinia": "^3.0.3",
         "pinyin": "^4.0.0",
+        "qrcode": "^1.5.4",
         "qs": "^6.14.0",
         "speak-tts": "^2.0.8",
         "vant": "^3.4.3",
@@ -26,6 +27,7 @@
         "vue-router": "^4.0.13"
       },
       "devDependencies": {
+        "@types/qrcode": "^1.5.5",
         "@vitejs/plugin-vue": "^5.2.1",
         "@vue/compiler-sfc": "^3.5.13",
         "@vue/tsconfig": "^0.7.0",
@@ -888,6 +890,26 @@
         "@types/lodash": "*"
       }
     },
+    "node_modules/@types/node": {
+      "version": "24.3.0",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-24.3.0.tgz",
+      "integrity": "sha512-aPTXCrfwnDLj4VvXrm+UUCQjNEvJgNA8s5F1cvwQU+3KNltTOkBm1j30uNLyqqPNe7gE3KFzImYoZEfLhp4Yow==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "undici-types": "~7.10.0"
+      }
+    },
+    "node_modules/@types/qrcode": {
+      "version": "1.5.5",
+      "resolved": "https://registry.npmjs.org/@types/qrcode/-/qrcode-1.5.5.tgz",
+      "integrity": "sha512-CdfBi/e3Qk+3Z/fXYShipBT13OJ2fDO2Q2w5CIP5anLTLIndQG9z6P1cnm+8zCWSpm5dnxMFd/uREtb0EXuQzg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@types/node": "*"
+      }
+    },
     "node_modules/@types/web-bluetooth": {
       "version": "0.0.16",
       "resolved": "https://registry.npmmirror.com/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz",
@@ -1278,6 +1300,30 @@
       "dev": true,
       "license": "MIT"
     },
+    "node_modules/ansi-regex": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "license": "MIT",
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
     "node_modules/async-validator": {
       "version": "4.2.5",
       "resolved": "https://registry.npmmirror.com/async-validator/-/async-validator-4.2.5.tgz",
@@ -1363,6 +1409,44 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/camelcase": {
+      "version": "5.3.1",
+      "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
+      "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/cliui": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
+      "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
+      "license": "ISC",
+      "dependencies": {
+        "string-width": "^4.2.0",
+        "strip-ansi": "^6.0.0",
+        "wrap-ansi": "^6.2.0"
+      }
+    },
+    "node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "license": "MIT",
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "license": "MIT"
+    },
     "node_modules/combined-stream": {
       "version": "1.0.8",
       "resolved": "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz",
@@ -1437,6 +1521,15 @@
       "integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==",
       "dev": true
     },
+    "node_modules/decamelize": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
+      "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
     "node_modules/delayed-stream": {
       "version": "1.0.0",
       "resolved": "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz",
@@ -1445,6 +1538,12 @@
       "engines": {
         "node": ">=0.4.0"
       }
+    },
+    "node_modules/dijkstrajs": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.3.tgz",
+      "integrity": "sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==",
+      "license": "MIT"
     },
     "node_modules/dunder-proto": {
       "version": "1.0.1",
@@ -1495,6 +1594,12 @@
       "peerDependencies": {
         "vue": "^3.2.0"
       }
+    },
+    "node_modules/emoji-regex": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+      "license": "MIT"
     },
     "node_modules/entities": {
       "version": "4.5.0",
@@ -1623,6 +1728,19 @@
       "integrity": "sha512-4IJSItgS/41IxN5UVAVuAyczwZF7ZIEsM1XAoUzIHA6A+xzusEZUutdXz2Nr+MQPLxfTiCvqE79/C8HT8fKFvA==",
       "license": "MIT"
     },
+    "node_modules/find-up": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+      "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+      "license": "MIT",
+      "dependencies": {
+        "locate-path": "^5.0.0",
+        "path-exists": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
     "node_modules/follow-redirects": {
       "version": "1.15.9",
       "resolved": "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.9.tgz",
@@ -1679,6 +1797,15 @@
       "license": "MIT",
       "funding": {
         "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/get-caller-file": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+      "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+      "license": "ISC",
+      "engines": {
+        "node": "6.* || 8.* || >= 10.*"
       }
     },
     "node_modules/get-intrinsic": {
@@ -1830,6 +1957,15 @@
         "node": ">= 0.10"
       }
     },
+    "node_modules/is-fullwidth-code-point": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+      "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
     "node_modules/is-what": {
       "version": "3.14.1",
       "resolved": "https://registry.npmmirror.com/is-what/-/is-what-3.14.1.tgz",
@@ -1868,6 +2004,18 @@
         "mime": "^1.4.1",
         "needle": "^3.1.0",
         "source-map": "~0.6.0"
+      }
+    },
+    "node_modules/locate-path": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+      "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+      "license": "MIT",
+      "dependencies": {
+        "p-locate": "^4.1.0"
+      },
+      "engines": {
+        "node": ">=8"
       }
     },
     "node_modules/lodash": {
@@ -4725,6 +4873,42 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/p-limit": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+      "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+      "license": "MIT",
+      "dependencies": {
+        "p-try": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/p-locate": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+      "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+      "license": "MIT",
+      "dependencies": {
+        "p-limit": "^2.2.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/p-try": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
+      "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
     "node_modules/parse-node-version": {
       "version": "1.0.1",
       "resolved": "https://registry.npmmirror.com/parse-node-version/-/parse-node-version-1.0.1.tgz",
@@ -4740,6 +4924,15 @@
       "resolved": "https://registry.npmmirror.com/path-browserify/-/path-browserify-1.0.1.tgz",
       "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==",
       "dev": true
+    },
+    "node_modules/path-exists": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+      "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
     },
     "node_modules/perfect-debounce": {
       "version": "1.0.0",
@@ -4835,6 +5028,15 @@
         "node": ">= 0.6.x"
       }
     },
+    "node_modules/pngjs": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-5.0.0.tgz",
+      "integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=10.13.0"
+      }
+    },
     "node_modules/postcss": {
       "version": "8.4.49",
       "resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.4.49.tgz",
@@ -4886,6 +5088,23 @@
       "license": "MIT",
       "optional": true
     },
+    "node_modules/qrcode": {
+      "version": "1.5.4",
+      "resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.4.tgz",
+      "integrity": "sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==",
+      "license": "MIT",
+      "dependencies": {
+        "dijkstrajs": "^1.0.1",
+        "pngjs": "^5.0.0",
+        "yargs": "^15.3.1"
+      },
+      "bin": {
+        "qrcode": "bin/qrcode"
+      },
+      "engines": {
+        "node": ">=10.13.0"
+      }
+    },
     "node_modules/qs": {
       "version": "6.14.0",
       "resolved": "https://registry.npmmirror.com/qs/-/qs-6.14.0.tgz",
@@ -4900,6 +5119,21 @@
       "funding": {
         "url": "https://github.com/sponsors/ljharb"
       }
+    },
+    "node_modules/require-directory": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+      "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/require-main-filename": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
+      "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
+      "license": "ISC"
     },
     "node_modules/rfdc": {
       "version": "1.4.1",
@@ -4971,6 +5205,12 @@
       "bin": {
         "semver": "bin/semver"
       }
+    },
+    "node_modules/set-blocking": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
+      "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==",
+      "license": "ISC"
     },
     "node_modules/side-channel": {
       "version": "1.1.0",
@@ -5091,6 +5331,32 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/string-width": {
+      "version": "4.2.3",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+      "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+      "license": "MIT",
+      "dependencies": {
+        "emoji-regex": "^8.0.0",
+        "is-fullwidth-code-point": "^3.0.0",
+        "strip-ansi": "^6.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/strip-ansi": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+      "license": "MIT",
+      "dependencies": {
+        "ansi-regex": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
     "node_modules/superjson": {
       "version": "2.2.2",
       "resolved": "https://registry.npmjs.org/superjson/-/superjson-2.2.2.tgz",
@@ -5178,6 +5444,13 @@
       "engines": {
         "node": ">=14.17"
       }
+    },
+    "node_modules/undici-types": {
+      "version": "7.10.0",
+      "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.10.0.tgz",
+      "integrity": "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==",
+      "dev": true,
+      "license": "MIT"
     },
     "node_modules/vant": {
       "version": "3.4.3",
@@ -5337,6 +5610,67 @@
       },
       "peerDependencies": {
         "typescript": ">=5.0.0"
+      }
+    },
+    "node_modules/which-module": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz",
+      "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==",
+      "license": "ISC"
+    },
+    "node_modules/wrap-ansi": {
+      "version": "6.2.0",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
+      "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
+      "license": "MIT",
+      "dependencies": {
+        "ansi-styles": "^4.0.0",
+        "string-width": "^4.1.0",
+        "strip-ansi": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/y18n": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz",
+      "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==",
+      "license": "ISC"
+    },
+    "node_modules/yargs": {
+      "version": "15.4.1",
+      "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz",
+      "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==",
+      "license": "MIT",
+      "dependencies": {
+        "cliui": "^6.0.0",
+        "decamelize": "^1.2.0",
+        "find-up": "^4.1.0",
+        "get-caller-file": "^2.0.1",
+        "require-directory": "^2.1.1",
+        "require-main-filename": "^2.0.0",
+        "set-blocking": "^2.0.0",
+        "string-width": "^4.2.0",
+        "which-module": "^2.0.0",
+        "y18n": "^4.0.0",
+        "yargs-parser": "^18.1.2"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/yargs-parser": {
+      "version": "18.1.3",
+      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
+      "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
+      "license": "ISC",
+      "dependencies": {
+        "camelcase": "^5.0.0",
+        "decamelize": "^1.2.0"
+      },
+      "engines": {
+        "node": ">=6"
       }
     },
     "node_modules/zrender": {
@@ -5805,6 +6139,24 @@
         "@types/lodash": "*"
       }
     },
+    "@types/node": {
+      "version": "24.3.0",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-24.3.0.tgz",
+      "integrity": "sha512-aPTXCrfwnDLj4VvXrm+UUCQjNEvJgNA8s5F1cvwQU+3KNltTOkBm1j30uNLyqqPNe7gE3KFzImYoZEfLhp4Yow==",
+      "dev": true,
+      "requires": {
+        "undici-types": "~7.10.0"
+      }
+    },
+    "@types/qrcode": {
+      "version": "1.5.5",
+      "resolved": "https://registry.npmjs.org/@types/qrcode/-/qrcode-1.5.5.tgz",
+      "integrity": "sha512-CdfBi/e3Qk+3Z/fXYShipBT13OJ2fDO2Q2w5CIP5anLTLIndQG9z6P1cnm+8zCWSpm5dnxMFd/uREtb0EXuQzg==",
+      "dev": true,
+      "requires": {
+        "@types/node": "*"
+      }
+    },
     "@types/web-bluetooth": {
       "version": "0.0.16",
       "resolved": "https://registry.npmmirror.com/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz",
@@ -6090,6 +6442,19 @@
       "integrity": "sha512-L2VfvDzoETBjhRptg5u/IUuzHSuxm22JpSRb404p/TBGeRfwWmmNEbB+TFPIP/sS/+pbM18bCFH9QnMojLuPNw==",
       "dev": true
     },
+    "ansi-regex": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="
+    },
+    "ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "requires": {
+        "color-convert": "^2.0.1"
+      }
+    },
     "async-validator": {
       "version": "4.2.5",
       "resolved": "https://registry.npmmirror.com/async-validator/-/async-validator-4.2.5.tgz",
@@ -6156,6 +6521,34 @@
         "get-intrinsic": "^1.3.0"
       }
     },
+    "camelcase": {
+      "version": "5.3.1",
+      "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
+      "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="
+    },
+    "cliui": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
+      "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
+      "requires": {
+        "string-width": "^4.2.0",
+        "strip-ansi": "^6.0.0",
+        "wrap-ansi": "^6.2.0"
+      }
+    },
+    "color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "requires": {
+        "color-name": "~1.1.4"
+      }
+    },
+    "color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
+    },
     "combined-stream": {
       "version": "1.0.8",
       "resolved": "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz",
@@ -6207,10 +6600,20 @@
       "integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==",
       "dev": true
     },
+    "decamelize": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
+      "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA=="
+    },
     "delayed-stream": {
       "version": "1.0.0",
       "resolved": "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz",
       "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="
+    },
+    "dijkstrajs": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.3.tgz",
+      "integrity": "sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA=="
     },
     "dunder-proto": {
       "version": "1.0.1",
@@ -6252,6 +6655,11 @@
         "memoize-one": "^6.0.0",
         "normalize-wheel-es": "^1.2.0"
       }
+    },
+    "emoji-regex": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
     },
     "entities": {
       "version": "4.5.0",
@@ -6345,6 +6753,15 @@
       "resolved": "https://registry.npmmirror.com/event-source-polyfill/-/event-source-polyfill-1.0.31.tgz",
       "integrity": "sha512-4IJSItgS/41IxN5UVAVuAyczwZF7ZIEsM1XAoUzIHA6A+xzusEZUutdXz2Nr+MQPLxfTiCvqE79/C8HT8fKFvA=="
     },
+    "find-up": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+      "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+      "requires": {
+        "locate-path": "^5.0.0",
+        "path-exists": "^4.0.0"
+      }
+    },
     "follow-redirects": {
       "version": "1.15.9",
       "resolved": "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.9.tgz",
@@ -6372,6 +6789,11 @@
       "version": "1.1.2",
       "resolved": "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz",
       "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="
+    },
+    "get-caller-file": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+      "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="
     },
     "get-intrinsic": {
       "version": "1.3.0",
@@ -6466,6 +6888,11 @@
       "integrity": "sha512-zDml/jzr2PKU9I8J/xyZBQn8rPCAY//UOYNmR01XwNwyfhEWObo2SWfSl1+0tm1u6PhxLwDnfsT/6jB7OUxqFA==",
       "dev": true
     },
+    "is-fullwidth-code-point": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+      "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="
+    },
     "is-what": {
       "version": "3.14.1",
       "resolved": "https://registry.npmmirror.com/is-what/-/is-what-3.14.1.tgz",
@@ -6493,6 +6920,14 @@
         "parse-node-version": "^1.0.1",
         "source-map": "~0.6.0",
         "tslib": "^2.3.0"
+      }
+    },
+    "locate-path": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+      "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+      "requires": {
+        "p-locate": "^4.1.0"
       }
     },
     "lodash": {
@@ -8383,6 +8818,27 @@
       "resolved": "https://registry.npmmirror.com/object-inspect/-/object-inspect-1.13.4.tgz",
       "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="
     },
+    "p-limit": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+      "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+      "requires": {
+        "p-try": "^2.0.0"
+      }
+    },
+    "p-locate": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+      "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+      "requires": {
+        "p-limit": "^2.2.0"
+      }
+    },
+    "p-try": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
+      "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ=="
+    },
     "parse-node-version": {
       "version": "1.0.1",
       "resolved": "https://registry.npmmirror.com/parse-node-version/-/parse-node-version-1.0.1.tgz",
@@ -8394,6 +8850,11 @@
       "resolved": "https://registry.npmmirror.com/path-browserify/-/path-browserify-1.0.1.tgz",
       "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==",
       "dev": true
+    },
+    "path-exists": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+      "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="
     },
     "perfect-debounce": {
       "version": "1.0.0",
@@ -8448,6 +8909,11 @@
         }
       }
     },
+    "pngjs": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-5.0.0.tgz",
+      "integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw=="
+    },
     "postcss": {
       "version": "8.4.49",
       "resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.4.49.tgz",
@@ -8477,6 +8943,16 @@
       "dev": true,
       "optional": true
     },
+    "qrcode": {
+      "version": "1.5.4",
+      "resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.4.tgz",
+      "integrity": "sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==",
+      "requires": {
+        "dijkstrajs": "^1.0.1",
+        "pngjs": "^5.0.0",
+        "yargs": "^15.3.1"
+      }
+    },
     "qs": {
       "version": "6.14.0",
       "resolved": "https://registry.npmmirror.com/qs/-/qs-6.14.0.tgz",
@@ -8484,6 +8960,16 @@
       "requires": {
         "side-channel": "^1.1.0"
       }
+    },
+    "require-directory": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+      "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="
+    },
+    "require-main-filename": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
+      "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg=="
     },
     "rfdc": {
       "version": "1.4.1",
@@ -8539,6 +9025,11 @@
       "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
       "dev": true,
       "optional": true
+    },
+    "set-blocking": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
+      "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw=="
     },
     "side-channel": {
       "version": "1.1.0",
@@ -8618,6 +9109,24 @@
       "resolved": "https://registry.npmjs.org/speakingurl/-/speakingurl-14.0.1.tgz",
       "integrity": "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ=="
     },
+    "string-width": {
+      "version": "4.2.3",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+      "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+      "requires": {
+        "emoji-regex": "^8.0.0",
+        "is-fullwidth-code-point": "^3.0.0",
+        "strip-ansi": "^6.0.1"
+      }
+    },
+    "strip-ansi": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+      "requires": {
+        "ansi-regex": "^5.0.1"
+      }
+    },
     "superjson": {
       "version": "2.2.2",
       "resolved": "https://registry.npmjs.org/superjson/-/superjson-2.2.2.tgz",
@@ -8670,6 +9179,12 @@
       "resolved": "https://registry.npmmirror.com/typescript/-/typescript-5.6.3.tgz",
       "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==",
       "devOptional": true
+    },
+    "undici-types": {
+      "version": "7.10.0",
+      "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.10.0.tgz",
+      "integrity": "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==",
+      "dev": true
     },
     "vant": {
       "version": "3.4.3",
@@ -8747,6 +9262,53 @@
         "@vue/language-core": "2.2.0"
       }
     },
+    "which-module": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz",
+      "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ=="
+    },
+    "wrap-ansi": {
+      "version": "6.2.0",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
+      "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
+      "requires": {
+        "ansi-styles": "^4.0.0",
+        "string-width": "^4.1.0",
+        "strip-ansi": "^6.0.0"
+      }
+    },
+    "y18n": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz",
+      "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ=="
+    },
+    "yargs": {
+      "version": "15.4.1",
+      "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz",
+      "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==",
+      "requires": {
+        "cliui": "^6.0.0",
+        "decamelize": "^1.2.0",
+        "find-up": "^4.1.0",
+        "get-caller-file": "^2.0.1",
+        "require-directory": "^2.1.1",
+        "require-main-filename": "^2.0.0",
+        "set-blocking": "^2.0.0",
+        "string-width": "^4.2.0",
+        "which-module": "^2.0.0",
+        "y18n": "^4.0.0",
+        "yargs-parser": "^18.1.2"
+      }
+    },
+    "yargs-parser": {
+      "version": "18.1.3",
+      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
+      "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
+      "requires": {
+        "camelcase": "^5.0.0",
+        "decamelize": "^1.2.0"
+      }
+    },
     "zrender": {
       "version": "5.6.1",
       "resolved": "https://registry.npmmirror.com/zrender/-/zrender-5.6.1.tgz",
diff --git a/package.json b/package.json
index 7bf01ac..358a7c1 100644
--- a/package.json
+++ b/package.json
@@ -22,6 +22,7 @@
     "event-source-polyfill": "^1.0.31",
     "pinia": "^3.0.3",
     "pinyin": "^4.0.0",
+    "qrcode": "^1.5.4",
     "qs": "^6.14.0",
     "speak-tts": "^2.0.8",
     "vant": "^3.4.3",
@@ -30,6 +31,7 @@
     "vue-router": "^4.0.13"
   },
   "devDependencies": {
+    "@types/qrcode": "^1.5.5",
     "@vitejs/plugin-vue": "^5.2.1",
     "@vue/compiler-sfc": "^3.5.13",
     "@vue/tsconfig": "^0.7.0",
diff --git a/src/components/QrCode/index.vue b/src/components/QrCode/index.vue
new file mode 100644
index 0000000..7ea79c2
--- /dev/null
+++ b/src/components/QrCode/index.vue
@@ -0,0 +1,89 @@
+<template>
+  <img :src="qrCodeUrl" alt="" srcset="" style="width: 100%; height: 100%;" />
+</template>
+
+<script lang="ts">
+import { onMounted, reactive, toRefs, watch } from "vue";
+import QrCode from "qrcode";
+export default {
+  name: "QrCode",
+  props: {
+    width: {
+      type: Number,
+      default: 200,
+    },
+    height: {
+      type: Number,
+      default: 200,
+    },
+    colorDark: {
+      type: String,
+      default: "#000000",
+    },
+    colorLight: {
+      type: String,
+      default: "#ffffff",
+    },
+    margin: {
+      type: Number,
+      default: 4,
+    },
+    value: {
+      type: Object,
+    },
+  },
+  setup(props, contxt) {
+    let debounceTimer: any;
+    const state = reactive({
+      qrCodeUrl: "",
+    });
+
+    watch(
+      () => props.value,
+      () => {
+        console.log('二维码触发了')
+        debounceTimer && clearTimeout(debounceTimer);
+        debounceTimer = setTimeout(generateQRCode, 500);
+      }, { deep: true }
+    );
+
+    /** 生成二维码 */
+    const generateQRCode = () => {
+      if (!props.value) {
+        state.qrCodeUrl = "";
+        contxt.emit("error", { message: "二维码内容为空" });
+        return;
+      }
+      const options = {
+        width: props.width,
+        height: props.height,
+        margin: props.margin,
+        color: {
+          dark: props.colorDark,
+          light: props.colorLight,
+        },
+      };
+      QrCode.toDataURL(JSON.stringify(props.value), options, (error, url) => {
+        if (error) {
+          console.error("二维码生成失败: ", error);
+          contxt.emit("error", { message: "二维码生成失败" });
+          return;
+        }
+        state.qrCodeUrl = url;
+      });
+    };
+
+    onMounted(() => {
+        generateQRCode();
+    })
+
+    return {
+      ...toRefs(state),
+      generateQRCode,
+    };
+  },
+};
+</script>
+
+<style lang="less" scoped>
+</style>
\ No newline at end of file
diff --git a/src/store/bedsideAuxiliaryScreen.ts b/src/store/bedsideAuxiliaryScreen.ts
index e67222b..3596ee1 100644
--- a/src/store/bedsideAuxiliaryScreen.ts
+++ b/src/store/bedsideAuxiliaryScreen.ts
@@ -14,6 +14,7 @@
 } from "./type/bedsideAuxiliaryScreen.type";
 import { ElMessage } from "element-plus/es";
 import { Local } from "@/utils/storage";
+import type { UserInfo } from './type/user.type';
 
 export const useBedsideAuxiliaryScreenStore = defineStore(
   "bedsideAuxiliaryScreen",
@@ -29,6 +30,12 @@
 
     /** 任务列表 */
     const taskData = ref<Task[]>([]);
+
+    /** 用户信息 */
+    const userInfo = ref<UserInfo | null>(Local.get('userInfo'));
+
+    /** 用户token */
+    const token = ref<string>(Local.get('token'));
 
     /** 设置副屏版本号 */
     const setVersion = (val: string) => {
@@ -68,6 +75,26 @@
     /** 清除当前定时任务 */
     const clearTask = () => {
       taskData.value = [];
+    };
+
+    /** 设置用户信息 */
+    const setUserInfo = (user: UserInfo) => {
+      userInfo.value = user;
+      Local.set('userInfo', user);
+    };
+
+    /** 设置token */
+    const setToken = (str: string) => {
+      token.value = str;
+      Local.set('token', str);
+    }
+
+    /** 退出登录 */
+    const logout = () => {
+      Local.remove('token');
+      Local.remove('userInfo');
+      token.value = '';
+      userInfo.value = null;
     };
 
     // SSE 相关状态
@@ -221,6 +248,11 @@
       clearTask,
       setVersion,
       refreshVersion,
+      userInfo,
+      token,
+      setUserInfo,
+      setToken,
+      logout,
     };
   }
 );
diff --git a/src/store/type/user.type.ts b/src/store/type/user.type.ts
new file mode 100644
index 0000000..da40248
--- /dev/null
+++ b/src/store/type/user.type.ts
@@ -0,0 +1,11 @@
+export interface UserInfo {
+    用户头像: string;
+    用户昵称: string;
+}
+
+export const defaultUserInfo = (): UserInfo => {
+    return {
+        用户头像: '',
+        用户昵称: ''
+    }
+}
\ No newline at end of file
diff --git a/src/views/mobile/bedsideAuxiliaryScreen/components/Header.vue b/src/views/mobile/bedsideAuxiliaryScreen/components/Header.vue
index 121d8fa..cb20147 100644
--- a/src/views/mobile/bedsideAuxiliaryScreen/components/Header.vue
+++ b/src/views/mobile/bedsideAuxiliaryScreen/components/Header.vue
@@ -74,6 +74,8 @@
   <ScheduledTaskDialog ref="scheduledTaskDialogRef" />
   <!-- 定时任务提醒组件 -->
   <TaskAlert ref="taskAlertRef" @close="taskAlaetClose" />
+  <!-- 用户登录组件 -->
+  <LoginDialog ref="loginDialogRef" />
 </template>
 
 <script lang="ts" setup name="Header">
@@ -94,6 +96,7 @@
   () => import("./ScheduledTask.vue")
 );
 const TaskAlert = defineAsyncComponent(() => import("./TaskAlart.vue"));
+const LoginDialog = defineAsyncComponent(() => import('./Login/index.vue'));
 
 import atRegularTimeImg from "../../../../img/dingshi.png";
 import setUpImg from "../../../../img/shezhi.png";
@@ -112,6 +115,7 @@
 const settingDeviceDialogRef = ref<any>(null);
 const scheduledTaskDialogRef = ref<any>(null);
 const taskAlertRef = ref<any>(null);
+const loginDialogRef = ref<any>(null);
 
 const countdown = ref(null); // 定时任务的倒计时
 const isTaskAlartIsOpen = ref(false); // 定时任务的提醒弹框是否显示
@@ -234,10 +238,12 @@
 };
 
 const openLoginDialog = () => {
-  ElMessage({
-    message: "功能开发中,敬请期待!",
-    type: "warning",
-  });
+  if (
+    !bedsideAuxiliaryScreenStore.deviceCode ||
+    !bedsideAuxiliaryScreenStore.deviceData.deviceCode
+  )
+    return ElMessage.warning("未初始化或正在进行初始化操作中");
+    loginDialogRef.value.openDialog();
 };
 
 onUnmounted(() => {
diff --git a/src/views/mobile/bedsideAuxiliaryScreen/components/Login/index.vue b/src/views/mobile/bedsideAuxiliaryScreen/components/Login/index.vue
new file mode 100644
index 0000000..43c53fc
--- /dev/null
+++ b/src/views/mobile/bedsideAuxiliaryScreen/components/Login/index.vue
@@ -0,0 +1,224 @@
+<template>
+  <div class="login-dialog-container">
+    <el-dialog
+      v-model="show"
+      center
+      title="个人用户"
+      width="40%"
+      :show-close="false"
+      class="scheduled-task-dialog"
+      :destroy-on-close="true"
+      :close-on-click-modal="false"
+    >
+      <template #header>
+        <div class="setting-dialog-header">
+          <span class="header-title">个人用户</span>
+          <img
+            :src="closeImg"
+            class="header-close"
+            @click="handleCancel"
+            alt=""
+          />
+        </div>
+      </template>
+      <!-- 已登录 -->
+      <div v-if="isLoginng" class="login-dialog-content loging-content">
+        <UserInfo />
+      </div>
+      <!-- 未登录 -->
+      <div v-else class="login-dialog-content">
+        <div class="qr-code-box">
+          <QrCode :value="qrCodeData" :margin="1" />
+        </div>
+        <div class="qr-text">请扫描二维码进行登录操作</div>
+      </div>
+      <template v-if="isLoginng" #footer>
+        <div class="my-button cancel" @click="onLogout">退出登录</div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script lang="ts">
+import { reactive, toRefs, computed } from "vue";
+import closeImg from "@/img/close.png";
+import QrCode from "@/components/QrCode/index.vue";
+import UserInfo from "./userInfo.vue";
+import { useBedsideAuxiliaryScreenStore } from "@/store/bedsideAuxiliaryScreen";
+import { ElMessage, ElMessageBox } from "element-plus";
+
+export default {
+  name: "LoginDialog",
+  components: { QrCode, UserInfo },
+  setup() {
+    const bedsideAuxiliaryScreenStore = useBedsideAuxiliaryScreenStore();
+
+    const state = reactive({
+      show: false,
+      loading: false,
+    });
+
+    const isLoginng = computed(() => {
+      return !!bedsideAuxiliaryScreenStore.token;
+    });
+
+    const qrCodeData = computed(() => {
+      return {
+        deviceCode: bedsideAuxiliaryScreenStore.deviceCode,
+      };
+    });
+
+    const openDialog = () => {
+      state.show = true;
+    };
+
+    const handleCancel = () => {
+      state.show = false;
+    };
+
+    const onLogout = () => {
+      ElMessageBox.confirm("是否确认退出当前登录用户?", "提示", {
+        confirmButtonText: "确认",
+        cancelButtonText: "取消",
+        type: "warning",
+      })
+        .then(() => {
+            bedsideAuxiliaryScreenStore.logout();
+          ElMessage({
+            type: "success",
+            message: "退出成功!",
+          });
+        })
+        .catch(() => {});
+    };
+
+    return {
+      ...toRefs(state),
+      closeImg,
+      qrCodeData,
+      isLoginng,
+      handleCancel,
+      openDialog,
+      onLogout,
+    };
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.login-dialog-container {
+  ::v-deep(.el-dialog) {
+    padding: 0;
+    border-radius: 6px;
+    overflow: hidden;
+  }
+  ::v-deep(.el-dialog__footer) {
+    padding: 4px;
+  }
+  ::v-deep(.el-upload-dragger) {
+    height: 65px;
+    padding: 0 !important;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+  }
+  ::v-deep(.el-upload-dragger .el-icon--upload) {
+    display: none;
+  }
+  ::v-deep(.el-dialog__header) {
+    padding-bottom: 6px;
+  }
+  .setting-dialog-header {
+    position: relative;
+    height: 16px;
+    background: #769aff;
+    .header-title {
+      position: absolute;
+      left: 50%;
+      top: 50%;
+      transform: translateX(-50%) translateY(-50%);
+      font-family: AlibabaPuHuiTi, AlibabaPuHuiTi;
+      font-weight: 500;
+      font-size: 8px;
+      color: #ffffff;
+      line-height: 11px;
+      text-align: center;
+    }
+    .header-close {
+      position: absolute;
+      top: 50%;
+      transform: translateY(-50%);
+      right: 6px;
+      width: 15px;
+      height: 15px;
+      transition: transform 0.2s;
+
+      &:active {
+        opacity: 0.6;
+        transform: translateY(-50%) scale(0.95);
+      }
+    }
+  }
+  .login-dialog-content {
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: center;
+    padding: 0 12px 6px;
+    &.loging-content {
+      border-bottom: 1px solid #d8d8d8;
+    }
+    .qr-code-box {
+      width: 80px;
+      height: 80px;
+      margin-bottom: 2px;
+    }
+    .qr-text {
+      font-size: 4px;
+      color: #769aff;
+    }
+  }
+
+  .my-button {
+    display: inline-block;
+    border-radius: 2px;
+    padding: 0px 10px;
+    font-family: PingFangSC, PingFang SC;
+    font-weight: 500;
+    font-size: 7px;
+    color: #ffffff;
+    line-height: 16px;
+    letter-spacing: 1px;
+    text-align: center;
+    font-style: normal;
+    transition: transform 0.1s ease, opacity 0.1s ease;
+    cursor: pointer;
+    &:active {
+      transform: scale(0.95);
+      opacity: 0.8;
+    }
+
+    &:not(:first-child) {
+      margin-left: 6px;
+    }
+    &.cancel {
+      background: #fff;
+      color: #000;
+      border: 1px solid #dedede;
+    }
+    &.confirm {
+      background: #769aff;
+    }
+    &.refresh {
+      background: #e6a23c;
+    }
+  }
+}
+</style>
+<style>
+.scheduled-task-dialog {
+  margin: 0 auto;
+  top: 50% !important;
+  transform: translateY(-50%) !important;
+}
+</style>
\ No newline at end of file
diff --git a/src/views/mobile/bedsideAuxiliaryScreen/components/Login/userInfo.vue b/src/views/mobile/bedsideAuxiliaryScreen/components/Login/userInfo.vue
new file mode 100644
index 0000000..f5e9fa2
--- /dev/null
+++ b/src/views/mobile/bedsideAuxiliaryScreen/components/Login/userInfo.vue
@@ -0,0 +1,55 @@
+<template>
+  <div class="userinfo-container">
+    <img :src="userInfo.用户头像" alt="" srcset="" class="user-avatar">
+    <div class="user-text">当前账户:{{ userInfo.用户昵称 }}</div>
+    <div class="user-text">床号:{{ userInfo.床号 }}</div>
+    <div class="user-text">设备号:{{ userInfo.设备编号 }}</div>
+  </div>
+</template>
+
+<script lang="ts">
+import { computed } from "vue";
+import { useBedsideAuxiliaryScreenStore } from "@/store/bedsideAuxiliaryScreen";
+import { defaultUserInfo } from '@/store/type/user.type';
+
+export default {
+  name: "UserInfo",
+  setup() {
+    const bedsideAuxiliaryScreenStore = useBedsideAuxiliaryScreenStore();
+
+    const userInfo = computed(() => {
+      const userInfo = bedsideAuxiliaryScreenStore.userInfo || defaultUserInfo();
+      return {
+        ...userInfo,
+        床号: bedsideAuxiliaryScreenStore.deviceData.devicdeNo,
+        设备编号: bedsideAuxiliaryScreenStore.deviceCode
+      }
+    });
+
+    return {
+        userInfo
+    };
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.userinfo-container {
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: center;
+    .user-avatar {
+        width: 15px;
+        height: 15px;
+        border-radius: 50%;
+        overflow: hidden;
+        margin-bottom: 5px;
+    }
+    .user-text {
+        font-size: 5px;
+        color: #000;
+        margin-bottom: 4px;
+    }
+}
+</style>
\ No newline at end of file

--
Gitblit v1.8.0