Skip to content

Commit d62a3da

Browse files
committed
perf: improve the logic related to login expiration
1 parent 8e6c1ab commit d62a3da

File tree

43 files changed

+550
-345
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+550
-345
lines changed
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import type { Response } from 'express';
2+
3+
import { Controller, Get, Query, Res } from '@nestjs/common';
4+
5+
@Controller('mock')
6+
export class MockController {
7+
/**
8+
* 用于模拟任意的状态码
9+
* @param res
10+
*/
11+
@Get('status')
12+
async mockAnyStatus(
13+
@Res() res: Response,
14+
@Query() { status }: { status: string },
15+
) {
16+
res.status(Number.parseInt(status, 10)).send({
17+
code: 1,
18+
data: null,
19+
error: null,
20+
message: `code is ${status}`,
21+
});
22+
}
23+
}

apps/backend-mock/src/modules/mock/mock.module.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import { Module } from '@nestjs/common';
22

3+
import { MockController } from './mock.controller';
34
import { MockService } from './mock.service';
45

56
@Module({
7+
controllers: [MockController],
68
exports: [MockService],
79
providers: [MockService],
810
})
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
export * from './menu';
2+
export * from './mock';
23
export * from './user';
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { requestClient } from '#/forward';
2+
3+
/**
4+
* 模拟人意状态码
5+
*/
6+
async function getMockStatus(status: string) {
7+
return requestClient.get('/mock/status', { params: { status } });
8+
}
9+
10+
export { getMockStatus };

apps/web-antd/src/forward/request.ts

Lines changed: 29 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,14 @@
11
/**
22
* 该文件可自行根据业务逻辑进行调整
33
*/
4+
import type { HttpResponse } from '@vben-core/request';
45

5-
import type { AxiosResponse } from '@vben-core/request';
6-
7-
import { RequestClient, isCancelError } from '@vben-core/request';
8-
import { useCoreAccessStore } from '@vben-core/stores';
6+
import { preferences } from '@vben-core/preferences';
7+
import { RequestClient } from '@vben-core/request';
98

109
import { message } from 'ant-design-vue';
1110

12-
interface HttpResponse<T = any> {
13-
/**
14-
* 0 表示成功 其他表示失败
15-
* 0 means success, others means fail
16-
*/
17-
code: number;
18-
data: T;
19-
message: string;
20-
}
11+
import { useAccessStore } from '#/store';
2112

2213
/**
2314
* 创建请求实例
@@ -29,57 +20,40 @@ function createRequestClient() {
2920
// 为每个请求携带 Authorization
3021
makeAuthorization: () => {
3122
return {
32-
handler: () => {
33-
// 这里不能用 useAccessStore,因为 useAccessStore 会导致循环引用
34-
const accessStore = useCoreAccessStore();
23+
// 默认
24+
key: 'Authorization',
25+
tokenHandler: () => {
26+
const accessStore = useAccessStore();
3527
return {
3628
refreshToken: `Bearer ${accessStore.refreshToken}`,
3729
token: `Bearer ${accessStore.accessToken}`,
3830
};
3931
},
40-
// 默认
41-
key: 'Authorization',
32+
unAuthorizedHandler: async () => {
33+
const accessStore = useAccessStore();
34+
accessStore.setAccessToken(null);
35+
36+
if (preferences.app.loginExpiredMode === 'modal') {
37+
accessStore.openLoginExpiredModal = true;
38+
} else {
39+
// 退出登录
40+
await accessStore.logout();
41+
}
42+
},
4243
};
4344
},
45+
makeErrorMessage: (msg) => message.error(msg),
4446
});
45-
setupRequestInterceptors(client);
46-
return client;
47-
}
48-
49-
function setupRequestInterceptors(client: RequestClient) {
50-
client.addResponseInterceptor(
51-
(response: AxiosResponse<HttpResponse>) => {
52-
const { data: responseData, status } = response;
53-
54-
const { code, data, message: msg } = responseData;
55-
56-
if (status >= 200 && status < 400 && code === 0) {
57-
return data;
58-
} else {
59-
message.error(msg);
60-
throw new Error(msg);
61-
}
62-
},
63-
(error: any) => {
64-
if (isCancelError(error)) {
65-
return Promise.reject(error);
66-
}
47+
client.addResponseInterceptor<HttpResponse>((response) => {
48+
const { data: responseData, status } = response;
6749

68-
const err: string = error?.toString?.() ?? '';
69-
let errMsg = '';
70-
if (err?.includes('Network Error')) {
71-
errMsg = '网络错误。';
72-
} else if (error?.message?.includes?.('timeout')) {
73-
errMsg = '请求超时。';
74-
} else {
75-
const data = error?.response?.data;
76-
errMsg = (data?.message || data?.error?.message) ?? '';
77-
}
78-
79-
message.error(errMsg);
80-
return Promise.reject(error);
81-
},
82-
);
50+
const { code, data, message: msg } = responseData;
51+
if (status >= 200 && status < 400 && code === 0) {
52+
return data;
53+
}
54+
throw new Error(msg);
55+
});
56+
return client;
8357
}
8458

8559
const requestClient = createRequestClient();

apps/web-antd/src/layouts/basic.vue

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@ import { LOGIN_PATH } from '@vben/constants';
66
import { IcRoundCreditScore, MdiDriveDocument, MdiGithub } from '@vben/icons';
77
import {
88
BasicLayout,
9-
LoginDialog,
109
Notification,
1110
NotificationItem,
1211
UserDropdown,
1312
} from '@vben/layouts';
13+
import { AuthenticationLoginExpiredModal } from '@vben/universal-ui';
1414
import { openWindow } from '@vben/utils';
1515
import { preferences } from '@vben-core/preferences';
1616
@@ -85,7 +85,7 @@ const menus = computed(() => [
8585
8686
const appStore = useAppStore();
8787
const accessStore = useAccessStore();
88-
const { showLoginDialog, userInfo } = toRefs(accessStore);
88+
const { openLoginExpiredModal, userInfo } = toRefs(accessStore);
8989
const router = useRouter();
9090
9191
async function handleLogout() {
@@ -124,11 +124,11 @@ function handleMakeAll() {
124124
/>
125125
</template>
126126
<template #dialog>
127-
<LoginDialog
128-
:open="showLoginDialog"
127+
<AuthenticationLoginExpiredModal
128+
v-model:open="openLoginExpiredModal"
129129
password-placeholder="123456"
130130
username-placeholder="vben"
131-
@login="accessStore.authLogin"
131+
@submit="accessStore.authLogin"
132132
/>
133133
</template>
134134
</BasicLayout>

apps/web-antd/src/locales/langs/en-US.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,12 @@
2828
"embedded": "Embedded",
2929
"externalLink": "External Link"
3030
},
31-
"fallback": { "title": "Fallback Page" }
31+
"fallback": { "title": "Fallback Page" },
32+
"features": {
33+
"title": "Features",
34+
"hideChildrenInMenu": "Hide Menu Children",
35+
"loginExpired": "Login Expired"
36+
}
3237
}
3338
}
3439
}

apps/web-antd/src/locales/langs/zh-CN.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@
3030
},
3131
"fallback": {
3232
"title": "缺省页"
33+
},
34+
"features": {
35+
"title": "功能",
36+
"hideChildrenInMenu": "隐藏菜单子项",
37+
"loginExpired": "登录过期"
3338
}
3439
}
3540
}

apps/web-antd/src/router/guard.ts

Lines changed: 3 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -93,24 +93,9 @@ function setupAccessGuard(router: Router) {
9393
// 生成路由表
9494
// 当前登录用户拥有的角色标识列表
9595
let userRoles: string[] = [];
96-
try {
97-
const userInfo =
98-
accessStore.userInfo || (await accessStore.fetchUserInfo());
99-
userRoles = userInfo.roles ?? [];
100-
} catch (error: any) {
101-
if (error.status === 409) {
102-
accessStore.setShowLoginDialog(true);
103-
} else if (error.status === 401) {
104-
accessStore.reset();
105-
return {
106-
path: LOGIN_PATH,
107-
// 如不需要,直接删除 query
108-
query: { redirect: encodeURIComponent(to.fullPath) },
109-
// 携带当前跳转的页面,登录后重新跳转该页面
110-
replace: true,
111-
};
112-
}
113-
}
96+
const userInfo =
97+
accessStore.userInfo || (await accessStore.fetchUserInfo());
98+
userRoles = userInfo.roles ?? [];
11499

115100
// 生成菜单和路由
116101
const { accessibleMenus, accessibleRoutes } = await generateAccess({

apps/web-antd/src/router/routes/modules/demos.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,48 @@ const routes: RouteRecordRaw[] = [
125125
},
126126
],
127127
},
128+
{
129+
meta: {
130+
icon: 'mdi:feature-highlight',
131+
title: $t('page.demos.features.title'),
132+
},
133+
name: 'Features',
134+
path: '/features',
135+
redirect: '/features/hide-menu-children',
136+
children: [
137+
{
138+
name: 'HideChildrenInMenuParent',
139+
path: 'hide-children-in-menu',
140+
component: () =>
141+
import('#/views/demos/features/hide-menu-children/parent.vue'),
142+
meta: {
143+
hideChildrenInMenu: true,
144+
icon: 'ic:round-menu',
145+
title: 'page.demos.features.hideChildrenInMenu',
146+
},
147+
children: [
148+
{
149+
name: 'HideChildrenInMenuChildren',
150+
path: 'hide-children-in-menu',
151+
component: () =>
152+
import(
153+
'#/views/demos/features/hide-menu-children/children.vue'
154+
),
155+
},
156+
],
157+
},
158+
{
159+
name: 'LoginExpired',
160+
path: 'login-expired',
161+
component: () =>
162+
import('#/views/demos/features/login-expired/index.vue'),
163+
meta: {
164+
icon: 'mdi:encryption-expiration',
165+
title: $t('page.demos.features.loginExpired'),
166+
},
167+
},
168+
],
169+
},
128170
{
129171
meta: {
130172
icon: 'mdi:lightbulb-error-outline',

0 commit comments

Comments
 (0)