hookehuyr

feat(登录): 添加用户信息认证工具函数并重构登录逻辑

refactor: 将登录页面的用户信息处理逻辑提取到独立工具函数
test: 添加用户信息认证工具函数的单元测试
chore: 添加vitest测试框架及相关依赖
###
# @Date: 2025-03-20 23:40:15
# @LastEditors: hookehuyr hookehuyr@gmail.com
# @LastEditTime: 2025-12-02 18:34:41
# @LastEditTime: 2025-12-09 21:05:15
# @FilePath: /mlaj/.env.development
# @Description: 文件描述
###
......
......@@ -7,6 +7,7 @@
"dev": ". ~/.nvm/nvm.sh && nvm use 18.19.1 && vite",
"build": ". ~/.nvm/nvm.sh && nvm use 18.19.1 && vite build",
"preview": "vite preview",
"test": "vitest run",
"tar": "tar -czvpf dist.tar.gz mlaj",
"build_tar": "npm run build && npm run tar",
"scp-dev": "scp dist.tar.gz ipadbiz-inner:/opt/space-dev/f",
......@@ -62,6 +63,7 @@
"tailwindcss": "^3.4.1",
"unplugin-auto-import": "^19.1.1",
"unplugin-vue-components": "^28.4.1",
"vite": "^6.2.0"
"vite": "^6.2.0",
"vitest": "^3.2.0"
}
}
......
......@@ -129,6 +129,9 @@ importers:
vite:
specifier: ^6.2.0
version: 6.4.1(@types/node@20.19.25)(jiti@1.21.7)(less@4.4.2)
vitest:
specifier: ^3.2.0
version: 3.2.4(@types/node@20.19.25)(jiti@1.21.7)(less@4.4.2)
packages:
......@@ -608,6 +611,12 @@ packages:
'@sunsetglow/vue-pdf-viewer@0.3.72':
resolution: {integrity: sha512-on1Ma1tEIKShQjWCnFMWqijOhAsiIYjQMCm+b7ISDOAQDen6icqQLj++PvrObKeQda9Tuq+l+lkwqk4Z2acDJw==}
'@types/chai@5.2.3':
resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==}
'@types/deep-eql@4.0.2':
resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==}
'@types/estree@1.0.8':
resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
......@@ -665,6 +674,35 @@ packages:
vite: ^5.0.0 || ^6.0.0
vue: ^3.2.25
'@vitest/expect@3.2.4':
resolution: {integrity: sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==}
'@vitest/mocker@3.2.4':
resolution: {integrity: sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==}
peerDependencies:
msw: ^2.4.9
vite: ^5.0.0 || ^6.0.0 || ^7.0.0-0
peerDependenciesMeta:
msw:
optional: true
vite:
optional: true
'@vitest/pretty-format@3.2.4':
resolution: {integrity: sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==}
'@vitest/runner@3.2.4':
resolution: {integrity: sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==}
'@vitest/snapshot@3.2.4':
resolution: {integrity: sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==}
'@vitest/spy@3.2.4':
resolution: {integrity: sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==}
'@vitest/utils@3.2.4':
resolution: {integrity: sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==}
'@vue-office/docx@1.6.3':
resolution: {integrity: sha512-Cs+3CAaRBOWOiW4XAhTwwxJ0dy8cPIf6DqfNvYcD3YACiLwO4kuawLF2IAXxyijhbuOeoFsfvoVbOc16A/4bZA==}
peerDependencies:
......@@ -810,6 +848,10 @@ packages:
array-tree-filter@2.1.0:
resolution: {integrity: sha512-4ROwICNlNw/Hqa9v+rk5h22KjmzB1JGTMVKP2AKJBOCgb0yL0ASf0+YvCcLNNwquOHNX48jkeZIJ3a+oOQqKcw==}
assertion-error@2.0.1:
resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==}
engines: {node: '>=12'}
async-validator@4.2.5:
resolution: {integrity: sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==}
......@@ -856,6 +898,10 @@ packages:
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
hasBin: true
cac@6.7.14:
resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}
engines: {node: '>=8'}
call-bind-apply-helpers@1.0.2:
resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==}
engines: {node: '>= 0.4'}
......@@ -879,6 +925,14 @@ packages:
resolution: {integrity: sha512-ItanGBMrmRV7Py2Z+Xhs7cT+FNt5K0vPL4p9EZ/UX/Mu7hFbkxSjKF2KVtPwX7UYWp7dRKnrTvReflgrItJbdw==}
engines: {node: '>=6'}
chai@5.3.3:
resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==}
engines: {node: '>=18'}
check-error@2.1.1:
resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==}
engines: {node: '>= 16'}
chokidar@3.6.0:
resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==}
engines: {node: '>= 8.10.0'}
......@@ -968,6 +1022,10 @@ packages:
resolution: {integrity: sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==}
engines: {node: '>=8'}
deep-eql@5.0.2:
resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==}
engines: {node: '>=6'}
delayed-stream@1.0.0:
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
engines: {node: '>=0.4.0'}
......@@ -1023,6 +1081,9 @@ packages:
resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
engines: {node: '>= 0.4'}
es-module-lexer@1.7.0:
resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==}
es-object-atoms@1.1.1:
resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==}
engines: {node: '>= 0.4'}
......@@ -1050,6 +1111,10 @@ packages:
estree-walker@3.0.3:
resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==}
expect-type@1.3.0:
resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==}
engines: {node: '>=12.0.0'}
exsolve@1.0.8:
resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==}
......@@ -1290,6 +1355,9 @@ packages:
resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
hasBin: true
loupe@3.2.1:
resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==}
lru-cache@5.1.1:
resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
......@@ -1474,6 +1542,10 @@ packages:
pathe@2.0.3:
resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==}
pathval@2.0.1:
resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==}
engines: {node: '>= 14.16'}
pdf-vue3@1.0.12:
resolution: {integrity: sha512-7SMTx1RfRwdc+2WPniDzqM8MxJLqTNNzdyV0SeQTxeRLJGndb5Wv/fz5afO13oBSIvvaqcbZ/S3gF+XjqkSb9g==}
......@@ -1691,6 +1763,9 @@ packages:
resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==}
engines: {node: '>= 0.4'}
siginfo@2.0.0:
resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==}
signal-exit@3.0.7:
resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
......@@ -1711,6 +1786,12 @@ packages:
spark-md5@2.0.2:
resolution: {integrity: sha512-9WfT+FYBEvlrOOBEs484/zmbtSX4BlGjzXih1qIEWA1yhHbcqgcMHkiwXoWk2Sq1aJjLpcs6ZKV7JxrDNjIlNg==}
stackback@0.0.2:
resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==}
std-env@3.10.0:
resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==}
string-width@4.2.3:
resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
engines: {node: '>=8'}
......@@ -1764,10 +1845,28 @@ packages:
resolution: {integrity: sha512-B71/4oyj61iNH0KeCamLuE2rmKuTO5byTOSVwECM5FA7TiAiAW+UqTKZ9ERueC4qvgSttUhdmq1mXC3kJqGX7A==}
engines: {node: '>=12.22'}
tinybench@2.9.0:
resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==}
tinyexec@0.3.2:
resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==}
tinyglobby@0.2.15:
resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==}
engines: {node: '>=12.0.0'}
tinypool@1.1.1:
resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==}
engines: {node: ^18.0.0 || >=20.0.0}
tinyrainbow@2.0.0:
resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==}
engines: {node: '>=14.0.0'}
tinyspy@4.0.4:
resolution: {integrity: sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==}
engines: {node: '>=14.0.0'}
to-regex-range@5.0.1:
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
engines: {node: '>=8.0'}
......@@ -1864,6 +1963,11 @@ packages:
videojs-vtt.js@0.15.5:
resolution: {integrity: sha512-yZbBxvA7QMYn15Lr/ZfhhLPrNpI/RmCSCqgIff57GC2gIrV5YfyzLfLyZMj0NnZSAz8syB4N0nHXpZg9MyrMOQ==}
vite-node@3.2.4:
resolution: {integrity: sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==}
engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
hasBin: true
vite-plugin-static-copy@1.0.6:
resolution: {integrity: sha512-3uSvsMwDVFZRitqoWHj0t4137Kz7UynnJeq1EZlRW7e25h2068fyIZX4ORCCOAkfp1FklGxJNVJBkBOD+PZIew==}
engines: {node: ^18.0.0 || >=20.0.0}
......@@ -1910,6 +2014,34 @@ packages:
yaml:
optional: true
vitest@3.2.4:
resolution: {integrity: sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==}
engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
hasBin: true
peerDependencies:
'@edge-runtime/vm': '*'
'@types/debug': ^4.1.12
'@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0
'@vitest/browser': 3.2.4
'@vitest/ui': 3.2.4
happy-dom: '*'
jsdom: '*'
peerDependenciesMeta:
'@edge-runtime/vm':
optional: true
'@types/debug':
optional: true
'@types/node':
optional: true
'@vitest/browser':
optional: true
'@vitest/ui':
optional: true
happy-dom:
optional: true
jsdom:
optional: true
vue-demi@0.14.6:
resolution: {integrity: sha512-8QA7wrYSHKaYgUxDA5ZC24w+eHm3sYCbp0EzcDwKqN3p6HqtTCGR/GVsPyZW92unff4UlcSh++lmqDWN3ZIq4w==}
engines: {node: '>=12'}
......@@ -1962,6 +2094,11 @@ packages:
which-module@2.0.1:
resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==}
why-is-node-running@2.3.0:
resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==}
engines: {node: '>=8'}
hasBin: true
wide-align@1.1.5:
resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==}
......@@ -2411,6 +2548,13 @@ snapshots:
- typescript
- vite
'@types/chai@5.2.3':
dependencies:
'@types/deep-eql': 4.0.2
assertion-error: 2.0.1
'@types/deep-eql@4.0.2': {}
'@types/estree@1.0.8': {}
'@types/node@20.19.25':
......@@ -2474,6 +2618,48 @@ snapshots:
vite: 6.4.1(@types/node@20.19.25)(jiti@1.21.7)(less@4.4.2)
vue: 3.5.25
'@vitest/expect@3.2.4':
dependencies:
'@types/chai': 5.2.3
'@vitest/spy': 3.2.4
'@vitest/utils': 3.2.4
chai: 5.3.3
tinyrainbow: 2.0.0
'@vitest/mocker@3.2.4(vite@6.4.1(@types/node@20.19.25)(jiti@1.21.7)(less@4.4.2))':
dependencies:
'@vitest/spy': 3.2.4
estree-walker: 3.0.3
magic-string: 0.30.21
optionalDependencies:
vite: 6.4.1(@types/node@20.19.25)(jiti@1.21.7)(less@4.4.2)
'@vitest/pretty-format@3.2.4':
dependencies:
tinyrainbow: 2.0.0
'@vitest/runner@3.2.4':
dependencies:
'@vitest/utils': 3.2.4
pathe: 2.0.3
strip-literal: 3.1.0
'@vitest/snapshot@3.2.4':
dependencies:
'@vitest/pretty-format': 3.2.4
magic-string: 0.30.21
pathe: 2.0.3
'@vitest/spy@3.2.4':
dependencies:
tinyspy: 4.0.4
'@vitest/utils@3.2.4':
dependencies:
'@vitest/pretty-format': 3.2.4
loupe: 3.2.1
tinyrainbow: 2.0.0
'@vue-office/docx@1.6.3(vue-demi@0.14.6(vue@3.5.25))(vue@3.5.25)':
dependencies:
vue: 3.5.25
......@@ -2660,6 +2846,8 @@ snapshots:
array-tree-filter@2.1.0: {}
assertion-error@2.0.1: {}
async-validator@4.2.5: {}
asynckit@0.4.0: {}
......@@ -2713,6 +2901,8 @@ snapshots:
node-releases: 2.0.27
update-browserslist-db: 1.2.2(browserslist@4.28.1)
cac@6.7.14: {}
call-bind-apply-helpers@1.0.2:
dependencies:
es-errors: 1.3.0
......@@ -2739,6 +2929,16 @@ snapshots:
- supports-color
optional: true
chai@5.3.3:
dependencies:
assertion-error: 2.0.1
check-error: 2.1.1
deep-eql: 5.0.2
loupe: 3.2.1
pathval: 2.0.1
check-error@2.1.1: {}
chokidar@3.6.0:
dependencies:
anymatch: 3.1.3
......@@ -2818,6 +3018,8 @@ snapshots:
mimic-response: 2.1.0
optional: true
deep-eql@5.0.2: {}
delayed-stream@1.0.0: {}
delegates@1.0.0:
......@@ -2859,6 +3061,8 @@ snapshots:
es-errors@1.3.0: {}
es-module-lexer@1.7.0: {}
es-object-atoms@1.1.1:
dependencies:
es-errors: 1.3.0
......@@ -2909,6 +3113,8 @@ snapshots:
dependencies:
'@types/estree': 1.0.8
expect-type@1.3.0: {}
exsolve@1.0.8: {}
fast-glob@3.3.3:
......@@ -3154,6 +3360,8 @@ snapshots:
dependencies:
js-tokens: 4.0.0
loupe@3.2.1: {}
lru-cache@5.1.1:
dependencies:
yallist: 3.1.1
......@@ -3326,6 +3534,8 @@ snapshots:
pathe@2.0.3: {}
pathval@2.0.1: {}
pdf-vue3@1.0.12: {}
pdfjs-dist@3.4.120:
......@@ -3558,6 +3768,8 @@ snapshots:
side-channel-map: 1.0.1
side-channel-weakmap: 1.0.2
siginfo@2.0.0: {}
signal-exit@3.0.7:
optional: true
......@@ -3578,6 +3790,10 @@ snapshots:
spark-md5@2.0.2: {}
stackback@0.0.2: {}
std-env@3.10.0: {}
string-width@4.2.3:
dependencies:
emoji-regex: 8.0.0
......@@ -3665,11 +3881,21 @@ snapshots:
throttle-debounce@5.0.2: {}
tinybench@2.9.0: {}
tinyexec@0.3.2: {}
tinyglobby@0.2.15:
dependencies:
fdir: 6.5.0(picomatch@4.0.3)
picomatch: 4.0.3
tinypool@1.1.1: {}
tinyrainbow@2.0.0: {}
tinyspy@4.0.4: {}
to-regex-range@5.0.1:
dependencies:
is-number: 7.0.0
......@@ -3795,6 +4021,27 @@ snapshots:
dependencies:
global: 4.4.0
vite-node@3.2.4(@types/node@20.19.25)(jiti@1.21.7)(less@4.4.2):
dependencies:
cac: 6.7.14
debug: 4.4.3
es-module-lexer: 1.7.0
pathe: 2.0.3
vite: 6.4.1(@types/node@20.19.25)(jiti@1.21.7)(less@4.4.2)
transitivePeerDependencies:
- '@types/node'
- jiti
- less
- lightningcss
- sass
- sass-embedded
- stylus
- sugarss
- supports-color
- terser
- tsx
- yaml
vite-plugin-static-copy@1.0.6(vite@6.4.1(@types/node@20.19.25)(jiti@1.21.7)(less@4.4.2)):
dependencies:
chokidar: 3.6.0
......@@ -3817,6 +4064,47 @@ snapshots:
jiti: 1.21.7
less: 4.4.2
vitest@3.2.4(@types/node@20.19.25)(jiti@1.21.7)(less@4.4.2):
dependencies:
'@types/chai': 5.2.3
'@vitest/expect': 3.2.4
'@vitest/mocker': 3.2.4(vite@6.4.1(@types/node@20.19.25)(jiti@1.21.7)(less@4.4.2))
'@vitest/pretty-format': 3.2.4
'@vitest/runner': 3.2.4
'@vitest/snapshot': 3.2.4
'@vitest/spy': 3.2.4
'@vitest/utils': 3.2.4
chai: 5.3.3
debug: 4.4.3
expect-type: 1.3.0
magic-string: 0.30.21
pathe: 2.0.3
picomatch: 4.0.3
std-env: 3.10.0
tinybench: 2.9.0
tinyexec: 0.3.2
tinyglobby: 0.2.15
tinypool: 1.1.1
tinyrainbow: 2.0.0
vite: 6.4.1(@types/node@20.19.25)(jiti@1.21.7)(less@4.4.2)
vite-node: 3.2.4(@types/node@20.19.25)(jiti@1.21.7)(less@4.4.2)
why-is-node-running: 2.3.0
optionalDependencies:
'@types/node': 20.19.25
transitivePeerDependencies:
- jiti
- less
- lightningcss
- msw
- sass
- sass-embedded
- stylus
- sugarss
- supports-color
- terser
- tsx
- yaml
vue-demi@0.14.6(vue@3.5.25):
dependencies:
vue: 3.5.25
......@@ -3860,6 +4148,11 @@ snapshots:
which-module@2.0.1: {}
why-is-node-running@2.3.0:
dependencies:
siginfo: 2.0.0
stackback: 0.0.2
wide-align@1.1.5:
dependencies:
string-width: 4.2.3
......
import { describe, expect, it, vi } from 'vitest'
import { applyUserInfoAuth } from '../auth_user_info'
const createStorage = () => {
const store = {}
return {
store,
setItem: vi.fn((key, value) => {
store[key] = value
}),
getItem: vi.fn((key) => store[key] ?? null),
removeItem: vi.fn((key) => {
delete store[key]
}),
clear: vi.fn(() => {
Object.keys(store).forEach((key) => delete store[key])
})
}
}
describe('applyUserInfoAuth', () => {
it('从 response.data.user_info 写入鉴权与缓存', () => {
const storage = createStorage()
const set_auth_headers = vi.fn()
const response = {
data: {
user_info: {
user_id: '100',
HTTP_USER_TOKEN: 'token-xxx',
user_name: '张三'
}
}
}
const ok = applyUserInfoAuth(response, { storage, set_auth_headers })
expect(ok).toBe(true)
expect(set_auth_headers).toHaveBeenCalledTimes(1)
expect(set_auth_headers).toHaveBeenCalledWith('100', 'token-xxx')
expect(storage.setItem).toHaveBeenCalledTimes(1)
expect(storage.setItem).toHaveBeenCalledWith('user_info', JSON.stringify(response.data.user_info))
})
it('缺少 user_id 或 HTTP_USER_TOKEN 时不做任何写入', () => {
const storage = createStorage()
const set_auth_headers = vi.fn()
const ok = applyUserInfoAuth({ user_id: '100' }, { storage, set_auth_headers })
expect(ok).toBe(false)
expect(set_auth_headers).not.toHaveBeenCalled()
expect(storage.setItem).not.toHaveBeenCalled()
})
it('支持直接传入 user_info 对象', () => {
const storage = createStorage()
const set_auth_headers = vi.fn()
const user_info = { user_id: 1, HTTP_USER_TOKEN: 't' }
const ok = applyUserInfoAuth(user_info, { storage, set_auth_headers })
expect(ok).toBe(true)
expect(set_auth_headers).toHaveBeenCalledWith(1, 't')
expect(storage.setItem).toHaveBeenCalledWith('user_info', JSON.stringify(user_info))
})
})
export const applyUserInfoAuth = (input, options = {}) => {
const user_info = input && input.data && input.data.user_info ? input.data.user_info : input
if (!user_info || typeof user_info !== 'object') {
return false
}
const { user_id, HTTP_USER_TOKEN } = user_info
if (!user_id || !HTTP_USER_TOKEN) {
return false
}
const set_auth_headers = options.set_auth_headers
if (typeof set_auth_headers === 'function') {
set_auth_headers(user_id, HTTP_USER_TOKEN)
}
const storage = Object.prototype.hasOwnProperty.call(options, 'storage') ? options.storage : globalThis.localStorage
if (storage && typeof storage.setItem === 'function') {
storage.setItem('user_info', JSON.stringify(user_info || {}))
}
return true
}
......@@ -192,6 +192,7 @@ import { smsAPI } from "@/api/common";
import { showToast } from "vant";
import UserAgreement from "@/components/ui/UserAgreement.vue";
import { setAuthHeaders } from "@/utils/axios";
import { applyUserInfoAuth } from "@/utils/auth_user_info";
import weixinLogo from '@/assets/images/weixin_logo_lg.jpeg'
import { startWxAuth } from '@/router/guards'
import { wxInfo } from '@/utils/tools'
......@@ -310,14 +311,7 @@ const handleSubmit = async () => {
error.value = response.msg || "登录失败,请检查您的输入项";
return;
} else {
// 获取data里面的 user_id, HTTP_USER_TOKEN, 并设置到后面所有的请求头里面,headers.User-Id, headers.User-Token
const { user_id, HTTP_USER_TOKEN } = response?.data?.user_info || {};
if (user_id && HTTP_USER_TOKEN) {
// 设置认证请求头
setAuthHeaders(user_id, HTTP_USER_TOKEN);
// 缓存user_info
localStorage.setItem('user_info', JSON.stringify(response?.data?.user_info || {}));
}
applyUserInfoAuth(response, { set_auth_headers: setAuthHeaders, storage: localStorage })
}
const { code, data } = await getUserInfoAPI();
......
......@@ -90,6 +90,7 @@ import { showToast } from 'vant'
import { useTitle } from '@vueuse/core'
import { setAuthHeaders } from "@/utils/axios";
import VideoBackground from '@/components/ui/VideoBackground.vue'
import { applyUserInfoAuth } from '@/utils/auth_user_info'
// 导入接口
import { smsAPI } from '@/api/common'
......@@ -172,14 +173,7 @@ const handleLogin = async () => {
try {
const res = await loginAPI({ mobile: phone.value, sms_code: code.value, entry: entry.value, referrer_user_id: referrer_user_id.value })
if (res.code) {
// 获取data里面的 user_id, HTTP_USER_TOKEN, 并设置到后面所有的请求头里面,headers.User-Id, headers.User-Token
const { user_id, HTTP_USER_TOKEN } = res?.data?.user_info || {};
if (user_id && HTTP_USER_TOKEN) {
// 设置认证请求头
setAuthHeaders(user_id, HTTP_USER_TOKEN);
// 缓存user_info
localStorage.setItem('user_info', JSON.stringify(res?.data?.user_info || {}));
}
applyUserInfoAuth(res, { set_auth_headers: setAuthHeaders, storage: localStorage })
const userInfo = await userInfoAPI()
// 登录之后需要判断是否有完善个人信息
if (userInfo.code) {
......