Commit 4ce1d526c80cd859c815b9e629ae1838f441cf0b
1 parent
e9c28319
refactor(lock-page): refactor lock page
Showing
23 changed files
with
426 additions
and
192 deletions
CHANGELOG.zh_CN.md
src/api/sys/user.ts
... | ... | @@ -5,6 +5,7 @@ import { |
5 | 5 | GetUserInfoByUserIdParams, |
6 | 6 | GetUserInfoByUserIdModel, |
7 | 7 | } from './model/userModel'; |
8 | +import { ErrorMessageMode } from '/@/utils/http/axios/types'; | |
8 | 9 | |
9 | 10 | enum Api { |
10 | 11 | Login = '/login', |
... | ... | @@ -15,7 +16,7 @@ enum Api { |
15 | 16 | /** |
16 | 17 | * @description: user login api |
17 | 18 | */ |
18 | -export function loginApi(params: LoginParams) { | |
19 | +export function loginApi(params: LoginParams, mode: ErrorMessageMode = 'modal') { | |
19 | 20 | return defHttp.request<LoginResultModel>( |
20 | 21 | { |
21 | 22 | url: Api.Login, |
... | ... | @@ -23,7 +24,7 @@ export function loginApi(params: LoginParams) { |
23 | 24 | params, |
24 | 25 | }, |
25 | 26 | { |
26 | - errorMessageMode: 'modal', | |
27 | + errorMessageMode: mode, | |
27 | 28 | } |
28 | 29 | ); |
29 | 30 | } | ... | ... |
src/assets/images/lock-page.jpg deleted
100644 → 0
218 KB
src/design/mixins.less
src/design/var/breakpoint.less
... | ... | @@ -26,9 +26,13 @@ |
26 | 26 | @screen-xxl: 1600px; |
27 | 27 | @screen-xxl-min: @screen-xxl; |
28 | 28 | |
29 | +@screen-xxxl: 1900px; | |
30 | +@screen-xxxl-min: @screen-xxxl; | |
31 | + | |
29 | 32 | // provide a maximum |
30 | 33 | @screen-xs-max: (@screen-sm-min - 1px); |
31 | 34 | @screen-sm-max: (@screen-md-min - 1px); |
32 | 35 | @screen-md-max: (@screen-lg-min - 1px); |
33 | 36 | @screen-lg-max: (@screen-xl-min - 1px); |
34 | 37 | @screen-xl-max: (@screen-xxl-min - 1px); |
38 | +@screen-xxl-max: (@screen-xxxl-min - 1px); | ... | ... |
src/hooks/setting/useRootSetting.ts
... | ... | @@ -42,6 +42,8 @@ const getColorWeak = computed(() => unref(getRootSetting).colorWeak); |
42 | 42 | |
43 | 43 | const getGrayMode = computed(() => unref(getRootSetting).grayMode); |
44 | 44 | |
45 | +const getLockTime = computed(() => unref(getRootSetting).lockTime); | |
46 | + | |
45 | 47 | const getLayoutContentMode = computed(() => |
46 | 48 | unref(getRootSetting).contentMode === ContentEnum.FULL ? ContentEnum.FULL : ContentEnum.FIXED |
47 | 49 | ); |
... | ... | @@ -71,5 +73,6 @@ export function useRootSetting() { |
71 | 73 | getShowSettingButton, |
72 | 74 | getShowFooter, |
73 | 75 | getContentMode, |
76 | + getLockTime, | |
74 | 77 | }; |
75 | 78 | } | ... | ... |
src/hooks/web/useLockPage.ts
1 | -import { computed, onUnmounted, watchEffect } from 'vue'; | |
1 | +import { computed, onUnmounted, unref, watchEffect } from 'vue'; | |
2 | 2 | import { useThrottle } from '/@/hooks/core/useThrottle'; |
3 | 3 | |
4 | 4 | import { appStore } from '/@/store/modules/app'; |
5 | +import { lockStore } from '/@/store/modules/lock'; | |
5 | 6 | import { userStore } from '/@/store/modules/user'; |
7 | +import { useRootSetting } from '../setting/useRootSetting'; | |
6 | 8 | |
7 | 9 | export function useLockPage() { |
10 | + const { getLockTime } = useRootSetting(); | |
8 | 11 | let timeId: TimeoutHandle; |
9 | 12 | |
10 | 13 | function clear(): void { |
... | ... | @@ -30,7 +33,7 @@ export function useLockPage() { |
30 | 33 | } |
31 | 34 | |
32 | 35 | function lockPage(): void { |
33 | - appStore.commitLockInfoState({ | |
36 | + lockStore.commitLockInfoState({ | |
34 | 37 | isLock: true, |
35 | 38 | pwd: undefined, |
36 | 39 | }); |
... | ... | @@ -54,8 +57,7 @@ export function useLockPage() { |
54 | 57 | const [keyupFn] = useThrottle(resetCalcLockTimeout, 2000); |
55 | 58 | |
56 | 59 | return computed(() => { |
57 | - const openLockPage = appStore.getProjectConfig.lockTime; | |
58 | - if (openLockPage) { | |
60 | + if (unref(getLockTime)) { | |
59 | 61 | return { onKeyup: keyupFn, onMousemove: keyupFn }; |
60 | 62 | } else { |
61 | 63 | clear(); |
... | ... | @@ -63,3 +65,9 @@ export function useLockPage() { |
63 | 65 | } |
64 | 66 | }); |
65 | 67 | } |
68 | + | |
69 | +export const getIsLock = computed(() => { | |
70 | + const { getLockInfo } = lockStore; | |
71 | + const { isLock } = getLockInfo; | |
72 | + return isLock; | |
73 | +}); | ... | ... |
src/layouts/default/index.tsx
... | ... | @@ -6,7 +6,7 @@ import LayoutHeader from './header/LayoutHeader'; |
6 | 6 | |
7 | 7 | import LayoutContent from './content'; |
8 | 8 | import LayoutFooter from './footer'; |
9 | -import LayoutLockPage from './lock'; | |
9 | +import LayoutLockPage from './lock/index.vue'; | |
10 | 10 | import LayoutSideBar from './sider'; |
11 | 11 | import SettingBtn from './setting/index.vue'; |
12 | 12 | import LayoutMultipleHeader from './header/LayoutMultipleHeader'; | ... | ... |
src/layouts/default/lock/LockAction.tsx
... | ... | @@ -7,9 +7,9 @@ import { BasicForm, useForm } from '/@/components/Form/index'; |
7 | 7 | |
8 | 8 | import headerImg from '/@/assets/images/header.jpg'; |
9 | 9 | |
10 | -import { appStore } from '/@/store/modules/app'; | |
11 | 10 | import { userStore } from '/@/store/modules/user'; |
12 | 11 | import { useI18n } from '/@/hooks/web/useI18n'; |
12 | +import { lockStore } from '/@/store/modules/lock'; | |
13 | 13 | |
14 | 14 | const prefixCls = 'lock-modal'; |
15 | 15 | export default defineComponent({ |
... | ... | @@ -30,24 +30,16 @@ export default defineComponent({ |
30 | 30 | ], |
31 | 31 | }); |
32 | 32 | |
33 | - async function lock(valid = true) { | |
34 | - let password: string | undefined = ''; | |
33 | + async function lock() { | |
34 | + const values = (await validateFields()) as any; | |
35 | + const password: string | undefined = values.password; | |
36 | + closeModal(); | |
35 | 37 | |
36 | - try { | |
37 | - if (!valid) { | |
38 | - password = undefined; | |
39 | - } else { | |
40 | - const values = (await validateFields()) as any; | |
41 | - password = values.password; | |
42 | - } | |
43 | - closeModal(); | |
44 | - | |
45 | - appStore.commitLockInfoState({ | |
46 | - isLock: true, | |
47 | - pwd: password, | |
48 | - }); | |
49 | - await resetFields(); | |
50 | - } catch (error) {} | |
38 | + lockStore.commitLockInfoState({ | |
39 | + isLock: true, | |
40 | + pwd: password, | |
41 | + }); | |
42 | + await resetFields(); | |
51 | 43 | } |
52 | 44 | |
53 | 45 | return () => ( |
... | ... | @@ -71,9 +63,6 @@ export default defineComponent({ |
71 | 63 | <Button type="primary" block class="mt-2" onClick={lock}> |
72 | 64 | {() => t('layout.header.lockScreenBtn')} |
73 | 65 | </Button> |
74 | - <Button block class="mt-2" onClick={lock.bind(null, false)}> | |
75 | - {() => t('layout.header.notLockScreenPassword')} | |
76 | - </Button> | |
77 | 66 | </div> |
78 | 67 | </div> |
79 | 68 | )} | ... | ... |
src/layouts/default/lock/index.tsx deleted
100644 → 0
1 | -import { defineComponent, unref, computed } from 'vue'; | |
2 | -import { appStore } from '/@/store/modules/app'; | |
3 | -import LockPage from '/@/views/sys/lock/index.vue'; | |
4 | - | |
5 | -export default defineComponent({ | |
6 | - name: 'LayoutLockPage', | |
7 | - setup() { | |
8 | - const getIsLockRef = computed(() => { | |
9 | - const { getLockInfo } = appStore; | |
10 | - const { isLock } = getLockInfo; | |
11 | - return isLock; | |
12 | - }); | |
13 | - return () => { | |
14 | - return unref(getIsLockRef) ? <LockPage /> : null; | |
15 | - }; | |
16 | - }, | |
17 | -}); |
src/layouts/default/lock/index.vue
0 → 100644
1 | +<template> | |
2 | + <transition name="fade-bottom"> | |
3 | + <LockPage v-if="getIsLock" /> | |
4 | + </transition> | |
5 | +</template> | |
6 | +<script lang="ts"> | |
7 | + import { defineComponent } from 'vue'; | |
8 | + import LockPage from '/@/views/sys/lock/index.vue'; | |
9 | + import { getIsLock } from '/@/hooks/web/useLockPage'; | |
10 | + export default defineComponent({ | |
11 | + name: 'LayoutLockPage', | |
12 | + components: { LockPage }, | |
13 | + setup() { | |
14 | + return { getIsLock }; | |
15 | + }, | |
16 | + }); | |
17 | +</script> | ... | ... |
src/locales/lang/en/layout/header.ts
src/locales/lang/en/sys/lock.ts
src/locales/lang/zh_CN/layout/header.ts
src/locales/lang/zh_CN/sys/lock.ts
src/store/modules/app.ts
... | ... | @@ -3,16 +3,10 @@ import type { ProjectConfig } from '/@/types/config'; |
3 | 3 | import { VuexModule, getModule, Module, Mutation, Action } from 'vuex-module-decorators'; |
4 | 4 | import store from '/@/store'; |
5 | 5 | |
6 | -import { PROJ_CFG_KEY, LOCK_INFO_KEY } from '/@/enums/cacheEnum'; | |
6 | +import { PROJ_CFG_KEY } from '/@/enums/cacheEnum'; | |
7 | 7 | |
8 | 8 | import { hotModuleUnregisterModule } from '/@/utils/helper/vuexHelper'; |
9 | -import { | |
10 | - setLocal, | |
11 | - getLocal, | |
12 | - removeLocal, | |
13 | - clearSession, | |
14 | - clearLocal, | |
15 | -} from '/@/utils/helper/persistent'; | |
9 | +import { setLocal, getLocal, clearSession, clearLocal } from '/@/utils/helper/persistent'; | |
16 | 10 | import { deepMerge } from '/@/utils'; |
17 | 11 | |
18 | 12 | import { resetRouter } from '/@/router'; |
... | ... | @@ -37,9 +31,6 @@ class App extends VuexModule { |
37 | 31 | // project config |
38 | 32 | private projectConfigState: ProjectConfig | null = getLocal(PROJ_CFG_KEY); |
39 | 33 | |
40 | - // lock info | |
41 | - private lockInfoState: LockInfo | null = getLocal(LOCK_INFO_KEY); | |
42 | - | |
43 | 34 | // set main overflow hidden |
44 | 35 | private lockMainScrollState = false; |
45 | 36 | |
... | ... | @@ -51,10 +42,6 @@ class App extends VuexModule { |
51 | 42 | return this.lockMainScrollState; |
52 | 43 | } |
53 | 44 | |
54 | - get getLockInfo(): LockInfo { | |
55 | - return this.lockInfoState || ({} as LockInfo); | |
56 | - } | |
57 | - | |
58 | 45 | get getProjectConfig(): ProjectConfig { |
59 | 46 | return this.projectConfigState || ({} as ProjectConfig); |
60 | 47 | } |
... | ... | @@ -75,18 +62,6 @@ class App extends VuexModule { |
75 | 62 | setLocal(PROJ_CFG_KEY, this.projectConfigState); |
76 | 63 | } |
77 | 64 | |
78 | - @Mutation | |
79 | - commitLockInfoState(info: LockInfo): void { | |
80 | - this.lockInfoState = Object.assign({}, this.lockInfoState, info); | |
81 | - setLocal(LOCK_INFO_KEY, this.lockInfoState); | |
82 | - } | |
83 | - | |
84 | - @Mutation | |
85 | - resetLockInfo(): void { | |
86 | - removeLocal(LOCK_INFO_KEY); | |
87 | - this.lockInfoState = null; | |
88 | - } | |
89 | - | |
90 | 65 | @Action |
91 | 66 | async resumeAllState() { |
92 | 67 | resetRouter(); |
... | ... | @@ -111,39 +86,5 @@ class App extends VuexModule { |
111 | 86 | clearTimeout(timeId); |
112 | 87 | } |
113 | 88 | } |
114 | - | |
115 | - /** | |
116 | - * @description: unlock page | |
117 | - */ | |
118 | - @Action | |
119 | - public async unLockAction({ password, valid = true }: { password: string; valid?: boolean }) { | |
120 | - if (!valid) { | |
121 | - this.resetLockInfo(); | |
122 | - return true; | |
123 | - } | |
124 | - const tryLogin = async () => { | |
125 | - try { | |
126 | - const username = userStore.getUserInfoState.username; | |
127 | - const res = await userStore.login({ username, password }, false); | |
128 | - if (res) { | |
129 | - this.resetLockInfo(); | |
130 | - } | |
131 | - return res; | |
132 | - } catch (error) { | |
133 | - return false; | |
134 | - } | |
135 | - }; | |
136 | - | |
137 | - if (this.getLockInfo) { | |
138 | - if (this.getLockInfo.pwd === password) { | |
139 | - this.resetLockInfo(); | |
140 | - return true; | |
141 | - } | |
142 | - const res = await tryLogin(); | |
143 | - return res; | |
144 | - } | |
145 | - const res = await tryLogin(); | |
146 | - return res; | |
147 | - } | |
148 | 89 | } |
149 | 90 | export const appStore = getModule<App>(App); | ... | ... |
src/store/modules/lock.ts
0 → 100644
1 | +import { VuexModule, getModule, Module, Mutation, Action } from 'vuex-module-decorators'; | |
2 | +import store from '/@/store'; | |
3 | + | |
4 | +import { LOCK_INFO_KEY } from '/@/enums/cacheEnum'; | |
5 | + | |
6 | +import { hotModuleUnregisterModule } from '/@/utils/helper/vuexHelper'; | |
7 | +import { setLocal, getLocal, removeLocal } from '/@/utils/helper/persistent'; | |
8 | + | |
9 | +import { userStore } from './user'; | |
10 | + | |
11 | +export interface LockInfo { | |
12 | + pwd: string | undefined; | |
13 | + isLock: boolean; | |
14 | +} | |
15 | + | |
16 | +const NAME = 'lock'; | |
17 | +hotModuleUnregisterModule(NAME); | |
18 | +@Module({ dynamic: true, namespaced: true, store, name: NAME }) | |
19 | +class Lock extends VuexModule { | |
20 | + // lock info | |
21 | + private lockInfoState: LockInfo | null = getLocal(LOCK_INFO_KEY); | |
22 | + | |
23 | + get getLockInfo(): LockInfo { | |
24 | + return this.lockInfoState || ({} as LockInfo); | |
25 | + } | |
26 | + | |
27 | + @Mutation | |
28 | + commitLockInfoState(info: LockInfo): void { | |
29 | + this.lockInfoState = Object.assign({}, this.lockInfoState, info); | |
30 | + setLocal(LOCK_INFO_KEY, this.lockInfoState); | |
31 | + } | |
32 | + | |
33 | + @Mutation | |
34 | + resetLockInfo(): void { | |
35 | + removeLocal(LOCK_INFO_KEY); | |
36 | + this.lockInfoState = null; | |
37 | + } | |
38 | + | |
39 | + /** | |
40 | + * @description: unlock page | |
41 | + */ | |
42 | + @Action | |
43 | + public async unLockAction({ password }: { password: string }) { | |
44 | + const tryLogin = async () => { | |
45 | + try { | |
46 | + const username = userStore.getUserInfoState.username; | |
47 | + const res = await userStore.login({ username, password, goHome: false, mode: 'none' }); | |
48 | + if (res) { | |
49 | + this.resetLockInfo(); | |
50 | + } | |
51 | + return res; | |
52 | + } catch (error) { | |
53 | + return false; | |
54 | + } | |
55 | + }; | |
56 | + | |
57 | + if (this.getLockInfo?.pwd === password) { | |
58 | + this.resetLockInfo(); | |
59 | + return true; | |
60 | + } | |
61 | + return await tryLogin(); | |
62 | + } | |
63 | +} | |
64 | +export const lockStore = getModule<Lock>(Lock); | ... | ... |
src/store/modules/user.ts
... | ... | @@ -21,6 +21,7 @@ import { loginApi, getUserInfoById } from '/@/api/sys/user'; |
21 | 21 | import { setLocal, getLocal, getSession, setSession } from '/@/utils/helper/persistent'; |
22 | 22 | import { useProjectSetting } from '/@/hooks/setting'; |
23 | 23 | import { useI18n } from '/@/hooks/web/useI18n'; |
24 | +import { ErrorMessageMode } from '/@/utils/http/axios/types'; | |
24 | 25 | |
25 | 26 | export type UserInfo = Omit<GetUserInfoByUserIdModel, 'roles'>; |
26 | 27 | |
... | ... | @@ -94,9 +95,16 @@ class User extends VuexModule { |
94 | 95 | * @description: login |
95 | 96 | */ |
96 | 97 | @Action |
97 | - async login(params: LoginParams, goHome = true): Promise<GetUserInfoByUserIdModel | null> { | |
98 | + async login( | |
99 | + params: LoginParams & { | |
100 | + goHome?: boolean; | |
101 | + mode?: ErrorMessageMode; | |
102 | + } | |
103 | + ): Promise<GetUserInfoByUserIdModel | null> { | |
98 | 104 | try { |
99 | - const data = await loginApi(params); | |
105 | + const { goHome = true, mode, ...loginParams } = params; | |
106 | + const data = await loginApi(loginParams, mode); | |
107 | + | |
100 | 108 | const { token, userId } = data; |
101 | 109 | // get user info |
102 | 110 | const userInfo = await this.getUserInfoAction({ userId }); |
... | ... | @@ -106,7 +114,7 @@ class User extends VuexModule { |
106 | 114 | |
107 | 115 | // const name = FULL_PAGE_NOT_FOUND_ROUTE.name; |
108 | 116 | // name && router.removeRoute(name); |
109 | - goHome && router.push(PageEnum.BASE_HOME); | |
117 | + goHome && router.replace(PageEnum.BASE_HOME); | |
110 | 118 | return userInfo; |
111 | 119 | } catch (error) { |
112 | 120 | return null; | ... | ... |
src/utils/http/axios/Axios.ts
... | ... | @@ -80,6 +80,7 @@ export class VAxios { |
80 | 80 | |
81 | 81 | // 请求拦截器配置处理 |
82 | 82 | this.axiosInstance.interceptors.request.use((config: AxiosRequestConfig) => { |
83 | + // If cancel repeat request is turned on, then cancel repeat request is prohibited | |
83 | 84 | const { headers: { ignoreCancelToken } = { ignoreCancelToken: false } } = config; |
84 | 85 | !ignoreCancelToken && axiosCanceler.addPending(config); |
85 | 86 | if (requestInterceptors && isFunction(requestInterceptors)) { | ... | ... |
src/utils/http/axios/index.ts
... | ... | @@ -58,7 +58,7 @@ const transform: AxiosTransform = { |
58 | 58 | // errorMessageMode=‘modal’的时候会显示modal错误弹窗,而不是消息提示,用于一些比较重要的错误 |
59 | 59 | if (options.errorMessageMode === 'modal') { |
60 | 60 | createErrorModal({ title: t('sys.api.errorTip'), content: message }); |
61 | - } else { | |
61 | + } else if (options.errorMessageMode === 'message') { | |
62 | 62 | createMessage.error(message); |
63 | 63 | } |
64 | 64 | } |
... | ... | @@ -201,7 +201,7 @@ function createAxios(opt?: Partial<CreateAxiosOptions>) { |
201 | 201 | // 格式化提交参数时间 |
202 | 202 | formatDate: true, |
203 | 203 | // 消息提示类型 |
204 | - errorMessageMode: 'none', | |
204 | + errorMessageMode: 'message', | |
205 | 205 | // 接口地址 |
206 | 206 | apiUrl: globSetting.apiUrl, |
207 | 207 | }, | ... | ... |
src/utils/http/axios/types.ts
1 | 1 | import type { AxiosRequestConfig } from 'axios'; |
2 | 2 | import { AxiosTransform } from './axiosTransform'; |
3 | 3 | |
4 | +export type ErrorMessageMode = 'none' | 'modal' | 'message' | undefined; | |
5 | + | |
4 | 6 | export interface RequestOptions { |
5 | 7 | // 请求参数拼接到url |
6 | 8 | joinParamsToUrl?: boolean; |
... | ... | @@ -13,7 +15,7 @@ export interface RequestOptions { |
13 | 15 | // 接口地址, 不填则使用默认apiUrl |
14 | 16 | apiUrl?: string; |
15 | 17 | // 错误消息提示类型 |
16 | - errorMessageMode?: 'none' | 'modal'; | |
18 | + errorMessageMode?: ErrorMessageMode; | |
17 | 19 | } |
18 | 20 | |
19 | 21 | export interface CreateAxiosOptions extends AxiosRequestConfig { | ... | ... |
src/views/sys/lock/index.vue
1 | 1 | <template> |
2 | - <div class="lock-page"> | |
3 | - <div class="lock-page__entry"> | |
4 | - <div class="lock-page__header"> | |
5 | - <img src="../../../assets/images/header.jpg" class="lock-page__header-img" /> | |
6 | - <p class="lock-page__header-name">{{ realName }}</p> | |
2 | + <div :class="prefixCls"> | |
3 | + <div :class="`${prefixCls}__unlock`" @click="handleShowForm(false)" v-show="showDate"> | |
4 | + <LockOutlined /> | |
5 | + <span>{{ t('sys.lock.unlock') }}</span> | |
6 | + </div> | |
7 | + | |
8 | + <div :class="`${prefixCls}__date`"> | |
9 | + <div :class="`${prefixCls}__hour`"> | |
10 | + {{ hour }} | |
11 | + <span class="meridiem" v-show="showDate">{{ meridiem }}</span> | |
7 | 12 | </div> |
8 | - <BasicForm @register="register" v-if="!getIsNotPwd" /> | |
9 | - <Alert v-if="errMsgRef" type="error" :message="t('alert')" banner /> | |
10 | - <div class="lock-page__footer"> | |
11 | - <a-button type="default" class="mt-2 mr-2" @click="goLogin" v-if="!getIsNotPwd"> | |
12 | - {{ t('sys.lock.backToLogin') }} | |
13 | - </a-button> | |
14 | - <a-button type="primary" class="mt-2" @click="unLock(!getIsNotPwd)" :loading="loadingRef"> | |
15 | - {{ t('sys.lock.entry') }} | |
16 | - </a-button> | |
13 | + <div :class="`${prefixCls}__minute`">{{ minute }} </div> | |
14 | + </div> | |
15 | + <transition name="fade-slide"> | |
16 | + <div :class="`${prefixCls}-entry`" v-show="!showDate"> | |
17 | + <div :class="`${prefixCls}-entry-content`"> | |
18 | + <div :class="`${prefixCls}-entry__header`"> | |
19 | + <img src="/@/assets/images/header.jpg" :class="`${prefixCls}-entry__header-img`" /> | |
20 | + <p :class="`${prefixCls}-entry__header-name`">{{ realName }}</p> | |
21 | + </div> | |
22 | + <InputPassword :placeholder="t('sys.lock.placeholder')" v-model:value="password" /> | |
23 | + <span :class="`${prefixCls}-entry__err-msg`" v-if="errMsgRef"> | |
24 | + {{ t('sys.lock.alert') }} | |
25 | + </span> | |
26 | + <div :class="`${prefixCls}-entry__footer`"> | |
27 | + <a-button | |
28 | + type="link" | |
29 | + size="small" | |
30 | + class="mt-2 mr-2" | |
31 | + :disabled="loadingRef" | |
32 | + @click="handleShowForm(true)" | |
33 | + > | |
34 | + {{ t('sys.lock.back') }} | |
35 | + </a-button> | |
36 | + <a-button | |
37 | + type="link" | |
38 | + size="small" | |
39 | + class="mt-2 mr-2" | |
40 | + :disabled="loadingRef" | |
41 | + @click="goLogin" | |
42 | + > | |
43 | + {{ t('sys.lock.backToLogin') }} | |
44 | + </a-button> | |
45 | + <a-button class="mt-2" type="link" size="small" @click="unLock()" :loading="loadingRef"> | |
46 | + {{ t('sys.lock.entry') }} | |
47 | + </a-button> | |
48 | + </div> | |
49 | + </div> | |
17 | 50 | </div> |
51 | + </transition> | |
52 | + | |
53 | + <div :class="`${prefixCls}__footer-date`"> | |
54 | + <div class="time" v-show="!showDate"> | |
55 | + {{ hour }}:{{ minute }} <span class="meridiem">{{ meridiem }}</span> | |
56 | + </div> | |
57 | + <div class="date"> {{ year }}/{{ month }}/{{ day }} {{ week }} </div> | |
18 | 58 | </div> |
19 | 59 | </div> |
20 | 60 | </template> |
21 | 61 | <script lang="ts"> |
22 | 62 | import { defineComponent, ref, computed } from 'vue'; |
23 | - import { Alert } from 'ant-design-vue'; | |
24 | - | |
25 | - import { BasicForm, useForm } from '/@/components/Form'; | |
63 | + import { Alert, Input } from 'ant-design-vue'; | |
26 | 64 | |
27 | 65 | import { userStore } from '/@/store/modules/user'; |
28 | - import { appStore } from '/@/store/modules/app'; | |
66 | + import { lockStore } from '/@/store/modules/lock'; | |
29 | 67 | import { useI18n } from '/@/hooks/web/useI18n'; |
30 | 68 | |
69 | + import { useNow } from './useNow'; | |
70 | + import { useDesign } from '/@/hooks/web/useDesign'; | |
71 | + | |
72 | + import { LockOutlined } from '@ant-design/icons-vue'; | |
73 | + | |
31 | 74 | export default defineComponent({ |
32 | 75 | name: 'LockPage', |
33 | - components: { Alert, BasicForm }, | |
76 | + components: { Alert, LockOutlined, InputPassword: Input.Password }, | |
34 | 77 | |
35 | 78 | setup() { |
79 | + const passwordRef = ref(''); | |
36 | 80 | const loadingRef = ref(false); |
37 | 81 | const errMsgRef = ref(false); |
82 | + const showDate = ref(true); | |
83 | + | |
84 | + const { prefixCls } = useDesign('lock-page'); | |
85 | + | |
86 | + const { start, stop, ...state } = useNow(true); | |
38 | 87 | |
39 | 88 | const { t } = useI18n(); |
40 | - const [register, { validateFields }] = useForm({ | |
41 | - showActionButtonGroup: false, | |
42 | - schemas: [ | |
43 | - { | |
44 | - field: 'password', | |
45 | - label: '', | |
46 | - component: 'InputPassword', | |
47 | - componentProps: { | |
48 | - style: { width: '100%' }, | |
49 | - placeholder: t('sys.lock.placeholder'), | |
50 | - }, | |
51 | - rules: [{ required: true }], | |
52 | - }, | |
53 | - ], | |
54 | - }); | |
89 | + | |
55 | 90 | const realName = computed(() => { |
56 | 91 | const { realName } = userStore.getUserInfoState || {}; |
57 | 92 | return realName; |
58 | 93 | }); |
59 | 94 | |
60 | - const getIsNotPwd = computed(() => { | |
61 | - if (!appStore.getLockInfo) { | |
62 | - return true; | |
63 | - } | |
64 | - return appStore.getLockInfo.pwd === undefined; | |
65 | - }); | |
66 | - | |
67 | 95 | /** |
68 | 96 | * @description: unLock |
69 | 97 | */ |
70 | - async function unLock(valid = true) { | |
71 | - let password = ''; | |
72 | - if (valid) { | |
73 | - try { | |
74 | - const values = (await validateFields()) as any; | |
75 | - password = values.password; | |
76 | - } catch (error) { | |
77 | - return; | |
78 | - } | |
98 | + async function unLock() { | |
99 | + if (!passwordRef.value) { | |
100 | + return; | |
79 | 101 | } |
102 | + let password = passwordRef.value; | |
80 | 103 | try { |
81 | 104 | loadingRef.value = true; |
82 | - const res = await appStore.unLockAction({ password, valid }); | |
105 | + const res = await lockStore.unLockAction({ password }); | |
83 | 106 | errMsgRef.value = !res; |
84 | 107 | } finally { |
85 | 108 | loadingRef.value = false; |
... | ... | @@ -88,67 +111,190 @@ |
88 | 111 | |
89 | 112 | function goLogin() { |
90 | 113 | userStore.loginOut(true); |
91 | - appStore.resetLockInfo(); | |
114 | + lockStore.resetLockInfo(); | |
115 | + } | |
116 | + | |
117 | + function handleShowForm(show = false) { | |
118 | + showDate.value = show; | |
92 | 119 | } |
93 | 120 | |
94 | 121 | return { |
95 | - register, | |
96 | - getIsNotPwd, | |
97 | 122 | goLogin, |
98 | 123 | realName, |
99 | 124 | unLock, |
100 | 125 | errMsgRef, |
101 | 126 | loadingRef, |
102 | 127 | t, |
128 | + prefixCls, | |
129 | + showDate, | |
130 | + password: passwordRef, | |
131 | + handleShowForm, | |
132 | + ...state, | |
103 | 133 | }; |
104 | 134 | }, |
105 | 135 | }); |
106 | 136 | </script> |
107 | 137 | <style lang="less" scoped> |
108 | 138 | @import (reference) '../../../design/index.less'; |
139 | + @prefix-cls: ~'@{namespace}-lock-page'; | |
109 | 140 | |
110 | - .lock-page { | |
141 | + .@{prefix-cls} { | |
111 | 142 | position: fixed; |
112 | 143 | top: 0; |
144 | + right: 0; | |
145 | + bottom: 0; | |
113 | 146 | left: 0; |
114 | - z-index: 999999; | |
147 | + z-index: 3000; | |
115 | 148 | display: flex; |
116 | 149 | width: 100vw; |
117 | 150 | height: 100vh; |
118 | - background: url(../../../assets/images/lock-page.jpg) no-repeat; | |
119 | - background-size: 100% 100%; | |
151 | + // background: rgba(23, 27, 41); | |
152 | + background: #000; | |
120 | 153 | align-items: center; |
121 | - justify-content: flex-end; | |
154 | + justify-content: center; | |
155 | + | |
156 | + &__unlock { | |
157 | + position: absolute; | |
158 | + top: 0; | |
159 | + left: 50%; | |
160 | + display: flex; | |
161 | + height: 50px; | |
162 | + padding-top: 20px; | |
163 | + font-size: 18px; | |
164 | + color: #fff; | |
165 | + cursor: pointer; | |
166 | + transform: translate(-50%, 0); | |
167 | + flex-direction: column; | |
168 | + align-items: center; | |
169 | + justify-content: space-between; | |
170 | + transition: all 0.3s; | |
171 | + } | |
172 | + | |
173 | + &__date { | |
174 | + display: flex; | |
175 | + width: 100vw; | |
176 | + height: 100vh; | |
177 | + align-items: center; | |
178 | + justify-content: center; | |
179 | + } | |
122 | 180 | |
123 | - &__entry { | |
181 | + &__hour { | |
124 | 182 | position: relative; |
125 | - width: 400px; | |
126 | - // height: 260px; | |
127 | - padding: 80px 50px 50px 50px; | |
128 | - margin-right: 50px; | |
129 | - background: #fff; | |
130 | - border-radius: 6px; | |
183 | + margin-right: 80px; | |
184 | + | |
185 | + .meridiem { | |
186 | + position: absolute; | |
187 | + top: 20px; | |
188 | + left: 20px; | |
189 | + font-size: 26px; | |
190 | + } | |
191 | + @media (max-width: @screen-xs) { | |
192 | + margin-right: 20px; | |
193 | + } | |
131 | 194 | } |
132 | 195 | |
133 | - &__header { | |
196 | + &__hour, | |
197 | + &__minute { | |
198 | + display: flex; | |
199 | + width: 40%; | |
200 | + height: 74%; | |
201 | + // font-size: 50em; | |
202 | + font-weight: 700; | |
203 | + color: #bababa; | |
204 | + background: #141313; | |
205 | + border-radius: 30px; | |
206 | + justify-content: center; | |
207 | + align-items: center; | |
208 | + // .respond-to(large-only, { font-size: 25em;}); | |
209 | + // .respond-to(large-only, { font-size: 30em;}); | |
210 | + @media (min-width: @screen-xxxl-min) { | |
211 | + font-size: 46em; | |
212 | + } | |
213 | + @media (min-width: @screen-xl-max) and (max-width: @screen-xxl-max) { | |
214 | + font-size: 38em; | |
215 | + } | |
216 | + | |
217 | + @media (min-width: @screen-lg-max) and (max-width: @screen-xl-max) { | |
218 | + font-size: 30em; | |
219 | + } | |
220 | + @media (min-width: @screen-md-max) and (max-width: @screen-lg-max) { | |
221 | + font-size: 23em; | |
222 | + } | |
223 | + @media (min-width: @screen-sm-max) and (max-width: @screen-md-max) { | |
224 | + font-size: 19em; | |
225 | + } | |
226 | + @media (min-width: @screen-xs-max) and (max-width: @screen-sm-max) { | |
227 | + font-size: 13em; | |
228 | + } | |
229 | + @media (max-width: @screen-xs) { | |
230 | + height: 50%; | |
231 | + font-size: 6em; | |
232 | + border-radius: 20px; | |
233 | + } | |
234 | + } | |
235 | + | |
236 | + &__footer-date { | |
134 | 237 | position: absolute; |
135 | - top: -35px; | |
136 | - left: calc(50% - 45px); | |
137 | - width: auto; | |
138 | - text-align: center; | |
238 | + bottom: 20px; | |
239 | + left: 50%; | |
240 | + font-family: helvetica; | |
241 | + color: #bababa; | |
242 | + transform: translate(-50%, 0); | |
139 | 243 | |
140 | - &-img { | |
141 | - width: 70px; | |
142 | - border-radius: 50%; | |
244 | + .time { | |
245 | + font-size: 50px; | |
246 | + | |
247 | + .meridiem { | |
248 | + font-size: 32px; | |
249 | + } | |
143 | 250 | } |
144 | 251 | |
145 | - &-name { | |
146 | - margin-top: 5px; | |
252 | + .date { | |
253 | + font-size: 26px; | |
147 | 254 | } |
148 | 255 | } |
149 | 256 | |
150 | - &__footer { | |
151 | - text-align: center; | |
257 | + &-entry { | |
258 | + position: absolute; | |
259 | + top: 0; | |
260 | + left: 0; | |
261 | + display: flex; | |
262 | + width: 100%; | |
263 | + height: 100%; | |
264 | + background: rgba(0, 0, 0, 0.5); | |
265 | + backdrop-filter: blur(10px); | |
266 | + justify-content: center; | |
267 | + align-items: center; | |
268 | + | |
269 | + &-content { | |
270 | + width: 260px; | |
271 | + } | |
272 | + | |
273 | + &__header { | |
274 | + text-align: center; | |
275 | + | |
276 | + &-img { | |
277 | + width: 70px; | |
278 | + border-radius: 50%; | |
279 | + } | |
280 | + | |
281 | + &-name { | |
282 | + margin-top: 5px; | |
283 | + font-weight: 500; | |
284 | + color: #bababa; | |
285 | + } | |
286 | + } | |
287 | + | |
288 | + &__err-msg { | |
289 | + display: inline-block; | |
290 | + margin-top: 10px; | |
291 | + color: @error-color; | |
292 | + } | |
293 | + | |
294 | + &__footer { | |
295 | + display: flex; | |
296 | + justify-content: space-between; | |
297 | + } | |
152 | 298 | } |
153 | 299 | } |
154 | 300 | </style> | ... | ... |
src/views/sys/lock/useNow.ts
0 → 100644
1 | +import moment from 'moment'; | |
2 | +import { reactive, toRefs } from 'vue'; | |
3 | +import { tryOnMounted, tryOnUnmounted } from '/@/utils/helper/vueHelper'; | |
4 | +import { useLocaleSetting } from '/@/hooks/setting/useLocaleSetting'; | |
5 | + | |
6 | +export function useNow(immediate = true) { | |
7 | + const { getLang } = useLocaleSetting(); | |
8 | + const localData = moment.localeData(getLang.value); | |
9 | + let timer: IntervalHandle; | |
10 | + | |
11 | + const state = reactive({ | |
12 | + year: 0, | |
13 | + month: 0, | |
14 | + week: '', | |
15 | + day: 0, | |
16 | + hour: '', | |
17 | + minute: '', | |
18 | + second: 0, | |
19 | + meridiem: '', | |
20 | + }); | |
21 | + | |
22 | + const update = () => { | |
23 | + const now = moment(); | |
24 | + | |
25 | + const h = now.format('HH'); | |
26 | + const m = now.format('mm'); | |
27 | + const s = now.get('s'); | |
28 | + | |
29 | + state.year = now.get('y'); | |
30 | + state.month = now.get('M'); | |
31 | + state.week = localData.weekdays()[now.day()]; | |
32 | + state.day = now.get('D'); | |
33 | + state.hour = h; | |
34 | + state.minute = m; | |
35 | + state.second = s; | |
36 | + | |
37 | + state.meridiem = localData.meridiem(Number(h), Number(h), true); | |
38 | + }; | |
39 | + | |
40 | + function start() { | |
41 | + update(); | |
42 | + clearInterval(timer); | |
43 | + timer = setInterval(() => update(), 1000); | |
44 | + } | |
45 | + | |
46 | + function stop() { | |
47 | + clearInterval(timer); | |
48 | + } | |
49 | + | |
50 | + tryOnMounted(() => { | |
51 | + immediate && start(); | |
52 | + }); | |
53 | + | |
54 | + tryOnUnmounted(() => { | |
55 | + stop(); | |
56 | + }); | |
57 | + | |
58 | + return { | |
59 | + ...toRefs(state), | |
60 | + start, | |
61 | + stop, | |
62 | + }; | |
63 | +} | ... | ... |