From 76aaf921dc755e0f095e62344bed659da86e7070 Mon Sep 17 00:00:00 2001
From: loulijun2021 <1694218219@qq.com>
Date: 星期二, 20 十二月 2022 12:08:38 +0800
Subject: [PATCH] 1.面包屑右上角新增搜索菜单功能

---
 src/icons/svg/search.svg              |    1 
 src/layout/components/Navbar.vue      |   35 +++++---
 package.json                          |    1 
 src/components/HeaderSearch/index.vue |  190 +++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 215 insertions(+), 12 deletions(-)

diff --git a/package.json b/package.json
index 427342e..686353e 100644
--- a/package.json
+++ b/package.json
@@ -53,6 +53,7 @@
     "element-themex": "^1.0.3",
     "eslint": "6.7.2",
     "eslint-plugin-vue": "6.2.2",
+    "fuse.js": "^6.6.2",
     "html-webpack-plugin": "3.2.0",
     "mockjs": "1.0.1-beta3",
     "px2rem-loader": "^0.1.9",
diff --git a/src/components/HeaderSearch/index.vue b/src/components/HeaderSearch/index.vue
new file mode 100644
index 0000000..20a42aa
--- /dev/null
+++ b/src/components/HeaderSearch/index.vue
@@ -0,0 +1,190 @@
+<template>
+  <div :class="{'show':show}" class="header-search">
+    <svg-icon class-name="search-icon" icon-class="search" style="color:#A7A7A7;" @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.path" :value="item" :label="item.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'
+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)
+
+    console.log(this.searchPool)
+  },
+  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) {
+      console.log(val, 1)
+      this.$router.push(val.item.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 = []) {
+      // console.log(routes, 1)
+      let res = []
+
+      for (const router of routes) {
+        // skip hidden router
+        if (router.hidden) { continue }
+
+        const data = {
+          path: path.resolve(basePath, 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]
+          }
+        }
+      }
+      // console.log(res, 2)
+      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;
+
+  .search-icon {
+    cursor: pointer;
+    font-size: 18px;
+    vertical-align: middle;
+  }
+
+  .svg-icon:hover{
+    color: #42b983 !important;
+  }
+
+  .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>
diff --git a/src/icons/svg/search.svg b/src/icons/svg/search.svg
new file mode 100644
index 0000000..84233dd
--- /dev/null
+++ b/src/icons/svg/search.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M124.884 109.812L94.256 79.166c-.357-.357-.757-.629-1.129-.914a50.366 50.366 0 0 0 8.186-27.59C101.327 22.689 78.656 0 50.67 0 22.685 0 0 22.688 0 50.663c0 27.989 22.685 50.663 50.656 50.663 10.186 0 19.643-3.03 27.6-8.201.286.385.557.771.9 1.114l30.628 30.632a10.633 10.633 0 0 0 7.543 3.129c2.728 0 5.457-1.043 7.543-3.115 4.171-4.157 4.171-10.915.014-15.073M50.671 85.338C31.557 85.338 16 69.78 16 50.663c0-19.102 15.557-34.661 34.67-34.661 19.115 0 34.657 15.559 34.657 34.675 0 19.102-15.557 34.661-34.656 34.661"/></svg>
\ No newline at end of file
diff --git a/src/layout/components/Navbar.vue b/src/layout/components/Navbar.vue
index 298570f..cafa44b 100644
--- a/src/layout/components/Navbar.vue
+++ b/src/layout/components/Navbar.vue
@@ -5,12 +5,27 @@
     <breadcrumb class="breadcrumb-container" />
 
     <div class="right-menu">
+
+      <template v-if="device!=='mobile'">
+        <search id="header-search" class="right-menu-item" />
+
+        <!--        <error-log class="errLog-container right-menu-item hover-effect" />-->
+
+        <!--        <screenfull id="screenfull" class="right-menu-item hover-effect" />-->
+
+        <!--        <el-tooltip content="Global Size" effect="dark" placement="bottom">-->
+        <!--          <size-select id="size-select" class="right-menu-item hover-effect" />-->
+        <!--        </el-tooltip>-->
+
+      </template>
+
       <el-dropdown class="avatar-container" trigger="click">
         <div class="avatar-wrapper">
           <!--          <img :src="avatar+'?imageView2/1/w/80/h/80'" class="user-avatar">-->
           <div style="display: flex;align-items: center;margin-top: -5px">
-            <div class="headerImg"><i class="el-icon-user" /></div>
-            <div class="headerName">{{ username }}</div>
+
+            <i class="el-icon-user" style="font-weight: bolder;font-size: 18px;margin-right: 5px;color:#A7A7A7" />
+            <div style=" font-size: 18px;font-family: 'Microsoft YaHei';color:#AAAAAA">{{ username }}</div>
           </div>
 
           <!--          <i class="el-icon-caret-bottom" />-->
@@ -74,17 +89,20 @@
 import Hamburger from '@/components/Hamburger'
 import { getCookie } from '@/utils/auth'
 import { UpdateUserPassword } from '@/api/user'
+import Search from '@/components/HeaderSearch'
 
 const SER_HZ = /^[\u4e00-\u9fa5]+$/
 export default {
   components: {
     Breadcrumb,
-    Hamburger
+    Hamburger,
+    Search
   },
   computed: {
     ...mapGetters([
       'sidebar',
-      'avatar'
+      'avatar',
+      'device'
     ])
   },
   created() {
@@ -206,6 +224,7 @@
     float: right;
     height: 100%;
     line-height: 50px;
+    display: flex;
 
     &:focus {
       outline: none;
@@ -236,14 +255,6 @@
         margin-top: 5px;
         position: relative;
         cursor: pointer;
-
-        .headerImg {
-          margin: 5px;
-        }
-
-        .headerName {
-          font-weight: bolder;
-        }
 
         .user-avatar {
           cursor: pointer;

--
Gitblit v1.9.3