Skip to content

Commit

Permalink
feat: 增加菜单搜索功能 (#10)
Browse files Browse the repository at this point in the history
* feat: 增加菜单搜索功能
* fix: 修复菜单搜索浮层样式问题
yixiaco authored Jul 9, 2023

Verified

This commit was signed with the committer’s verified signature.
benelan Ben Elan
1 parent 611fc5d commit 9add79d
Showing 2 changed files with 74 additions and 7 deletions.
2 changes: 2 additions & 0 deletions ruoyi-ui/components.d.ts
Original file line number Diff line number Diff line change
@@ -22,6 +22,7 @@ declare module 'vue' {
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
TAside: typeof import('tdesign-vue-next')['Aside']
TAutoComplete: typeof import('tdesign-vue-next')['AutoComplete']
TAvatar: typeof import('tdesign-vue-next')['Avatar']
TAvatarGroup: typeof import('tdesign-vue-next')['AvatarGroup']
TBadge: typeof import('tdesign-vue-next')['Badge']
@@ -47,6 +48,7 @@ declare module 'vue' {
TFormItem: typeof import('tdesign-vue-next')['FormItem']
THeader: typeof import('tdesign-vue-next')['Header']
THeadMenu: typeof import('tdesign-vue-next')['HeadMenu']
THighlightOption: typeof import('tdesign-vue-next')['HighlightOption']
Thumbnail: typeof import('./src/components/thumbnail/index.vue')['default']
TImage: typeof import('tdesign-vue-next')['Image']
TImageViewer: typeof import('tdesign-vue-next')['ImageViewer']
79 changes: 72 additions & 7 deletions ruoyi-ui/src/layouts/components/Search.vue
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
<template>
<div v-if="layout === 'side'" class="header-menu-search">
<t-input
<t-auto-complete
v-model="searchData"
:class="['header-search', { 'hover-active': isSearchFocus }]"
placeholder="请输入搜索内容"
:options="options"
:popup-props="{
overlayInnerClassName: ['search-popup'],
}"
@blur="changeSearchFocus(false)"
@focus="changeSearchFocus(true)"
>
<template #prefix-icon>
<search-icon class="icon" size="16" />
</template>
</t-input>
<template #option="{ option }">
<t-highlight-option :content="option.text" :keyword="searchData" @click="() => $router.push(option.value)" />
</template>
</t-auto-complete>
</div>

<div v-else class="header-menu-search-left">
@@ -22,37 +30,94 @@
>
<search-icon />
</t-button>
<t-input
<t-auto-complete
v-model="searchData"
:class="['header-search', { 'width-zero': !isSearchFocus }]"
placeholder="输入要搜索内容"
:autofocus="isSearchFocus"
:options="options"
:popup-props="{
overlayInnerClassName: ['search-popup'],
}"
@blur="changeSearchFocus(false)"
>
<template #prefix-icon>
<search-icon size="16" />
</template>
</t-input>
<template #option="{ option }">
<t-highlight-option :content="option.text" :keyword="searchData" @click="() => $router.push(option.value)" />
</template>
</t-auto-complete>
</div>
</template>

<script setup lang="ts">
import { storeToRefs } from 'pinia';
import { SearchIcon } from 'tdesign-icons-vue-next';
import { ref } from 'vue';
import { HighlightOption as THighlightOption } from 'tdesign-vue-next';
import { computed, ref } from 'vue';
import { usePermissionStore } from '@/store';
import { MenuRoute } from '@/types/interface';
defineProps({
layout: String,
});
const permissionStore = usePermissionStore();
const { defaultRoutes: menuRouters } = storeToRefs(permissionStore);
const isSearchFocus = ref(false);
const searchData = ref('');
const changeSearchFocus = (value: boolean) => {
if (!value) {
searchData.value = '';
if (!value && searchData.value) {
setTimeout(() => {
searchData.value = '';
}, 100);
}
isSearchFocus.value = value;
};
const menus = computed(() => {
const newMenuRouters = menuRouters.value as Array<MenuRoute>;
return getLeftMenus(newMenuRouters)
.filter((value) => value?.title && !value?.meta?.hidden)
.map((value) => ({ text: value.title, value: value.path }));
});
const options = computed(() => {
if (!searchData.value) {
return [];
}
return menus.value;
});
/** 获取叶子节点的菜单结构 */
function getLeftMenus(menus: Array<MenuRoute>, parent?: MenuRoute): MenuRoute[] {
return menus.flatMap((value) => {
// 浅克隆对象
value = { ...value };
function getTitle(title: string) {
if (title && parent?.title) {
return `${parent.title} / ${title}`;
}
return title;
}
if (value?.meta?.title) {
value.title = getTitle(value.meta.title);
}
value.path = parent?.path && !value.path.startsWith('http') ? `${parent?.path}/${value.path}` : value.path;
if (value.children && value.children.length > 0) {
return getLeftMenus(value.children, value);
}
return value;
});
}
</script>
<!-- eslint-disable-next-line vue-scoped-css/enforce-style-type -->
<style lang="less">
.search-popup {
width: auto !important;
}
</style>
<style lang="less" scoped>
.header-menu-search {
display: flex;

0 comments on commit 9add79d

Please sign in to comment.