From fe65d548beab2490013b56539d01da4e24ebdff8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=86=E4=BC=AF=E8=A8=80?= Date: Sun, 19 Jul 2026 01:17:22 +0800 Subject: [PATCH 1/4] =?UTF-8?q?docs:=20=E4=BF=AE=E5=A4=8D=E8=8B=B1?= =?UTF-8?q?=E6=96=87=E8=AF=AD=E8=A8=80=E6=96=87=E4=BB=B6=E8=B7=AF=E5=BE=84?= =?UTF-8?q?=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit closed #8158 --- docs/src/en/guide/in-depth/locale.md | 8 +++----- docs/src/guide/in-depth/locale.md | 8 +++----- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/docs/src/en/guide/in-depth/locale.md b/docs/src/en/guide/in-depth/locale.md index 549bc83f..b46716d9 100644 --- a/docs/src/en/guide/in-depth/locale.md +++ b/docs/src/en/guide/in-depth/locale.md @@ -60,25 +60,23 @@ To add new translation texts, simply find `src/locales/langs/` in the correspond **src/locales/langs/zh-CN/\*.json** -````ts ```json { "about": { "desc": "Vben Admin 是一个现代的管理模版。" } } -```` +``` -**src/locales/langs/en-US.ts** +**src/locales/langs/en-US/\*.json** -````ts ```json { "about": { "desc": "Vben Admin is a modern management template." } } -```` +``` ## Using Translation Texts diff --git a/docs/src/guide/in-depth/locale.md b/docs/src/guide/in-depth/locale.md index e4a4a659..8c4b7ac0 100644 --- a/docs/src/guide/in-depth/locale.md +++ b/docs/src/guide/in-depth/locale.md @@ -60,25 +60,23 @@ updateLocale('en-US'); **src/locales/langs/zh-CN/\*.json** -````ts ```json { "about": { "desc": "Vben Admin 是一个现代的管理模版。" } } -```` +``` -**src/locales/langs/en-US.ts** +**src/locales/langs/en-US/\*.json** -````ts ```json { "about": { "desc": "Vben Admin is a modern management template." } } -```` +``` ## 使用翻译文本 From 41c20a43aff4d0b3c795c358241fd1a588e45996 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=86=E4=BC=AF=E8=A8=80?= Date: Sun, 19 Jul 2026 01:22:00 +0800 Subject: [PATCH 2/4] =?UTF-8?q?docs:=20=E6=9B=B4=E6=AD=A3=E8=AF=AD?= =?UTF-8?q?=E8=A8=80=E4=BD=BF=E7=94=A8=E7=A4=BA=E4=BE=8B,=E7=A1=AE?= =?UTF-8?q?=E4=BF=9D=E5=8F=AF=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 使用可用的语言配置 修复computed变量使用语法错误 closed #8159 --- docs/src/en/guide/in-depth/locale.md | 6 +++--- docs/src/guide/in-depth/locale.md | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/src/en/guide/in-depth/locale.md b/docs/src/en/guide/in-depth/locale.md index b46716d9..ee46901a 100644 --- a/docs/src/en/guide/in-depth/locale.md +++ b/docs/src/en/guide/in-depth/locale.md @@ -89,11 +89,11 @@ With `@vben/locales`, you can easily use translation texts: import { computed } from 'vue'; import { $t } from '@vben/locales'; -const items = computed(() => [{ title: $t('about.desc') }]); +const items = computed(() => [{ title: $t('demos.title') }]); diff --git a/packages/effects/layouts/src/basic/layout.vue b/packages/effects/layouts/src/basic/layout.vue index e83f5a4c..d8646a6c 100644 --- a/packages/effects/layouts/src/basic/layout.vue +++ b/packages/effects/layouts/src/basic/layout.vue @@ -369,9 +369,6 @@ const headerSlots = computed(() => { - diff --git a/packages/effects/layouts/src/widgets/preferences/blocks/draggable-list.vue b/packages/effects/layouts/src/widgets/preferences/blocks/draggable-list.vue new file mode 100644 index 00000000..db85f45f --- /dev/null +++ b/packages/effects/layouts/src/widgets/preferences/blocks/draggable-list.vue @@ -0,0 +1,140 @@ + + + diff --git a/packages/effects/layouts/src/widgets/preferences/blocks/layout/widget.vue b/packages/effects/layouts/src/widgets/preferences/blocks/layout/widget.vue index 39cd14e5..e0b084a9 100644 --- a/packages/effects/layouts/src/widgets/preferences/blocks/layout/widget.vue +++ b/packages/effects/layouts/src/widgets/preferences/blocks/layout/widget.vue @@ -1,31 +1,70 @@ diff --git a/packages/effects/layouts/src/widgets/preferences/preferences-drawer.vue b/packages/effects/layouts/src/widgets/preferences/preferences-drawer.vue index 66e09a71..c1b6ec8e 100644 --- a/packages/effects/layouts/src/widgets/preferences/preferences-drawer.vue +++ b/packages/effects/layouts/src/widgets/preferences/preferences-drawer.vue @@ -174,15 +174,34 @@ const shortcutKeysGlobalLockScreen = defineModel( 'shortcutKeysGlobalLockScreen', ); -const widgetGlobalSearch = defineModel('widgetGlobalSearch'); -const widgetFullscreen = defineModel('widgetFullscreen'); -const widgetLanguageToggle = defineModel('widgetLanguageToggle'); -const widgetNotification = defineModel('widgetNotification'); -const widgetThemeToggle = defineModel('widgetThemeToggle'); -const widgetSidebarToggle = defineModel('widgetSidebarToggle'); -const widgetLockScreen = defineModel('widgetLockScreen'); -const widgetRefresh = defineModel('widgetRefresh'); -const widgetTimezone = defineModel('widgetTimezone'); +const widgetGlobalSearchButtonPosition = defineModel( + 'widgetGlobalSearchButtonPosition', +); +const widgetFullscreenButtonPosition = defineModel( + 'widgetFullscreenButtonPosition', +); +const widgetLanguageToggleButtonPosition = defineModel( + 'widgetLanguageToggleButtonPosition', +); +const widgetNotificationButtonPosition = defineModel( + 'widgetNotificationButtonPosition', +); +const widgetThemeToggleButtonPosition = defineModel( + 'widgetThemeToggleButtonPosition', +); +const widgetLockScreenButtonPosition = defineModel( + 'widgetLockScreenButtonPosition', +); +const widgetLogoutButtonPosition = defineModel( + 'widgetLogoutButtonPosition', +); +const widgetOrder = defineModel('widgetOrder', { required: true }); +const widgetRefreshButtonPosition = defineModel( + 'widgetRefreshButtonPosition', +); +const widgetTimezoneButtonPosition = defineModel( + 'widgetTimezoneButtonPosition', +); const { customPreferences, @@ -483,15 +502,34 @@ function handleCustomPreferencesUpdate(updates: CustomPreferencesRecord) { v-model:app-preferences-button-position=" appPreferencesButtonPosition " - 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-refresh="widgetRefresh" - v-model:widget-sidebar-toggle="widgetSidebarToggle" - v-model:widget-theme-toggle="widgetThemeToggle" - v-model:widget-timezone="widgetTimezone" + v-model:widget-fullscreen-button-position=" + widgetFullscreenButtonPosition + " + v-model:widget-global-search-button-position=" + widgetGlobalSearchButtonPosition + " + v-model:widget-language-toggle-button-position=" + widgetLanguageToggleButtonPosition + " + v-model:widget-lock-screen-button-position=" + widgetLockScreenButtonPosition + " + v-model:widget-logout-button-position=" + widgetLogoutButtonPosition + " + v-model:widget-order="widgetOrder" + v-model:widget-notification-button-position=" + widgetNotificationButtonPosition + " + v-model:widget-refresh-button-position=" + widgetRefreshButtonPosition + " + v-model:widget-theme-toggle-button-position=" + widgetThemeToggleButtonPosition + " + v-model:widget-timezone-button-position=" + widgetTimezoneButtonPosition + " /> diff --git a/packages/effects/layouts/src/widgets/user-dropdown/user-dropdown.vue b/packages/effects/layouts/src/widgets/user-dropdown/user-dropdown.vue index 2047b950..7a0f293a 100644 --- a/packages/effects/layouts/src/widgets/user-dropdown/user-dropdown.vue +++ b/packages/effects/layouts/src/widgets/user-dropdown/user-dropdown.vue @@ -3,13 +3,27 @@ import type { Component } from 'vue'; import type { AnyFunction } from '@vben/types'; -import { useTemplateRef, watch } from 'vue'; +import { computed, useTemplateRef, watch } from 'vue'; import { useHoverToggle } from '@vben/hooks'; -import { Settings } from '@vben/icons'; +import { + Bell, + Fullscreen, + Languages, + LockKeyhole, + LogOut, + RotateCw, + Search, + Settings, + Sun, + SunMoon, +} from '@vben/icons'; import { $t } from '@vben/locales'; -import { usePreferences } from '@vben/preferences'; +import { preferences, usePreferences } from '@vben/preferences'; +import { useAccessStore } from '@vben/stores'; +import { isWindowsOs } from '@vben/utils'; +import { useVbenModal } from '@vben-core/popup-ui'; import { Badge, DropdownMenu, @@ -17,11 +31,15 @@ import { DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, + DropdownMenuShortcut, DropdownMenuTrigger, VbenAvatar, VbenIcon, } from '@vben-core/shadcn-ui'; +import { useMagicKeys, whenever } from '@vueuse/core'; + +import { LockScreenModal } from '../lock-screen'; import { Preferences } from '../preferences'; interface Props { @@ -70,9 +88,22 @@ const props = withDefaults(defineProps(), { hoverDelay: 500, }); -const emit = defineEmits<{ clearPreferencesAndLogout: [] }>(); +const emit = defineEmits<{ clearPreferencesAndLogout: []; logout: [] }>(); -const { preferencesButtonPosition } = usePreferences(); +const { + globalLockScreenShortcutKey, + globalLogoutShortcutKey, + preferencesButtonPosition, +} = usePreferences(); +const accessStore = useAccessStore(); +const [LockModal, lockModalApi] = useVbenModal({ + connectedComponent: LockScreenModal, +}); +const [LogoutModal, logoutModalApi] = useVbenModal({ + onConfirm() { + handleSubmitLogout(); + }, +}); const refTrigger = useTemplateRef('refTrigger'); const refContent = useTemplateRef('refContent'); @@ -96,13 +127,157 @@ watch( }, ); +const showLockInDropdown = computed( + () => + preferences.widget.lockScreen && + preferences.widget.lockScreenButtonPosition === 'user-dropdown', +); + +const showLogoutInDropdown = computed( + () => preferences.widget.logoutButtonPosition === 'user-dropdown', +); + +const showGlobalSearchInDropdown = computed( + () => + preferences.widget.globalSearch && + preferences.widget.globalSearchButtonPosition === 'user-dropdown', +); + +const showThemeToggleInDropdown = computed( + () => + preferences.widget.themeToggle && + preferences.widget.themeToggleButtonPosition === 'user-dropdown', +); + +const showLanguageToggleInDropdown = computed( + () => + preferences.widget.languageToggle && + preferences.widget.languageToggleButtonPosition === 'user-dropdown', +); + +const showTimezoneInDropdown = computed( + () => + preferences.widget.timezone && + preferences.widget.timezoneButtonPosition === 'user-dropdown', +); + +const showFullscreenInDropdown = computed( + () => + preferences.widget.fullscreen && + preferences.widget.fullscreenButtonPosition === 'user-dropdown', +); + +const showNotificationInDropdown = computed( + () => + preferences.widget.notification && + preferences.widget.notificationButtonPosition === 'user-dropdown', +); + +const showRefreshInDropdown = computed( + () => + preferences.widget.refresh && + preferences.widget.refreshButtonPosition === 'user-dropdown', +); + +const hasAnyInDropdown = computed( + () => + showLockInDropdown.value || + showLogoutInDropdown.value || + showGlobalSearchInDropdown.value || + showThemeToggleInDropdown.value || + showLanguageToggleInDropdown.value || + showTimezoneInDropdown.value || + showFullscreenInDropdown.value || + showNotificationInDropdown.value || + showRefreshInDropdown.value, +); + +const altView = computed(() => (isWindowsOs() ? 'Alt' : '⌥')); + +const enableLogoutShortcutKey = computed(() => { + return showLogoutInDropdown.value && globalLogoutShortcutKey.value; +}); + +const enableLockScreenShortcutKey = computed(() => { + return showLockInDropdown.value && globalLockScreenShortcutKey.value; +}); + +const enableShortcutKey = computed(() => { + return ( + (showLockInDropdown.value || showLogoutInDropdown.value) && + preferences.shortcutKeys.enable + ); +}); + +function handleOpenLock() { + lockModalApi.open(); +} + +function handleSubmitLock(lockScreenPassword: string) { + lockModalApi.close(); + accessStore.lockScreen(lockScreenPassword); +} + +function handleLogout() { + logoutModalApi.open(); + openPopover.value = false; +} + +function handleSubmitLogout() { + emit('logout'); + logoutModalApi.close(); +} + // 设置 - 打开偏好设置抽屉 function handleOpenSettings() { refPreferences.value?.open(); } + +if (enableShortcutKey.value) { + const keys = useMagicKeys(); + const logoutKey = keys['Alt+KeyQ']; + const lockKey = keys['Alt+KeyL']; + + if (logoutKey) { + whenever(logoutKey, () => { + if (enableLogoutShortcutKey.value) { + handleLogout(); + } + }); + } + + if (lockKey) { + whenever(lockKey, () => { + if (enableLockScreenShortcutKey.value) { + handleOpenLock(); + } + }); + } +}