feat: 添加二维码登录功能并优化全屏播放器界面
添加了 qrcode 库支持扫码登录功能,包括相关API接口类型定义 和扫码登录流程实现。同时调整全屏播放器组件的样式布局, 优化歌词显示效果和封面旋转动画尺寸。
This commit is contained in:
parent
2db45f95c0
commit
6e8c97ff64
|
|
@ -15,12 +15,14 @@
|
||||||
"axios": "^1.19.0",
|
"axios": "^1.19.0",
|
||||||
"dayjs": "^1.11.21",
|
"dayjs": "^1.11.21",
|
||||||
"naive-ui": "^2.44.1",
|
"naive-ui": "^2.44.1",
|
||||||
|
"qrcode": "^1.5.4",
|
||||||
"vue": "^3.5.13",
|
"vue": "^3.5.13",
|
||||||
"vue-router": "^5.2.0"
|
"vue-router": "^5.2.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tauri-apps/cli": "^2",
|
"@tauri-apps/cli": "^2",
|
||||||
"@types/node": "^26.2.0",
|
"@types/node": "^26.2.0",
|
||||||
|
"@types/qrcode": "^1.5.6",
|
||||||
"@vitejs/plugin-vue": "^5.2.1",
|
"@vitejs/plugin-vue": "^5.2.1",
|
||||||
"typescript": "~5.6.2",
|
"typescript": "~5.6.2",
|
||||||
"unplugin-auto-import": "^21.1.0",
|
"unplugin-auto-import": "^21.1.0",
|
||||||
|
|
|
||||||
226
pnpm-lock.yaml
226
pnpm-lock.yaml
|
|
@ -23,6 +23,9 @@ importers:
|
||||||
naive-ui:
|
naive-ui:
|
||||||
specifier: ^2.44.1
|
specifier: ^2.44.1
|
||||||
version: 2.44.1(vue@3.5.41(typescript@5.6.2))
|
version: 2.44.1(vue@3.5.41(typescript@5.6.2))
|
||||||
|
qrcode:
|
||||||
|
specifier: ^1.5.4
|
||||||
|
version: 1.5.4
|
||||||
vue:
|
vue:
|
||||||
specifier: ^3.5.13
|
specifier: ^3.5.13
|
||||||
version: 3.5.41(typescript@5.6.2)
|
version: 3.5.41(typescript@5.6.2)
|
||||||
|
|
@ -36,6 +39,9 @@ importers:
|
||||||
'@types/node':
|
'@types/node':
|
||||||
specifier: ^26.2.0
|
specifier: ^26.2.0
|
||||||
version: 26.2.0
|
version: 26.2.0
|
||||||
|
'@types/qrcode':
|
||||||
|
specifier: ^1.5.6
|
||||||
|
version: 1.5.6
|
||||||
'@vitejs/plugin-vue':
|
'@vitejs/plugin-vue':
|
||||||
specifier: ^5.2.1
|
specifier: ^5.2.1
|
||||||
version: 5.2.1(vite@6.4.3(@types/node@26.2.0)(yaml@2.9.0))(vue@3.5.41(typescript@5.6.2))
|
version: 5.2.1(vite@6.4.3(@types/node@26.2.0)(yaml@2.9.0))(vue@3.5.41(typescript@5.6.2))
|
||||||
|
|
@ -527,6 +533,9 @@ packages:
|
||||||
'@types/node@26.2.0':
|
'@types/node@26.2.0':
|
||||||
resolution: {integrity: sha512-5IviulTZeRNp2vAJ514cc/HUlY5nZ9fCbq9DMyC52BrhFZACo3nI0R7qBxhQmo/d27NFe96ur/b7Wwxklda+kg==}
|
resolution: {integrity: sha512-5IviulTZeRNp2vAJ514cc/HUlY5nZ9fCbq9DMyC52BrhFZACo3nI0R7qBxhQmo/d27NFe96ur/b7Wwxklda+kg==}
|
||||||
|
|
||||||
|
'@types/qrcode@1.5.6':
|
||||||
|
resolution: {integrity: sha512-te7NQcV2BOvdj2b1hCAHzAoMNuj65kNBMz0KBaxM6c3VGBOhU0dURQKOtH8CFNI/dsKkwlv32p26qYQTWoB5bw==}
|
||||||
|
|
||||||
'@vitejs/plugin-vue@5.2.1':
|
'@vitejs/plugin-vue@5.2.1':
|
||||||
resolution: {integrity: sha512-cxh314tzaWwOLqVes2gnnCtvBDcM1UMdn+iFR+UjAn411dPT3tOmqrJjbMd7koZpMAmBM/GqeV4n9ge7JSiJJQ==}
|
resolution: {integrity: sha512-cxh314tzaWwOLqVes2gnnCtvBDcM1UMdn+iFR+UjAn411dPT3tOmqrJjbMd7koZpMAmBM/GqeV4n9ge7JSiJJQ==}
|
||||||
engines: {node: ^18.0.0 || >=20.0.0}
|
engines: {node: ^18.0.0 || >=20.0.0}
|
||||||
|
|
@ -611,6 +620,14 @@ packages:
|
||||||
alien-signals@0.2.0:
|
alien-signals@0.2.0:
|
||||||
resolution: {integrity: sha512-StlonZhBBrsPPwrDjiPAiVTf/rolxffLxVPT60Qv/t88BZ81BvUVzHgGqEFvJ1ii8HXtm1+zU2Icr59tfWEcag==}
|
resolution: {integrity: sha512-StlonZhBBrsPPwrDjiPAiVTf/rolxffLxVPT60Qv/t88BZ81BvUVzHgGqEFvJ1ii8HXtm1+zU2Icr59tfWEcag==}
|
||||||
|
|
||||||
|
ansi-regex@5.0.1:
|
||||||
|
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
|
ansi-styles@4.0.0:
|
||||||
|
resolution: {integrity: sha512-8zjUtFJ3db/QoPXuuEMloS2AUf79/yeyttJ7Abr3hteopJu9HK8vsgGviGUMq+zyA6cZZO6gAyZoMTF6TgaEjA==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
ast-kit@2.1.2:
|
ast-kit@2.1.2:
|
||||||
resolution: {integrity: sha512-cl76xfBQM6pztbrFWRnxbrDm9EOqDr1BF6+qQnnDZG2Co2LjyUktkN9GTJfBAfdae+DbT2nJf2nCGAdDDN7W2g==}
|
resolution: {integrity: sha512-cl76xfBQM6pztbrFWRnxbrDm9EOqDr1BF6+qQnnDZG2Co2LjyUktkN9GTJfBAfdae+DbT2nJf2nCGAdDDN7W2g==}
|
||||||
engines: {node: '>=20.18.0'}
|
engines: {node: '>=20.18.0'}
|
||||||
|
|
@ -645,10 +662,24 @@ 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'}
|
||||||
|
|
||||||
chokidar@5.0.0:
|
chokidar@5.0.0:
|
||||||
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==}
|
||||||
|
|
||||||
|
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'}
|
||||||
|
|
@ -691,14 +722,24 @@ 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'}
|
||||||
|
|
||||||
delayed-stream@1.0.0:
|
delayed-stream@1.0.0:
|
||||||
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
|
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
|
||||||
engines: {node: '>=0.4.0'}
|
engines: {node: '>=0.4.0'}
|
||||||
|
|
||||||
|
dijkstrajs@1.0.3:
|
||||||
|
resolution: {integrity: sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==}
|
||||||
|
|
||||||
dunder-proto@1.0.1:
|
dunder-proto@1.0.1:
|
||||||
resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
|
resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
|
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'}
|
||||||
|
|
@ -749,6 +790,10 @@ packages:
|
||||||
picomatch:
|
picomatch:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
find-up@4.1.0:
|
||||||
|
resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
follow-redirects@1.16.0:
|
follow-redirects@1.16.0:
|
||||||
resolution: {integrity: sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==}
|
resolution: {integrity: sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==}
|
||||||
engines: {node: '>=4.0'}
|
engines: {node: '>=4.0'}
|
||||||
|
|
@ -770,6 +815,10 @@ packages:
|
||||||
function-bind@1.1.2:
|
function-bind@1.1.2:
|
||||||
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
|
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
|
||||||
|
|
||||||
|
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'}
|
||||||
|
|
@ -809,6 +858,10 @@ packages:
|
||||||
resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==}
|
resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==}
|
||||||
engines: {node: '>= 6'}
|
engines: {node: '>= 6'}
|
||||||
|
|
||||||
|
is-fullwidth-code-point@3.0.0:
|
||||||
|
resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
js-tokens@10.0.0:
|
js-tokens@10.0.0:
|
||||||
resolution: {integrity: sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==}
|
resolution: {integrity: sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==}
|
||||||
|
|
||||||
|
|
@ -826,6 +879,10 @@ packages:
|
||||||
resolution: {integrity: sha512-++gUqRDEvcnN6Zhqrr+y/CkVEHhlrR96vZn3nZZPYzMcBUyBtTKzB9NadClFIsIVSsu+3i9tfk/erqy9kAmt7Q==}
|
resolution: {integrity: sha512-++gUqRDEvcnN6Zhqrr+y/CkVEHhlrR96vZn3nZZPYzMcBUyBtTKzB9NadClFIsIVSsu+3i9tfk/erqy9kAmt7Q==}
|
||||||
engines: {node: '>=14'}
|
engines: {node: '>=14'}
|
||||||
|
|
||||||
|
locate-path@5.0.0:
|
||||||
|
resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
lodash-es@4.18.1:
|
lodash-es@4.18.1:
|
||||||
resolution: {integrity: sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==}
|
resolution: {integrity: sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==}
|
||||||
|
|
||||||
|
|
@ -885,9 +942,25 @@ packages:
|
||||||
resolution: {integrity: sha512-4a+OsYv9UktOJKE+l1A4OufDgdRF9PifWj+tJnHURo/P+WOxpG4GzUFL9qCalmWauao6ogiG+QvnCovwPoyAWA==}
|
resolution: {integrity: sha512-4a+OsYv9UktOJKE+l1A4OufDgdRF9PifWj+tJnHURo/P+WOxpG4GzUFL9qCalmWauao6ogiG+QvnCovwPoyAWA==}
|
||||||
engines: {node: '>=12.20.0'}
|
engines: {node: '>=12.20.0'}
|
||||||
|
|
||||||
|
p-limit@2.2.0:
|
||||||
|
resolution: {integrity: sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==}
|
||||||
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
|
p-locate@4.1.0:
|
||||||
|
resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
|
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==}
|
||||||
|
|
||||||
|
path-exists@4.0.0:
|
||||||
|
resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
pathe@2.0.3:
|
pathe@2.0.3:
|
||||||
resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==}
|
resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==}
|
||||||
|
|
||||||
|
|
@ -907,6 +980,10 @@ packages:
|
||||||
pkg-types@2.3.1:
|
pkg-types@2.3.1:
|
||||||
resolution: {integrity: sha512-y+ichcgc2LrADuhLNAx8DFjVfgz91pRxfZdI3UDhxHvcVEZsenLO+7XaU5vOp0u/7V/wZ+plyuQxtrDlZJ+yeg==}
|
resolution: {integrity: sha512-y+ichcgc2LrADuhLNAx8DFjVfgz91pRxfZdI3UDhxHvcVEZsenLO+7XaU5vOp0u/7V/wZ+plyuQxtrDlZJ+yeg==}
|
||||||
|
|
||||||
|
pngjs@5.0.0:
|
||||||
|
resolution: {integrity: sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==}
|
||||||
|
engines: {node: '>=10.13.0'}
|
||||||
|
|
||||||
postcss@8.5.26:
|
postcss@8.5.26:
|
||||||
resolution: {integrity: sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ==}
|
resolution: {integrity: sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ==}
|
||||||
engines: {node: ^10 || ^12 || >=14}
|
engines: {node: ^10 || ^12 || >=14}
|
||||||
|
|
@ -915,6 +992,11 @@ packages:
|
||||||
resolution: {integrity: sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==}
|
resolution: {integrity: sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
|
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==}
|
||||||
|
|
||||||
|
|
@ -922,6 +1004,13 @@ packages:
|
||||||
resolution: {integrity: sha512-Kko+Y5XQ6fM+Ce3dq3m9YGxnacYZYl9cA1wZjaF3Vbry2L3i1qVg8+CAgNPsXRArPMUMCaOR7oa9Nqntc43JKA==}
|
resolution: {integrity: sha512-Kko+Y5XQ6fM+Ce3dq3m9YGxnacYZYl9cA1wZjaF3Vbry2L3i1qVg8+CAgNPsXRArPMUMCaOR7oa9Nqntc43JKA==}
|
||||||
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==}
|
||||||
|
|
||||||
rollup@4.62.4:
|
rollup@4.62.4:
|
||||||
resolution: {integrity: sha512-RXOqwaPsBGjMNMa4sQjDjHieHEZDFoj/Rdr46l2MU5DfEs16wHJPC2RPTPHWhNl+M3aI472LLqFkFKut4SblOg==}
|
resolution: {integrity: sha512-RXOqwaPsBGjMNMa4sQjDjHieHEZDFoj/Rdr46l2MU5DfEs16wHJPC2RPTPHWhNl+M3aI472LLqFkFKut4SblOg==}
|
||||||
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
|
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
|
||||||
|
|
@ -938,10 +1027,21 @@ packages:
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
set-blocking@2.0.0:
|
||||||
|
resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==}
|
||||||
|
|
||||||
source-map-js@1.2.1:
|
source-map-js@1.2.1:
|
||||||
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
|
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
|
string-width@4.2.0:
|
||||||
|
resolution: {integrity: sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
|
strip-ansi@6.0.0:
|
||||||
|
resolution: {integrity: sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
strip-literal@4.0.0:
|
strip-literal@4.0.0:
|
||||||
resolution: {integrity: sha512-PaqAvfUZKBwc/SLmNZtHmzK+v19Z4O4eS3cKPeGvbIv/U3pnyEq4Tuw3/4v/FwfM8VQaEawsyCcOQ0P+kpwWWw==}
|
resolution: {integrity: sha512-PaqAvfUZKBwc/SLmNZtHmzK+v19Z4O4eS3cKPeGvbIv/U3pnyEq4Tuw3/4v/FwfM8VQaEawsyCcOQ0P+kpwWWw==}
|
||||||
|
|
||||||
|
|
@ -1127,11 +1227,29 @@ 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==}
|
||||||
|
|
||||||
|
wrap-ansi@6.2.0:
|
||||||
|
resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
|
y18n@4.0.3:
|
||||||
|
resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==}
|
||||||
|
|
||||||
yaml@2.9.0:
|
yaml@2.9.0:
|
||||||
resolution: {integrity: sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==}
|
resolution: {integrity: sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==}
|
||||||
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.3.1:
|
||||||
|
resolution: {integrity: sha512-92O1HWEjw27sBfgmXiixJWT5hRBp2eobqXicLtPBIDBhYB+1HpwZlXmbW2luivBJHBzki+7VyCLRtAkScbTBQA==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
snapshots:
|
snapshots:
|
||||||
|
|
||||||
'@babel/generator@8.0.0':
|
'@babel/generator@8.0.0':
|
||||||
|
|
@ -1428,6 +1546,10 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
undici-types: 8.3.0
|
undici-types: 8.3.0
|
||||||
|
|
||||||
|
'@types/qrcode@1.5.6':
|
||||||
|
dependencies:
|
||||||
|
'@types/node': 26.2.0
|
||||||
|
|
||||||
'@vitejs/plugin-vue@5.2.1(vite@6.4.3(@types/node@26.2.0)(yaml@2.9.0))(vue@3.5.41(typescript@5.6.2))':
|
'@vitejs/plugin-vue@5.2.1(vite@6.4.3(@types/node@26.2.0)(yaml@2.9.0))(vue@3.5.41(typescript@5.6.2))':
|
||||||
dependencies:
|
dependencies:
|
||||||
vite: 6.4.3(@types/node@26.2.0)(yaml@2.9.0)
|
vite: 6.4.3(@types/node@26.2.0)(yaml@2.9.0)
|
||||||
|
|
@ -1550,6 +1672,12 @@ snapshots:
|
||||||
|
|
||||||
alien-signals@0.2.0: {}
|
alien-signals@0.2.0: {}
|
||||||
|
|
||||||
|
ansi-regex@5.0.1: {}
|
||||||
|
|
||||||
|
ansi-styles@4.0.0:
|
||||||
|
dependencies:
|
||||||
|
color-convert: 2.0.1
|
||||||
|
|
||||||
ast-kit@2.1.2:
|
ast-kit@2.1.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/parser': 7.29.8
|
'@babel/parser': 7.29.8
|
||||||
|
|
@ -1593,10 +1721,24 @@ 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: {}
|
||||||
|
|
||||||
chokidar@5.0.0:
|
chokidar@5.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
readdirp: 5.1.1
|
readdirp: 5.1.1
|
||||||
|
|
||||||
|
cliui@6.0.0:
|
||||||
|
dependencies:
|
||||||
|
string-width: 4.2.0
|
||||||
|
strip-ansi: 6.0.0
|
||||||
|
wrap-ansi: 6.2.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
|
||||||
|
|
@ -1628,14 +1770,20 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
ms: 2.1.3
|
ms: 2.1.3
|
||||||
|
|
||||||
|
decamelize@1.2.0: {}
|
||||||
|
|
||||||
delayed-stream@1.0.0: {}
|
delayed-stream@1.0.0: {}
|
||||||
|
|
||||||
|
dijkstrajs@1.0.3: {}
|
||||||
|
|
||||||
dunder-proto@1.0.1:
|
dunder-proto@1.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
call-bind-apply-helpers: 1.0.2
|
call-bind-apply-helpers: 1.0.2
|
||||||
es-errors: 1.3.0
|
es-errors: 1.3.0
|
||||||
gopd: 1.2.0
|
gopd: 1.2.0
|
||||||
|
|
||||||
|
emoji-regex@8.0.0: {}
|
||||||
|
|
||||||
entities@7.0.1: {}
|
entities@7.0.1: {}
|
||||||
|
|
||||||
es-define-property@1.0.1: {}
|
es-define-property@1.0.1: {}
|
||||||
|
|
@ -1697,6 +1845,11 @@ snapshots:
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
picomatch: 4.0.5
|
picomatch: 4.0.5
|
||||||
|
|
||||||
|
find-up@4.1.0:
|
||||||
|
dependencies:
|
||||||
|
locate-path: 5.0.0
|
||||||
|
path-exists: 4.0.0
|
||||||
|
|
||||||
follow-redirects@1.16.0(debug@4.4.3):
|
follow-redirects@1.16.0(debug@4.4.3):
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
debug: 4.4.3
|
debug: 4.4.3
|
||||||
|
|
@ -1714,6 +1867,8 @@ snapshots:
|
||||||
|
|
||||||
function-bind@1.1.2: {}
|
function-bind@1.1.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
|
||||||
|
|
@ -1757,6 +1912,8 @@ snapshots:
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
|
is-fullwidth-code-point@3.0.0: {}
|
||||||
|
|
||||||
js-tokens@10.0.0: {}
|
js-tokens@10.0.0: {}
|
||||||
|
|
||||||
jsesc@3.1.0: {}
|
jsesc@3.1.0: {}
|
||||||
|
|
@ -1769,6 +1926,10 @@ snapshots:
|
||||||
pkg-types: 2.3.1
|
pkg-types: 2.3.1
|
||||||
quansync: 0.2.11
|
quansync: 0.2.11
|
||||||
|
|
||||||
|
locate-path@5.0.0:
|
||||||
|
dependencies:
|
||||||
|
p-locate: 4.1.0
|
||||||
|
|
||||||
lodash-es@4.18.1: {}
|
lodash-es@4.18.1: {}
|
||||||
|
|
||||||
lodash@4.18.1: {}
|
lodash@4.18.1: {}
|
||||||
|
|
@ -1836,8 +1997,20 @@ snapshots:
|
||||||
|
|
||||||
obug@2.1.4: {}
|
obug@2.1.4: {}
|
||||||
|
|
||||||
|
p-limit@2.2.0:
|
||||||
|
dependencies:
|
||||||
|
p-try: 2.2.0
|
||||||
|
|
||||||
|
p-locate@4.1.0:
|
||||||
|
dependencies:
|
||||||
|
p-limit: 2.2.0
|
||||||
|
|
||||||
|
p-try@2.2.0: {}
|
||||||
|
|
||||||
path-browserify@1.0.1: {}
|
path-browserify@1.0.1: {}
|
||||||
|
|
||||||
|
path-exists@4.0.0: {}
|
||||||
|
|
||||||
pathe@2.0.3: {}
|
pathe@2.0.3: {}
|
||||||
|
|
||||||
perfect-debounce@2.1.0: {}
|
perfect-debounce@2.1.0: {}
|
||||||
|
|
@ -1858,6 +2031,8 @@ snapshots:
|
||||||
exsolve: 1.1.1
|
exsolve: 1.1.1
|
||||||
pathe: 2.0.3
|
pathe: 2.0.3
|
||||||
|
|
||||||
|
pngjs@5.0.0: {}
|
||||||
|
|
||||||
postcss@8.5.26:
|
postcss@8.5.26:
|
||||||
dependencies:
|
dependencies:
|
||||||
nanoid: 3.3.18
|
nanoid: 3.3.18
|
||||||
|
|
@ -1866,10 +2041,20 @@ snapshots:
|
||||||
|
|
||||||
proxy-from-env@2.1.0: {}
|
proxy-from-env@2.1.0: {}
|
||||||
|
|
||||||
|
qrcode@1.5.4:
|
||||||
|
dependencies:
|
||||||
|
dijkstrajs: 1.0.3
|
||||||
|
pngjs: 5.0.0
|
||||||
|
yargs: 15.3.1
|
||||||
|
|
||||||
quansync@0.2.11: {}
|
quansync@0.2.11: {}
|
||||||
|
|
||||||
readdirp@5.1.1: {}
|
readdirp@5.1.1: {}
|
||||||
|
|
||||||
|
require-directory@2.1.1: {}
|
||||||
|
|
||||||
|
require-main-filename@2.0.0: {}
|
||||||
|
|
||||||
rollup@4.62.4:
|
rollup@4.62.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/estree': 1.0.9
|
'@types/estree': 1.0.9
|
||||||
|
|
@ -1908,8 +2093,20 @@ snapshots:
|
||||||
|
|
||||||
semver@7.8.5: {}
|
semver@7.8.5: {}
|
||||||
|
|
||||||
|
set-blocking@2.0.0: {}
|
||||||
|
|
||||||
source-map-js@1.2.1: {}
|
source-map-js@1.2.1: {}
|
||||||
|
|
||||||
|
string-width@4.2.0:
|
||||||
|
dependencies:
|
||||||
|
emoji-regex: 8.0.0
|
||||||
|
is-fullwidth-code-point: 3.0.0
|
||||||
|
strip-ansi: 6.0.0
|
||||||
|
|
||||||
|
strip-ansi@6.0.0:
|
||||||
|
dependencies:
|
||||||
|
ansi-regex: 5.0.1
|
||||||
|
|
||||||
strip-literal@4.0.0:
|
strip-literal@4.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
js-tokens: 10.0.0
|
js-tokens: 10.0.0
|
||||||
|
|
@ -2100,4 +2297,33 @@ snapshots:
|
||||||
|
|
||||||
webpack-virtual-modules@0.6.2: {}
|
webpack-virtual-modules@0.6.2: {}
|
||||||
|
|
||||||
|
which-module@2.0.1: {}
|
||||||
|
|
||||||
|
wrap-ansi@6.2.0:
|
||||||
|
dependencies:
|
||||||
|
ansi-styles: 4.0.0
|
||||||
|
string-width: 4.2.0
|
||||||
|
strip-ansi: 6.0.0
|
||||||
|
|
||||||
|
y18n@4.0.3: {}
|
||||||
|
|
||||||
yaml@2.9.0: {}
|
yaml@2.9.0: {}
|
||||||
|
|
||||||
|
yargs-parser@18.1.3:
|
||||||
|
dependencies:
|
||||||
|
camelcase: 5.3.1
|
||||||
|
decamelize: 1.2.0
|
||||||
|
|
||||||
|
yargs@15.3.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.0
|
||||||
|
which-module: 2.0.1
|
||||||
|
y18n: 4.0.3
|
||||||
|
yargs-parser: 18.1.3
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,37 @@
|
||||||
import { get, post } from "@/utils/request"
|
import { get, post } from "@/utils/request"
|
||||||
import Source from "@/types/global"
|
import Source from "@/types/global"
|
||||||
|
|
||||||
|
/** 支持扫码登录的平台 */
|
||||||
|
export interface QrLoginSource {
|
||||||
|
name: string
|
||||||
|
source: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 扫码登录会话 */
|
||||||
|
export interface QrLoginSession {
|
||||||
|
source: string
|
||||||
|
key: string
|
||||||
|
url: string
|
||||||
|
expires_at: number
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 扫码登录状态 */
|
||||||
|
export interface QrLoginStatus {
|
||||||
|
source: string
|
||||||
|
key: string
|
||||||
|
status: string
|
||||||
|
message: string
|
||||||
|
extra?: Record<string, unknown>
|
||||||
|
}
|
||||||
|
|
||||||
const SystemApi = {
|
const SystemApi = {
|
||||||
/**
|
/**
|
||||||
* 获取当前系统加载的 Cookies
|
* 获取当前系统加载的 Cookies
|
||||||
* @description 读取并在 JSON 格式下返回当前系统已配置的各平台 Cookies。
|
* @description 读取并在 JSON 格式下返回当前系统已配置的各平台 Cookies。
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
cookies: () => {
|
cookies: (): Promise<Record<string, string>> => {
|
||||||
return get<any>(`/api/v1/system/cookies`)
|
return get<Record<string, string>>(`/api/v1/system/cookies`)
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* 设置系统 Cookies
|
* 设置系统 Cookies
|
||||||
|
|
@ -23,17 +46,18 @@ const SystemApi = {
|
||||||
* @description 返回当前 API 支持创建二维码登录会话的平台列表。
|
* @description 返回当前 API 支持创建二维码登录会话的平台列表。
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
qrLoginSource: () => {
|
qrLoginSource: (): Promise<QrLoginSource[]> => {
|
||||||
return get<any>(`/api/v1/system/qr_login/sources`)
|
return get<QrLoginSource[]>(`/api/v1/system/qr_login/sources`)
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* 轮询扫码登录状态
|
* 轮询扫码登录状态
|
||||||
* @description 使用创建扫码登录会话返回的 key 轮询登录状态;成功时自动写入 cookies.json。
|
* @description 使用创建扫码登录会话返回的 key 轮询登录状态;成功时自动写入 cookies.json。
|
||||||
* @param source 扫码登录平台
|
* @param source 扫码登录平台
|
||||||
|
* @param key 扫码登录会话 key
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
loginStatus: (source: Source) => {
|
loginStatus: (source: Source, key: string): Promise<QrLoginStatus> => {
|
||||||
return get<any>(`/api/v1/system/qr_login/${source}`)
|
return get<QrLoginStatus>(`/api/v1/system/qr_login/${source}?key=${encodeURIComponent(key)}`)
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* 创建扫码登录会话
|
* 创建扫码登录会话
|
||||||
|
|
@ -41,8 +65,8 @@ const SystemApi = {
|
||||||
* @param source 扫码登录平台
|
* @param source 扫码登录平台
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
qrLogin: (source: Source) => {
|
qrLogin: (source: Source): Promise<QrLoginSession> => {
|
||||||
return post<any>(`/api/v1/system/qr_login/${source}`)
|
return post<QrLoginSession>(`/api/v1/system/qr_login/${source}`)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
|
<Teleport to="body">
|
||||||
<Transition name="fullscreen">
|
<Transition name="fullscreen">
|
||||||
<div v-if="show" class="fullscreen-player">
|
<div v-if="show" class="fullscreen-player">
|
||||||
<div class="fullscreen-bg" :style="current ? { background: coverBackground(current.cover) } : undefined" />
|
<div class="fullscreen-bg" :style="current ? { background: coverBackground(current.cover) } : undefined" />
|
||||||
|
|
@ -91,6 +92,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Transition>
|
</Transition>
|
||||||
|
</Teleport>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
|
@ -250,14 +252,16 @@ watch(currentLyricIndex, (newIndex) => {
|
||||||
|
|
||||||
.cover-rotating {
|
.cover-rotating {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 360px;
|
width: 300px;
|
||||||
height: 360px;
|
height: 300px;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
|
overflow: hidden;
|
||||||
background: var(--app-card);
|
background: var(--app-card);
|
||||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
|
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
|
||||||
animation-duration: 20s;
|
animation-duration: 20s;
|
||||||
animation-timing-function: linear;
|
animation-timing-function: linear;
|
||||||
animation-iteration-count: infinite;
|
animation-iteration-count: infinite;
|
||||||
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cover-rotating.spinning {
|
.cover-rotating.spinning {
|
||||||
|
|
@ -331,8 +335,8 @@ watch(currentLyricIndex, (newIndex) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
.lyric-line {
|
.lyric-line {
|
||||||
padding: 16px 0;
|
padding: 12px 0;
|
||||||
font-size: 24px;
|
font-size: 16px;
|
||||||
line-height: 1.6;
|
line-height: 1.6;
|
||||||
color: rgba(255, 255, 255, 0.4);
|
color: rgba(255, 255, 255, 0.4);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
@ -340,7 +344,7 @@ watch(currentLyricIndex, (newIndex) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
.lyric-line.active {
|
.lyric-line.active {
|
||||||
font-size: 32px;
|
font-size: 20px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: var(--app-text);
|
color: var(--app-text);
|
||||||
text-shadow: 0 2px 8px rgba(109, 93, 246, 0.4);
|
text-shadow: 0 2px 8px rgba(109, 93, 246, 0.4);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,352 @@
|
||||||
|
<template>
|
||||||
|
<section class="setting-card">
|
||||||
|
<div class="setting-head">
|
||||||
|
<h3>扫码登录</h3>
|
||||||
|
<p>选择平台生成二维码,用对应 App 扫码后自动写入平台 Cookies,可提升搜索与播放的可用性。</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="loadingSources" class="login-loading">
|
||||||
|
<n-spin size="small" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<template v-else-if="sources.length > 0">
|
||||||
|
<n-radio-group :value="selectedSource" @update:value="onSelectSource" class="login-sources">
|
||||||
|
<n-radio-button
|
||||||
|
v-for="item in sources"
|
||||||
|
:key="item.source"
|
||||||
|
:value="item.source"
|
||||||
|
:label="item.name"
|
||||||
|
/>
|
||||||
|
</n-radio-group>
|
||||||
|
|
||||||
|
<div class="login-body">
|
||||||
|
<div class="qr-box">
|
||||||
|
<canvas ref="qrCanvasRef" class="qr-canvas" />
|
||||||
|
<div v-if="status.type === 'success'" class="qr-mask success">登录成功</div>
|
||||||
|
<div v-else-if="status.type === 'expired'" class="qr-mask expired">二维码已过期</div>
|
||||||
|
<div v-else-if="status.type === 'error'" class="qr-mask error">生成失败</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="login-side">
|
||||||
|
<p class="status-text" :class="status.type">{{ status.text }}</p>
|
||||||
|
<n-button
|
||||||
|
type="primary"
|
||||||
|
round
|
||||||
|
:loading="creating"
|
||||||
|
:disabled="polling && status.type !== 'expired' && status.type !== 'error'"
|
||||||
|
@click="startLogin"
|
||||||
|
>
|
||||||
|
{{ session ? "重新生成" : "生成二维码" }}
|
||||||
|
</n-button>
|
||||||
|
<p class="hint">请使用「{{ currentSourceName }}」App 扫码</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<n-empty v-else description="暂无支持扫码登录的平台" class="empty" />
|
||||||
|
|
||||||
|
<div v-if="cookies.length > 0" class="cookie-row">
|
||||||
|
<span class="cookie-label">已配置 Cookies:</span>
|
||||||
|
<n-tag v-for="name in cookies" :key="name" size="small" :bordered="false" type="success">
|
||||||
|
{{ name }}
|
||||||
|
</n-tag>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { computed, onBeforeUnmount, onMounted, ref } from "vue"
|
||||||
|
import { NButton, NEmpty, NRadioButton, NRadioGroup, NSpin, NTag, useMessage } from "naive-ui"
|
||||||
|
import QRCode from "qrcode"
|
||||||
|
import SystemApi, {
|
||||||
|
type QrLoginSession,
|
||||||
|
type QrLoginSource,
|
||||||
|
type QrLoginStatus,
|
||||||
|
} from "@/api/system"
|
||||||
|
import Source from "@/types/global"
|
||||||
|
import { SOURCE_LABELS } from "@/stores/settings"
|
||||||
|
|
||||||
|
const message = useMessage()
|
||||||
|
|
||||||
|
type StatusType = "waiting" | "scanned" | "success" | "expired" | "error"
|
||||||
|
|
||||||
|
const sources = ref<QrLoginSource[]>([])
|
||||||
|
const loadingSources = ref(true)
|
||||||
|
const selectedSource = ref<Source | null>(null)
|
||||||
|
|
||||||
|
const qrCanvasRef = ref<HTMLCanvasElement | null>(null)
|
||||||
|
const session = ref<QrLoginSession | null>(null)
|
||||||
|
const creating = ref(false)
|
||||||
|
const polling = ref(false)
|
||||||
|
const status = ref<{ type: StatusType; text: string }>({
|
||||||
|
type: "waiting",
|
||||||
|
text: "等待扫码",
|
||||||
|
})
|
||||||
|
|
||||||
|
const cookies = ref<string[]>([])
|
||||||
|
|
||||||
|
let pollTimer: number | undefined
|
||||||
|
let pollSeq = 0
|
||||||
|
|
||||||
|
const currentSourceName = computed(
|
||||||
|
() => sources.value.find((item) => item.source === selectedSource.value)?.name ?? SOURCE_LABELS[selectedSource.value as Source] ?? "",
|
||||||
|
)
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
try {
|
||||||
|
const list = await SystemApi.qrLoginSource()
|
||||||
|
sources.value = list
|
||||||
|
if (list.length > 0) {
|
||||||
|
selectedSource.value = list[0].source as Source
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
sources.value = []
|
||||||
|
} finally {
|
||||||
|
loadingSources.value = false
|
||||||
|
}
|
||||||
|
void refreshCookies()
|
||||||
|
})
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
stopPolling()
|
||||||
|
})
|
||||||
|
|
||||||
|
async function refreshCookies() {
|
||||||
|
try {
|
||||||
|
const data = await SystemApi.cookies()
|
||||||
|
cookies.value = Object.entries(data ?? {})
|
||||||
|
.filter(([, value]) => Boolean(value))
|
||||||
|
.map(([key]) => SOURCE_LABELS[key as Source] ?? key)
|
||||||
|
} catch {
|
||||||
|
// 忽略:登录成功后再刷新,失败不影响页面
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onSelectSource(value: string | number | boolean) {
|
||||||
|
selectedSource.value = value as Source
|
||||||
|
stopPolling()
|
||||||
|
session.value = null
|
||||||
|
status.value = { type: "waiting", text: "等待扫码" }
|
||||||
|
}
|
||||||
|
|
||||||
|
async function startLogin() {
|
||||||
|
if (!selectedSource.value) return
|
||||||
|
stopPolling()
|
||||||
|
session.value = null
|
||||||
|
status.value = { type: "waiting", text: "等待扫码" }
|
||||||
|
creating.value = true
|
||||||
|
try {
|
||||||
|
const result = await SystemApi.qrLogin(selectedSource.value)
|
||||||
|
session.value = result
|
||||||
|
await renderQr(result.url)
|
||||||
|
status.value = { type: "waiting", text: "等待扫码" }
|
||||||
|
startPolling(result)
|
||||||
|
} catch {
|
||||||
|
status.value = { type: "error", text: "生成二维码失败,请重试" }
|
||||||
|
} finally {
|
||||||
|
creating.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function renderQr(text: string) {
|
||||||
|
if (!qrCanvasRef.value) return
|
||||||
|
await QRCode.toCanvas(qrCanvasRef.value, text, {
|
||||||
|
width: 216,
|
||||||
|
margin: 2,
|
||||||
|
errorCorrectionLevel: "M",
|
||||||
|
color: { dark: "#000000", light: "#ffffff" },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function startPolling(result: QrLoginSession) {
|
||||||
|
const seq = ++pollSeq
|
||||||
|
polling.value = true
|
||||||
|
pollTimer = window.setInterval(async () => {
|
||||||
|
if (seq !== pollSeq) return
|
||||||
|
try {
|
||||||
|
const res = await SystemApi.loginStatus(result.source as Source, result.key)
|
||||||
|
if (seq !== pollSeq) return
|
||||||
|
applyStatus(res)
|
||||||
|
if (status.value.type === "success") {
|
||||||
|
stopPolling()
|
||||||
|
message.success(`「${currentSourceName.value}」登录成功,Cookies 已保存`)
|
||||||
|
void refreshCookies()
|
||||||
|
} else if (status.value.type === "expired" || status.value.type === "error") {
|
||||||
|
stopPolling()
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
if (seq !== pollSeq) return
|
||||||
|
status.value = { type: "error", text: "查询登录状态失败,请重试" }
|
||||||
|
stopPolling()
|
||||||
|
}
|
||||||
|
}, 2000)
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyStatus(res: QrLoginStatus) {
|
||||||
|
const code = String(res.extra?.code ?? "")
|
||||||
|
const raw = res.status ?? ""
|
||||||
|
if (raw.includes("success") || code === "803") {
|
||||||
|
status.value = { type: "success", text: res.message || "登录成功" }
|
||||||
|
} else if (raw.includes("expired") || code === "800") {
|
||||||
|
status.value = { type: "expired", text: res.message || "二维码已过期" }
|
||||||
|
} else if (raw.includes("scan") || code === "802") {
|
||||||
|
status.value = { type: "scanned", text: res.message || "已扫码,请在手机上确认" }
|
||||||
|
} else {
|
||||||
|
status.value = { type: "waiting", text: res.message || "等待扫码" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function stopPolling() {
|
||||||
|
pollSeq += 1
|
||||||
|
polling.value = false
|
||||||
|
if (pollTimer !== undefined) {
|
||||||
|
window.clearInterval(pollTimer)
|
||||||
|
pollTimer = undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.setting-card {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
padding: clamp(16px, 2vw, 22px);
|
||||||
|
border: 1px solid var(--app-border);
|
||||||
|
border-radius: 14px;
|
||||||
|
background: rgba(255, 255, 255, 0.02);
|
||||||
|
}
|
||||||
|
|
||||||
|
.setting-head {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.setting-head h3 {
|
||||||
|
margin: 0 0 4px;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.setting-head p {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--app-text-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-loading {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 24px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-sources {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 8px;
|
||||||
|
margin-bottom: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-body {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: clamp(18px, 3vw, 28px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.qr-box {
|
||||||
|
position: relative;
|
||||||
|
width: 220px;
|
||||||
|
height: 220px;
|
||||||
|
border-radius: 12px;
|
||||||
|
overflow: hidden;
|
||||||
|
flex-shrink: 0;
|
||||||
|
background: #fff;
|
||||||
|
box-shadow: 0 10px 24px rgba(0, 0, 0, 0.25);
|
||||||
|
}
|
||||||
|
|
||||||
|
.qr-canvas {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qr-mask {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #fff;
|
||||||
|
background: rgba(0, 0, 0, 0.55);
|
||||||
|
backdrop-filter: blur(2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.qr-mask.success {
|
||||||
|
background: rgba(34, 197, 94, 0.72);
|
||||||
|
}
|
||||||
|
|
||||||
|
.qr-mask.expired {
|
||||||
|
background: rgba(239, 68, 68, 0.72);
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-side {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 14px;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-text {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-text.waiting {
|
||||||
|
color: var(--app-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-text.scanned {
|
||||||
|
color: #f59e0b;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-text.success {
|
||||||
|
color: var(--app-green);
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-text.expired,
|
||||||
|
.status-text.error {
|
||||||
|
color: #ef4444;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hint {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--app-text-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cookie-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 6px;
|
||||||
|
margin-top: 16px;
|
||||||
|
padding-top: 14px;
|
||||||
|
border-top: 1px solid var(--app-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cookie-label {
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--app-text-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty {
|
||||||
|
padding: 24px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 640px) {
|
||||||
|
.login-body {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -20,6 +20,7 @@ declare module 'vue' {
|
||||||
NRadioGroup: typeof import('naive-ui')['NRadioGroup']
|
NRadioGroup: typeof import('naive-ui')['NRadioGroup']
|
||||||
NScrollbar: typeof import('naive-ui')['NScrollbar']
|
NScrollbar: typeof import('naive-ui')['NScrollbar']
|
||||||
PlayerBar: typeof import('./../components/PlayerBar.vue')['default']
|
PlayerBar: typeof import('./../components/PlayerBar.vue')['default']
|
||||||
|
QrLogin: typeof import('./../components/QrLogin.vue')['default']
|
||||||
RouterLink: typeof import('vue-router')['RouterLink']
|
RouterLink: typeof import('vue-router')['RouterLink']
|
||||||
RouterView: typeof import('vue-router')['RouterView']
|
RouterView: typeof import('vue-router')['RouterView']
|
||||||
SongTable: typeof import('./../components/SongTable.vue')['default']
|
SongTable: typeof import('./../components/SongTable.vue')['default']
|
||||||
|
|
|
||||||
|
|
@ -45,11 +45,14 @@
|
||||||
/>
|
/>
|
||||||
</n-radio-group>
|
</n-radio-group>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<QrLogin />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { NCheckboxGroup, NRadioGroup } from "naive-ui"
|
import { NCheckboxGroup, NRadioGroup } from "naive-ui"
|
||||||
|
import QrLogin from "@/components/QrLogin.vue"
|
||||||
import { ALL_SOURCES, SOURCE_LABELS, setDefaultSource, setEnabledSources, settingsState } from "@/stores/settings"
|
import { ALL_SOURCES, SOURCE_LABELS, setDefaultSource, setEnabledSources, settingsState } from "@/stores/settings"
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue