Commit 5465f058ceb7b130e456feaebb17c3beedb092a5
1 parent
d5b76892
feat(user): add user login expiration example
Showing
16 changed files
with
149 additions
and
30 deletions
CHANGELOG.zh_CN.md
@@ -7,6 +7,7 @@ | @@ -7,6 +7,7 @@ | ||
7 | - 新增 `JsonPreview`Json 数据查看组件 | 7 | - 新增 `JsonPreview`Json 数据查看组件 |
8 | - 表格的数据列(column)和操作列(actionColumn)的字段可以根据权限和业务来控制是否显示 | 8 | - 表格的数据列(column)和操作列(actionColumn)的字段可以根据权限和业务来控制是否显示 |
9 | - 新增权限控制表格示例(AuthColumn.vue) | 9 | - 新增权限控制表格示例(AuthColumn.vue) |
10 | +- 新增用户登录过期示例 | ||
10 | 11 | ||
11 | ### ⚡ Performance Improvements | 12 | ### ⚡ Performance Improvements |
12 | 13 |
mock/demo/account.ts
1 | import { MockMethod } from 'vite-plugin-mock'; | 1 | import { MockMethod } from 'vite-plugin-mock'; |
2 | -import { resultSuccess } from '../_util'; | 2 | +import { resultSuccess, resultError } from '../_util'; |
3 | 3 | ||
4 | const userInfo = { | 4 | const userInfo = { |
5 | name: 'Vben', | 5 | name: 'Vben', |
@@ -51,4 +51,12 @@ export default [ | @@ -51,4 +51,12 @@ export default [ | ||
51 | return resultSuccess(userInfo); | 51 | return resultSuccess(userInfo); |
52 | }, | 52 | }, |
53 | }, | 53 | }, |
54 | + { | ||
55 | + url: '/basic-api/user/sessionTimeout', | ||
56 | + method: 'post', | ||
57 | + statusCode: 401, | ||
58 | + response: () => { | ||
59 | + return resultError(); | ||
60 | + }, | ||
61 | + }, | ||
54 | ] as MockMethod[]; | 62 | ] as MockMethod[]; |
src/api/demo/account.ts
@@ -3,8 +3,11 @@ import { GetAccountInfoModel } from './model/accountModel'; | @@ -3,8 +3,11 @@ import { GetAccountInfoModel } from './model/accountModel'; | ||
3 | 3 | ||
4 | enum Api { | 4 | enum Api { |
5 | ACCOUNT_INFO = '/account/getAccountInfo', | 5 | ACCOUNT_INFO = '/account/getAccountInfo', |
6 | + SESSION_TIMEOUT = '/user/sessionTimeout', | ||
6 | } | 7 | } |
7 | 8 | ||
8 | // Get personal center-basic settings | 9 | // Get personal center-basic settings |
9 | 10 | ||
10 | export const accountInfoApi = () => defHttp.get<GetAccountInfoModel>({ url: Api.ACCOUNT_INFO }); | 11 | export const accountInfoApi = () => defHttp.get<GetAccountInfoModel>({ url: Api.ACCOUNT_INFO }); |
12 | + | ||
13 | +export const sessionTimeoutApi = () => defHttp.post<void>({ url: Api.SESSION_TIMEOUT }); |
src/layouts/default/feature/index.vue
@@ -5,28 +5,29 @@ | @@ -5,28 +5,29 @@ | ||
5 | import { useRootSetting } from '/@/hooks/setting/useRootSetting'; | 5 | import { useRootSetting } from '/@/hooks/setting/useRootSetting'; |
6 | import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting'; | 6 | import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting'; |
7 | import { useDesign } from '/@/hooks/web/useDesign'; | 7 | import { useDesign } from '/@/hooks/web/useDesign'; |
8 | + import { useUserStoreWidthOut } from '/@/store/modules/user'; | ||
8 | 9 | ||
9 | import { SettingButtonPositionEnum } from '/@/enums/appEnum'; | 10 | import { SettingButtonPositionEnum } from '/@/enums/appEnum'; |
10 | import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent'; | 11 | import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent'; |
11 | 12 | ||
13 | + import SessionTimeoutLogin from '/@/views/sys/login/SessionTimeoutLogin.vue'; | ||
12 | export default defineComponent({ | 14 | export default defineComponent({ |
13 | name: 'LayoutFeatures', | 15 | name: 'LayoutFeatures', |
14 | components: { | 16 | components: { |
15 | BackTop, | 17 | BackTop, |
16 | LayoutLockPage: createAsyncComponent(() => import('/@/views/sys/lock/index.vue')), | 18 | LayoutLockPage: createAsyncComponent(() => import('/@/views/sys/lock/index.vue')), |
17 | SettingDrawer: createAsyncComponent(() => import('/@/layouts/default/setting/index.vue')), | 19 | SettingDrawer: createAsyncComponent(() => import('/@/layouts/default/setting/index.vue')), |
20 | + SessionTimeoutLogin, | ||
18 | }, | 21 | }, |
19 | setup() { | 22 | setup() { |
20 | - const { | ||
21 | - getUseOpenBackTop, | ||
22 | - getShowSettingButton, | ||
23 | - getSettingButtonPosition, | ||
24 | - getFullContent, | ||
25 | - } = useRootSetting(); | ||
26 | - | 23 | + const { getUseOpenBackTop, getShowSettingButton, getSettingButtonPosition, getFullContent } = |
24 | + useRootSetting(); | ||
25 | + const userStore = useUserStoreWidthOut(); | ||
27 | const { prefixCls } = useDesign('setting-drawer-fearure'); | 26 | const { prefixCls } = useDesign('setting-drawer-fearure'); |
28 | const { getShowHeader } = useHeaderSetting(); | 27 | const { getShowHeader } = useHeaderSetting(); |
29 | 28 | ||
29 | + const getIsSessionTimeout = computed(() => userStore.getSessionTimeout); | ||
30 | + | ||
30 | const getIsFixedSettingDrawer = computed(() => { | 31 | const getIsFixedSettingDrawer = computed(() => { |
31 | if (!unref(getShowSettingButton)) { | 32 | if (!unref(getShowSettingButton)) { |
32 | return false; | 33 | return false; |
@@ -44,6 +45,7 @@ | @@ -44,6 +45,7 @@ | ||
44 | getUseOpenBackTop, | 45 | getUseOpenBackTop, |
45 | getIsFixedSettingDrawer, | 46 | getIsFixedSettingDrawer, |
46 | prefixCls, | 47 | prefixCls, |
48 | + getIsSessionTimeout, | ||
47 | }; | 49 | }; |
48 | }, | 50 | }, |
49 | }); | 51 | }); |
@@ -53,6 +55,7 @@ | @@ -53,6 +55,7 @@ | ||
53 | <LayoutLockPage /> | 55 | <LayoutLockPage /> |
54 | <BackTop v-if="getUseOpenBackTop" :target="getTarget" /> | 56 | <BackTop v-if="getUseOpenBackTop" :target="getTarget" /> |
55 | <SettingDrawer v-if="getIsFixedSettingDrawer" :class="prefixCls" /> | 57 | <SettingDrawer v-if="getIsFixedSettingDrawer" :class="prefixCls" /> |
58 | + <SessionTimeoutLogin v-if="getIsSessionTimeout" /> | ||
56 | </template> | 59 | </template> |
57 | 60 | ||
58 | <style lang="less"> | 61 | <style lang="less"> |
src/locales/lang/en/routes/demo/feat.ts
@@ -2,6 +2,7 @@ export default { | @@ -2,6 +2,7 @@ export default { | ||
2 | feat: 'Page Function', | 2 | feat: 'Page Function', |
3 | icon: 'Icon', | 3 | icon: 'Icon', |
4 | tabs: 'Tabs', | 4 | tabs: 'Tabs', |
5 | + sessionTimeout: 'Session Timeout', | ||
5 | print: 'Print', | 6 | print: 'Print', |
6 | contextMenu: 'Context Menu', | 7 | contextMenu: 'Context Menu', |
7 | download: 'Download', | 8 | download: 'Download', |
src/locales/lang/zh_CN/routes/demo/feat.ts
src/router/menus/modules/demo/comp.ts
@@ -6,9 +6,6 @@ const menu: MenuModule = { | @@ -6,9 +6,6 @@ const menu: MenuModule = { | ||
6 | menu: { | 6 | menu: { |
7 | name: t('routes.demo.comp.comp'), | 7 | name: t('routes.demo.comp.comp'), |
8 | path: '/comp', | 8 | path: '/comp', |
9 | - tag: { | ||
10 | - dot: true, | ||
11 | - }, | ||
12 | children: [ | 9 | children: [ |
13 | { | 10 | { |
14 | path: 'basic', | 11 | path: 'basic', |
@@ -191,9 +188,6 @@ const menu: MenuModule = { | @@ -191,9 +188,6 @@ const menu: MenuModule = { | ||
191 | { | 188 | { |
192 | name: t('routes.demo.editor.editor'), | 189 | name: t('routes.demo.editor.editor'), |
193 | path: 'editor', | 190 | path: 'editor', |
194 | - tag: { | ||
195 | - dot: true, | ||
196 | - }, | ||
197 | children: [ | 191 | children: [ |
198 | { | 192 | { |
199 | path: 'json', | 193 | path: 'json', |
src/router/menus/modules/demo/feat.ts
@@ -6,7 +6,9 @@ const menu: MenuModule = { | @@ -6,7 +6,9 @@ const menu: MenuModule = { | ||
6 | menu: { | 6 | menu: { |
7 | name: t('routes.demo.feat.feat'), | 7 | name: t('routes.demo.feat.feat'), |
8 | path: '/feat', | 8 | path: '/feat', |
9 | - | 9 | + tag: { |
10 | + dot: true, | ||
11 | + }, | ||
10 | children: [ | 12 | children: [ |
11 | { | 13 | { |
12 | path: 'icon', | 14 | path: 'icon', |
@@ -17,6 +19,13 @@ const menu: MenuModule = { | @@ -17,6 +19,13 @@ const menu: MenuModule = { | ||
17 | name: t('routes.demo.feat.ws'), | 19 | name: t('routes.demo.feat.ws'), |
18 | }, | 20 | }, |
19 | { | 21 | { |
22 | + name: t('routes.demo.feat.sessionTimeout'), | ||
23 | + path: 'session-timeout', | ||
24 | + tag: { | ||
25 | + content: 'new', | ||
26 | + }, | ||
27 | + }, | ||
28 | + { | ||
20 | path: 'tabs', | 29 | path: 'tabs', |
21 | name: t('routes.demo.feat.tabs'), | 30 | name: t('routes.demo.feat.tabs'), |
22 | }, | 31 | }, |
src/router/menus/modules/demo/flow.ts
@@ -6,17 +6,10 @@ const menu: MenuModule = { | @@ -6,17 +6,10 @@ const menu: MenuModule = { | ||
6 | menu: { | 6 | menu: { |
7 | name: t('routes.demo.flow.name'), | 7 | name: t('routes.demo.flow.name'), |
8 | path: '/flow', | 8 | path: '/flow', |
9 | - tag: { | ||
10 | - dot: true, | ||
11 | - }, | ||
12 | - | ||
13 | children: [ | 9 | children: [ |
14 | { | 10 | { |
15 | path: 'flowChart', | 11 | path: 'flowChart', |
16 | name: t('routes.demo.flow.flowChart'), | 12 | name: t('routes.demo.flow.flowChart'), |
17 | - tag: { | ||
18 | - content: 'new', | ||
19 | - }, | ||
20 | }, | 13 | }, |
21 | ], | 14 | ], |
22 | }, | 15 | }, |
src/router/routes/modules/demo/feat.ts
@@ -12,6 +12,7 @@ const feat: AppRouteModule = { | @@ -12,6 +12,7 @@ const feat: AppRouteModule = { | ||
12 | icon: 'ion:git-compare-outline', | 12 | icon: 'ion:git-compare-outline', |
13 | title: t('routes.demo.feat.feat'), | 13 | title: t('routes.demo.feat.feat'), |
14 | }, | 14 | }, |
15 | + | ||
15 | children: [ | 16 | children: [ |
16 | { | 17 | { |
17 | path: 'icon', | 18 | path: 'icon', |
@@ -30,6 +31,14 @@ const feat: AppRouteModule = { | @@ -30,6 +31,14 @@ const feat: AppRouteModule = { | ||
30 | }, | 31 | }, |
31 | }, | 32 | }, |
32 | { | 33 | { |
34 | + path: 'session-timeout', | ||
35 | + name: 'SessionTimeout', | ||
36 | + component: () => import('/@/views/demo/feat/session-timeout/index.vue'), | ||
37 | + meta: { | ||
38 | + title: t('routes.demo.feat.sessionTimeout'), | ||
39 | + }, | ||
40 | + }, | ||
41 | + { | ||
33 | path: 'print', | 42 | path: 'print', |
34 | name: 'Print', | 43 | name: 'Print', |
35 | component: () => import('/@/views/demo/feat/print/index.vue'), | 44 | component: () => import('/@/views/demo/feat/print/index.vue'), |
src/store/modules/user.ts
@@ -25,6 +25,7 @@ interface UserState { | @@ -25,6 +25,7 @@ interface UserState { | ||
25 | userInfo: Nullable<UserInfo>; | 25 | userInfo: Nullable<UserInfo>; |
26 | token?: string; | 26 | token?: string; |
27 | roleList: RoleEnum[]; | 27 | roleList: RoleEnum[]; |
28 | + sessionTimeout?: boolean; | ||
28 | } | 29 | } |
29 | 30 | ||
30 | export const useUserStore = defineStore({ | 31 | export const useUserStore = defineStore({ |
@@ -36,6 +37,8 @@ export const useUserStore = defineStore({ | @@ -36,6 +37,8 @@ export const useUserStore = defineStore({ | ||
36 | token: undefined, | 37 | token: undefined, |
37 | // roleList | 38 | // roleList |
38 | roleList: [], | 39 | roleList: [], |
40 | + // Whether the login expired | ||
41 | + sessionTimeout: false, | ||
39 | }), | 42 | }), |
40 | getters: { | 43 | getters: { |
41 | getUserInfo(): UserInfo { | 44 | getUserInfo(): UserInfo { |
@@ -47,9 +50,12 @@ export const useUserStore = defineStore({ | @@ -47,9 +50,12 @@ export const useUserStore = defineStore({ | ||
47 | getRoleList(): RoleEnum[] { | 50 | getRoleList(): RoleEnum[] { |
48 | return this.roleList.length > 0 ? this.roleList : getAuthCache<RoleEnum[]>(ROLES_KEY); | 51 | return this.roleList.length > 0 ? this.roleList : getAuthCache<RoleEnum[]>(ROLES_KEY); |
49 | }, | 52 | }, |
53 | + getSessionTimeout(): boolean { | ||
54 | + return !!this.sessionTimeout; | ||
55 | + }, | ||
50 | }, | 56 | }, |
51 | actions: { | 57 | actions: { |
52 | - setToken(info: string) { | 58 | + setToken(info: string | undefined) { |
53 | this.token = info; | 59 | this.token = info; |
54 | setAuthCache(TOKEN_KEY, info); | 60 | setAuthCache(TOKEN_KEY, info); |
55 | }, | 61 | }, |
@@ -61,10 +67,14 @@ export const useUserStore = defineStore({ | @@ -61,10 +67,14 @@ export const useUserStore = defineStore({ | ||
61 | this.userInfo = info; | 67 | this.userInfo = info; |
62 | setAuthCache(USER_INFO_KEY, info); | 68 | setAuthCache(USER_INFO_KEY, info); |
63 | }, | 69 | }, |
70 | + setSessionTimeout(flag: boolean) { | ||
71 | + this.sessionTimeout = flag; | ||
72 | + }, | ||
64 | resetState() { | 73 | resetState() { |
65 | this.userInfo = null; | 74 | this.userInfo = null; |
66 | this.token = ''; | 75 | this.token = ''; |
67 | this.roleList = []; | 76 | this.roleList = []; |
77 | + this.sessionTimeout = false; | ||
68 | }, | 78 | }, |
69 | /** | 79 | /** |
70 | * @description: login | 80 | * @description: login |
@@ -85,7 +95,9 @@ export const useUserStore = defineStore({ | @@ -85,7 +95,9 @@ export const useUserStore = defineStore({ | ||
85 | // get user info | 95 | // get user info |
86 | const userInfo = await this.getUserInfoAction({ userId }); | 96 | const userInfo = await this.getUserInfoAction({ userId }); |
87 | 97 | ||
88 | - goHome && (await router.replace(PageEnum.BASE_HOME)); | 98 | + const sessionTimeout = this.sessionTimeout; |
99 | + sessionTimeout && this.setSessionTimeout(false); | ||
100 | + !sessionTimeout && goHome && (await router.replace(PageEnum.BASE_HOME)); | ||
89 | return userInfo; | 101 | return userInfo; |
90 | } catch (error) { | 102 | } catch (error) { |
91 | return null; | 103 | return null; |
src/utils/http/axios/checkStatus.ts
1 | import { useMessage } from '/@/hooks/web/useMessage'; | 1 | import { useMessage } from '/@/hooks/web/useMessage'; |
2 | import { useI18n } from '/@/hooks/web/useI18n'; | 2 | import { useI18n } from '/@/hooks/web/useI18n'; |
3 | -import router from '/@/router'; | ||
4 | -import { PageEnum } from '/@/enums/pageEnum'; | 3 | +// import router from '/@/router'; |
4 | +// import { PageEnum } from '/@/enums/pageEnum'; | ||
5 | +import { useUserStoreWidthOut } from '/@/store/modules/user'; | ||
5 | 6 | ||
6 | const { createMessage } = useMessage(); | 7 | const { createMessage } = useMessage(); |
7 | 8 | ||
8 | const error = createMessage.error!; | 9 | const error = createMessage.error!; |
9 | export function checkStatus(status: number, msg: string): void { | 10 | export function checkStatus(status: number, msg: string): void { |
10 | const { t } = useI18n(); | 11 | const { t } = useI18n(); |
12 | + const userStore = useUserStoreWidthOut(); | ||
11 | switch (status) { | 13 | switch (status) { |
12 | case 400: | 14 | case 400: |
13 | error(`${msg}`); | 15 | error(`${msg}`); |
@@ -17,7 +19,8 @@ export function checkStatus(status: number, msg: string): void { | @@ -17,7 +19,8 @@ export function checkStatus(status: number, msg: string): void { | ||
17 | // Return to the current page after successful login. This step needs to be operated on the login page. | 19 | // Return to the current page after successful login. This step needs to be operated on the login page. |
18 | case 401: | 20 | case 401: |
19 | error(t('sys.api.errMsg401')); | 21 | error(t('sys.api.errMsg401')); |
20 | - router.push(PageEnum.BASE_LOGIN); | 22 | + userStore.setToken(undefined); |
23 | + userStore.setSessionTimeout(true); | ||
21 | break; | 24 | break; |
22 | case 403: | 25 | case 403: |
23 | error(t('sys.api.errMsg403')); | 26 | error(t('sys.api.errMsg403')); |
src/utils/http/axios/helper.ts
1 | import { isObject, isString } from '/@/utils/is'; | 1 | import { isObject, isString } from '/@/utils/is'; |
2 | 2 | ||
3 | +const DATE_TIME_FORMAT = 'YYYY-MM-DD HH:mm'; | ||
4 | + | ||
3 | export function createNow<T extends boolean>( | 5 | export function createNow<T extends boolean>( |
4 | join: boolean, | 6 | join: boolean, |
5 | restful: T | 7 | restful: T |
@@ -16,7 +18,6 @@ export function createNow(join: boolean, restful = false): string | object { | @@ -16,7 +18,6 @@ export function createNow(join: boolean, restful = false): string | object { | ||
16 | return { _t: now }; | 18 | return { _t: now }; |
17 | } | 19 | } |
18 | 20 | ||
19 | -const DATE_TIME_FORMAT = 'YYYY-MM-DD HH:mm'; | ||
20 | /** | 21 | /** |
21 | * @description: Format request parameter time | 22 | * @description: Format request parameter time |
22 | */ | 23 | */ |
src/views/demo/feat/session-timeout/index.vue
0 → 100644
1 | +<template> | ||
2 | + <PageWrapper | ||
3 | + title="登录过期示例" | ||
4 | + content="用户登录过期示例,不再跳转登录页,直接生成页面覆盖当前页面,方便保持过期前的用户状态!" | ||
5 | + > | ||
6 | + <a-button type="primary" @click="test">点击触发用户登录过期</a-button> | ||
7 | + </PageWrapper> | ||
8 | +</template> | ||
9 | +<script lang="ts"> | ||
10 | + import { defineComponent } from 'vue'; | ||
11 | + import { PageWrapper } from '/@/components/Page'; | ||
12 | + | ||
13 | + import { sessionTimeoutApi } from '/@/api/demo/account'; | ||
14 | + | ||
15 | + export default defineComponent({ | ||
16 | + name: 'TestSessionTimeout', | ||
17 | + components: { PageWrapper }, | ||
18 | + setup() { | ||
19 | + async function test() { | ||
20 | + await sessionTimeoutApi(); | ||
21 | + } | ||
22 | + return { test }; | ||
23 | + }, | ||
24 | + }); | ||
25 | +</script> |
src/views/sys/login/Login.vue
@@ -3,8 +3,9 @@ | @@ -3,8 +3,9 @@ | ||
3 | <AppLocalePicker | 3 | <AppLocalePicker |
4 | class="absolute top-4 right-4 enter-x text-white xl:text-gray-600" | 4 | class="absolute top-4 right-4 enter-x text-white xl:text-gray-600" |
5 | :showText="false" | 5 | :showText="false" |
6 | + v-if="!sessionTimeout" | ||
6 | /> | 7 | /> |
7 | - <AppDarkModeToggle class="absolute top-3 right-7 enter-x" /> | 8 | + <AppDarkModeToggle class="absolute top-3 right-7 enter-x" v-if="!sessionTimeout" /> |
8 | 9 | ||
9 | <span class="-enter-x xl:hidden"> | 10 | <span class="-enter-x xl:hidden"> |
10 | <AppLogo :alwaysShowTitle="true" /> | 11 | <AppLogo :alwaysShowTitle="true" /> |
@@ -31,7 +32,25 @@ | @@ -31,7 +32,25 @@ | ||
31 | <div class="h-full xl:h-auto flex py-5 xl:py-0 xl:my-0 w-full xl:w-6/12"> | 32 | <div class="h-full xl:h-auto flex py-5 xl:py-0 xl:my-0 w-full xl:w-6/12"> |
32 | <div | 33 | <div |
33 | :class="`${prefixCls}-form`" | 34 | :class="`${prefixCls}-form`" |
34 | - class="my-auto mx-auto xl:ml-20 xl:bg-transparent px-5 py-8 sm:px-8 xl:p-4 rounded-md shadow-md xl:shadow-none w-full sm:w-3/4 lg:w-2/4 xl:w-auto enter-x relative" | 35 | + class=" |
36 | + my-auto | ||
37 | + mx-auto | ||
38 | + xl:ml-20 | ||
39 | + xl:bg-transparent | ||
40 | + px-5 | ||
41 | + py-8 | ||
42 | + sm:px-8 | ||
43 | + xl:p-4 | ||
44 | + rounded-md | ||
45 | + shadow-md | ||
46 | + xl:shadow-none | ||
47 | + w-full | ||
48 | + sm:w-3/4 | ||
49 | + lg:w-2/4 | ||
50 | + xl:w-auto | ||
51 | + enter-x | ||
52 | + relative | ||
53 | + " | ||
35 | > | 54 | > |
36 | <LoginForm /> | 55 | <LoginForm /> |
37 | <ForgetPasswordForm /> | 56 | <ForgetPasswordForm /> |
@@ -72,6 +91,11 @@ | @@ -72,6 +91,11 @@ | ||
72 | AppLocalePicker, | 91 | AppLocalePicker, |
73 | AppDarkModeToggle, | 92 | AppDarkModeToggle, |
74 | }, | 93 | }, |
94 | + props: { | ||
95 | + sessionTimeout: { | ||
96 | + type: Boolean, | ||
97 | + }, | ||
98 | + }, | ||
75 | setup() { | 99 | setup() { |
76 | const globSetting = useGlobSetting(); | 100 | const globSetting = useGlobSetting(); |
77 | const { prefixCls } = useDesign('login'); | 101 | const { prefixCls } = useDesign('login'); |
src/views/sys/login/SessionTimeoutLogin.vue
0 → 100644
1 | +<template> | ||
2 | + <transition> | ||
3 | + <div :class="prefixCls"> | ||
4 | + <Login sessionTimeout /> | ||
5 | + </div> | ||
6 | + </transition> | ||
7 | +</template> | ||
8 | +<script lang="ts"> | ||
9 | + import { defineComponent } from 'vue'; | ||
10 | + import Login from './Login.vue'; | ||
11 | + | ||
12 | + import { useDesign } from '/@/hooks/web/useDesign'; | ||
13 | + export default defineComponent({ | ||
14 | + name: 'SessionTimeoutLogin', | ||
15 | + components: { Login }, | ||
16 | + setup() { | ||
17 | + const { prefixCls } = useDesign('st-login'); | ||
18 | + return { prefixCls }; | ||
19 | + }, | ||
20 | + }); | ||
21 | +</script> | ||
22 | +<style lang="less" scoped> | ||
23 | + @prefix-cls: ~'@{namespace}-st-login'; | ||
24 | + | ||
25 | + .@{prefix-cls} { | ||
26 | + position: fixed; | ||
27 | + z-index: 9999999; | ||
28 | + width: 100%; | ||
29 | + height: 100%; | ||
30 | + background: @component-background; | ||
31 | + } | ||
32 | +</style> |