UserLayout.vue 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. <template>
  2. <div class="user-layout">
  3. <el-container>
  4. <el-header class="header">
  5. <div class="header-left" @click="router.push('/booking')">
  6. <img :src="metaStore.logo" alt="logo" class="logo">
  7. <h2 class="title">宠物服务管理系统</h2>
  8. </div>
  9. <el-menu
  10. :default-active="activeIndex"
  11. mode="horizontal"
  12. router
  13. class="nav-menu"
  14. >
  15. <el-menu-item :index="menu.path" v-for="menu in navMenus" :key="menu.path">
  16. <el-icon><component :is="menu.meta?.icon" /></el-icon>
  17. <template #title>{{ menu.meta?.title }}</template>
  18. </el-menu-item>
  19. <el-menu-item v-if="isAdmin" index="/admin">
  20. <el-icon><Tools /></el-icon>
  21. <template #title>后台管理</template>
  22. </el-menu-item>
  23. </el-menu>
  24. <div class="header-right">
  25. <template v-if="login">
  26. <el-dropdown placement="bottom">
  27. <el-button class="user-btn" text>
  28. <el-icon class="user-avatar"><UserFilled /></el-icon>
  29. <span class="username">{{ loginUserStore.loginUser?.user?.name }}</span>
  30. </el-button>
  31. <template #dropdown>
  32. <el-dropdown-menu>
  33. <el-dropdown-item @click="router.push('/profile')">个人信息</el-dropdown-item>
  34. <el-dropdown-item @click="router.push('/orders')">我的订单</el-dropdown-item>
  35. <el-dropdown-item @click="router.push('/pets')">宠物档案</el-dropdown-item>
  36. <el-dropdown-item divided @click="logoutHandler">退出登录</el-dropdown-item>
  37. </el-dropdown-menu>
  38. </template>
  39. </el-dropdown>
  40. </template>
  41. <template v-else>
  42. <el-button type="primary" size="small" @click="router.push('/login')">登录</el-button>
  43. <el-button size="small" @click="router.push('/login')">注册</el-button>
  44. </template>
  45. </div>
  46. </el-header>
  47. <el-main>
  48. <router-view />
  49. </el-main>
  50. </el-container>
  51. </div>
  52. </template>
  53. <script setup lang="ts">
  54. import { computed } from 'vue'
  55. import { useRoute } from 'vue-router'
  56. import { useLoginUserStore, useMetaStore } from '../store'
  57. import router, { userRoutes } from '../router'
  58. import { Tools, UserFilled } from '@element-plus/icons-vue'
  59. import { getAuthController } from '../api/auth-controller'
  60. const route = useRoute()
  61. const metaStore = useMetaStore()
  62. const loginUserStore = useLoginUserStore()
  63. const login = computed(() => loginUserStore.loginUser.isLogin)
  64. const isAdmin = computed(() => loginUserStore.loginUser.user?.role === 'admin')
  65. const activeIndex = computed(() => route.path)
  66. const navMenus = computed(() => {
  67. return (userRoutes[0].children || []).filter(m => m.meta?.icon)
  68. })
  69. const logoutHandler = async () => {
  70. try {
  71. await getAuthController().logout()
  72. } catch {
  73. // 忽略服务端登出错误
  74. }
  75. loginUserStore.logoutUser()
  76. router.push('/login')
  77. }
  78. </script>
  79. <style scoped>
  80. .user-layout {
  81. display: flex;
  82. flex-direction: column;
  83. min-height: 100vh;
  84. }
  85. .header {
  86. display: flex;
  87. align-items: center;
  88. justify-content: space-between;
  89. padding: 0 20px;
  90. border-bottom: 1px solid #eee;
  91. }
  92. .header-left {
  93. display: flex;
  94. align-items: center;
  95. gap: 10px;
  96. cursor: pointer;
  97. }
  98. .logo {
  99. width: 40px;
  100. height: 40px;
  101. }
  102. .title {
  103. margin: 0;
  104. font-size: 20px;
  105. }
  106. .nav-menu {
  107. flex: 1;
  108. display: flex;
  109. justify-content: center;
  110. border-bottom: none;
  111. }
  112. .header-right {
  113. display: flex;
  114. align-items: center;
  115. gap: 10px;
  116. }
  117. .username {
  118. font-size: 14px;
  119. color: #606266;
  120. }
  121. .user-btn {
  122. display: flex;
  123. align-items: center;
  124. gap: 6px;
  125. cursor: pointer;
  126. transition: color 0.2s;
  127. }
  128. .user-btn:hover {
  129. color: var(--el-color-primary);
  130. }
  131. .user-avatar {
  132. font-size: 20px;
  133. color: var(--el-color-primary);
  134. }
  135. </style>