index.vue 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. <script setup lang="ts">
  2. import {
  3. h,
  4. ref,
  5. unref,
  6. reactive,
  7. computed,
  8. onMounted,
  9. watchEffect,
  10. onBeforeMount,
  11. defineComponent,
  12. getCurrentInstance
  13. } from "vue";
  14. import { setType } from "./types";
  15. import { useI18n } from "vue-i18n";
  16. import { routerArrays } from "./types";
  17. import { emitter } from "/@/utils/mitt";
  18. import { useEventListener } from "@vueuse/core";
  19. import { storageLocal } from "/@/utils/storage";
  20. import { useAppStoreHook } from "/@/store/modules/app";
  21. import fullScreen from "/@/assets/svg/full_screen.svg";
  22. import exitScreen from "/@/assets/svg/exit_screen.svg";
  23. import { useSettingStoreHook } from "/@/store/modules/settings";
  24. import navbar from "./components/navbar.vue";
  25. import tag from "./components/tag/index.vue";
  26. import appMain from "./components/appMain.vue";
  27. import setting from "./components/setting/index.vue";
  28. import Vertical from "./components/sidebar/vertical.vue";
  29. import Horizontal from "./components/sidebar/horizontal.vue";
  30. const pureSetting = useSettingStoreHook();
  31. const instance =
  32. getCurrentInstance().appContext.app.config.globalProperties.$storage;
  33. const hiddenSideBar = ref(
  34. getCurrentInstance().appContext.config.globalProperties.$config?.HiddenSideBar
  35. );
  36. const layout = computed(() => {
  37. if (!instance.layout) {
  38. // eslint-disable-next-line vue/no-side-effects-in-computed-properties
  39. instance.layout = { layout: "vertical-dark" };
  40. }
  41. if (!instance.routesInStorage || instance.routesInStorage.length === 0) {
  42. // eslint-disable-next-line vue/no-side-effects-in-computed-properties
  43. instance.routesInStorage = routerArrays;
  44. }
  45. if (!instance.locale) {
  46. // eslint-disable-next-line
  47. instance.locale = { locale: "zh" };
  48. useI18n().locale.value = "zh";
  49. }
  50. return instance?.layout.layout;
  51. });
  52. const set: setType = reactive({
  53. sidebar: computed(() => {
  54. return useAppStoreHook().sidebar;
  55. }),
  56. device: computed(() => {
  57. return useAppStoreHook().device;
  58. }),
  59. fixedHeader: computed(() => {
  60. return pureSetting.fixedHeader;
  61. }),
  62. classes: computed(() => {
  63. return {
  64. hideSidebar: !set.sidebar.opened,
  65. openSidebar: set.sidebar.opened,
  66. withoutAnimation: set.sidebar.withoutAnimation,
  67. mobile: set.device === "mobile"
  68. };
  69. })
  70. });
  71. const handleClickOutside = (params: boolean) => {
  72. useAppStoreHook().closeSideBar({ withoutAnimation: params });
  73. };
  74. function setTheme(layoutModel: string) {
  75. let { layout } = storageLocal.getItem("responsive-layout");
  76. let theme = layout.match(/-(.*)/)[1];
  77. window.document.body.setAttribute("data-layout", layoutModel);
  78. window.document.body.setAttribute("data-theme", theme);
  79. instance.layout = { layout: `${layoutModel}-${theme}` };
  80. }
  81. // 监听容器
  82. emitter.on("resize", ({ detail }) => {
  83. let { width } = detail;
  84. width <= 670 ? setTheme("vertical") : setTheme(useAppStoreHook().layout);
  85. });
  86. watchEffect(() => {
  87. if (set.device === "mobile" && !set.sidebar.opened) {
  88. handleClickOutside(false);
  89. }
  90. });
  91. const $_isMobile = () => {
  92. const rect = document.body.getBoundingClientRect();
  93. return rect.width - 1 < 992;
  94. };
  95. const $_resizeHandler = () => {
  96. if (!document.hidden) {
  97. const isMobile = $_isMobile();
  98. useAppStoreHook().toggleDevice(isMobile ? "mobile" : "desktop");
  99. if (isMobile) {
  100. handleClickOutside(true);
  101. }
  102. }
  103. };
  104. function onFullScreen() {
  105. unref(hiddenSideBar)
  106. ? (hiddenSideBar.value = false)
  107. : (hiddenSideBar.value = true);
  108. }
  109. onMounted(() => {
  110. const isMobile = $_isMobile();
  111. if (isMobile) {
  112. useAppStoreHook().toggleDevice("mobile");
  113. handleClickOutside(true);
  114. }
  115. });
  116. onBeforeMount(() => {
  117. useEventListener("resize", $_resizeHandler);
  118. });
  119. const layoutHeader = defineComponent({
  120. render() {
  121. return h(
  122. "div",
  123. { class: { "fixed-header": set.fixedHeader } },
  124. {
  125. default: () => [
  126. !hiddenSideBar.value && layout.value.includes("vertical")
  127. ? h(navbar)
  128. : h("div"),
  129. !hiddenSideBar.value && layout.value.includes("horizontal")
  130. ? h(Horizontal)
  131. : h("div"),
  132. h(
  133. tag,
  134. {},
  135. {
  136. default: () => [
  137. h(
  138. "span",
  139. { onClick: onFullScreen },
  140. {
  141. default: () => [
  142. !hiddenSideBar.value ? h(fullScreen) : h(exitScreen)
  143. ]
  144. }
  145. )
  146. ]
  147. }
  148. )
  149. ]
  150. }
  151. );
  152. }
  153. });
  154. </script>
  155. <template>
  156. <div :class="['app-wrapper', set.classes]" v-resize>
  157. <div
  158. v-show="
  159. set.device === 'mobile' &&
  160. set.sidebar.opened &&
  161. layout.includes('vertical')
  162. "
  163. class="drawer-bg"
  164. @click="handleClickOutside(false)"
  165. />
  166. <Vertical v-show="!hiddenSideBar && layout.includes('vertical')" />
  167. <div :class="['main-container', hiddenSideBar ? 'main-hidden' : '']">
  168. <div v-if="set.fixedHeader">
  169. <layout-header />
  170. <!-- 主体内容 -->
  171. <app-main :fixed-header="set.fixedHeader" />
  172. </div>
  173. <el-scrollbar v-else>
  174. <el-backtop target=".main-container .el-scrollbar__wrap"></el-backtop>
  175. <layout-header />
  176. <!-- 主体内容 -->
  177. <app-main :fixed-header="set.fixedHeader" />
  178. </el-scrollbar>
  179. </div>
  180. <!-- 系统设置 -->
  181. <setting />
  182. </div>
  183. </template>
  184. <style lang="scss" scoped>
  185. @mixin clearfix {
  186. &::after {
  187. content: "";
  188. display: table;
  189. clear: both;
  190. }
  191. }
  192. .app-wrapper {
  193. @include clearfix;
  194. position: relative;
  195. height: 100%;
  196. width: 100%;
  197. &.mobile.openSidebar {
  198. position: fixed;
  199. top: 0;
  200. }
  201. }
  202. .main-hidden {
  203. margin-left: 0 !important;
  204. }
  205. .drawer-bg {
  206. background: #000;
  207. opacity: 0.3;
  208. width: 100%;
  209. top: 0;
  210. height: 100%;
  211. position: absolute;
  212. z-index: 999;
  213. }
  214. .re-screen {
  215. margin-top: 12px;
  216. }
  217. </style>