Blame view

pinia/user.js 13.2 KB
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
    },
  });