diff --git a/CHANGELOG.zh_CN.md b/CHANGELOG.zh_CN.md index 0d4ba495e2c4a188eeb9341252da09eacff05ec4..40b60d864b48ad9d9eda726fc998609590ec2cd8 100644 --- a/CHANGELOG.zh_CN.md +++ b/CHANGELOG.zh_CN.md @@ -16,6 +16,7 @@ ### ✨ Refactor - tree 组件 ref 函数调用删除 `$` +- 锁屏界面重构美化,删除不必要的背景图片 ### ⚡ Performance Improvements diff --git a/src/api/sys/user.ts b/src/api/sys/user.ts index acd996e1ca4f396e5e3cb88b856acd9891918c99..157fc7be2046dcf4db2c40ecd0c30fd27795a828 100644 --- a/src/api/sys/user.ts +++ b/src/api/sys/user.ts @@ -5,6 +5,7 @@ import { GetUserInfoByUserIdParams, GetUserInfoByUserIdModel, } from './model/userModel'; +import { ErrorMessageMode } from '/@/utils/http/axios/types'; enum Api { Login = '/login', @@ -15,7 +16,7 @@ enum Api { /** * @description: user login api */ -export function loginApi(params: LoginParams) { +export function loginApi(params: LoginParams, mode: ErrorMessageMode = 'modal') { return defHttp.request( { url: Api.Login, @@ -23,7 +24,7 @@ export function loginApi(params: LoginParams) { params, }, { - errorMessageMode: 'modal', + errorMessageMode: mode, } ); } diff --git a/src/assets/images/lock-page.jpg b/src/assets/images/lock-page.jpg deleted file mode 100644 index 593e9d1771f0b8081d4468aefa99a2617e1639ee..0000000000000000000000000000000000000000 Binary files a/src/assets/images/lock-page.jpg and /dev/null differ diff --git a/src/design/mixins.less b/src/design/mixins.less index f7f028b3ca2a5b69cbf9586402f38c25bd00e896..53866ead8d38ef054b822cd31aa9f517c6021737 100644 --- a/src/design/mixins.less +++ b/src/design/mixins.less @@ -90,6 +90,7 @@ @content(); } } + .respond-to (xsmall-and-small, @content) { @media only screen and (max-width: @screen-sm-max) { @content(); diff --git a/src/design/var/breakpoint.less b/src/design/var/breakpoint.less index 7b84ffe40a82527c9d2e800370bad760400e23d5..a38617a78b489ecfa0f4547157a4b36782ac719d 100644 --- a/src/design/var/breakpoint.less +++ b/src/design/var/breakpoint.less @@ -26,9 +26,13 @@ @screen-xxl: 1600px; @screen-xxl-min: @screen-xxl; +@screen-xxxl: 1900px; +@screen-xxxl-min: @screen-xxxl; + // provide a maximum @screen-xs-max: (@screen-sm-min - 1px); @screen-sm-max: (@screen-md-min - 1px); @screen-md-max: (@screen-lg-min - 1px); @screen-lg-max: (@screen-xl-min - 1px); @screen-xl-max: (@screen-xxl-min - 1px); +@screen-xxl-max: (@screen-xxxl-min - 1px); diff --git a/src/hooks/setting/useRootSetting.ts b/src/hooks/setting/useRootSetting.ts index 7a4bda7e6308e7aee0e1c1f0d8f8a41bbb3cbc96..93d05aa44d843d8a136a515aa23d2cb8d8db8fcf 100644 --- a/src/hooks/setting/useRootSetting.ts +++ b/src/hooks/setting/useRootSetting.ts @@ -42,6 +42,8 @@ const getColorWeak = computed(() => unref(getRootSetting).colorWeak); const getGrayMode = computed(() => unref(getRootSetting).grayMode); +const getLockTime = computed(() => unref(getRootSetting).lockTime); + const getLayoutContentMode = computed(() => unref(getRootSetting).contentMode === ContentEnum.FULL ? ContentEnum.FULL : ContentEnum.FIXED ); @@ -71,5 +73,6 @@ export function useRootSetting() { getShowSettingButton, getShowFooter, getContentMode, + getLockTime, }; } diff --git a/src/hooks/web/useLockPage.ts b/src/hooks/web/useLockPage.ts index c315e670b266d7ce7ead3a7925f153ef9fc528fc..335e0a28d6bae23a7fffbbef647902005a56205b 100644 --- a/src/hooks/web/useLockPage.ts +++ b/src/hooks/web/useLockPage.ts @@ -1,10 +1,13 @@ -import { computed, onUnmounted, watchEffect } from 'vue'; +import { computed, onUnmounted, unref, watchEffect } from 'vue'; import { useThrottle } from '/@/hooks/core/useThrottle'; import { appStore } from '/@/store/modules/app'; +import { lockStore } from '/@/store/modules/lock'; import { userStore } from '/@/store/modules/user'; +import { useRootSetting } from '../setting/useRootSetting'; export function useLockPage() { + const { getLockTime } = useRootSetting(); let timeId: TimeoutHandle; function clear(): void { @@ -30,7 +33,7 @@ export function useLockPage() { } function lockPage(): void { - appStore.commitLockInfoState({ + lockStore.commitLockInfoState({ isLock: true, pwd: undefined, }); @@ -54,8 +57,7 @@ export function useLockPage() { const [keyupFn] = useThrottle(resetCalcLockTimeout, 2000); return computed(() => { - const openLockPage = appStore.getProjectConfig.lockTime; - if (openLockPage) { + if (unref(getLockTime)) { return { onKeyup: keyupFn, onMousemove: keyupFn }; } else { clear(); @@ -63,3 +65,9 @@ export function useLockPage() { } }); } + +export const getIsLock = computed(() => { + const { getLockInfo } = lockStore; + const { isLock } = getLockInfo; + return isLock; +}); diff --git a/src/layouts/default/index.tsx b/src/layouts/default/index.tsx index 80e6946e017d5ea57ae4dd44549d3fa72bcc3fae..bd64ec46ba3875af049dc4f72e3f47acabf08073 100644 --- a/src/layouts/default/index.tsx +++ b/src/layouts/default/index.tsx @@ -6,7 +6,7 @@ import LayoutHeader from './header/LayoutHeader'; import LayoutContent from './content'; import LayoutFooter from './footer'; -import LayoutLockPage from './lock'; +import LayoutLockPage from './lock/index.vue'; import LayoutSideBar from './sider'; import SettingBtn from './setting/index.vue'; import LayoutMultipleHeader from './header/LayoutMultipleHeader'; diff --git a/src/layouts/default/lock/LockAction.tsx b/src/layouts/default/lock/LockAction.tsx index f3f9f02db064603ac0f00022c692c40c970af001..b3d3d99106465fb0ff91dcaf44eb4fd50ae1a4bb 100644 --- a/src/layouts/default/lock/LockAction.tsx +++ b/src/layouts/default/lock/LockAction.tsx @@ -7,9 +7,9 @@ import { BasicForm, useForm } from '/@/components/Form/index'; import headerImg from '/@/assets/images/header.jpg'; -import { appStore } from '/@/store/modules/app'; import { userStore } from '/@/store/modules/user'; import { useI18n } from '/@/hooks/web/useI18n'; +import { lockStore } from '/@/store/modules/lock'; const prefixCls = 'lock-modal'; export default defineComponent({ @@ -30,24 +30,16 @@ export default defineComponent({ ], }); - async function lock(valid = true) { - let password: string | undefined = ''; + async function lock() { + const values = (await validateFields()) as any; + const password: string | undefined = values.password; + closeModal(); - try { - if (!valid) { - password = undefined; - } else { - const values = (await validateFields()) as any; - password = values.password; - } - closeModal(); - - appStore.commitLockInfoState({ - isLock: true, - pwd: password, - }); - await resetFields(); - } catch (error) {} + lockStore.commitLockInfoState({ + isLock: true, + pwd: password, + }); + await resetFields(); } return () => ( @@ -71,9 +63,6 @@ export default defineComponent({ - )} diff --git a/src/layouts/default/lock/index.tsx b/src/layouts/default/lock/index.tsx deleted file mode 100644 index a7fc4677d30f8433eff702dd54e649d036282be3..0000000000000000000000000000000000000000 --- a/src/layouts/default/lock/index.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import { defineComponent, unref, computed } from 'vue'; -import { appStore } from '/@/store/modules/app'; -import LockPage from '/@/views/sys/lock/index.vue'; - -export default defineComponent({ - name: 'LayoutLockPage', - setup() { - const getIsLockRef = computed(() => { - const { getLockInfo } = appStore; - const { isLock } = getLockInfo; - return isLock; - }); - return () => { - return unref(getIsLockRef) ? : null; - }; - }, -}); diff --git a/src/layouts/default/lock/index.vue b/src/layouts/default/lock/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..243d4f4567b2a7aee8c92b62b8854618b344ee2c --- /dev/null +++ b/src/layouts/default/lock/index.vue @@ -0,0 +1,17 @@ + + diff --git a/src/locales/lang/en/layout/header.ts b/src/locales/lang/en/layout/header.ts index fee7e324cfac0b76daace32ee1ecc0fce182649e..d096e28a585d11d91dd27c2ebcd9d7bf15150c05 100644 --- a/src/locales/lang/en/layout/header.ts +++ b/src/locales/lang/en/layout/header.ts @@ -14,7 +14,6 @@ export default { lockScreenPassword: 'Lock screen password', lockScreen: 'Lock screen', lockScreenBtn: 'Locking', - notLockScreenPassword: 'No password lock screen', home: 'Home', }; diff --git a/src/locales/lang/en/sys/lock.ts b/src/locales/lang/en/sys/lock.ts index 745966362027ca8280ef09aa840f8237fccc5c8f..f5bf633e91597ff2afc40abc606880e91faa5861 100644 --- a/src/locales/lang/en/sys/lock.ts +++ b/src/locales/lang/en/sys/lock.ts @@ -1,6 +1,8 @@ export default { + unlock: 'Click to unlock', alert: 'Lock screen password error', backToLogin: 'Back to login', + back: 'Back', entry: 'Enter the system', placeholder: 'Please enter the lock screen password or user password', }; diff --git a/src/locales/lang/zh_CN/layout/header.ts b/src/locales/lang/zh_CN/layout/header.ts index e2719c29f8fcd1995f8ed165df2f50e3d35b3893..3fbfc5cf620e01dd92868326dae9cf80bdba2e1c 100644 --- a/src/locales/lang/zh_CN/layout/header.ts +++ b/src/locales/lang/zh_CN/layout/header.ts @@ -15,7 +15,6 @@ export default { lockScreenPassword: '锁屏密码', lockScreen: '锁定屏幕', lockScreenBtn: '锁定', - notLockScreenPassword: '不设置密码锁屏', home: '首页', }; diff --git a/src/locales/lang/zh_CN/sys/lock.ts b/src/locales/lang/zh_CN/sys/lock.ts index a5f7ef90bcff22c4b15305e29c72386ea6e23e7e..8df91b4d9992f4f0ccdebe4f8795d3cbb8b0d4f7 100644 --- a/src/locales/lang/zh_CN/sys/lock.ts +++ b/src/locales/lang/zh_CN/sys/lock.ts @@ -1,5 +1,7 @@ export default { + unlock: '点击解锁', alert: '锁屏密码错误', + back: '返回', backToLogin: '返回登录', entry: '进入系统', placeholder: '请输入锁屏密码或者用户密码', diff --git a/src/store/modules/app.ts b/src/store/modules/app.ts index 1a680b485fb29f65bed643df391deeee531ad406..a184dc6abec68c6fa790450c846a43f0d331b06d 100644 --- a/src/store/modules/app.ts +++ b/src/store/modules/app.ts @@ -3,16 +3,10 @@ import type { ProjectConfig } from '/@/types/config'; import { VuexModule, getModule, Module, Mutation, Action } from 'vuex-module-decorators'; import store from '/@/store'; -import { PROJ_CFG_KEY, LOCK_INFO_KEY } from '/@/enums/cacheEnum'; +import { PROJ_CFG_KEY } from '/@/enums/cacheEnum'; import { hotModuleUnregisterModule } from '/@/utils/helper/vuexHelper'; -import { - setLocal, - getLocal, - removeLocal, - clearSession, - clearLocal, -} from '/@/utils/helper/persistent'; +import { setLocal, getLocal, clearSession, clearLocal } from '/@/utils/helper/persistent'; import { deepMerge } from '/@/utils'; import { resetRouter } from '/@/router'; @@ -37,9 +31,6 @@ class App extends VuexModule { // project config private projectConfigState: ProjectConfig | null = getLocal(PROJ_CFG_KEY); - // lock info - private lockInfoState: LockInfo | null = getLocal(LOCK_INFO_KEY); - // set main overflow hidden private lockMainScrollState = false; @@ -51,10 +42,6 @@ class App extends VuexModule { return this.lockMainScrollState; } - get getLockInfo(): LockInfo { - return this.lockInfoState || ({} as LockInfo); - } - get getProjectConfig(): ProjectConfig { return this.projectConfigState || ({} as ProjectConfig); } @@ -75,18 +62,6 @@ class App extends VuexModule { setLocal(PROJ_CFG_KEY, this.projectConfigState); } - @Mutation - commitLockInfoState(info: LockInfo): void { - this.lockInfoState = Object.assign({}, this.lockInfoState, info); - setLocal(LOCK_INFO_KEY, this.lockInfoState); - } - - @Mutation - resetLockInfo(): void { - removeLocal(LOCK_INFO_KEY); - this.lockInfoState = null; - } - @Action async resumeAllState() { resetRouter(); @@ -111,39 +86,5 @@ class App extends VuexModule { clearTimeout(timeId); } } - - /** - * @description: unlock page - */ - @Action - public async unLockAction({ password, valid = true }: { password: string; valid?: boolean }) { - if (!valid) { - this.resetLockInfo(); - return true; - } - const tryLogin = async () => { - try { - const username = userStore.getUserInfoState.username; - const res = await userStore.login({ username, password }, false); - if (res) { - this.resetLockInfo(); - } - return res; - } catch (error) { - return false; - } - }; - - if (this.getLockInfo) { - if (this.getLockInfo.pwd === password) { - this.resetLockInfo(); - return true; - } - const res = await tryLogin(); - return res; - } - const res = await tryLogin(); - return res; - } } export const appStore = getModule(App); diff --git a/src/store/modules/lock.ts b/src/store/modules/lock.ts new file mode 100644 index 0000000000000000000000000000000000000000..c88d1bbefd9804dc4caff5b1e4ac6678c7997c94 --- /dev/null +++ b/src/store/modules/lock.ts @@ -0,0 +1,64 @@ +import { VuexModule, getModule, Module, Mutation, Action } from 'vuex-module-decorators'; +import store from '/@/store'; + +import { LOCK_INFO_KEY } from '/@/enums/cacheEnum'; + +import { hotModuleUnregisterModule } from '/@/utils/helper/vuexHelper'; +import { setLocal, getLocal, removeLocal } from '/@/utils/helper/persistent'; + +import { userStore } from './user'; + +export interface LockInfo { + pwd: string | undefined; + isLock: boolean; +} + +const NAME = 'lock'; +hotModuleUnregisterModule(NAME); +@Module({ dynamic: true, namespaced: true, store, name: NAME }) +class Lock extends VuexModule { + // lock info + private lockInfoState: LockInfo | null = getLocal(LOCK_INFO_KEY); + + get getLockInfo(): LockInfo { + return this.lockInfoState || ({} as LockInfo); + } + + @Mutation + commitLockInfoState(info: LockInfo): void { + this.lockInfoState = Object.assign({}, this.lockInfoState, info); + setLocal(LOCK_INFO_KEY, this.lockInfoState); + } + + @Mutation + resetLockInfo(): void { + removeLocal(LOCK_INFO_KEY); + this.lockInfoState = null; + } + + /** + * @description: unlock page + */ + @Action + public async unLockAction({ password }: { password: string }) { + const tryLogin = async () => { + try { + const username = userStore.getUserInfoState.username; + const res = await userStore.login({ username, password, goHome: false, mode: 'none' }); + if (res) { + this.resetLockInfo(); + } + return res; + } catch (error) { + return false; + } + }; + + if (this.getLockInfo?.pwd === password) { + this.resetLockInfo(); + return true; + } + return await tryLogin(); + } +} +export const lockStore = getModule(Lock); diff --git a/src/store/modules/user.ts b/src/store/modules/user.ts index 7db5c0a14581c60246e00c54a8f338179cfb5fcc..16bef467a9931bf86face95526b442ce9882b42b 100644 --- a/src/store/modules/user.ts +++ b/src/store/modules/user.ts @@ -21,6 +21,7 @@ import { loginApi, getUserInfoById } from '/@/api/sys/user'; import { setLocal, getLocal, getSession, setSession } from '/@/utils/helper/persistent'; import { useProjectSetting } from '/@/hooks/setting'; import { useI18n } from '/@/hooks/web/useI18n'; +import { ErrorMessageMode } from '/@/utils/http/axios/types'; export type UserInfo = Omit; @@ -94,9 +95,16 @@ class User extends VuexModule { * @description: login */ @Action - async login(params: LoginParams, goHome = true): Promise { + async login( + params: LoginParams & { + goHome?: boolean; + mode?: ErrorMessageMode; + } + ): Promise { try { - const data = await loginApi(params); + const { goHome = true, mode, ...loginParams } = params; + const data = await loginApi(loginParams, mode); + const { token, userId } = data; // get user info const userInfo = await this.getUserInfoAction({ userId }); @@ -106,7 +114,7 @@ class User extends VuexModule { // const name = FULL_PAGE_NOT_FOUND_ROUTE.name; // name && router.removeRoute(name); - goHome && router.push(PageEnum.BASE_HOME); + goHome && router.replace(PageEnum.BASE_HOME); return userInfo; } catch (error) { return null; diff --git a/src/utils/http/axios/Axios.ts b/src/utils/http/axios/Axios.ts index 044e47b7e191ec92174d871f2fe080fd21103aad..1cc23db84d2aeb5322a9443bb90cb83b8df24f51 100644 --- a/src/utils/http/axios/Axios.ts +++ b/src/utils/http/axios/Axios.ts @@ -80,6 +80,7 @@ export class VAxios { // 请求拦截器配置处理 this.axiosInstance.interceptors.request.use((config: AxiosRequestConfig) => { + // If cancel repeat request is turned on, then cancel repeat request is prohibited const { headers: { ignoreCancelToken } = { ignoreCancelToken: false } } = config; !ignoreCancelToken && axiosCanceler.addPending(config); if (requestInterceptors && isFunction(requestInterceptors)) { diff --git a/src/utils/http/axios/index.ts b/src/utils/http/axios/index.ts index 7220c3b01e42966dca38ca2799a937e077e39180..86c4f8e534642ce9338d870f89f7921e855da772 100644 --- a/src/utils/http/axios/index.ts +++ b/src/utils/http/axios/index.ts @@ -58,7 +58,7 @@ const transform: AxiosTransform = { // errorMessageMode=‘modal’的时候会显示modal错误弹窗,而不是消息提示,用于一些比较重要的错误 if (options.errorMessageMode === 'modal') { createErrorModal({ title: t('sys.api.errorTip'), content: message }); - } else { + } else if (options.errorMessageMode === 'message') { createMessage.error(message); } } @@ -201,7 +201,7 @@ function createAxios(opt?: Partial) { // 格式化提交参数时间 formatDate: true, // 消息提示类型 - errorMessageMode: 'none', + errorMessageMode: 'message', // 接口地址 apiUrl: globSetting.apiUrl, }, diff --git a/src/utils/http/axios/types.ts b/src/utils/http/axios/types.ts index 25a708c881a002f0e9058cdb079a324345442485..486eaab1d4a4ce09d69f6837744830c173453e69 100644 --- a/src/utils/http/axios/types.ts +++ b/src/utils/http/axios/types.ts @@ -1,6 +1,8 @@ import type { AxiosRequestConfig } from 'axios'; import { AxiosTransform } from './axiosTransform'; +export type ErrorMessageMode = 'none' | 'modal' | 'message' | undefined; + export interface RequestOptions { // 请求参数拼接到url joinParamsToUrl?: boolean; @@ -13,7 +15,7 @@ export interface RequestOptions { // 接口地址, 不填则使用默认apiUrl apiUrl?: string; // 错误消息提示类型 - errorMessageMode?: 'none' | 'modal'; + errorMessageMode?: ErrorMessageMode; } export interface CreateAxiosOptions extends AxiosRequestConfig { diff --git a/src/views/sys/lock/index.vue b/src/views/sys/lock/index.vue index 96b6d920baa8ab99578337ef4d78cfe2e72625c1..c0e2df2cc8ac83995de1b9d9c211bf17eb933853 100644 --- a/src/views/sys/lock/index.vue +++ b/src/views/sys/lock/index.vue @@ -1,85 +1,108 @@ diff --git a/src/views/sys/lock/useNow.ts b/src/views/sys/lock/useNow.ts new file mode 100644 index 0000000000000000000000000000000000000000..0b99feed9ba43718f63b42eb47af892eadb0c2a7 --- /dev/null +++ b/src/views/sys/lock/useNow.ts @@ -0,0 +1,63 @@ +import moment from 'moment'; +import { reactive, toRefs } from 'vue'; +import { tryOnMounted, tryOnUnmounted } from '/@/utils/helper/vueHelper'; +import { useLocaleSetting } from '/@/hooks/setting/useLocaleSetting'; + +export function useNow(immediate = true) { + const { getLang } = useLocaleSetting(); + const localData = moment.localeData(getLang.value); + let timer: IntervalHandle; + + const state = reactive({ + year: 0, + month: 0, + week: '', + day: 0, + hour: '', + minute: '', + second: 0, + meridiem: '', + }); + + const update = () => { + const now = moment(); + + const h = now.format('HH'); + const m = now.format('mm'); + const s = now.get('s'); + + state.year = now.get('y'); + state.month = now.get('M'); + state.week = localData.weekdays()[now.day()]; + state.day = now.get('D'); + state.hour = h; + state.minute = m; + state.second = s; + + state.meridiem = localData.meridiem(Number(h), Number(h), true); + }; + + function start() { + update(); + clearInterval(timer); + timer = setInterval(() => update(), 1000); + } + + function stop() { + clearInterval(timer); + } + + tryOnMounted(() => { + immediate && start(); + }); + + tryOnUnmounted(() => { + stop(); + }); + + return { + ...toRefs(state), + start, + stop, + }; +}