From 06f5d5686dfae5c2ce4da766d69f873b694d0a8d Mon Sep 17 00:00:00 2001
From: Laychen <37046689+Layczm@users.noreply.github.com>
Date: Fri, 12 Jul 2024 12:14:09 +0800
Subject: [PATCH] feat: add the ability to lock the screen (#30)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* feat: 锁屏功能
* feat: 锁屏样式调整
* feat: complete the lock-screen screen and support shortcut keys and preference configuration
---------
Co-authored-by: vince
---
apps/web-antd/src/layouts/basic.vue | 34 +++-
.../web-antd/src/router/routes/_essentials.ts | 2 +-
apps/web-antd/src/store/index.ts | 4 +-
apps/web-antd/src/store/modules/app.ts | 42 +++--
.../@core/forward/preferences/src/config.ts | 3 +-
.../@core/forward/preferences/src/types.ts | 6 +-
.../preferences/src/use-preferences.ts | 6 +
packages/@core/locales/src/langs/en-US.json | 13 +-
packages/@core/locales/src/langs/zh-CN.json | 13 +-
.../@core/shared/design/src/scss-bem/bem.scss | 2 +-
.../@core/shared/iconify/src/create-icon.ts | 9 +-
packages/@core/shared/iconify/src/material.ts | 2 +
.../business/layouts/src/basic/layout.vue | 5 +-
.../business/layouts/src/widgets/index.ts | 1 +
.../layouts/src/widgets/lock-screen/index.ts | 2 +
.../widgets/lock-screen/lock-screen-modal.vue | 106 +++++++++++
.../src/widgets/lock-screen/lock-screen.vue | 170 ++++++++++++++++++
.../src/widgets/lock-screen/typings.ts | 9 +
.../preferences/blocks/layout/widget.vue | 4 +
.../blocks/shortcut-keys/global.vue | 14 +-
.../widgets/preferences/preferences-sheet.vue | 6 +
.../src/widgets/preferences/preferences.vue | 4 +-
.../widgets/user-dropdown/user-dropdown.vue | 57 +++++-
.../src/authentication/code-login.vue | 4 +-
.../src/authentication/forget-password.vue | 4 +-
.../src/authentication/qrcode-login.vue | 4 +-
.../src/authentication/register.vue | 4 +-
27 files changed, 482 insertions(+), 48 deletions(-)
create mode 100644 packages/business/layouts/src/widgets/lock-screen/index.ts
create mode 100644 packages/business/layouts/src/widgets/lock-screen/lock-screen-modal.vue
create mode 100644 packages/business/layouts/src/widgets/lock-screen/lock-screen.vue
create mode 100644 packages/business/layouts/src/widgets/lock-screen/typings.ts
diff --git a/apps/web-antd/src/layouts/basic.vue b/apps/web-antd/src/layouts/basic.vue
index 3c2178e9..c9af11b1 100644
--- a/apps/web-antd/src/layouts/basic.vue
+++ b/apps/web-antd/src/layouts/basic.vue
@@ -1,11 +1,12 @@
@@ -127,7 +140,7 @@ function handleMakeAll() {
@make-all="handleMakeAll"
/>
-
+
+
+
+
diff --git a/apps/web-antd/src/router/routes/_essentials.ts b/apps/web-antd/src/router/routes/_essentials.ts
index 0965912b..bd3f45e7 100644
--- a/apps/web-antd/src/router/routes/_essentials.ts
+++ b/apps/web-antd/src/router/routes/_essentials.ts
@@ -51,7 +51,7 @@ const essentialsRoutes: RouteRecordRaw[] = [
component: () =>
import('#/views/_essential/authentication/code-login.vue'),
meta: {
- title: $t('page.essentials.code-login'),
+ title: $t('page.essentials.codeLogin'),
},
},
{
diff --git a/apps/web-antd/src/store/index.ts b/apps/web-antd/src/store/index.ts
index 593e4fd6..4deb7341 100644
--- a/apps/web-antd/src/store/index.ts
+++ b/apps/web-antd/src/store/index.ts
@@ -2,7 +2,7 @@ import type { InitStoreOptions } from '@vben-core/stores';
import type { App } from 'vue';
-import { initStore } from '@vben-core/stores';
+import { initStore, storeToRefs } from '@vben-core/stores';
/**
* @zh_CN 初始化pinia
@@ -13,7 +13,7 @@ async function setupStore(app: App, options: InitStoreOptions) {
app.use(pinia);
}
-export { setupStore };
+export { setupStore, storeToRefs };
export { useAccessStore } from './modules/access';
export { useAppStore } from './modules/app';
diff --git a/apps/web-antd/src/store/modules/app.ts b/apps/web-antd/src/store/modules/app.ts
index 97a0b642..46b0fcd6 100644
--- a/apps/web-antd/src/store/modules/app.ts
+++ b/apps/web-antd/src/store/modules/app.ts
@@ -4,19 +4,35 @@ import { defineStore } from 'pinia';
import { useAccessStore } from './access';
-export const useAppStore = defineStore('app', () => {
- const accessStore = useAccessStore();
- const coreTabbarStore = useCoreTabbarStore();
+interface AppState {
+ isLockScreen: boolean;
+ lockScreenPassword?: string;
+}
- /**
- * 重置所有状态
- */
- async function resetAppState() {
- accessStore.reset();
- coreTabbarStore.$reset();
- }
+export const useAppStore = defineStore('app', {
+ actions: {
+ lockScreen(password: string) {
+ this.isLockScreen = true;
+ this.lockScreenPassword = password;
+ },
- return {
- resetAppState,
- };
+ resetAppState() {
+ const accessStore = useAccessStore();
+ const coreTabbarStore = useCoreTabbarStore();
+ accessStore.reset();
+ coreTabbarStore.$reset();
+ },
+
+ unlockScreen() {
+ this.isLockScreen = false;
+ this.lockScreenPassword = undefined;
+ },
+ },
+ persist: {
+ paths: ['isLockScreen', 'lockScreenPassword'],
+ },
+ state: (): AppState => ({
+ isLockScreen: false,
+ lockScreenPassword: undefined,
+ }),
});
diff --git a/packages/@core/forward/preferences/src/config.ts b/packages/@core/forward/preferences/src/config.ts
index 998d0c2d..4ef14f78 100644
--- a/packages/@core/forward/preferences/src/config.ts
+++ b/packages/@core/forward/preferences/src/config.ts
@@ -3,7 +3,6 @@ import type { Preferences } from './types';
const defaultPreferences: Preferences = {
app: {
accessMode: 'frontend',
- aiAssistant: true,
authPageLayout: 'panel-right',
colorGrayMode: false,
colorWeakMode: false,
@@ -55,6 +54,7 @@ const defaultPreferences: Preferences = {
},
shortcutKeys: {
enable: true,
+ globalLockScreen: true,
globalLogout: true,
globalPreferences: true,
globalSearch: true,
@@ -95,6 +95,7 @@ const defaultPreferences: Preferences = {
fullscreen: true,
globalSearch: true,
languageToggle: true,
+ lockScreen: true,
notification: true,
sidebarToggle: true,
themeToggle: true,
diff --git a/packages/@core/forward/preferences/src/types.ts b/packages/@core/forward/preferences/src/types.ts
index bd6297a2..3638cac7 100644
--- a/packages/@core/forward/preferences/src/types.ts
+++ b/packages/@core/forward/preferences/src/types.ts
@@ -26,8 +26,6 @@ type AuthPageLayoutType = 'panel-center' | 'panel-left' | 'panel-right';
interface AppPreferences {
/** 权限模式 */
accessMode: AccessModeType;
- /** 是否开启vben助手 */
- aiAssistant: boolean;
/** 登录注册页面布局 */
authPageLayout: AuthPageLayoutType;
/** 是否开启灰色模式 */
@@ -136,6 +134,8 @@ interface SidebarPreferences {
interface ShortcutKeyPreferences {
/** 是否启用快捷键-全局 */
enable: boolean;
+ /** 是否启用全局锁屏快捷键 */
+ globalLockScreen: boolean;
/** 是否启用全局注销快捷键 */
globalLogout: boolean;
/** 是否启用全局偏好设置快捷键 */
@@ -194,6 +194,8 @@ interface WidgetPreferences {
globalSearch: boolean;
/** 是否启用语言切换部件 */
languageToggle: boolean;
+ /** 是否开启锁屏功能 */
+ lockScreen: boolean;
/** 是否显示通知部件 */
notification: boolean;
/** 是否显示侧边栏显示/隐藏部件 */
diff --git a/packages/@core/forward/preferences/src/use-preferences.ts b/packages/@core/forward/preferences/src/use-preferences.ts
index c43606a7..2eac7a70 100644
--- a/packages/@core/forward/preferences/src/use-preferences.ts
+++ b/packages/@core/forward/preferences/src/use-preferences.ts
@@ -125,6 +125,11 @@ function usePreferences() {
return enable && globalLogout;
});
+ const globalLockScreenShortcutKey = computed(() => {
+ const { enable, globalLockScreen } = shortcutKeysPreferences.value;
+ return enable && globalLockScreen;
+ });
+
/**
* @zh_CN 是否启用全局偏好设置快捷键
*/
@@ -138,6 +143,7 @@ function usePreferences() {
authPanelLeft,
authPanelRight,
diffPreference,
+ globalLockScreenShortcutKey,
globalLogoutShortcutKey,
globalPreferencesShortcutKey,
globalSearchShortcutKey,
diff --git a/packages/@core/locales/src/langs/en-US.json b/packages/@core/locales/src/langs/en-US.json
index d650cb77..e7ad4f21 100644
--- a/packages/@core/locales/src/langs/en-US.json
+++ b/packages/@core/locales/src/langs/en-US.json
@@ -68,6 +68,16 @@
"noResults": "No Search Results Found",
"noRecent": "No Search History",
"recent": "Search History"
+ },
+ "lockScreen": {
+ "title": "Lock Screen",
+ "screenButton": "Locking",
+ "password": "Password",
+ "placeholder": "Please enter password",
+ "unlock": "Click to unlock",
+ "errorPasswordTip": "Password error, please re-enter",
+ "backToLogin": "Back to login",
+ "entry": "Enter the system"
}
},
"authentication": {
@@ -263,7 +273,8 @@
"languageToggle": "Enable Language Toggle",
"notification": "Enable Notification",
"sidebarToggle": "Enable Sidebar Toggle",
- "aiAssistant": "Enable AI Assistant"
+ "aiAssistant": "Enable AI Assistant",
+ "lockScreen": "Enable Lock Screen"
}
}
}
diff --git a/packages/@core/locales/src/langs/zh-CN.json b/packages/@core/locales/src/langs/zh-CN.json
index 6dd6aad8..6d317a13 100644
--- a/packages/@core/locales/src/langs/zh-CN.json
+++ b/packages/@core/locales/src/langs/zh-CN.json
@@ -68,6 +68,16 @@
"noResults": "未找到搜索结果",
"noRecent": "没有搜索历史",
"recent": "搜索历史"
+ },
+ "lockScreen": {
+ "title": "锁定屏幕",
+ "screenButton": "锁定",
+ "password": "密码",
+ "placeholder": "请输入锁屏密码",
+ "unlock": "点击解锁",
+ "errorPasswordTip": "密码错误,请重新输入",
+ "backToLogin": "返回登录",
+ "entry": "进入系统"
}
},
"authentication": {
@@ -263,7 +273,8 @@
"languageToggle": "启用语言切换",
"notification": "启用通知",
"sidebarToggle": "启用侧边栏切换",
- "aiAssistant": "启用 AI 助手"
+ "aiAssistant": "启用 AI 助手",
+ "lockScreen": "启用锁屏"
}
}
}
diff --git a/packages/@core/shared/design/src/scss-bem/bem.scss b/packages/@core/shared/design/src/scss-bem/bem.scss
index 2c8ec306..3910a305 100644
--- a/packages/@core/shared/design/src/scss-bem/bem.scss
+++ b/packages/@core/shared/design/src/scss-bem/bem.scss
@@ -1,4 +1,4 @@
-@forward './constants.scss';
+@forward './constants';
@mixin b($block) {
$B: $namespace + '-' + $block !global;
diff --git a/packages/@core/shared/iconify/src/create-icon.ts b/packages/@core/shared/iconify/src/create-icon.ts
index 49a7c805..f108023f 100644
--- a/packages/@core/shared/iconify/src/create-icon.ts
+++ b/packages/@core/shared/iconify/src/create-icon.ts
@@ -1,9 +1,14 @@
-import { h } from 'vue';
+import { defineComponent, h } from 'vue';
import { Icon } from '@iconify/vue';
function createIconifyIcon(icon: string) {
- return h(Icon, { icon });
+ return defineComponent({
+ name: `SvgIcon-${icon}`,
+ setup(props, { attrs }) {
+ return () => h(Icon, { icon, ...props, ...attrs });
+ },
+ });
}
export { createIconifyIcon };
diff --git a/packages/@core/shared/iconify/src/material.ts b/packages/@core/shared/iconify/src/material.ts
index d85ea7c4..52a41899 100644
--- a/packages/@core/shared/iconify/src/material.ts
+++ b/packages/@core/shared/iconify/src/material.ts
@@ -82,3 +82,5 @@ export const IcRoundMultipleStop = createIconifyIcon('ic:round-multiple-stop');
export const IcRoundRefresh = createIconifyIcon('ic:round-refresh');
export const IcRoundCreditScore = createIconifyIcon('ic:round-credit-score');
+
+export const IcRoundLock = createIconifyIcon('ic:round-lock');
diff --git a/packages/business/layouts/src/basic/layout.vue b/packages/business/layouts/src/basic/layout.vue
index 112c2798..3165b979 100644
--- a/packages/business/layouts/src/basic/layout.vue
+++ b/packages/business/layouts/src/basic/layout.vue
@@ -279,7 +279,10 @@ function clearPreferencesAndLogout() {
-
+
+
+
+
diff --git a/packages/business/layouts/src/widgets/index.ts b/packages/business/layouts/src/widgets/index.ts
index 718d1a73..c6e5fbd4 100644
--- a/packages/business/layouts/src/widgets/index.ts
+++ b/packages/business/layouts/src/widgets/index.ts
@@ -4,6 +4,7 @@ export { default as CozeAssistant } from './coze-assistant.vue';
export * from './global-search';
export { default as LanguageToggle } from './language-toggle.vue';
export { default as AuthenticationLayoutToggle } from './layout-toggle.vue';
+export * from './lock-screen';
export * from './notification';
export * from './preferences';
export * from './theme-toggle';
diff --git a/packages/business/layouts/src/widgets/lock-screen/index.ts b/packages/business/layouts/src/widgets/lock-screen/index.ts
new file mode 100644
index 00000000..1609becb
--- /dev/null
+++ b/packages/business/layouts/src/widgets/lock-screen/index.ts
@@ -0,0 +1,2 @@
+export { default as LockScreen } from './lock-screen.vue';
+export { default as LockScreenModal } from './lock-screen-modal.vue';
diff --git a/packages/business/layouts/src/widgets/lock-screen/lock-screen-modal.vue b/packages/business/layouts/src/widgets/lock-screen/lock-screen-modal.vue
new file mode 100644
index 00000000..72af6f1a
--- /dev/null
+++ b/packages/business/layouts/src/widgets/lock-screen/lock-screen-modal.vue
@@ -0,0 +1,106 @@
+
+
+
+
+
+
+
diff --git a/packages/business/layouts/src/widgets/lock-screen/lock-screen.vue b/packages/business/layouts/src/widgets/lock-screen/lock-screen.vue
new file mode 100644
index 00000000..ad34f9ec
--- /dev/null
+++ b/packages/business/layouts/src/widgets/lock-screen/lock-screen.vue
@@ -0,0 +1,170 @@
+
+
+
+
+
+
+
+
+ {{ $t('widgets.lockScreen.unlock') }}
+
+
+
+ {{
+ meridiem
+ }}
+ {{ hour }}
+
+
+ {{ minute }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ $t('widgets.lockScreen.entry') }}
+
+
+ {{ $t('widgets.lockScreen.backToLogin') }}
+
+
+ {{ $t('common.back') }}
+
+
+
+
+
+
+
+ {{ hour }}:{{ minute }} {{ meridiem }}
+
+
{{ year }}/{{ month }}/{{ day }} {{ week }}
+
+
+
diff --git a/packages/business/layouts/src/widgets/lock-screen/typings.ts b/packages/business/layouts/src/widgets/lock-screen/typings.ts
new file mode 100644
index 00000000..c06ea750
--- /dev/null
+++ b/packages/business/layouts/src/widgets/lock-screen/typings.ts
@@ -0,0 +1,9 @@
+interface LockAndRegisterParams {
+ lockScreenPassword: string;
+}
+
+interface RegisterEmits {
+ submit: [LockAndRegisterParams];
+}
+
+export type { LockAndRegisterParams, RegisterEmits };
diff --git a/packages/business/layouts/src/widgets/preferences/blocks/layout/widget.vue b/packages/business/layouts/src/widgets/preferences/blocks/layout/widget.vue
index 4107a311..6329c79c 100644
--- a/packages/business/layouts/src/widgets/preferences/blocks/layout/widget.vue
+++ b/packages/business/layouts/src/widgets/preferences/blocks/layout/widget.vue
@@ -14,6 +14,7 @@ const widgetNotification = defineModel('widgetNotification');
const widgetThemeToggle = defineModel('widgetThemeToggle');
const widgetAiAssistant = defineModel('widgetAiAssistant');
const widgetSidebarToggle = defineModel('widgetSidebarToggle');
+const widgetLockScreen = defineModel('widgetLockScreen');
@@ -35,6 +36,9 @@ const widgetSidebarToggle = defineModel('widgetSidebarToggle');
{{ $t('preferences.widget.aiAssistant') }}
+
+ {{ $t('preferences.widget.lockScreen') }}
+
{{ $t('preferences.widget.sidebarToggle') }}
diff --git a/packages/business/layouts/src/widgets/preferences/blocks/shortcut-keys/global.vue b/packages/business/layouts/src/widgets/preferences/blocks/shortcut-keys/global.vue
index 853c41fd..7cacb2b2 100644
--- a/packages/business/layouts/src/widgets/preferences/blocks/shortcut-keys/global.vue
+++ b/packages/business/layouts/src/widgets/preferences/blocks/shortcut-keys/global.vue
@@ -16,6 +16,7 @@ const shortcutKeysGlobalSearch = defineModel(
);
const shortcutKeysLogout = defineModel('shortcutKeysLogout');
const shortcutKeysPreferences = defineModel('shortcutKeysPreferences');
+const shortcutKeysLockScreen = defineModel('shortcutKeysLockScreen');
const altView = computed(() => (isWindowsOs() ? 'Alt' : '⌥'));
@@ -24,19 +25,26 @@ const altView = computed(() => (isWindowsOs() ? 'Alt' : '⌥'));
{{ $t('preferences.shortcutKeys.title') }}
-
+
{{ $t('preferences.shortcutKeys.search') }}
{{ isWindowsOs() ? 'Ctrl' : '⌘' }}
K
-
+
{{ $t('preferences.shortcutKeys.logout') }}
{{ altView }} Q
-
+
{{ $t('preferences.shortcutKeys.preferences') }}
{{ altView }} ,
+
+ {{ $t('widgets.lockScreen.title') }}
+ {{ altView }} L
+
diff --git a/packages/business/layouts/src/widgets/preferences/preferences-sheet.vue b/packages/business/layouts/src/widgets/preferences/preferences-sheet.vue
index 1e846e5f..9a29de27 100644
--- a/packages/business/layouts/src/widgets/preferences/preferences-sheet.vue
+++ b/packages/business/layouts/src/widgets/preferences/preferences-sheet.vue
@@ -128,6 +128,9 @@ const shortcutKeysGlobalLogout = defineModel(
const shortcutKeysGlobalPreferences = defineModel(
'shortcutKeysGlobalPreferences',
);
+const shortcutKeysGlobalLockScreen = defineModel(
+ 'shortcutKeysGlobalLockScreen',
+);
const widgetGlobalSearch = defineModel('widgetGlobalSearch');
const widgetFullscreen = defineModel('widgetFullscreen');
@@ -136,6 +139,7 @@ const widgetNotification = defineModel('widgetNotification');
const widgetThemeToggle = defineModel('widgetThemeToggle');
const widgetAiAssistant = defineModel('widgetAiAssistant');
const widgetSidebarToggle = defineModel('widgetSidebarToggle');
+const widgetLockScreen = defineModel('widgetLockScreen');
const {
diffPreference,
@@ -355,6 +359,7 @@ async function handleReset() {
v-model:widget-fullscreen="widgetFullscreen"
v-model:widget-global-search="widgetGlobalSearch"
v-model:widget-language-toggle="widgetLanguageToggle"
+ v-model:widget-lock-screen="widgetLockScreen"
v-model:widget-notification="widgetNotification"
v-model:widget-sidebar-toggle="widgetSidebarToggle"
v-model:widget-theme-toggle="widgetThemeToggle"
@@ -384,6 +389,7 @@ async function handleReset() {
+
+
+ {{ $t('widgets.lockScreen.title') }}
+
+ {{ altView }} L
+
+
{
{{ $t('common.login') }}
-
+
{{ $t('common.back') }}
diff --git a/packages/business/universal-ui/src/authentication/forget-password.vue b/packages/business/universal-ui/src/authentication/forget-password.vue
index 8968e2f3..a296199e 100644
--- a/packages/business/universal-ui/src/authentication/forget-password.vue
+++ b/packages/business/universal-ui/src/authentication/forget-password.vue
@@ -50,7 +50,7 @@ function handleSubmut() {
emit('submit', formState.email);
}
-function goLogin() {
+function goToLogin() {
router.push(props.loginPath);
}
@@ -79,7 +79,7 @@ function goLogin() {
{{ $t('authentication.sendResetLink') }}
-
+
{{ $t('common.back') }}
diff --git a/packages/business/universal-ui/src/authentication/qrcode-login.vue b/packages/business/universal-ui/src/authentication/qrcode-login.vue
index 8b4f0dbd..ceafc408 100644
--- a/packages/business/universal-ui/src/authentication/qrcode-login.vue
+++ b/packages/business/universal-ui/src/authentication/qrcode-login.vue
@@ -39,7 +39,7 @@ const qrcode = useQRCode(text, {
margin: 4,
});
-function goLogin() {
+function goToLogin() {
router.push(props.loginPath);
}
@@ -62,7 +62,7 @@ function goLogin() {
-
+
{{ $t('common.back') }}
diff --git a/packages/business/universal-ui/src/authentication/register.vue b/packages/business/universal-ui/src/authentication/register.vue
index c99fd0f5..3969c2f0 100644
--- a/packages/business/universal-ui/src/authentication/register.vue
+++ b/packages/business/universal-ui/src/authentication/register.vue
@@ -78,7 +78,7 @@ function handleSubmit() {
});
}
-function goLogin() {
+function goToLogin() {
router.push(props.loginPath);
}
@@ -160,7 +160,7 @@ function goLogin() {
{{ $t('authentication.alreadyHaveAccount') }}
{{ $t('authentication.goToLogin') }}