module-submenu.vue 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. <template>
  2. <div class="app-container submenu-container">
  3. <div class="page-header">
  4. <h2>{{ moduleTitle }}</h2>
  5. <p>请选择具体功能</p>
  6. </div>
  7. <div class="submenu-grid">
  8. <div
  9. v-for="item in menuItems"
  10. :key="item.path"
  11. class="submenu-card"
  12. @click="handleItemClick(item)"
  13. >
  14. <div class="submenu-icon">
  15. <svg-icon v-if="item.meta && item.meta.icon" :icon-class="item.meta.icon" class="icon" />
  16. <i v-else class="el-icon-document icon"></i>
  17. </div>
  18. <div class="submenu-title">{{ item.meta ? item.meta.title : item.name }}</div>
  19. </div>
  20. </div>
  21. </div>
  22. </template>
  23. <script>
  24. import { mapGetters } from 'vuex'
  25. export default {
  26. name: 'ModuleSubmenu',
  27. data() {
  28. return {
  29. moduleTitle: '',
  30. menuItems: []
  31. }
  32. },
  33. computed: {
  34. ...mapGetters(['sidebarRouters'])
  35. },
  36. created() {
  37. this.loadMenuItems()
  38. },
  39. watch: {
  40. '$route.query': {
  41. handler() {
  42. this.loadMenuItems()
  43. },
  44. deep: true
  45. }
  46. },
  47. methods: {
  48. loadMenuItems() {
  49. const { modulePath, moduleTitle } = this.$route.query
  50. this.moduleTitle = moduleTitle || '功能菜单'
  51. // 查找对应的菜单项
  52. this.menuItems = this.findMenuItems(modulePath)
  53. },
  54. findMenuItems(modulePath) {
  55. // 从系统菜单查找
  56. if (this.sidebarRouters && this.sidebarRouters.length > 0) {
  57. for (const route of this.sidebarRouters) {
  58. if (route.path === modulePath && route.children) {
  59. // 返回系统模块的子菜单,确保路径完整
  60. return route.children
  61. .filter(child => !child.hidden)
  62. .map(child => {
  63. // 如果路径是相对路径,需要拼接父路径
  64. const fullPath = child.path.startsWith('/') ? child.path : `${route.path}/${child.path}`
  65. return {
  66. ...child,
  67. path: fullPath
  68. }
  69. })
  70. }
  71. }
  72. }
  73. return []
  74. },
  75. handleItemClick(item) {
  76. this.$router.push(item.path)
  77. }
  78. }
  79. }
  80. </script>
  81. <style scoped lang="scss">
  82. .submenu-container {
  83. .page-header {
  84. text-align: center;
  85. margin-bottom: 48px;
  86. padding: 32px 24px;
  87. background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  88. border-radius: 16px;
  89. box-shadow: 0 8px 32px 0 rgba(102, 126, 234, 0.2);
  90. h2 {
  91. font-size: 32px;
  92. font-weight: 700;
  93. color: #ffffff;
  94. margin-bottom: 12px;
  95. text-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  96. }
  97. p {
  98. font-size: 16px;
  99. color: rgba(255, 255, 255, 0.9);
  100. font-weight: 300;
  101. }
  102. }
  103. .submenu-grid {
  104. display: grid;
  105. grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  106. gap: 24px;
  107. .submenu-card {
  108. background: #ffffff;
  109. border-radius: 12px;
  110. padding: 32px 24px;
  111. text-align: center;
  112. cursor: pointer;
  113. transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  114. border: 2px solid transparent;
  115. box-shadow: 0 4px 12px 0 rgba(0, 0, 0, 0.08);
  116. position: relative;
  117. overflow: hidden;
  118. &::before {
  119. content: '';
  120. position: absolute;
  121. top: 0;
  122. left: 0;
  123. right: 0;
  124. height: 4px;
  125. background: linear-gradient(90deg, #667eea 0%, #764ba2 100%);
  126. transform: scaleX(0);
  127. transition: transform 0.3s ease;
  128. }
  129. &:hover {
  130. background: #ffffff;
  131. border-color: transparent;
  132. transform: translateY(-8px);
  133. box-shadow: 0 12px 32px 0 rgba(102, 126, 234, 0.25);
  134. &::before {
  135. transform: scaleX(1);
  136. }
  137. .submenu-icon {
  138. background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  139. transform: scale(1.1) rotate(5deg);
  140. box-shadow: 0 8px 24px rgba(102, 126, 234, 0.3);
  141. ::v-deep(.svg-icon),
  142. .icon {
  143. color: #ffffff;
  144. }
  145. }
  146. .submenu-title {
  147. color: #667eea;
  148. }
  149. }
  150. .submenu-icon {
  151. display: inline-flex;
  152. align-items: center;
  153. justify-content: center;
  154. width: 72px;
  155. height: 72px;
  156. border-radius: 16px;
  157. background: linear-gradient(135deg, #f5f7fa 0%, #e4e7ed 100%);
  158. margin: 0 auto 20px;
  159. transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  160. box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
  161. ::v-deep(.svg-icon) {
  162. font-size: 36px;
  163. color: #606266;
  164. transition: color 0.3s ease;
  165. }
  166. .icon {
  167. font-size: 36px;
  168. color: #606266;
  169. transition: color 0.3s ease;
  170. }
  171. }
  172. .submenu-title {
  173. font-size: 17px;
  174. font-weight: 600;
  175. color: #303133;
  176. transition: color 0.3s ease;
  177. line-height: 1.5;
  178. }
  179. }
  180. }
  181. // 响应式布局
  182. @media (max-width: 1200px) {
  183. .submenu-grid {
  184. grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  185. gap: 20px;
  186. }
  187. }
  188. @media (max-width: 768px) {
  189. .page-header {
  190. margin-bottom: 32px;
  191. padding: 24px 16px;
  192. h2 {
  193. font-size: 24px;
  194. }
  195. p {
  196. font-size: 14px;
  197. }
  198. }
  199. .submenu-grid {
  200. grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
  201. gap: 16px;
  202. .submenu-card {
  203. padding: 28px 20px;
  204. .submenu-icon {
  205. width: 60px;
  206. height: 60px;
  207. margin-bottom: 16px;
  208. ::v-deep(.svg-icon),
  209. .icon {
  210. font-size: 30px;
  211. }
  212. }
  213. .submenu-title {
  214. font-size: 15px;
  215. }
  216. }
  217. }
  218. }
  219. }
  220. </style>