style: 全局菜单搜索仅过滤菜单名称

This commit is contained in:
TsMask
2025-09-17 15:10:08 +08:00
parent 749e880aa7
commit 4a5008f1b5

View File

@@ -2,11 +2,7 @@
<!-- 搜索按钮 --> <!-- 搜索按钮 -->
<a-tooltip placement="bottom"> <a-tooltip placement="bottom">
<template #title>{{ t('common.search') }}</template> <template #title>{{ t('common.search') }}</template>
<a-button <a-button type="text" style="color: inherit" @click="fnClickSearch">
type="text"
style="color: inherit"
@click="fnClickSearch"
>
<template #icon> <template #icon>
<SearchOutlined /> <SearchOutlined />
</template> </template>
@@ -38,11 +34,13 @@
<SearchOutlined style="color: #bfbfbf" /> <SearchOutlined style="color: #bfbfbf" />
</template> </template>
</a-input> </a-input>
<div class="search-results"> <div class="search-results">
<div v-if="filteredMenus.length === 0" class="no-results"> <div v-if="filteredMenus.length === 0" class="no-results">
<a-empty <a-empty
:description="searchKeyword ? t('common.noData') : t('common.searchTip')" :description="
searchKeyword ? t('common.noData') : t('common.searchTip')
"
:image="false" :image="false"
/> />
</div> </div>
@@ -55,15 +53,15 @@
> >
<div class="menu-icon"> <div class="menu-icon">
<!-- 处理自定义图标字体 --> <!-- 处理自定义图标字体 -->
<IconFont <IconFont
v-if="menu.icon && menu.icon.startsWith('icon-')" v-if="menu.icon && menu.icon.startsWith('icon-')"
:type="menu.icon" :type="menu.icon"
class="icon" class="icon"
/> />
<!-- 处理Ant Design图标组件 --> <!-- 处理Ant Design图标组件 -->
<component <component
:is="menu.icon" :is="menu.icon"
v-else-if="menu.icon && !menu.icon.startsWith('icon-')" v-else-if="menu.icon && !menu.icon.startsWith('icon-')"
class="icon" class="icon"
/> />
<!-- 默认图标 --> <!-- 默认图标 -->
@@ -83,10 +81,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { import { getMenuData, clearMenuItem } from 'antdv-pro-layout';
getMenuData,
clearMenuItem
} from 'antdv-pro-layout';
import { ProModal } from 'antdv-pro-modal'; import { ProModal } from 'antdv-pro-modal';
import IconFont from '@/components/IconFont/index.vue'; import IconFont from '@/components/IconFont/index.vue';
import { ref, computed, nextTick } from 'vue'; import { ref, computed, nextTick } from 'vue';
@@ -127,7 +122,7 @@ const searchableMenus = computed(() => {
} else { } else {
rootRoute.children = children; rootRoute.children = children;
} }
// 根据用户角色过滤 // 根据用户角色过滤
if (!userStore.roles.includes('tenant')) { if (!userStore.roles.includes('tenant')) {
rootRoute.children = rootRoute.children.filter( rootRoute.children = rootRoute.children.filter(
@@ -164,26 +159,30 @@ const searchableMenus = computed(() => {
try { try {
const title = t(route.meta.title); const title = t(route.meta.title);
// 避免重复添加已存在的路由 // 避免重复添加已存在的路由
const exists = menus.find(m => m.routeName === route.name || m.path === fullPath); const exists = menus.find(
m => m.routeName === route.name || m.path === fullPath
);
if (!exists) { if (!exists) {
menus.push({ menus.push({
title: title, title: title,
path: fullPath, path: fullPath,
icon: route.meta.icon, icon: route.meta.icon,
key: route.name || fullPath, key: route.name || fullPath,
routeName: route.name routeName: route.name,
}); });
} }
} catch (error) { } catch (error) {
// 如果翻译失败,使用原始标题 // 如果翻译失败,使用原始标题
const exists = menus.find(m => m.routeName === route.name || m.path === fullPath); const exists = menus.find(
m => m.routeName === route.name || m.path === fullPath
);
if (!exists) { if (!exists) {
menus.push({ menus.push({
title: route.meta.title, title: route.meta.title,
path: fullPath, path: fullPath,
icon: route.meta.icon, icon: route.meta.icon,
key: route.name || fullPath, key: route.name || fullPath,
routeName: route.name routeName: route.name,
}); });
} }
} }
@@ -198,7 +197,7 @@ const searchableMenus = computed(() => {
// 使用和菜单面板相同的数据源 // 使用和菜单面板相同的数据源
const menuRoutes = getMenuDataForSearch(); const menuRoutes = getMenuDataForSearch();
if (menuRoutes && menuRoutes.length > 0) { if (menuRoutes && menuRoutes.length > 0) {
getRouteItems(menuRoutes); getRouteItems(menuRoutes);
} }
@@ -211,18 +210,22 @@ const filteredMenus = computed(() => {
if (!searchKeyword.value.trim()) { if (!searchKeyword.value.trim()) {
return searchableMenus.value.slice(0, 10); // 默认显示前10个 return searchableMenus.value.slice(0, 10); // 默认显示前10个
} }
return searchableMenus.value.filter(menu => // return searchableMenus.value.filter(menu =>
menu.title.toLowerCase().includes(searchKeyword.value.toLowerCase()) || // menu.title.toLowerCase().includes(searchKeyword.value.toLowerCase()) ||
menu.path.toLowerCase().includes(searchKeyword.value.toLowerCase()) // menu.path.toLowerCase().includes(searchKeyword.value.toLowerCase())
).slice(0, 10); // ).slice(0, 10);
const value = searchKeyword.value.toLowerCase();
return searchableMenus.value
.filter(menu => menu.title.toLowerCase().includes(value))
.slice(0, 10);
}); });
/**打开搜索弹窗 */ /**打开搜索弹窗 */
function fnClickSearch() { function fnClickSearch() {
searchModalOpen.value = true; searchModalOpen.value = true;
searchKeyword.value = ''; searchKeyword.value = '';
nextTick(() => { nextTick(() => {
searchInputRef.value?.focus(); searchInputRef.value?.focus();
}); });
@@ -268,12 +271,12 @@ function fnHandleKeydown(e: KeyboardEvent) {
.search-results { .search-results {
max-height: 400px; max-height: 400px;
overflow-y: auto; overflow-y: auto;
.no-results { .no-results {
text-align: center; text-align: center;
padding: 40px 0; padding: 40px 0;
} }
.menu-list { .menu-list {
.menu-item { .menu-item {
display: flex; display: flex;
@@ -283,15 +286,15 @@ function fnHandleKeydown(e: KeyboardEvent) {
cursor: pointer; cursor: pointer;
transition: all 0.2s ease; transition: all 0.2s ease;
margin-bottom: 4px; margin-bottom: 4px;
&:hover { &:hover {
background-color: #f5f5f5; background-color: #f5f5f5;
.menu-action { .menu-action {
opacity: 1; opacity: 1;
} }
} }
.menu-icon { .menu-icon {
margin-right: 12px; margin-right: 12px;
display: flex; display: flex;
@@ -301,17 +304,17 @@ function fnHandleKeydown(e: KeyboardEvent) {
height: 32px; height: 32px;
background-color: #f0f2f5; background-color: #f0f2f5;
border-radius: 6px; border-radius: 6px;
.icon { .icon {
font-size: 16px; font-size: 16px;
color: #666; color: #666;
} }
} }
.menu-info { .menu-info {
flex: 1; flex: 1;
min-width: 0; min-width: 0;
.menu-title { .menu-title {
font-size: 14px; font-size: 14px;
font-weight: 500; font-weight: 500;
@@ -321,7 +324,7 @@ function fnHandleKeydown(e: KeyboardEvent) {
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
} }
.menu-path { .menu-path {
font-size: 12px; font-size: 12px;
color: #8c8c8c; color: #8c8c8c;
@@ -330,7 +333,7 @@ function fnHandleKeydown(e: KeyboardEvent) {
white-space: nowrap; white-space: nowrap;
} }
} }
.menu-action { .menu-action {
opacity: 0; opacity: 0;
transition: opacity 0.2s ease; transition: opacity 0.2s ease;
@@ -343,7 +346,7 @@ function fnHandleKeydown(e: KeyboardEvent) {
} }
// 暗黑主题支持 // 暗黑主题支持
[data-theme="dark"] { [data-theme='dark'] {
.search-modal-content { .search-modal-content {
.search-results { .search-results {
.menu-list { .menu-list {
@@ -351,20 +354,20 @@ function fnHandleKeydown(e: KeyboardEvent) {
&:hover { &:hover {
background-color: #303030; background-color: #303030;
} }
.menu-icon { .menu-icon {
background-color: #262626; background-color: #262626;
.icon { .icon {
color: #bfbfbf; color: #bfbfbf;
} }
} }
.menu-info { .menu-info {
.menu-title { .menu-title {
color: #f0f0f0; color: #f0f0f0;
} }
.menu-path { .menu-path {
color: #8c8c8c; color: #8c8c8c;
} }