xto-fronted 0.3.5 → 0.3.6
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-B7etKk33.js +372 -0
- package/dist/index-BBqvHkzE.js +475 -0
- package/dist/index-C0VN9nFF.js +142 -0
- package/dist/index-CeCysOnl.js +345 -0
- package/dist/index-D7TZamyY.js +1664 -0
- package/dist/index.es.js +1 -1
- package/dist/index.umd.js +1 -1
- package/dist/style.css +1 -1
- package/package.json +1 -1
- package/src/components/Layout/Sidebar.vue +2 -129
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import {
|
|
2
|
+
import { computed } from 'vue'
|
|
3
3
|
import { useRoute, useRouter } from 'vue-router'
|
|
4
4
|
import { useMenuStore } from '@/stores/menu'
|
|
5
5
|
import { useUserStore } from '@/stores/user'
|
|
@@ -7,9 +7,7 @@ import { useAuthStore } from '@/stores/auth'
|
|
|
7
7
|
import { useAppStore } from '@/stores/app'
|
|
8
8
|
import { Menu, MenuItem, SubMenu } from '@xto/navigation'
|
|
9
9
|
import { Button } from '@xto/base'
|
|
10
|
-
import { Input } from '@xto/form'
|
|
11
10
|
import { Icon } from '@xto/base'
|
|
12
|
-
import type { MenuItem as MenuItemType } from '@/types/api'
|
|
13
11
|
|
|
14
12
|
const route = useRoute()
|
|
15
13
|
const router = useRouter()
|
|
@@ -18,7 +16,6 @@ const userStore = useUserStore()
|
|
|
18
16
|
const authStore = useAuthStore()
|
|
19
17
|
const appStore = useAppStore()
|
|
20
18
|
|
|
21
|
-
const searchKeyword = ref('')
|
|
22
19
|
const isCollapsed = computed(() => appStore.isCollapsed)
|
|
23
20
|
const activeMenu = computed(() => route.path)
|
|
24
21
|
|
|
@@ -27,63 +24,13 @@ const menuBgColor = computed(() => appStore.isDark ? '#1d1e1f' : '#fff')
|
|
|
27
24
|
const menuTextColor = computed(() => appStore.isDark ? '#cfd3dc' : '#303133')
|
|
28
25
|
const menuActiveTextColor = computed(() => '#409eff')
|
|
29
26
|
|
|
30
|
-
// 扁平化菜单用于搜索
|
|
31
|
-
const flattenMenus = (menus: MenuItemType[], parentTitle = ''): (MenuItemType & { parentTitle: string })[] => {
|
|
32
|
-
const result: (MenuItemType & { parentTitle: string })[] = []
|
|
33
|
-
menus.forEach(menu => {
|
|
34
|
-
if (menu.children && menu.children.length > 0) {
|
|
35
|
-
result.push(...flattenMenus(menu.children, menu.title))
|
|
36
|
-
} else {
|
|
37
|
-
result.push({ ...menu, parentTitle })
|
|
38
|
-
}
|
|
39
|
-
})
|
|
40
|
-
return result
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// 搜索结果
|
|
44
|
-
const searchResults = computed(() => {
|
|
45
|
-
if (!searchKeyword.value.trim()) return []
|
|
46
|
-
const flatMenus = flattenMenus(menuStore.menuList)
|
|
47
|
-
return flatMenus.filter(menu =>
|
|
48
|
-
menu.title.toLowerCase().includes(searchKeyword.value.toLowerCase())
|
|
49
|
-
)
|
|
50
|
-
})
|
|
51
|
-
|
|
52
|
-
// 过滤后的菜单列表
|
|
53
|
-
const filteredMenuList = computed(() => {
|
|
54
|
-
if (!searchKeyword.value.trim()) return menuStore.menuList
|
|
55
|
-
|
|
56
|
-
return menuStore.menuList.map(menu => {
|
|
57
|
-
if (menu.children && menu.children.length > 0) {
|
|
58
|
-
const filteredChildren = menu.children.filter(child =>
|
|
59
|
-
child.title.toLowerCase().includes(searchKeyword.value.toLowerCase())
|
|
60
|
-
)
|
|
61
|
-
if (filteredChildren.length > 0) {
|
|
62
|
-
return { ...menu, children: filteredChildren }
|
|
63
|
-
}
|
|
64
|
-
return null
|
|
65
|
-
}
|
|
66
|
-
if (menu.title.toLowerCase().includes(searchKeyword.value.toLowerCase())) {
|
|
67
|
-
return menu
|
|
68
|
-
}
|
|
69
|
-
return null
|
|
70
|
-
}).filter(Boolean) as MenuItemType[]
|
|
71
|
-
})
|
|
72
|
-
|
|
73
27
|
// 菜单选择
|
|
74
28
|
const handleMenuSelect = (index: string) => {
|
|
75
29
|
if (index && index !== route.path) {
|
|
76
30
|
router.push(index)
|
|
77
|
-
searchKeyword.value = ''
|
|
78
31
|
}
|
|
79
32
|
}
|
|
80
33
|
|
|
81
|
-
// 搜索结果点击
|
|
82
|
-
const handleSearchItemClick = (path: string) => {
|
|
83
|
-
router.push(path)
|
|
84
|
-
searchKeyword.value = ''
|
|
85
|
-
}
|
|
86
|
-
|
|
87
34
|
// 退出登录
|
|
88
35
|
const handleLogout = () => {
|
|
89
36
|
authStore.logout()
|
|
@@ -114,31 +61,6 @@ const getMenuIcon = (icon?: string): string => {
|
|
|
114
61
|
<span v-show="!isCollapsed" class="sidebar__logo-text">{{ appStore.appName }}</span>
|
|
115
62
|
</div>
|
|
116
63
|
|
|
117
|
-
<!-- 搜索框 -->
|
|
118
|
-
<div v-if="!isCollapsed" class="sidebar__search">
|
|
119
|
-
<Input
|
|
120
|
-
v-model="searchKeyword"
|
|
121
|
-
placeholder="搜索菜单..."
|
|
122
|
-
size="small"
|
|
123
|
-
clearable
|
|
124
|
-
/>
|
|
125
|
-
<!-- 搜索结果 -->
|
|
126
|
-
<div v-if="searchResults.length > 0" class="sidebar__search-results">
|
|
127
|
-
<div
|
|
128
|
-
v-for="item in searchResults"
|
|
129
|
-
:key="item.path"
|
|
130
|
-
class="sidebar__search-item"
|
|
131
|
-
@click="handleSearchItemClick(item.path)"
|
|
132
|
-
>
|
|
133
|
-
<Icon :name="getMenuIcon(item.icon)" :size="16" />
|
|
134
|
-
<div class="sidebar__search-item-info">
|
|
135
|
-
<span class="sidebar__search-item-title">{{ item.title }}</span>
|
|
136
|
-
<span v-if="item.parentTitle" class="sidebar__search-item-parent">{{ item.parentTitle }}</span>
|
|
137
|
-
</div>
|
|
138
|
-
</div>
|
|
139
|
-
</div>
|
|
140
|
-
</div>
|
|
141
|
-
|
|
142
64
|
<!-- 菜单 -->
|
|
143
65
|
<Menu
|
|
144
66
|
:default-active="activeMenu"
|
|
@@ -151,7 +73,7 @@ const getMenuIcon = (icon?: string): string => {
|
|
|
151
73
|
class="sidebar__menu"
|
|
152
74
|
@select="handleMenuSelect"
|
|
153
75
|
>
|
|
154
|
-
<template v-for="menu in
|
|
76
|
+
<template v-for="menu in menuStore.menuList" :key="menu.path">
|
|
155
77
|
<!-- 有子菜单 -->
|
|
156
78
|
<SubMenu v-if="menu.children && menu.children.length > 0" :index="menu.path">
|
|
157
79
|
<template #title>
|
|
@@ -221,55 +143,6 @@ const getMenuIcon = (icon?: string): string => {
|
|
|
221
143
|
color: var(--color-primary);
|
|
222
144
|
}
|
|
223
145
|
|
|
224
|
-
&__search {
|
|
225
|
-
padding: 10px;
|
|
226
|
-
border-bottom: 1px solid var(--color-border-lighter);
|
|
227
|
-
position: relative;
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
&__search-results {
|
|
231
|
-
position: absolute;
|
|
232
|
-
top: 100%;
|
|
233
|
-
left: 0;
|
|
234
|
-
right: 0;
|
|
235
|
-
background-color: var(--bg-color);
|
|
236
|
-
border: 1px solid var(--color-border-lighter);
|
|
237
|
-
border-radius: var(--border-radius-base);
|
|
238
|
-
box-shadow: var(--box-shadow);
|
|
239
|
-
max-height: 300px;
|
|
240
|
-
overflow-y: auto;
|
|
241
|
-
z-index: 100;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
&__search-item {
|
|
245
|
-
display: flex;
|
|
246
|
-
align-items: center;
|
|
247
|
-
gap: 10px;
|
|
248
|
-
padding: 10px 12px;
|
|
249
|
-
cursor: pointer;
|
|
250
|
-
transition: background-color 0.2s;
|
|
251
|
-
|
|
252
|
-
&:hover {
|
|
253
|
-
background-color: var(--color-fill);
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
&-info {
|
|
257
|
-
display: flex;
|
|
258
|
-
flex-direction: column;
|
|
259
|
-
gap: 2px;
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
&-title {
|
|
263
|
-
font-size: 14px;
|
|
264
|
-
color: var(--color-text-primary);
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
&-parent {
|
|
268
|
-
font-size: 12px;
|
|
269
|
-
color: var(--color-text-secondary);
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
|
|
273
146
|
&__menu {
|
|
274
147
|
flex: 1;
|
|
275
148
|
border-right: none;
|