index.vue 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. <script setup lang="ts">
  2. import { setType } from "./types";
  3. import { emitter } from "/@/utils/mitt";
  4. import { useLayout } from "./hooks/useLayout";
  5. import { useAppStoreHook } from "/@/store/modules/app";
  6. import { deviceDetection, useDark } from "@pureadmin/utils";
  7. import { useSettingStoreHook } from "/@/store/modules/settings";
  8. import { h, reactive, computed, onMounted, defineComponent } from "vue";
  9. import backTop from "/@/assets/svg/back_top.svg?component";
  10. import fullScreen from "/@/assets/svg/full_screen.svg?component";
  11. import exitScreen from "/@/assets/svg/exit_screen.svg?component";
  12. import navbar from "./components/navbar.vue";
  13. import tag from "./components/tag/index.vue";
  14. import appMain from "./components/appMain.vue";
  15. import setting from "./components/setting/index.vue";
  16. import Vertical from "./components/sidebar/vertical.vue";
  17. import Horizontal from "./components/sidebar/horizontal.vue";
  18. const { isDark } = useDark();
  19. const isMobile = deviceDetection();
  20. const pureSetting = useSettingStoreHook();
  21. const { instance, layout } = useLayout();
  22. const set: setType = reactive({
  23. sidebar: computed(() => {
  24. return useAppStoreHook().sidebar;
  25. }),
  26. device: computed(() => {
  27. return useAppStoreHook().device;
  28. }),
  29. fixedHeader: computed(() => {
  30. return pureSetting.fixedHeader;
  31. }),
  32. classes: computed(() => {
  33. return {
  34. hideSidebar: !set.sidebar.opened,
  35. openSidebar: set.sidebar.opened,
  36. withoutAnimation: set.sidebar.withoutAnimation,
  37. mobile: set.device === "mobile"
  38. };
  39. }),
  40. hideTabs: computed(() => {
  41. return instance.$storage?.configure.hideTabs;
  42. })
  43. });
  44. function setTheme(layoutModel: string) {
  45. window.document.body.setAttribute("layout", layoutModel);
  46. instance.$storage.layout = {
  47. layout: `${layoutModel}`,
  48. theme: instance.$storage.layout?.theme,
  49. darkMode: instance.$storage.layout?.darkMode,
  50. sidebarStatus: instance.$storage.layout?.sidebarStatus,
  51. epThemeColor: instance.$storage.layout?.epThemeColor
  52. };
  53. }
  54. function toggle(device: string, bool: boolean) {
  55. useAppStoreHook().toggleDevice(device);
  56. useAppStoreHook().toggleSideBar(bool, "resize");
  57. }
  58. // 判断是否可自动关闭菜单栏
  59. let isAutoCloseSidebar = true;
  60. // 监听容器
  61. emitter.on("resize", ({ detail }) => {
  62. if (isMobile) return;
  63. let { width } = detail;
  64. width <= 760 ? setTheme("vertical") : setTheme(useAppStoreHook().layout);
  65. /** width app-wrapper类容器宽度
  66. * 0 < width <= 760 隐藏侧边栏
  67. * 760 < width <= 990 折叠侧边栏
  68. * width > 990 展开侧边栏
  69. */
  70. if (width > 0 && width <= 760) {
  71. toggle("mobile", false);
  72. isAutoCloseSidebar = true;
  73. } else if (width > 760 && width <= 990) {
  74. if (isAutoCloseSidebar) {
  75. toggle("desktop", false);
  76. isAutoCloseSidebar = false;
  77. }
  78. } else if (width > 990) {
  79. if (!set.sidebar.isClickCollapse) {
  80. toggle("desktop", true);
  81. isAutoCloseSidebar = true;
  82. }
  83. }
  84. });
  85. onMounted(() => {
  86. if (isMobile) {
  87. toggle("mobile", false);
  88. }
  89. });
  90. function onFullScreen() {
  91. pureSetting.hiddenSideBar
  92. ? pureSetting.changeSetting({ key: "hiddenSideBar", value: false })
  93. : pureSetting.changeSetting({ key: "hiddenSideBar", value: true });
  94. }
  95. const layoutHeader = defineComponent({
  96. render() {
  97. return h(
  98. "div",
  99. {
  100. class: { "fixed-header": set.fixedHeader },
  101. style: [
  102. set.hideTabs && layout.value.includes("horizontal")
  103. ? isDark.value
  104. ? "box-shadow: 0 1px 4px #0d0d0d"
  105. : "box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08)"
  106. : ""
  107. ]
  108. },
  109. {
  110. default: () => [
  111. !pureSetting.hiddenSideBar &&
  112. (layout.value.includes("vertical") || layout.value.includes("mix"))
  113. ? h(navbar)
  114. : h("div"),
  115. !pureSetting.hiddenSideBar && layout.value.includes("horizontal")
  116. ? h(Horizontal)
  117. : h("div"),
  118. h(
  119. tag,
  120. {},
  121. {
  122. default: () => [
  123. h(
  124. "span",
  125. {
  126. onClick: onFullScreen
  127. },
  128. {
  129. default: () => [
  130. !pureSetting.hiddenSideBar
  131. ? h(fullScreen, { class: "dark:color-white" })
  132. : h(exitScreen, { class: "dark:color-white" })
  133. ]
  134. }
  135. )
  136. ]
  137. }
  138. )
  139. ]
  140. }
  141. );
  142. }
  143. });
  144. </script>
  145. <template>
  146. <div :class="['app-wrapper', set.classes]" v-resize>
  147. <div
  148. v-show="
  149. set.device === 'mobile' &&
  150. set.sidebar.opened &&
  151. layout.includes('vertical')
  152. "
  153. class="app-mask"
  154. @click="useAppStoreHook().toggleSideBar()"
  155. />
  156. <Vertical
  157. v-show="
  158. !pureSetting.hiddenSideBar &&
  159. (layout.includes('vertical') || layout.includes('mix'))
  160. "
  161. />
  162. <div
  163. :class="[
  164. 'main-container',
  165. pureSetting.hiddenSideBar ? 'main-hidden' : ''
  166. ]"
  167. >
  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
  175. title="回到顶部"
  176. target=".main-container .el-scrollbar__wrap"
  177. >
  178. <backTop />
  179. </el-backtop>
  180. <layout-header />
  181. <!-- 主体内容 -->
  182. <app-main :fixed-header="set.fixedHeader" />
  183. </el-scrollbar>
  184. </div>
  185. <!-- 系统设置 -->
  186. <setting />
  187. </div>
  188. </template>
  189. <style lang="scss" scoped>
  190. @mixin clearfix {
  191. &::after {
  192. content: "";
  193. display: table;
  194. clear: both;
  195. }
  196. }
  197. .app-wrapper {
  198. @include clearfix;
  199. position: relative;
  200. height: 100%;
  201. width: 100%;
  202. &.mobile.openSidebar {
  203. position: fixed;
  204. top: 0;
  205. }
  206. }
  207. .main-hidden {
  208. margin-left: 0 !important;
  209. }
  210. .app-mask {
  211. background: #000;
  212. opacity: 0.3;
  213. width: 100%;
  214. top: 0;
  215. height: 100%;
  216. position: absolute;
  217. z-index: 999;
  218. }
  219. .re-screen {
  220. margin-top: 12px;
  221. }
  222. </style>