xto-fronted 0.4.18 → 0.4.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{index-DmjW2npo.js → index-3zeoNaqT.js} +1 -1
- package/dist/{index-C2LrtpQb.js → index-BHZ_y8lp.js} +747 -732
- package/dist/{index-DK5nOrQA.js → index-BK8qDl14.js} +1 -1
- package/dist/{index-D6SM8jcQ.js → index-BNBv_FCu.js} +1 -1
- package/dist/index-BNwtCm83.js +345 -0
- package/dist/{index--Urjal10.js → index-CUAC0ZFB.js} +1 -1
- package/dist/index-CVMV9Tfg.js +142 -0
- package/dist/index-CbEIzXG9.js +475 -0
- package/dist/index-Do7uXDSi.js +2071 -0
- package/dist/index-DzerABZq.js +372 -0
- package/dist/index.es.js +1 -1
- package/dist/index.umd.js +1 -1
- package/dist/stores/app.d.ts +1 -1
- package/dist/style.css +1 -1
- package/package.json +1 -1
- package/src/components/Layout/Header.vue +61 -5
- package/src/components/Layout/index.vue +120 -104
- package/src/stores/app.ts +162 -180
|
@@ -8,7 +8,7 @@ import { useMenuStore } from '@/stores/menu'
|
|
|
8
8
|
import { Icon } from '@xto/base'
|
|
9
9
|
import { Drawer } from '@xto/feedback'
|
|
10
10
|
|
|
11
|
-
type LayoutMode = 'sidebar' | 'top'
|
|
11
|
+
type LayoutMode = 'sidebar' | 'top' | 'mix'
|
|
12
12
|
|
|
13
13
|
const route = useRoute()
|
|
14
14
|
const router = useRouter()
|
|
@@ -31,7 +31,8 @@ const greyMode = ref(false)
|
|
|
31
31
|
// 布局模式选项
|
|
32
32
|
const layoutOptions: { value: LayoutMode; label: string; icon: string }[] = [
|
|
33
33
|
{ value: 'sidebar', label: '左侧菜单', icon: 'sidebar-left' },
|
|
34
|
-
{ value: 'top', label: '顶部菜单', icon: 'menu' }
|
|
34
|
+
{ value: 'top', label: '顶部菜单', icon: 'menu' },
|
|
35
|
+
{ value: 'mix', label: '混合菜单', icon: 'grid' }
|
|
35
36
|
]
|
|
36
37
|
|
|
37
38
|
// 主题色选项
|
|
@@ -96,6 +97,7 @@ const openSettingsDrawer = () => {
|
|
|
96
97
|
// 切换布局模式
|
|
97
98
|
const handleLayoutChange = (mode: LayoutMode) => {
|
|
98
99
|
appStore.setLayout(mode)
|
|
100
|
+
drawerVisible.value = false
|
|
99
101
|
}
|
|
100
102
|
|
|
101
103
|
// 切换灰色模式
|
|
@@ -109,6 +111,18 @@ const handleGreyModeChange = (value: boolean) => {
|
|
|
109
111
|
}
|
|
110
112
|
}
|
|
111
113
|
|
|
114
|
+
// 抽屉内灰色模式开关
|
|
115
|
+
const handleGreyModeToggle = () => {
|
|
116
|
+
handleGreyModeChange(!greyMode.value)
|
|
117
|
+
drawerVisible.value = false
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// 抽屉内暗黑模式开关
|
|
121
|
+
const handleDarkModeToggle = () => {
|
|
122
|
+
appStore.toggleTheme()
|
|
123
|
+
drawerVisible.value = false
|
|
124
|
+
}
|
|
125
|
+
|
|
112
126
|
// 切换全屏
|
|
113
127
|
const toggleFullscreen = () => {
|
|
114
128
|
if (!document.fullscreenElement) {
|
|
@@ -153,6 +167,7 @@ const handleSearchItemClick = (path: string) => {
|
|
|
153
167
|
// 设置主题色
|
|
154
168
|
const handleColorChange = (color: string) => {
|
|
155
169
|
appStore.setPrimaryColor(color)
|
|
170
|
+
drawerVisible.value = false
|
|
156
171
|
}
|
|
157
172
|
|
|
158
173
|
// 个人信息
|
|
@@ -363,10 +378,19 @@ onUnmounted(() => {
|
|
|
363
378
|
<div class="preview-content"></div>
|
|
364
379
|
</div>
|
|
365
380
|
</div>
|
|
366
|
-
<div v-else class="layout-preview-top">
|
|
381
|
+
<div v-else-if="option.value === 'top'" class="layout-preview-top">
|
|
367
382
|
<div class="preview-header-full"></div>
|
|
368
383
|
<div class="preview-content-full"></div>
|
|
369
384
|
</div>
|
|
385
|
+
<div v-else class="layout-preview-mix">
|
|
386
|
+
<div class="preview-header-mix">
|
|
387
|
+
<div class="preview-mix-left"></div>
|
|
388
|
+
</div>
|
|
389
|
+
<div class="preview-mix-body">
|
|
390
|
+
<div class="preview-mix-aside"></div>
|
|
391
|
+
<div class="preview-mix-content"></div>
|
|
392
|
+
</div>
|
|
393
|
+
</div>
|
|
370
394
|
</div>
|
|
371
395
|
<span class="layout-option__label">{{ option.label }}</span>
|
|
372
396
|
</div>
|
|
@@ -396,13 +420,13 @@ onUnmounted(() => {
|
|
|
396
420
|
<div class="settings-switch-list">
|
|
397
421
|
<div class="settings-switch-item">
|
|
398
422
|
<span>灰色模式</span>
|
|
399
|
-
<div class="switch-wrapper" :class="{ 'is-checked': greyMode }" @click="
|
|
423
|
+
<div class="switch-wrapper" :class="{ 'is-checked': greyMode }" @click="handleGreyModeToggle">
|
|
400
424
|
<span class="switch-core"></span>
|
|
401
425
|
</div>
|
|
402
426
|
</div>
|
|
403
427
|
<div class="settings-switch-item">
|
|
404
428
|
<span>暗黑模式</span>
|
|
405
|
-
<div class="switch-wrapper" :class="{ 'is-checked': appStore.isDark }" @click="
|
|
429
|
+
<div class="switch-wrapper" :class="{ 'is-checked': appStore.isDark }" @click="handleDarkModeToggle">
|
|
406
430
|
<span class="switch-core"></span>
|
|
407
431
|
</div>
|
|
408
432
|
</div>
|
|
@@ -821,6 +845,38 @@ onUnmounted(() => {
|
|
|
821
845
|
}
|
|
822
846
|
}
|
|
823
847
|
|
|
848
|
+
.layout-preview-mix {
|
|
849
|
+
display: flex;
|
|
850
|
+
flex-direction: column;
|
|
851
|
+
height: 100%;
|
|
852
|
+
|
|
853
|
+
.preview-header-mix {
|
|
854
|
+
height: 25%;
|
|
855
|
+
background-color: var(--color-primary-light-7);
|
|
856
|
+
display: flex;
|
|
857
|
+
|
|
858
|
+
.preview-mix-left {
|
|
859
|
+
width: 30%;
|
|
860
|
+
background-color: var(--color-primary);
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
.preview-mix-body {
|
|
865
|
+
flex: 1;
|
|
866
|
+
display: flex;
|
|
867
|
+
|
|
868
|
+
.preview-mix-aside {
|
|
869
|
+
width: 25%;
|
|
870
|
+
background-color: var(--color-primary-light-8);
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
.preview-mix-content {
|
|
874
|
+
flex: 1;
|
|
875
|
+
background-color: var(--bg-color-page);
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
|
|
824
880
|
.settings-color-options {
|
|
825
881
|
display: flex;
|
|
826
882
|
gap: 12px;
|
|
@@ -1,105 +1,121 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import { computed } from 'vue'
|
|
3
|
-
import { useAppStore } from '@/stores/app'
|
|
4
|
-
import { useMenuStore } from '@/stores/menu'
|
|
5
|
-
import Sidebar from './Sidebar.vue'
|
|
6
|
-
import Header from './Header.vue'
|
|
7
|
-
import TopMenu from './TopMenu.vue'
|
|
8
|
-
|
|
9
|
-
const appStore = useAppStore()
|
|
10
|
-
const menuStore = useMenuStore()
|
|
11
|
-
|
|
12
|
-
const sidebarWidth = computed(() =>
|
|
13
|
-
appStore.isCollapsed ? '64px' : '210px'
|
|
14
|
-
)
|
|
15
|
-
|
|
16
|
-
// 布局模式
|
|
17
|
-
const layoutMode = computed(() => appStore.layout)
|
|
18
|
-
|
|
19
|
-
// 是否显示左侧菜单
|
|
20
|
-
const showSidebar = computed(() => layoutMode.value === 'sidebar')
|
|
21
|
-
|
|
22
|
-
//
|
|
23
|
-
const showTopMenu = computed(() => layoutMode.value === 'top')
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
<
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
overflow: hidden;
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed } from 'vue'
|
|
3
|
+
import { useAppStore } from '@/stores/app'
|
|
4
|
+
import { useMenuStore } from '@/stores/menu'
|
|
5
|
+
import Sidebar from './Sidebar.vue'
|
|
6
|
+
import Header from './Header.vue'
|
|
7
|
+
import TopMenu from './TopMenu.vue'
|
|
8
|
+
|
|
9
|
+
const appStore = useAppStore()
|
|
10
|
+
const menuStore = useMenuStore()
|
|
11
|
+
|
|
12
|
+
const sidebarWidth = computed(() =>
|
|
13
|
+
appStore.isCollapsed ? '64px' : '210px'
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
// 布局模式
|
|
17
|
+
const layoutMode = computed(() => appStore.layout)
|
|
18
|
+
|
|
19
|
+
// 是否显示左侧菜单
|
|
20
|
+
const showSidebar = computed(() => layoutMode.value === 'sidebar' || layoutMode.value === 'mix')
|
|
21
|
+
|
|
22
|
+
// 是否显示顶部菜单
|
|
23
|
+
const showTopMenu = computed(() => layoutMode.value === 'top')
|
|
24
|
+
|
|
25
|
+
// 混合模式下只显示当前顶部菜单的子菜单
|
|
26
|
+
const mixSubMenus = computed(() => {
|
|
27
|
+
if (layoutMode.value !== 'mix') return menuStore.menuList
|
|
28
|
+
// 混合模式需要根据顶部选中的菜单显示子菜单
|
|
29
|
+
// 这里暂时返回全部菜单,后续可根据实际需求调整
|
|
30
|
+
return menuStore.menuList
|
|
31
|
+
})
|
|
32
|
+
</script>
|
|
33
|
+
|
|
34
|
+
<template>
|
|
35
|
+
<div class="layout" :class="`layout--${layoutMode}`">
|
|
36
|
+
<!-- 左侧菜单布局 -->
|
|
37
|
+
<aside v-if="showSidebar" class="layout__aside" :style="{ width: sidebarWidth }">
|
|
38
|
+
<Sidebar :menu-list="layoutMode === 'mix' ? mixSubMenus : menuStore.menuList" />
|
|
39
|
+
</aside>
|
|
40
|
+
|
|
41
|
+
<!-- 顶部菜单布局 -->
|
|
42
|
+
<div v-if="showTopMenu" class="layout__top-menu">
|
|
43
|
+
<TopMenu />
|
|
44
|
+
</div>
|
|
45
|
+
|
|
46
|
+
<div class="layout__main">
|
|
47
|
+
<header class="layout__header">
|
|
48
|
+
<Header />
|
|
49
|
+
</header>
|
|
50
|
+
<main class="layout__content">
|
|
51
|
+
<router-view />
|
|
52
|
+
</main>
|
|
53
|
+
</div>
|
|
54
|
+
</div>
|
|
55
|
+
</template>
|
|
56
|
+
|
|
57
|
+
<style lang="scss" scoped>
|
|
58
|
+
.layout {
|
|
59
|
+
display: flex;
|
|
60
|
+
width: 100%;
|
|
61
|
+
height: 100%;
|
|
62
|
+
|
|
63
|
+
// 左侧菜单模式
|
|
64
|
+
&--sidebar {
|
|
65
|
+
flex-direction: row;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// 顶部菜单模式
|
|
69
|
+
&--top {
|
|
70
|
+
flex-direction: column;
|
|
71
|
+
|
|
72
|
+
.layout__aside {
|
|
73
|
+
display: none;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.layout__main {
|
|
77
|
+
flex: 1;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// 混合菜单模式
|
|
82
|
+
&--mix {
|
|
83
|
+
flex-direction: row;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
&__aside {
|
|
87
|
+
transition: width 0.3s;
|
|
88
|
+
overflow: hidden;
|
|
89
|
+
flex-shrink: 0;
|
|
90
|
+
height: 100%;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
&__top-menu {
|
|
94
|
+
width: 100%;
|
|
95
|
+
height: 50px;
|
|
96
|
+
background-color: var(--bg-color);
|
|
97
|
+
border-bottom: 1px solid var(--color-border-lighter);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
&__main {
|
|
101
|
+
flex: 1;
|
|
102
|
+
display: flex;
|
|
103
|
+
flex-direction: column;
|
|
104
|
+
overflow: hidden;
|
|
105
|
+
height: 100%;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
&__header {
|
|
109
|
+
height: 50px;
|
|
110
|
+
background-color: var(--bg-color);
|
|
111
|
+
border-bottom: 1px solid var(--color-border-lighter);
|
|
112
|
+
flex-shrink: 0;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
&__content {
|
|
116
|
+
flex: 1;
|
|
117
|
+
overflow: auto;
|
|
118
|
+
background-color: var(--bg-color-page);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
105
121
|
</style>
|