From 589151d1edded867fd8d15e9249fd0dfbf3544ef Mon Sep 17 00:00:00 2001 From: RuoYi <yzz_ivy@163.com> Date: 星期一, 21 四月 2025 13:23:19 +0800 Subject: [PATCH] 优化菜单搜索查询页 --- src/components/HeaderSearch/index.vue | 170 +++++++++++++++++++++++++++++++++----------------------- 1 files changed, 100 insertions(+), 70 deletions(-) diff --git a/src/components/HeaderSearch/index.vue b/src/components/HeaderSearch/index.vue index f87ff52..89a9478 100644 --- a/src/components/HeaderSearch/index.vue +++ b/src/components/HeaderSearch/index.vue @@ -1,19 +1,41 @@ <template> - <div :class="{ 'show': show }" class="header-search"> + <div class="header-search"> <svg-icon class-name="search-icon" icon-class="search" @click.stop="click" /> - <el-select - ref="headerSearchSelectRef" - v-model="search" - :remote-method="querySearch" - filterable - default-first-option - remote - placeholder="Search" - class="header-search-select" - @change="change" + <el-dialog + v-model="show" + width="600" + @close="close" + :show-close="false" + append-to-body > - <el-option v-for="option in options" :key="option.item.path" :value="option.item" :label="option.item.title.join(' > ')" /> - </el-select> + <el-input + v-model="search" + ref="headerSearchSelectRef" + size="large" + @input="querySearch" + prefix-icon="Search" + placeholder="鑿滃崟鎼滅储锛屾敮鎸佹爣棰樸�乁RL妯$硦鏌ヨ" + > + </el-input> + + <div class="result-wrap"> + <el-scrollbar> + <div class="search-item" tabindex="1" v-for="item in options" :key="item.path"> + <div class="left"> + <svg-icon class="menu-icon" :icon-class="item.icon" /> + </div> + <div class="search-info" @click="change(item)"> + <div class="menu-title"> + {{ item.title.join(" / ") }} + </div> + <div class="menu-path"> + {{ item.path }} + </div> + </div> + </div> + </el-scrollbar> + </div> + </el-dialog> </div> </template> @@ -23,36 +45,40 @@ import { isHttp } from '@/utils/validate' import usePermissionStore from '@/store/modules/permission' -const search = ref(''); -const options = ref([]); -const searchPool = ref([]); -const show = ref(false); -const fuse = ref(undefined); -const headerSearchSelectRef = ref(null); -const router = useRouter(); -const routes = computed(() => usePermissionStore().defaultRoutes); +const search = ref('') +const options = ref([]) +const searchPool = ref([]) +const show = ref(false) +const fuse = ref(undefined) +const headerSearchSelectRef = ref(null) +const router = useRouter() +const routes = computed(() => usePermissionStore().defaultRoutes) function click() { show.value = !show.value if (show.value) { headerSearchSelectRef.value && headerSearchSelectRef.value.focus() + options.value = searchPool.value } -}; +} + function close() { headerSearchSelectRef.value && headerSearchSelectRef.value.blur() + search.value = '' options.value = [] show.value = false } + function change(val) { - const path = val.path; - const query = val.query; + const path = val.path + const query = val.query if (isHttp(path)) { // http(s):// 璺緞鏂扮獥鍙f墦寮� - const pindex = path.indexOf("http"); - window.open(path.substr(pindex, path.length), "_blank"); + const pindex = path.indexOf("http") + window.open(path.substr(pindex, path.length), "_blank") } else { if (query) { - router.push({ path: path, query: JSON.parse(query) }); + router.push({ path: path, query: JSON.parse(query) }) } else { router.push(path) } @@ -64,6 +90,7 @@ show.value = false }) } + function initFuse(list) { fuse.value = new Fuse(list, { shouldSort: true, @@ -80,6 +107,7 @@ }] }) } + // Filter out the routes that can be displayed in the sidebar // And generate the internationalized title function generateRoutes(routes, basePath = '', prefixTitle = []) { @@ -88,16 +116,17 @@ for (const r of routes) { // skip hidden router if (r.hidden) { continue } - const p = r.path.length > 0 && r.path[0] === '/' ? r.path : '/' + r.path; + const p = r.path.length > 0 && r.path[0] === '/' ? r.path : '/' + r.path const data = { path: !isHttp(r.path) ? getNormalPath(basePath + p) : r.path, - title: [...prefixTitle] + title: [...prefixTitle], + icon: '' } if (r.meta && r.meta.title) { data.title = [...data.title, r.meta.title] - - if (r.redirect !== 'noRedirect') { + data.icon = r.meta.icon + if (r.redirect !== "noRedirect") { // only push the routes with title // special case: need to exclude parent router without redirect res.push(data) @@ -117,28 +146,17 @@ } return res } + function querySearch(query) { if (query !== '') { - options.value = fuse.value.search(query) + options.value = fuse.value.search(query).map((item) => item.item) ?? searchPool.value } else { - options.value = [] + options.value = searchPool.value } } onMounted(() => { - searchPool.value = generateRoutes(routes.value); -}) - -watchEffect(() => { searchPool.value = generateRoutes(routes.value) -}) - -watch(show, (value) => { - if (value) { - document.body.addEventListener('click', close) - } else { - document.body.removeEventListener('click', close) - } }) watch(searchPool, (list) => { @@ -148,40 +166,52 @@ <style lang='scss' scoped> .header-search { - font-size: 0 !important; - .search-icon { cursor: pointer; font-size: 18px; vertical-align: middle; } +} - .header-search-select { - font-size: 18px; - transition: width 0.2s; - width: 0; - overflow: hidden; - background: transparent; - border-radius: 0; - display: inline-block; - vertical-align: middle; +.result-wrap { + height: 280px; + margin: 10px 0; - :deep(.el-input__inner) { - border-radius: 0; - border: 0; - padding-left: 0; - padding-right: 0; - box-shadow: none !important; - border-bottom: 1px solid #d9d9d9; - vertical-align: middle; + .search-item { + display: flex; + height: 48px; + + .left { + width: 60px; + text-align: center; + + .menu-icon { + width: 18px; + height: 18px; + margin-top: 5px; + } + } + + .search-info { + padding-left: 5px; + width: 100%; + display: flex; + flex-direction: column; + justify-content: flex-start; + + .menu-title, + .menu-path { + height: 20px; + } + .menu-path { + color: #ccc; + font-size: 10px; + } } } - &.show { - .header-search-select { - width: 210px; - margin-left: 10px; - } + .search-item:hover { + cursor: pointer; } } -</style> \ No newline at end of file +</style> -- Gitblit v1.9.3