3cbb8754
刘淇
动态字典
|
1
2
3
|
import { defineStore } from "pinia";
import cache from "@/common/utils/cache";
import globalConfig from "@/common/config/global";
|
e6a04285
刘淇
单图情况 宽高70*70
|
4
|
// 新增:导入 refreshToken 接口
|
3cbb8754
刘淇
动态字典
|
5
6
7
8
9
10
11
12
13
|
import {
login,
smsLogin,
getUserInfo,
logout,
moduleList,
getSimpleDictDataList,
refreshToken,
} from "@/api/user";
|
e6a04285
刘淇
单图情况 宽高70*70
|
14
15
|
// 新增:定义刷新Token的定时器标识(避免重复创建定时器)
let refreshTokenTimer = null;
|
3cbb8754
刘淇
动态字典
|
16
|
export const useUserStore = defineStore("user", {
|
9b30ab8c
刘淇
新增快速工单,原版
|
17
|
// 修复1:删除重复的 state 定义,只保留根层级的 state
|
c293da23
刘淇
新园林init
|
18
|
state: () => ({
|
3cbb8754
刘淇
动态字典
|
19
20
|
token: cache.get(globalConfig.cache.tokenKey) || "", // 初始值从缓存取(兼容持久化)
refreshToken: cache.get(globalConfig.cache.refreshTokenKey) || "", // 新增:Refresh Token 状态
|
9b30ab8c
刘淇
新增快速工单,原版
|
21
|
userInfo: cache.get(globalConfig.cache.userInfoKey) || {},
|
3cbb8754
刘淇
动态字典
|
22
23
|
userId: cache.get(globalConfig.cache.userIdKey) || "",
moduleListInfo: cache.get(globalConfig.cache.moduleListKey) || "",
|
9b30ab8c
刘淇
新增快速工单,原版
|
24
25
|
expireTime: cache.get(globalConfig.cache.expireTimeKey) || 0,
dictData: cache.get(globalConfig.cache.dictDataKey) || {},
|
3cbb8754
刘淇
动态字典
|
26
27
|
dictList: cache.get(globalConfig.cache.dictListKey) || [], // 用来存放【过滤后的】字典数组
logoutLoading: false,
|
c293da23
刘淇
新园林init
|
28
|
}),
|
c293da23
刘淇
新园林init
|
29
30
31
32
33
34
35
36
|
getters: {
isLogin: (state) => {
if (!state.token) return false;
if (state.expireTime && state.expireTime < Date.now()) {
return false;
}
return true;
},
|
e6a04285
刘淇
单图情况 宽高70*70
|
37
38
39
40
41
42
43
|
permissions: (state) => state.userInfo.permissions || [],
// 新增:判断是否需要刷新Token(过期前30秒触发,避免已过期才刷新)
needRefreshToken: (state) => {
if (!state.token || !state.refreshToken) return false;
const remainingTime = state.expireTime - Date.now();
// 剩余时间大于0秒 且 小于30秒(即将过期)
return remainingTime > 0 && remainingTime < 30 * 1000;
|
3cbb8754
刘淇
动态字典
|
44
|
},
|
c293da23
刘淇
新园林init
|
45
|
},
|
c293da23
刘淇
新园林init
|
46
47
48
|
actions: {
async login(params) {
try {
|
e2e5221c
刘淇
验证码登录
|
49
|
// smsLogin
|
3cbb8754
刘淇
动态字典
|
50
51
|
let res;
if (params.type == "sms") {
|
e2e5221c
刘淇
验证码登录
|
52
|
res = await smsLogin(params);
|
3cbb8754
刘淇
动态字典
|
53
|
} else {
|
e2e5221c
刘淇
验证码登录
|
54
55
|
res = await login(params);
}
|
e6a04285
刘淇
单图情况 宽高70*70
|
56
57
|
// 新增:从登录接口返回值中获取 refreshToken(若接口返回字段名不一致,可调整,如 res.refresh_token)
const { accessToken, expiresTime, userId, refreshToken } = res;
|
c293da23
刘淇
新园林init
|
58
|
if (!accessToken) {
|
3cbb8754
刘淇
动态字典
|
59
|
throw new Error("登录失败,未获取到令牌");
|
c293da23
刘淇
新园林init
|
60
|
}
|
9b30ab8c
刘淇
新增快速工单,原版
|
61
|
// 更新 Pinia state
|
c293da23
刘淇
新园林init
|
62
|
this.token = accessToken;
|
3cbb8754
刘淇
动态字典
|
63
|
this.refreshToken = refreshToken || ""; // 新增:存储Refresh Token
|
c293da23
刘淇
新园林init
|
64
65
66
|
this.expireTime = expiresTime;
this.userId = userId;
this.userInfo = {};
|
9b30ab8c
刘淇
新增快速工单,原版
|
67
|
// 等待 Pinia 持久化同步
|
3cbb8754
刘淇
动态字典
|
68
|
await new Promise((resolve) => setTimeout(resolve, 50));
|
c293da23
刘淇
新园林init
|
69
70
71
|
// 获取用户信息
const userInfo = await this.getUserInfo();
this.userInfo = userInfo;
|
c293da23
刘淇
新园林init
|
72
73
74
75
76
|
// 获取模块列表
let moduleListInfo = null;
try {
moduleListInfo = await this.getModuleList();
this.moduleListInfo = moduleListInfo;
|
c293da23
刘淇
新园林init
|
77
|
} catch (moduleErr) {
|
3cbb8754
刘淇
动态字典
|
78
79
80
81
82
|
console.warn("获取模块列表失败(不影响登录):", moduleErr);
uni.showToast({
title: "获取模块列表失败,可正常登录",
icon: "none",
});
|
c293da23
刘淇
新园林init
|
83
|
}
|
9b30ab8c
刘淇
新增快速工单,原版
|
84
85
86
87
88
|
// 修复2:调用字典接口时,不直接抛错(避免阻断登录)
try {
const dictRes = await this.getAndSaveDictData();
// 仅接口返回成功时才更新字典
this.dictData = dictRes || {};
|
3cbb8754
刘淇
动态字典
|
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
|
console.log("字典数据获取成功:", this.dictData);
// 获取原始完整字典
const originDictList = uni.$dict.getDictSimpleList("business_line");
console.log("原始完整字典:", originDictList);
// ========== 核心:根据 userInfo.busiLine 过滤,结果存入 dictList ==========
// this.userInfo?.busiLine
console.log("用户信息", this.userInfo.user);
if (this.userInfo.user.busiLine && originDictList?.length) {
const busiValueArr = this.userInfo.user.busiLine
.split(",")
.map((item) => item.trim())
.filter(Boolean);
this.dictList = originDictList.filter((item) => {
return busiValueArr.includes(item.value);
});
} else {
this.dictList = [];
}
console.log("过滤完成,dictList = ", this.dictList);
|
9b30ab8c
刘淇
新增快速工单,原版
|
111
|
} catch (dictErr) {
|
3cbb8754
刘淇
动态字典
|
112
113
114
|
console.warn("获取字典失败(不影响登录):", dictErr);
uni.showToast({ title: "获取字典失败,可正常使用", icon: "none" });
this.dictList = []; // 异常情况置空
|
9b30ab8c
刘淇
新增快速工单,原版
|
115
|
}
|
e6a04285
刘淇
单图情况 宽高70*70
|
116
117
|
// 新增:登录成功后,启动 Token 自动刷新定时器
this.startRefreshTokenTimer();
|
c293da23
刘淇
新园林init
|
118
119
|
return { ...res, userInfo, moduleListInfo };
} catch (err) {
|
3cbb8754
刘淇
动态字典
|
120
|
console.error("登录流程失败:", err);
|
c293da23
刘淇
新园林init
|
121
122
123
|
throw err;
}
},
|
e6a04285
刘淇
单图情况 宽高70*70
|
124
125
126
127
|
// 新增:调用刷新Token接口,返回刷新是否成功
async refreshTokenApi() {
// 前置校验:无Refresh Token直接返回失败
if (!this.refreshToken) {
|
3cbb8754
刘淇
动态字典
|
128
|
console.warn("无刷新令牌,无法刷新Token");
|
e6a04285
刘淇
单图情况 宽高70*70
|
129
130
131
|
this.logout(); // 无刷新令牌,直接退出登录
return false;
}
|
e6a04285
刘淇
单图情况 宽高70*70
|
132
133
134
|
try {
// 调用修正后的 refreshToken 接口,传入当前的 refreshToken
const res = await refreshToken(this.refreshToken);
|
e6a04285
刘淇
单图情况 宽高70*70
|
135
136
|
// 校验接口返回结果(根据你的实际接口返回格式调整)
if (!res || !res.accessToken) {
|
3cbb8754
刘淇
动态字典
|
137
|
throw new Error("刷新Token失败,未获取到新令牌");
|
e6a04285
刘淇
单图情况 宽高70*70
|
138
|
}
|
e6a04285
刘淇
单图情况 宽高70*70
|
139
140
141
142
|
// 更新 Token 相关状态
this.token = res.accessToken; // 新的访问令牌
this.refreshToken = res.refreshToken || this.refreshToken; // 若接口返回新的Refresh Token则更新
this.expireTime = res.expiresTime; // 新的过期时间
|
3cbb8754
刘淇
动态字典
|
143
|
console.log("Token 刷新成功");
|
e6a04285
刘淇
单图情况 宽高70*70
|
144
145
|
return true;
} catch (err) {
|
3cbb8754
刘淇
动态字典
|
146
|
console.error("刷新Token失败:", err);
|
e6a04285
刘淇
单图情况 宽高70*70
|
147
148
149
150
151
|
// 刷新失败,直接退出登录
this.logout();
return false;
}
},
|
e6a04285
刘淇
单图情况 宽高70*70
|
152
153
154
155
156
157
158
|
// 新增:启动 Token 自动刷新定时器
startRefreshTokenTimer() {
// 先清除已有定时器,避免重复创建
if (refreshTokenTimer) {
clearTimeout(refreshTokenTimer);
refreshTokenTimer = null;
}
|
e6a04285
刘淇
单图情况 宽高70*70
|
159
160
161
162
163
164
165
|
// 计算剩余时间(过期前30秒执行刷新)
const remainingTime = this.expireTime - Date.now() - 30 * 1000;
if (remainingTime <= 0) {
// 剩余时间不足,立即执行刷新
this.refreshTokenApi();
return;
}
|
e6a04285
刘淇
单图情况 宽高70*70
|
166
167
168
169
170
171
172
173
|
// 设置定时器,到期后执行刷新
refreshTokenTimer = setTimeout(async () => {
const refreshSuccess = await this.refreshTokenApi();
// 刷新成功后,重新启动定时器(循环自动刷新)
if (refreshSuccess) {
this.startRefreshTokenTimer();
}
}, remainingTime);
|
3cbb8754
刘淇
动态字典
|
174
175
176
|
console.log(
`Token 自动刷新定时器已启动,将在 ${Math.ceil(remainingTime / 1000)} 秒后执行刷新`,
);
|
e6a04285
刘淇
单图情况 宽高70*70
|
177
|
},
|
e6a04285
刘淇
单图情况 宽高70*70
|
178
179
180
181
182
183
184
|
// 新增:停止 Token 自动刷新定时器(避免内存泄漏)
stopRefreshTokenTimer() {
if (refreshTokenTimer) {
clearTimeout(refreshTokenTimer);
refreshTokenTimer = null;
}
},
|
9b30ab8c
刘淇
新增快速工单,原版
|
185
186
187
188
|
// 修复3:重构字典获取方法(加 Token 校验 + 强制携带 Token + 宽松错误处理)
async getAndSaveDictData() {
// 前置校验:无登录态直接返回,不请求接口
if (!this.isLogin) {
|
3cbb8754
刘淇
动态字典
|
189
190
|
console.warn("未登录,跳过字典获取");
return { code: -1, msg: "未登录" };
|
9b30ab8c
刘淇
新增快速工单,原版
|
191
|
}
|
9b30ab8c
刘淇
新增快速工单,原版
|
192
193
194
195
|
try {
// 强制携带 Token(和 getModuleList 保持一致,避免拦截器同步延迟)
const res = await getSimpleDictDataList(
{}, // 接口入参(按需传,比如 dictType: ['level'])
|
3cbb8754
刘淇
动态字典
|
196
|
{ header: { Authorization: `Bearer ${this.token}` } },
|
9b30ab8c
刘淇
新增快速工单,原版
|
197
|
);
|
9b30ab8c
刘淇
新增快速工单,原版
|
198
199
|
// 校验接口返回码(核心:避免非 0 码数据存入)
if (res.code !== 0) {
|
3cbb8754
刘淇
动态字典
|
200
|
console.warn("字典接口返回失败:", res.msg);
|
9b30ab8c
刘淇
新增快速工单,原版
|
201
202
203
204
205
|
return res; // 返回错误信息,但不抛错
}
return res;
} catch (err) {
// 修复4:宽松错误处理,只打印日志,不抛错(避免阻断登录)
|
3cbb8754
刘淇
动态字典
|
206
207
208
209
210
|
console.error("字典接口请求异常:", err);
return {
code: -2,
msg: "接口请求异常:" + (err.message || "网络错误"),
};
|
9b30ab8c
刘淇
新增快速工单,原版
|
211
212
|
}
},
|
c293da23
刘淇
新园林init
|
213
214
|
async getModuleList() {
try {
|
c293da23
刘淇
新园林init
|
215
|
if (!this.token) {
|
3cbb8754
刘淇
动态字典
|
216
|
throw new Error("未获取到登录令牌,无法获取模块列表");
|
c293da23
刘淇
新园林init
|
217
|
}
|
3cbb8754
刘淇
动态字典
|
218
219
220
221
222
223
|
const res = await moduleList(
{},
{
header: { Authorization: `Bearer ${this.token}` },
},
);
|
c293da23
刘淇
新园林init
|
224
225
|
return res;
} catch (err) {
|
3cbb8754
刘淇
动态字典
|
226
227
228
|
console.error("获取用户菜单失败:", err);
if (err?.data?.code === 401 || err?.message.includes("401")) {
throw new Error("登录态已过期,请重新登录");
|
c293da23
刘淇
新园林init
|
229
|
} else {
|
3cbb8754
刘淇
动态字典
|
230
|
throw new Error("获取用户菜单失败,请重新登录");
|
c293da23
刘淇
新园林init
|
231
232
233
|
}
}
},
|
c293da23
刘淇
新园林init
|
234
235
|
async getUserInfo() {
try {
|
c293da23
刘淇
新园林init
|
236
237
238
|
const res = await getUserInfo();
return res;
} catch (err) {
|
3cbb8754
刘淇
动态字典
|
239
240
|
console.error("获取用户信息失败:", err);
throw new Error("获取用户信息失败,请重新登录");
|
c293da23
刘淇
新园林init
|
241
242
|
}
},
|
c293da23
刘淇
新园林init
|
243
|
logout() {
|
e6a04285
刘淇
单图情况 宽高70*70
|
244
245
|
// 新增:退出登录时,停止刷新定时器
this.stopRefreshTokenTimer();
|
c293da23
刘淇
新园林init
|
246
247
|
const pages = getCurrentPages();
if (pages.length === 0) return;
|
c293da23
刘淇
新园林init
|
248
249
|
const currentPageRoute = pages[pages.length - 1].route;
const loginPath = globalConfig.router.loginPath
|
3cbb8754
刘淇
动态字典
|
250
251
|
.replace(/^\//, "")
.split("?")[0];
|
c293da23
刘淇
新园林init
|
252
|
if (currentPageRoute === loginPath) {
|
3cbb8754
刘淇
动态字典
|
253
254
|
this.token = "";
this.refreshToken = ""; // 新增:清空Refresh Token
|
c293da23
刘淇
新园林init
|
255
|
this.userInfo = {};
|
3cbb8754
刘淇
动态字典
|
256
257
|
this.userId = "";
this.moduleListInfo = "";
|
c293da23
刘淇
新园林init
|
258
|
this.expireTime = 0;
|
9b30ab8c
刘淇
新增快速工单,原版
|
259
|
this.dictData = {};
|
3cbb8754
刘淇
动态字典
|
260
|
this.dictList = [];
|
c293da23
刘淇
新园林init
|
261
262
|
return;
}
|
c293da23
刘淇
新园林init
|
263
264
265
|
const logoutWithLock = async () => {
if (this.logoutLoading) return;
this.logoutLoading = true;
|
c293da23
刘淇
新园林init
|
266
267
268
|
try {
await logout();
} catch (err) {
|
3cbb8754
刘淇
动态字典
|
269
|
console.error("退出登录接口调用失败:", err);
|
c293da23
刘淇
新园林init
|
270
|
} finally {
|
3cbb8754
刘淇
动态字典
|
271
272
|
this.token = "";
this.refreshToken = ""; // 新增:清空Refresh Token
|
c293da23
刘淇
新园林init
|
273
|
this.userInfo = {};
|
3cbb8754
刘淇
动态字典
|
274
275
|
this.userId = "";
this.moduleListInfo = "";
|
9b30ab8c
刘淇
新增快速工单,原版
|
276
|
this.dictData = {};
|
3cbb8754
刘淇
动态字典
|
277
|
this.dictList = [];
|
c293da23
刘淇
新园林init
|
278
279
|
this.expireTime = 0;
this.logoutLoading = false;
|
c293da23
刘淇
新园林init
|
280
|
uni.redirectTo({
|
3cbb8754
刘淇
动态字典
|
281
|
url: globalConfig.router.loginPath,
|
c293da23
刘淇
新园林init
|
282
283
284
|
});
}
};
|
c293da23
刘淇
新园林init
|
285
286
|
logoutWithLock();
},
|
c293da23
刘淇
新园林init
|
287
288
|
checkLogin() {
if (!this.isLogin) {
|
c293da23
刘淇
新园林init
|
289
290
|
const pages = getCurrentPages();
if (pages.length === 0) return false;
|
c293da23
刘淇
新园林init
|
291
292
|
const currentPageRoute = pages[pages.length - 1].route;
const loginPath = globalConfig.router.loginPath
|
3cbb8754
刘淇
动态字典
|
293
294
|
.replace(/^\//, "")
.split("?")[0];
|
c293da23
刘淇
新园林init
|
295
296
|
if (currentPageRoute !== loginPath) {
uni.redirectTo({
|
3cbb8754
刘淇
动态字典
|
297
|
url: globalConfig.router.loginPath,
|
c293da23
刘淇
新园林init
|
298
299
300
301
|
});
}
return false;
}
|
e6a04285
刘淇
单图情况 宽高70*70
|
302
303
|
// 新增:已登录时,启动刷新定时器(防止页面刷新后定时器丢失)
this.startRefreshTokenTimer();
|
c293da23
刘淇
新园林init
|
304
|
return true;
|
3cbb8754
刘淇
动态字典
|
305
|
},
|
c293da23
刘淇
新园林init
|
306
|
},
|
c293da23
刘淇
新园林init
|
307
308
|
persist: {
enabled: true,
|
3cbb8754
刘淇
动态字典
|
309
|
key: "user_store",
|
c293da23
刘淇
新园林init
|
310
311
312
|
storage: {
getItem: (key) => uni.getStorageSync(key),
setItem: (key, value) => uni.setStorageSync(key, value),
|
3cbb8754
刘淇
动态字典
|
313
|
removeItem: (key) => uni.removeStorageSync(key),
|
c293da23
刘淇
新园林init
|
314
|
},
|
c293da23
刘淇
新园林init
|
315
316
|
serializer: {
serialize: (state) => {
|
c293da23
刘淇
新园林init
|
317
|
uni.setStorageSync(globalConfig.cache.tokenKey, state.token);
|
3cbb8754
刘淇
动态字典
|
318
319
320
321
|
uni.setStorageSync(
globalConfig.cache.refreshTokenKey,
state.refreshToken,
);
|
c293da23
刘淇
新园林init
|
322
323
324
|
uni.setStorageSync(globalConfig.cache.userIdKey, state.userId);
uni.setStorageSync(globalConfig.cache.expireTimeKey, state.expireTime);
uni.setStorageSync(globalConfig.cache.userInfoKey, state.userInfo);
|
3cbb8754
刘淇
动态字典
|
325
326
327
328
|
uni.setStorageSync(
globalConfig.cache.moduleListKey,
state.moduleListInfo,
);
|
9b30ab8c
刘淇
新增快速工单,原版
|
329
|
uni.setStorageSync(globalConfig.cache.dictDataKey, state.dictData);
|
3cbb8754
刘淇
动态字典
|
330
|
uni.setStorageSync(globalConfig.cache.dictListKey, state.dictList);
|
9b30ab8c
刘淇
新增快速工单,原版
|
331
|
return state;
|
c293da23
刘淇
新园林init
|
332
333
|
},
deserialize: (value) => {
|
c293da23
刘淇
新园林init
|
334
|
return {
|
3cbb8754
刘淇
动态字典
|
335
336
337
338
|
token: uni.getStorageSync(globalConfig.cache.tokenKey) || "",
refreshToken:
uni.getStorageSync(globalConfig.cache.refreshTokenKey) || "",
userId: uni.getStorageSync(globalConfig.cache.userIdKey) || "",
|
c293da23
刘淇
新园林init
|
339
340
|
expireTime: uni.getStorageSync(globalConfig.cache.expireTimeKey) || 0,
userInfo: uni.getStorageSync(globalConfig.cache.userInfoKey) || {},
|
3cbb8754
刘淇
动态字典
|
341
342
|
moduleListInfo:
uni.getStorageSync(globalConfig.cache.moduleListKey) || "",
|
9b30ab8c
刘淇
新增快速工单,原版
|
343
|
dictData: uni.getStorageSync(globalConfig.cache.dictDataKey) || {},
|
3cbb8754
刘淇
动态字典
|
344
345
|
dictList: uni.getStorageSync(globalConfig.cache.dictListKey) || [],
logoutLoading: false,
|
c293da23
刘淇
新园林init
|
346
|
};
|
3cbb8754
刘淇
动态字典
|
347
|
},
|
c293da23
刘淇
新园林init
|
348
|
},
|
3cbb8754
刘淇
动态字典
|
349
350
|
},
});
|