@infly/libs 2.0.26 → 2.0.36

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -17,21 +17,23 @@ import TokenService from "./TokenService";
17
17
  * * @returns {void}
18
18
  */
19
19
  export function initPermission({
20
- whiteList = ["/login"],
20
+ whiteList = ["/login", "/404", "/403", "/error/401", "/error/404"],
21
21
  getUserInfoAction = "user/getInfo",
22
22
  resetTokenAction = "user/resetToken",
23
23
  refreshTokenAction = "user/refreshToken",
24
24
  pagePathCacheKey, // 页面路径缓存
25
25
  router,
26
26
  store,
27
- defaultSettings = {},
27
+ defaultSettings,
28
+ settings = defaultSettings || {},
28
29
  NProgress,
29
30
  Message,
30
31
  getUserInfo,
31
32
  resetToken,
32
33
  showMessage
33
34
  }) {
34
- const { title: projectTitle } = defaultSettings || {};
35
+ const { title: projectTitle, projectConfig } = settings || {};
36
+ const { initRoutePath = "/" } = projectConfig || {};
35
37
  const { dispatch } = store || {};
36
38
 
37
39
  const redirectToLogin = (to, next) => {
@@ -78,56 +80,113 @@ export function initPermission({
78
80
 
79
81
  NProgress.configure({ showSpinner: false });
80
82
 
81
- router.beforeEach(async (to, from, next) => {
82
- NProgress.start();
83
- document.title = handlePageTitle(to.meta.title);
83
+ // 辅助函数:处理 URL token 参数
84
+ const handleUrlTokenParam = async (to, next, accessTokenKey, accessToken) => {
85
+ if (!to.query[accessTokenKey]) return false;
86
+
87
+ const newQuery = { ...to.query };
84
88
 
85
- if (!whiteList.includes(to.path) && pagePathCacheKey) {
86
- localStorage.setItem(pagePathCacheKey, window.location.href);
89
+ // 优先从地址栏获取token, 更新存储token值
90
+ if (accessToken && Uts.isFunction(dispatch)) {
91
+ try {
92
+ await dispatch(refreshTokenAction, { token: accessToken });
93
+ } catch (error) {
94
+ console.error("[Token Refresh Error]:", error);
95
+ }
87
96
  }
88
97
 
89
- const Token = TokenService.getToken();
90
- const accessTokenKey = TokenService.getUrlTokenKey();
91
- const accessToken = TokenService.getUrlToken();
98
+ delete newQuery[accessTokenKey];
99
+ next({ path: to.path, query: newQuery, replace: true });
100
+ return true;
101
+ };
92
102
 
93
- // 处理 URL 中的 accessToken 参数
94
- if (to.query[accessTokenKey]) {
95
- const newQuery = { ...to.query };
103
+ // 辅助函数:检查权限
104
+ const checkPermission = (permission) => {
105
+ if (!permission) return true;
96
106
 
97
- // 优先从地址栏获取token, 更新存储token值
98
- if (accessToken && Uts.isFunction(dispatch)) {
99
- await dispatch(refreshTokenAction, { token: accessToken });
100
- }
107
+ const hasPermission = Uts.getPM(permission);
101
108
 
102
- delete newQuery[accessTokenKey];
103
- NProgress.done();
104
- return next({ path: to.path, query: newQuery, replace: true });
109
+ if (!hasPermission) {
110
+ console.warn(`[权限不足] 需要权限: ${permission}`);
105
111
  }
106
112
 
107
- // 检查白名单路径
108
- if (whiteList.includes(to.path)) {
109
- NProgress.done();
110
- return next();
113
+ return hasPermission;
114
+ };
115
+
116
+ // 辅助函数:处理已认证用户的路由
117
+ const handleAuthenticatedRoute = async (to, next, permission) => {
118
+ // 已登录用户访问登录页,重定向到首页
119
+ if (to.path === "/login") {
120
+ return next({ path: "/" });
121
+ }
122
+
123
+ try {
124
+ // 获取用户信息
125
+ const { PMRedirectPath } = await handleGetUserInfo();
126
+
127
+ // 如果是进入初始化配置的path:""重定向路由且没权限(PMRedirectPath !== initRoutePath),则重定向到指定有权限的第一条菜单路由
128
+ if (initRoutePath && to.path === initRoutePath && PMRedirectPath !== initRoutePath) {
129
+ return next({ path: PMRedirectPath || "/" });
130
+ }
131
+
132
+ // 检查页面权限
133
+ if (permission && !checkPermission(permission) && !whiteList.includes(to.path)) {
134
+ return next({ path: "/error/403" });
135
+ }
136
+
137
+ next();
138
+ } catch (error) {
139
+ const { message = "" } = error || {};
140
+ console.error("[认证失败]:", message || error);
141
+
142
+ // 可选:显示错误消息
143
+ // handleShowMessage(message || "验证失败,请重新登录");
144
+
145
+ await handleResetToken();
146
+ redirectToLogin(to, next);
111
147
  }
148
+ };
149
+
150
+ router.beforeEach(async (to, from, next) => {
151
+ NProgress.start();
152
+
153
+ try {
154
+ const Token = TokenService.getToken();
155
+ const accessTokenKey = TokenService.getUrlTokenKey();
156
+ const accessToken = TokenService.getUrlToken();
157
+ const { meta = {} } = to || {};
158
+ const { permission } = meta || {};
159
+
160
+ // 设置页面标题
161
+ document.title = handlePageTitle(to.meta.title);
112
162
 
113
- if (Token) {
114
- // 如果已登录,但尝试访问登录页,则重定向到首页
115
- if (to.path === "/login") {
116
- NProgress.done();
117
- next({ path: "/" });
118
- } else {
119
- try {
120
- await handleGetUserInfo();
121
- NProgress.done();
122
- next();
123
- } catch (error) {
124
- const { message = "" } = error || {};
125
- // handleShowMessage(message || error || "验证失败, 请重新登录");
126
- await handleResetToken();
127
- redirectToLogin(to, next);
128
- }
163
+ // 缓存页面路径(非白名单页面)
164
+ if (!whiteList.includes(to.path) && pagePathCacheKey) {
165
+ localStorage.setItem(pagePathCacheKey, window.location.href);
129
166
  }
130
- } else {
167
+
168
+ // 1. 处理 URL token 参数
169
+ if (await handleUrlTokenParam(to, next, accessTokenKey, accessToken)) {
170
+ return;
171
+ }
172
+
173
+ // 2. 检查白名单路径
174
+ if (whiteList.includes(to.path)) {
175
+ return next();
176
+ }
177
+
178
+ // 3. 未登录用户,重定向到登录页
179
+ if (!Token) {
180
+ return redirectToLogin(to, next);
181
+ }
182
+
183
+ // 4. 已登录用户的路由处理
184
+ await handleAuthenticatedRoute(to, next, permission);
185
+ } catch (error) {
186
+ console.error("[路由守卫错误]:", error);
187
+
188
+ // 发生未预期的错误时,重定向到登录页
189
+ await handleResetToken();
131
190
  redirectToLogin(to, next);
132
191
  }
133
192
  });
package/module/REST.js CHANGED
@@ -17,11 +17,15 @@ const isProdAPI = Uts.contain(["https://api.sutpay.com"], baseURL);
17
17
  */
18
18
  export function createService(config) {
19
19
  const {
20
+ baseURL: customBaseURL,
21
+ defaultField = "admin",
22
+ serviceField = defaultField,
20
23
  logoutAction = "user/logout", // 退出登录的action方法
21
24
  onLogout,
22
- onNotify
25
+ onNotify,
26
+ getTokenFunc = "getToken"
23
27
  } = config || {};
24
- const service = axios.create({ baseURL });
28
+ const service = axios.create({ baseURL: customBaseURL || baseURL });
25
29
 
26
30
  /**
27
31
  * 发送通知
@@ -37,13 +41,13 @@ export function createService(config) {
37
41
  // 涉及到store和request循环依赖,导致store为undefined,所以不要引入store来处理而是通过闭包形式
38
42
  const handleLogout = () => {
39
43
  if (Uts.isFunction(onLogout)) {
40
- onLogout(logoutAction);
44
+ onLogout(logoutAction, { redirectLogin: true });
41
45
  }
42
46
  };
43
47
 
44
48
  service.interceptors.request.use(
45
- config => {
46
- const Token = TokenService.getToken();
49
+ (config) => {
50
+ const Token = TokenService[getTokenFunc]();
47
51
 
48
52
  if (Token) {
49
53
  config.headers["Authorization"] = " JWT " + Token;
@@ -57,30 +61,73 @@ export function createService(config) {
57
61
  });
58
62
  }
59
63
 
64
+ // 鼓励金接口特殊处理
65
+ if (customBaseURL) {
66
+ config.url = config.url.replace("https://auth.sutpay.cn/", customBaseURL);
67
+ }
68
+
69
+ if (serviceField !== defaultField) {
70
+ config.url = config.url.replace(`/${defaultField}/`, `/${serviceField}/`);
71
+ }
72
+
73
+ Uts.filterCommaFields(config?.data);
74
+
75
+ Uts.filterCommaFields(config?.params);
76
+
60
77
  return config;
61
78
  },
62
- error => {
79
+ (error) => {
63
80
  return Promise.reject(error);
64
81
  }
65
82
  );
66
83
 
67
84
  service.interceptors.response.use(
68
- response => {
85
+ (response) => {
69
86
  return response.data || {};
70
87
  },
71
- error => {
72
- const { response } = error || {};
73
- const { status } = response || {};
88
+ (error) => {
89
+ const { response, request } = error || {};
90
+ const { status, data } = response || {};
91
+ const { error: dataError, detail, message } = data || {};
92
+
93
+ // 添加标识,表示错误已被拦截器处理
94
+ error.handledByInterceptor = true;
74
95
 
75
- if ([401, 403].includes(status)) {
96
+ // HTTP 状态码错误处理映射
97
+ const STATUS_HANDLERS = {
98
+ 401: { message: "登录信息已过期,请重新登录", action: () => handleLogout() },
99
+ 403: { message: "您没有权限访问,请联系管理员" },
100
+ 500: { message: "服务器内部错误,请联系开发人员" },
101
+ 502: { message: "网关错误,请稍后重试或联系开发人员" },
102
+ 503: { message: "服务暂时不可用,请稍后重试" },
103
+ 504: { message: "网关超时,请稍后重试或联系开发人员" }
104
+ };
105
+
106
+ // 处理特定状态码
107
+ const handler = STATUS_HANDLERS[status];
108
+ if (handler) {
109
+ handleNotify({
110
+ message: handler.message,
111
+ type: "error"
112
+ });
113
+ handler.action?.();
114
+ } else if (response) {
115
+ // 其他 HTTP 错误响应,优先使用后端返回的错误信息
116
+ const errorMsg = dataError || detail || message || `请求失败(${status})`;
117
+ handleNotify({
118
+ message: errorMsg,
119
+ type: "error"
120
+ });
121
+ } else if (request) {
122
+ // 请求已发送但无响应(网络问题)
76
123
  handleNotify({
77
- message: `登录信息已过期(${status}), 请重新登录!`,
124
+ message: "网络请求失败,请检查网络连接",
78
125
  type: "error"
79
126
  });
80
- handleLogout();
81
- } else if ([500, 502].includes(status)) {
127
+ } else {
128
+ // 请求配置错误
82
129
  handleNotify({
83
- message: `服务器异常(${status}),请联系开发人员`,
130
+ message: error.message || "请求配置错误",
84
131
  type: "error"
85
132
  });
86
133
  }
@@ -0,0 +1,15 @@
1
+ export const resetRouter = (RouterInstance, router, constantRoutes) => {
2
+ const newRouter = createRouter(RouterInstance, constantRoutes);
3
+ router.matcher = newRouter.matcher; // reset router
4
+ };
5
+
6
+ export const updateRouter = resetRouter
7
+
8
+ export const createRouter = (RouterInstance, constantRoutes) =>
9
+ new RouterInstance({
10
+ // mode: 'history', // require service support
11
+ scrollBehavior: () => ({
12
+ y: 0
13
+ }),
14
+ routes: constantRoutes || []
15
+ });