index.vue 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. <script setup lang="ts">
  2. import { useI18n } from "vue-i18n";
  3. import LayFrame from "../lay-frame/index.vue";
  4. import LayFooter from "../lay-footer/index.vue";
  5. import { useTags } from "@/layout/hooks/useTag";
  6. import { useGlobal, isNumber } from "@pureadmin/utils";
  7. import BackTopIcon from "@/assets/svg/back_top.svg?component";
  8. import { h, computed, Transition, defineComponent } from "vue";
  9. import { usePermissionStoreHook } from "@/store/modules/permission";
  10. const props = defineProps({
  11. fixedHeader: Boolean
  12. });
  13. const { t } = useI18n();
  14. const { showModel } = useTags();
  15. const { $storage, $config } = useGlobal<GlobalPropertiesApi>();
  16. const isKeepAlive = computed(() => {
  17. return $config?.KeepAlive;
  18. });
  19. const transitions = computed(() => {
  20. return route => {
  21. return route.meta.transition;
  22. };
  23. });
  24. const hideTabs = computed(() => {
  25. return $storage?.configure.hideTabs;
  26. });
  27. const hideFooter = computed(() => {
  28. return $storage?.configure.hideFooter;
  29. });
  30. const stretch = computed(() => {
  31. return $storage?.configure.stretch;
  32. });
  33. const layout = computed(() => {
  34. return $storage?.layout.layout === "vertical";
  35. });
  36. const getMainWidth = computed(() => {
  37. return isNumber(stretch.value)
  38. ? stretch.value + "px"
  39. : stretch.value
  40. ? "1440px"
  41. : "100%";
  42. });
  43. const getSectionStyle = computed(() => {
  44. return [
  45. hideTabs.value && layout ? "padding-top: 48px;" : "",
  46. !hideTabs.value && layout
  47. ? showModel.value == "chrome"
  48. ? "padding-top: 85px;"
  49. : "padding-top: 81px;"
  50. : "",
  51. hideTabs.value && !layout.value ? "padding-top: 48px;" : "",
  52. !hideTabs.value && !layout.value
  53. ? showModel.value == "chrome"
  54. ? "padding-top: 85px;"
  55. : "padding-top: 81px;"
  56. : "",
  57. props.fixedHeader
  58. ? ""
  59. : `padding-top: 0;${
  60. hideTabs.value
  61. ? "min-height: calc(100vh - 48px);"
  62. : "min-height: calc(100vh - 86px);"
  63. }`
  64. ];
  65. });
  66. const transitionMain = defineComponent({
  67. props: {
  68. route: {
  69. type: undefined,
  70. required: true
  71. }
  72. },
  73. render() {
  74. const transitionName =
  75. transitions.value(this.route)?.name || "fade-transform";
  76. const enterTransition = transitions.value(this.route)?.enterTransition;
  77. const leaveTransition = transitions.value(this.route)?.leaveTransition;
  78. return h(
  79. Transition,
  80. {
  81. name: enterTransition ? "pure-classes-transition" : transitionName,
  82. enterActiveClass: enterTransition
  83. ? `animate__animated ${enterTransition}`
  84. : undefined,
  85. leaveActiveClass: leaveTransition
  86. ? `animate__animated ${leaveTransition}`
  87. : undefined,
  88. mode: "out-in",
  89. appear: true
  90. },
  91. {
  92. default: () => [this.$slots.default()]
  93. }
  94. );
  95. }
  96. });
  97. </script>
  98. <template>
  99. <section
  100. :class="[fixedHeader ? 'app-main' : 'app-main-nofixed-header']"
  101. :style="getSectionStyle"
  102. >
  103. <router-view>
  104. <template #default="{ Component, route }">
  105. <LayFrame :currComp="Component" :currRoute="route">
  106. <template #default="{ Comp, fullPath, frameInfo }">
  107. <el-scrollbar
  108. v-if="fixedHeader"
  109. :wrap-style="{
  110. display: 'flex',
  111. 'flex-wrap': 'wrap',
  112. 'max-width': getMainWidth,
  113. margin: '0 auto',
  114. transition: 'all 300ms cubic-bezier(0.4, 0, 0.2, 1)'
  115. }"
  116. :view-style="{
  117. display: 'flex',
  118. flex: 'auto',
  119. overflow: 'hidden',
  120. 'flex-direction': 'column'
  121. }"
  122. >
  123. <el-backtop
  124. :title="t('buttons.pureBackTop')"
  125. target=".app-main .el-scrollbar__wrap"
  126. >
  127. <BackTopIcon />
  128. </el-backtop>
  129. <div class="grow">
  130. <transitionMain :route="route">
  131. <keep-alive
  132. v-if="isKeepAlive"
  133. :include="usePermissionStoreHook().cachePageList"
  134. >
  135. <component
  136. :is="Comp"
  137. :key="fullPath"
  138. :frameInfo="frameInfo"
  139. class="main-content"
  140. />
  141. </keep-alive>
  142. <component
  143. :is="Comp"
  144. v-else
  145. :key="fullPath"
  146. :frameInfo="frameInfo"
  147. class="main-content"
  148. />
  149. </transitionMain>
  150. </div>
  151. <LayFooter v-if="!hideFooter" />
  152. </el-scrollbar>
  153. <div v-else class="grow">
  154. <transitionMain :route="route">
  155. <keep-alive
  156. v-if="isKeepAlive"
  157. :include="usePermissionStoreHook().cachePageList"
  158. >
  159. <component
  160. :is="Comp"
  161. :key="fullPath"
  162. :frameInfo="frameInfo"
  163. class="main-content"
  164. />
  165. </keep-alive>
  166. <component
  167. :is="Comp"
  168. v-else
  169. :key="fullPath"
  170. :frameInfo="frameInfo"
  171. class="main-content"
  172. />
  173. </transitionMain>
  174. </div>
  175. </template>
  176. </LayFrame>
  177. </template>
  178. </router-view>
  179. <!-- 页脚 -->
  180. <LayFooter v-if="!hideFooter && !fixedHeader" />
  181. </section>
  182. </template>
  183. <style scoped>
  184. .app-main {
  185. position: relative;
  186. width: 100%;
  187. height: 100vh;
  188. overflow-x: hidden;
  189. }
  190. .app-main-nofixed-header {
  191. position: relative;
  192. display: flex;
  193. flex-direction: column;
  194. width: 100%;
  195. }
  196. .main-content {
  197. /* margin: 24px; */
  198. }
  199. </style>