index.vue 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. <!--
  2. - Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
  3. -
  4. - Licensed under the GNU Affero General Public License, Version 3 (the "License");
  5. - you may not use this file except in compliance with the License.
  6. - You may obtain a copy of the License at
  7. -
  8. - https://www.gnu.org/licenses/agpl-3.0.html
  9. -
  10. - Unless required by applicable law or agreed to in writing, software
  11. - distributed under the License is distributed on an "AS IS" BASIS,
  12. - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. - See the License for the specific language governing permissions and
  14. - limitations under the License.
  15. -->
  16. <template>
  17. <n-layout :position="fixedMenu" class="layout" has-sider>
  18. <n-layout-sider
  19. v-if="
  20. !isMobile && isMixMenuNoneSub && (navMode === 'vertical' || navMode === 'horizontal-mix')
  21. "
  22. :collapsed="collapsed"
  23. :collapsed-width="64"
  24. :inverted="inverted"
  25. :native-scrollbar="false"
  26. :position="fixedMenu"
  27. :width="leftMenuWidth"
  28. class="layout-sider"
  29. collapse-mode="width"
  30. show-trigger="bar"
  31. @collapse="collapsed = true"
  32. @expand="collapsed = false"
  33. >
  34. <Logo :collapsed="collapsed" />
  35. <AsideMenu v-model:collapsed="collapsed" v-model:location="getMenuLocation" />
  36. </n-layout-sider>
  37. <n-drawer
  38. v-model:show="showSideDrawer"
  39. :placement="'left'"
  40. :width="menuWidth"
  41. class="layout-side-drawer"
  42. >
  43. <n-layout-sider
  44. :collapsed="false"
  45. :inverted="inverted"
  46. :native-scrollbar="false"
  47. :position="fixedMenu"
  48. :width="menuWidth"
  49. class="layout-sider"
  50. >
  51. <Logo :collapsed="collapsed" />
  52. <AsideMenu v-model:location="getMenuLocation" />
  53. </n-layout-sider>
  54. </n-drawer>
  55. <n-layout :inverted="inverted">
  56. <n-layout-header :inverted="getHeaderInverted" :position="fixedHeader">
  57. <PageHeader v-model:collapsed="collapsed" :inverted="inverted" />
  58. </n-layout-header>
  59. <n-layout-content
  60. :class="{ 'layout-default-background': getDarkTheme === false }"
  61. class="layout-content"
  62. >
  63. <div
  64. :class="{
  65. 'layout-content-main-fix': fixedMulti,
  66. 'fluid-header': fixedHeader === 'static',
  67. }"
  68. class="layout-content-main"
  69. >
  70. <TabsView v-if="isMultiTabs" v-model:collapsed="collapsed" />
  71. <div
  72. :class="{
  73. 'main-view-fix': fixedMulti,
  74. noMultiTabs: !isMultiTabs,
  75. 'mt-3': !isMultiTabs,
  76. }"
  77. class="main-view"
  78. >
  79. <MainView />
  80. </div>
  81. </div>
  82. <!--1.15废弃,没啥用,占用操作空间-->
  83. <!-- <NLayoutFooter v-if="getShowFooter">-->
  84. <!-- <PageFooter />-->
  85. <!-- </NLayoutFooter>-->
  86. </n-layout-content>
  87. <n-back-top :right="100" />
  88. </n-layout>
  89. </n-layout>
  90. </template>
  91. <script lang="ts" setup>
  92. import { computed, onMounted, ref, unref, watch } from 'vue';
  93. import { Logo } from './components/Logo';
  94. import { TabsView } from './components/TagsView';
  95. import { MainView } from './components/Main';
  96. import { AsideMenu } from './components/Menu';
  97. import { PageHeader } from './components/Header';
  98. import { useProjectSetting } from '@/hooks/setting/useProjectSetting';
  99. import { useDesignSetting } from '@/hooks/setting/useDesignSetting';
  100. import { useRoute } from 'vue-router';
  101. import { useProjectSettingStore } from '@/store/modules/projectSetting';
  102. const { getDarkTheme } = useDesignSetting();
  103. const {
  104. // showFooter,
  105. navMode,
  106. navTheme,
  107. headerSetting,
  108. menuSetting,
  109. multiTabsSetting,
  110. } = useProjectSetting();
  111. const settingStore = useProjectSettingStore();
  112. const collapsed = ref<boolean>(false);
  113. const { mobileWidth, menuWidth } = unref(menuSetting);
  114. const isMobile = computed<boolean>({
  115. get: () => settingStore.getIsMobile,
  116. set: (val) => settingStore.setIsMobile(val),
  117. });
  118. const fixedHeader = computed(() => {
  119. const { fixed } = unref(headerSetting);
  120. return fixed ? 'absolute' : 'static';
  121. });
  122. const isMixMenuNoneSub = computed(() => {
  123. const mixMenu = unref(menuSetting).mixMenu;
  124. const currentRoute = useRoute();
  125. if (unref(navMode) != 'horizontal-mix') return true;
  126. if (unref(navMode) === 'horizontal-mix' && mixMenu && currentRoute.meta.isRoot) {
  127. return false;
  128. }
  129. return true;
  130. });
  131. const fixedMenu = computed(() => {
  132. const { fixed } = unref(headerSetting);
  133. return fixed ? 'absolute' : 'static';
  134. });
  135. const isMultiTabs = computed(() => {
  136. return unref(multiTabsSetting).show;
  137. });
  138. const fixedMulti = computed(() => {
  139. return unref(multiTabsSetting).fixed;
  140. });
  141. const inverted = computed(() => {
  142. return ['dark', 'header-dark'].includes(unref(navTheme));
  143. });
  144. const getHeaderInverted = computed(() => {
  145. return ['light', 'header-dark'].includes(unref(navTheme)) ? unref(inverted) : !unref(inverted);
  146. });
  147. const leftMenuWidth = computed(() => {
  148. const { minMenuWidth, menuWidth } = unref(menuSetting);
  149. return collapsed.value ? minMenuWidth : menuWidth;
  150. });
  151. const getMenuLocation = computed(() => {
  152. return 'left';
  153. });
  154. // 控制显示或隐藏移动端侧边栏
  155. const showSideDrawer = computed({
  156. get: () => isMobile.value && collapsed.value,
  157. set: (val) => (collapsed.value = val),
  158. });
  159. //判断是否触发移动端模式
  160. const checkMobileMode = () => {
  161. if (document.body.clientWidth <= mobileWidth) {
  162. isMobile.value = true;
  163. } else {
  164. isMobile.value = false;
  165. }
  166. collapsed.value = false;
  167. };
  168. const watchWidth = () => {
  169. const Width = document.body.clientWidth;
  170. if (Width <= 950) {
  171. collapsed.value = true;
  172. } else collapsed.value = false;
  173. checkMobileMode();
  174. };
  175. watch(
  176. () => settingStore.menuSetting.collapsed,
  177. (val) => {
  178. if (val) {
  179. // 单独校验store中的collapsed配置,优先于store中设置的true选项
  180. collapsed.value = true;
  181. }
  182. }
  183. );
  184. onMounted(() => {
  185. checkMobileMode();
  186. window.addEventListener('resize', watchWidth);
  187. });
  188. </script>
  189. <style lang="less">
  190. .layout-side-drawer {
  191. background-color: rgb(0, 20, 40);
  192. .layout-sider {
  193. min-height: 100vh;
  194. box-shadow: 2px 0 8px 0 rgb(29 35 41 / 5%);
  195. position: relative;
  196. z-index: 13;
  197. transition: all 0.2s ease-in-out;
  198. }
  199. }
  200. </style>
  201. <style lang="less" scoped>
  202. .layout {
  203. display: flex;
  204. flex-direction: row;
  205. flex: auto;
  206. &-default-background {
  207. background: #f8f8fa;
  208. }
  209. .layout-sider {
  210. min-height: 100vh;
  211. box-shadow: 2px 0 8px 0 rgb(29 35 41 / 5%);
  212. position: relative;
  213. z-index: 13;
  214. transition: all 0.2s ease-in-out;
  215. }
  216. .layout-sider-fix {
  217. position: fixed;
  218. top: 0;
  219. left: 0;
  220. }
  221. .ant-layout {
  222. overflow: hidden;
  223. }
  224. .layout-right-fix {
  225. overflow-x: hidden;
  226. padding-left: 200px;
  227. min-height: 100vh;
  228. transition: all 0.2s ease-in-out;
  229. }
  230. .layout-content {
  231. flex: auto;
  232. min-height: 100vh;
  233. }
  234. .n-layout-header.n-layout-header--absolute-positioned {
  235. z-index: 11;
  236. }
  237. .n-layout-footer {
  238. background: none;
  239. }
  240. }
  241. .layout-content-main {
  242. margin: 0 10px 10px;
  243. position: relative;
  244. padding-top: 64px;
  245. }
  246. .layout-content-main-fix {
  247. padding-top: 64px;
  248. }
  249. .fluid-header {
  250. padding-top: 0;
  251. }
  252. .main-view-fix {
  253. padding-top: 44px;
  254. height: calc(100vh - 64px) !important;
  255. }
  256. .noMultiTabs {
  257. padding-top: 0;
  258. }
  259. </style>