Files
Yi.Framework/Yi.Ai.Vue3/src/layouts/components/Header/components/Avatar.vue

296 lines
8.5 KiB
Vue

<!-- 头像 -->
<script setup lang="ts">
import { useRouter } from 'vue-router';
import Popover from '@/components/Popover/index.vue';
import SvgIcon from '@/components/SvgIcon/index.vue';
import { useUserStore } from '@/stores';
import { useSessionStore } from '@/stores/modules/session';
import { getUserProfilePicture, isUserVip } from '@/utils/user';
const router = useRouter();
const userStore = useUserStore();
const sessionStore = useSessionStore();
// const src = computed(
// () => userStore.userInfo?.avatar ?? 'https://avatars.githubusercontent.com/u/76239030',
// );
const src = computed(
() => userStore.userInfo?.user?.icon ? `${import.meta.env.VITE_WEB_BASE_API}/file/${userStore.userInfo.user.icon}` : `@/assets/images/logo.png`,
);
/* 弹出面板 开始 */
const popoverStyle = ref({
width: '200px',
padding: '4px',
height: 'fit-content',
});
const popoverRef = ref();
// 弹出面板内容
const popoverList = ref([
// {
// key: '1',
// title: '收藏夹',
// icon: 'book-mark-fill',
// },
// {
// key: '2',
// title: '设置',
// icon: 'settings-4-fill',
// },
{
key: '5',
title: '用户中心',
icon: 'settings-4-fill',
},
{
key: '3',
divider: true,
},
{
key: '4',
title: '退出登录',
icon: 'logout-box-r-line',
},
]);
const dialogVisible = ref(false);
const navItems = [
// { name: 'user', label: '用户管理', icon: 'User' },
// { name: 'role', label: '角色管理', icon: 'Avatar' },
// { name: 'permission', label: '权限管理', icon: 'Key' },
{ name: 'apiKey', label: 'API密钥', icon: 'Key' },
{ name: 'rechargeLog', label: '充值记录', icon: 'Document' },
];
function openDialog() {
dialogVisible.value = true;
}
function handleConfirm(activeNav: string) {
console.log('确认操作,当前导航:', activeNav);
ElMessage.success('操作成功');
}
function handleNavChange(nav: string) {
console.log('导航切换:', nav);
}
// 点击
function handleClick(item: any) {
switch (item.key) {
case '1':
ElMessage.warning('暂未开放');
break;
case '2':
ElMessage.warning('暂未开放');
break;
case '5':
openDialog();
break;
case '4':
popoverRef.value?.hide?.();
ElMessageBox.confirm('退出登录不会丢失任何数据,你仍可以登录此账号。', '确认退出登录?', {
confirmButtonText: '确认退出',
cancelButtonText: '取消',
type: 'warning',
confirmButtonClass: 'el-button--danger',
cancelButtonClass: 'el-button--info',
roundButton: true,
autofocus: false,
})
.then(async () => {
// 在这里执行退出方法
await userStore.logout();
// 清空回话列表并回到默认页
await sessionStore.requestSessionList(1, true);
await sessionStore.createSessionBtn();
ElMessage({
type: 'success',
message: '退出成功',
});
})
.catch(() => {
// ElMessage({
// type: 'info',
// message: '取消',
// });
});
break;
default:
break;
}
}
function openVipGuide() {
ElMessageBox.confirm(
`
<div class="text-center leading-relaxed">
<h3 class="text-lg font-bold mb-3">${isUserVip() ? 'YiXinAI-VIP 会员' : '成为 YiXinAI-VIP'}</h3>
<p class="mb-2">
${
isUserVip()
? '您已是尊贵会员,享受全部 AI 模型与专属服务。感谢支持!'
: '解锁所有 AI 模型,无限加速,专属客服,尽享尊贵体验。'
}
</p>
${
isUserVip()
? '<p class="text-sm text-gray-500">您可随时访问产品页面查看更多特权内容。</p>'
: '<p class="text-sm text-gray-500">点击下方按钮,立即升级为 VIP 会员!</p>'
}
</div>
`,
isUserVip() ? '会员状态' : '会员尊享',
{
confirmButtonText: '前往产品页面',
cancelButtonText: '关闭',
dangerouslyUseHTMLString: true,
type: 'info',
center: true,
roundButton: true,
},
)
.then(() => {
router.push({
name: 'products', // 使用命名路由
query: { from: isUserVip() ? 'vip' : 'user' }, // 可选:添加来源标识
});
})
.catch(() => {
// 点击右上角关闭或“关闭”按钮,不执行任何操作
});
}
/* 弹出面板 结束 */
</script>
<template>
<div class="flex items-center gap-2">
<!-- 用户信息区域 -->
<div class=" cursor-pointer flex flex-col text-right mr-2 leading-tight" @click="openVipGuide">
<div class="text-sm font-semibold text-gray-800">
{{ userStore.userInfo?.user.nick ?? '未登录用户' }}
</div>
<!-- 角色展示 -->
<div>
<span
v-if="isUserVip()"
class="inline-block px-2 py-0.5 text-xs text-yellow-700 bg-yellow-100 rounded-full font-semibold"
>
YiXinAI-VIP
</span>
<span
v-else
class="inline-block px-2 py-0.5 text-xs text-gray-600 bg-gray-100 rounded-full cursor-pointer hover:bg-yellow-50 hover:text-yellow-700 transition"
>
普通用户 · 开通 VIP
</span>
</div>
</div>
<!-- 头像区域 -->
<div class="avatar-container">
<Popover
ref="popoverRef"
placement="bottom-end"
trigger="clickTarget"
:trigger-style="{ cursor: 'pointer' }"
popover-class="popover-content"
:popover-style="popoverStyle"
>
<template #trigger>
<el-avatar :src="getUserProfilePicture()" :size="28" fit="fit" shape="circle" />
</template>
<div class="popover-content-box shadow-lg">
<!-- 用户信息 -->
<div class="user-info-box flex items-center gap-8px p-8px rounded-lg mb-2">
<el-avatar :src="getUserProfilePicture()" :size="32" fit="fit" shape="circle" />
<div class="flex flex-col text-sm">
<div class="font-semibold text-gray-800">
{{ userStore.userInfo?.user.nick ?? '未登录用户' }}
</div>
<div class="text-xs text-gray-500">
<span
v-if="isUserVip()"
class="inline-block px-2 py-0.5 text-xs text-yellow-700 bg-yellow-100 rounded-full font-semibold"
>
YiXinAI-VIP
</span>
<span
v-else
class="inline-block px-2 py-0.5 text-xs text-gray-600 bg-gray-100 rounded-full cursor-pointer hover:bg-yellow-50 hover:text-yellow-700 transition"
>
普通用户 · 开通 VIP
</span>
</div>
</div>
</div>
<div class="divder h-1px bg-gray-200 my-4px" />
<div v-for="item in popoverList" :key="item.key" class="popover-content-box-items h-full">
<div
v-if="!item.divider"
class="popover-content-box-item flex items-center h-full gap-8px p-8px pl-10px pr-12px rounded-lg hover:cursor-pointer hover:bg-[rgba(0,0,0,.04)]"
@click="handleClick(item)"
>
<SvgIcon :name="item.icon!" size="16" class-name="flex-none" />
<div class="popover-content-box-item-text font-size-14px text-overflow max-h-120px">
{{ item.title }}
</div>
</div>
<div v-if="item.divider" class="divder h-1px bg-gray-200 my-4px" />
</div>
</div>
</Popover>
</div>
<nav-dialog
v-model="dialogVisible"
title="用户中心"
:nav-items="navItems"
@confirm="handleConfirm"
@nav-change="handleNavChange"
>
<!-- 用户管理内容 -->
<template #user>
<user-management />
</template>
<!-- 角色管理内容 -->
<template #role>
<!-- < /> -->
</template>
<!-- 权限管理内容 -->
<template #permission>
<!-- <permission-management /> -->
</template>
<template #apiKey>
<APIKeyManagement />
</template>
<template #rechargeLog>
<recharge-log />
</template>
</nav-dialog>
</div>
</template>
<style scoped lang="scss">
.popover-content {
width: 520px;
height: 520px;
}
.popover-content-box {
padding: 8px;
background: #ffffff;
border: 1px solid #e5e7eb;
border-radius: 8px;
box-shadow: 0 4px 16px rgb(0 0 0 / 8%);
}
</style>