|
|
@@ -1,190 +1,189 @@
|
|
|
-<template>
|
|
|
- <div :class="{'show':show}" class="header-search">
|
|
|
- <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="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>
|
|
|
-// fuse is a lightweight fuzzy-search module
|
|
|
-// make search results more in line with expectations
|
|
|
-import Fuse from 'fuse.js/dist/fuse.min.js'
|
|
|
-import path from 'path'
|
|
|
-
|
|
|
-export default {
|
|
|
- name: 'HeaderSearch',
|
|
|
- data() {
|
|
|
- return {
|
|
|
- search: '',
|
|
|
- options: [],
|
|
|
- searchPool: [],
|
|
|
- show: false,
|
|
|
- fuse: undefined
|
|
|
- }
|
|
|
- },
|
|
|
- computed: {
|
|
|
- routes() {
|
|
|
- return this.$store.getters.permission_routes
|
|
|
- }
|
|
|
- },
|
|
|
- watch: {
|
|
|
- routes() {
|
|
|
- this.searchPool = this.generateRoutes(this.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.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) {
|
|
|
- const path = val.path;
|
|
|
- if(this.ishttp(val.path)) {
|
|
|
- // http(s):// 路径新窗口打开
|
|
|
- const pindex = path.indexOf("http");
|
|
|
- window.open(path.substr(pindex, path.length), "_blank");
|
|
|
- } else {
|
|
|
- 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: '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
|
|
|
- generateRoutes(routes, basePath = '/', prefixTitle = []) {
|
|
|
- let res = []
|
|
|
-
|
|
|
- for (const router of routes) {
|
|
|
- // skip hidden router
|
|
|
- if (router.hidden) { continue }
|
|
|
-
|
|
|
- const data = {
|
|
|
- path: !this.ishttp(router.path) ? path.resolve(basePath, router.path) : router.path,
|
|
|
- title: [...prefixTitle]
|
|
|
- }
|
|
|
-
|
|
|
- if (router.meta && router.meta.title) {
|
|
|
- data.title = [...data.title, router.meta.title]
|
|
|
-
|
|
|
- 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.children) {
|
|
|
- const tempRoutes = this.generateRoutes(router.children, data.path, data.title)
|
|
|
- if (tempRoutes.length >= 1) {
|
|
|
- res = [...res, ...tempRoutes]
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- return res
|
|
|
- },
|
|
|
- querySearch(query) {
|
|
|
- if (query !== '') {
|
|
|
- this.options = this.fuse.search(query)
|
|
|
- } else {
|
|
|
- this.options = []
|
|
|
- }
|
|
|
- },
|
|
|
- ishttp(url) {
|
|
|
- return url.indexOf('http://') !== -1 || url.indexOf('https://') !== -1
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-</script>
|
|
|
-
|
|
|
-<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;
|
|
|
-
|
|
|
- ::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>
|
|
|
+<template>
|
|
|
+ <div :class="{'show':show}" class="header-search">
|
|
|
+ <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="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>
|
|
|
+// fuse is a lightweight fuzzy-search module
|
|
|
+// make search results more in line with expectations
|
|
|
+import Fuse from 'fuse.js/dist/fuse.min.js'
|
|
|
+import path from 'path'
|
|
|
+
|
|
|
+export default {
|
|
|
+ name: 'HeaderSearch',
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ search: '',
|
|
|
+ options: [],
|
|
|
+ searchPool: [],
|
|
|
+ show: false,
|
|
|
+ fuse: undefined
|
|
|
+ }
|
|
|
+ },
|
|
|
+ computed: {
|
|
|
+ routes() {
|
|
|
+ return this.$store.getters.permission_routes
|
|
|
+ }
|
|
|
+ },
|
|
|
+ watch: {
|
|
|
+ routes() {
|
|
|
+ this.searchPool = this.generateRoutes(this.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.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) {
|
|
|
+ const path = val.path;
|
|
|
+ if(this.ishttp(val.path)) {
|
|
|
+ // http(s):// 路径新窗口打开
|
|
|
+ const pindex = path.indexOf("http");
|
|
|
+ window.open(path.substr(pindex, path.length), "_blank");
|
|
|
+ } else {
|
|
|
+ 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,
|
|
|
+ minMatchCharLength: 1,
|
|
|
+ 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
|
|
|
+ generateRoutes(routes, basePath = '/', prefixTitle = []) {
|
|
|
+ let res = []
|
|
|
+
|
|
|
+ for (const router of routes) {
|
|
|
+ // skip hidden router
|
|
|
+ if (router.hidden) { continue }
|
|
|
+
|
|
|
+ const data = {
|
|
|
+ path: !this.ishttp(router.path) ? path.resolve(basePath, router.path) : router.path,
|
|
|
+ title: [...prefixTitle]
|
|
|
+ }
|
|
|
+
|
|
|
+ if (router.meta && router.meta.title) {
|
|
|
+ data.title = [...data.title, router.meta.title]
|
|
|
+
|
|
|
+ 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.children) {
|
|
|
+ const tempRoutes = this.generateRoutes(router.children, data.path, data.title)
|
|
|
+ if (tempRoutes.length >= 1) {
|
|
|
+ res = [...res, ...tempRoutes]
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return res
|
|
|
+ },
|
|
|
+ querySearch(query) {
|
|
|
+ if (query !== '') {
|
|
|
+ this.options = this.fuse.search(query)
|
|
|
+ } else {
|
|
|
+ this.options = []
|
|
|
+ }
|
|
|
+ },
|
|
|
+ ishttp(url) {
|
|
|
+ return url.indexOf('http://') !== -1 || url.indexOf('https://') !== -1
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<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;
|
|
|
+
|
|
|
+ ::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>
|