index.vue 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. <!-- layout/components/Sidebar/index.vue -->
  2. <template>
  3. <div class="sidebar-container" :class="{ collapsed: isCollapse }">
  4. <div class="menu-list">
  5. <div
  6. v-for="item in menuList"
  7. :key="item.path"
  8. :class="['menu-item', { active: isActive(item.path) }]"
  9. @click="handleMenuClick(item)"
  10. >
  11. <!-- 使用原本的 svg 图标 -->
  12. <svg-icon
  13. v-if="item.meta?.icon"
  14. :icon-class="item.meta.icon"
  15. class="menu-icon"
  16. />
  17. <span class="menu-text">{{ item.meta?.title }}</span>
  18. </div>
  19. </div>
  20. <div class="collapse-btn" @click="toggleCollapse">
  21. <span class="btn-text">{{ isCollapse ? "▶" : "◀" }}</span>
  22. </div>
  23. </div>
  24. </template>
  25. <script>
  26. import { computed } from "vue";
  27. import { useRoute, useRouter } from "vue-router";
  28. import useAppStore from "@/store/modules/app";
  29. import usePermissionStore from "@/store/modules/permission";
  30. export default {
  31. name: "Sidebar",
  32. props: {
  33. topMenuKey: {
  34. type: String,
  35. default: "",
  36. },
  37. },
  38. setup(props) {
  39. const route = useRoute();
  40. const router = useRouter();
  41. const appStore = useAppStore();
  42. const permissionStore = usePermissionStore();
  43. const isCollapse = computed(() => appStore.sidebar.isCollapse);
  44. const menuList = computed(() => {
  45. const routes = permissionStore.sidebarRouters || [];
  46. if (!routes.length) return [];
  47. if (props.topMenuKey) {
  48. const current = routes.find((item) => item.path === props.topMenuKey);
  49. if (current && current.children) {
  50. return current.children.filter((child) => !child.hidden);
  51. }
  52. }
  53. const firstMenu = routes[0];
  54. if (firstMenu && firstMenu.children) {
  55. return firstMenu.children.filter((child) => !child.hidden);
  56. }
  57. return [];
  58. });
  59. const isActive = (path) => {
  60. return route.path.includes(path);
  61. };
  62. const handleMenuClick = (item) => {
  63. let fullPath = item.path;
  64. if (!fullPath.startsWith("/") && props.topMenuKey) {
  65. fullPath = props.topMenuKey + "/" + fullPath;
  66. }
  67. router.push(fullPath);
  68. };
  69. const toggleCollapse = () => {
  70. appStore.sidebar.isCollapse = !appStore.sidebar.isCollapse;
  71. };
  72. return {
  73. menuList,
  74. isCollapse,
  75. isActive,
  76. handleMenuClick,
  77. toggleCollapse,
  78. };
  79. },
  80. };
  81. </script>
  82. <style scoped>
  83. .sidebar-container {
  84. width: 210px;
  85. background-color: #304156;
  86. height: 100%;
  87. transition: width 0.2s;
  88. display: flex;
  89. flex-direction: column;
  90. overflow: hidden;
  91. }
  92. .sidebar-container.collapsed {
  93. width: 64px;
  94. }
  95. .menu-list {
  96. flex: 1;
  97. overflow-y: auto;
  98. padding: 10px 0;
  99. }
  100. .menu-item {
  101. padding: 0 20px;
  102. height: 44px;
  103. line-height: 44px;
  104. color: #bfcbd9;
  105. cursor: pointer;
  106. white-space: nowrap;
  107. display: flex;
  108. align-items: center;
  109. gap: 12px;
  110. }
  111. /* 收起时的样式 */
  112. .sidebar-container.collapsed .menu-item {
  113. justify-content: center;
  114. padding: 0;
  115. }
  116. .menu-item:hover {
  117. background-color: #263445;
  118. color: #fff;
  119. }
  120. .menu-item.active {
  121. background-color: #409eff;
  122. color: #fff;
  123. }
  124. /* 图标样式 */
  125. .menu-icon {
  126. width: 20px;
  127. height: 20px;
  128. flex-shrink: 0;
  129. }
  130. /* 文字样式 */
  131. .menu-text {
  132. font-size: 14px;
  133. }
  134. /* 收起时隐藏文字 */
  135. .sidebar-container.collapsed .menu-text {
  136. display: none;
  137. }
  138. /* 收起时图标居中 */
  139. .sidebar-container.collapsed .menu-icon {
  140. margin: 0;
  141. }
  142. .collapse-btn {
  143. height: 44px;
  144. line-height: 44px;
  145. text-align: center;
  146. color: #bfcbd9;
  147. cursor: pointer;
  148. border-top: 1px solid #1f2d3d;
  149. }
  150. .collapse-btn:hover {
  151. background-color: #263445;
  152. color: #fff;
  153. }
  154. .btn-text {
  155. font-size: 16px;
  156. }
  157. </style>