# 标签页功能说明

## 功能概述

已将 `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

```typescript
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

```typescript
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 组件

```vue
<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>
```

#### 布局集成

```vue
<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` 属性：

```typescript
{
  path: '/dashboard',
  name: 'dashboard',
  meta: {
    title: '工作台',
    icon: 'Odometer',
    affix: true, // 固定标签页
  },
}
```

### 隐藏标签页

在路由配置中添加 `meta.isHide` 属性：

```typescript
{
  path: '/profile',
  name: 'profile',
  meta: {
    title: '个人中心',
    isHide: '1', // 不显示在标签页中
  },
}
```

### 禁用缓存

在路由配置中添加 `meta.isKeepAlive` 属性：

```typescript
{
  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 个标签页）
- 固定标签页与普通标签页混排测试