index.vue 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. <script setup lang="ts">
  2. import {
  3. h,
  4. reactive,
  5. computed,
  6. onMounted,
  7. defineComponent,
  8. getCurrentInstance
  9. } from "vue";
  10. import { setType } from "./types";
  11. import { useI18n } from "vue-i18n";
  12. import { routerArrays } from "./types";
  13. import { emitter } from "/@/utils/mitt";
  14. import { deviceDetection } from "@pureadmin/utils";
  15. import { useAppStoreHook } from "/@/store/modules/app";
  16. import { useMultiTagsStore } from "/@/store/modules/multiTags";
  17. import { useSettingStoreHook } from "/@/store/modules/settings";
  18. import backTop from "/@/assets/svg/back_top.svg?component";
  19. import fullScreen from "/@/assets/svg/full_screen.svg?component";
  20. import exitScreen from "/@/assets/svg/exit_screen.svg?component";
  21. import navbar from "./components/navbar.vue";
  22. import tag from "./components/tag/index.vue";
  23. import appMain from "./components/appMain.vue";
  24. import setting from "./components/setting/index.vue";
  25. import Vertical from "./components/sidebar/vertical.vue";
  26. import Horizontal from "./components/sidebar/horizontal.vue";
  27. const isMobile = deviceDetection();
  28. const pureSetting = useSettingStoreHook();
  29. const instance = getCurrentInstance().appContext.app.config.globalProperties;
  30. // 清空缓存后从serverConfig.json读取默认配置并赋值到storage中
  31. const layout = computed(() => {
  32. // 路由
  33. if (
  34. useMultiTagsStore().multiTagsCache &&
  35. (!instance.$storage.tags || instance.$storage.tags.length === 0)
  36. ) {
  37. // eslint-disable-next-line vue/no-side-effects-in-computed-properties
  38. instance.$storage.tags = routerArrays;
  39. }
  40. // 国际化
  41. if (!instance.$storage.locale) {
  42. // eslint-disable-next-line
  43. instance.$storage.locale = { locale: instance.$config?.Locale ?? "zh" };
  44. useI18n().locale.value = instance.$config?.Locale ?? "zh";
  45. }
  46. // 导航
  47. if (!instance.$storage.layout) {
  48. // eslint-disable-next-line vue/no-side-effects-in-computed-properties
  49. instance.$storage.layout = {
  50. layout: instance.$config?.Layout ?? "vertical",
  51. theme: instance.$config?.Theme ?? "default",
  52. darkMode: instance.$config?.DarkMode ?? false,
  53. sidebarStatus: instance.$config?.SidebarStatus ?? true,
  54. epThemeColor: instance.$config?.EpThemeColor ?? "#409EFF"
  55. };
  56. }
  57. // 灰色模式、色弱模式、隐藏标签页
  58. if (!instance.$storage.configure) {
  59. // eslint-disable-next-line
  60. instance.$storage.configure = {
  61. grey: instance.$config?.Grey ?? false,
  62. weak: instance.$config?.Weak ?? false,
  63. hideTabs: instance.$config?.HideTabs ?? false,
  64. showLogo: instance.$config?.ShowLogo ?? true,
  65. showModel: instance.$config?.ShowModel ?? "smart",
  66. multiTagsCache: instance.$config?.MultiTagsCache ?? false
  67. };
  68. }
  69. return instance.$storage?.layout.layout;
  70. });
  71. const set: setType = reactive({
  72. sidebar: computed(() => {
  73. return useAppStoreHook().sidebar;
  74. }),
  75. device: computed(() => {
  76. return useAppStoreHook().device;
  77. }),
  78. fixedHeader: computed(() => {
  79. return pureSetting.fixedHeader;
  80. }),
  81. classes: computed(() => {
  82. return {
  83. hideSidebar: !set.sidebar.opened,
  84. openSidebar: set.sidebar.opened,
  85. withoutAnimation: set.sidebar.withoutAnimation,
  86. mobile: set.device === "mobile"
  87. };
  88. }),
  89. hideTabs: computed(() => {
  90. return instance.$storage?.configure.hideTabs;
  91. })
  92. });
  93. function setTheme(layoutModel: string) {
  94. window.document.body.setAttribute("layout", layoutModel);
  95. instance.$storage.layout = {
  96. layout: `${layoutModel}`,
  97. theme: instance.$storage.layout?.theme,
  98. darkMode: instance.$storage.layout?.darkMode,
  99. sidebarStatus: instance.$storage.layout?.sidebarStatus,
  100. epThemeColor: instance.$storage.layout?.epThemeColor
  101. };
  102. }
  103. function toggle(device: string, bool: boolean) {
  104. useAppStoreHook().toggleDevice(device);
  105. useAppStoreHook().toggleSideBar(bool, "resize");
  106. }
  107. // 判断是否可自动关闭菜单栏
  108. let isAutoCloseSidebar = true;
  109. // 监听容器
  110. emitter.on("resize", ({ detail }) => {
  111. if (isMobile) return;
  112. let { width } = detail;
  113. width <= 670 ? setTheme("vertical") : setTheme(useAppStoreHook().layout);
  114. /** width app-wrapper类容器宽度
  115. * 0 < width <= 760 隐藏侧边栏
  116. * 760 < width <= 990 折叠侧边栏
  117. * width > 990 展开侧边栏
  118. */
  119. if (width > 0 && width <= 760) {
  120. toggle("mobile", false);
  121. isAutoCloseSidebar = true;
  122. } else if (width > 760 && width <= 990) {
  123. if (isAutoCloseSidebar) {
  124. toggle("desktop", false);
  125. isAutoCloseSidebar = false;
  126. }
  127. } else if (width > 990) {
  128. if (!set.sidebar.isClickHamburger) {
  129. toggle("desktop", true);
  130. isAutoCloseSidebar = true;
  131. }
  132. }
  133. });
  134. onMounted(() => {
  135. if (isMobile) {
  136. toggle("mobile", false);
  137. }
  138. });
  139. function onFullScreen() {
  140. pureSetting.hiddenSideBar
  141. ? pureSetting.changeSetting({ key: "hiddenSideBar", value: false })
  142. : pureSetting.changeSetting({ key: "hiddenSideBar", value: true });
  143. }
  144. const layoutHeader = defineComponent({
  145. render() {
  146. return h(
  147. "div",
  148. {
  149. class: { "fixed-header": set.fixedHeader },
  150. style: [
  151. set.hideTabs && layout.value.includes("horizontal")
  152. ? "box-shadow: 0 1px 4px rgb(0 21 41 / 8%);"
  153. : ""
  154. ]
  155. },
  156. {
  157. default: () => [
  158. !pureSetting.hiddenSideBar &&
  159. (layout.value.includes("vertical") || layout.value.includes("mix"))
  160. ? h(navbar)
  161. : h("div"),
  162. !pureSetting.hiddenSideBar && layout.value.includes("horizontal")
  163. ? h(Horizontal)
  164. : h("div"),
  165. h(
  166. tag,
  167. {},
  168. {
  169. default: () => [
  170. h(
  171. "span",
  172. { onClick: onFullScreen },
  173. {
  174. default: () => [
  175. !pureSetting.hiddenSideBar ? h(fullScreen) : h(exitScreen)
  176. ]
  177. }
  178. )
  179. ]
  180. }
  181. )
  182. ]
  183. }
  184. );
  185. }
  186. });
  187. </script>
  188. <template>
  189. <div :class="['app-wrapper', set.classes]" v-resize>
  190. <div
  191. v-show="
  192. set.device === 'mobile' &&
  193. set.sidebar.opened &&
  194. layout.includes('vertical')
  195. "
  196. class="app-mask"
  197. @click="useAppStoreHook().toggleSideBar()"
  198. />
  199. <Vertical
  200. v-show="
  201. !pureSetting.hiddenSideBar &&
  202. (layout.includes('vertical') || layout.includes('mix'))
  203. "
  204. />
  205. <div
  206. :class="[
  207. 'main-container',
  208. pureSetting.hiddenSideBar ? 'main-hidden' : ''
  209. ]"
  210. >
  211. <div v-if="set.fixedHeader">
  212. <layout-header />
  213. <!-- 主体内容 -->
  214. <app-main :fixed-header="set.fixedHeader" />
  215. </div>
  216. <el-scrollbar v-else>
  217. <el-backtop
  218. title="回到顶部"
  219. target=".main-container .el-scrollbar__wrap"
  220. >
  221. <backTop />
  222. </el-backtop>
  223. <layout-header />
  224. <!-- 主体内容 -->
  225. <app-main :fixed-header="set.fixedHeader" />
  226. </el-scrollbar>
  227. </div>
  228. <!-- 系统设置 -->
  229. <setting />
  230. </div>
  231. </template>
  232. <style lang="scss" scoped>
  233. @mixin clearfix {
  234. &::after {
  235. content: "";
  236. display: table;
  237. clear: both;
  238. }
  239. }
  240. .app-wrapper {
  241. @include clearfix;
  242. position: relative;
  243. height: 100%;
  244. width: 100%;
  245. &.mobile.openSidebar {
  246. position: fixed;
  247. top: 0;
  248. }
  249. }
  250. .main-hidden {
  251. margin-left: 0 !important;
  252. }
  253. .app-mask {
  254. background: #000;
  255. opacity: 0.3;
  256. width: 100%;
  257. top: 0;
  258. height: 100%;
  259. position: absolute;
  260. z-index: 999;
  261. }
  262. .re-screen {
  263. margin-top: 12px;
  264. }
  265. </style>