浏览代码

项目结构重构

yujinwen 4 月之前
父节点
当前提交
6f09630057

+ 1 - 0
package.json

@@ -27,6 +27,7 @@
   },
   "devDependencies": {
     "@vitejs/plugin-vue": "^5.0.4",
+    "archiver": "^7.0.1",
     "sass": "^1.75.0",
     "unplugin-auto-import": "^0.17.5",
     "unplugin-vue-components": "^0.26.0",

+ 427 - 3
pnpm-lock.yaml

@@ -48,6 +48,9 @@ devDependencies:
   '@vitejs/plugin-vue':
     specifier: ^5.0.4
     version: 5.0.5(vite@5.3.2)(vue@3.5.13)
+  archiver:
+    specifier: ^7.0.1
+    version: 7.0.1
   sass:
     specifier: ^1.75.0
     version: 1.77.6
@@ -377,6 +380,18 @@ packages:
     resolution: {integrity: sha512-XGndio0l5/Gvd6CLIABvsav9HHezgDFFhDfHk1bvLfr9ni8dojqLSvBbotJEjmIwNHL7vK4QzBJTdBRoB+c1ww==}
     dev: false
 
+  /@isaacs/cliui@8.0.2:
+    resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
+    engines: {node: '>=12'}
+    dependencies:
+      string-width: 5.1.2
+      string-width-cjs: /string-width@4.2.3
+      strip-ansi: 7.1.0
+      strip-ansi-cjs: /strip-ansi@6.0.1
+      wrap-ansi: 8.1.0
+      wrap-ansi-cjs: /wrap-ansi@7.0.0
+    dev: true
+
   /@jridgewell/sourcemap-codec@1.4.15:
     resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==}
     dev: true
@@ -405,6 +420,13 @@ packages:
       fastq: 1.17.1
     dev: true
 
+  /@pkgjs/parseargs@0.11.0:
+    resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
+    engines: {node: '>=14'}
+    requiresBuild: true
+    dev: true
+    optional: true
+
   /@popperjs/core@2.11.8:
     resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==}
     dev: false
@@ -731,7 +753,7 @@ packages:
   /@vueuse/shared@10.11.0(vue@3.5.13):
     resolution: {integrity: sha512-fyNoIXEq3PfX1L3NkNhtVQUSRtqYwJtJg+Bp9rIzculIZWHTkKSysujrOk2J+NrRulLTQH9+3gGSfYLWSEWU1A==}
     dependencies:
-      vue-demi: 0.14.8(vue@3.5.13)
+      vue-demi: 0.14.10(vue@3.5.13)
     transitivePeerDependencies:
       - '@vue/composition-api'
       - vue
@@ -745,6 +767,13 @@ packages:
       - vue
     dev: false
 
+  /abort-controller@3.0.0:
+    resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==}
+    engines: {node: '>=6.5'}
+    dependencies:
+      event-target-shim: 5.0.1
+    dev: true
+
   /acorn@8.12.0:
     resolution: {integrity: sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw==}
     engines: {node: '>=0.4.0'}
@@ -756,11 +785,33 @@ packages:
     engines: {node: '>=0.10.0'}
     dev: true
 
+  /ansi-regex@5.0.1:
+    resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
+    engines: {node: '>=8'}
+    dev: true
+
+  /ansi-regex@6.1.0:
+    resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==}
+    engines: {node: '>=12'}
+    dev: true
+
   /ansi-styles@2.2.1:
     resolution: {integrity: sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==}
     engines: {node: '>=0.10.0'}
     dev: true
 
+  /ansi-styles@4.3.0:
+    resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
+    engines: {node: '>=8'}
+    dependencies:
+      color-convert: 2.0.1
+    dev: true
+
+  /ansi-styles@6.2.1:
+    resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==}
+    engines: {node: '>=12'}
+    dev: true
+
   /anymatch@3.1.3:
     resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
     engines: {node: '>= 8'}
@@ -769,6 +820,32 @@ packages:
       picomatch: 2.3.1
     dev: true
 
+  /archiver-utils@5.0.2:
+    resolution: {integrity: sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA==}
+    engines: {node: '>= 14'}
+    dependencies:
+      glob: 10.4.5
+      graceful-fs: 4.2.11
+      is-stream: 2.0.1
+      lazystream: 1.0.1
+      lodash: 4.17.21
+      normalize-path: 3.0.0
+      readable-stream: 4.5.2
+    dev: true
+
+  /archiver@7.0.1:
+    resolution: {integrity: sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ==}
+    engines: {node: '>= 14'}
+    dependencies:
+      archiver-utils: 5.0.2
+      async: 3.2.6
+      buffer-crc32: 1.0.0
+      readable-stream: 4.5.2
+      readdir-glob: 1.1.3
+      tar-stream: 3.1.7
+      zip-stream: 6.0.1
+    dev: true
+
   /arr-diff@4.0.0:
     resolution: {integrity: sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==}
     engines: {node: '>=0.10.0'}
@@ -820,6 +897,10 @@ packages:
     resolution: {integrity: sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==}
     dev: false
 
+  /async@3.2.6:
+    resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==}
+    dev: true
+
   /asynckit@0.4.0:
     resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
     dev: false
@@ -847,10 +928,24 @@ packages:
       - debug
     dev: false
 
+  /b4a@1.6.7:
+    resolution: {integrity: sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==}
+    dev: true
+
   /balanced-match@1.0.2:
     resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
     dev: true
 
+  /bare-events@2.5.0:
+    resolution: {integrity: sha512-/E8dDe9dsbLyh2qrZ64PEPadOQ0F4gbl1sUJOrmph7xOiIxfY8vwab/4bFLh4Y88/Hk/ujKcrQKc+ps0mv873A==}
+    requiresBuild: true
+    dev: true
+    optional: true
+
+  /base64-js@1.5.1:
+    resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
+    dev: true
+
   /base@0.11.2:
     resolution: {integrity: sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==}
     engines: {node: '>=0.10.0'}
@@ -912,6 +1007,18 @@ packages:
       fill-range: 7.1.1
     dev: true
 
+  /buffer-crc32@1.0.0:
+    resolution: {integrity: sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==}
+    engines: {node: '>=8.0.0'}
+    dev: true
+
+  /buffer@6.0.3:
+    resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==}
+    dependencies:
+      base64-js: 1.5.1
+      ieee754: 1.2.1
+    dev: true
+
   /cache-base@1.0.1:
     resolution: {integrity: sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==}
     engines: {node: '>=0.10.0'}
@@ -987,6 +1094,17 @@ packages:
       object-visit: 1.0.1
     dev: true
 
+  /color-convert@2.0.1:
+    resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
+    engines: {node: '>=7.0.0'}
+    dependencies:
+      color-name: 1.1.4
+    dev: true
+
+  /color-name@1.1.4:
+    resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
+    dev: true
+
   /combined-stream@1.0.8:
     resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
     engines: {node: '>= 0.8'}
@@ -1003,6 +1121,17 @@ packages:
     resolution: {integrity: sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==}
     dev: true
 
+  /compress-commons@6.0.2:
+    resolution: {integrity: sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg==}
+    engines: {node: '>= 14'}
+    dependencies:
+      crc-32: 1.2.2
+      crc32-stream: 6.0.0
+      is-stream: 2.0.1
+      normalize-path: 3.0.0
+      readable-stream: 4.5.2
+    dev: true
+
   /confbox@0.1.7:
     resolution: {integrity: sha512-uJcB/FKZtBMCJpK8MQji6bJHgu1tixKPxRLeGkNzBoOZzpnZUJm0jm2/sBDWcuBx1dYgxV4JU+g5hmNxCyAmdA==}
     dev: true
@@ -1012,6 +1141,10 @@ packages:
     engines: {node: '>=0.10.0'}
     dev: true
 
+  /core-util-is@1.0.3:
+    resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==}
+    dev: true
+
   /cors@2.8.5:
     resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==}
     engines: {node: '>= 0.10'}
@@ -1020,6 +1153,29 @@ packages:
       vary: 1.1.2
     dev: true
 
+  /crc-32@1.2.2:
+    resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==}
+    engines: {node: '>=0.8'}
+    hasBin: true
+    dev: true
+
+  /crc32-stream@6.0.0:
+    resolution: {integrity: sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g==}
+    engines: {node: '>= 14'}
+    dependencies:
+      crc-32: 1.2.2
+      readable-stream: 4.5.2
+    dev: true
+
+  /cross-spawn@7.0.6:
+    resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
+    engines: {node: '>= 8'}
+    dependencies:
+      path-key: 3.1.1
+      shebang-command: 2.0.0
+      which: 2.0.2
+    dev: true
+
   /css-select@4.3.0:
     resolution: {integrity: sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==}
     dependencies:
@@ -1219,6 +1375,10 @@ packages:
       domhandler: 4.3.1
     dev: true
 
+  /eastasianwidth@0.2.0:
+    resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
+    dev: true
+
   /element-plus@2.7.6(vue@3.5.13):
     resolution: {integrity: sha512-36sw1K23hYjgeooR10U6CiCaCp2wvOqwoFurADZVlekeQ9v5U1FhJCFGEXO6i/kZBBMwsE1c9fxjLs9LENw2Rg==}
     peerDependencies:
@@ -1244,6 +1404,14 @@ packages:
       - '@vue/composition-api'
     dev: false
 
+  /emoji-regex@8.0.0:
+    resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
+    dev: true
+
+  /emoji-regex@9.2.2:
+    resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
+    dev: true
+
   /emojis-list@3.0.0:
     resolution: {integrity: sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==}
     engines: {node: '>= 4'}
@@ -1409,6 +1577,16 @@ packages:
     engines: {node: '>= 0.6'}
     dev: true
 
+  /event-target-shim@5.0.1:
+    resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==}
+    engines: {node: '>=6'}
+    dev: true
+
+  /events@3.3.0:
+    resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==}
+    engines: {node: '>=0.8.x'}
+    dev: true
+
   /expand-brackets@2.1.4:
     resolution: {integrity: sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==}
     engines: {node: '>=0.10.0'}
@@ -1455,6 +1633,10 @@ packages:
       - supports-color
     dev: true
 
+  /fast-fifo@1.3.2:
+    resolution: {integrity: sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==}
+    dev: true
+
   /fast-glob@3.3.2:
     resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==}
     engines: {node: '>=8.6.0'}
@@ -1510,6 +1692,14 @@ packages:
     engines: {node: '>=0.10.0'}
     dev: true
 
+  /foreground-child@3.3.0:
+    resolution: {integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==}
+    engines: {node: '>=14'}
+    dependencies:
+      cross-spawn: 7.0.6
+      signal-exit: 4.1.0
+    dev: true
+
   /form-data@4.0.0:
     resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==}
     engines: {node: '>= 6'}
@@ -1593,6 +1783,18 @@ packages:
       is-glob: 4.0.3
     dev: true
 
+  /glob@10.4.5:
+    resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==}
+    hasBin: true
+    dependencies:
+      foreground-child: 3.3.0
+      jackspeak: 3.4.3
+      minimatch: 9.0.5
+      minipass: 7.1.2
+      package-json-from-dist: 1.0.1
+      path-scurry: 1.11.1
+    dev: true
+
   /globalthis@1.0.4:
     resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==}
     engines: {node: '>= 0.4'}
@@ -1714,6 +1916,10 @@ packages:
       readable-stream: 3.6.2
     dev: true
 
+  /ieee754@1.2.1:
+    resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
+    dev: true
+
   /image-size@0.5.5:
     resolution: {integrity: sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==}
     engines: {node: '>=0.10.0'}
@@ -1843,6 +2049,11 @@ packages:
     engines: {node: '>=0.10.0'}
     dev: true
 
+  /is-fullwidth-code-point@3.0.0:
+    resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
+    engines: {node: '>=8'}
+    dev: true
+
   /is-glob@4.0.3:
     resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
     engines: {node: '>=0.10.0'}
@@ -1901,6 +2112,11 @@ packages:
       call-bind: 1.0.7
     dev: true
 
+  /is-stream@2.0.1:
+    resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==}
+    engines: {node: '>=8'}
+    dev: true
+
   /is-string@1.0.7:
     resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==}
     engines: {node: '>= 0.4'}
@@ -1941,6 +2157,10 @@ packages:
     resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==}
     dev: true
 
+  /isexe@2.0.0:
+    resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
+    dev: true
+
   /isobject@2.1.0:
     resolution: {integrity: sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==}
     engines: {node: '>=0.10.0'}
@@ -1953,6 +2173,14 @@ packages:
     engines: {node: '>=0.10.0'}
     dev: true
 
+  /jackspeak@3.4.3:
+    resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==}
+    dependencies:
+      '@isaacs/cliui': 8.0.2
+    optionalDependencies:
+      '@pkgjs/parseargs': 0.11.0
+    dev: true
+
   /js-base64@2.6.4:
     resolution: {integrity: sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ==}
     dev: true
@@ -2000,6 +2228,13 @@ packages:
     engines: {node: '>=0.10.0'}
     dev: true
 
+  /lazystream@1.0.1:
+    resolution: {integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==}
+    engines: {node: '>= 0.6.3'}
+    dependencies:
+      readable-stream: 2.3.8
+    dev: true
+
   /loader-utils@1.4.2:
     resolution: {integrity: sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==}
     engines: {node: '>=4.0.0'}
@@ -2040,7 +2275,10 @@ packages:
 
   /lodash@4.17.21:
     resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
-    dev: false
+
+  /lru-cache@10.4.3:
+    resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==}
+    dev: true
 
   /magic-string@0.30.10:
     resolution: {integrity: sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==}
@@ -2126,6 +2364,13 @@ packages:
       mime-db: 1.52.0
     dev: false
 
+  /minimatch@5.1.6:
+    resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==}
+    engines: {node: '>=10'}
+    dependencies:
+      brace-expansion: 2.0.1
+    dev: true
+
   /minimatch@9.0.5:
     resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==}
     engines: {node: '>=16 || 14 >=14.17'}
@@ -2137,6 +2382,11 @@ packages:
     resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
     dev: true
 
+  /minipass@7.1.2:
+    resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==}
+    engines: {node: '>=16 || 14 >=14.17'}
+    dev: true
+
   /mitt@3.0.1:
     resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==}
     dev: false
@@ -2261,15 +2511,32 @@ packages:
       isobject: 3.0.1
     dev: true
 
+  /package-json-from-dist@1.0.1:
+    resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==}
+    dev: true
+
   /pascalcase@0.1.1:
     resolution: {integrity: sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==}
     engines: {node: '>=0.10.0'}
     dev: true
 
+  /path-key@3.1.1:
+    resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
+    engines: {node: '>=8'}
+    dev: true
+
   /path-parse@1.0.7:
     resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
     dev: true
 
+  /path-scurry@1.11.1:
+    resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==}
+    engines: {node: '>=16 || 14 >=14.18'}
+    dependencies:
+      lru-cache: 10.4.3
+      minipass: 7.1.2
+    dev: true
+
   /pathe@0.2.0:
     resolution: {integrity: sha512-sTitTPYnn23esFR3RlqYBWn4c45WGeLcsKzQiUpXJAyfcWkolvlYpV8FLo7JishK946oQwMFUCHXQ9AjGPKExw==}
     dev: true
@@ -2378,6 +2645,15 @@ packages:
       posthtml-render: 1.4.0
     dev: true
 
+  /process-nextick-args@2.0.1:
+    resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==}
+    dev: true
+
+  /process@0.11.10:
+    resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==}
+    engines: {node: '>= 0.6.0'}
+    dev: true
+
   /proxy-from-env@1.1.0:
     resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
     dev: false
@@ -2394,6 +2670,22 @@ packages:
     resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
     dev: true
 
+  /queue-tick@1.0.1:
+    resolution: {integrity: sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==}
+    dev: true
+
+  /readable-stream@2.3.8:
+    resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==}
+    dependencies:
+      core-util-is: 1.0.3
+      inherits: 2.0.4
+      isarray: 1.0.0
+      process-nextick-args: 2.0.1
+      safe-buffer: 5.1.2
+      string_decoder: 1.1.1
+      util-deprecate: 1.0.2
+    dev: true
+
   /readable-stream@3.6.2:
     resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==}
     engines: {node: '>= 6'}
@@ -2403,6 +2695,23 @@ packages:
       util-deprecate: 1.0.2
     dev: true
 
+  /readable-stream@4.5.2:
+    resolution: {integrity: sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+    dependencies:
+      abort-controller: 3.0.0
+      buffer: 6.0.3
+      events: 3.3.0
+      process: 0.11.10
+      string_decoder: 1.3.0
+    dev: true
+
+  /readdir-glob@1.1.3:
+    resolution: {integrity: sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==}
+    dependencies:
+      minimatch: 5.1.6
+    dev: true
+
   /readdirp@3.6.0:
     resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
     engines: {node: '>=8.10.0'}
@@ -2508,6 +2817,10 @@ packages:
       isarray: 2.0.5
     dev: true
 
+  /safe-buffer@5.1.2:
+    resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==}
+    dev: true
+
   /safe-buffer@5.2.1:
     resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
     dev: true
@@ -2573,6 +2886,18 @@ packages:
       split-string: 3.1.0
     dev: true
 
+  /shebang-command@2.0.0:
+    resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
+    engines: {node: '>=8'}
+    dependencies:
+      shebang-regex: 3.0.0
+    dev: true
+
+  /shebang-regex@3.0.0:
+    resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
+    engines: {node: '>=8'}
+    dev: true
+
   /side-channel@1.0.6:
     resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==}
     engines: {node: '>= 0.4'}
@@ -2583,6 +2908,11 @@ packages:
       object-inspect: 1.13.2
     dev: true
 
+  /signal-exit@4.1.0:
+    resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
+    engines: {node: '>=14'}
+    dev: true
+
   /snapdragon-node@2.1.1:
     resolution: {integrity: sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==}
     engines: {node: '>=0.10.0'}
@@ -2673,11 +3003,39 @@ packages:
       object-copy: 0.1.0
     dev: true
 
+  /streamx@2.21.0:
+    resolution: {integrity: sha512-Qz6MsDZXJ6ur9u+b+4xCG18TluU7PGlRfXVAAjNiGsFrBUt/ioyLkxbFaKJygoPs+/kW4VyBj0bSj89Qu0IGyg==}
+    dependencies:
+      fast-fifo: 1.3.2
+      queue-tick: 1.0.1
+      text-decoder: 1.2.1
+    optionalDependencies:
+      bare-events: 2.5.0
+    dev: true
+
   /strict-uri-encode@1.1.0:
     resolution: {integrity: sha512-R3f198pcvnB+5IpnBlRkphuE9n46WyVl8I39W/ZUTZLz4nqSP/oLYUrcnJrw462Ds8he4YKMov2efsTIw1BDGQ==}
     engines: {node: '>=0.10.0'}
     dev: true
 
+  /string-width@4.2.3:
+    resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
+    engines: {node: '>=8'}
+    dependencies:
+      emoji-regex: 8.0.0
+      is-fullwidth-code-point: 3.0.0
+      strip-ansi: 6.0.1
+    dev: true
+
+  /string-width@5.1.2:
+    resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==}
+    engines: {node: '>=12'}
+    dependencies:
+      eastasianwidth: 0.2.0
+      emoji-regex: 9.2.2
+      strip-ansi: 7.1.0
+    dev: true
+
   /string.prototype.trim@1.2.9:
     resolution: {integrity: sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==}
     engines: {node: '>= 0.4'}
@@ -2705,6 +3063,12 @@ packages:
       es-object-atoms: 1.0.0
     dev: true
 
+  /string_decoder@1.1.1:
+    resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==}
+    dependencies:
+      safe-buffer: 5.1.2
+    dev: true
+
   /string_decoder@1.3.0:
     resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==}
     dependencies:
@@ -2718,6 +3082,20 @@ packages:
       ansi-regex: 2.1.1
     dev: true
 
+  /strip-ansi@6.0.1:
+    resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
+    engines: {node: '>=8'}
+    dependencies:
+      ansi-regex: 5.0.1
+    dev: true
+
+  /strip-ansi@7.1.0:
+    resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==}
+    engines: {node: '>=12'}
+    dependencies:
+      ansi-regex: 6.1.0
+    dev: true
+
   /strip-literal@2.1.0:
     resolution: {integrity: sha512-Op+UycaUt/8FbN/Z2TWPBLge3jWrP3xj10f3fnYxf052bKuS3EKs1ZQcVGjnEMdsNVAM+plXRdmjrZ/KgG3Skw==}
     dependencies:
@@ -2775,6 +3153,14 @@ packages:
       stable: 0.1.8
     dev: true
 
+  /tar-stream@3.1.7:
+    resolution: {integrity: sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==}
+    dependencies:
+      b4a: 1.6.7
+      fast-fifo: 1.3.2
+      streamx: 2.21.0
+    dev: true
+
   /tdesign-icons-vue-next@0.2.2(vue@3.5.13):
     resolution: {integrity: sha512-ZKleBME7ZF1IVgnRXmIBPjfNa2Mef1nrK56f2xwn1Aa5mvXxB3fSxEzwhObR7bhzf/K42mz/Knnbll5Y7vCBjg==}
     peerDependencies:
@@ -2814,6 +3200,10 @@ packages:
       vue: 3.5.13
     dev: false
 
+  /text-decoder@1.2.1:
+    resolution: {integrity: sha512-x9v3H/lTKIJKQQe7RPQkLfKAnc9lUTkWDypIQgTzPJAq+5/GCDHonmshfvlsNSj58yyshbIJJDLmU15qNERrXQ==}
+    dev: true
+
   /tinycolor2@1.6.0:
     resolution: {integrity: sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==}
     dev: false
@@ -3135,7 +3525,6 @@ packages:
         optional: true
     dependencies:
       vue: 3.5.13
-    dev: false
 
   /vue-demi@0.14.8(vue@3.5.13):
     resolution: {integrity: sha512-Uuqnk9YE9SsWeReYqK2alDI5YzciATE0r2SkA6iMAtuXvNTMNACJLJEXNXaEy94ECuBe4Sk6RzRU80kjdbIo1Q==}
@@ -3203,3 +3592,38 @@ packages:
       gopd: 1.0.1
       has-tostringtag: 1.0.2
     dev: true
+
+  /which@2.0.2:
+    resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
+    engines: {node: '>= 8'}
+    hasBin: true
+    dependencies:
+      isexe: 2.0.0
+    dev: true
+
+  /wrap-ansi@7.0.0:
+    resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
+    engines: {node: '>=10'}
+    dependencies:
+      ansi-styles: 4.3.0
+      string-width: 4.2.3
+      strip-ansi: 6.0.1
+    dev: true
+
+  /wrap-ansi@8.1.0:
+    resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==}
+    engines: {node: '>=12'}
+    dependencies:
+      ansi-styles: 6.2.1
+      string-width: 5.1.2
+      strip-ansi: 7.1.0
+    dev: true
+
+  /zip-stream@6.0.1:
+    resolution: {integrity: sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==}
+    engines: {node: '>= 14'}
+    dependencies:
+      archiver-utils: 5.0.2
+      compress-commons: 6.0.2
+      readable-stream: 4.5.2
+    dev: true

+ 3 - 1
src/App.vue

@@ -1,5 +1,7 @@
 <script setup>
-
+import {useUserInfo} from '@/hooks/userInfo'
+const {getUserInfo} =useUserInfo()
+getUserInfo()
 </script>
 
 <template>

二进制
src/assets/imgs/logo.png


+ 6 - 0
src/assets/svg/menu/chart.svg

@@ -0,0 +1,6 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M4.49999 12L4.5 7.49994L5.5 7.49994L5.49999 12H4.49999Z" fill="black" fill-opacity="0.9"/>
+<path d="M7.5 4.5L7.5 12H8.5L8.5 4.5H7.5Z" fill="black" fill-opacity="0.9"/>
+<path d="M10.5 12L10.5 9L11.5 9L11.5 12H10.5Z" fill="black" fill-opacity="0.9"/>
+<path d="M2 3C2 2.44771 2.44772 2 3 2H13C13.5523 2 14 2.44772 14 3L14 13C14 13.5523 13.5523 14 13 14L3 14C2.44771 14 2 13.5523 2 13V3ZM3 3L3 13L13 13L13 3L3 3Z" fill="black" fill-opacity="0.9"/>
+</svg>

+ 4 - 0
src/assets/svg/menu/customer.svg

@@ -0,0 +1,4 @@
+<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M14.375 6.25C14.375 8.66625 12.4162 10.625 10 10.625C7.58375 10.625 5.625 8.66625 5.625 6.25C5.625 3.83375 7.58375 1.875 10 1.875C12.4162 1.875 14.375 3.83375 14.375 6.25ZM13.125 6.25C13.125 4.52411 11.7259 3.125 10 3.125C8.27411 3.125 6.875 4.52411 6.875 6.25C6.875 7.97589 8.27411 9.375 10 9.375C11.7259 9.375 13.125 7.97589 13.125 6.25Z" fill="black" fill-opacity="0.9"/>
+<path d="M17.4539 13.566C17.8712 13.7653 18.125 14.1933 18.125 14.6558V17.5C18.125 17.8452 17.8452 18.125 17.5 18.125H2.5C2.15482 18.125 1.875 17.8452 1.875 17.5V14.6558C1.875 14.1933 2.12877 13.7653 2.54608 13.566C4.81175 12.4838 7.33314 11.875 10 11.875C12.6669 11.875 15.1882 12.4838 17.4539 13.566ZM10 13.125C7.54175 13.125 5.21793 13.6822 3.125 14.6748V16.875H16.875V14.6748C14.7821 13.6822 12.4582 13.125 10 13.125Z" fill="black" fill-opacity="0.9"/>
+</svg>

+ 0 - 0
src/components/Empty.vue → src/components/EmptyWrap.vue


+ 15 - 0
src/components/globalComponents.js

@@ -0,0 +1,15 @@
+import { defineAsyncComponent } from 'vue';
+
+// 自动注册src/components目录下的所有.vue文件
+export default function registerGlobalComponents(app) {
+  const components = import.meta.glob('./components/**/*.vue');
+
+  for (const path in components) {
+    const componentName = path
+      .split('/')
+      .pop()
+      .replace(/\.\w+$/, '');
+
+    app.component(componentName, defineAsyncComponent(components[path]));
+  }
+}

+ 18 - 0
src/hooks/userInfo.js

@@ -0,0 +1,18 @@
+// 全局接口请求loading hook
+import {ref} from 'vue'
+
+const userInfo=ref(null)
+
+export function useUserInfo(){
+    function getUserInfo(){
+      const objStr=sessionStorage.getItem('userInfo')
+      if(objStr) {
+        userInfo.value=JSON.parse(objStr)
+      }
+    }
+
+    return {
+      userInfo,
+      getUserInfo,
+    }
+}

+ 24 - 37
src/layout/Index.vue

@@ -1,48 +1,35 @@
 <script setup>
+import HeaderWrap from './components/HeaderWrap.vue'
+import LeftWrap from './components/LeftWrap.vue'
+import { useLayoutState } from './hooks/index'
+
+
+const { menuClose } = useLayoutState()
 
 </script>
 
 <template>
-    <div class="layout-wrap">
-        <div class="bg-white header">
-            <span class="bread-item" v-for="item in $route.matched" :key="item.name">{{item.meta.title}}</span>
-        </div>
-        <div class="layout-content">
-            <router-view />
-        </div>
-        
+  <div :class="['layout-wrap', menuClose ? 'layout-wrap__max' : '']">
+    <HeaderWrap />
+    <LeftWrap />
+    <div class="layout-content">
+      <router-view />
     </div>
+  </div>
 </template>
 
 <style lang="scss" scoped>
-.layout-wrap{
-    height: 100%;
-    padding-top: 64px;
-    .header{
-        position: fixed;
-        left: 0;
-        right: 0;
-        top: 0;
-        z-index: 10;
-        height: 64px;
-        display: flex;
-        align-items: center;
-        padding-left: 24px;
-        .bread-item{
-            &::after{
-                content:'/'
-            }
-        }
-        .bread-item:last-child{
-            color: $primary-color;
-            &::after{
-                content:''
-            }
-        }
-    }
-    .layout-content{
-        padding: 20px;
-        min-height: calc(100% - 64px);
-    }
+.layout-wrap {
+  min-height: 100%;
+  padding-top: 66px;
+  padding-left: 200px;
+  transition: all .3s;
+  .layout-content {
+    padding: 30px;
+    min-height: calc(100% - 100px);
+  }
+}
+.layout-wrap__max{
+  padding-left: 80px;
 }
 </style>

+ 114 - 0
src/layout/components/HeaderWrap.vue

@@ -0,0 +1,114 @@
+<script setup>
+import { useLayoutState } from '../hooks/index'
+import { useRoute, useRouter } from 'vue-router'
+import {useUserInfo} from '@/hooks/userInfo'
+const {userInfo} =useUserInfo()
+
+
+const { menuClose, menuCloseChange } = useLayoutState()
+
+const router=useRouter()
+const route=useRoute()
+
+
+const breadcrumbArr=computed(()=>{
+  const arr=route.matched
+  let temarr=arr.map(item=>{
+    return {title:item.meta.title}
+  })
+  if(arr[1]&&arr[1].meta.from){
+    temarr.splice(1,0,{title:arr[1].meta.from,path:arr[1].meta.fromPath})
+  }
+  if(arr[1]){
+    if(['消息推送管理','客户反馈','图片资源库'].includes(arr[1].meta.title)){
+        return [{title:arr[1].meta.title}]
+    }
+  }
+  return temarr
+})
+function handleClickBreadcrumb(e){
+  // console.log(e);
+  if(e.path){
+    router.push(e.path)
+  }else{
+    window.location.reload();
+  }
+  // router.push()
+}
+
+</script>
+
+<template>
+  <div class="flex header-wrap">
+    <img src="@/assets/imgs/logo.png" alt= "" class="logo-img">
+    <div class="flex content">
+      <!-- 折叠按钮 -->
+      <t-icon size="20px" :name="menuClose?'menu-fold':'menu-unfold'" @click="menuCloseChange"></t-icon>
+      
+      <!-- 面包屑 -->
+      <t-breadcrumb separator="/" style="margin-left: 30px">
+        <template #default>
+          <t-breadcrumb-item v-for="item,index in breadcrumbArr" :key="index" @click="handleClickBreadcrumb(item)">{{
+            item.title
+          }}</t-breadcrumb-item>
+        </template>
+      </t-breadcrumb>
+      <!-- 用户信息 -->
+      <div class="flex system-user-box">
+        <span class="icon">弘则</span>
+        <span>{{ userInfo?.RealName }}</span>
+        <span>,欢迎您</span>
+      </div>
+    </div>
+  </div>
+</template>
+
+<style lang="scss" scoped>
+.header-wrap {
+  position: fixed;
+  left: 0px;
+  top: 0;
+  right: 0;
+  height: 66px;
+  z-index: 50;
+  background-color: #fff;
+  box-shadow: 0px 3px 6px 0px #0000001A;
+  padding: 0 20px 0 0;
+  align-items: center;
+  color: #333;
+  .logo-img{
+    width: 200px;
+    display: block;
+  }
+
+  .content {
+    flex: 1;
+    padding-left: 16px;
+    align-items: center;
+    .t-breadcrumb__item{
+      color: #333;
+    }
+    .t-breadcrumb__item:last-child{
+      color: var(--td-brand-color);
+    }
+  }
+  .system-user-box{
+    margin-left: auto;
+    align-items: center;
+    .icon{
+      display: block;
+      background-color: var(--td-brand-color);
+      color: #fff;
+      width: 30px;
+      height: 30px;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      margin-right: 10px;
+      border-radius: 50%;
+      font-size: 12px;
+    }
+    
+  }
+}
+</style>

+ 315 - 0
src/layout/components/LeftWrap.vue

@@ -0,0 +1,315 @@
+<script setup>
+import { useRouter } from 'vue-router'
+import { useLayoutState } from '../hooks/index'
+// import {apiSystemRole} from '@/api/system'
+
+const router = useRouter()
+
+const { menuClose } = useLayoutState()
+
+const navList = ref([
+  {
+    name: '客户管理',
+    path: '/customer',
+    IsLevel: 2,
+    Children: [
+      {
+        name: '商家管理',
+        path: '/business'
+      },
+      {
+        name: '用户管理',
+        path: '/userList'
+      }
+    ]
+  },
+  {
+    name: 'ETA客户行为统计',
+    path: '/',
+    IsLevel: 1,
+    Children: [
+      {
+        name: 'ETA客户行为统计',
+        path: '/',
+      }
+    ]
+  },
+  {
+    name: 'ETA试用管理',
+    path: '/',
+    IsLevel: 1,
+    Children: [
+      {
+        name: 'ETA试用管理',
+        path: '/',
+      }
+    ]
+  },
+  {
+    name: 'ETA社区管理',
+    path: '/etaChart',
+    IsLevel: 1,
+    Children: [
+      {
+        name: 'ETA社区管理',
+        path: '/etaChart/index',
+      }
+    ]
+  },
+  {
+    name: 'ETA菜单配置',
+    path: '/',
+    IsLevel: 1,
+    Children: [
+      {
+        name: 'ETA菜单配置',
+        path: '/',
+      }
+    ]
+  },
+  {
+    name: '培训管理',
+    path: '/',
+    IsLevel: 2,
+    Children: [
+      {
+        name: '视频管理',
+        path: '/',
+      },
+      {
+        name: '标签管理',
+        path: '/',
+      },
+      {
+        name: '分类管理',
+        path: '/',
+      }
+    ]
+  },
+  {
+    name: '个性化设置',
+    path: '/',
+    IsLevel: 1,
+    Children: [
+      {
+        name: '个性化设置',
+        path: '/',
+      }
+    ]
+  },
+  {
+    name: '权限配置',
+    path: '/',
+    IsLevel: 1,
+    Children: [
+      {
+        name: '权限配置',
+        path: '/',
+      }
+    ]
+  },
+  {
+    name: '系统设置',
+    path: '/',
+    IsLevel: 2,
+    Children: [
+      {
+        name: '更新日志配置',
+        path: '/',
+      },
+      {
+        name: '帮助中心配置',
+        path: '/',
+      }
+    ]
+  },
+])
+
+function getNavList() {
+  //mock navList
+  /* navList.value = [
+      {
+          Path:'/customer',
+          Name:'客户管理',
+          Children:[
+              {
+                  Path:'/customer/tempUserList',
+                  Name:'临时用户列表',
+              }
+          ]
+      },
+      {
+          Path:'/authorMgt/authorList',
+          Name:'研究员管理',
+          Children:[]
+      },
+      {
+          Path:'/mediaMgt',
+          Name:'音视频管理',
+          Children:[
+              {
+                  Path:'/mediaMgt/audioList',
+                  Name:'音频管理',
+              },
+              {
+                  Path:'/mediaMgt/videoList',
+                  Name:'视频管理',
+              }
+          ]
+      },
+      {
+          Path:'/customer/notification',
+          Name:'消息推送管理',
+          Children:[]
+      },
+      {
+          Path:'/mediaMgt/pictureLib',
+          Name:'图片资源库',
+          Children:[]
+      },
+      {
+          Path:'/customer/feedbackList',
+          Name:'客户反馈',
+          Children:[]
+      },
+      {
+          Path:'/system',
+          Name:'系统设置',
+          Children:[
+              {
+                  Path:'/system/userList',
+                  Name:'用户列表',
+              },
+              {
+                  Path:'/system/roleList',
+                  Name:'角色管理',
+              },
+              {
+                  Path:'/system/authSet',
+                  Name:'权限管理',
+              }
+          ]
+      },
+  ] */
+
+  // apiSystemRole.menuData().then(res=>{
+  //   if(res.Ret===200){
+  //     navList.value=res.Data||[]
+  //   }
+  // })
+}
+getNavList()
+
+
+
+function getMenuIcon(item) {
+  const iconMap = {
+    '/customer': 'menu/customer',
+  }
+  return iconMap[item] || 'menu/setting'
+
+}
+
+</script>
+
+<template>
+  <div :class="['left-wrap', menuClose ? 'left-wrap__close' : '']">
+    <t-menu
+      class="menu-wrap"
+      :value="$route.path"
+      :collapsed="menuClose"
+      :width="['200px', '80px']"
+    >
+      <template v-for="level1 in navList" :key="level1.SysMenuId">
+        <t-menu-item :index="level1.path" v-if="level1.IsLevel === 1">
+          <svg-icon
+            :name="getMenuIcon(level1.path)"
+            :color="$route.path === level1.path ? '#086CE0' : '#333'"
+            style="font-size: 16px"
+          ></svg-icon>
+          <span style="margin-left: 5px">{{ level1.name }}</span>
+        </t-menu-item>
+        <t-submenu :index="level1.path" v-if="level1.IsLevel === 2">
+          <template #title>
+            <svg-icon
+              :name="getMenuIcon(level1.path)"
+              :color="$route.path === level1.path ? '#086CE0' : '#333'"
+              style="font-size: 16px"
+            ></svg-icon>
+            <span style="margin-left: 5px">{{ level1.name }}</span>
+          </template>
+          <t-menu-item
+            v-for="child in level1.Children"
+            :index="child.path"
+            :key="child.path"
+          >
+            <svg-icon
+              name="menu/submenu"
+              :color="$route.path === child.path ? '#086CE0' : '#333'"
+              style="font-size: 16px"
+            ></svg-icon>
+            <span style="margin-left: 5px">{{ child.name }}</span>
+          </t-menu-item>
+        </t-submenu>
+      </template>
+    </t-menu>
+  </div>
+</template>
+
+<style lang="scss" scoped>
+.left-wrap {
+  width: 200px;
+  z-index: 50;
+  position: fixed;
+  top: 67px;
+  left: 0;
+  bottom: 0;
+  padding: 8px 0;
+  background-color: #fff;
+  display: flex;
+  flex-direction: column;
+  padding-bottom: 111px;
+  transition: all 0.5s;
+  .menu-wrap {
+    flex: 1;
+    height: 100%;
+    border: none;
+    .t-submenu {
+      :deep(.t-menu-item) {
+        padding-left: var(--t-menu-base-level-padding);
+      }
+      :deep(.t-submenu__icon-arrow) {
+        transform: rotateZ(-90deg) !important;
+      }
+      &.is-opened {
+        :deep(.t-submenu__icon-arrow) {
+          transform: rotateZ(0deg) !important;
+          border-radius: 4px;
+        }
+      }
+    }
+    :deep(.t-menu-item.is-active) {
+      background-color: #f3f9ff;
+    }
+  }
+  .user-box {
+    background-color: var(--t-menu-hover-bg-color);
+    color: #333;
+    text-align: center;
+    padding: 20px;
+    .name-box {
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      gap: 0 5px;
+    }
+    .opt {
+      margin: 10px 0;
+      cursor: pointer;
+    }
+  }
+}
+.left-wrap__close {
+  width: 80px;
+}
+</style>

+ 13 - 0
src/layout/hooks/index.js

@@ -0,0 +1,13 @@
+import {ref} from 'vue'
+
+const menuClose=ref(false)
+
+export function useLayoutState(){
+  function menuCloseChange(){
+    menuClose.value=!menuClose.value
+  }
+  return {
+    menuClose,
+    menuCloseChange
+  }
+}

+ 4 - 8
src/main.js

@@ -6,18 +6,14 @@ import './styles/common.scss'
 // 引入组件库的少量全局样式变量
 import 'tdesign-vue-next/es/style/index.css';
 
-
-// svg图标组件
-import svgIcon from "@/components/SvgIcon.vue";
 //引入注册脚本
 import 'virtual:svg-icons-register'
-
-import EmptyWrap from '@/components/Empty.vue'
-
+import registerGlobalComponents from '@/components/globalComponents';
 
 const app= createApp(App)
 
-app.component('svg-icon', svgIcon)
-app.component('empty-wrap', EmptyWrap)
+// 注册全局组件
+registerGlobalComponents(app)
+
 app.use(router)
 app.mount('#app')

+ 14 - 28
src/router/index.js

@@ -1,7 +1,20 @@
 import { createRouter, createWebHistory } from "vue-router";
-import LayoutIndex from "@/layout/Index.vue";
+
+//all routes
+const appAllRoutes = [];
+function importAllRoutes (r){
+  for(let key in r) {
+    appAllRoutes.push(...r[key].default)
+  }
+}
+importAllRoutes(import.meta.glob('./modules/*.js',{ eager: true }))
 
 const routes = [
+  ...appAllRoutes,
+  {
+    path:'/',
+    redirect: '/autoLogin'
+  },
   {
     path:'/autoLogin',
     name:'AutoLogin',
@@ -10,33 +23,6 @@ const routes = [
       title:'ETA社区'
     },
   },
-  {
-    path:'/',
-    name:'LayoutIndex',
-    redirect: '/autoLogin',
-    component:LayoutIndex,
-    meta:{
-      title:'ETA社区'
-    },
-    children:[
-      {
-        path:'etaChart/index',
-        name:'ETAChartIndex',
-        component:()=>import('@/views/etaChart/Index.vue'),
-        meta:{
-          title:'ETA图库'
-        },
-      },
-      {
-        path:'EDBSource',
-        name:'EDBSource',
-        component:()=>import('@/views/EDBSource.vue'),
-        meta:{
-          title:'指标溯源'
-        },
-      },
-    ]
-  },
   {
     path: "/:pathMatch(.*)",
     name: "error",

+ 30 - 0
src/router/modules/etaChart.js

@@ -0,0 +1,30 @@
+import LayoutIndex from "@/layout/Index.vue";
+
+export default[
+  {
+    path:'/etaChart',
+    name:'ETAChart',
+    component:LayoutIndex,
+    meta:{
+      title:'ETA社区管理'
+    },
+    children:[
+      {
+        path:'index',
+        name:'ETAChartIndex',
+        component:()=>import('@/views/etaChart/Index.vue'),
+        meta:{
+          title:'ETA图库'
+        },
+      },
+      {
+        path:'EDBSource',
+        name:'EDBSource',
+        component:()=>import('@/views/EDBSource.vue'),
+        meta:{
+          title:'指标溯源'
+        },
+      },
+    ]
+  }
+]

+ 4 - 0
src/styles/common.scss

@@ -27,6 +27,10 @@ img {
     -ms-interpolation-mode: nearest-neighbor;
 }
 
+.flex{
+    display: flex;
+}
+
 .bg-white{
     background-color: #fff;
 }

+ 3 - 1
src/styles/var.scss

@@ -1 +1,3 @@
-$primary-color:#0052D9;
+:root{
+  
+}

+ 3 - 3
src/views/etaChart/components/ClassifyWrap.vue

@@ -558,7 +558,7 @@ const showBatchMove = ref(false)
         display: flex;
         gap: 0 5px;
         .t-icon {
-          color: $primary-color;
+          color: var(--td-brand-color);
         }
       }
     }
@@ -570,9 +570,9 @@ const showBatchMove = ref(false)
     align-items: center;
     justify-content: center;
     gap: 0 5px;
-    color: $primary-color;
+    color: var(--td-brand-color);
     .t-icon {
-      color: $primary-color;
+      color: var(--td-brand-color);
     }
   }
 }

+ 4 - 0
vite.config.js

@@ -5,6 +5,7 @@ import AutoImport from "unplugin-auto-import/vite";
 import Components from "unplugin-vue-components/vite";
 import { TDesignResolver } from "unplugin-vue-components/resolvers";
 import { createSvgIconsPlugin } from "vite-plugin-svg-icons";
+import zipBuildPlugin from './zipBuildPlugin';
 
 // https://vitejs.dev/config/
 export default defineConfig(({ mode }) => {
@@ -15,6 +16,8 @@ export default defineConfig(({ mode }) => {
     plugins: [
       vue(),
       AutoImport({
+        // 自动导入 Vue 相关函数,如:ref, reactive, toRef 等
+        imports: ["vue"],
         resolvers: [
           TDesignResolver({
             library: "vue-next",
@@ -61,6 +64,7 @@ export default defineConfig(({ mode }) => {
          */
         // customDomId: '__svg__icons__dom__'
       }),
+      zipBuildPlugin()
     ],
     css: {
       // css预处理器

+ 55 - 0
zipBuildPlugin.js

@@ -0,0 +1,55 @@
+// zipPlugin.js
+import { resolve } from 'path';
+import { createWriteStream } from 'fs';
+import archiver from 'archiver';
+
+export default function zipBuildPlugin() {
+  let outDir = 'dist'; // 默认值
+
+  return {
+    name: 'zip-after-build',
+    configResolved(resolvedConfig) {
+      // 读取 Vite 配置中的 build.outDir
+      outDir = resolvedConfig.build.outDir;
+    },
+    closeBundle: {
+      sequential: true,
+      async handler() {
+        const outputDir = resolve(__dirname, outDir);
+        const zipFilePath = resolve(__dirname, `${outDir}.zip`);
+
+        // 创建文件输出流
+        const output = createWriteStream(zipFilePath);
+        const archive = archiver('zip', {
+          zlib: { level: 9 } // 设置压缩等级
+        });
+
+        return new Promise((resolve, reject) => {
+          output.on('close', () => {
+            console.log(`打包完成,共 ${archive.pointer()} 字节`);
+            resolve();
+          });
+
+          archive.on('warning', (err) => {
+            if (err.code !== 'ENOENT') {
+              reject(err);
+            }
+          });
+
+          archive.on('error', (err) => {
+            reject(err);
+          });
+
+          // 将归档数据管道化到文件
+          archive.pipe(output);
+
+          // 将 dist 文件夹及其内容都压缩进 zip
+          archive.directory(outputDir, outDir);
+
+          // 完成归档
+          archive.finalize();
+        });
+      }
+    }
+  };
+}