This commit is contained in:
parent
b694fb3461
commit
698ea070ae
210
pnpm-lock.yaml
210
pnpm-lock.yaml
|
|
@ -44,6 +44,9 @@ importers:
|
||||||
pinia:
|
pinia:
|
||||||
specifier: ^3.0.4
|
specifier: ^3.0.4
|
||||||
version: 3.0.4(typescript@5.9.3)(vue@3.5.29(typescript@5.9.3))
|
version: 3.0.4(typescript@5.9.3)(vue@3.5.29(typescript@5.9.3))
|
||||||
|
qrcode:
|
||||||
|
specifier: ^1.5.4
|
||||||
|
version: 1.5.4
|
||||||
vue:
|
vue:
|
||||||
specifier: ^3.5.29
|
specifier: ^3.5.29
|
||||||
version: 3.5.29(typescript@5.9.3)
|
version: 3.5.29(typescript@5.9.3)
|
||||||
|
|
@ -1262,6 +1265,14 @@ packages:
|
||||||
alien-signals@3.1.2:
|
alien-signals@3.1.2:
|
||||||
resolution: {integrity: sha512-d9dYqZTS90WLiU0I5c6DHj/HcKkF8ZyGN3G5x8wSbslulz70KOxaqCT0hQCo9KOyhVqzqGojvNdJXoTumZOtcw==}
|
resolution: {integrity: sha512-d9dYqZTS90WLiU0I5c6DHj/HcKkF8ZyGN3G5x8wSbslulz70KOxaqCT0hQCo9KOyhVqzqGojvNdJXoTumZOtcw==}
|
||||||
|
|
||||||
|
ansi-regex@5.0.1:
|
||||||
|
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
|
ansi-styles@4.3.0:
|
||||||
|
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
ansi-styles@6.2.3:
|
ansi-styles@6.2.3:
|
||||||
resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==}
|
resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
|
|
@ -1323,6 +1334,10 @@ packages:
|
||||||
resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==}
|
resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
|
camelcase@5.3.1:
|
||||||
|
resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==}
|
||||||
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
caniuse-lite@1.0.30001774:
|
caniuse-lite@1.0.30001774:
|
||||||
resolution: {integrity: sha512-DDdwPGz99nmIEv216hKSgLD+D4ikHQHjBC/seF98N9CPqRX4M5mSxT9eTV6oyisnJcuzxtZy4n17yKKQYmYQOA==}
|
resolution: {integrity: sha512-DDdwPGz99nmIEv216hKSgLD+D4ikHQHjBC/seF98N9CPqRX4M5mSxT9eTV6oyisnJcuzxtZy4n17yKKQYmYQOA==}
|
||||||
|
|
||||||
|
|
@ -1338,10 +1353,20 @@ packages:
|
||||||
resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==}
|
resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==}
|
||||||
engines: {node: '>= 20.19.0'}
|
engines: {node: '>= 20.19.0'}
|
||||||
|
|
||||||
|
cliui@6.0.0:
|
||||||
|
resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==}
|
||||||
|
|
||||||
codepage@1.15.0:
|
codepage@1.15.0:
|
||||||
resolution: {integrity: sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==}
|
resolution: {integrity: sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==}
|
||||||
engines: {node: '>=0.8'}
|
engines: {node: '>=0.8'}
|
||||||
|
|
||||||
|
color-convert@2.0.1:
|
||||||
|
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
|
||||||
|
engines: {node: '>=7.0.0'}
|
||||||
|
|
||||||
|
color-name@1.1.4:
|
||||||
|
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
|
||||||
|
|
||||||
combined-stream@1.0.8:
|
combined-stream@1.0.8:
|
||||||
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
|
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
|
||||||
engines: {node: '>= 0.8'}
|
engines: {node: '>= 0.8'}
|
||||||
|
|
@ -1398,6 +1423,10 @@ packages:
|
||||||
supports-color:
|
supports-color:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
decamelize@1.2.0:
|
||||||
|
resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==}
|
||||||
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
deep-is@0.1.4:
|
deep-is@0.1.4:
|
||||||
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
|
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
|
||||||
|
|
||||||
|
|
@ -1421,6 +1450,9 @@ packages:
|
||||||
resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}
|
resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
|
dijkstrajs@1.0.3:
|
||||||
|
resolution: {integrity: sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==}
|
||||||
|
|
||||||
dom7@3.0.0:
|
dom7@3.0.0:
|
||||||
resolution: {integrity: sha512-oNlcUdHsC4zb7Msx7JN3K0Nro1dzJ48knvBOnDPKJ2GV9wl1i5vydJZUSyOfrkKFDZEud/jBsTk92S/VGSAe/g==}
|
resolution: {integrity: sha512-oNlcUdHsC4zb7Msx7JN3K0Nro1dzJ48knvBOnDPKJ2GV9wl1i5vydJZUSyOfrkKFDZEud/jBsTk92S/VGSAe/g==}
|
||||||
|
|
||||||
|
|
@ -1436,6 +1468,9 @@ packages:
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
vue: ^3.3.0
|
vue: ^3.3.0
|
||||||
|
|
||||||
|
emoji-regex@8.0.0:
|
||||||
|
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
|
||||||
|
|
||||||
entities@7.0.1:
|
entities@7.0.1:
|
||||||
resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==}
|
resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==}
|
||||||
engines: {node: '>=0.12'}
|
engines: {node: '>=0.12'}
|
||||||
|
|
@ -1607,6 +1642,10 @@ packages:
|
||||||
resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
|
resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
|
find-up@4.1.0:
|
||||||
|
resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
find-up@5.0.0:
|
find-up@5.0.0:
|
||||||
resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
|
resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
|
@ -1647,6 +1686,10 @@ packages:
|
||||||
resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
|
resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
|
||||||
engines: {node: '>=6.9.0'}
|
engines: {node: '>=6.9.0'}
|
||||||
|
|
||||||
|
get-caller-file@2.0.5:
|
||||||
|
resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
|
||||||
|
engines: {node: 6.* || 8.* || >= 10.*}
|
||||||
|
|
||||||
get-intrinsic@1.3.0:
|
get-intrinsic@1.3.0:
|
||||||
resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==}
|
resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
@ -1715,6 +1758,10 @@ packages:
|
||||||
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
|
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
|
is-fullwidth-code-point@3.0.0:
|
||||||
|
resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
is-glob@4.0.3:
|
is-glob@4.0.3:
|
||||||
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
|
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
@ -1803,6 +1850,10 @@ packages:
|
||||||
resolution: {integrity: sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A==}
|
resolution: {integrity: sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A==}
|
||||||
engines: {node: '>=14'}
|
engines: {node: '>=14'}
|
||||||
|
|
||||||
|
locate-path@5.0.0:
|
||||||
|
resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
locate-path@6.0.0:
|
locate-path@6.0.0:
|
||||||
resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
|
resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
|
@ -1966,14 +2017,26 @@ packages:
|
||||||
oxlint-tsgolint:
|
oxlint-tsgolint:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
p-limit@2.3.0:
|
||||||
|
resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==}
|
||||||
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
p-limit@3.1.0:
|
p-limit@3.1.0:
|
||||||
resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
|
resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
|
p-locate@4.1.0:
|
||||||
|
resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
p-locate@5.0.0:
|
p-locate@5.0.0:
|
||||||
resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
|
resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
|
p-try@2.2.0:
|
||||||
|
resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==}
|
||||||
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
path-browserify@1.0.1:
|
path-browserify@1.0.1:
|
||||||
resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==}
|
resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==}
|
||||||
|
|
||||||
|
|
@ -2025,6 +2088,10 @@ packages:
|
||||||
pkg-types@2.3.0:
|
pkg-types@2.3.0:
|
||||||
resolution: {integrity: sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==}
|
resolution: {integrity: sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==}
|
||||||
|
|
||||||
|
pngjs@5.0.0:
|
||||||
|
resolution: {integrity: sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==}
|
||||||
|
engines: {node: '>=10.13.0'}
|
||||||
|
|
||||||
postcss-selector-parser@7.1.1:
|
postcss-selector-parser@7.1.1:
|
||||||
resolution: {integrity: sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==}
|
resolution: {integrity: sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==}
|
||||||
engines: {node: '>=4'}
|
engines: {node: '>=4'}
|
||||||
|
|
@ -2056,6 +2123,11 @@ packages:
|
||||||
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
|
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
|
qrcode@1.5.4:
|
||||||
|
resolution: {integrity: sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==}
|
||||||
|
engines: {node: '>=10.13.0'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
quansync@0.2.11:
|
quansync@0.2.11:
|
||||||
resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==}
|
resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==}
|
||||||
|
|
||||||
|
|
@ -2074,6 +2146,13 @@ packages:
|
||||||
resolution: {integrity: sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==}
|
resolution: {integrity: sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==}
|
||||||
engines: {node: '>= 20.19.0'}
|
engines: {node: '>= 20.19.0'}
|
||||||
|
|
||||||
|
require-directory@2.1.1:
|
||||||
|
resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
|
||||||
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
|
require-main-filename@2.0.0:
|
||||||
|
resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==}
|
||||||
|
|
||||||
reusify@1.1.0:
|
reusify@1.1.0:
|
||||||
resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==}
|
resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==}
|
||||||
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
|
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
|
||||||
|
|
@ -2113,6 +2192,9 @@ packages:
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
set-blocking@2.0.0:
|
||||||
|
resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==}
|
||||||
|
|
||||||
shebang-command@2.0.0:
|
shebang-command@2.0.0:
|
||||||
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
|
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
@ -2156,6 +2238,14 @@ packages:
|
||||||
ssr-window@3.0.0:
|
ssr-window@3.0.0:
|
||||||
resolution: {integrity: sha512-q+8UfWDg9Itrg0yWK7oe5p/XRCJpJF9OBtXfOPgSJl+u3Xd5KI328RUEvUqSMVM9CiQUEf1QdBzJMkYGErj9QA==}
|
resolution: {integrity: sha512-q+8UfWDg9Itrg0yWK7oe5p/XRCJpJF9OBtXfOPgSJl+u3Xd5KI328RUEvUqSMVM9CiQUEf1QdBzJMkYGErj9QA==}
|
||||||
|
|
||||||
|
string-width@4.2.3:
|
||||||
|
resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
|
strip-ansi@6.0.1:
|
||||||
|
resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
strip-literal@3.1.0:
|
strip-literal@3.1.0:
|
||||||
resolution: {integrity: sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==}
|
resolution: {integrity: sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==}
|
||||||
|
|
||||||
|
|
@ -2382,6 +2472,9 @@ packages:
|
||||||
webpack-virtual-modules@0.6.2:
|
webpack-virtual-modules@0.6.2:
|
||||||
resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==}
|
resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==}
|
||||||
|
|
||||||
|
which-module@2.0.1:
|
||||||
|
resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==}
|
||||||
|
|
||||||
which@2.0.2:
|
which@2.0.2:
|
||||||
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
|
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
|
||||||
engines: {node: '>= 8'}
|
engines: {node: '>= 8'}
|
||||||
|
|
@ -2407,6 +2500,10 @@ packages:
|
||||||
resolution: {integrity: sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==}
|
resolution: {integrity: sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==}
|
||||||
engines: {node: '>=0.8'}
|
engines: {node: '>=0.8'}
|
||||||
|
|
||||||
|
wrap-ansi@6.2.0:
|
||||||
|
resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
wsl-utils@0.1.0:
|
wsl-utils@0.1.0:
|
||||||
resolution: {integrity: sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==}
|
resolution: {integrity: sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
|
|
@ -2420,6 +2517,9 @@ packages:
|
||||||
resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==}
|
resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
|
|
||||||
|
y18n@4.0.3:
|
||||||
|
resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==}
|
||||||
|
|
||||||
yallist@3.1.1:
|
yallist@3.1.1:
|
||||||
resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
|
resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
|
||||||
|
|
||||||
|
|
@ -2428,6 +2528,14 @@ packages:
|
||||||
engines: {node: '>= 14.6'}
|
engines: {node: '>= 14.6'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
yargs-parser@18.1.3:
|
||||||
|
resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==}
|
||||||
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
|
yargs@15.4.1:
|
||||||
|
resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
yocto-queue@0.1.0:
|
yocto-queue@0.1.0:
|
||||||
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
|
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
|
@ -3516,6 +3624,12 @@ snapshots:
|
||||||
|
|
||||||
alien-signals@3.1.2: {}
|
alien-signals@3.1.2: {}
|
||||||
|
|
||||||
|
ansi-regex@5.0.1: {}
|
||||||
|
|
||||||
|
ansi-styles@4.3.0:
|
||||||
|
dependencies:
|
||||||
|
color-convert: 2.0.1
|
||||||
|
|
||||||
ansi-styles@6.2.3: {}
|
ansi-styles@6.2.3: {}
|
||||||
|
|
||||||
ansis@4.2.0: {}
|
ansis@4.2.0: {}
|
||||||
|
|
@ -3575,6 +3689,8 @@ snapshots:
|
||||||
es-errors: 1.3.0
|
es-errors: 1.3.0
|
||||||
function-bind: 1.1.2
|
function-bind: 1.1.2
|
||||||
|
|
||||||
|
camelcase@5.3.1: {}
|
||||||
|
|
||||||
caniuse-lite@1.0.30001774: {}
|
caniuse-lite@1.0.30001774: {}
|
||||||
|
|
||||||
cfb@1.2.2:
|
cfb@1.2.2:
|
||||||
|
|
@ -3590,8 +3706,20 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
readdirp: 5.0.0
|
readdirp: 5.0.0
|
||||||
|
|
||||||
|
cliui@6.0.0:
|
||||||
|
dependencies:
|
||||||
|
string-width: 4.2.3
|
||||||
|
strip-ansi: 6.0.1
|
||||||
|
wrap-ansi: 6.2.0
|
||||||
|
|
||||||
codepage@1.15.0: {}
|
codepage@1.15.0: {}
|
||||||
|
|
||||||
|
color-convert@2.0.1:
|
||||||
|
dependencies:
|
||||||
|
color-name: 1.1.4
|
||||||
|
|
||||||
|
color-name@1.1.4: {}
|
||||||
|
|
||||||
combined-stream@1.0.8:
|
combined-stream@1.0.8:
|
||||||
dependencies:
|
dependencies:
|
||||||
delayed-stream: 1.0.0
|
delayed-stream: 1.0.0
|
||||||
|
|
@ -3633,6 +3761,8 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
ms: 2.1.3
|
ms: 2.1.3
|
||||||
|
|
||||||
|
decamelize@1.2.0: {}
|
||||||
|
|
||||||
deep-is@0.1.4: {}
|
deep-is@0.1.4: {}
|
||||||
|
|
||||||
default-browser-id@5.0.1: {}
|
default-browser-id@5.0.1: {}
|
||||||
|
|
@ -3649,6 +3779,8 @@ snapshots:
|
||||||
detect-libc@2.1.2:
|
detect-libc@2.1.2:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
dijkstrajs@1.0.3: {}
|
||||||
|
|
||||||
dom7@3.0.0:
|
dom7@3.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
ssr-window: 3.0.0
|
ssr-window: 3.0.0
|
||||||
|
|
@ -3681,6 +3813,8 @@ snapshots:
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- '@vue/composition-api'
|
- '@vue/composition-api'
|
||||||
|
|
||||||
|
emoji-regex@8.0.0: {}
|
||||||
|
|
||||||
entities@7.0.1: {}
|
entities@7.0.1: {}
|
||||||
|
|
||||||
error-stack-parser-es@1.0.5: {}
|
error-stack-parser-es@1.0.5: {}
|
||||||
|
|
@ -3896,6 +4030,11 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
to-regex-range: 5.0.1
|
to-regex-range: 5.0.1
|
||||||
|
|
||||||
|
find-up@4.1.0:
|
||||||
|
dependencies:
|
||||||
|
locate-path: 5.0.0
|
||||||
|
path-exists: 4.0.0
|
||||||
|
|
||||||
find-up@5.0.0:
|
find-up@5.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
locate-path: 6.0.0
|
locate-path: 6.0.0
|
||||||
|
|
@ -3927,6 +4066,8 @@ snapshots:
|
||||||
|
|
||||||
gensync@1.0.0-beta.2: {}
|
gensync@1.0.0-beta.2: {}
|
||||||
|
|
||||||
|
get-caller-file@2.0.5: {}
|
||||||
|
|
||||||
get-intrinsic@1.3.0:
|
get-intrinsic@1.3.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
call-bind-apply-helpers: 1.0.2
|
call-bind-apply-helpers: 1.0.2
|
||||||
|
|
@ -3987,6 +4128,8 @@ snapshots:
|
||||||
|
|
||||||
is-extglob@2.1.1: {}
|
is-extglob@2.1.1: {}
|
||||||
|
|
||||||
|
is-fullwidth-code-point@3.0.0: {}
|
||||||
|
|
||||||
is-glob@4.0.3:
|
is-glob@4.0.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
is-extglob: 2.1.1
|
is-extglob: 2.1.1
|
||||||
|
|
@ -4050,6 +4193,10 @@ snapshots:
|
||||||
pkg-types: 2.3.0
|
pkg-types: 2.3.0
|
||||||
quansync: 0.2.11
|
quansync: 0.2.11
|
||||||
|
|
||||||
|
locate-path@5.0.0:
|
||||||
|
dependencies:
|
||||||
|
p-locate: 4.1.0
|
||||||
|
|
||||||
locate-path@6.0.0:
|
locate-path@6.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
p-locate: 5.0.0
|
p-locate: 5.0.0
|
||||||
|
|
@ -4208,14 +4355,24 @@ snapshots:
|
||||||
'@oxlint/binding-win32-ia32-msvc': 1.50.0
|
'@oxlint/binding-win32-ia32-msvc': 1.50.0
|
||||||
'@oxlint/binding-win32-x64-msvc': 1.50.0
|
'@oxlint/binding-win32-x64-msvc': 1.50.0
|
||||||
|
|
||||||
|
p-limit@2.3.0:
|
||||||
|
dependencies:
|
||||||
|
p-try: 2.2.0
|
||||||
|
|
||||||
p-limit@3.1.0:
|
p-limit@3.1.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
yocto-queue: 0.1.0
|
yocto-queue: 0.1.0
|
||||||
|
|
||||||
|
p-locate@4.1.0:
|
||||||
|
dependencies:
|
||||||
|
p-limit: 2.3.0
|
||||||
|
|
||||||
p-locate@5.0.0:
|
p-locate@5.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
p-limit: 3.1.0
|
p-limit: 3.1.0
|
||||||
|
|
||||||
|
p-try@2.2.0: {}
|
||||||
|
|
||||||
path-browserify@1.0.1: {}
|
path-browserify@1.0.1: {}
|
||||||
|
|
||||||
path-exists@4.0.0: {}
|
path-exists@4.0.0: {}
|
||||||
|
|
@ -4255,6 +4412,8 @@ snapshots:
|
||||||
exsolve: 1.0.8
|
exsolve: 1.0.8
|
||||||
pathe: 2.0.3
|
pathe: 2.0.3
|
||||||
|
|
||||||
|
pngjs@5.0.0: {}
|
||||||
|
|
||||||
postcss-selector-parser@7.1.1:
|
postcss-selector-parser@7.1.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
cssesc: 3.0.0
|
cssesc: 3.0.0
|
||||||
|
|
@ -4278,6 +4437,12 @@ snapshots:
|
||||||
|
|
||||||
punycode@2.3.1: {}
|
punycode@2.3.1: {}
|
||||||
|
|
||||||
|
qrcode@1.5.4:
|
||||||
|
dependencies:
|
||||||
|
dijkstrajs: 1.0.3
|
||||||
|
pngjs: 5.0.0
|
||||||
|
yargs: 15.4.1
|
||||||
|
|
||||||
quansync@0.2.11: {}
|
quansync@0.2.11: {}
|
||||||
|
|
||||||
queue-microtask@1.2.3: {}
|
queue-microtask@1.2.3: {}
|
||||||
|
|
@ -4291,6 +4456,10 @@ snapshots:
|
||||||
|
|
||||||
readdirp@5.0.0: {}
|
readdirp@5.0.0: {}
|
||||||
|
|
||||||
|
require-directory@2.1.1: {}
|
||||||
|
|
||||||
|
require-main-filename@2.0.0: {}
|
||||||
|
|
||||||
reusify@1.1.0: {}
|
reusify@1.1.0: {}
|
||||||
|
|
||||||
rfdc@1.4.1: {}
|
rfdc@1.4.1: {}
|
||||||
|
|
@ -4350,6 +4519,8 @@ snapshots:
|
||||||
|
|
||||||
semver@7.7.4: {}
|
semver@7.7.4: {}
|
||||||
|
|
||||||
|
set-blocking@2.0.0: {}
|
||||||
|
|
||||||
shebang-command@2.0.0:
|
shebang-command@2.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
shebang-regex: 3.0.0
|
shebang-regex: 3.0.0
|
||||||
|
|
@ -4387,6 +4558,16 @@ snapshots:
|
||||||
|
|
||||||
ssr-window@3.0.0: {}
|
ssr-window@3.0.0: {}
|
||||||
|
|
||||||
|
string-width@4.2.3:
|
||||||
|
dependencies:
|
||||||
|
emoji-regex: 8.0.0
|
||||||
|
is-fullwidth-code-point: 3.0.0
|
||||||
|
strip-ansi: 6.0.1
|
||||||
|
|
||||||
|
strip-ansi@6.0.1:
|
||||||
|
dependencies:
|
||||||
|
ansi-regex: 5.0.1
|
||||||
|
|
||||||
strip-literal@3.1.0:
|
strip-literal@3.1.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
js-tokens: 9.0.1
|
js-tokens: 9.0.1
|
||||||
|
|
@ -4635,6 +4816,8 @@ snapshots:
|
||||||
|
|
||||||
webpack-virtual-modules@0.6.2: {}
|
webpack-virtual-modules@0.6.2: {}
|
||||||
|
|
||||||
|
which-module@2.0.1: {}
|
||||||
|
|
||||||
which@2.0.2:
|
which@2.0.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
isexe: 2.0.0
|
isexe: 2.0.0
|
||||||
|
|
@ -4651,6 +4834,12 @@ snapshots:
|
||||||
|
|
||||||
word@0.3.0: {}
|
word@0.3.0: {}
|
||||||
|
|
||||||
|
wrap-ansi@6.2.0:
|
||||||
|
dependencies:
|
||||||
|
ansi-styles: 4.3.0
|
||||||
|
string-width: 4.2.3
|
||||||
|
strip-ansi: 6.0.1
|
||||||
|
|
||||||
wsl-utils@0.1.0:
|
wsl-utils@0.1.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
is-wsl: 3.1.1
|
is-wsl: 3.1.1
|
||||||
|
|
@ -4667,8 +4856,29 @@ snapshots:
|
||||||
|
|
||||||
xml-name-validator@4.0.0: {}
|
xml-name-validator@4.0.0: {}
|
||||||
|
|
||||||
|
y18n@4.0.3: {}
|
||||||
|
|
||||||
yallist@3.1.1: {}
|
yallist@3.1.1: {}
|
||||||
|
|
||||||
yaml@2.8.2: {}
|
yaml@2.8.2: {}
|
||||||
|
|
||||||
|
yargs-parser@18.1.3:
|
||||||
|
dependencies:
|
||||||
|
camelcase: 5.3.1
|
||||||
|
decamelize: 1.2.0
|
||||||
|
|
||||||
|
yargs@15.4.1:
|
||||||
|
dependencies:
|
||||||
|
cliui: 6.0.0
|
||||||
|
decamelize: 1.2.0
|
||||||
|
find-up: 4.1.0
|
||||||
|
get-caller-file: 2.0.5
|
||||||
|
require-directory: 2.1.1
|
||||||
|
require-main-filename: 2.0.0
|
||||||
|
set-blocking: 2.0.0
|
||||||
|
string-width: 4.2.3
|
||||||
|
which-module: 2.0.1
|
||||||
|
y18n: 4.0.3
|
||||||
|
yargs-parser: 18.1.3
|
||||||
|
|
||||||
yocto-queue@0.1.0: {}
|
yocto-queue@0.1.0: {}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
allowBuilds:
|
||||||
|
'@parcel/watcher': set this to true or false
|
||||||
|
es5-ext: set this to true or false
|
||||||
|
esbuild: set this to true or false
|
||||||
|
vue-demi: set this to true or false
|
||||||
|
|
@ -30,7 +30,7 @@ export async function bindEmailApi(data: BindEmailParams): Promise<void> {
|
||||||
|
|
||||||
// 修改用户名
|
// 修改用户名
|
||||||
export async function editUsernameApi(data: EditUsernameParams): Promise<void> {
|
export async function editUsernameApi(data: EditUsernameParams): Promise<void> {
|
||||||
return request.post('/user/editUser', data);
|
return request.post('/user/editUserName', data);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 验证码修改密码(统一接口)
|
// 验证码修改密码(统一接口)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,65 @@
|
||||||
|
<template>
|
||||||
|
<div class="breadcrumb-container">
|
||||||
|
<el-breadcrumb separator="/">
|
||||||
|
<el-breadcrumb-item
|
||||||
|
v-for="(item, index) in breadcrumbList"
|
||||||
|
:key="index"
|
||||||
|
:to="item.path"
|
||||||
|
>
|
||||||
|
{{ item.title }}
|
||||||
|
</el-breadcrumb-item>
|
||||||
|
</el-breadcrumb>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useTabsStore } from '@/stores/modules/tabs'
|
||||||
|
|
||||||
|
interface BreadcrumbItem {
|
||||||
|
title: string
|
||||||
|
path: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const tabsStore = useTabsStore()
|
||||||
|
|
||||||
|
// 从 tabs store 获取当前激活标签页的面包屑
|
||||||
|
const breadcrumbList = computed<BreadcrumbItem[]>(() => tabsStore.currentBreadcrumbs)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.breadcrumb-container {
|
||||||
|
padding: 12px 16px;
|
||||||
|
background: #fff;
|
||||||
|
border-bottom: 1px solid var(--el-border-color-light);
|
||||||
|
|
||||||
|
:deep(.el-breadcrumb) {
|
||||||
|
font-size: 14px;
|
||||||
|
|
||||||
|
.el-breadcrumb__item {
|
||||||
|
.el-breadcrumb__inner {
|
||||||
|
color: #606266;
|
||||||
|
font-weight: normal;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: var(--el-color-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-link {
|
||||||
|
color: #606266;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
.el-breadcrumb__inner {
|
||||||
|
color: #909399;
|
||||||
|
cursor: default;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: #909399;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -1,116 +1,242 @@
|
||||||
<template>
|
<template>
|
||||||
<header>
|
<header class="layout-header">
|
||||||
<div class="logo"></div>
|
<!-- 左侧:Logo 和系统名称 -->
|
||||||
|
<div class="header-left">
|
||||||
|
<div class="logo">
|
||||||
|
<img src="@/assets/images/logo.webp" alt="logo" />
|
||||||
|
<span class="system-name">Admin System</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 右侧:功能按钮和用户信息 -->
|
||||||
|
<div class="header-right">
|
||||||
|
<!-- 全屏 -->
|
||||||
|
<el-tooltip :content="isFullscreen ? '退出全屏' : '全屏'">
|
||||||
|
<el-button :icon="isFullscreen ? Crop : FullScreen" circle @click="toggleFullscreen" />
|
||||||
|
</el-tooltip>
|
||||||
|
|
||||||
|
<!-- 语言选择 -->
|
||||||
|
<LanguageSelect v-model="languageStore.lang" @change="languageStore.changeLang" />
|
||||||
|
|
||||||
|
<!-- 用户信息下拉菜单 -->
|
||||||
|
<el-dropdown @command="handleCommand" class="user-dropdown">
|
||||||
<div class="user-info">
|
<div class="user-info">
|
||||||
<LanguageSelect v-model="languageStore.lang" @change="languageStore.changeLang" />
|
<el-avatar :size="32" :src="userAvatar" class="user-avatar">
|
||||||
<el-dropdown @command="handleCommand">
|
<el-icon><User /></el-icon>
|
||||||
<el-button class="user-button">
|
</el-avatar>
|
||||||
{{ activeUserName }}<el-icon class="el-icon--right">
|
<span class="username">{{ activeUserName }}</span>
|
||||||
<ArrowDownBold />
|
<el-icon class="dropdown-icon"><ArrowDown /></el-icon>
|
||||||
</el-icon>
|
|
||||||
</el-button>
|
|
||||||
<template #dropdown>
|
|
||||||
<el-dropdown-menu>
|
|
||||||
<el-dropdown-item v-for="item in dropdownItems" :key="item.command" :command="item.command">
|
|
||||||
{{ item.label }}
|
|
||||||
</el-dropdown-item>
|
|
||||||
</el-dropdown-menu>
|
|
||||||
</template>
|
|
||||||
</el-dropdown>
|
|
||||||
</div>
|
</div>
|
||||||
</header>
|
<template #dropdown>
|
||||||
|
<el-dropdown-menu>
|
||||||
|
<el-dropdown-item command="profile">
|
||||||
|
<el-icon><User /></el-icon>
|
||||||
|
个人中心
|
||||||
|
</el-dropdown-item>
|
||||||
|
<el-dropdown-item command="password">
|
||||||
|
<el-icon><Lock /></el-icon>
|
||||||
|
修改密码
|
||||||
|
</el-dropdown-item>
|
||||||
|
<el-dropdown-item divided command="logout">
|
||||||
|
<el-icon><SwitchButton /></el-icon>
|
||||||
|
退出登录
|
||||||
|
</el-dropdown-item>
|
||||||
|
</el-dropdown-menu>
|
||||||
|
</template>
|
||||||
|
</el-dropdown>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ArrowDownBold } from '@element-plus/icons-vue'
|
import {
|
||||||
//引入语言选择组件和导入Pinia状态
|
Bell,
|
||||||
import LanguageSelect from '@/components/LanguageSelect/index.vue'
|
Sunny,
|
||||||
import { useLanguageStore } from '@/stores/modules/language'
|
Moon,
|
||||||
|
FullScreen,
|
||||||
//引入store和storage
|
Crop,
|
||||||
|
User,
|
||||||
|
Lock,
|
||||||
|
SwitchButton,
|
||||||
|
ArrowDown
|
||||||
|
} from '@element-plus/icons-vue'
|
||||||
import { useUserStore } from '@/stores/modules/user'
|
import { useUserStore } from '@/stores/modules/user'
|
||||||
|
import { useLanguageStore } from '@/stores/modules/language'
|
||||||
|
import LanguageSelect from '@/components/LanguageSelect/index.vue'
|
||||||
import { getStorage } from '@/utils/storage'
|
import { getStorage } from '@/utils/storage'
|
||||||
|
|
||||||
//定义路由/Store实例
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
const languageStore = useLanguageStore()
|
const languageStore = useLanguageStore()
|
||||||
//获取用户信息
|
|
||||||
|
// 用户信息
|
||||||
const userInfo = getStorage<any>('userInfo')
|
const userInfo = getStorage<any>('userInfo')
|
||||||
|
const activeUserName = ref(userInfo?.username || 'Admin')
|
||||||
|
const userAvatar = ref(userInfo?.avatar || '')
|
||||||
|
const unreadCount = ref(3) // 未读消息数量
|
||||||
|
|
||||||
//用户操作实例
|
// 全屏相关
|
||||||
const activeUserName = ref(userInfo?.username || '')
|
const isFullscreen = ref(false)
|
||||||
const activeItem = ref('currentUser')
|
const toggleFullscreen = () => {
|
||||||
const dropdownItems = [
|
if (!document.fullscreenElement) {
|
||||||
// { label: '切换账户', command: 'account' },
|
document.documentElement.requestFullscreen()
|
||||||
{ label: '修改密码', command: 'password' },
|
isFullscreen.value = true
|
||||||
{ label: '退出登录', command: 'logout' }
|
} else {
|
||||||
]
|
if (document.exitFullscreen) {
|
||||||
|
document.exitFullscreen()
|
||||||
|
isFullscreen.value = false
|
||||||
const handleAccount = async () => {
|
}
|
||||||
userStore.switchAccount()
|
}
|
||||||
await router.push('/user/login')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleChangePassword = () => {
|
// 监听全屏变化
|
||||||
router.push('/user/change-password')
|
onMounted(() => {
|
||||||
|
document.addEventListener('fullscreenchange', () => {
|
||||||
|
isFullscreen.value = !!document.fullscreenElement
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// 消息通知
|
||||||
|
const handleNotification = () => {
|
||||||
|
ElMessage.info('暂无新消息')
|
||||||
|
unreadCount.value = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 用户操作
|
||||||
|
const handleCommand = (command: string) => {
|
||||||
|
switch (command) {
|
||||||
|
case 'profile':
|
||||||
|
router.push('/profile/personal-center')
|
||||||
|
break
|
||||||
|
case 'password':
|
||||||
|
router.push('/user/change-password')
|
||||||
|
break
|
||||||
|
case 'logout':
|
||||||
|
handleLogout()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 退出登录
|
||||||
const handleLogout = () => {
|
const handleLogout = () => {
|
||||||
// 示例:退出登录逻辑
|
ElMessageBox.confirm('确定要退出登录吗?', '提示', {
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning'
|
||||||
|
}).then(() => {
|
||||||
const deviceNo = getStorage('device_no') as string
|
const deviceNo = getStorage('device_no') as string
|
||||||
userStore.logout({ device_no: String(deviceNo) })
|
userStore.logout({ device_no: String(deviceNo) })
|
||||||
}
|
}).catch(() => {
|
||||||
|
// 取消退出
|
||||||
// 处理菜单项点击
|
})
|
||||||
const handleCommand = (command: string) => {
|
|
||||||
activeItem.value = command
|
|
||||||
// 不同指令的业务逻辑
|
|
||||||
switch (command) {
|
|
||||||
case 'currentUser':
|
|
||||||
// 点击当前用户:无操作(仅选中)
|
|
||||||
break
|
|
||||||
case 'account':
|
|
||||||
// 这里添加切换账户的逻辑(如弹窗/路由跳转)
|
|
||||||
handleAccount()
|
|
||||||
break
|
|
||||||
case 'password':
|
|
||||||
// 示例:跳转到修改密码页
|
|
||||||
handleChangePassword()
|
|
||||||
break
|
|
||||||
case 'logout':
|
|
||||||
// 示例:退出登录逻辑
|
|
||||||
handleLogout()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
header {
|
.layout-header {
|
||||||
height: 60px;
|
height: 60px;
|
||||||
border-bottom: solid 1px var(--el-menu-border-color);
|
background: #fff;
|
||||||
padding: 0 10px;
|
border-bottom: 1px solid var(--el-border-color-light);
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
padding: 0 20px;
|
||||||
|
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.05);
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 1000;
|
||||||
|
|
||||||
.user-info {
|
.header-left {
|
||||||
.el-select {
|
display: flex;
|
||||||
margin-right: 10px;
|
align-items: center;
|
||||||
}
|
gap: 20px;
|
||||||
.el-dropdown {
|
|
||||||
.user-button {
|
.logo {
|
||||||
border: none;
|
display: flex;
|
||||||
&:focus-visible {
|
align-items: center;
|
||||||
outline: none;
|
gap: 10px;
|
||||||
}
|
|
||||||
&:hover {
|
img {
|
||||||
background-color: transparent;
|
height: 32px;
|
||||||
}
|
width: auto;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
.system-name {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--el-text-color-primary);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-right {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
|
||||||
|
.notification-badge {
|
||||||
|
:deep(.el-badge__content) {
|
||||||
|
transform: translateY(-50%) translateX(50%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-button {
|
||||||
|
border: none;
|
||||||
|
background: transparent;
|
||||||
|
padding: 8px;
|
||||||
|
color: var(--el-text-color-regular);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: var(--el-fill-color-light);
|
||||||
|
color: var(--el-color-primary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-dropdown {
|
||||||
|
margin-left: 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
.user-info {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 4px 8px;
|
||||||
|
border-radius: 4px;
|
||||||
|
transition: background 0.3s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: var(--el-fill-color-light);
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-avatar {
|
||||||
|
background: var(--el-color-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.username {
|
||||||
|
font-size: 14px;
|
||||||
|
color: var(--el-text-color-primary);
|
||||||
|
max-width: 100px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-icon {
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--el-text-color-regular);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 暗色模式适配
|
||||||
|
:deep(.dark) {
|
||||||
|
.layout-header {
|
||||||
|
background: var(--el-bg-color);
|
||||||
|
border-bottom-color: var(--el-border-color-darker);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
@ -1,23 +1,89 @@
|
||||||
<!-- src/components/layout/Layout.vue -->
|
<template>
|
||||||
<template class="layout">
|
<section class="layout">
|
||||||
<section class="layout">
|
<!-- 顶部导航栏:固定在顶部 -->
|
||||||
<!-- 左侧菜单:Sidebar -->
|
<Header />
|
||||||
<Sidebar />
|
|
||||||
|
|
||||||
<!-- 标红区域:MainContent(主内容区) -->
|
<!-- 主体内容区域 -->
|
||||||
<section class="main-container">
|
<section class="main-container">
|
||||||
<!-- Header -->
|
<!-- 左侧侧边菜单:固定在左侧 -->
|
||||||
<Header />
|
<Sidebar />
|
||||||
|
|
||||||
<!-- 内容路由视图 -->
|
<!-- 右侧内容区:面包屑 + 页签 + 主体内容 -->
|
||||||
<main>
|
<section class="content-container">
|
||||||
<router-view/>
|
<!-- 面包屑导航 -->
|
||||||
</main>
|
<Breadcrumb />
|
||||||
</section>
|
|
||||||
|
<!-- 页签标签栏 -->
|
||||||
|
<Tabs />
|
||||||
|
|
||||||
|
<!-- 主体内容区 -->
|
||||||
|
<main class="main-content">
|
||||||
|
<router-view v-slot="{ Component }">
|
||||||
|
<transition name="fade-transform" mode="out-in">
|
||||||
|
<KeepAlive>
|
||||||
|
<component :is="Component" :key="route.path" />
|
||||||
|
</KeepAlive>
|
||||||
|
</transition>
|
||||||
|
</router-view>
|
||||||
|
</main>
|
||||||
|
</section>
|
||||||
</section>
|
</section>
|
||||||
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import Sidebar from './Sidebar.vue'
|
|
||||||
import Header from './Header.vue'
|
import Header from './Header.vue'
|
||||||
|
import Sidebar from './Sidebar.vue'
|
||||||
|
import Breadcrumb from './Breadcrumb.vue'
|
||||||
|
import Tabs from './Tabs.vue'
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.layout {
|
||||||
|
width: 100%;
|
||||||
|
height: 100vh;
|
||||||
|
overflow: hidden;
|
||||||
|
background: var(--el-bg-color-page);
|
||||||
|
|
||||||
|
.main-container {
|
||||||
|
display: flex;
|
||||||
|
height: calc(100vh - 60px);
|
||||||
|
margin-top: 60px;
|
||||||
|
|
||||||
|
.content-container {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
margin-left: 200px;
|
||||||
|
|
||||||
|
.main-content {
|
||||||
|
flex: 1;
|
||||||
|
padding: 16px;
|
||||||
|
overflow-y: auto;
|
||||||
|
overflow-x: hidden;
|
||||||
|
background: var(--el-bg-color-page);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 页面切换动画
|
||||||
|
.fade-transform-enter-active,
|
||||||
|
.fade-transform-leave-active {
|
||||||
|
transition: all 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fade-transform-enter-from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateX(30px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.fade-transform-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateX(-30px);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,34 +1,34 @@
|
||||||
<template>
|
<template>
|
||||||
<aside>
|
<aside class="sidebar">
|
||||||
<div class="sidebar-header">
|
|
||||||
<div class="logo">
|
|
||||||
<img src="@/assets/images/logo.webp" alt="logo" :router="true" />
|
|
||||||
<span>Admin System</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 菜单区域 -->
|
<!-- 菜单区域 -->
|
||||||
<el-menu class="menu" :unique-opened="true" :default-active="activeMenu" router>
|
<el-menu
|
||||||
|
class="sidebar-menu"
|
||||||
|
:unique-opened="true"
|
||||||
|
:default-active="activeMenu"
|
||||||
|
router
|
||||||
|
>
|
||||||
<template v-for="menu in menuList" :key="menu.id">
|
<template v-for="menu in menuList" :key="menu.id">
|
||||||
<!-- 无子菜单 -->
|
<!-- 无子菜单 -->
|
||||||
<el-menu-item v-if="!menu.children || menu.children.length === 0" :index="menu.path">
|
<el-menu-item v-if="!menu.children || menu.children.length === 0" :index="menu.path">
|
||||||
<el-icon>
|
<el-icon v-if="menu.icon">
|
||||||
<component :is="iconMap[menu.icon]" />
|
<component :is="iconMap[menu.icon]" />
|
||||||
</el-icon>
|
</el-icon>
|
||||||
<template #title>{{ menu.label }}</template>
|
<template #title>{{ menu.label }}</template>
|
||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
|
|
||||||
|
<!-- 有子菜单 -->
|
||||||
<el-sub-menu v-else :index="menu.path">
|
<el-sub-menu v-else :index="menu.path">
|
||||||
<template #title>
|
<template #title>
|
||||||
<el-icon>
|
<el-icon v-if="menu.icon">
|
||||||
<component :is="iconMap[menu.icon]" />
|
<component :is="iconMap[menu.icon]" />
|
||||||
</el-icon>
|
</el-icon>
|
||||||
<span>{{ menu.label }}</span>
|
<span>{{ menu.label }}</span>
|
||||||
</template>
|
</template>
|
||||||
<el-menu-item v-for="subMenu in menu.children" :key="subMenu.id" :index="subMenu.path">
|
<el-menu-item
|
||||||
<!-- <el-icon v-if="subMenu.icon">-->
|
v-for="subMenu in menu.children"
|
||||||
<!-- <component :is="iconMap[subMenu.icon]" />-->
|
:key="subMenu.id"
|
||||||
<!-- </el-icon>-->
|
:index="subMenu.path"
|
||||||
|
>
|
||||||
<template #title>{{ subMenu.label }}</template>
|
<template #title>{{ subMenu.label }}</template>
|
||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
</el-sub-menu>
|
</el-sub-menu>
|
||||||
|
|
@ -48,25 +48,22 @@ import {
|
||||||
WarningFilled,
|
WarningFilled,
|
||||||
Tools,
|
Tools,
|
||||||
} from '@element-plus/icons-vue'
|
} from '@element-plus/icons-vue'
|
||||||
|
|
||||||
//获取格式化后的菜单列表
|
|
||||||
import { useUserStore } from '@/stores/modules/user'
|
import { useUserStore } from '@/stores/modules/user'
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
const menuList = ref<any[]>([])
|
|
||||||
|
|
||||||
// 计算当前激活的菜单 index(取路由 fullPath 作为激活标识)
|
// 计算当前激活的菜单 index
|
||||||
const activeMenu = computed(() => {
|
const activeMenu = computed(() => {
|
||||||
return route.fullPath // 直接使用完整路径,和菜单 path 保持一致
|
return route.fullPath
|
||||||
})
|
|
||||||
// 组件挂载时异步加载菜单
|
|
||||||
onMounted(async () => {
|
|
||||||
menuList.value = userStore.sideMenu || []
|
|
||||||
console.log('menuList.value', menuList.value)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
//图标映射表
|
// 获取完整菜单列表
|
||||||
|
const menuList = computed(() => {
|
||||||
|
return userStore.sideMenu || []
|
||||||
|
})
|
||||||
|
|
||||||
|
// 图标映射表
|
||||||
const iconMap: Record<string, any> = {
|
const iconMap: Record<string, any> = {
|
||||||
HomeFilled,
|
HomeFilled,
|
||||||
List,
|
List,
|
||||||
|
|
@ -77,36 +74,64 @@ const iconMap: Record<string, any> = {
|
||||||
WarningFilled,
|
WarningFilled,
|
||||||
Tools,
|
Tools,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
aside {
|
.sidebar {
|
||||||
.sidebar-header {
|
position: fixed;
|
||||||
height: 60px;
|
top: 60px;
|
||||||
border-bottom: solid 1px var(--el-menu-border-color);
|
left: 0;
|
||||||
padding: 0 10px;
|
bottom: 0;
|
||||||
display: flex;
|
width: 200px;
|
||||||
justify-content: space-between;
|
background: var(--el-bg-color-page);
|
||||||
align-items: center;
|
border-right: 1px solid var(--el-border-color-light);
|
||||||
|
overflow-y: auto;
|
||||||
|
overflow-x: hidden;
|
||||||
|
z-index: 999;
|
||||||
|
|
||||||
.logo {
|
.sidebar-menu {
|
||||||
display: flex;
|
height: 100%;
|
||||||
align-items: center;
|
border: none;
|
||||||
|
background: transparent;
|
||||||
|
|
||||||
img {
|
:deep(.el-menu-item) {
|
||||||
width: 100px;
|
height: 50px;
|
||||||
|
line-height: 50px;
|
||||||
|
|
||||||
|
&.is-active {
|
||||||
|
background: var(--el-color-primary-light-9);
|
||||||
|
color: var(--el-color-primary);
|
||||||
|
border-right: 3px solid var(--el-color-primary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-sub-menu) {
|
||||||
|
.el-sub-menu__title {
|
||||||
|
height: 50px;
|
||||||
|
line-height: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-active {
|
||||||
|
> .el-sub-menu__title {
|
||||||
|
color: var(--el-color-primary);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.menu {
|
// 暗色模式适配
|
||||||
height: 100%;
|
:deep(.dark) {
|
||||||
border: none;
|
.sidebar {
|
||||||
|
background: var(--el-bg-color);
|
||||||
|
border-right-color: var(--el-border-color-darker);
|
||||||
|
|
||||||
:deep(.el-menu-item.is-active) {
|
.sidebar-menu {
|
||||||
background-color: var(--el-menu-hover-bg-color);
|
:deep(.el-menu-item) {
|
||||||
|
&.is-active {
|
||||||
|
background: var(--el-color-primary-dark-2);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,411 @@
|
||||||
|
<template>
|
||||||
|
<div class="tabs-container">
|
||||||
|
<el-tabs
|
||||||
|
v-model="tabsStore.activeTab"
|
||||||
|
type="card"
|
||||||
|
closable
|
||||||
|
@tab-click="handleTabClick"
|
||||||
|
@tab-remove="handleTabRemove"
|
||||||
|
>
|
||||||
|
<el-tab-pane
|
||||||
|
v-for="(tab, index) in tabsStore.tabs"
|
||||||
|
:key="tab.path"
|
||||||
|
:label="tab.title"
|
||||||
|
:name="tab.path"
|
||||||
|
>
|
||||||
|
<template #label>
|
||||||
|
<div
|
||||||
|
class="tab-label"
|
||||||
|
:class="{ 'is-context-active': contextMenuPath === tab.path }"
|
||||||
|
draggable="true"
|
||||||
|
@dragstart="handleDragStart($event, index)"
|
||||||
|
@dragover.prevent="handleDragOver($event, index)"
|
||||||
|
@drop="handleDrop($event, index)"
|
||||||
|
@dragend="handleDragEnd"
|
||||||
|
@contextmenu.prevent="handleContextMenu($event, tab.path)"
|
||||||
|
>
|
||||||
|
<span class="tab-text">{{ tab.title }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
|
|
||||||
|
<!-- 右键菜单 -->
|
||||||
|
<el-dropdown
|
||||||
|
popper-class="el-droMenu"
|
||||||
|
:popper-style="style"
|
||||||
|
ref="contextMenuRef"
|
||||||
|
trigger="contextmenu"
|
||||||
|
@command="handleContextMenuCommand"
|
||||||
|
@visible-change="handleMenuVisibleChange"
|
||||||
|
>
|
||||||
|
<span class="context-menu-trigger"></span>
|
||||||
|
<template #dropdown>
|
||||||
|
<el-dropdown-menu>
|
||||||
|
<el-dropdown-item command="refresh">刷新当前页</el-dropdown-item>
|
||||||
|
<el-dropdown-item command="close">关闭当前</el-dropdown-item>
|
||||||
|
<el-dropdown-item command="closeOther">关闭其他</el-dropdown-item>
|
||||||
|
<el-dropdown-item command="closeLeft">关闭左侧</el-dropdown-item>
|
||||||
|
<el-dropdown-item command="closeRight">关闭右侧</el-dropdown-item>
|
||||||
|
<el-dropdown-item command="closeAll" divided>关闭全部</el-dropdown-item>
|
||||||
|
</el-dropdown-menu>
|
||||||
|
</template>
|
||||||
|
</el-dropdown>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useTabsStore } from '@/stores/modules/tabs'
|
||||||
|
import type { TabItem } from '@/stores/modules/tabs'
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
const route = useRoute()
|
||||||
|
const tabsStore = useTabsStore()
|
||||||
|
const contextMenuRef = ref()
|
||||||
|
|
||||||
|
// 当前右键点击的页签路径
|
||||||
|
let contextMenuPath = ''
|
||||||
|
|
||||||
|
// 拖拽相关
|
||||||
|
let dragIndex: number | null = null
|
||||||
|
let dropIndex: number | null = null
|
||||||
|
|
||||||
|
// 组件挂载后,检查是否需要跳转到保存的激活页面
|
||||||
|
onMounted(() => {
|
||||||
|
// 如果当前路由不是保存的激活页面,则跳转
|
||||||
|
if (tabsStore.activeTab && tabsStore.activeTab !== route.path) {
|
||||||
|
const targetTab = tabsStore.tabs.find(item => item.path === tabsStore.activeTab)
|
||||||
|
if (targetTab) {
|
||||||
|
router.replace({ path: targetTab.path, query: targetTab.query })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 监听路由变化,自动添加页签
|
||||||
|
watch(
|
||||||
|
() => route.fullPath,
|
||||||
|
(newPath) => {
|
||||||
|
if (route.meta?.title && !route.meta?.isAuthPage) {
|
||||||
|
tabsStore.addTab({
|
||||||
|
title: route.meta.title as string,
|
||||||
|
path: route.path,
|
||||||
|
query: route.query
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ immediate: true }
|
||||||
|
)
|
||||||
|
|
||||||
|
// 页签点击
|
||||||
|
const handleTabClick = (tab: any) => {
|
||||||
|
const targetTab = tabsStore.tabs.find(item => item.path === tab.paneName)
|
||||||
|
if (targetTab) {
|
||||||
|
router.push({ path: targetTab.path, query: targetTab.query })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 页签关闭
|
||||||
|
const handleTabRemove = (path: string) => {
|
||||||
|
tabsStore.removeTab(path)
|
||||||
|
// 如果关闭的是当前页签,跳转到新的激活页签
|
||||||
|
if (path === route.path && tabsStore.activeTab) {
|
||||||
|
const targetTab = tabsStore.tabs.find(item => item.path === tabsStore.activeTab)
|
||||||
|
if (targetTab) {
|
||||||
|
router.push({ path: targetTab.path, query: targetTab.query })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 右键菜单命令处理
|
||||||
|
const handleContextMenuCommand = (command: string) => {
|
||||||
|
const currentPath = contextMenuPath || tabsStore.activeTab
|
||||||
|
|
||||||
|
switch (command) {
|
||||||
|
case 'refresh':
|
||||||
|
router.go(0)
|
||||||
|
break
|
||||||
|
case 'close':
|
||||||
|
if (currentPath) {
|
||||||
|
handleTabRemove(currentPath)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 'closeOther':
|
||||||
|
if (currentPath) {
|
||||||
|
tabsStore.closeOtherTabs(currentPath)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 'closeLeft':
|
||||||
|
if (currentPath) {
|
||||||
|
tabsStore.closeLeftTabs(currentPath)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 'closeRight':
|
||||||
|
if (currentPath) {
|
||||||
|
tabsStore.closeRightTabs(currentPath)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 'closeAll':
|
||||||
|
tabsStore.closeAllTabs()
|
||||||
|
router.push('/dashboard')
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理右键菜单显示/隐藏
|
||||||
|
const handleMenuVisibleChange = (visible: boolean) => {
|
||||||
|
if (!visible) {
|
||||||
|
contextMenuPath = ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const style = ref('')
|
||||||
|
// 处理右键菜单点击
|
||||||
|
const handleContextMenu = (e: MouseEvent, path: string) => {
|
||||||
|
contextMenuPath = path
|
||||||
|
// 右键时激活该标签并跳转
|
||||||
|
tabsStore.setActiveTab(path)
|
||||||
|
const targetTab = tabsStore.tabs.find(item => item.path === path)
|
||||||
|
if (targetTab && path !== route.path) {
|
||||||
|
router.push({ path: targetTab.path, query: targetTab.query })
|
||||||
|
}
|
||||||
|
// 手动触发 dropdown
|
||||||
|
const dropdown = contextMenuRef.value
|
||||||
|
if (dropdown) {
|
||||||
|
// 获取 dropdown 实例
|
||||||
|
const dropdownInstance = dropdown
|
||||||
|
// 计算菜单位置
|
||||||
|
const x = e.clientX
|
||||||
|
const y = e.clientY
|
||||||
|
// 使用 Element Plus 的内部方法显示菜单
|
||||||
|
dropdownInstance?.handleOpen()
|
||||||
|
// 设置菜单位置
|
||||||
|
nextTick().then(() => {
|
||||||
|
const menu = document.querySelector('.el-droMenu')
|
||||||
|
if (menu) {
|
||||||
|
style.value = `position: fixed; z-index: 9999; left: ${x}px; top: ${y}px;`
|
||||||
|
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 拖拽开始
|
||||||
|
const handleDragStart = (e: DragEvent, index: number) => {
|
||||||
|
dragIndex = index
|
||||||
|
if (e.dataTransfer) {
|
||||||
|
e.dataTransfer.effectAllowed = 'move'
|
||||||
|
e.dataTransfer.setData('text/plain', index.toString())
|
||||||
|
}
|
||||||
|
// 添加拖拽样式
|
||||||
|
const target = e.target as HTMLElement
|
||||||
|
target.classList.add('dragging')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 拖拽经过
|
||||||
|
const handleDragOver = (e: DragEvent, index: number) => {
|
||||||
|
e.preventDefault()
|
||||||
|
if (e.dataTransfer) {
|
||||||
|
e.dataTransfer.dropEffect = 'move'
|
||||||
|
}
|
||||||
|
dropIndex = index
|
||||||
|
}
|
||||||
|
|
||||||
|
// 拖拽结束
|
||||||
|
const handleDragEnd = (e: DragEvent) => {
|
||||||
|
const target = e.target as HTMLElement
|
||||||
|
target.classList.remove('dragging')
|
||||||
|
dragIndex = null
|
||||||
|
dropIndex = null
|
||||||
|
}
|
||||||
|
|
||||||
|
// 拖拽放置
|
||||||
|
const handleDrop = (e: DragEvent, index: number) => {
|
||||||
|
e.preventDefault()
|
||||||
|
if (dragIndex === null || dragIndex === index) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重新排序 tabs
|
||||||
|
const newTabs = [...tabsStore.tabs]
|
||||||
|
const [draggedTab] = newTabs.splice(dragIndex, 1)
|
||||||
|
if (draggedTab) {
|
||||||
|
newTabs.splice(index, 0, draggedTab)
|
||||||
|
// 更新 store
|
||||||
|
tabsStore.setTabs(newTabs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 移除拖拽样式
|
||||||
|
const target = e.target as HTMLElement
|
||||||
|
target.classList.remove('dragging')
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.tabs-container {
|
||||||
|
background: linear-gradient(180deg, #ffffff 0%, #fafbfc 100%);
|
||||||
|
border-bottom: 1px solid var(--el-border-color-light);
|
||||||
|
padding: 8px 20px 0;
|
||||||
|
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
|
||||||
|
position: relative;
|
||||||
|
z-index: 10;
|
||||||
|
|
||||||
|
:deep(.el-tabs) {
|
||||||
|
.el-tabs__header {
|
||||||
|
margin: 0;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-tabs__nav {
|
||||||
|
border: none !important;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-tabs__item {
|
||||||
|
border: 1px solid var(--el-border-color-lighter) !important;
|
||||||
|
border-bottom: none !important;
|
||||||
|
margin-right: 0;
|
||||||
|
border-radius: 8px 8px 0 0;
|
||||||
|
background: linear-gradient(180deg, #f8f9fb 0%, #f0f2f5 100%);
|
||||||
|
color: #5a5e66;
|
||||||
|
height: 38px;
|
||||||
|
line-height: 38px;
|
||||||
|
padding: 0 18px;
|
||||||
|
font-size: 13px;
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
// 顶部渐变装饰
|
||||||
|
&::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
height: 3px;
|
||||||
|
background: linear-gradient(90deg, var(--el-color-primary), var(--el-color-primary-light-3));
|
||||||
|
transform: scaleX(0);
|
||||||
|
transition: transform 0.3s ease;
|
||||||
|
border-radius: 8px 8px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 底部白色边框效果
|
||||||
|
&::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
bottom: -1px;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
height: 2px;
|
||||||
|
background: #fff;
|
||||||
|
transform: scaleX(0);
|
||||||
|
transition: transform 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: var(--el-color-primary);
|
||||||
|
background: linear-gradient(180deg, #fff 0%, #f5f7fa 100%);
|
||||||
|
border-color: var(--el-color-primary-light-6) !important;
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
|
||||||
|
transform: translateY(-2px);
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
transform: scaleX(0.7);
|
||||||
|
}
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
transform: scaleX(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-active,
|
||||||
|
&.is-context-active {
|
||||||
|
background: #fff;
|
||||||
|
color: var(--el-color-primary);
|
||||||
|
// border-bottom: 1px solid #fff !important;
|
||||||
|
border-color: var(--el-color-primary-light-4) !important;
|
||||||
|
box-shadow: 0 4px 16px rgba(var(--el-color-primary-rgb), 0.15);
|
||||||
|
font-weight: 500;
|
||||||
|
z-index: 2;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
transform: scaleX(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
transform: scaleX(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 右键选中时的特殊样式
|
||||||
|
&.is-context-active:not(.is-active) {
|
||||||
|
background: linear-gradient(180deg, #fff 0%, #f0f7ff 100%);
|
||||||
|
border-color: var(--el-color-primary-light-5) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关闭按钮样式
|
||||||
|
.el-icon-close {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
border-radius: 50%;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
font-size: 12px;
|
||||||
|
margin-left: 6px;
|
||||||
|
vertical-align: middle;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: var(--el-color-danger);
|
||||||
|
color: #fff;
|
||||||
|
transform: scale(1.15) rotate(90deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 拖拽样式
|
||||||
|
.tab-label {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
gap: 6px;
|
||||||
|
|
||||||
|
.tab-text {
|
||||||
|
display: inline-block;
|
||||||
|
max-width: 150px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.dragging {
|
||||||
|
opacity: 0.5;
|
||||||
|
cursor: move;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-tabs__nav-wrap::after {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 左右滚动按钮样式
|
||||||
|
.el-tabs__nav-prev,
|
||||||
|
.el-tabs__nav-next {
|
||||||
|
width: 32px;
|
||||||
|
line-height: 38px;
|
||||||
|
color: var(--el-text-color-secondary);
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
border-radius: 4px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: var(--el-color-primary);
|
||||||
|
background: var(--el-fill-color-light);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.context-menu-trigger {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,229 @@
|
||||||
|
import { defineStore } from 'pinia'
|
||||||
|
import { getStorage, setStorage, removeStorage } from '@/utils/storage'
|
||||||
|
import { useUserStore } from './user'
|
||||||
|
|
||||||
|
export interface BreadcrumbItem {
|
||||||
|
title: string
|
||||||
|
path: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TabItem {
|
||||||
|
title: string
|
||||||
|
path: string
|
||||||
|
query?: any
|
||||||
|
breadcrumbs?: BreadcrumbItem[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useTabsStore = defineStore('tabs', () => {
|
||||||
|
const userStore = useUserStore()
|
||||||
|
|
||||||
|
// 从本地存储恢复页签数据
|
||||||
|
const savedTabs = getStorage('tabs')
|
||||||
|
const savedActiveTab = getStorage('activeTab')
|
||||||
|
|
||||||
|
// 验证恢复的数据是否有效
|
||||||
|
const tabs = ref<TabItem[]>(Array.isArray(savedTabs) && savedTabs.length > 0 ? savedTabs : [])
|
||||||
|
const activeTab = ref<string>(
|
||||||
|
typeof savedActiveTab === 'string' &&
|
||||||
|
tabs.value.some(t => t.path === savedActiveTab)
|
||||||
|
? savedActiveTab
|
||||||
|
: '/dashboard'
|
||||||
|
)
|
||||||
|
|
||||||
|
// 如果没有有效的标签页,初始化添加首页
|
||||||
|
if (tabs.value.length === 0) {
|
||||||
|
tabs.value.push({
|
||||||
|
title: '首页',
|
||||||
|
path: '/dashboard'
|
||||||
|
})
|
||||||
|
activeTab.value = '/dashboard'
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从菜单中查找当前路由的面包屑路径
|
||||||
|
*/
|
||||||
|
const findBreadcrumbPath = (path: string): BreadcrumbItem[] => {
|
||||||
|
const list: BreadcrumbItem[] = []
|
||||||
|
|
||||||
|
// 添加首页
|
||||||
|
list.push({
|
||||||
|
title: '首页',
|
||||||
|
path: '/dashboard'
|
||||||
|
})
|
||||||
|
|
||||||
|
// 如果是首页,直接返回
|
||||||
|
if (path === '/dashboard') {
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从菜单中查找当前路由的层级信息
|
||||||
|
const findMenuPath = (menus: any[], targetPath: string, currentPath: any[] = []): any[] | null => {
|
||||||
|
for (const menu of menus) {
|
||||||
|
const menuPath = menu.path || menu.api || `/menu-${menu.id}`
|
||||||
|
const newPath = [...currentPath, menu]
|
||||||
|
|
||||||
|
if (menuPath === targetPath) {
|
||||||
|
return newPath
|
||||||
|
}
|
||||||
|
|
||||||
|
// 兼容 children 和 son 两种子菜单字段名
|
||||||
|
const subMenus = menu.children || menu.son
|
||||||
|
if (subMenus && subMenus.length > 0) {
|
||||||
|
const result = findMenuPath(subMenus, targetPath, newPath)
|
||||||
|
if (result) {
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const menuPath = findMenuPath(userStore.sideMenu, path)
|
||||||
|
console.log('menuPath:', menuPath);
|
||||||
|
|
||||||
|
if (menuPath) {
|
||||||
|
console.log('list:', menuPath)
|
||||||
|
menuPath.forEach((menu: any, index: number) => {
|
||||||
|
// 跳过第一个(首页已添加)
|
||||||
|
if (index === 0 && menu.label === '首页') {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
list.push({
|
||||||
|
title: menu.label,
|
||||||
|
path: menu.path || menu.api || `/menu-${menu.id}`
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
;
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加页签
|
||||||
|
const addTab = (tab: TabItem) => {
|
||||||
|
// 检查是否已存在
|
||||||
|
const existIndex = tabs.value.findIndex(item => item.path === tab.path)
|
||||||
|
// 计算面包屑路径
|
||||||
|
const breadcrumbs = findBreadcrumbPath(tab.path)
|
||||||
|
console.log('aaaaaaaaaaaaa:', breadcrumbs);
|
||||||
|
|
||||||
|
if (existIndex === -1) {
|
||||||
|
// 新标签页,添加到列表
|
||||||
|
tabs.value.push({ ...tab, breadcrumbs })
|
||||||
|
} else {
|
||||||
|
// 已存在的标签页,更新面包屑(确保数据是最新的)
|
||||||
|
const existingTab = tabs.value[existIndex]
|
||||||
|
if (existingTab) {
|
||||||
|
existingTab.breadcrumbs = breadcrumbs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
activeTab.value = tab.path
|
||||||
|
saveTabs()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 移除页签
|
||||||
|
const removeTab = (path: string) => {
|
||||||
|
const index = tabs.value.findIndex(item => item.path === path)
|
||||||
|
if (index !== -1) {
|
||||||
|
tabs.value.splice(index, 1)
|
||||||
|
// 如果移除的是当前激活的页签,则激活前一个或后一个
|
||||||
|
if (activeTab.value === path && tabs.value.length > 0) {
|
||||||
|
const newIndex = Math.max(0, index - 1)
|
||||||
|
const newTab = tabs.value[newIndex]
|
||||||
|
if (newTab) {
|
||||||
|
activeTab.value = newTab.path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
saveTabs()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关闭其他页签
|
||||||
|
const closeOtherTabs = (path: string) => {
|
||||||
|
const currentTab = tabs.value.find(item => item.path === path)
|
||||||
|
if (currentTab) {
|
||||||
|
tabs.value = [currentTab]
|
||||||
|
activeTab.value = path
|
||||||
|
saveTabs()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关闭所有页签
|
||||||
|
const closeAllTabs = () => {
|
||||||
|
// 保留首页
|
||||||
|
tabs.value = [{
|
||||||
|
title: '首页',
|
||||||
|
path: '/dashboard'
|
||||||
|
}]
|
||||||
|
activeTab.value = '/dashboard'
|
||||||
|
saveTabs()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关闭左侧页签
|
||||||
|
const closeLeftTabs = (path: string) => {
|
||||||
|
const index = tabs.value.findIndex(item => item.path === path)
|
||||||
|
if (index > 0) {
|
||||||
|
tabs.value = tabs.value.slice(index)
|
||||||
|
saveTabs()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关闭右侧页签
|
||||||
|
const closeRightTabs = (path: string) => {
|
||||||
|
const index = tabs.value.findIndex(item => item.path === path)
|
||||||
|
if (index !== -1 && index < tabs.value.length - 1) {
|
||||||
|
tabs.value = tabs.value.slice(0, index + 1)
|
||||||
|
saveTabs()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置当前激活的页签
|
||||||
|
const setActiveTab = (path: string) => {
|
||||||
|
activeTab.value = path
|
||||||
|
saveTabs()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存到本地存储
|
||||||
|
const saveTabs = () => {
|
||||||
|
setStorage('tabs', tabs.value)
|
||||||
|
setStorage('activeTab', activeTab.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清空页签
|
||||||
|
const clearTabs = () => {
|
||||||
|
tabs.value = []
|
||||||
|
activeTab.value = ''
|
||||||
|
removeStorage('tabs')
|
||||||
|
removeStorage('activeTab')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置标签页列表(用于拖拽排序)
|
||||||
|
const setTabs = (newTabs: TabItem[]) => {
|
||||||
|
tabs.value = newTabs
|
||||||
|
saveTabs()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取当前激活标签页的面包屑
|
||||||
|
const currentBreadcrumbs = computed<BreadcrumbItem[]>(() => {
|
||||||
|
const currentTab = tabs.value.find(item => item.path === activeTab.value)
|
||||||
|
if (currentTab && currentTab.breadcrumbs) {
|
||||||
|
return currentTab.breadcrumbs
|
||||||
|
}
|
||||||
|
// 默认返回首页
|
||||||
|
return [{ title: '首页', path: '/dashboard' }]
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
tabs,
|
||||||
|
activeTab,
|
||||||
|
currentBreadcrumbs,
|
||||||
|
addTab,
|
||||||
|
removeTab,
|
||||||
|
closeOtherTabs,
|
||||||
|
closeAllTabs,
|
||||||
|
closeLeftTabs,
|
||||||
|
closeRightTabs,
|
||||||
|
setActiveTab,
|
||||||
|
clearTabs,
|
||||||
|
setTabs
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
@ -317,9 +317,7 @@ const handleLanguageChange = async (val: number) => {
|
||||||
await editLangTypeApi({ lang_type: val });
|
await editLangTypeApi({ lang_type: val });
|
||||||
userInfo.lang_type = val;
|
userInfo.lang_type = val;
|
||||||
languageStore.changeLang(val === 1 ? 'zh-CN' : 'en-US');
|
languageStore.changeLang(val === 1 ? 'zh-CN' : 'en-US');
|
||||||
ElMessage.success('语言切换成功');
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
ElMessage.error('语言切换失败');
|
|
||||||
console.error('语言切换失败:', error);
|
console.error('语言切换失败:', error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -331,7 +329,7 @@ const handleEditConfirm = async () => {
|
||||||
await editFormRef.value.validate();
|
await editFormRef.value.validate();
|
||||||
|
|
||||||
if (editField.value === 'username') {
|
if (editField.value === 'username') {
|
||||||
const params: EditUsernameParams = { username: editForm.value, user_id: userInfo.id };
|
const params: EditUsernameParams = { username: editForm.value };
|
||||||
await editUsernameApi(params);
|
await editUsernameApi(params);
|
||||||
userInfo.username = editForm.value;
|
userInfo.username = editForm.value;
|
||||||
}
|
}
|
||||||
|
|
@ -345,7 +343,6 @@ const handleEditConfirm = async () => {
|
||||||
await bindEmailApi(params);
|
await bindEmailApi(params);
|
||||||
userInfo.email = editForm.value;
|
userInfo.email = editForm.value;
|
||||||
}
|
}
|
||||||
ElMessage.success('操作成功');
|
|
||||||
dialogVisible.value = false;
|
dialogVisible.value = false;
|
||||||
editFormRef.value.resetFields();
|
editFormRef.value.resetFields();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|
@ -424,7 +421,6 @@ const handlePasswordConfirm = async () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
await updatePwdByCaptchaApi(params);
|
await updatePwdByCaptchaApi(params);
|
||||||
ElMessage.success('密码修改成功');
|
|
||||||
passwordDialogVisible.value = false;
|
passwordDialogVisible.value = false;
|
||||||
passwordFormRef.value.resetFields();
|
passwordFormRef.value.resetFields();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue