user.js
7.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
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: []
}
});