- 新增 hzhub-portal-employee 员工门户前端项目(基于 Vue3 + Element Plus) - 后端登录接口增加返回 nickName 字段 - 移除 KnowledgeInfoController 的 @SaCheckPermission 注解 - 删除 hzhub-portal-company 旧门户项目 - 更新项目文档和架构说明 - 添加后台运行管理脚本(start-all.sh / status-all.sh / stop-all.sh) - 更新 docker-compose 配置 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
8.5 KiB
8.5 KiB
标签页功能说明
功能概述
已将 hzhub-admin 中的标签页导航功能移植到 hzhub-portal-employee,使用 Element Plus 组件重新实现。
主要功能
1. 标签页管理
- 自动添加标签页:路由切换时自动创建对应标签页
- 关闭标签页:点击关闭按钮关闭当前标签页
- 固定标签页:固定后的标签页不可关闭,以不同颜色标识
- 标签页持久化:标签页状态自动保存到本地存储
2. 工具栏功能
- 更多操作菜单:
- 关闭其他标签页
- 关闭右侧标签页
- 关闭所有标签页
- 全屏切换:切换浏览器全屏模式
3. 视觉效果
- 当前激活标签页高亮显示(主题色)
- 固定标签页以警告色标识
- 悬停显示关闭按钮
- 平滑过渡动画
- 标签页图标支持(可选)
技术实现
UI 框架适配
从 hzhub-admin (Ant Design Vue) 到 hzhub-portal-employee (Element Plus) 的适配:
| 功能 | hzhub-admin | hzhub-portal-employee |
|---|---|---|
| UI 框架 | Ant Design Vue + Vben | Element Plus |
| 图标组件 | <VbenIcon> |
<el-icon> |
| 下拉菜单 | <VbenDropdownMenu> |
<el-dropdown> |
| CSS 系统 | TailwindCSS | SCSS + Element Plus 变量 |
| 图标库 | Vben Icons | Element Plus Icons |
文件结构
src/
├── stores/
│ ├── modules/
│ │ └── tabbar.ts # 标签页状态管理
│ └── index.ts # 导出 tabbar store
├── hooks/
│ └── useTabbar.ts # 标签页操作 Hook
├── layouts/
│ ├── components/
│ │ └── TabsView/
│ │ └── index.vue # 标签页视图组件
│ └── LayoutVertical/
│ └── index.vue # 集成标签页的布局
└── routers/
└ modules/
└── staticRouter.ts # 路由配置
核心代码
Tabbar Store
export interface TabItem {
path: string; // 路由路径
name: string; // 路由名称
title: string; // 标签页标题
icon?: string; // 图标
affix?: boolean; // 是否固定
query?: any; // 路由参数
}
export const useTabbarStore = defineStore('tabbar', {
state: (): TabbarState => ({
tabs: [], // 标签页列表
activeTab: '/', // 当前激活的标签页
cachedTabs: new Set(), // 缓存的组件名称
}),
actions: {
addTab(route), // 添加标签页
closeTab(path), // 关闭标签页
closeOtherTabs(path), // 关闭其他标签页
closeAllTabs(), // 关闭所有标签页
closeRightTabs(path), // 关闭右侧标签页
toggleAffixTab(path), // 固定/取消固定
initAffixTabs(routes), // 初始化固定标签页
},
persist: {
key: 'hzhub-employee-tabs',
paths: ['tabs', 'activeTab'],
},
});
useTabbar Hook
export function useTabbar() {
const router = useRouter();
const route = useRoute();
const tabbarStore = useTabbarStore();
// 监听路由变化,自动添加标签页
watch(() => route.path, () => {
if (route.name) {
tabbarStore.addTab(route);
}
}, { immediate: true });
// 初始化固定标签页
watch(() => router.getRoutes(), () => {
tabbarStore.initAffixTabs(router.getRoutes());
}, { immediate: true });
return {
currentActive, // 当前激活的标签页
currentTabs, // 标签页列表
handleClick, // 点击标签页
handleClose, // 关闭标签页
handleUnpin, // 固定/取消固定
closeOtherTabs, // 关闭其他标签页
closeAllTabs, // 关闭所有标签页
closeRightTabs, // 关闭右侧标签页
};
}
TabsView 组件
<script setup lang="ts">
import { computed, ref } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { useTabbarStore } from '@/stores';
const tabbarStore = useTabbarStore();
const activeTabPath = computed(() => tabbarStore.activeTab);
const tabs = computed(() => tabbarStore.tabs);
const isFullscreen = ref(false);
// 点击标签页
const handleTabClick = (tab: TabItem) => {
tabbarStore.setActiveTab(tab.path);
router.push(tab.path);
};
// 关闭标签页
const handleTabClose = (path: string) => {
tabbarStore.closeTab(path);
};
// 切换全屏
const toggleFullscreen = () => {
isFullscreen.value = !isFullscreen.value;
if (isFullscreen.value) {
document.documentElement.requestFullscreen();
} else {
document.exitFullscreen();
}
};
</script>
布局集成
<script setup lang="ts">
import TabsView from '@/layouts/components/TabsView/index.vue';
import { useTabbar } from '@/hooks/useTabbar';
const { handleClose, handleUnpin } = useTabbar();
</script>
<template>
<div class="layout">
<Aside />
<div class="main-area">
<Header />
<TabsView
:show-icon="true"
@close="handleClose"
@unpin="handleUnpin"
/>
<main class="page-content">
<router-view />
</main>
</div>
</div>
</template>
使用说明
固定标签页
在路由配置中添加 meta.affix 属性:
{
path: '/dashboard',
name: 'dashboard',
meta: {
title: '工作台',
icon: 'Odometer',
affix: true, // 固定标签页
},
}
隐藏标签页
在路由配置中添加 meta.isHide 属性:
{
path: '/profile',
name: 'profile',
meta: {
title: '个人中心',
isHide: '1', // 不显示在标签页中
},
}
禁用缓存
在路由配置中添加 meta.isKeepAlive 属性:
{
path: '/example',
name: 'example',
meta: {
title: '示例页面',
isKeepAlive: '0', // 不缓存组件
},
}
样式定制
标签页样式使用 Element Plus CSS 变量系统:
- 激活状态:
--el-color-primary(主题色) - 固定状态:
--el-color-warning(警告色) - 悬停状态:
--el-color-primary-light-9 - 背景色:
--el-bg-color-page - 边框色:
--el-border-color-light
可在 src/styles/var.scss 中自定义这些变量值。
注意事项
-
标签页限制:
- 固定的标签页不能关闭
- 至少保留一个标签页
- 标签页标题过长会自动截断
-
路由要求:
- 路由必须设置
name属性 - 路由必须设置
meta.title属性 - 隐藏路由(
isHide='1')不会添加到标签页
- 路由必须设置
-
持久化配置:
- 使用
pinia-plugin-persistedstate自动保存 - 保存路径:
['tabs', 'activeTab'] - 不保存
cachedTabs(组件缓存)
- 使用
-
性能优化:
- 使用
keep-alive缓存组件 - 标签页列表使用
Set优化查找 - 懒加载图标组件
- 使用
与 hzhub-admin 的差异
保留的功能
- ✅ 标签页自动添加/关闭
- ✅ 标签页固定/取消固定
- ✅ 批量关闭操作
- ✅ 标签页持久化
- ✅ 全屏切换
- ✅ 标签页图标显示
简化的功能
- ❌ 拖拽排序(暂未实现)
- ❌ 滚轮滚动(暂未实现)
- ❌ 中键关闭(暂未实现)
- ❌ 右键菜单(暂未实现)
- ❌ 多种标签页样式(plain/brisk/card)
- ❌ 国际化标题切换
新增的功能
- ✅ 简化的工具栏设计
- ✅ Element Plus 原生样式
- ✅ 更简洁的代码结构
后续优化建议
-
交互增强:
- 添加右键菜单功能
- 支持拖拽排序标签页
- 支持鼠标滚轮横向滚动
- 支持中键点击关闭
-
样式定制:
- 提供多种标签页样式(chrome/card/plain)
- 支持自定义标签页主题色
- 标签页宽度自适应
-
功能扩展:
- 标签页分组功能
- 标签页搜索功能
- 最近访问的标签页历史
- 标签页快捷键操作
-
性能优化:
- 虚拟滚动优化大量标签页
- 标签页懒加载优化
- 组件缓存策略优化
测试建议
功能测试
-
标签页管理:
- 切换路由自动添加标签页
- 关闭标签页后自动切换到相邻标签页
- 固定标签页不可关闭
- 刷新后标签页状态保持
-
批量操作:
- 关闭其他标签页
- 关闭右侧标签页
- 关闭所有标签页
-
全屏功能:
- 点击全屏按钮进入全屏模式
- 再次点击退出全屏模式
兼容性测试
- Chrome、Firefox、Safari 浏览器测试
- 响应式布局测试(桌面端、平板)
- 标签页滚动测试(超过 10 个标签页)
- 固定标签页与普通标签页混排测试