diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2f27db9..7338be6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -56,9 +56,6 @@ dependencies: vue: specifier: ^3.4.21 version: 3.5.6(typescript@4.9.5) - vue-i18n: - specifier: ^9.1.9 - version: 9.14.0(vue@3.5.6) wot-design-uni: specifier: ^1.3.11 version: 1.3.11(vue@3.5.6) @@ -2851,14 +2848,6 @@ packages: '@intlify/shared': 9.1.9 '@intlify/vue-devtools': 9.1.9 - /@intlify/core-base@9.14.0: - resolution: {integrity: sha512-zJn0imh9HIsZZUtt9v8T16PeVstPv6bP2YzlrYJwoF8F30gs4brZBwW2KK6EI5WYKFi3NeqX6+UU4gniz5TkGg==} - engines: {node: '>= 16'} - dependencies: - '@intlify/message-compiler': 9.14.0 - '@intlify/shared': 9.14.0 - dev: false - /@intlify/devtools-if@9.1.9: resolution: {integrity: sha512-oKSMKjttG3Ut/1UGEZjSdghuP3fwA15zpDPcjkf/1FjlOIm6uIBGMNS5jXzsZy593u+P/YcnrZD6cD3IVFz9vQ==} engines: {node: '>= 10'} @@ -2873,14 +2862,6 @@ packages: '@intlify/shared': 9.1.9 source-map: 0.6.1 - /@intlify/message-compiler@9.14.0: - resolution: {integrity: sha512-sXNsoMI0YsipSXW8SR75drmVK56tnJHoYbPXUv2Cf9lz6FzvwsosFm6JtC1oQZI/kU+n7qx0qRrEWkeYFTgETA==} - engines: {node: '>= 16'} - dependencies: - '@intlify/shared': 9.14.0 - source-map-js: 1.2.1 - dev: false - /@intlify/message-resolver@9.1.9: resolution: {integrity: sha512-Lx/DBpigeK0sz2BBbzv5mu9/dAlt98HxwbG7xLawC3O2xMF9MNWU5FtOziwYG6TDIjNq0O/3ZbOJAxwITIWXEA==} engines: {node: '>= 10'} @@ -2897,11 +2878,6 @@ packages: resolution: {integrity: sha512-xKGM1d0EAxdDFCWedcYXOm6V5Pfw/TMudd6/qCdEb4tv0hk9EKeg7lwQF1azE0dP2phvx0yXxrt7UQK+IZjNdw==} engines: {node: '>= 10'} - /@intlify/shared@9.14.0: - resolution: {integrity: sha512-r+N8KRQL7LgN1TMTs1A2svfuAU0J94Wu9wWdJVJqYsoMMLIeJxrPjazihfHpmJqfgZq0ah3Y9Q4pgWV2O90Fyg==} - engines: {node: '>= 16'} - dev: false - /@intlify/vue-devtools@9.1.9: resolution: {integrity: sha512-YPehH9uL4vZcGXky4Ev5qQIITnHKIvsD2GKGXgqf+05osMUI6WSEQHaN9USRa318Rs8RyyPCiDfmA0hRu3k7og==} engines: {node: '>= 10'} @@ -9705,18 +9681,6 @@ packages: - supports-color dev: true - /vue-i18n@9.14.0(vue@3.5.6): - resolution: {integrity: sha512-LxmpRuCt2rI8gqU+kxeflRZMQn4D5+4M3oP3PWZdowW/ePJraHqhF7p4CuaME52mUxdw3Mmy2yAUKgfZYgCRjA==} - engines: {node: '>= 16'} - peerDependencies: - vue: ^3.0.0 - dependencies: - '@intlify/core-base': 9.14.0 - '@intlify/shared': 9.14.0 - '@vue/devtools-api': 6.6.4 - vue: 3.5.6(typescript@4.9.5) - dev: false - /vue-router@4.4.5(vue@3.5.6): resolution: {integrity: sha512-4fKZygS8cH1yCyuabAXGUAsyi1b2/o/OKgu/RUb+znIYOxPRxdkytJEx+0wGcpBE1pX6vUgh5jwWOKRGvuA/7Q==} peerDependencies: diff --git a/src/enums/ResultCodeEnum.ts b/src/enums/ResultCodeEnum.ts new file mode 100644 index 0000000..7a71a04 --- /dev/null +++ b/src/enums/ResultCodeEnum.ts @@ -0,0 +1,18 @@ +/** + * 响应码枚举 + */ +export const enum ResultCodeEnum { + /** + * 成功 + */ + SUCCESS = "00000", + /** + * 错误 + */ + ERROR = "B0001", + + /** + * 令牌无效或过期 + */ + TOKEN_INVALID = "A0230", +} diff --git a/src/store/modules/user.ts b/src/store/modules/user.ts index 3613ade..f201ec3 100644 --- a/src/store/modules/user.ts +++ b/src/store/modules/user.ts @@ -1,6 +1,7 @@ import { defineStore } from "pinia"; import AuthAPI from "@/api/auth"; import UserAPI, { UserInfo } from "@/api/user"; +import { setToken, clearToken } from "@/utils/auth"; export const useUserStore = defineStore("user", () => { // 确保 token 是响应式的 @@ -8,10 +9,22 @@ export const useUserStore = defineStore("user", () => { const userInfo = ref(null); // 登录 - const login = async (username: string, password: string) => { - const { tokenType, accessToken } = await AuthAPI.login(username, password); - token.value = `${tokenType} ${accessToken}`; // Bearer token - uni.setStorageSync("token", token.value); + const login = (username: string, password: string) => { + AuthAPI.login(username, password) + .then((res) => { + token.value = ` ${res.accessToken}`; // Bearer token + setToken(token.value); + }) + .catch((error) => { + if (error.action === "TOKEN_INVALID") { + // 处理 Token 失效,比如弹出登录提示框,而不是直接跳转 + console.log("Token 已失效,请重新登录"); + // 例如:uni.navigateTo({ url: '/pages/login/index' }); + } else { + // 处理其他错误 + console.error("请求失败", error.message); + } + }); }; // 获取用户信息 @@ -25,7 +38,7 @@ export const useUserStore = defineStore("user", () => { await AuthAPI.logout(); userInfo.value = null; token.value = ""; // 清空 token - uni.removeStorageSync("token"); // 从本地缓存移除 token + clearToken(); // 从本地缓存移除 token }; return { diff --git a/src/utils/auth.ts b/src/utils/auth.ts new file mode 100644 index 0000000..3b14e17 --- /dev/null +++ b/src/utils/auth.ts @@ -0,0 +1,19 @@ +const TOKEN_KEY = "app-token"; + +function getToken(): string { + return uni.getStorageSync(TOKEN_KEY) || ""; +} + +function setToken(token: string) { + return uni.setStorageSync(TOKEN_KEY, token); +} + +function clearToken() { + return uni.removeStorageSync(TOKEN_KEY); +} + +function isLogin(): boolean { + return !!getToken(); +} + +export { getToken, setToken, clearToken, isLogin }; diff --git a/src/utils/request.ts b/src/utils/request.ts index 7a289cb..3ec34ca 100644 --- a/src/utils/request.ts +++ b/src/utils/request.ts @@ -1,20 +1,48 @@ +import { getToken, clearToken } from "@/utils/auth"; +import { ResultCodeEnum } from "@/enums/ResultCodeEnum"; + export default function request(options: UniApp.RequestOptions): Promise { - const token = uni.getStorageSync("token"); // 从本地缓存获取 token + // H5 使用 VITE_APP_BASE_API 作为代理路径,其他平台使用 VITE_APP_API_URL 作为请求路径 + let baseApi = import.meta.env.VITE_APP_API_URL; + // #ifdef H5 + baseApi = import.meta.env.VITE_APP_BASE_API; + // #endif return new Promise((resolve, reject) => { uni.request({ ...options, - url: `${import.meta.env.VITE_APP_BASE_API}${options.url}`, + url: `${baseApi}${options.url}`, header: { ...options.header, - Authorization: token, + Authorization: getToken() ? `Bearer ${getToken()}` : "", // 添加 Bearer 前缀 }, success: (response) => { + console.log("success response", response); const resData = response.data as ResponseData; + // 业务状态码 00000 表示成功 - if (resData.code === "00000") { + if (resData.code === ResultCodeEnum.SUCCESS) { resolve(resData.data); - } else { + } + // 令牌失效或过期处理 + else if (resData.code === ResultCodeEnum.TOKEN_INVALID) { + uni.showToast({ + title: resData.msg || "令牌无效或过期", + icon: "none", + duration: 2000, + }); + + clearToken(); + + // 此处不强制跳转到登录页,可以让调用方决定下一步操作 + reject({ + message: resData.msg || "令牌无效或过期", + code: resData.code, + action: "TOKEN_INVALID", // 提供一个 action 用于后续调用方判断 + }); + } + // 其他业务处理失败 + else { uni.showToast({ title: resData.msg || "业务处理失败", icon: "none", @@ -27,6 +55,7 @@ export default function request(options: UniApp.RequestOptions): Promise { } }, fail: (error) => { + console.log("fail error", error); uni.showToast({ title: "网络请求失败", icon: "none", diff --git a/vite.config.ts b/vite.config.ts index 30f0550..cffdbef 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -11,6 +11,7 @@ export default defineConfig(async ({ mode }: ConfigEnv): Promise => host: "0.0.0.0", port: +env.VITE_APP_PORT, open: true, + // 代理配置只在 H5(浏览器)开发时生效。 其他平台(如小程序、App)在开发时不使用 Vite 的开发服务器,它们直接运行在各自的环境中。 proxy: { [env.VITE_APP_BASE_API]: { changeOrigin: true,