App.vue 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. <template>
  2. <router-view v-if="isLoginPage" />
  3. <el-container v-else class="app-shell">
  4. <el-aside width="232px" class="sidebar">
  5. <div class="brand">组织人事管理平台</div>
  6. <el-menu :default-active="$route.path" router class="menu">
  7. <el-menu-item v-for="item in visibleMenuItems" :key="item.index" :index="item.index">
  8. <el-icon><component :is="item.icon" /></el-icon>
  9. <span>{{ item.label }}</span>
  10. </el-menu-item>
  11. </el-menu>
  12. </el-aside>
  13. <el-container>
  14. <el-header class="topbar">
  15. <div>{{ pageTitle }}</div>
  16. <div class="topbar-actions">
  17. <el-tag type="info">{{ auth.user?.username }}</el-tag>
  18. <el-button :icon="SwitchButton" @click="logout">退出</el-button>
  19. </div>
  20. </el-header>
  21. <el-main class="main">
  22. <router-view />
  23. </el-main>
  24. </el-container>
  25. </el-container>
  26. </template>
  27. <script setup lang="ts">
  28. import { computed } from 'vue'
  29. import { useRoute, useRouter } from 'vue-router'
  30. import { useAuthStore } from './stores/auth'
  31. import { featureRoles, hasAnyRole } from './security/access'
  32. import {
  33. Briefcase,
  34. Calendar,
  35. CircleCheck,
  36. DataBoard,
  37. Download,
  38. Lock,
  39. Money,
  40. Monitor,
  41. SwitchButton,
  42. Tickets,
  43. TrendCharts,
  44. User
  45. } from '@element-plus/icons-vue'
  46. const route = useRoute()
  47. const router = useRouter()
  48. const auth = useAuthStore()
  49. const isLoginPage = computed(() => route.path === '/login')
  50. const pageTitle = computed(() => String(route.meta.title ?? '工作台'))
  51. const menuItems = [
  52. { index: '/', label: '工作台', icon: DataBoard, roles: featureRoles.dashboard },
  53. { index: '/employees', label: '员工档案', icon: User, roles: featureRoles.employees },
  54. { index: '/recruitment', label: '招聘管理', icon: Briefcase, roles: featureRoles.recruitment },
  55. { index: '/onboarding', label: '入离职', icon: CircleCheck, roles: featureRoles.onboarding },
  56. { index: '/attendance', label: '考勤请假', icon: Calendar, roles: featureRoles.attendance },
  57. { index: '/payroll', label: '薪酬工资', icon: Money, roles: featureRoles.payroll },
  58. { index: '/performance', label: '绩效管理', icon: TrendCharts, roles: featureRoles.performance },
  59. { index: '/reports', label: '报表导出', icon: Download, roles: featureRoles.reports },
  60. { index: '/security', label: '权限管理', icon: Lock, roles: featureRoles.security },
  61. { index: '/audit', label: '审计日志', icon: Tickets, roles: featureRoles.audit },
  62. { index: '/system', label: '系统信息', icon: Monitor, roles: featureRoles.system }
  63. ]
  64. const visibleMenuItems = computed(() => menuItems.filter((item) => hasAnyRole(auth.user?.roles, item.roles)))
  65. async function logout() {
  66. await auth.logout()
  67. router.push('/login')
  68. }
  69. </script>