Files
pc-10584/app/components/console/ConsoleHeader.vue
赵忠林 775841eed3 feat(core): 初始化项目基础架构和CMS功能模块
- 添加Docker相关配置文件(.dockerignore, .env.example, .gitignore)
- 实现服务端API代理功能,支持文件、模块和服务器API转发
- 创建文章详情页、栏目文章列表页和单页内容展示页面
- 集成Ant Design Vue组件库并实现SSR样式提取功能
- 定义API响应数据结构类型和应用布局组件
- 开发开发者应用中心和文章管理页面
- 实现CMS导航菜单获取和多租户切换功能
2026-01-27 00:14:08 +08:00

170 lines
4.9 KiB
Vue

<template>
<a-layout-header class="top-header !bg-white !p-0">
<div class="h-full px-4 flex items-center justify-between">
<div class="logo">
<a-space size="large">
<a-image
src="https://oss.wsdns.cn/20250204/a21e034cdb2441b797f5027db5305be5.png"
class="mb-1"
:width="90"
:preview="false"
@click="navigateTo('/console')"
/>
<!-- <a-dropdown-button @click="handleButtonClick">-->
<!-- {{ productLabel }}-->
<!-- <template #overlay>-->
<!-- <a-menu @click="handleProductMenuClick">-->
<!-- <a-menu-item key="site">-->
<!-- <a-avatar shape="square" :size="22" src="https://oss.wsdns.cn/20250215/2016c6f2da074b09b11a0e3603f5be23.png" />-->
<!-- ·企业官网-->
<!-- </a-menu-item>-->
<!-- <a-menu-item key="mp">-->
<!-- <a-avatar shape="square" :size="22" src="https://oss.wsdns.cn/20250304/e65ea719564e47a1b8da93d6eea8287a.png" />-->
<!-- 小程序开发-->
<!-- </a-menu-item>-->
<!-- <a-menu-item key="oa">-->
<!-- <a-avatar shape="square" :size="22" src="https://oss.wsdns.cn/20250215/457a343dba204d019281d8a23556c4b1.png" />-->
<!-- 办公协同OA-->
<!-- </a-menu-item>-->
<!-- <a-menu-item key="developer">-->
<!-- <a-avatar shape="square" :size="22" src="https://oss.wsdns.cn/20250214/d455a32a7a2043d899e079b4eb9b27b8.png" />-->
<!-- 开发者中心-->
<!-- </a-menu-item>-->
<!-- </a-menu>-->
<!-- </template>-->
<!-- </a-dropdown-button>-->
</a-space>
</div>
<a-dropdown placement="bottomRight" :trigger="['click']">
<div class="user-trigger">
<a-space>
<a-avatar :size="28" :src="user?.avatar || user?.avatarUrl">
<template #icon>
<AppstoreOutlined />
</template>
</a-avatar>
<span class="user-name">
{{ userDisplayName }}
</span>
</a-space>
</div>
<template #overlay>
<a-menu @click="onUserMenuClick">
<a-menu-item v-for="item in mergedUserMenuItems" :key="item.key">
{{ item.label }}
</a-menu-item>
</a-menu>
</template>
</a-dropdown>
</div>
</a-layout-header>
</template>
<script setup lang="ts">
import { AppstoreOutlined } from '@ant-design/icons-vue'
import type { MenuProps } from 'ant-design-vue'
import type { User } from '@/api/system/user/model'
type ConsoleHeaderMenuItem = {
key: string
label: string
}
const props = withDefaults(
defineProps<{
productLabel?: string
defaultJumpKey?: 'site' | 'mp' | 'oa' | 'developer'
user: User | null
userDisplayName: string
userMenuItems?: ConsoleHeaderMenuItem[]
}>(),
{
productLabel: '云·企业官网',
defaultJumpKey: 'site',
userMenuItems: () => [{ key: 'logout', label: '退出登录' }],
}
)
const emit = defineEmits<{
(e: 'logout'): void
(e: 'userMenuClick', key: string): void
}>()
const mergedUserMenuItems = computed<ConsoleHeaderMenuItem[]>(() => {
const items = Array.isArray(props.userMenuItems) ? props.userMenuItems.slice() : []
if (!items.some((i) => i.key === 'account')) {
const accountItem: ConsoleHeaderMenuItem = { key: 'account', label: '账号管理' }
const logoutIndex = items.findIndex((i) => i.key === 'logout')
if (logoutIndex >= 0) items.splice(logoutIndex, 0, accountItem)
else items.push(accountItem)
}
return items
})
const consoleJumpTargets = {
site: '/site',
mp: '/mp',
oa: '/oa',
developer: '/developer',
} as const
function openExternal(url: string) {
if (!import.meta.client) return
if (url.startsWith('http://') || url.startsWith('https://')) {
window.location.href = url
return
}
void navigateTo(url)
}
const handleButtonClick = () => {
openExternal(consoleJumpTargets[props.defaultJumpKey])
}
const handleProductMenuClick: MenuProps['onClick'] = (e) => {
const key = String(e.key) as keyof typeof consoleJumpTargets
const url = consoleJumpTargets[key]
if (!url) return
openExternal(url)
}
function onUserMenuClick(info: { key: string }) {
const key = String(info.key)
emit('userMenuClick', key)
if (key === 'account') {
void navigateTo('/console/account')
return
}
if (key === 'logout') emit('logout')
}
</script>
<style scoped>
.top-header {
height: 56px;
line-height: 56px;
border-radius: 12px;
}
.user-trigger {
height: 36px;
display: flex;
align-items: center;
padding: 0 10px;
border-radius: 9999px;
cursor: pointer;
}
.user-trigger:hover {
background: rgba(0, 0, 0, 0.04);
}
.user-name {
max-width: 180px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
</style>