From a1d7e81859f554f3a53680cc35f0f49bf1f77098 Mon Sep 17 00:00:00 2001
From: wwf <1971391498@qq.com>
Date: 星期四, 14 五月 2026 14:37:02 +0800
Subject: [PATCH] 导入项目
---
src/layout/components/UserInfo/src/UserInfo.vue | 113 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 113 insertions(+), 0 deletions(-)
diff --git a/src/layout/components/UserInfo/src/UserInfo.vue b/src/layout/components/UserInfo/src/UserInfo.vue
new file mode 100644
index 0000000..355aabc
--- /dev/null
+++ b/src/layout/components/UserInfo/src/UserInfo.vue
@@ -0,0 +1,113 @@
+<script lang="ts" setup>
+import { ElMessageBox } from 'element-plus'
+
+import avatarImg from '@/assets/imgs/avatar.gif'
+import { useDesign } from '@/hooks/web/useDesign'
+import { useTagsViewStore } from '@/store/modules/tagsView'
+import { useUserStore } from '@/store/modules/user'
+import LockDialog from './components/LockDialog.vue'
+import LockPage from './components/LockPage.vue'
+import { useLockStore } from '@/store/modules/lock'
+
+defineOptions({ name: 'UserInfo' })
+
+const { t } = useI18n()
+
+const { push, replace } = useRouter()
+
+const userStore = useUserStore()
+
+const tagsViewStore = useTagsViewStore()
+
+const { getPrefixCls } = useDesign()
+
+const prefixCls = getPrefixCls('user-info')
+
+const avatar = computed(() => userStore.user.avatar || avatarImg)
+const userName = computed(() => userStore.user.nickname ?? 'Admin')
+
+// 閿佸畾灞忓箷
+const lockStore = useLockStore()
+const getIsLock = computed(() => lockStore.getLockInfo?.isLock ?? false)
+const dialogVisible = ref<boolean>(false)
+const lockScreen = () => {
+ dialogVisible.value = true
+}
+
+const loginOut = async () => {
+ try {
+ await ElMessageBox.confirm(t('common.loginOutMessage'), t('common.reminder'), {
+ confirmButtonText: t('common.ok'),
+ cancelButtonText: t('common.cancel'),
+ type: 'warning'
+ })
+ await userStore.loginOut()
+ tagsViewStore.delAllViews()
+ replace('/login?redirect=/index')
+ } catch {}
+}
+const toProfile = async () => {
+ push('/user/profile')
+}
+const toDocument = () => {
+ window.open('https://doc.iocoder.cn/')
+}
+</script>
+
+<template>
+ <ElDropdown class="custom-hover" :class="prefixCls" trigger="click">
+ <div class="flex items-center">
+ <ElAvatar :src="avatar" alt="" class="w-[calc(var(--logo-height)-25px)] rounded-[50%]" />
+ <span class="pl-[5px] text-14px text-[var(--top-header-text-color)] <lg:hidden">
+ {{ userName }}
+ </span>
+ </div>
+ <template #dropdown>
+ <ElDropdownMenu>
+ <ElDropdownItem>
+ <Icon icon="ep:tools" />
+ <div @click="toProfile">{{ t('common.profile') }}</div>
+ </ElDropdownItem>
+ <ElDropdownItem>
+ <Icon icon="ep:menu" />
+ <div @click="toDocument">{{ t('common.document') }}</div>
+ </ElDropdownItem>
+ <ElDropdownItem divided>
+ <Icon icon="ep:lock" />
+ <div @click="lockScreen">{{ t('lock.lockScreen') }}</div>
+ </ElDropdownItem>
+ <ElDropdownItem divided @click="loginOut">
+ <Icon icon="ep:switch-button" />
+ <div>{{ t('common.loginOut') }}</div>
+ </ElDropdownItem>
+ </ElDropdownMenu>
+ </template>
+ </ElDropdown>
+
+ <LockDialog v-if="dialogVisible" v-model="dialogVisible" />
+
+ <teleport to="body">
+ <transition name="fade-bottom" mode="out-in">
+ <LockPage v-if="getIsLock" />
+ </transition>
+ </teleport>
+</template>
+
+<style scoped lang="scss">
+.fade-bottom-enter-active,
+.fade-bottom-leave-active {
+ transition:
+ opacity 0.25s,
+ transform 0.3s;
+}
+
+.fade-bottom-enter-from {
+ opacity: 0;
+ transform: translateY(-10%);
+}
+
+.fade-bottom-leave-to {
+ opacity: 0;
+ transform: translateY(10%);
+}
+</style>
--
Gitblit v1.8.0