From e181f04c642204e79749af93fa921875ff6c21ba Mon Sep 17 00:00:00 2001 From: baoshiwei <baoshiwei@shlanbao.cn> Date: 星期二, 20 五月 2025 10:46:35 +0800 Subject: [PATCH] refactor(qms): 重构趋势图展示逻辑 --- src/components/HeaderSearch/index.vue | 156 ++++++++++++++++++++++++++++----------------------- 1 files changed, 85 insertions(+), 71 deletions(-) diff --git a/src/components/HeaderSearch/index.vue b/src/components/HeaderSearch/index.vue index e6b9531..a785958 100644 --- a/src/components/HeaderSearch/index.vue +++ b/src/components/HeaderSearch/index.vue @@ -1,50 +1,74 @@ -<script setup lang="ts"> -import Fuse from 'fuse.js' -import { getNormalPath } from '@/utils/ruoyi' -import { isHttp } from '@/utils/validate' -import usePermissionStore from '@/store/modules/permission' -import { RouteOption } from 'vue-router' +<template> + <div :class="{ show: show }" 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-option v-for="option in options" :key="option.item.path" :value="option.item" :label="option.item.title.join(' > ')" /> + </el-select> + </div> +</template> + +<script setup lang="ts" name="HeaderSearch"> +import Fuse from 'fuse.js'; +import { getNormalPath } from '@/utils/ruoyi'; +import { isHttp } from '@/utils/validate'; +import usePermissionStore from '@/store/modules/permission'; +import { RouteRecordRaw } from 'vue-router'; type Router = Array<{ path: string; title: string[]; -}> +}>; const search = ref(''); const options = ref<any>([]); const searchPool = ref<Router>([]); const show = ref(false); const fuse = ref(); -const headerSearchSelectRef = ref(ElSelect); +const headerSearchSelectRef = ref<ElSelectInstance>(); const router = useRouter(); -const routes = computed(() => usePermissionStore().routes); +const routes = computed(() => usePermissionStore().getRoutes()); const click = () => { - show.value = !show.value + show.value = !show.value; if (show.value) { - headerSearchSelectRef.value && headerSearchSelectRef.value.focus() + headerSearchSelectRef.value && headerSearchSelectRef.value.focus(); } }; const close = () => { - headerSearchSelectRef.value && headerSearchSelectRef.value.blur() - options.value = [] - show.value = false -} + headerSearchSelectRef.value && headerSearchSelectRef.value.blur(); + options.value = []; + show.value = false; +}; const change = (val: any) => { 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 { - router.push(path) + if (query) { + router.push({ path: path, query: JSON.parse(query) }); + } else { + router.push(path); + } } - search.value = '' - options.value = [] + search.value = ''; + options.value = []; nextTick(() => { - show.value = false - }) -} + show.value = false; + }); +}; const initFuse = (list: Router) => { fuse.value = new Fuse(list, { shouldSort: true, @@ -52,27 +76,31 @@ location: 0, distance: 100, minMatchCharLength: 1, - keys: [{ - name: 'title', - weight: 0.7 - }, { - name: 'path', - weight: 0.3 - }] - }) -} + keys: [ + { + name: 'title', + weight: 0.7 + }, + { + name: 'path', + weight: 0.3 + } + ] + }); +}; // Filter out the routes that can be displayed in the sidebar // And generate the internationalized title -const generateRoutes = (routes: RouteOption[], basePath = '', prefixTitle: string[] = []) => { - let res: Router = [] - routes.forEach(r => { +const generateRoutes = (routes: RouteRecordRaw[], basePath = '', prefixTitle: string[] = []) => { + let res: Router = []; + routes.forEach((r) => { // skip hidden router if (!r.hidden) { 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], + query: '' + }; if (r.meta && r.meta.title) { data.title = [...data.title, r.meta.title]; if (r.redirect !== 'noRedirect') { @@ -81,6 +109,11 @@ res.push(data); } } + + if (r.query) { + data.query = r.query; + } + // recursive child routes if (r.children) { const tempRoutes = generateRoutes(r.children, data.path, data.title); @@ -89,56 +122,37 @@ } } } - }) + }); return res; -} +}; const querySearch = (query: string) => { if (query !== '') { - options.value = fuse.value.search(query) + options.value = fuse.value.search(query); } else { - options.value = [] + options.value = []; } -} +}; onMounted(() => { searchPool.value = generateRoutes(routes.value); -}) +}); -watchEffect(() => { - searchPool.value = generateRoutes(routes.value) -}) +// watchEffect(() => { +// searchPool.value = generateRoutes(routes.value) +// }) watch(show, (value) => { if (value) { - document.body.addEventListener('click', close) + document.body.addEventListener('click', close); } else { - document.body.removeEventListener('click', close) + document.body.removeEventListener('click', close); } -}) +}); -watch(searchPool, (list) => { - initFuse(list) -}) +watch(searchPool, (list: Router) => { + initFuse(list); +}); </script> - -<template> - <div :class="{ 'show': show }" 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-option v-for="option in options" :key="option.item.path" :value="option.item" :label="option.item.title.join(' > ')" /> - </el-select> - </div> -</template> <style lang="scss" scoped> .header-search { -- Gitblit v1.9.3