index.vue 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. <template>
  2. <main-framework
  3. :class="`main-theme main-theme--${theme}`"
  4. :hide-footer="hideFooter"
  5. :hide-aside-switch="hideAsideSwitch"
  6. :layout="usingLayout"
  7. :with-tabs="withTabs"
  8. >
  9. <template #name="{isCollapse}">
  10. <slot name="collapse" v-if="isCollapse">
  11. <span style="margin-left: 8px;">{{name?.[0]}}</span>
  12. </slot>
  13. <slot name="expand" v-else>
  14. <span style="margin-left: 8px;">{{name}}</span>
  15. </slot>
  16. <slot name="name" :is-collapse="isCollapse"></slot>
  17. </template>
  18. <template #nav="{isCollapse}">
  19. <slot name="nav">
  20. <cip-main-nav :nav-menu="dynamicMenu"
  21. :theme="theme"
  22. :privileges="privileges"
  23. :mode="navMode"
  24. :isCollapse="isCollapse"
  25. :ellipsis="true"
  26. :badgeMap="badgeMap"
  27. @triggerGetBadge="consumptionBadgeFn"/>
  28. </slot>
  29. </template>
  30. <template #headerNav>
  31. <!-- 平铺模式的菜单[注:仅显示一层]-->
  32. <cip-main-nav :nav-menu="menu"
  33. v-model:activeMenu="activeMenu"
  34. :privileges="privileges"
  35. mode="horizontal"
  36. :ellipsis="true"
  37. :top-menu-only="true"
  38. :badgeMap="badgeMap"
  39. @triggerGetBadge="consumptionBadgeFn"/>
  40. </template>
  41. <template #tabs>
  42. <cip-tabs
  43. ref="tabsRef"
  44. :menu="menu"
  45. :menu-title-map="menuPathMap"
  46. :home-view="homeView"
  47. :with-tabs="withTabs"
  48. v-model:cache="cache"
  49. />
  50. </template>
  51. <template #breadcrumb>
  52. <cip-main-breadcrumb />
  53. </template>
  54. <template #header>
  55. <header-bar>
  56. <template #header-plugin><slot name="header-plugin" /></template>
  57. <template #header-user><slot name="header-user" /></template>
  58. <template v-if="$slots.dropdown" #dropdown><slot name="dropdown" /></template>
  59. <template v-if="$slots['pre-dropdown']" #pre-dropdown><slot name="pre-dropdown" /></template>
  60. </header-bar>
  61. </template>
  62. <cip-router-view :viewKey="viewKey" :cacheList="cache"/>
  63. <template #footer>
  64. <slot name="footer"></slot>
  65. </template>
  66. </main-framework>
  67. </template>
  68. <script>
  69. import { computed, ref, watch, provide, reactive, onUnmounted } from 'vue'
  70. import { useCipConfig } from '../hooks/use-cip-config'
  71. import MainFramework from './framework/framework'
  72. import CipMainNav from './cip-main-nav'
  73. import CipMainBreadcrumb from './cip-main-breadcrumb'
  74. import HeaderBar from './header-bar'
  75. import CipTabs from './cip-main-tabs'
  76. import CipRouterView from './cip-router-view'
  77. import { useRoute } from 'vue-router'
  78. import { useBadge, useMenuTitle } from './main-hooks'
  79. import { getFullPathWithoutHash } from './helper'
  80. export default {
  81. name: 'Main',
  82. components: { MainFramework, CipMainNav, HeaderBar, CipMainBreadcrumb, CipTabs, CipRouterView },
  83. props: {
  84. logo: String, // 平台LOGO
  85. platformName: String, // 平台名称
  86. navMenu: Array, // 导航菜单
  87. privileges: Array, // 权限
  88. hideFooter: Boolean, // 是否隐藏footer
  89. hideAsideSwitch: Boolean, // 是否隐藏手风琴折叠开关
  90. theme: {
  91. type: String,
  92. default: 'standard' // 默认使用数据中台的主题
  93. // validator: (value) => {
  94. // return ['data-center', 'light', 'dark'].includes(value)
  95. // }
  96. }, // 主题
  97. layout: {
  98. type: String,
  99. default: 'left-2',
  100. validator: (value) => {
  101. return ['left', 'left-2', 'top', 'top-left', 'hide'].includes(value)
  102. }
  103. }, // 布局
  104. withTabs: Boolean, // 是否使用tabs)
  105. homeView: Object, // 首页配置(开启tabs时建议开启)
  106. badgeInterval: Number, // 获取badge的时间间隔 单位min(分钟)
  107. noViewKey: { type: Boolean, default: undefined }
  108. },
  109. setup (props) {
  110. const cipConfig = useCipConfig()
  111. const route = useRoute()
  112. const activeMenu = ref([])
  113. const cache = ref([])
  114. const { menuNameMap, menuPathMap } = useMenuTitle()
  115. // 菜单
  116. const menu = computed(() => {
  117. return props.navMenu
  118. })
  119. const layoutHide = ref(false)
  120. const setFrameHide = (val) => {
  121. layoutHide.value = val
  122. }
  123. onUnmounted(() => {
  124. console.log('Main Unmounted')
  125. })
  126. const usingLayout = computed(() => {
  127. return layoutHide.value ? 'hide' : props.layout
  128. })
  129. const dynamicMenu = computed(() => {
  130. if (usingLayout.value !== 'top-left') return menu.value
  131. if (!activeMenu.value) return []
  132. // 明确标记没有children时返回当前menu
  133. if ((activeMenu.value.children || []).length === 0) return [activeMenu.value]
  134. // 传入当前激活路由top menu的children
  135. return activeMenu.value.children
  136. })
  137. const oneMinute = 60 * 1000
  138. const { badgeMap, collectBadgeFn, consumptionBadgeFn } = useBadge(props.badgeInterval * oneMinute)
  139. watch(menu, (val) => {
  140. collectBadgeFn(val, { key: 'name', fnKey: 'getBadge' })
  141. }, { immediate: true })
  142. // 平台名称
  143. const name = computed(() => {
  144. return props.platformName ?? process.env.VUE_APP_PLATFORM_NAME
  145. })
  146. // 菜单模式
  147. const navMode = computed(() => {
  148. return props.layout === 'top' ? 'horizontal' : 'vertical'
  149. })
  150. // 兼容KeepAlivePages组件的运行
  151. const viewKey = computed(() => {
  152. if (props.noViewKey) return 'viewKey'
  153. const routeMatch = route.matched
  154. const length = routeMatch.length
  155. const cacheName = length > 1 ? routeMatch[routeMatch.length - 2].name : undefined
  156. if (cacheName?.indexOf('_cache') > -1) {
  157. return cacheName
  158. }
  159. return cipConfig.withQuery === false ? route.path : getFullPathWithoutHash(route.fullPath)
  160. })
  161. const tabsRef = ref()
  162. const closeTab = () => {
  163. const fullPath = getFullPathWithoutHash(route.fullPath)
  164. // eslint-disable-next-line no-unused-expressions
  165. tabsRef.value?.removeTab(fullPath)
  166. }
  167. const handlerPathChange = (fullPath) => {
  168. fullPath = getFullPathWithoutHash(fullPath)
  169. // eslint-disable-next-line no-unused-expressions
  170. tabsRef.value?.handlerPathChange(fullPath)
  171. }
  172. provide('closeTab', closeTab)
  173. provide('pathChange', handlerPathChange)
  174. provide('cip-menu', reactive({
  175. menuNameMap,
  176. navMenu: menu
  177. }))
  178. provide('setFrameHide', setFrameHide)
  179. const setChangeSign = () => {
  180. // const fullPath = getFullPathWithoutHash(route.fullPath)
  181. }
  182. provide('setChangeSign', setChangeSign)
  183. return {
  184. cache,
  185. menu,
  186. name,
  187. menuNameMap,
  188. menuPathMap,
  189. navMode,
  190. dynamicMenu,
  191. activeMenu,
  192. viewKey,
  193. badgeMap,
  194. consumptionBadgeFn,
  195. tabsRef,
  196. usingLayout
  197. }
  198. }
  199. }
  200. </script>
  201. <style lang="less">
  202. @import './theme';
  203. </style>