xto-fronted 0.4.38 → 0.4.40
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 +4 -0
- package/dist/index-BOwDukt-.js +2346 -0
- package/dist/index-BhKJLk9M.js +2824 -0
- package/dist/index-BtE24Mt4.js +142 -0
- package/dist/index-C1cKUqmA.js +372 -0
- package/dist/index-CGrvOpdb.js +372 -0
- package/dist/index-CttJvDTG.js +475 -0
- package/dist/index-DONIBpuJ.js +345 -0
- package/dist/index-DyybaRkK.js +345 -0
- package/dist/index-cl4Y-BWw.js +475 -0
- package/dist/index-oOzAFXfr.js +142 -0
- package/dist/index.es.js +1 -1
- package/dist/index.umd.js +1 -1
- package/dist/stores/app.d.ts +8 -2
- package/dist/style.css +1 -1
- package/package.json +1 -1
- package/src/components/Layout/Header.vue +0 -23
- package/src/components/Layout/MixTopMenu.vue +930 -0
- package/src/components/Layout/Sidebar.vue +7 -3
- package/src/components/Layout/index.vue +163 -124
- package/src/stores/app.ts +8 -0
|
@@ -11,8 +11,12 @@ import { Button, Icon } from '@xto/base'
|
|
|
11
11
|
// Props
|
|
12
12
|
const props = withDefaults(defineProps<{
|
|
13
13
|
menuList?: any[]
|
|
14
|
+
showLogo?: boolean
|
|
15
|
+
showUser?: boolean
|
|
14
16
|
}>(), {
|
|
15
|
-
menuList: () => []
|
|
17
|
+
menuList: () => [],
|
|
18
|
+
showLogo: true,
|
|
19
|
+
showUser: true
|
|
16
20
|
})
|
|
17
21
|
|
|
18
22
|
const route = useRoute()
|
|
@@ -133,7 +137,7 @@ const iconExists = (iconName: string): boolean => {
|
|
|
133
137
|
<template>
|
|
134
138
|
<div class="sidebar" :class="{ 'sidebar--collapsed': isCollapsed }">
|
|
135
139
|
<!-- Logo -->
|
|
136
|
-
<div class="sidebar__logo">
|
|
140
|
+
<div v-if="props.showLogo" class="sidebar__logo">
|
|
137
141
|
<img src="/vite.svg" alt="Logo" class="sidebar__logo-img" />
|
|
138
142
|
<span v-show="!isCollapsed" class="sidebar__logo-text">{{ appStore.appName }}</span>
|
|
139
143
|
</div>
|
|
@@ -190,7 +194,7 @@ const iconExists = (iconName: string): boolean => {
|
|
|
190
194
|
</Menu>
|
|
191
195
|
|
|
192
196
|
<!-- 用户信息 -->
|
|
193
|
-
<div v-if="!isCollapsed" class="sidebar__user">
|
|
197
|
+
<div v-if="props.showUser && !isCollapsed" class="sidebar__user">
|
|
194
198
|
<div class="sidebar__user-info">
|
|
195
199
|
<span class="sidebar__user-name">{{ userStore.userName }}</span>
|
|
196
200
|
<span class="sidebar__user-role">{{ userStore.departmentName }}</span>
|
|
@@ -1,125 +1,164 @@
|
|
|
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
|
-
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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
|
-
|
|
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
|
-
flex-direction: row;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
flex:
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
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
|
+
import MixTopMenu from './MixTopMenu.vue'
|
|
9
|
+
|
|
10
|
+
const appStore = useAppStore()
|
|
11
|
+
const menuStore = useMenuStore()
|
|
12
|
+
|
|
13
|
+
const sidebarWidth = computed(() =>
|
|
14
|
+
appStore.isCollapsed ? '64px' : '210px'
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
// 布局模式
|
|
18
|
+
const layoutMode = computed(() => appStore.layout)
|
|
19
|
+
|
|
20
|
+
// 是否显示左侧菜单(sidebar模式和mix模式都显示)
|
|
21
|
+
const showSidebar = computed(() => layoutMode.value === 'sidebar' || layoutMode.value === 'mix')
|
|
22
|
+
|
|
23
|
+
// 是否显示顶部菜单(top模式)
|
|
24
|
+
const showTopMenu = computed(() => layoutMode.value === 'top')
|
|
25
|
+
|
|
26
|
+
// 是否显示混合顶部菜单(mix模式)
|
|
27
|
+
const showMixTopMenu = computed(() => layoutMode.value === 'mix')
|
|
28
|
+
|
|
29
|
+
// 是否显示Header(仅在sidebar模式下显示)
|
|
30
|
+
const showHeader = computed(() => layoutMode.value === 'sidebar')
|
|
31
|
+
|
|
32
|
+
// 左侧菜单数据
|
|
33
|
+
const sidebarMenuList = computed(() => {
|
|
34
|
+
if (layoutMode.value === 'sidebar') {
|
|
35
|
+
return menuStore.menuList
|
|
36
|
+
} else if (layoutMode.value === 'mix') {
|
|
37
|
+
// mix模式下显示当前选中一级菜单的子菜单
|
|
38
|
+
return appStore.mixSubMenus
|
|
39
|
+
}
|
|
40
|
+
return []
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
// 是否显示左侧菜单(mix模式下只有在有子菜单时才显示)
|
|
44
|
+
const showMixSidebar = computed(() => {
|
|
45
|
+
if (layoutMode.value !== 'mix') return showSidebar.value
|
|
46
|
+
return appStore.mixSubMenus.length > 0
|
|
47
|
+
})
|
|
48
|
+
</script>
|
|
49
|
+
|
|
50
|
+
<template>
|
|
51
|
+
<div class="layout" :class="`layout--${layoutMode}`">
|
|
52
|
+
<!-- 左侧菜单布局 -->
|
|
53
|
+
<aside v-if="showMixSidebar" class="layout__aside" :style="{ width: sidebarWidth }">
|
|
54
|
+
<Sidebar :menu-list="sidebarMenuList" :show-logo="layoutMode !== 'mix'" :show-user="layoutMode !== 'mix'" />
|
|
55
|
+
</aside>
|
|
56
|
+
|
|
57
|
+
<!-- 顶部菜单布局(top模式) -->
|
|
58
|
+
<div v-if="showTopMenu" class="layout__top-menu">
|
|
59
|
+
<TopMenu />
|
|
60
|
+
</div>
|
|
61
|
+
|
|
62
|
+
<!-- 混合顶部菜单布局(mix模式) -->
|
|
63
|
+
<div v-if="showMixTopMenu" class="layout__mix-top-menu">
|
|
64
|
+
<MixTopMenu />
|
|
65
|
+
</div>
|
|
66
|
+
|
|
67
|
+
<div class="layout__main">
|
|
68
|
+
<!-- Header仅在sidebar模式下显示 -->
|
|
69
|
+
<header v-if="showHeader" class="layout__header">
|
|
70
|
+
<Header />
|
|
71
|
+
</header>
|
|
72
|
+
<main class="layout__content">
|
|
73
|
+
<router-view />
|
|
74
|
+
</main>
|
|
75
|
+
</div>
|
|
76
|
+
</div>
|
|
77
|
+
</template>
|
|
78
|
+
|
|
79
|
+
<style lang="scss" scoped>
|
|
80
|
+
.layout {
|
|
81
|
+
display: flex;
|
|
82
|
+
width: 100%;
|
|
83
|
+
height: 100%;
|
|
84
|
+
|
|
85
|
+
// 左侧菜单模式
|
|
86
|
+
&--sidebar {
|
|
87
|
+
flex-direction: row;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// 顶部菜单模式
|
|
91
|
+
&--top {
|
|
92
|
+
flex-direction: column;
|
|
93
|
+
|
|
94
|
+
.layout__aside {
|
|
95
|
+
display: none;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.layout__main {
|
|
99
|
+
flex: 1;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// 混合菜单模式
|
|
104
|
+
&--mix {
|
|
105
|
+
flex-direction: column;
|
|
106
|
+
|
|
107
|
+
.layout__main {
|
|
108
|
+
display: flex;
|
|
109
|
+
flex-direction: row;
|
|
110
|
+
flex: 1;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.layout__content {
|
|
114
|
+
flex: 1;
|
|
115
|
+
display: flex;
|
|
116
|
+
flex-direction: column;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
&__aside {
|
|
121
|
+
transition: width 0.3s;
|
|
122
|
+
overflow: hidden;
|
|
123
|
+
flex-shrink: 0;
|
|
124
|
+
height: 100%;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
&__top-menu {
|
|
128
|
+
width: 100%;
|
|
129
|
+
height: 50px;
|
|
130
|
+
background-color: var(--bg-color);
|
|
131
|
+
border-bottom: 1px solid var(--color-border-lighter);
|
|
132
|
+
flex-shrink: 0;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
&__mix-top-menu {
|
|
136
|
+
width: 100%;
|
|
137
|
+
height: 50px;
|
|
138
|
+
background-color: var(--bg-color);
|
|
139
|
+
border-bottom: 1px solid var(--color-border-lighter);
|
|
140
|
+
flex-shrink: 0;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
&__main {
|
|
144
|
+
flex: 1;
|
|
145
|
+
display: flex;
|
|
146
|
+
flex-direction: column;
|
|
147
|
+
overflow: hidden;
|
|
148
|
+
height: 100%;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
&__header {
|
|
152
|
+
height: 50px;
|
|
153
|
+
background-color: var(--bg-color);
|
|
154
|
+
border-bottom: 1px solid var(--color-border-lighter);
|
|
155
|
+
flex-shrink: 0;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
&__content {
|
|
159
|
+
flex: 1;
|
|
160
|
+
overflow: auto;
|
|
161
|
+
background-color: var(--bg-color-page);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
125
164
|
</style>
|
package/src/stores/app.ts
CHANGED
|
@@ -22,6 +22,7 @@ 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
|
+
const mixSubMenus = ref<any[]>([])
|
|
25
26
|
|
|
26
27
|
// 计算属性
|
|
27
28
|
const themeClass = computed(() => (isDark.value ? 'dark' : 'light'))
|
|
@@ -121,6 +122,11 @@ export const useAppStore = defineStore('app', () => {
|
|
|
121
122
|
cachedViews.value = []
|
|
122
123
|
}
|
|
123
124
|
|
|
125
|
+
// 设置混合模式子菜单
|
|
126
|
+
const setMixSubMenus = (menus: any[]) => {
|
|
127
|
+
mixSubMenus.value = menus
|
|
128
|
+
}
|
|
129
|
+
|
|
124
130
|
// 初始化主题
|
|
125
131
|
const initTheme = () => {
|
|
126
132
|
updateTheme()
|
|
@@ -144,6 +150,7 @@ export const useAppStore = defineStore('app', () => {
|
|
|
144
150
|
showBreadcrumb,
|
|
145
151
|
primaryColor,
|
|
146
152
|
cachedViews,
|
|
153
|
+
mixSubMenus,
|
|
147
154
|
themeClass,
|
|
148
155
|
setAppName,
|
|
149
156
|
setIndexPath,
|
|
@@ -158,6 +165,7 @@ export const useAppStore = defineStore('app', () => {
|
|
|
158
165
|
addCachedView,
|
|
159
166
|
removeCachedView,
|
|
160
167
|
clearCachedViews,
|
|
168
|
+
setMixSubMenus,
|
|
161
169
|
initTheme
|
|
162
170
|
}
|
|
163
171
|
})
|