mirror of
https://github.com/certd/certd.git
synced 2026-05-16 05:07:32 +08:00
🔱: [client] sync upgrade with 7 commits [trident-sync]
chore: Merge branch 'vben' # Conflicts: # package.json perf: antdv示例改成使用vben框架 chore: vben chore: vben chore: vben
This commit is contained in:
@@ -0,0 +1,213 @@
|
||||
<script setup lang="ts">
|
||||
import type { Component } from "vue";
|
||||
|
||||
import type { AnyFunction } from "/@/vben/types";
|
||||
|
||||
import { computed, useTemplateRef, watch } from "vue";
|
||||
|
||||
import { useHoverToggle } from "/@/vben/hooks";
|
||||
import { LockKeyhole, LogOut } from "/@/vben/icons";
|
||||
import { $t } from "/@/vben/locales";
|
||||
import { preferences, usePreferences } from "/@/vben/preferences";
|
||||
import { useLockStore } from "/@/vben/stores";
|
||||
import { isWindowsOs } from "/@/vben/utils";
|
||||
|
||||
import { useVbenModal } from "/@/vben//popup-ui";
|
||||
import { Badge, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuTrigger, VbenAvatar, VbenIcon } from "/@/vben//shadcn-ui";
|
||||
|
||||
import { useMagicKeys, whenever } from "@vueuse/core";
|
||||
|
||||
import { LockScreenModal } from "../lock-screen";
|
||||
|
||||
interface Props {
|
||||
/**
|
||||
* 头像
|
||||
*/
|
||||
avatar?: string;
|
||||
/**
|
||||
* @zh_CN 描述
|
||||
*/
|
||||
description?: string;
|
||||
/**
|
||||
* 是否启用快捷键
|
||||
*/
|
||||
enableShortcutKey?: boolean;
|
||||
/**
|
||||
* 菜单数组
|
||||
*/
|
||||
menus?: Array<{ handler: AnyFunction; icon?: Component; text: string }>;
|
||||
|
||||
/**
|
||||
* 标签文本
|
||||
*/
|
||||
tagText?: string;
|
||||
/**
|
||||
* 文本
|
||||
*/
|
||||
text?: string;
|
||||
/** 触发方式 */
|
||||
trigger?: "both" | "click" | "hover";
|
||||
/** hover触发时,延迟响应的时间 */
|
||||
hoverDelay?: number;
|
||||
}
|
||||
|
||||
defineOptions({
|
||||
name: "UserDropdown"
|
||||
});
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
avatar: "",
|
||||
description: "",
|
||||
enableShortcutKey: true,
|
||||
menus: () => [],
|
||||
showShortcutKey: true,
|
||||
tagText: "",
|
||||
text: "",
|
||||
trigger: "click",
|
||||
hoverDelay: 500
|
||||
});
|
||||
|
||||
const emit = defineEmits<{ logout: [] }>();
|
||||
|
||||
const { globalLockScreenShortcutKey, globalLogoutShortcutKey } = usePreferences();
|
||||
const lockStore = useLockStore();
|
||||
const [LockModal, lockModalApi] = useVbenModal({
|
||||
connectedComponent: LockScreenModal
|
||||
});
|
||||
const [LogoutModal, logoutModalApi] = useVbenModal({
|
||||
onConfirm() {
|
||||
handleSubmitLogout();
|
||||
}
|
||||
});
|
||||
|
||||
const refTrigger = useTemplateRef("refTrigger");
|
||||
const refContent = useTemplateRef("refContent");
|
||||
const [openPopover, hoverWatcher] = useHoverToggle([refTrigger, refContent], () => props.hoverDelay);
|
||||
|
||||
watch(
|
||||
() => props.trigger === "hover" || props.trigger === "both",
|
||||
(val) => {
|
||||
if (val) {
|
||||
hoverWatcher.enable();
|
||||
} else {
|
||||
hoverWatcher.disable();
|
||||
}
|
||||
},
|
||||
{
|
||||
immediate: true
|
||||
}
|
||||
);
|
||||
|
||||
const altView = computed(() => (isWindowsOs() ? "Alt" : "⌥"));
|
||||
|
||||
const enableLogoutShortcutKey = computed(() => {
|
||||
return props.enableShortcutKey && globalLogoutShortcutKey.value;
|
||||
});
|
||||
|
||||
const enableLockScreenShortcutKey = computed(() => {
|
||||
return props.enableShortcutKey && globalLockScreenShortcutKey.value;
|
||||
});
|
||||
|
||||
const enableShortcutKey = computed(() => {
|
||||
return props.enableShortcutKey && preferences.shortcutKeys.enable;
|
||||
});
|
||||
|
||||
function handleOpenLock() {
|
||||
lockModalApi.open();
|
||||
}
|
||||
|
||||
function handleSubmitLock(lockScreenPassword: string) {
|
||||
lockModalApi.close();
|
||||
lockStore.lockScreen(lockScreenPassword);
|
||||
}
|
||||
|
||||
function handleLogout() {
|
||||
// emit
|
||||
logoutModalApi.open();
|
||||
openPopover.value = false;
|
||||
}
|
||||
|
||||
function handleSubmitLogout() {
|
||||
emit("logout");
|
||||
logoutModalApi.close();
|
||||
}
|
||||
|
||||
if (enableShortcutKey.value) {
|
||||
const keys = useMagicKeys();
|
||||
whenever(keys["Alt+KeyQ"]!, () => {
|
||||
if (enableLogoutShortcutKey.value) {
|
||||
handleLogout();
|
||||
}
|
||||
});
|
||||
|
||||
whenever(keys["Alt+KeyL"]!, () => {
|
||||
if (enableLockScreenShortcutKey.value) {
|
||||
handleOpenLock();
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<LockModal v-if="preferences.widget.lockScreen" :avatar="avatar" :text="text" @submit="handleSubmitLock" />
|
||||
|
||||
<LogoutModal
|
||||
:cancel-text="$t('common.cancel')"
|
||||
:confirm-text="$t('common.confirm')"
|
||||
:fullscreen-button="false"
|
||||
:title="$t('common.prompt')"
|
||||
centered
|
||||
content-class="px-8 min-h-10"
|
||||
footer-class="border-none mb-3 mr-3"
|
||||
header-class="border-none"
|
||||
>
|
||||
{{ $t("ui.widgets.logoutTip") }}
|
||||
</LogoutModal>
|
||||
|
||||
<DropdownMenu v-model:open="openPopover">
|
||||
<DropdownMenuTrigger ref="refTrigger" :disabled="props.trigger === 'hover'">
|
||||
<div class="hover:bg-accent ml-1 mr-2 cursor-pointer rounded-full p-1.5">
|
||||
<div class="hover:text-accent-foreground flex-center">
|
||||
<VbenAvatar :alt="text" :src="avatar" class="size-8" dot />
|
||||
</div>
|
||||
</div>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent class="mr-2 min-w-[240px] p-0 pb-1">
|
||||
<div ref="refContent">
|
||||
<DropdownMenuLabel class="flex items-center p-3">
|
||||
<VbenAvatar :alt="text" :src="avatar" class="size-12" dot dot-class="bottom-0 right-1 border-2 size-4 bg-green-500" />
|
||||
<div class="ml-2 w-full">
|
||||
<div v-if="tagText || text || $slots.tagText" class="text-foreground mb-1 flex items-center text-sm font-medium">
|
||||
{{ text }}
|
||||
<slot name="tagText">
|
||||
<Badge v-if="tagText" class="ml-2 text-green-400">
|
||||
{{ tagText }}
|
||||
</Badge>
|
||||
</slot>
|
||||
</div>
|
||||
<div class="text-muted-foreground text-xs font-normal">
|
||||
{{ description }}
|
||||
</div>
|
||||
</div>
|
||||
</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator v-if="menus?.length" />
|
||||
<DropdownMenuItem v-for="menu in menus" :key="menu.text" class="mx-1 flex cursor-pointer items-center rounded-sm py-1 leading-8" @click="menu.handler">
|
||||
<VbenIcon :icon="menu.icon" class="mr-2 size-4" />
|
||||
{{ menu.text }}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem v-if="preferences.widget.lockScreen" class="mx-1 flex cursor-pointer items-center rounded-sm py-1 leading-8" @click="handleOpenLock">
|
||||
<LockKeyhole class="mr-2 size-4" />
|
||||
{{ $t("ui.widgets.lockScreen.title") }}
|
||||
<DropdownMenuShortcut v-if="enableLockScreenShortcutKey"> {{ altView }} L </DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator v-if="preferences.widget.lockScreen" />
|
||||
<DropdownMenuItem class="mx-1 flex cursor-pointer items-center rounded-sm py-1 leading-8" @click="handleLogout">
|
||||
<LogOut class="mr-2 size-4" />
|
||||
{{ $t("common.logout") }}
|
||||
<DropdownMenuShortcut v-if="enableLogoutShortcutKey"> {{ altView }} Q </DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
</div>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</template>
|
||||
Reference in New Issue
Block a user