feat(admin): add msh_single_admin project and harden ignore rules
Introduce the new Vue admin project into version control while tightening gitignore patterns to keep env files, logs, build artifacts, and test outputs out of commits. Made-with: Cursor
This commit is contained in:
188
msh_single_admin/src/components/HeaderSearch/index.vue
Executable file
188
msh_single_admin/src/components/HeaderSearch/index.vue
Executable file
@@ -0,0 +1,188 @@
|
||||
<template>
|
||||
<div :class="{ show: show }" class="header-search">
|
||||
<i class="iconfont iconios-search" style="font-size: 20px" @click.stop="click"></i>
|
||||
<!--<svg-icon class-name="search-icon" icon-class="search" @click.stop="click" />-->
|
||||
<el-select
|
||||
ref="headerSearchSelect"
|
||||
v-model="search"
|
||||
:remote-method="querySearch"
|
||||
filterable
|
||||
default-first-option
|
||||
remote
|
||||
placeholder="搜索菜单"
|
||||
class="header-search-select"
|
||||
@change="change"
|
||||
>
|
||||
<el-option v-for="item in options" :key="item.url" :value="item" :label="item.name.join(' > ')" />
|
||||
</el-select>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// fuse is a lightweight fuzzy-search module
|
||||
// make search results more in line with expectations
|
||||
import Fuse from 'fuse.js';
|
||||
import path from 'path';
|
||||
import { mapGetters } from 'vuex';
|
||||
export default {
|
||||
name: 'HeaderSearch',
|
||||
data() {
|
||||
return {
|
||||
search: '',
|
||||
options: [],
|
||||
searchPool: [],
|
||||
show: false,
|
||||
fuse: undefined,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['permission_routes']),
|
||||
// routes() {
|
||||
// return this.$store.getters.permission_routes
|
||||
// }
|
||||
},
|
||||
watch: {
|
||||
routes(n) {
|
||||
this.searchPool = this.generateRoutes(this.permission_routes);
|
||||
},
|
||||
searchPool(list) {
|
||||
this.initFuse(list);
|
||||
},
|
||||
show(value) {
|
||||
if (value) {
|
||||
document.body.addEventListener('click', this.close);
|
||||
} else {
|
||||
document.body.removeEventListener('click', this.close);
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.searchPool = this.generateRoutes(this.permission_routes);
|
||||
},
|
||||
methods: {
|
||||
click() {
|
||||
this.show = !this.show;
|
||||
if (this.show) {
|
||||
this.$refs.headerSearchSelect && this.$refs.headerSearchSelect.focus();
|
||||
}
|
||||
},
|
||||
close() {
|
||||
this.$refs.headerSearchSelect && this.$refs.headerSearchSelect.blur();
|
||||
this.options = [];
|
||||
this.show = false;
|
||||
},
|
||||
change(val) {
|
||||
this.$router.push(val.path);
|
||||
this.search = '';
|
||||
this.options = [];
|
||||
this.$nextTick(() => {
|
||||
this.show = false;
|
||||
});
|
||||
},
|
||||
initFuse(list) {
|
||||
this.fuse = new Fuse(list, {
|
||||
shouldSort: true,
|
||||
threshold: 0.4,
|
||||
location: 0,
|
||||
distance: 100,
|
||||
maxPatternLength: 32,
|
||||
minMatchCharLength: 1,
|
||||
keys: [
|
||||
{
|
||||
name: 'name',
|
||||
weight: 0.7,
|
||||
},
|
||||
{
|
||||
name: 'url',
|
||||
weight: 0.3,
|
||||
},
|
||||
],
|
||||
});
|
||||
},
|
||||
// Filter out the routes that can be displayed in the sidebar
|
||||
// And generate the internationalized title
|
||||
generateRoutes(routes, basePath = '/', prefixTitle = []) {
|
||||
let res = [];
|
||||
for (const router of routes) {
|
||||
// skip hidden router
|
||||
if (router.hidden) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const data = {
|
||||
path: path.resolve(basePath, router.url),
|
||||
name: [...prefixTitle],
|
||||
children: router.child || [],
|
||||
};
|
||||
|
||||
if (router.name) {
|
||||
data.name = [...data.name, router.name];
|
||||
|
||||
if (router.redirect !== 'noRedirect') {
|
||||
// only push the routes with title
|
||||
// special case: need to exclude parent router without redirect
|
||||
res.push(data);
|
||||
}
|
||||
}
|
||||
|
||||
// recursive child routes
|
||||
if (router.child) {
|
||||
const tempRoutes = this.generateRoutes(router.child, data.url, data.name);
|
||||
if (tempRoutes.length >= 1) {
|
||||
res = [...res, ...tempRoutes];
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
},
|
||||
querySearch(query) {
|
||||
if (query !== '') {
|
||||
this.options = this.fuse.search(query);
|
||||
} else {
|
||||
this.options = [];
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.header-search {
|
||||
font-size: 0 !important;
|
||||
display: inline-flex !important;
|
||||
cursor: pointer;
|
||||
.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;*/
|
||||
line-height: 50px;
|
||||
::v-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;
|
||||
}
|
||||
}
|
||||
|
||||
&.show {
|
||||
.header-search-select {
|
||||
width: 210px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user