diff --git a/.env.development b/.env.development
index 932410b..722ca9b 100644
--- a/.env.development
+++ b/.env.development
@@ -1,8 +1,14 @@
# Development environment variables
# API base URL
-VITE_API_BASE_URL=https://api.dev.example.com
+VITE_API_BASE_URL=/api
+
+# Proxy Target (Where the /api requests are forwarded to) 改完后需要重启
+VITE_API_PROXY_TARGET=http://localhost:8080
# Other development-specific variables
VITE_APP_TITLE=My App (Development)
-VITE_DEBUG_MODE=true
\ No newline at end of file
+VITE_DEBUG_MODE=true
+
+# API Signature Secret
+VITE_API_SECRET='yts@2025#secure'
diff --git a/.env.production b/.env.production
index d04be5b..6e0b641 100644
--- a/.env.production
+++ b/.env.production
@@ -5,4 +5,7 @@ VITE_API_BASE_URL=https://api.example.com
# Other production-specific variables
VITE_APP_TITLE=My App
-VITE_DEBUG_MODE=false
\ No newline at end of file
+VITE_DEBUG_MODE=false
+
+# API Signature Secret
+VITE_API_SECRET=yts@2025#secure
diff --git a/docs/api1.md b/docs/api1.md
new file mode 100644
index 0000000..930d650
--- /dev/null
+++ b/docs/api1.md
@@ -0,0 +1,184 @@
+---
+title: 艺考招生管理系统 API
+language_tabs:
+ - shell: Shell
+ - http: HTTP
+ - javascript: JavaScript
+ - ruby: Ruby
+ - python: Python
+ - php: PHP
+ - java: Java
+ - go: Go
+toc_footers: []
+includes: []
+search: true
+code_clipboard: true
+highlight_theme: darkula
+headingLevel: 2
+generator: "@tarslib/widdershins v4.0.30"
+
+---
+
+# 艺考招生管理系统 API
+
+提供用户认证、院校专业、历年招生、计算专业的管理接口
+
+Base URLs:
+
+* 开发环境: http://localhost:8080/api
+
+# Authentication
+
+# 认证
+
+## GET 获取当前登录用户信息
+
+GET /auth/info
+
+> 返回示例
+
+> 200 Response
+
+```
+{"code":0,"data":null,"message":"string"}
+```
+
+### 返回结果
+
+|状态码|状态码含义|说明|数据模型|
+|---|---|---|---|
+|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|OK|[common.Response](#schemacommon.response)|
+
+## POST 用户登录
+
+POST /auth/login
+
+> Body 请求参数
+
+```json
+{
+ "username": "18639433190",
+ "password": "123456"
+}
+```
+
+### 请求参数
+
+|名称|位置|类型|必选|说明|
+|---|---|---|---|---|
+|body|body|[controller.LoginRequest](#schemacontroller.loginrequest)| 是 |none|
+
+> 返回示例
+
+> 200 Response
+
+```json
+{
+ "code": 200,
+ "message": "success",
+ "data": {
+ "token": "140a1289-1a0a-4c14-82f6-ba1feb36351a",
+ "user": {
+ "id": "1779515858733772802",
+ "username": "dyT3c2tV",
+ "realname": "用户-dyT3c2tV",
+ "avatar": "",
+ "phone": "18639433190",
+ "email": "",
+ "token": "140a1289-1a0a-4c14-82f6-ba1feb36351a"
+ }
+ }
+}
+```
+
+### 返回结果
+
+|状态码|状态码含义|说明|数据模型|
+|---|---|---|---|
+|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|OK|Inline|
+
+### 返回数据结构
+
+状态码 **200**
+
+|名称|类型|必选|约束|中文名|说明|
+|---|---|---|---|---|---|
+|» code|integer|true|none|状态码|none|
+|» message|string|true|none|状态描述|none|
+|» data|object|true|none||none|
+|»» token|string|true|none|登录TOKEN|none|
+|»» user|object|true|none||none|
+|»»» id|string|true|none|用户ID|none|
+|»»» username|string|true|none|用户名|none|
+|»»» realname|string|true|none||none|
+|»»» avatar|string|true|none|头像|none|
+|»»» phone|string|true|none|手机号|none|
+|»»» email|string|true|none||none|
+|»»» token|string|true|none||none|
+
+## POST 用户登出
+
+POST /auth/logout
+
+> 返回示例
+
+> 200 Response
+
+```
+{"code":200,"message":"success","data":null}
+```
+
+### 返回结果
+
+|状态码|状态码含义|说明|数据模型|
+|---|---|---|---|
+|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|OK|[common.Response](#schemacommon.response)|
+
+# 数据模型
+
+
common.Response
+
+
+
+
+
+
+```json
+{
+ "code": 0,
+ "data": null,
+ "message": "string"
+}
+
+```
+
+### 属性
+
+|名称|类型|必选|约束|中文名|说明|
+|---|---|---|---|---|---|
+|code|integer|false|none||none|
+|data|any|false|none||none|
+|message|string|false|none||none|
+
+controller.LoginRequest
+
+
+
+
+
+
+```json
+{
+ "password": "string",
+ "username": "string"
+}
+
+```
+
+### 属性
+
+|名称|类型|必选|约束|中文名|说明|
+|---|---|---|---|---|---|
+|password|string|true|none||none|
+|username|string|true|none||none|
+
diff --git a/package.json b/package.json
index 3520630..00bea82 100644
--- a/package.json
+++ b/package.json
@@ -21,6 +21,8 @@
"@unhead/vue": "catalog:frontend",
"@unocss/reset": "catalog:frontend",
"@vueuse/core": "catalog:frontend",
+ "axios": "^1.13.2",
+ "crypto-js": "^4.2.0",
"nprogress": "catalog:frontend",
"pinia": "catalog:frontend",
"vue": "catalog:frontend",
@@ -33,6 +35,7 @@
"@iconify-json/carbon": "catalog:dev",
"@intlify/unplugin-vue-i18n": "catalog:build",
"@shikijs/markdown-it": "catalog:build",
+ "@types/crypto-js": "^4.2.2",
"@types/markdown-it-link-attributes": "catalog:types",
"@types/nprogress": "catalog:types",
"@unocss/eslint-config": "catalog:build",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 7692b34..8ad8b96 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -177,6 +177,12 @@ importers:
'@vueuse/core':
specifier: catalog:frontend
version: 13.0.0(vue@3.5.13(typescript@5.8.2))
+ axios:
+ specifier: ^1.13.2
+ version: 1.13.2
+ crypto-js:
+ specifier: ^4.2.0
+ version: 4.2.0
nprogress:
specifier: catalog:frontend
version: 0.2.0
@@ -208,6 +214,9 @@ importers:
'@shikijs/markdown-it':
specifier: catalog:build
version: 3.2.1(markdown-it-async@2.2.0)
+ '@types/crypto-js':
+ specifier: ^4.2.2
+ version: 4.2.2
'@types/markdown-it-link-attributes':
specifier: catalog:types
version: 3.0.5
@@ -1862,6 +1871,9 @@ packages:
'@tybys/wasm-util@0.9.0':
resolution: {integrity: sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==}
+ '@types/crypto-js@4.2.2':
+ resolution: {integrity: sha512-sDOLlVbHhXpAUAL0YHDUUwDZf3iN4Bwi4W6a0W0b+QcAezUbRtH4FVb+9J4h+XFPW7l/gQ9F8qC7P+Ec4k8QVQ==}
+
'@types/debug@4.1.12':
resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==}
@@ -2656,9 +2668,6 @@ packages:
argparse@2.0.1:
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
- array-buffer-byte-length@1.0.0:
- resolution: {integrity: sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==}
-
array-buffer-byte-length@1.0.2:
resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==}
engines: {node: '>= 0.4'}
@@ -2682,10 +2691,6 @@ packages:
resolution: {integrity: sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==}
engines: {node: '>= 0.4'}
- arraybuffer.prototype.slice@1.0.2:
- resolution: {integrity: sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==}
- engines: {node: '>= 0.4'}
-
arraybuffer.prototype.slice@1.0.4:
resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==}
engines: {node: '>= 0.4'}
@@ -2734,10 +2739,6 @@ packages:
peerDependencies:
postcss: ^8.1.0
- available-typed-arrays@1.0.5:
- resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==}
- engines: {node: '>= 0.4'}
-
available-typed-arrays@1.0.7:
resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==}
engines: {node: '>= 0.4'}
@@ -2748,6 +2749,9 @@ packages:
aws4@1.12.0:
resolution: {integrity: sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==}
+ axios@1.13.2:
+ resolution: {integrity: sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==}
+
babel-plugin-polyfill-corejs2@0.3.3:
resolution: {integrity: sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==}
peerDependencies:
@@ -3081,6 +3085,9 @@ packages:
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
engines: {node: '>= 8'}
+ crypto-js@4.2.0:
+ resolution: {integrity: sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==}
+
crypto-random-string@2.0.0:
resolution: {integrity: sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==}
engines: {node: '>=8'}
@@ -3206,10 +3213,6 @@ packages:
resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==}
engines: {node: '>=12'}
- define-properties@1.2.0:
- resolution: {integrity: sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==}
- engines: {node: '>= 0.4'}
-
define-properties@1.2.1:
resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==}
engines: {node: '>= 0.4'}
@@ -3336,10 +3339,6 @@ packages:
error-stack-parser-es@1.0.5:
resolution: {integrity: sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA==}
- es-abstract@1.22.2:
- resolution: {integrity: sha512-YoxfFcDmhjOgWPWsV13+2RNjq1F6UQnfs+8TftwNqtzlmFzEXvlUwdrNrYeaizfjQzRMxkZ6ElWMOJIFKdVqwA==}
- engines: {node: '>= 0.4'}
-
es-abstract@1.24.1:
resolution: {integrity: sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw==}
engines: {node: '>= 0.4'}
@@ -3367,10 +3366,6 @@ packages:
resolution: {integrity: sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==}
engines: {node: '>= 0.4'}
- es-to-primitive@1.2.1:
- resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==}
- engines: {node: '>= 0.4'}
-
es-to-primitive@1.3.0:
resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==}
engines: {node: '>= 0.4'}
@@ -3808,6 +3803,15 @@ packages:
flatted@3.3.1:
resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==}
+ follow-redirects@1.15.11:
+ resolution: {integrity: sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==}
+ engines: {node: '>=4.0'}
+ peerDependencies:
+ debug: '*'
+ peerDependenciesMeta:
+ debug:
+ optional: true
+
for-each@0.3.3:
resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==}
@@ -3822,6 +3826,10 @@ packages:
resolution: {integrity: sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==}
engines: {node: '>= 6'}
+ form-data@4.0.5:
+ resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==}
+ engines: {node: '>= 6'}
+
forwarded@0.2.0:
resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==}
engines: {node: '>= 0.6'}
@@ -3848,10 +3856,6 @@ packages:
function-bind@1.1.2:
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
- function.prototype.name@1.1.6:
- resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==}
- engines: {node: '>= 0.4'}
-
function.prototype.name@1.1.8:
resolution: {integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==}
engines: {node: '>= 0.4'}
@@ -3901,10 +3905,6 @@ packages:
resolution: {integrity: sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==}
engines: {node: '>=18'}
- get-symbol-description@1.0.0:
- resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==}
- engines: {node: '>= 0.4'}
-
get-symbol-description@1.1.0:
resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==}
engines: {node: '>= 0.4'}
@@ -3955,10 +3955,6 @@ packages:
resolution: {integrity: sha512-iInW14XItCXET01CQFqudPOWP2jYMl7T+QRQT+UNcR/iQncN/F0UNpgd76iFkBPgNQb4+X3LV9tLJYzwh+Gl3A==}
engines: {node: '>=18'}
- globalthis@1.0.3:
- resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==}
- engines: {node: '>= 0.4'}
-
globalthis@1.0.4:
resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==}
engines: {node: '>= 0.4'}
@@ -3994,10 +3990,6 @@ packages:
has-property-descriptors@1.0.2:
resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==}
- has-proto@1.0.1:
- resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==}
- engines: {node: '>= 0.4'}
-
has-proto@1.2.0:
resolution: {integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==}
engines: {node: '>= 0.4'}
@@ -4010,10 +4002,6 @@ packages:
resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==}
engines: {node: '>= 0.4'}
- has@1.0.3:
- resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==}
- engines: {node: '>= 0.4.0'}
-
hasown@2.0.2:
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
engines: {node: '>= 0.4'}
@@ -4148,10 +4136,6 @@ packages:
resolution: {integrity: sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==}
engines: {node: '>=10'}
- internal-slot@1.0.5:
- resolution: {integrity: sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==}
- engines: {node: '>= 0.4'}
-
internal-slot@1.1.0:
resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==}
engines: {node: '>= 0.4'}
@@ -4160,9 +4144,6 @@ packages:
resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==}
engines: {node: '>= 0.10'}
- is-array-buffer@3.0.2:
- resolution: {integrity: sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==}
-
is-array-buffer@3.0.5:
resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==}
engines: {node: '>= 0.4'}
@@ -4174,9 +4155,6 @@ packages:
resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==}
engines: {node: '>= 0.4'}
- is-bigint@1.0.4:
- resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==}
-
is-bigint@1.1.0:
resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==}
engines: {node: '>= 0.4'}
@@ -4185,10 +4163,6 @@ packages:
resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
engines: {node: '>=8'}
- is-boolean-object@1.1.2:
- resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==}
- engines: {node: '>= 0.4'}
-
is-boolean-object@1.2.2:
resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==}
engines: {node: '>= 0.4'}
@@ -4278,18 +4252,10 @@ packages:
is-module@1.0.0:
resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==}
- is-negative-zero@2.0.2:
- resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==}
- engines: {node: '>= 0.4'}
-
is-negative-zero@2.0.3:
resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==}
engines: {node: '>= 0.4'}
- is-number-object@1.0.7:
- resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==}
- engines: {node: '>= 0.4'}
-
is-number-object@1.1.1:
resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==}
engines: {node: '>= 0.4'}
@@ -4313,10 +4279,6 @@ packages:
is-potential-custom-element-name@1.0.1:
resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==}
- is-regex@1.1.4:
- resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==}
- engines: {node: '>= 0.4'}
-
is-regex@1.2.1:
resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==}
engines: {node: '>= 0.4'}
@@ -4329,9 +4291,6 @@ packages:
resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==}
engines: {node: '>= 0.4'}
- is-shared-array-buffer@1.0.2:
- resolution: {integrity: sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==}
-
is-shared-array-buffer@1.0.4:
resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==}
engines: {node: '>= 0.4'}
@@ -4348,10 +4307,6 @@ packages:
resolution: {integrity: sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==}
engines: {node: '>=18'}
- is-string@1.0.7:
- resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==}
- engines: {node: '>= 0.4'}
-
is-string@1.1.1:
resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==}
engines: {node: '>= 0.4'}
@@ -4364,10 +4319,6 @@ packages:
resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==}
engines: {node: '>= 0.4'}
- is-typed-array@1.1.12:
- resolution: {integrity: sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==}
- engines: {node: '>= 0.4'}
-
is-typed-array@1.1.15:
resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==}
engines: {node: '>= 0.4'}
@@ -4387,9 +4338,6 @@ packages:
resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==}
engines: {node: '>= 0.4'}
- is-weakref@1.0.2:
- resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==}
-
is-weakref@1.1.1:
resolution: {integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==}
engines: {node: '>= 0.4'}
@@ -4982,10 +4930,6 @@ packages:
resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==}
engines: {node: '>= 0.4'}
- object.assign@4.1.4:
- resolution: {integrity: sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==}
- engines: {node: '>= 0.4'}
-
object.assign@4.1.7:
resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==}
engines: {node: '>= 0.4'}
@@ -5325,6 +5269,9 @@ packages:
proxy-from-env@1.0.0:
resolution: {integrity: sha512-F2JHgJQ1iqwnHDcQjVBsq3n/uoaFL+iPW/eAeL7kVxy/2RrWaN4WroKjjvbsoRtv0ftelNyC01bjRhn/bhcf4A==}
+ proxy-from-env@1.1.0:
+ resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
+
pump@3.0.0:
resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==}
@@ -5425,10 +5372,6 @@ packages:
resolution: {integrity: sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==}
hasBin: true
- regexp.prototype.flags@1.5.1:
- resolution: {integrity: sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==}
- engines: {node: '>= 0.4'}
-
regexp.prototype.flags@1.5.4:
resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==}
engines: {node: '>= 0.4'}
@@ -5519,10 +5462,6 @@ packages:
rxjs@7.8.1:
resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==}
- safe-array-concat@1.0.1:
- resolution: {integrity: sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q==}
- engines: {node: '>=0.4'}
-
safe-array-concat@1.1.3:
resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==}
engines: {node: '>=0.4'}
@@ -5537,9 +5476,6 @@ packages:
resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==}
engines: {node: '>= 0.4'}
- safe-regex-test@1.0.0:
- resolution: {integrity: sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==}
-
safe-regex-test@1.1.0:
resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==}
engines: {node: '>= 0.4'}
@@ -5593,10 +5529,6 @@ packages:
resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==}
engines: {node: '>= 0.4'}
- set-function-name@2.0.1:
- resolution: {integrity: sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==}
- engines: {node: '>= 0.4'}
-
set-function-name@2.0.2:
resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==}
engines: {node: '>= 0.4'}
@@ -5775,20 +5707,10 @@ packages:
resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==}
engines: {node: '>= 0.4'}
- string.prototype.trim@1.2.8:
- resolution: {integrity: sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==}
- engines: {node: '>= 0.4'}
-
- string.prototype.trimend@1.0.7:
- resolution: {integrity: sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==}
-
string.prototype.trimend@1.0.9:
resolution: {integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==}
engines: {node: '>= 0.4'}
- string.prototype.trimstart@1.0.7:
- resolution: {integrity: sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==}
-
string.prototype.trimstart@1.0.8:
resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==}
engines: {node: '>= 0.4'}
@@ -6050,33 +5972,18 @@ packages:
resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==}
engines: {node: '>= 0.6'}
- typed-array-buffer@1.0.0:
- resolution: {integrity: sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==}
- engines: {node: '>= 0.4'}
-
typed-array-buffer@1.0.3:
resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==}
engines: {node: '>= 0.4'}
- typed-array-byte-length@1.0.0:
- resolution: {integrity: sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==}
- engines: {node: '>= 0.4'}
-
typed-array-byte-length@1.0.3:
resolution: {integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==}
engines: {node: '>= 0.4'}
- typed-array-byte-offset@1.0.0:
- resolution: {integrity: sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==}
- engines: {node: '>= 0.4'}
-
typed-array-byte-offset@1.0.4:
resolution: {integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==}
engines: {node: '>= 0.4'}
- typed-array-length@1.0.4:
- resolution: {integrity: sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==}
-
typed-array-length@1.0.7:
resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==}
engines: {node: '>= 0.4'}
@@ -6097,9 +6004,6 @@ packages:
engines: {node: '>=0.8.0'}
hasBin: true
- unbox-primitive@1.0.2:
- resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==}
-
unbox-primitive@1.1.0:
resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==}
engines: {node: '>= 0.4'}
@@ -6535,9 +6439,6 @@ packages:
whatwg-url@7.1.0:
resolution: {integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==}
- which-boxed-primitive@1.0.2:
- resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==}
-
which-boxed-primitive@1.1.1:
resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==}
engines: {node: '>= 0.4'}
@@ -6550,10 +6451,6 @@ packages:
resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==}
engines: {node: '>= 0.4'}
- which-typed-array@1.1.11:
- resolution: {integrity: sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==}
- engines: {node: '>= 0.4'}
-
which-typed-array@1.1.19:
resolution: {integrity: sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==}
engines: {node: '>= 0.4'}
@@ -8246,6 +8143,8 @@ snapshots:
tslib: 2.8.1
optional: true
+ '@types/crypto-js@4.2.2': {}
+
'@types/debug@4.1.12':
dependencies:
'@types/ms': 0.7.34
@@ -8506,7 +8405,7 @@ snapshots:
'@unocss/eslint-plugin@65.4.0(eslint@9.23.0(jiti@1.21.7))(typescript@5.8.2)':
dependencies:
- '@typescript-eslint/utils': 8.28.0(eslint@9.23.0(jiti@1.21.7))(typescript@5.8.2)
+ '@typescript-eslint/utils': 8.50.0(eslint@9.23.0(jiti@1.21.7))(typescript@5.8.2)
'@unocss/config': 65.4.0
'@unocss/core': 65.4.0
magic-string: 0.30.17
@@ -9280,11 +9179,6 @@ snapshots:
argparse@2.0.1: {}
- array-buffer-byte-length@1.0.0:
- dependencies:
- call-bind: 1.0.7
- is-array-buffer: 3.0.2
-
array-buffer-byte-length@1.0.2:
dependencies:
call-bound: 1.0.4
@@ -9327,16 +9221,6 @@ snapshots:
es-abstract: 1.24.1
es-shim-unscopables: 1.1.0
- arraybuffer.prototype.slice@1.0.2:
- dependencies:
- array-buffer-byte-length: 1.0.0
- call-bind: 1.0.7
- define-properties: 1.2.0
- es-abstract: 1.22.2
- get-intrinsic: 1.3.0
- is-array-buffer: 3.0.2
- is-shared-array-buffer: 1.0.2
-
arraybuffer.prototype.slice@1.0.4:
dependencies:
array-buffer-byte-length: 1.0.2
@@ -9385,8 +9269,6 @@ snapshots:
postcss: 8.5.3
postcss-value-parser: 4.2.0
- available-typed-arrays@1.0.5: {}
-
available-typed-arrays@1.0.7:
dependencies:
possible-typed-array-names: 1.1.0
@@ -9395,6 +9277,14 @@ snapshots:
aws4@1.12.0: {}
+ axios@1.13.2:
+ dependencies:
+ follow-redirects: 1.15.11
+ form-data: 4.0.5
+ proxy-from-env: 1.1.0
+ transitivePeerDependencies:
+ - debug
+
babel-plugin-polyfill-corejs2@0.3.3(@babel/core@7.25.2):
dependencies:
'@babel/compat-data': 7.25.2
@@ -9736,6 +9626,8 @@ snapshots:
shebang-command: 2.0.0
which: 2.0.2
+ crypto-js@4.2.0: {}
+
crypto-random-string@2.0.0: {}
css-select@5.1.0:
@@ -9892,11 +9784,6 @@ snapshots:
define-lazy-prop@3.0.0: {}
- define-properties@1.2.0:
- dependencies:
- has-property-descriptors: 1.0.2
- object-keys: 1.1.1
-
define-properties@1.2.1:
dependencies:
define-data-property: 1.1.4
@@ -10015,48 +9902,6 @@ snapshots:
error-stack-parser-es@1.0.5: {}
- es-abstract@1.22.2:
- dependencies:
- array-buffer-byte-length: 1.0.0
- arraybuffer.prototype.slice: 1.0.2
- available-typed-arrays: 1.0.5
- call-bind: 1.0.7
- es-set-tostringtag: 2.1.0
- es-to-primitive: 1.2.1
- function.prototype.name: 1.1.6
- get-intrinsic: 1.3.0
- get-symbol-description: 1.0.0
- globalthis: 1.0.3
- gopd: 1.2.0
- has: 1.0.3
- has-property-descriptors: 1.0.2
- has-proto: 1.0.1
- has-symbols: 1.1.0
- internal-slot: 1.0.5
- is-array-buffer: 3.0.2
- is-callable: 1.2.7
- is-negative-zero: 2.0.2
- is-regex: 1.1.4
- is-shared-array-buffer: 1.0.2
- is-string: 1.0.7
- is-typed-array: 1.1.12
- is-weakref: 1.0.2
- object-inspect: 1.13.3
- object-keys: 1.1.1
- object.assign: 4.1.4
- regexp.prototype.flags: 1.5.1
- safe-array-concat: 1.0.1
- safe-regex-test: 1.0.0
- string.prototype.trim: 1.2.8
- string.prototype.trimend: 1.0.7
- string.prototype.trimstart: 1.0.7
- typed-array-buffer: 1.0.0
- typed-array-byte-length: 1.0.0
- typed-array-byte-offset: 1.0.0
- typed-array-length: 1.0.4
- unbox-primitive: 1.0.2
- which-typed-array: 1.1.11
-
es-abstract@1.24.1:
dependencies:
array-buffer-byte-length: 1.0.2
@@ -10135,12 +9980,6 @@ snapshots:
dependencies:
hasown: 2.0.2
- es-to-primitive@1.2.1:
- dependencies:
- is-callable: 1.2.7
- is-date-object: 1.0.5
- is-symbol: 1.0.4
-
es-to-primitive@1.3.0:
dependencies:
is-callable: 1.2.7
@@ -10785,6 +10624,8 @@ snapshots:
flatted@3.3.1: {}
+ follow-redirects@1.15.11: {}
+
for-each@0.3.3:
dependencies:
is-callable: 1.2.7
@@ -10802,6 +10643,14 @@ snapshots:
es-set-tostringtag: 2.1.0
mime-types: 2.1.35
+ form-data@4.0.5:
+ dependencies:
+ asynckit: 0.4.0
+ combined-stream: 1.0.8
+ es-set-tostringtag: 2.1.0
+ hasown: 2.0.2
+ mime-types: 2.1.35
+
forwarded@0.2.0: {}
fraction.js@5.3.4: {}
@@ -10822,13 +10671,6 @@ snapshots:
function-bind@1.1.2: {}
- function.prototype.name@1.1.6:
- dependencies:
- call-bind: 1.0.7
- define-properties: 1.2.0
- es-abstract: 1.22.2
- functions-have-names: 1.2.3
-
function.prototype.name@1.1.8:
dependencies:
call-bind: 1.0.8
@@ -10881,11 +10723,6 @@ snapshots:
'@sec-ant/readable-stream': 0.4.1
is-stream: 4.0.1
- get-symbol-description@1.0.0:
- dependencies:
- call-bind: 1.0.7
- get-intrinsic: 1.3.0
-
get-symbol-description@1.1.0:
dependencies:
call-bound: 1.0.4
@@ -10941,10 +10778,6 @@ snapshots:
globals@16.0.0: {}
- globalthis@1.0.3:
- dependencies:
- define-properties: 1.2.0
-
globalthis@1.0.4:
dependencies:
define-properties: 1.2.1
@@ -10977,8 +10810,6 @@ snapshots:
dependencies:
es-define-property: 1.0.1
- has-proto@1.0.1: {}
-
has-proto@1.2.0:
dependencies:
dunder-proto: 1.0.1
@@ -10989,10 +10820,6 @@ snapshots:
dependencies:
has-symbols: 1.1.0
- has@1.0.3:
- dependencies:
- function-bind: 1.1.2
-
hasown@2.0.2:
dependencies:
function-bind: 1.1.2
@@ -11159,12 +10986,6 @@ snapshots:
ini@2.0.0: {}
- internal-slot@1.0.5:
- dependencies:
- get-intrinsic: 1.3.0
- has: 1.0.3
- side-channel: 1.1.0
-
internal-slot@1.1.0:
dependencies:
es-errors: 1.3.0
@@ -11173,12 +10994,6 @@ snapshots:
ipaddr.js@1.9.1: {}
- is-array-buffer@3.0.2:
- dependencies:
- call-bind: 1.0.7
- get-intrinsic: 1.3.0
- is-typed-array: 1.1.12
-
is-array-buffer@3.0.5:
dependencies:
call-bind: 1.0.8
@@ -11195,10 +11010,6 @@ snapshots:
has-tostringtag: 1.0.2
safe-regex-test: 1.1.0
- is-bigint@1.0.4:
- dependencies:
- has-bigints: 1.0.2
-
is-bigint@1.1.0:
dependencies:
has-bigints: 1.0.2
@@ -11207,11 +11018,6 @@ snapshots:
dependencies:
binary-extensions: 2.2.0
- is-boolean-object@1.1.2:
- dependencies:
- call-bind: 1.0.7
- has-tostringtag: 1.0.2
-
is-boolean-object@1.2.2:
dependencies:
call-bound: 1.0.4
@@ -11291,14 +11097,8 @@ snapshots:
is-module@1.0.0: {}
- is-negative-zero@2.0.2: {}
-
is-negative-zero@2.0.3: {}
- is-number-object@1.0.7:
- dependencies:
- has-tostringtag: 1.0.2
-
is-number-object@1.1.1:
dependencies:
call-bound: 1.0.4
@@ -11314,11 +11114,6 @@ snapshots:
is-potential-custom-element-name@1.0.1: {}
- is-regex@1.1.4:
- dependencies:
- call-bind: 1.0.7
- has-tostringtag: 1.0.2
-
is-regex@1.2.1:
dependencies:
call-bound: 1.0.4
@@ -11330,10 +11125,6 @@ snapshots:
is-set@2.0.3: {}
- is-shared-array-buffer@1.0.2:
- dependencies:
- call-bind: 1.0.7
-
is-shared-array-buffer@1.0.4:
dependencies:
call-bound: 1.0.4
@@ -11344,10 +11135,6 @@ snapshots:
is-stream@4.0.1: {}
- is-string@1.0.7:
- dependencies:
- has-tostringtag: 1.0.2
-
is-string@1.1.1:
dependencies:
call-bound: 1.0.4
@@ -11363,10 +11150,6 @@ snapshots:
has-symbols: 1.1.0
safe-regex-test: 1.1.0
- is-typed-array@1.1.12:
- dependencies:
- which-typed-array: 1.1.11
-
is-typed-array@1.1.15:
dependencies:
which-typed-array: 1.1.19
@@ -11379,10 +11162,6 @@ snapshots:
is-weakmap@2.0.2: {}
- is-weakref@1.0.2:
- dependencies:
- call-bind: 1.0.7
-
is-weakref@1.1.1:
dependencies:
call-bound: 1.0.4
@@ -12134,13 +11913,6 @@ snapshots:
object-keys@1.1.1: {}
- object.assign@4.1.4:
- dependencies:
- call-bind: 1.0.7
- define-properties: 1.2.0
- has-symbols: 1.1.0
- object-keys: 1.1.1
-
object.assign@4.1.7:
dependencies:
call-bind: 1.0.8
@@ -12465,6 +12237,8 @@ snapshots:
proxy-from-env@1.0.0: {}
+ proxy-from-env@1.1.0: {}
+
pump@3.0.0:
dependencies:
end-of-stream: 1.4.4
@@ -12582,12 +12356,6 @@ snapshots:
regexp-tree@0.1.27: {}
- regexp.prototype.flags@1.5.1:
- dependencies:
- call-bind: 1.0.7
- define-properties: 1.2.0
- set-function-name: 2.0.1
-
regexp.prototype.flags@1.5.4:
dependencies:
call-bind: 1.0.8
@@ -12699,13 +12467,6 @@ snapshots:
dependencies:
tslib: 2.8.1
- safe-array-concat@1.0.1:
- dependencies:
- call-bind: 1.0.7
- get-intrinsic: 1.3.0
- has-symbols: 1.1.0
- isarray: 2.0.5
-
safe-array-concat@1.1.3:
dependencies:
call-bind: 1.0.8
@@ -12723,12 +12484,6 @@ snapshots:
es-errors: 1.3.0
isarray: 2.0.5
- safe-regex-test@1.0.0:
- dependencies:
- call-bind: 1.0.7
- get-intrinsic: 1.3.0
- is-regex: 1.1.4
-
safe-regex-test@1.1.0:
dependencies:
call-bound: 1.0.4
@@ -12802,12 +12557,6 @@ snapshots:
gopd: 1.2.0
has-property-descriptors: 1.0.2
- set-function-name@2.0.1:
- dependencies:
- define-data-property: 1.1.4
- functions-have-names: 1.2.3
- has-property-descriptors: 1.0.2
-
set-function-name@2.0.2:
dependencies:
define-data-property: 1.1.4
@@ -13014,13 +12763,13 @@ snapshots:
string.prototype.matchall@4.0.8:
dependencies:
- call-bind: 1.0.7
- define-properties: 1.2.0
- es-abstract: 1.22.2
+ call-bind: 1.0.8
+ define-properties: 1.2.1
+ es-abstract: 1.24.1
get-intrinsic: 1.3.0
has-symbols: 1.1.0
- internal-slot: 1.0.5
- regexp.prototype.flags: 1.5.1
+ internal-slot: 1.1.0
+ regexp.prototype.flags: 1.5.4
side-channel: 1.1.0
string.prototype.trim@1.2.10:
@@ -13033,18 +12782,6 @@ snapshots:
es-object-atoms: 1.1.1
has-property-descriptors: 1.0.2
- string.prototype.trim@1.2.8:
- dependencies:
- call-bind: 1.0.7
- define-properties: 1.2.0
- es-abstract: 1.22.2
-
- string.prototype.trimend@1.0.7:
- dependencies:
- call-bind: 1.0.7
- define-properties: 1.2.0
- es-abstract: 1.22.2
-
string.prototype.trimend@1.0.9:
dependencies:
call-bind: 1.0.8
@@ -13052,12 +12789,6 @@ snapshots:
define-properties: 1.2.1
es-object-atoms: 1.1.1
- string.prototype.trimstart@1.0.7:
- dependencies:
- call-bind: 1.0.7
- define-properties: 1.2.0
- es-abstract: 1.22.2
-
string.prototype.trimstart@1.0.8:
dependencies:
call-bind: 1.0.8
@@ -13336,25 +13067,12 @@ snapshots:
media-typer: 0.3.0
mime-types: 2.1.35
- typed-array-buffer@1.0.0:
- dependencies:
- call-bind: 1.0.7
- get-intrinsic: 1.3.0
- is-typed-array: 1.1.12
-
typed-array-buffer@1.0.3:
dependencies:
call-bound: 1.0.4
es-errors: 1.3.0
is-typed-array: 1.1.15
- typed-array-byte-length@1.0.0:
- dependencies:
- call-bind: 1.0.7
- for-each: 0.3.3
- has-proto: 1.0.1
- is-typed-array: 1.1.12
-
typed-array-byte-length@1.0.3:
dependencies:
call-bind: 1.0.8
@@ -13363,14 +13081,6 @@ snapshots:
has-proto: 1.2.0
is-typed-array: 1.1.15
- typed-array-byte-offset@1.0.0:
- dependencies:
- available-typed-arrays: 1.0.5
- call-bind: 1.0.7
- for-each: 0.3.3
- has-proto: 1.0.1
- is-typed-array: 1.1.12
-
typed-array-byte-offset@1.0.4:
dependencies:
available-typed-arrays: 1.0.7
@@ -13381,12 +13091,6 @@ snapshots:
is-typed-array: 1.1.15
reflect.getprototypeof: 1.0.10
- typed-array-length@1.0.4:
- dependencies:
- call-bind: 1.0.7
- for-each: 0.3.3
- is-typed-array: 1.1.12
-
typed-array-length@1.0.7:
dependencies:
call-bind: 1.0.8
@@ -13404,13 +13108,6 @@ snapshots:
uglify-js@3.17.4: {}
- unbox-primitive@1.0.2:
- dependencies:
- call-bind: 1.0.7
- has-bigints: 1.0.2
- has-symbols: 1.1.0
- which-boxed-primitive: 1.0.2
-
unbox-primitive@1.1.0:
dependencies:
call-bound: 1.0.4
@@ -13988,14 +13685,6 @@ snapshots:
tr46: 1.0.1
webidl-conversions: 4.0.2
- which-boxed-primitive@1.0.2:
- dependencies:
- is-bigint: 1.0.4
- is-boolean-object: 1.1.2
- is-number-object: 1.0.7
- is-string: 1.0.7
- is-symbol: 1.0.4
-
which-boxed-primitive@1.1.1:
dependencies:
is-bigint: 1.1.0
@@ -14027,14 +13716,6 @@ snapshots:
is-weakmap: 2.0.2
is-weakset: 2.0.4
- which-typed-array@1.1.11:
- dependencies:
- available-typed-arrays: 1.0.5
- call-bind: 1.0.7
- for-each: 0.3.3
- gopd: 1.2.0
- has-tostringtag: 1.0.2
-
which-typed-array@1.1.19:
dependencies:
available-typed-arrays: 1.0.7
diff --git a/project_codebase.md b/project_codebase.md
new file mode 100644
index 0000000..8508b23
--- /dev/null
+++ b/project_codebase.md
@@ -0,0 +1,31 @@
+# Project Codebase
+
+## Function Overview
+
+### `src/utils/message.ts`
+- **Purpose**: Provides a global interface for showing toast messages.
+- **Methods**: `success(msg, duration)`, `error(msg, duration)`, `warning(msg, duration)`, `info(msg, duration)`.
+- **Implementation**: Programmatically mounts `WMessage.vue`.
+
+### `src/service/request/index.ts`
+- **Purpose**: Encapsulates Axios for API requests.
+- **Features**:
+ - Request Interceptor:
+ - Adds `token` to headers.
+ - Adds `X-App-Sign` (MD5(timestamp + secret)) and `X-App-Timestamp` headers for security.
+ - Starts `NProgress`.
+ - Response Interceptor: Unwraps `data`; handles global errors (401, 403, 500); stops `NProgress`.
+ - Config: `showLoading`, `showError`.
+
+### `src/service/api/auth.ts`
+- **Purpose**: API definitions for authentication.
+- **Methods**: `login`, `logout`, `getUserInfo`.
+
+### `src/stores/user.ts`
+- **Purpose**: Manages user session state.
+- **State**: `token`, `userInfo`.
+- **Actions**: `login` (calls API), `logout`, `setToken`, `setUserInfo`.
+- **Persistence**: Loads/Saves state to `localStorage`.
+
+### `src/components/TheNavigation.vue`
+- **Updated**: Added integration with `userStore` for login/logout and `message` for notifications.
diff --git a/project_doing.md b/project_doing.md
new file mode 100644
index 0000000..6093cb5
--- /dev/null
+++ b/project_doing.md
@@ -0,0 +1,14 @@
+# Project Doing
+
+## 2025-12-18
+
+### [Task 1] Global Message Component, API Encapsulation, and Login/Logout Integration
+- **Time**: 2025-12-18
+- **Goal**: Implement global message, encapsulate axios, and integrate login.
+- **Scope**:
+ - `src/components/ui/WMessage.vue` (Review/Update)
+ - `package.json` (Add axios)
+ - `src/service/request/index.ts` (Create)
+ - `src/service/api/auth.ts` (Create)
+ - `src/stores/user.ts` (Update)
+ - `src/components/TheNavigation.vue` (Update)
diff --git a/project_index.md b/project_index.md
new file mode 100644
index 0000000..894da7a
--- /dev/null
+++ b/project_index.md
@@ -0,0 +1,8 @@
+# Project File Index
+
+- `src/utils/message.ts`: Global message utility.
+- `src/service/request/index.ts`: Axios wrapper.
+- `src/service/api/auth.ts`: Authentication API.
+- `src/stores/user.ts`: User Pinia store.
+- `src/components/ui/WMessage.vue`: Message component UI.
+- `src/components/TheNavigation.vue`: Main navigation component.
diff --git a/project_task.md b/project_task.md
new file mode 100644
index 0000000..0d14a0f
--- /dev/null
+++ b/project_task.md
@@ -0,0 +1,9 @@
+# Project Tasks
+
+- [ ] [Task 1] Global Message Component, API Encapsulation, and Login/Logout Integration
+ - [ ] Check/Implement Global Message Component
+ - [ ] Install axios
+ - [ ] Create `src/service/request/index.ts`
+ - [ ] Create `src/service/api/auth.ts`
+ - [ ] Update `src/stores/user.ts` (Pinia + Persistence)
+ - [ ] Integrate Login/Logout in `TheNavigation.vue`
diff --git a/src/auto-imports.d.ts b/src/auto-imports.d.ts
index 842a7b7..d6ad0a4 100644
--- a/src/auto-imports.d.ts
+++ b/src/auto-imports.d.ts
@@ -324,6 +324,9 @@ declare global {
// @ts-ignore
export type { RequestConfig, RequestResponse } from './composables/request'
import('./composables/request')
+ // @ts-ignore
+ export type { UserInfo } from './stores/user'
+ import('./stores/user')
}
// for vue template auto import
diff --git a/src/components/TheNavigation.vue b/src/components/TheNavigation.vue
index c9b7a09..4f8134f 100644
--- a/src/components/TheNavigation.vue
+++ b/src/components/TheNavigation.vue
@@ -4,6 +4,7 @@ import { useWindowScroll } from '@vueuse/core' // 假设你使用了 VueUse
import { ref, watch } from 'vue'
import { useRoute } from 'vue-router'
import { useUserStore } from '../stores/user'
+import message from '~/utils/message'
const userStore = useUserStore()
const isLoginModalOpen = ref(false)
@@ -78,19 +79,32 @@ function closeLoginModal() {
error.value = ''
}
-function handleLogin() {
+async function handleLogin() {
if (!username.value || !password.value) {
error.value = '请输入用户名和密码'
return
}
- userStore.login(username.value, password.value)
- closeLoginModal()
+ try {
+ await userStore.login({ username: username.value, password: password.value })
+ message.success('登录成功')
+ closeLoginModal()
+ router.push('/')
+ } catch (e: any) {
+ error.value = e.message || '登录失败'
+ }
}
-function handleLogout() {
+async function handleLogout() {
+ try {
+ await apiLogout()
+ } catch (e) {
+ console.error(e)
+ }
userStore.logout()
+ message.success('退出登录成功')
// 登出后关闭菜单
isMobileMenuOpen.value = false
+ router.push('/')
}
// 新增:切换移动端菜单
diff --git a/src/service/api/auth.ts b/src/service/api/auth.ts
new file mode 100644
index 0000000..ee0dad7
--- /dev/null
+++ b/src/service/api/auth.ts
@@ -0,0 +1,24 @@
+import request from '../request'
+import type { UserInfo } from '~/stores/user'
+
+export interface LoginParams {
+ username: string
+ password: string
+}
+
+export interface LoginResult {
+ token: string
+ user: UserInfo
+}
+
+export function login(params: LoginParams) {
+ return request.post('/auth/login', params)
+}
+
+export function logout() {
+ return request.post('/auth/logout')
+}
+
+export function getUserInfo() {
+ return request.get('/auth/info')
+}
diff --git a/src/service/request/index.ts b/src/service/request/index.ts
new file mode 100644
index 0000000..9dd927a
--- /dev/null
+++ b/src/service/request/index.ts
@@ -0,0 +1,138 @@
+import axios, { type AxiosInstance, type AxiosRequestConfig, type AxiosResponse } from 'axios'
+import NProgress from 'nprogress'
+import CryptoJS from 'crypto-js'
+import { useUserStore } from '~/stores/user'
+import message from '~/utils/message'
+
+export interface RequestConfig extends AxiosRequestConfig {
+ showLoading?: boolean
+ showError?: boolean
+}
+
+interface ApiResponse {
+ code: number
+ message: string
+ data: T
+}
+
+class Request {
+ private instance: AxiosInstance
+
+ constructor(config: AxiosRequestConfig) {
+ this.instance = axios.create(config)
+
+ // Request interceptor
+ this.instance.interceptors.request.use(
+ (config: RequestConfig) => {
+ if (config.showLoading !== false) {
+ NProgress.start()
+ }
+
+ const userStore = useUserStore()
+ config.headers = config.headers || {}
+
+ if (userStore.token) {
+ config.headers.token = userStore.token
+ }
+
+ // Add Signature
+ const timestamp = Date.now().toString()
+ const secret = import.meta.env.VITE_API_SECRET || ''
+ const sign = CryptoJS.MD5(timestamp + secret).toString()
+ console.log(timestamp)
+ config.headers['X-App-Sign'] = sign
+ config.headers['X-App-Timestamp'] = timestamp
+
+ return config
+ },
+ (error) => {
+ return Promise.reject(error)
+ }
+ )
+
+ // Response interceptor
+ this.instance.interceptors.response.use(
+ (response: AxiosResponse) => {
+ const config = response.config as RequestConfig
+ if (config.showLoading !== false) {
+ NProgress.done()
+ }
+
+ const res = response.data
+ if (res.code === 200) {
+ return res.data
+ } else {
+ if (config.showError !== false) {
+ message.error(res.message || 'Error')
+ }
+ return Promise.reject(new Error(res.message || 'Error'))
+ }
+ },
+ (error) => {
+ const config = error.config as RequestConfig
+ if (config?.showLoading !== false) {
+ NProgress.done()
+ }
+
+ let msg = 'Network Error'
+ if (error.response) {
+ // 优先使用后端返回的错误信息
+ const backendMsg = error.response.data?.message
+
+ switch (error.response.status) {
+ case 401:
+ msg = backendMsg || 'Unauthorized'
+ const userStore = useUserStore()
+ userStore.logout()
+ // router push login?
+ break
+ case 403:
+ msg = backendMsg || 'Forbidden'
+ break
+ case 404:
+ msg = backendMsg || 'Not Found'
+ break
+ case 500:
+ msg = backendMsg || 'Internal Server Error'
+ break
+ default:
+ msg = backendMsg || error.message
+ }
+ }
+
+ if (config?.showError !== false) {
+ message.error(msg)
+ }
+ // 返回包含具体错误信息的 Error 对象
+ return Promise.reject(new Error(msg))
+ }
+ )
+ }
+
+ request(config: RequestConfig): Promise {
+ return this.instance.request(config)
+ }
+
+ get(url: string, config?: RequestConfig): Promise {
+ return this.instance.get(url, config)
+ }
+
+ post(url: string, data?: any, config?: RequestConfig): Promise {
+ return this.instance.post(url, data, config)
+ }
+
+ put(url: string, data?: any, config?: RequestConfig): Promise {
+ return this.instance.put(url, data, config)
+ }
+
+ delete(url: string, config?: RequestConfig): Promise {
+ return this.instance.delete(url, config)
+ }
+}
+
+const request = new Request({
+ baseURL: import.meta.env.VITE_API_BASE_URL,
+ timeout: 10000,
+})
+
+export default request
diff --git a/src/stores/user.ts b/src/stores/user.ts
index dd52e79..638e182 100644
--- a/src/stores/user.ts
+++ b/src/stores/user.ts
@@ -1,46 +1,70 @@
import { acceptHMRUpdate, defineStore } from 'pinia'
+import { ref } from 'vue'
-interface User {
+export interface UserInfo {
+ id: string
username: string
- password: string
+ realname: string
+ avatar: string
+ phone: string
+ email: string
}
-export const useUserStore = defineStore('user', () => {
- /**
- * Current logged-in user.
- */
- const user = ref(null)
+import { login as apiLogin, type LoginParams } from '~/service/api/auth'
- // Initialize user from localStorage
+export const useUserStore = defineStore('user', () => {
+ const token = ref('')
+ const userInfo = ref(null)
+
+ // Initialize from localStorage
if (typeof window !== 'undefined') {
+ const savedToken = localStorage.getItem('token')
const savedUser = localStorage.getItem('user')
+ if (savedToken) {
+ token.value = savedToken
+ }
if (savedUser) {
- user.value = JSON.parse(savedUser)
+ try {
+ userInfo.value = JSON.parse(savedUser)
+ } catch (e) {
+ console.error('Failed to parse user info', e)
+ }
}
}
- /**
- * Login the user.
- *
- * @param username - username to login with
- * @param password - password to login with
- */
- function login(username: string, password: string) {
- const newUser = { username, password }
- user.value = newUser
- localStorage.setItem('user', JSON.stringify(newUser))
+ function setToken(newToken: string) {
+ token.value = newToken
+ localStorage.setItem('token', newToken)
+ }
+
+ function setUserInfo(info: UserInfo) {
+ userInfo.value = info
+ localStorage.setItem('user', JSON.stringify(info))
+ }
+
+ async function login(params: LoginParams) {
+ try {
+ const data = await apiLogin(params)
+ setToken(data.token)
+ setUserInfo(data.user)
+ return data
+ } catch (error) {
+ throw error
+ }
}
- /**
- * Logout the user.
- */
function logout() {
- user.value = null
+ token.value = ''
+ userInfo.value = null
+ localStorage.removeItem('token')
localStorage.removeItem('user')
}
return {
- user,
+ token,
+ userInfo,
+ setToken,
+ setUserInfo,
login,
logout,
}
diff --git a/src/utils/message.ts b/src/utils/message.ts
new file mode 100644
index 0000000..e63ecb1
--- /dev/null
+++ b/src/utils/message.ts
@@ -0,0 +1,75 @@
+import { createVNode, render } from 'vue'
+import WMessage from '~/components/ui/WMessage.vue'
+
+let seed = 1
+const instances: any[] = []
+
+type MessageType = 'success' | 'error' | 'warning' | 'info'
+
+interface MessageOptions {
+ message: string
+ type?: MessageType
+ duration?: number
+}
+
+const Message = (options: MessageOptions) => {
+ const id = `message_${seed++}`
+ const container = document.createElement('div')
+
+ // Create a container for the message if it doesn't exist
+ let messageContainer = document.querySelector('.w-message-container')
+ if (!messageContainer) {
+ messageContainer = document.createElement('div')
+ messageContainer.className = 'w-message-container fixed top-4 left-1/2 transform -translate-x-1/2 z-50 flex flex-col items-center pointer-events-none'
+ document.body.appendChild(messageContainer)
+ }
+
+ const props = {
+ ...options,
+ id,
+ onClose: () => {
+ close(id, container)
+ },
+ }
+
+ const vnode = createVNode(WMessage, props)
+
+ // Render the component into the container
+ // We append the container to the messageContainer
+ messageContainer.appendChild(container)
+ render(vnode, container)
+
+ instances.push({ id, vnode, container })
+}
+
+function close(id: string, container: HTMLElement) {
+ const idx = instances.findIndex(vm => vm.id === id)
+ if (idx === -1) return
+
+ const { vnode } = instances[idx]
+ // Manually call close on component if needed, but here we just unmount
+ // The component handles its own visibility transition
+
+ // We wait for the transition to finish? The component calls onClose after transition.
+ // So we just remove it from DOM.
+
+ render(null, container)
+ container.remove()
+ instances.splice(idx, 1)
+
+ // Clean up container if empty
+ const messageContainer = document.querySelector('.w-message-container')
+ if (messageContainer && messageContainer.childNodes.length === 0) {
+ messageContainer.remove()
+ }
+}
+
+// Helpers
+export const message = {
+ success: (msg: string, duration?: number) => Message({ message: msg, type: 'success', duration }),
+ error: (msg: string, duration?: number) => Message({ message: msg, type: 'error', duration }),
+ warning: (msg: string, duration?: number) => Message({ message: msg, type: 'warning', duration }),
+ info: (msg: string, duration?: number) => Message({ message: msg, type: 'info', duration }),
+}
+
+export default message
diff --git a/task_detail.md b/task_detail.md
new file mode 100644
index 0000000..d6a4e9f
--- /dev/null
+++ b/task_detail.md
@@ -0,0 +1,14 @@
+# Task Detail
+
+## 2025-12-18 Session 5
+
+### Execution Reason
+User reported that the frontend was displaying a generic "Request failed with status code 401" error instead of the specific "用户不存在" message returned by the backend in the `data.message` field.
+
+### Execution Process
+1. **Analysis**: Examined `src/service/request/index.ts`. The response interceptor's error handler (onRejected) was hardcoding messages for 401, 403, etc., ignoring the `message` field from the backend response body (`error.response.data.message`).
+2. **Fix**: Updated the error handling logic to prioritize `error.response.data?.message` if it exists. If not, it falls back to the default status code descriptions.
+3. **Refinement**: Ensured `Promise.reject` returns a new `Error` object with the refined message, so calling code (`try/catch`) receives the correct error text.
+
+### Execution Result
+- The application will now display the specific error message returned by the backend (e.g., "用户不存在") in the global message toast and in `catch` blocks, improving the user experience and debugging capability.
diff --git a/tasks/Task1.md b/tasks/Task1.md
index e69de29..da1ff93 100644
--- a/tasks/Task1.md
+++ b/tasks/Task1.md
@@ -0,0 +1,5 @@
+首先我需要你帮我做一个全局的message提示组件,用于在全局范围内显示提示信息,如成功、失败、警告等。
+我需要你帮我参考#api1.md文件,根据接口文档内容,首先封装一个src/service/request/index.ts文件,用于封装axios请求,包括请求拦截器、响应拦截器、请求参数处理、响应数据处理等。然后封装一个src/service/api/xx.ts文件,用于封装每个接口的请求方法,包括请求参数、请求方法、请求路径等。
+接口请求时,可以直接调用封装好的请求方法,也可以在业务代码中直接调用axios请求。调用时可以根据需要传递参数,也可以在请求方法中直接传递参数。同时参数中可以传递一个config对象,用于配置请求参数,如请求头、请求体、超时时间等(不强制),以及是否加载,是否显示loading(loading时屏幕不可操作)等。
+针对登录接口,可以利用pinia存储登录状态,登录成功后将token存储在pinia中,后续请求在请求拦截器中添加token到请求头中。同时增加持久化存储,登录状态和token可以存储在localStorage中,避免页面刷新后登录状态丢失,需要防止持久化信息被恶意获取。
+登录和退出接口封装后,在业务代码中#TheNavigation.vue中调用登录和退出接口,登录成功后跳转到首页,退出登录后跳转到首页。
\ No newline at end of file
diff --git a/vite.config.ts b/vite.config.ts
index bf7e45a..41cee0f 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -11,157 +11,170 @@ import VueMacros from 'unplugin-vue-macros/vite'
import Markdown from 'unplugin-vue-markdown/vite'
import { VueRouterAutoImports } from 'unplugin-vue-router'
import VueRouter from 'unplugin-vue-router/vite'
-import { defineConfig } from 'vite'
+import { defineConfig, loadEnv } from 'vite'
import { VitePWA } from 'vite-plugin-pwa'
import VueDevTools from 'vite-plugin-vue-devtools'
import Layouts from 'vite-plugin-vue-layouts'
import generateSitemap from 'vite-ssg-sitemap'
import 'vitest/config'
-export default defineConfig({
- resolve: {
- alias: {
- '~/': `${path.resolve(__dirname, 'src')}/`,
+export default defineConfig(({ mode }) => {
+ const env = loadEnv(mode, process.cwd(), '')
+
+ return {
+ resolve: {
+ alias: {
+ '~/': `${path.resolve(__dirname, 'src')}/`,
+ },
},
- },
- plugins: [
- // https://github.com/posva/unplugin-vue-router
- VueRouter({
- extensions: ['.vue', '.md'],
- dts: 'src/typed-router.d.ts',
- }),
-
- VueMacros({
- plugins: {
- vue: Vue({
- include: [/\.vue$/, /\.md$/],
- }),
- },
- }),
-
- // https://github.com/JohnCampionJr/vite-plugin-vue-layouts
- Layouts(),
-
- // https://github.com/antfu/unplugin-auto-import
- AutoImport({
- include: [/\.[jt]sx?$/, /\.vue$/, /\.vue\?vue/, /\.md$/],
- imports: [
- 'vue',
- 'vue-i18n',
- '@vueuse/core',
- unheadVueComposablesImports,
- VueRouterAutoImports,
- {
- // add any other imports you were relying on
- 'vue-router/auto': ['useLink'],
+ server: {
+ proxy: {
+ '/api': {
+ target: env.VITE_API_PROXY_TARGET || 'http://localhost:8080',
+ changeOrigin: true,
},
- ],
- dts: 'src/auto-imports.d.ts',
- dirs: [
- 'src/composables',
- 'src/stores',
- ],
- vueTemplate: true,
- }),
-
- // https://github.com/antfu/unplugin-vue-components
- Components({
- // allow auto load markdown components under `./src/components/`
- extensions: ['vue', 'md'],
- // allow auto import and register components used in markdown
- include: [/\.vue$/, /\.vue\?vue/, /\.md$/],
- dts: 'src/components.d.ts',
- }),
-
- // https://github.com/antfu/unocss
- // see uno.config.ts for config
- Unocss(),
-
- // https://github.com/unplugin/unplugin-vue-markdown
- // Don't need this? Try vitesse-lite: https://github.com/antfu/vitesse-lite
- Markdown({
- wrapperClasses: 'prose prose-sm m-auto text-left',
- headEnabled: true,
- async markdownItSetup(md) {
- md.use(LinkAttributes, {
- matcher: (link: string) => /^https?:\/\//.test(link),
- attrs: {
- target: '_blank',
- rel: 'noopener',
- },
- })
- md.use(await Shiki({
- defaultColor: false,
- themes: {
- light: 'vitesse-light',
- dark: 'vitesse-dark',
- },
- }))
},
- }),
+ },
- // https://github.com/antfu/vite-plugin-pwa
- VitePWA({
- registerType: 'autoUpdate',
- includeAssets: ['favicon.svg', 'safari-pinned-tab.svg'],
- manifest: {
- name: 'Vitesse',
- short_name: 'Vitesse',
- theme_color: '#ffffff',
- icons: [
+ plugins: [
+ // https://github.com/posva/unplugin-vue-router
+ VueRouter({
+ extensions: ['.vue', '.md'],
+ dts: 'src/typed-router.d.ts',
+ }),
+
+ VueMacros({
+ plugins: {
+ vue: Vue({
+ include: [/\.vue$/, /\.md$/],
+ }),
+ },
+ }),
+
+ // https://github.com/JohnCampionJr/vite-plugin-vue-layouts
+ Layouts(),
+
+ // https://github.com/antfu/unplugin-auto-import
+ AutoImport({
+ include: [/\.[jt]sx?$/, /\.vue$/, /\.vue\?vue/, /\.md$/],
+ imports: [
+ 'vue',
+ 'vue-i18n',
+ '@vueuse/core',
+ unheadVueComposablesImports,
+ VueRouterAutoImports,
{
- src: '/pwa-192x192.png',
- sizes: '192x192',
- type: 'image/png',
- },
- {
- src: '/pwa-512x512.png',
- sizes: '512x512',
- type: 'image/png',
- },
- {
- src: '/pwa-512x512.png',
- sizes: '512x512',
- type: 'image/png',
- purpose: 'any maskable',
+ // add any other imports you were relying on
+ 'vue-router/auto': ['useLink'],
},
],
+ dts: 'src/auto-imports.d.ts',
+ dirs: [
+ 'src/composables',
+ 'src/stores',
+ ],
+ vueTemplate: true,
+ }),
+
+ // https://github.com/antfu/unplugin-vue-components
+ Components({
+ // allow auto load markdown components under `./src/components/`
+ extensions: ['vue', 'md'],
+ // allow auto import and register components used in markdown
+ include: [/\.vue$/, /\.vue\?vue/, /\.md$/],
+ dts: 'src/components.d.ts',
+ }),
+
+ // https://github.com/antfu/unocss
+ // see uno.config.ts for config
+ Unocss(),
+
+ // https://github.com/unplugin/unplugin-vue-markdown
+ // Don't need this? Try vitesse-lite: https://github.com/antfu/vitesse-lite
+ Markdown({
+ wrapperClasses: 'prose prose-sm m-auto text-left',
+ headEnabled: true,
+ async markdownItSetup(md) {
+ md.use(LinkAttributes, {
+ matcher: (link: string) => /^https?:\/\//.test(link),
+ attrs: {
+ target: '_blank',
+ rel: 'noopener',
+ },
+ })
+ md.use(await Shiki({
+ defaultColor: false,
+ themes: {
+ light: 'vitesse-light',
+ dark: 'vitesse-dark',
+ },
+ }))
+ },
+ }),
+
+ // https://github.com/antfu/vite-plugin-pwa
+ VitePWA({
+ registerType: 'autoUpdate',
+ includeAssets: ['favicon.svg', 'safari-pinned-tab.svg'],
+ manifest: {
+ name: 'Vitesse',
+ short_name: 'Vitesse',
+ theme_color: '#ffffff',
+ icons: [
+ {
+ src: '/pwa-192x192.png',
+ sizes: '192x192',
+ type: 'image/png',
+ },
+ {
+ src: '/pwa-512x512.png',
+ sizes: '512x512',
+ type: 'image/png',
+ },
+ {
+ src: '/pwa-512x512.png',
+ sizes: '512x512',
+ type: 'image/png',
+ purpose: 'any maskable',
+ },
+ ],
+ },
+ }),
+
+ // https://github.com/intlify/bundle-tools/tree/main/packages/unplugin-vue-i18n
+ VueI18n({
+ runtimeOnly: true,
+ compositionOnly: true,
+ fullInstall: true,
+ include: [path.resolve(__dirname, 'locales/**')],
+ }),
+
+ // https://github.com/webfansplz/vite-plugin-vue-devtools
+ VueDevTools(),
+ ],
+
+ // https://github.com/vitest-dev/vitest
+ test: {
+ include: ['test/**/*.test.ts'],
+ environment: 'jsdom',
+ },
+
+ // https://github.com/antfu/vite-ssg
+ ssgOptions: {
+ script: 'async',
+ formatting: 'minify',
+ beastiesOptions: {
+ reduceInlineStyles: false,
+ },
+ onFinished() {
+ generateSitemap()
},
- }),
-
- // https://github.com/intlify/bundle-tools/tree/main/packages/unplugin-vue-i18n
- VueI18n({
- runtimeOnly: true,
- compositionOnly: true,
- fullInstall: true,
- include: [path.resolve(__dirname, 'locales/**')],
- }),
-
- // https://github.com/webfansplz/vite-plugin-vue-devtools
- VueDevTools(),
- ],
-
- // https://github.com/vitest-dev/vitest
- test: {
- include: ['test/**/*.test.ts'],
- environment: 'jsdom',
- },
-
- // https://github.com/antfu/vite-ssg
- ssgOptions: {
- script: 'async',
- formatting: 'minify',
- beastiesOptions: {
- reduceInlineStyles: false,
},
- onFinished() {
- generateSitemap()
- },
- },
- ssr: {
- // TODO: workaround until they support native ESM
- noExternal: ['workbox-window', /vue-i18n/],
- },
+ ssr: {
+ // TODO: workaround until they support native ESM
+ noExternal: ['workbox-window', /vue-i18n/],
+ },
+ }
})