Files
hzhub/hzhub-portal-employee/docs/TABBAR_FEATURE.md
大壮 278e507e8a feat: 添加员工门户项目及相关后端改造
- 新增 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>
2026-04-13 03:47:33 +00:00

8.5 KiB
Raw Blame History

标签页功能说明

功能概述

已将 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 中自定义这些变量值。

注意事项

  1. 标签页限制

    • 固定的标签页不能关闭
    • 至少保留一个标签页
    • 标签页标题过长会自动截断
  2. 路由要求

    • 路由必须设置 name 属性
    • 路由必须设置 meta.title 属性
    • 隐藏路由(isHide='1')不会添加到标签页
  3. 持久化配置

    • 使用 pinia-plugin-persistedstate 自动保存
    • 保存路径:['tabs', 'activeTab']
    • 不保存 cachedTabs (组件缓存)
  4. 性能优化

    • 使用 keep-alive 缓存组件
    • 标签页列表使用 Set 优化查找
    • 懒加载图标组件

与 hzhub-admin 的差异

保留的功能

  • 标签页自动添加/关闭
  • 标签页固定/取消固定
  • 批量关闭操作
  • 标签页持久化
  • 全屏切换
  • 标签页图标显示

简化的功能

  • 拖拽排序(暂未实现)
  • 滚轮滚动(暂未实现)
  • 中键关闭(暂未实现)
  • 右键菜单(暂未实现)
  • 多种标签页样式plain/brisk/card
  • 国际化标题切换

新增的功能

  • 简化的工具栏设计
  • Element Plus 原生样式
  • 更简洁的代码结构

后续优化建议

  1. 交互增强

    • 添加右键菜单功能
    • 支持拖拽排序标签页
    • 支持鼠标滚轮横向滚动
    • 支持中键点击关闭
  2. 样式定制

    • 提供多种标签页样式chrome/card/plain
    • 支持自定义标签页主题色
    • 标签页宽度自适应
  3. 功能扩展

    • 标签页分组功能
    • 标签页搜索功能
    • 最近访问的标签页历史
    • 标签页快捷键操作
  4. 性能优化

    • 虚拟滚动优化大量标签页
    • 标签页懒加载优化
    • 组件缓存策略优化

测试建议

功能测试

  1. 标签页管理

    • 切换路由自动添加标签页
    • 关闭标签页后自动切换到相邻标签页
    • 固定标签页不可关闭
    • 刷新后标签页状态保持
  2. 批量操作

    • 关闭其他标签页
    • 关闭右侧标签页
    • 关闭所有标签页
  3. 全屏功能

    • 点击全屏按钮进入全屏模式
    • 再次点击退出全屏模式

兼容性测试

  • Chrome、Firefox、Safari 浏览器测试
  • 响应式布局测试(桌面端、平板)
  • 标签页滚动测试(超过 10 个标签页)
  • 固定标签页与普通标签页混排测试