import { defineStore } from 'pinia'; import cache from '@/common/utils/cache'; import globalConfig from '@/common/config/global'; import { login, getUserInfo, logout, moduleList } from '@/api/user'; export const useUserStore = defineStore('user', { // 1. 状态定义(修正 userId 类型 + 字段名) state: () => ({ token: '', userInfo: {}, userId: '', moduleListInfo: '', expireTime: 0, logoutLoading: false // 防重锁移到这里 }), // 2. 计算属性(保持不变) getters: { isLogin: (state) => { if (!state.token) return false; if (state.expireTime && state.expireTime < Date.now()) { return false; } return true; }, permissions: (state) => state.userInfo.permissions || [] }, // 3. 核心动作(修正语法错误 + 登录后自动调用户信息接口) actions: { async login(params) { try { const res = await login(params); const { accessToken, expiresTime, userId } = res; if (!accessToken) { throw new Error('登录失败,未获取到令牌'); } // 仅更新 Pinia state(持久化插件会自动同步到 storage) this.token = accessToken; this.expireTime = expiresTime; this.userId = userId; this.userInfo = {}; // 移除手动 cache.set() 代码 // cache.set(globalConfig.cache.tokenKey, accessToken); // cache.set(globalConfig.cache.expireTimeKey, expiresTime); // cache.set(globalConfig.cache.userIdKey, userId); // 等待 Pinia 持久化同步(可选,50ms 足够) await new Promise(resolve => setTimeout(resolve, 50)); // 获取用户信息 const userInfo = await this.getUserInfo(); this.userInfo = userInfo; // 移除 cache.set(globalConfig.cache.userInfoKey, userInfo); // 获取模块列表 let moduleListInfo = null; try { moduleListInfo = await this.getModuleList(); this.moduleListInfo = moduleListInfo; // 移除 cache.set(globalConfig.cache.moduleListKey, moduleListInfo); } catch (moduleErr) { console.warn('获取模块列表失败(不影响登录):', moduleErr); uni.showToast({ title: '获取模块列表失败,可正常登录', icon: 'none' }); } return { ...res, userInfo, moduleListInfo }; } catch (err) { console.error('登录流程失败:', err); throw err; } }, async getModuleList() { try { // 前置校验:无 Token 直接抛错,避免无效请求 if (!this.token) { throw new Error('未获取到登录令牌,无法获取模块列表'); } // 强制携带 Token(覆盖请求工具的自动携带,避免缓存同步延迟) const res = await moduleList({}, { header: { 'Authorization': `Bearer ${this.token}` } }); return res; } catch (err) { console.error('获取用户菜单失败:', err); // 区分 401 错误:仅登录态失效时抛错,避免触发 logout 循环 if (err?.data?.code === 401 || err?.message.includes('401')) { throw new Error('登录态已过期,请重新登录'); } else { throw new Error('获取用户菜单失败,请重新登录'); } } }, async getUserInfo() { try { // 调用用户信息接口(此时 token 已存入缓存,请求工具会自动携带) const res = await getUserInfo(); return res; } catch (err) { console.error('获取用户信息失败:', err); throw new Error('获取用户信息失败,请重新登录'); } }, logout() { const pages = getCurrentPages(); if (pages.length === 0) return; const currentPageRoute = pages[pages.length - 1].route; const loginPath = globalConfig.router.loginPath .replace(/^\//, '') .split('?')[0]; if (currentPageRoute === loginPath) { // 仅清空 Pinia state(持久化插件自动同步到 storage) this.token = ''; this.userInfo = {}; this.userId = ''; this.moduleListInfo = ''; this.expireTime = 0; // 移除手动 cache.remove() 代码 // cache.remove(globalConfig.cache.tokenKey); // ... 其他 cache.remove 都删除 return; } const logoutWithLock = async () => { if (this.logoutLoading) return; this.logoutLoading = true; try { await logout(); } catch (err) { console.error('退出登录接口调用失败:', err); } finally { // 清空 state this.token = ''; this.userInfo = {}; this.userId = ''; this.moduleListInfo = ''; this.expireTime = 0; this.logoutLoading = false; // 移除手动 cache.remove() 代码 uni.redirectTo({ url: globalConfig.router.loginPath }); } }; logoutWithLock(); }, // 新增:状态中添加 logoutLoading 防重锁 state: () => ({ token: cache.get(globalConfig.cache.tokenKey) || '', userInfo: cache.get(globalConfig.cache.userInfoKey) || {}, userId: cache.get(globalConfig.cache.userIdKey) || '', moduleListInfo: cache.get(globalConfig.cache.moduleListKey) || '', expireTime: cache.get(globalConfig.cache.expireTimeKey) || 0, logoutLoading: false // 新增:退出登录防重锁 }), checkLogin() { if (!this.isLogin) { // 先判断是否已在登录页,避免重复跳转 const pages = getCurrentPages(); if (pages.length === 0) return false; const currentPageRoute = pages[pages.length - 1].route; const loginPath = globalConfig.router.loginPath .replace(/^\//, '') .split('?')[0]; if (currentPageRoute !== loginPath) { uni.redirectTo({ url: globalConfig.router.loginPath }); } return false; } return true; } }, // 4. 持久化配置(修正:persist 应放在 store 根层级,非 actions 内) persist: { enabled: true, key: 'user_store', // 自定义存储键名(默认是 store 名 'user') storage: { getItem: (key) => uni.getStorageSync(key), setItem: (key, value) => uni.setStorageSync(key, value), removeItem: (key) => uni.removeStorageSync(key) }, // 自定义序列化:将 state 拆分为原有的 jcss_xxx 键(可选) serializer: { serialize: (state) => { // 拆分为多个独立键(和原 cache 格式对齐) uni.setStorageSync(globalConfig.cache.tokenKey, state.token); uni.setStorageSync(globalConfig.cache.userIdKey, state.userId); uni.setStorageSync(globalConfig.cache.expireTimeKey, state.expireTime); uni.setStorageSync(globalConfig.cache.userInfoKey, state.userInfo); uni.setStorageSync(globalConfig.cache.moduleListKey, state.moduleListInfo); return state; // 返回完整 state(兼容 Pinia 默认逻辑) }, deserialize: (value) => { // 从多个独立键恢复 state return { token: uni.getStorageSync(globalConfig.cache.tokenKey) || '', userId: uni.getStorageSync(globalConfig.cache.userIdKey) || '', expireTime: uni.getStorageSync(globalConfig.cache.expireTimeKey) || 0, userInfo: uni.getStorageSync(globalConfig.cache.userInfoKey) || {}, moduleListInfo: uni.getStorageSync(globalConfig.cache.moduleListKey) || '', logoutLoading: false }; } }, paths: [] // 序列化自定义后,paths 可留空 } });