|
|
|
@ -16,12 +16,15 @@ |
|
|
|
prefix-icon="Search" |
|
|
|
placeholder="菜单搜索,支持标题、URL模糊查询" |
|
|
|
clearable |
|
|
|
@keyup.enter="selectActiveResult" |
|
|
|
@keydown.up.prevent="navigateResult('up')" |
|
|
|
@keydown.down.prevent="navigateResult('down')" |
|
|
|
> |
|
|
|
</el-input> |
|
|
|
|
|
|
|
<div class="result-wrap"> |
|
|
|
<el-scrollbar> |
|
|
|
<div class="search-item" tabindex="1" v-for="item in options" :key="item.path"> |
|
|
|
<div class="search-item" tabindex="1" v-for="(item, index) in options" :key="item.path" :style="activeStyle(index)" @mouseenter="activeIndex = index" @mouseleave="activeIndex = -1"> |
|
|
|
<div class="left"> |
|
|
|
<svg-icon class="menu-icon" :icon-class="item.icon" /> |
|
|
|
</div> |
|
|
|
@ -33,6 +36,7 @@ |
|
|
|
{{ item.path }} |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<svg-icon icon-class="enter" v-show="index === activeIndex"/> |
|
|
|
</div> |
|
|
|
</el-scrollbar> |
|
|
|
</div> |
|
|
|
@ -44,15 +48,18 @@ |
|
|
|
import Fuse from 'fuse.js' |
|
|
|
import { getNormalPath } from '@/utils/ruoyi' |
|
|
|
import { isHttp } from '@/utils/validate' |
|
|
|
import useSettingsStore from '@/store/modules/settings' |
|
|
|
import usePermissionStore from '@/store/modules/permission' |
|
|
|
|
|
|
|
const search = ref('') |
|
|
|
const options = ref([]) |
|
|
|
const searchPool = ref([]) |
|
|
|
const activeIndex = ref(-1) |
|
|
|
const show = ref(false) |
|
|
|
const fuse = ref(undefined) |
|
|
|
const headerSearchSelectRef = ref(null) |
|
|
|
const router = useRouter() |
|
|
|
const theme = computed(() => useSettingsStore().theme) |
|
|
|
const routes = computed(() => usePermissionStore().defaultRoutes) |
|
|
|
|
|
|
|
function click() { |
|
|
|
@ -68,6 +75,7 @@ function close() { |
|
|
|
search.value = '' |
|
|
|
options.value = [] |
|
|
|
show.value = false |
|
|
|
activeIndex.value = -1 |
|
|
|
} |
|
|
|
|
|
|
|
function change(val) { |
|
|
|
@ -149,6 +157,7 @@ function generateRoutes(routes, basePath = '', prefixTitle = []) { |
|
|
|
} |
|
|
|
|
|
|
|
function querySearch(query) { |
|
|
|
activeIndex.value = -1 |
|
|
|
if (query !== '') { |
|
|
|
options.value = fuse.value.search(query).map((item) => item.item) ?? searchPool.value |
|
|
|
} else { |
|
|
|
@ -156,6 +165,28 @@ function querySearch(query) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
function activeStyle(index) { |
|
|
|
if (index !== activeIndex.value) return {} |
|
|
|
return { |
|
|
|
"background-color": theme.value, |
|
|
|
"color": "#fff" |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
function navigateResult(direction) { |
|
|
|
if (direction === "up") { |
|
|
|
activeIndex.value = activeIndex.value <= 0 ? options.value.length - 1 : activeIndex.value - 1 |
|
|
|
} else if (direction === "down") { |
|
|
|
activeIndex.value = activeIndex.value >= options.value.length - 1 ? 0 : activeIndex.value + 1 |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
function selectActiveResult() { |
|
|
|
if (options.value.length > 0 && activeIndex.value >= 0) { |
|
|
|
change(options.value[activeIndex.value]) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
onMounted(() => { |
|
|
|
searchPool.value = generateRoutes(routes.value) |
|
|
|
}) |
|
|
|
@ -174,13 +205,15 @@ watch(searchPool, (list) => { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
.result-wrap { |
|
|
|
.result-wrap { |
|
|
|
height: 280px; |
|
|
|
margin: 10px 0; |
|
|
|
margin: 6px 0; |
|
|
|
|
|
|
|
.search-item { |
|
|
|
display: flex; |
|
|
|
height: 48px; |
|
|
|
align-items: center; |
|
|
|
padding-right: 10px; |
|
|
|
|
|
|
|
.left { |
|
|
|
width: 60px; |
|
|
|
@ -189,16 +222,17 @@ watch(searchPool, (list) => { |
|
|
|
.menu-icon { |
|
|
|
width: 18px; |
|
|
|
height: 18px; |
|
|
|
margin-top: 5px; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
.search-info { |
|
|
|
padding-left: 5px; |
|
|
|
margin-top: 10px; |
|
|
|
width: 100%; |
|
|
|
display: flex; |
|
|
|
flex-direction: column; |
|
|
|
justify-content: flex-start; |
|
|
|
flex: 1; |
|
|
|
|
|
|
|
.menu-title, |
|
|
|
.menu-path { |
|
|
|
|