xto-fronted 0.4.35 → 0.4.37
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/components/Layout/Sidebar.vue.d.ts +0 -4
- package/dist/index-23nX2t9j.js +142 -0
- package/dist/index-8oCLh51t.js +475 -0
- package/dist/index-B4Wny0vt.js +345 -0
- package/dist/index-BeUYNx5P.js +475 -0
- package/dist/index-D8YBeNfn.js +345 -0
- package/dist/index-DWI51JAp.js +372 -0
- package/dist/index-Dw8KZwGJ.js +2354 -0
- package/dist/index-DwzGV3B9.js +142 -0
- package/dist/index-iyQQumAA.js +372 -0
- package/dist/index-wt7AbUqc.js +2342 -0
- package/dist/index.es.js +1 -1
- package/dist/index.umd.js +1 -1
- package/dist/stores/app.d.ts +2 -8
- package/dist/style.css +1 -1
- package/package.json +1 -1
- package/src/assets/styles/_dark.scss +0 -67
- package/src/components/Layout/Header.vue +23 -0
- package/src/components/Layout/Sidebar.vue +33 -26
- package/src/components/Layout/TopMenu.vue +51 -12
- package/src/components/Layout/index.vue +124 -254
- package/src/router/layoutRoute.ts +44 -57
- package/src/stores/app.ts +0 -16
- package/src/components/Layout/MixTopMenu.vue +0 -870
|
@@ -1,255 +1,125 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import { computed
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
)
|
|
18
|
-
|
|
19
|
-
//
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
//
|
|
23
|
-
const
|
|
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
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
)
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
// 监听布局模式变化,切换到 mix 模式时同步一级菜单
|
|
127
|
-
watch(
|
|
128
|
-
layoutMode,
|
|
129
|
-
(mode) => {
|
|
130
|
-
if (mode === 'mix' && menuStore.menuList.length > 0) {
|
|
131
|
-
syncTopMenuByRoute(route.path)
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
)
|
|
135
|
-
</script>
|
|
136
|
-
|
|
137
|
-
<template>
|
|
138
|
-
<div class="layout" :class="`layout--${layoutMode}`">
|
|
139
|
-
<!-- sidebar模式:左侧菜单 + Header + 内容 -->
|
|
140
|
-
<template v-if="layoutMode === 'sidebar'">
|
|
141
|
-
<aside class="layout__aside" :style="{ width: sidebarWidth }">
|
|
142
|
-
<Sidebar :menu-list="menuStore.menuList" />
|
|
143
|
-
</aside>
|
|
144
|
-
<div class="layout__main">
|
|
145
|
-
<header class="layout__header">
|
|
146
|
-
<Header />
|
|
147
|
-
</header>
|
|
148
|
-
<main class="layout__content">
|
|
149
|
-
<router-view />
|
|
150
|
-
</main>
|
|
151
|
-
</div>
|
|
152
|
-
</template>
|
|
153
|
-
|
|
154
|
-
<!-- top模式:顶部菜单 + 内容 -->
|
|
155
|
-
<template v-if="layoutMode === 'top'">
|
|
156
|
-
<div class="layout__top-menu">
|
|
157
|
-
<TopMenu />
|
|
158
|
-
</div>
|
|
159
|
-
<div class="layout__main">
|
|
160
|
-
<main class="layout__content">
|
|
161
|
-
<router-view />
|
|
162
|
-
</main>
|
|
163
|
-
</div>
|
|
164
|
-
</template>
|
|
165
|
-
|
|
166
|
-
<!-- mix模式:顶部一级菜单 + 左侧二级菜单 + 内容 -->
|
|
167
|
-
<template v-if="layoutMode === 'mix'">
|
|
168
|
-
<div class="layout__mix-top">
|
|
169
|
-
<MixTopMenu />
|
|
170
|
-
</div>
|
|
171
|
-
<div class="layout__mix-body">
|
|
172
|
-
<!-- 只有当一级菜单有子菜单时才显示左侧菜单 -->
|
|
173
|
-
<aside v-if="showMixSidebar" class="layout__aside" :style="{ width: sidebarWidth }">
|
|
174
|
-
<Sidebar :menu-list="mixSubMenus" :show-logo="false" :show-user="false" />
|
|
175
|
-
</aside>
|
|
176
|
-
<div class="layout__main">
|
|
177
|
-
<main class="layout__content">
|
|
178
|
-
<router-view />
|
|
179
|
-
</main>
|
|
180
|
-
</div>
|
|
181
|
-
</div>
|
|
182
|
-
</template>
|
|
183
|
-
</div>
|
|
184
|
-
</template>
|
|
185
|
-
|
|
186
|
-
<style lang="scss" scoped>
|
|
187
|
-
.layout {
|
|
188
|
-
display: flex;
|
|
189
|
-
width: 100%;
|
|
190
|
-
height: 100%;
|
|
191
|
-
|
|
192
|
-
// 左侧菜单模式
|
|
193
|
-
&--sidebar {
|
|
194
|
-
flex-direction: row;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
// 顶部菜单模式
|
|
198
|
-
&--top {
|
|
199
|
-
flex-direction: column;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
// 混合菜单模式
|
|
203
|
-
&--mix {
|
|
204
|
-
flex-direction: column;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
&__aside {
|
|
208
|
-
transition: width 0.3s;
|
|
209
|
-
overflow: hidden;
|
|
210
|
-
flex-shrink: 0;
|
|
211
|
-
height: 100%;
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
&__top-menu {
|
|
215
|
-
width: 100%;
|
|
216
|
-
height: 50px;
|
|
217
|
-
background-color: var(--bg-color);
|
|
218
|
-
border-bottom: 1px solid var(--color-border-lighter);
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
&__mix-top {
|
|
222
|
-
width: 100%;
|
|
223
|
-
height: 50px;
|
|
224
|
-
background-color: var(--bg-color);
|
|
225
|
-
border-bottom: 1px solid var(--color-border-lighter);
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
&__mix-body {
|
|
229
|
-
display: flex;
|
|
230
|
-
flex: 1;
|
|
231
|
-
overflow: hidden;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
&__main {
|
|
235
|
-
flex: 1;
|
|
236
|
-
display: flex;
|
|
237
|
-
flex-direction: column;
|
|
238
|
-
overflow: hidden;
|
|
239
|
-
height: 100%;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
&__header {
|
|
243
|
-
height: 50px;
|
|
244
|
-
background-color: var(--bg-color);
|
|
245
|
-
border-bottom: 1px solid var(--color-border-lighter);
|
|
246
|
-
flex-shrink: 0;
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
&__content {
|
|
250
|
-
flex: 1;
|
|
251
|
-
overflow: auto;
|
|
252
|
-
background-color: var(--bg-color-page);
|
|
253
|
-
}
|
|
254
|
-
}
|
|
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
|
+
// 是否显示Header(顶部菜单模式下不显示,因为功能已移到TopMenu)
|
|
26
|
+
const showHeader = computed(() => layoutMode.value !== 'top')
|
|
27
|
+
|
|
28
|
+
// 混合模式下只显示当前顶部菜单的子菜单
|
|
29
|
+
const mixSubMenus = computed(() => {
|
|
30
|
+
if (layoutMode.value !== 'mix') return menuStore.menuList
|
|
31
|
+
// 混合模式需要根据顶部选中的菜单显示子菜单
|
|
32
|
+
// 这里暂时返回全部菜单,后续可根据实际需求调整
|
|
33
|
+
return menuStore.menuList
|
|
34
|
+
})
|
|
35
|
+
</script>
|
|
36
|
+
|
|
37
|
+
<template>
|
|
38
|
+
<div class="layout" :class="`layout--${layoutMode}`">
|
|
39
|
+
<!-- 左侧菜单布局 -->
|
|
40
|
+
<aside v-if="showSidebar" class="layout__aside" :style="{ width: sidebarWidth }">
|
|
41
|
+
<Sidebar :menu-list="layoutMode === 'mix' ? mixSubMenus : menuStore.menuList" />
|
|
42
|
+
</aside>
|
|
43
|
+
|
|
44
|
+
<!-- 顶部菜单布局(包含右侧操作功能) -->
|
|
45
|
+
<div v-if="showTopMenu" class="layout__top-menu">
|
|
46
|
+
<TopMenu />
|
|
47
|
+
</div>
|
|
48
|
+
|
|
49
|
+
<div class="layout__main">
|
|
50
|
+
<!-- Header仅在sidebar和mix模式下显示 -->
|
|
51
|
+
<header v-if="showHeader" class="layout__header">
|
|
52
|
+
<Header />
|
|
53
|
+
</header>
|
|
54
|
+
<main class="layout__content">
|
|
55
|
+
<router-view />
|
|
56
|
+
</main>
|
|
57
|
+
</div>
|
|
58
|
+
</div>
|
|
59
|
+
</template>
|
|
60
|
+
|
|
61
|
+
<style lang="scss" scoped>
|
|
62
|
+
.layout {
|
|
63
|
+
display: flex;
|
|
64
|
+
width: 100%;
|
|
65
|
+
height: 100%;
|
|
66
|
+
|
|
67
|
+
// 左侧菜单模式
|
|
68
|
+
&--sidebar {
|
|
69
|
+
flex-direction: row;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// 顶部菜单模式
|
|
73
|
+
&--top {
|
|
74
|
+
flex-direction: column;
|
|
75
|
+
|
|
76
|
+
.layout__aside {
|
|
77
|
+
display: none;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.layout__main {
|
|
81
|
+
flex: 1;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// 混合菜单模式
|
|
86
|
+
&--mix {
|
|
87
|
+
flex-direction: row;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
&__aside {
|
|
91
|
+
transition: width 0.3s;
|
|
92
|
+
overflow: hidden;
|
|
93
|
+
flex-shrink: 0;
|
|
94
|
+
height: 100%;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
&__top-menu {
|
|
98
|
+
width: 100%;
|
|
99
|
+
height: 50px;
|
|
100
|
+
background-color: var(--bg-color);
|
|
101
|
+
border-bottom: 1px solid var(--color-border-lighter);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
&__main {
|
|
105
|
+
flex: 1;
|
|
106
|
+
display: flex;
|
|
107
|
+
flex-direction: column;
|
|
108
|
+
overflow: hidden;
|
|
109
|
+
height: 100%;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
&__header {
|
|
113
|
+
height: 50px;
|
|
114
|
+
background-color: var(--bg-color);
|
|
115
|
+
border-bottom: 1px solid var(--color-border-lighter);
|
|
116
|
+
flex-shrink: 0;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
&__content {
|
|
120
|
+
flex: 1;
|
|
121
|
+
overflow: auto;
|
|
122
|
+
background-color: var(--bg-color-page);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
255
125
|
</style>
|
|
@@ -1,58 +1,45 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 布局路由工厂函数
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { createRouter as vueCreateRouter, createWebHistory } from 'vue-router'
|
|
6
|
-
import type { RouteRecordRaw, Router } from 'vue-router'
|
|
7
|
-
import Layout from '@/components/Layout/index.vue'
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
*
|
|
16
|
-
* @param
|
|
17
|
-
* @
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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
|
-
* @param routes 路由配置数组
|
|
50
|
-
* @returns 路由实例
|
|
51
|
-
*/
|
|
52
|
-
export function createRouter(routes: RouteRecordRaw[]): Router {
|
|
53
|
-
return vueCreateRouter({
|
|
54
|
-
history: createWebHistory(),
|
|
55
|
-
routes,
|
|
56
|
-
scrollBehavior: () => ({ left: 0, top: 0 })
|
|
57
|
-
})
|
|
1
|
+
/**
|
|
2
|
+
* 布局路由工厂函数
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { createRouter as vueCreateRouter, createWebHistory } from 'vue-router'
|
|
6
|
+
import type { RouteRecordRaw, Router } from 'vue-router'
|
|
7
|
+
import Layout from '@/components/Layout/index.vue'
|
|
8
|
+
|
|
9
|
+
interface LayoutRouteOptions {
|
|
10
|
+
indexPath?: string
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* 创建布局路由
|
|
15
|
+
* @param children 子路由配置
|
|
16
|
+
* @param options 配置选项
|
|
17
|
+
* @returns 布局路由配置
|
|
18
|
+
*/
|
|
19
|
+
export function createLayoutRoute(
|
|
20
|
+
children: RouteRecordRaw[],
|
|
21
|
+
options: LayoutRouteOptions = {}
|
|
22
|
+
): RouteRecordRaw {
|
|
23
|
+
const indexPath = options.indexPath || '/dashboard'
|
|
24
|
+
|
|
25
|
+
return {
|
|
26
|
+
path: '/',
|
|
27
|
+
name: 'Layout',
|
|
28
|
+
component: Layout,
|
|
29
|
+
redirect: indexPath,
|
|
30
|
+
children
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* 创建路由实例
|
|
36
|
+
* @param routes 路由配置数组
|
|
37
|
+
* @returns 路由实例
|
|
38
|
+
*/
|
|
39
|
+
export function createRouter(routes: RouteRecordRaw[]): Router {
|
|
40
|
+
return vueCreateRouter({
|
|
41
|
+
history: createWebHistory(),
|
|
42
|
+
routes,
|
|
43
|
+
scrollBehavior: () => ({ left: 0, top: 0 })
|
|
44
|
+
})
|
|
58
45
|
}
|
package/src/stores/app.ts
CHANGED
|
@@ -22,8 +22,6 @@ export const useAppStore = defineStore('app', () => {
|
|
|
22
22
|
const showBreadcrumb = ref<boolean>(local.get<boolean>('showBreadcrumb') ?? true)
|
|
23
23
|
const primaryColor = ref<string>(local.get<string>('primaryColor') || '#409eff')
|
|
24
24
|
const cachedViews = ref<string[]>([])
|
|
25
|
-
// 混合模式下选中的一级菜单路径
|
|
26
|
-
const activeTopMenuPath = ref<string>(local.get<string>('activeTopMenuPath') || '')
|
|
27
25
|
|
|
28
26
|
// 计算属性
|
|
29
27
|
const themeClass = computed(() => (isDark.value ? 'dark' : 'light'))
|
|
@@ -76,18 +74,6 @@ export const useAppStore = defineStore('app', () => {
|
|
|
76
74
|
const setLayout = (mode: LayoutMode) => {
|
|
77
75
|
layout.value = mode
|
|
78
76
|
local.set('layout', mode)
|
|
79
|
-
// 切换到混合模式时不清除一级菜单选中状态
|
|
80
|
-
// 切换到其他模式时才清除
|
|
81
|
-
if (mode !== 'mix') {
|
|
82
|
-
activeTopMenuPath.value = ''
|
|
83
|
-
local.remove('activeTopMenuPath')
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// 设置混合模式选中的一级菜单
|
|
88
|
-
const setActiveTopMenuPath = (path: string) => {
|
|
89
|
-
activeTopMenuPath.value = path
|
|
90
|
-
local.set('activeTopMenuPath', path)
|
|
91
77
|
}
|
|
92
78
|
|
|
93
79
|
// 切换标签页
|
|
@@ -158,7 +144,6 @@ export const useAppStore = defineStore('app', () => {
|
|
|
158
144
|
showBreadcrumb,
|
|
159
145
|
primaryColor,
|
|
160
146
|
cachedViews,
|
|
161
|
-
activeTopMenuPath,
|
|
162
147
|
themeClass,
|
|
163
148
|
setAppName,
|
|
164
149
|
setIndexPath,
|
|
@@ -166,7 +151,6 @@ export const useAppStore = defineStore('app', () => {
|
|
|
166
151
|
toggleCollapse,
|
|
167
152
|
setTheme,
|
|
168
153
|
setLayout,
|
|
169
|
-
setActiveTopMenuPath,
|
|
170
154
|
toggleTabs,
|
|
171
155
|
toggleFooter,
|
|
172
156
|
toggleBreadcrumb,
|