import { defineStore } from 'pinia'; import cache from '@/common/utils/cache'; import globalConfig from '@/common/config/global'; import { login, getUserInfo, logout, moduleList, getSimpleDictDataList } from '@/api/user'; export const useUserStore = defineStore('user', { // 修复1:删除重复的 state 定义,只保留根层级的 state 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, dictData: cache.get(globalConfig.cache.dictDataKey) || {}, logoutLoading: false }), getters: { isLogin: (state) => { if (!state.token) return false; if (state.expireTime && state.expireTime < Date.now()) { return false; } return true; }, permissions: (state) => state.userInfo.permissions || [] }, actions: { async login(params) { try { const res = await login(params); const { accessToken, expiresTime, userId } = res; if (!accessToken) { throw new Error('登录失败,未获取到令牌'); } // 更新 Pinia state this.token = accessToken; this.expireTime = expiresTime; this.userId = userId; this.userInfo = {}; // 等待 Pinia 持久化同步 await new Promise(resolve => setTimeout(resolve, 50)); // 获取用户信息 const userInfo = await this.getUserInfo(); this.userInfo = userInfo; // 获取模块列表 let moduleListInfo = null; try { moduleListInfo = await this.getModuleList(); this.moduleListInfo = moduleListInfo; } catch (moduleErr) { console.warn('获取模块列表失败(不影响登录):', moduleErr); uni.showToast({ title: '获取模块列表失败,可正常登录', icon: 'none' }); } // 修复2:调用字典接口时,不直接抛错(避免阻断登录) try { const dictRes = await this.getAndSaveDictData(); // 仅接口返回成功时才更新字典 this.dictData = dictRes || {}; console.log('字典数据获取成功:', this.dictData); } catch (dictErr) { console.warn('获取字典失败(不影响登录):', dictErr); uni.showToast({ title: '获取字典失败,可正常使用', icon: 'none' }); } return { ...res, userInfo, moduleListInfo }; } catch (err) { console.error('登录流程失败:', err); throw err; } }, // 修复3:重构字典获取方法(加 Token 校验 + 强制携带 Token + 宽松错误处理) async getAndSaveDictData() { // 前置校验:无登录态直接返回,不请求接口 if (!this.isLogin) { console.warn('未登录,跳过字典获取'); return { code: -1, msg: '未登录' }; } try { // 强制携带 Token(和 getModuleList 保持一致,避免拦截器同步延迟) const res = await getSimpleDictDataList( {}, // 接口入参(按需传,比如 dictType: ['level']) { header: { 'Authorization': `Bearer ${this.token}` } } ); // 校验接口返回码(核心:避免非 0 码数据存入) if (res.code !== 0) { console.warn('字典接口返回失败:', res.msg); return res; // 返回错误信息,但不抛错 } return res; } catch (err) { // 修复4:宽松错误处理,只打印日志,不抛错(避免阻断登录) console.error('字典接口请求异常:', err); return { code: -2, msg: '接口请求异常:' + (err.message || '网络错误') }; } }, async getModuleList() { try { if (!this.token) { throw new Error('未获取到登录令牌,无法获取模块列表'); } const res = await moduleList({}, { header: { 'Authorization': `Bearer ${this.token}` } }); return res; } catch (err) { console.error('获取用户菜单失败:', err); if (err?.data?.code === 401 || err?.message.includes('401')) { throw new Error('登录态已过期,请重新登录'); } else { throw new Error('获取用户菜单失败,请重新登录'); } } }, async getUserInfo() { try { 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) { this.token = ''; this.userInfo = {}; this.userId = ''; this.moduleListInfo = ''; this.expireTime = 0; this.dictData = {}; return; } const logoutWithLock = async () => { if (this.logoutLoading) return; this.logoutLoading = true; try { await logout(); } catch (err) { console.error('退出登录接口调用失败:', err); } finally { this.token = ''; this.userInfo = {}; this.userId = ''; this.moduleListInfo = ''; this.dictData = {}; this.expireTime = 0; this.logoutLoading = false; uni.redirectTo({ url: globalConfig.router.loginPath }); } }; logoutWithLock(); }, 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; } }, persist: { enabled: true, key: 'user_store', storage: { getItem: (key) => uni.getStorageSync(key), setItem: (key, value) => uni.setStorageSync(key, value), removeItem: (key) => uni.removeStorageSync(key) }, serializer: { serialize: (state) => { 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); uni.setStorageSync(globalConfig.cache.dictDataKey, state.dictData); return state; }, deserialize: (value) => { 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) || '', dictData: uni.getStorageSync(globalConfig.cache.dictDataKey) || {}, logoutLoading: false }; } }, paths: [] } });