From 6e42b4c896a712bad9a4494c4bedd9a3df163daf Mon Sep 17 00:00:00 2001
From: Pan <panfree23@gmail.com>
Date: Fri, 1 Feb 2019 14:09:29 +0800
Subject: [PATCH 1/6] perf: fixed eslint errors

---
 src/views/layout/components/Sidebar/Link.vue  |  7 ++---
 .../layout/components/Sidebar/SidebarItem.vue | 28 ++++++++++---------
 src/views/table/dragTable.vue                 |  2 +-
 3 files changed, 18 insertions(+), 19 deletions(-)

diff --git a/src/views/layout/components/Sidebar/Link.vue b/src/views/layout/components/Sidebar/Link.vue
index 5d366f24..cd2e0413 100644
--- a/src/views/layout/components/Sidebar/Link.vue
+++ b/src/views/layout/components/Sidebar/Link.vue
@@ -1,6 +1,6 @@
 
 <template>
-  <!-- eslint-disable vue/require-component-is-->
+  <!-- eslint-disable vue/require-component-is -->
   <component v-bind="linkProps(to)">
     <slot/>
   </component>
@@ -17,11 +17,8 @@ export default {
     }
   },
   methods: {
-    isExternalLink(routePath) {
-      return isExternal(routePath)
-    },
     linkProps(url) {
-      if (this.isExternalLink(url)) {
+      if (isExternal(url)) {
         return {
           is: 'a',
           href: url,
diff --git a/src/views/layout/components/Sidebar/SidebarItem.vue b/src/views/layout/components/Sidebar/SidebarItem.vue
index 8a9b4396..56edf9f7 100644
--- a/src/views/layout/components/Sidebar/SidebarItem.vue
+++ b/src/views/layout/components/Sidebar/SidebarItem.vue
@@ -14,20 +14,22 @@
         <item v-if="item.meta" :icon="item.meta.icon" :title="generateTitle(item.meta.title)" />
       </template>
 
-      <template v-for="child in item.children" v-if="!child.hidden">
-        <sidebar-item
-          v-if="child.children&&child.children.length>0"
-          :is-nest="true"
-          :item="child"
-          :key="child.path"
-          :base-path="resolvePath(child.path)"
-          class="nest-menu" />
+      <template v-for="child in item.children">
+        <template v-if="!child.hidden">
+          <sidebar-item
+            v-if="child.children&&child.children.length>0"
+            :is-nest="true"
+            :item="child"
+            :key="child.path"
+            :base-path="resolvePath(child.path)"
+            class="nest-menu" />
 
-        <app-link v-else :to="resolvePath(child.path)" :key="child.name">
-          <el-menu-item :index="resolvePath(child.path)">
-            <item v-if="child.meta" :icon="child.meta.icon" :title="generateTitle(child.meta.title)" />
-          </el-menu-item>
-        </app-link>
+          <app-link v-else :to="resolvePath(child.path)" :key="child.name">
+            <el-menu-item :index="resolvePath(child.path)">
+              <item v-if="child.meta" :icon="child.meta.icon" :title="generateTitle(child.meta.title)" />
+            </el-menu-item>
+          </app-link>
+        </template>
       </template>
     </el-submenu>
 
diff --git a/src/views/table/dragTable.vue b/src/views/table/dragTable.vue
index 8f52c5de..3f3fb941 100644
--- a/src/views/table/dragTable.vue
+++ b/src/views/table/dragTable.vue
@@ -46,7 +46,7 @@
       </el-table-column>
 
       <el-table-column align="center" label="Drag" width="80">
-        <template slot-scope="scope">
+        <template slot-scope="{}">
           <svg-icon class="drag-handler" icon-class="drag"/>
         </template>
       </el-table-column>

From dd9fb09a293aa5d8332a5b8a9f9a70ff39deeb52 Mon Sep 17 00:00:00 2001
From: Pan <panfree23@gmail.com>
Date: Mon, 11 Feb 2019 14:15:55 +0800
Subject: [PATCH 2/6] perf[Lang]: make up for miss keywords

---
 src/lang/en.js      | 1 +
 src/lang/es.js      | 1 +
 src/lang/zh.js      | 1 +
 src/router/index.js | 4 ++--
 4 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/src/lang/en.js b/src/lang/en.js
index 2af355b1..ef98af4b 100644
--- a/src/lang/en.js
+++ b/src/lang/en.js
@@ -58,6 +58,7 @@ export default {
     selectExcel: 'Export Selected',
     uploadExcel: 'Upload Excel',
     zip: 'Zip',
+    pdf: 'PDF',
     exportZip: 'Export Zip',
     theme: 'Theme',
     clipboardDemo: 'Clipboard',
diff --git a/src/lang/es.js b/src/lang/es.js
index 1268f083..ed71fc15 100755
--- a/src/lang/es.js
+++ b/src/lang/es.js
@@ -58,6 +58,7 @@ export default {
     selectExcel: 'Export seleccionado',
     uploadExcel: 'Subir Excel',
     zip: 'Zip',
+    pdf: 'PDF',
     exportZip: 'Exportar a Zip',
     theme: 'Tema',
     clipboardDemo: 'Clipboard',
diff --git a/src/lang/zh.js b/src/lang/zh.js
index 4371713f..7da0ccee 100644
--- a/src/lang/zh.js
+++ b/src/lang/zh.js
@@ -58,6 +58,7 @@ export default {
     selectExcel: 'Export Selected',
     uploadExcel: 'Upload Excel',
     zip: 'Zip',
+    pdf: 'PDF',
     exportZip: 'Export Zip',
     theme: '换肤',
     clipboardDemo: 'Clipboard',
diff --git a/src/router/index.js b/src/router/index.js
index f42046ee..ce2b0d84 100644
--- a/src/router/index.js
+++ b/src/router/index.js
@@ -297,13 +297,13 @@ export const asyncRouterMap = [
     path: '/pdf',
     component: Layout,
     redirect: '/pdf/index',
-    meta: { title: 'PDF', icon: 'pdf' },
+    meta: { title: 'pdf', icon: 'pdf' },
     children: [
       {
         path: 'index',
         component: () => import('@/views/pdf/index'),
         name: 'PDF',
-        meta: { title: 'PDF' }
+        meta: { title: 'pdf' }
       }
     ]
   },

From 0b6e7515ce791d83fbbeb29fcbc8e567cbb65d0e Mon Sep 17 00:00:00 2001
From: Pan <panfree23@gmail.com>
Date: Mon, 11 Feb 2019 14:51:09 +0800
Subject: [PATCH 3/6] perf: optimize some code

---
 src/components/Kanban/index.vue  | 4 ++--
 src/components/SvgIcon/index.vue | 2 +-
 src/router/index.js              | 3 +--
 3 files changed, 4 insertions(+), 5 deletions(-)

diff --git a/src/components/Kanban/index.vue b/src/components/Kanban/index.vue
index 4975dbdd..dadeb648 100644
--- a/src/components/Kanban/index.vue
+++ b/src/components/Kanban/index.vue
@@ -41,7 +41,7 @@ export default {
   }
 }
 </script>
-<style lang="scss">
+<style lang="scss" scoped>
 .board-column {
   min-width: 300px;
   min-height: 100px;
@@ -81,7 +81,7 @@ export default {
       line-height: 54px;
       padding: 5px 10px;
       box-sizing: border-box;
-      box-shadow: 0px 1px 3px 0 rgba(0,0,0,0.2);
+      box-shadow: 0px 1px 3px 0 rgba(0, 0, 0, 0.2);
     }
   }
 }
diff --git a/src/components/SvgIcon/index.vue b/src/components/SvgIcon/index.vue
index 12a1f58d..b0b6d4cb 100644
--- a/src/components/SvgIcon/index.vue
+++ b/src/components/SvgIcon/index.vue
@@ -1,5 +1,5 @@
 <template>
-  <svg :class="svgClass" aria-hidden="true">
+  <svg :class="svgClass" aria-hidden="true" v-on="$listeners">
     <use :xlink:href="iconName"/>
   </svg>
 </template>
diff --git a/src/router/index.js b/src/router/index.js
index ce2b0d84..dda18156 100644
--- a/src/router/index.js
+++ b/src/router/index.js
@@ -297,13 +297,12 @@ export const asyncRouterMap = [
     path: '/pdf',
     component: Layout,
     redirect: '/pdf/index',
-    meta: { title: 'pdf', icon: 'pdf' },
     children: [
       {
         path: 'index',
         component: () => import('@/views/pdf/index'),
         name: 'PDF',
-        meta: { title: 'pdf' }
+        meta: { title: 'pdf', icon: 'pdf' }
       }
     ]
   },

From 24ee761809d8ffd8726c88f5a741dd2b169e3433 Mon Sep 17 00:00:00 2001
From: Pan <panfree23@gmail.com>
Date: Mon, 11 Feb 2019 17:42:31 +0800
Subject: [PATCH 4/6] perf[Navbar]: refactor navbar style

---
 src/components/Breadcrumb/index.vue    |  2 +-
 src/components/ErrorLog/index.vue      | 29 ++-----------
 src/components/Hamburger/index.vue     |  7 ++--
 src/components/LangSelect/index.vue    |  9 ----
 src/components/Screenfull/index.vue    | 39 +-----------------
 src/components/SizeSelect/index.vue    |  9 ----
 src/components/ThemePicker/index.vue   |  5 ++-
 src/icons/svg/screenfull.svg           |  1 +
 src/views/layout/components/Navbar.vue | 57 +++++++++++++++-----------
 9 files changed, 48 insertions(+), 110 deletions(-)
 create mode 100644 src/icons/svg/screenfull.svg

diff --git a/src/components/Breadcrumb/index.vue b/src/components/Breadcrumb/index.vue
index 5bc7a1b8..5f4d054f 100644
--- a/src/components/Breadcrumb/index.vue
+++ b/src/components/Breadcrumb/index.vue
@@ -63,7 +63,7 @@ export default {
     display: inline-block;
     font-size: 14px;
     line-height: 50px;
-    margin-left: 10px;
+    margin-left: 8px;
     .no-redirect {
       color: #97a8be;
       cursor: text;
diff --git a/src/components/ErrorLog/index.vue b/src/components/ErrorLog/index.vue
index 1fd883d0..c46cf110 100644
--- a/src/components/ErrorLog/index.vue
+++ b/src/components/ErrorLog/index.vue
@@ -1,21 +1,8 @@
 <template>
   <div v-if="errorLogs.length>0">
-    <el-badge :is-dot="true" style="line-height: 30px;" @click.native="dialogTableVisible=true">
-      <el-button size="small" type="danger" class="bug-btn">
-        <svg
-          t="1492682037685"
-          class="bug-svg"
-          viewBox="0 0 1024 1024"
-          version="1.1"
-          xmlns="http://www.w3.org/2000/svg"
-          p-id="1863"
-          xmlns:xlink="http://www.w3.org/1999/xlink"
-          width="128"
-          height="128">
-          <path
-            d="M969.142857 548.571429q0 14.848-10.861714 25.709714t-25.709714 10.861714l-128 0q0 97.718857-38.290286 165.705143l118.857143 119.442286q10.861714 10.861714 10.861714 25.709714t-10.861714 25.709714q-10.276571 10.861714-25.709714 10.861714t-25.709714-10.861714l-113.152-112.566857q-2.852571 2.852571-8.557714 7.424t-23.990857 16.274286-37.156571 20.845714-46.848 16.566857-55.442286 7.424l0-512-73.142857 0 0 512q-29.147429 0-58.002286-7.716571t-49.700571-18.870857-37.705143-22.272-24.868571-18.578286l-8.557714-8.009143-104.557714 118.272q-11.446857 11.995429-27.428571 11.995429-13.714286 0-24.576-9.142857-10.861714-10.276571-11.702857-25.417143t8.850286-26.587429l115.419429-129.718857q-33.133714-65.133714-33.133714-156.562286l-128 0q-14.848 0-25.709714-10.861714t-10.861714-25.709714 10.861714-25.709714 25.709714-10.861714l128 0 0-168.009143-98.852571-98.852571q-10.861714-10.861714-10.861714-25.709714t10.861714-25.709714 25.709714-10.861714 25.709714 10.861714l98.852571 98.852571 482.304 0 98.852571-98.852571q10.861714-10.861714 25.709714-10.861714t25.709714 10.861714 10.861714 25.709714-10.861714 25.709714l-98.852571 98.852571 0 168.009143 128 0q14.848 0 25.709714 10.861714t10.861714 25.709714zM694.857143 219.428571l-365.714286 0q0-75.995429 53.430857-129.426286t129.426286-53.430857 129.426286 53.430857 53.430857 129.426286z"
-            p-id="1864"/>
-        </svg>
+    <el-badge :is-dot="true" style="line-height: 25px;margin-top: -5px;" @click.native="dialogTableVisible=true">
+      <el-button style="padding: 8px 10px;" size="small" type="danger">
+        <svg-icon icon-class="bug" />
       </el-button>
     </el-badge>
 
@@ -67,16 +54,6 @@ export default {
 </script>
 
 <style scoped>
-.bug-btn.el-button--small {
-  padding: 9px 10px;
-}
-.bug-svg {
-  width: 1em;
-  height: 1em;
-  vertical-align: -0.15em;
-  fill: currentColor;
-  overflow: hidden;
-}
 .message-title {
   font-size: 16px;
   color: #333;
diff --git a/src/components/Hamburger/index.vue b/src/components/Hamburger/index.vue
index 220d67ec..ca7457c1 100644
--- a/src/components/Hamburger/index.vue
+++ b/src/components/Hamburger/index.vue
@@ -1,5 +1,5 @@
 <template>
-  <div>
+  <div style="padding: 0 15px;" @click="toggleClick">
     <svg
       :class="{'is-active':isActive}"
       class="hamburger"
@@ -7,7 +7,7 @@
       xmlns="http://www.w3.org/2000/svg"
       width="64"
       height="64"
-      @click="toggleClick">
+    >
       <path d="M408 442h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-8 204c0 4.4 3.6 8 8 8h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56zm504-486H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 632H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM142.4 642.1L298.7 519a8.84 8.84 0 0 0 0-13.9L142.4 381.9c-5.8-4.6-14.4-.5-14.4 6.9v246.3a8.9 8.9 0 0 0 14.4 7z" />
     </svg>
   </div>
@@ -32,10 +32,11 @@ export default {
 <style scoped>
 .hamburger {
   display: inline-block;
-  cursor: pointer;
+  vertical-align: middle;
   width: 20px;
   height: 20px;
 }
+
 .hamburger.is-active {
   transform: rotate(180deg);
 }
diff --git a/src/components/LangSelect/index.vue b/src/components/LangSelect/index.vue
index ef5f2c44..fea7ba71 100644
--- a/src/components/LangSelect/index.vue
+++ b/src/components/LangSelect/index.vue
@@ -30,12 +30,3 @@ export default {
   }
 }
 </script>
-
-<style scoped>
-.international-icon {
-  font-size: 20px;
-  cursor: pointer;
-  vertical-align: -5px!important;
-}
-</style>
-
diff --git a/src/components/Screenfull/index.vue b/src/components/Screenfull/index.vue
index 4cdcb568..5801ba4a 100644
--- a/src/components/Screenfull/index.vue
+++ b/src/components/Screenfull/index.vue
@@ -1,29 +1,6 @@
 <template>
   <div>
-    <svg
-      t="1508738709248"
-      class="screenfull-svg"
-      viewBox="0 0 1024 1024"
-      version="1.1"
-      xmlns="http://www.w3.org/2000/svg"
-      p-id="2069"
-      xmlns:xlink="http://www.w3.org/1999/xlink"
-      width="32"
-      height="32"
-      @click="click">
-      <path
-        d="M333.493443 428.647617 428.322206 333.832158 262.572184 168.045297 366.707916 64.444754 64.09683 64.444754 63.853283 366.570793 167.283957 262.460644Z"
-        p-id="2070"/>
-      <path
-        d="M854.845439 760.133334 688.61037 593.95864 593.805144 688.764889 759.554142 854.56096 655.44604 958.161503 958.055079 958.161503 958.274066 656.035464Z"
-        p-id="2071"/>
-      <path
-        d="M688.535669 428.550403 854.31025 262.801405 957.935352 366.921787 957.935352 64.34754 655.809313 64.081481 759.919463 167.535691 593.70793 333.731874Z"
-        p-id="2072"/>
-      <path
-        d="M333.590658 594.033341 167.8171 759.804852 64.218604 655.67219 64.218604 958.270996 366.342596 958.502263 262.234493 855.071589 428.421466 688.86108Z"
-        p-id="2073"/>
-    </svg>
+    <svg-icon class-name="screenfull-icon" icon-class="screenfull" />
   </div>
 </template>
 
@@ -32,20 +9,6 @@ import screenfull from 'screenfull'
 
 export default {
   name: 'Screenfull',
-  props: {
-    width: {
-      type: Number,
-      default: 22
-    },
-    height: {
-      type: Number,
-      default: 22
-    },
-    fill: {
-      type: String,
-      default: '#48576a'
-    }
-  },
   data() {
     return {
       isFullscreen: false
diff --git a/src/components/SizeSelect/index.vue b/src/components/SizeSelect/index.vue
index a92a17c3..6d3cd43a 100644
--- a/src/components/SizeSelect/index.vue
+++ b/src/components/SizeSelect/index.vue
@@ -53,12 +53,3 @@ export default {
 
 }
 </script>
-
-<style scoped>
-.size-icon {
-  font-size: 20px;
-  cursor: pointer;
-  vertical-align: -4px!important;
-}
-</style>
-
diff --git a/src/components/ThemePicker/index.vue b/src/components/ThemePicker/index.vue
index 5d1ff8bd..332b07e7 100644
--- a/src/components/ThemePicker/index.vue
+++ b/src/components/ThemePicker/index.vue
@@ -136,7 +136,10 @@ export default {
 
 <style>
 .theme-picker .el-color-picker__trigger {
-  vertical-align: middle;
+  margin-top: 12px;
+  height: 26px!important;
+  width: 26px!important;
+  padding: 2px;
 }
 
 .theme-picker-dropdown .el-color-dropdown__link-btn {
diff --git a/src/icons/svg/screenfull.svg b/src/icons/svg/screenfull.svg
new file mode 100644
index 00000000..0e86b6fa
--- /dev/null
+++ b/src/icons/svg/screenfull.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M38.47 52L52 38.462l-23.648-23.67L43.209 0H.035L0 43.137l14.757-14.865L38.47 52zm74.773 47.726L89.526 76 76 89.536l23.648 23.672L84.795 128h43.174L128 84.863l-14.757 14.863zM89.538 52l23.668-23.648L128 43.207V.038L84.866 0 99.73 14.76 76 38.472 89.538 52zM38.46 76L14.792 99.651 0 84.794v43.173l43.137.033-14.865-14.757L52 89.53 38.46 76z"/></svg>
\ No newline at end of file
diff --git a/src/views/layout/components/Navbar.vue b/src/views/layout/components/Navbar.vue
index 208186e3..018ef0f9 100644
--- a/src/views/layout/components/Navbar.vue
+++ b/src/views/layout/components/Navbar.vue
@@ -9,17 +9,17 @@
         <error-log class="errLog-container right-menu-item"/>
 
         <el-tooltip :content="$t('navbar.screenfull')" effect="dark" placement="bottom">
-          <screenfull class="screenfull right-menu-item"/>
+          <screenfull class="right-menu-item"/>
         </el-tooltip>
 
         <el-tooltip :content="$t('navbar.size')" effect="dark" placement="bottom">
-          <size-select class="international right-menu-item"/>
+          <size-select class="right-menu-item"/>
         </el-tooltip>
 
-        <lang-select class="international right-menu-item"/>
+        <lang-select class="right-menu-item"/>
 
         <el-tooltip :content="$t('navbar.theme')" effect="dark" placement="bottom">
-          <theme-picker class="theme-switch right-menu-item"/>
+          <theme-picker class="theme-picker right-menu-item"/>
         </el-tooltip>
       </template>
 
@@ -92,42 +92,52 @@ export default {
 <style rel="stylesheet/scss" lang="scss" scoped>
 .navbar {
   height: 50px;
-  line-height: 50px;
-  border-radius: 0px !important;
+  overflow: hidden;
+
   .hamburger-container {
-    line-height: 58px;
-    height: 50px;
+    line-height: 46px;
+    height: 100%;
     float: left;
-    padding: 0 10px;
+    cursor: pointer;
+    transition: background .3s;
+    &:hover {
+      background: rgba(0, 0, 0, .025)
+    }
   }
-  .breadcrumb-container{
+
+  .breadcrumb-container {
     float: left;
   }
+
   .errLog-container {
     display: inline-block;
     vertical-align: top;
   }
+
   .right-menu {
     float: right;
     height: 100%;
-    &:focus{
-     outline: none;
+    line-height: 50px;
+
+    &:focus {
+      outline: none;
     }
+
     .right-menu-item {
+      cursor: pointer;
       display: inline-block;
-      margin: 0 8px;
-    }
-    .screenfull {
-      height: 20px;
-    }
-    .international{
-      vertical-align: top;
-    }
-    .theme-switch {
-      vertical-align: 15px;
+      padding: 0 8px;
+      height: 100%;
+      font-size: 20px;
+      color: #5a5e66;
+      vertical-align: text-bottom;
+      transition: background .3s;
+      &:hover {
+        background: rgba(0, 0, 0, .025)
+      }
     }
+
     .avatar-container {
-      height: 50px;
       margin-right: 30px;
       .avatar-wrapper {
         margin-top: 5px;
@@ -138,6 +148,7 @@ export default {
           height: 40px;
           border-radius: 10px;
         }
+
         .el-icon-caret-bottom {
           cursor: pointer;
           position: absolute;

From fe381503eb0f6700ea18a9405e38c0d7cd16132e Mon Sep 17 00:00:00 2001
From: Pan <panfree23@gmail.com>
Date: Mon, 11 Feb 2019 17:52:53 +0800
Subject: [PATCH 5/6] perf[Login]: refine css

---
 src/views/login/index.vue | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/src/views/login/index.vue b/src/views/login/index.vue
index a44c6ad3..634c32da 100644
--- a/src/views/login/index.vue
+++ b/src/views/login/index.vue
@@ -262,8 +262,10 @@ $light_gray:#eee;
     .set-language {
       color: #fff;
       position: absolute;
-      top: 5px;
+      top: 3px;
+      font-size:18px;
       right: 0px;
+      cursor: pointer;
     }
   }
   .show-pwd {

From c71f3110fb415c5da940f3436d5c8ff3244659c9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E8=8A=B1=E8=A3=A4=E8=A1=A9?= <panfree23@gmail.com>
Date: Wed, 13 Feb 2019 15:09:14 +0800
Subject: [PATCH 6/6] feature[Navbar]: add header-search component (#1591)

* init

* init

* refactor search function by fuse

* fix bug

* fix bug

* tweak
---
 package.json                           |   1 +
 src/components/HeaderSearch/index.vue  | 187 +++++++++++++++++++++++++
 src/icons/svg/search.svg               |   1 +
 src/views/layout/components/Navbar.vue |  35 +++--
 4 files changed, 212 insertions(+), 12 deletions(-)
 create mode 100644 src/components/HeaderSearch/index.vue
 create mode 100644 src/icons/svg/search.svg

diff --git a/package.json b/package.json
index 83e93bce..5854b8d6 100644
--- a/package.json
+++ b/package.json
@@ -43,6 +43,7 @@
     "echarts": "4.1.0",
     "element-ui": "2.4.11",
     "file-saver": "1.3.8",
+    "fuse.js": "3.4.2",
     "js-cookie": "2.2.0",
     "jsonlint": "1.6.3",
     "jszip": "3.1.5",
diff --git a/src/components/HeaderSearch/index.vue b/src/components/HeaderSearch/index.vue
new file mode 100644
index 00000000..ab0d556a
--- /dev/null
+++ b/src/components/HeaderSearch/index.vue
@@ -0,0 +1,187 @@
+<template>
+  <div :class="{'show':show}" class="header-search">
+    <svg-icon class-name="search-icon" icon-class="search" @click="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="item in options" :key="item.path" :value="item" :label="item.title.join(' > ')"/>
+    </el-select>
+  </div>
+</template>
+
+<script>
+import Fuse from 'fuse.js'
+import path from 'path'
+import i18n from '@/lang'
+
+export default {
+  name: 'HeaderSearch',
+  data() {
+    return {
+      search: '',
+      options: [],
+      searchPool: [],
+      show: false,
+      fuse: undefined
+    }
+  },
+  computed: {
+    routers() {
+      return this.$store.getters.permission_routers
+    },
+    lang() {
+      return this.$store.getters.language
+    }
+  },
+  watch: {
+    lang() {
+      this.searchPool = this.generateRouters(this.routers)
+    },
+    routers() {
+      this.searchPool = this.generateRouters(this.routers)
+    },
+    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.generateRouters(this.routers)
+  },
+  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: '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
+    generateRouters(routers, basePath = '/', prefixTitle = []) {
+      let res = []
+
+      for (const router of routers) {
+        // skip hidden router
+        if (router.hidden) { continue }
+
+        const data = {
+          path: path.resolve(basePath, router.path),
+          title: [...prefixTitle]
+        }
+
+        if (router.meta && router.meta.title) {
+          // generate internationalized title
+          const i18ntitle = i18n.t(`route.${router.meta.title}`)
+
+          data.title = [...data.title, i18ntitle]
+
+          if (router.redirect !== 'noredirect') {
+            // only push the routes with title
+            // special case: need to exclude parent router without redirect
+            res.push(data)
+          }
+        }
+
+        // recursive child routers
+        if (router.children) {
+          const tempRouters = this.generateRouters(router.children, data.path, data.title)
+          if (tempRouters.length >= 1) {
+            res = [...res, ...tempRouters]
+          }
+        }
+      }
+      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;
+  }
+
+  .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;
+
+    /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 00000000..84233dda
--- /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/views/layout/components/Navbar.vue b/src/views/layout/components/Navbar.vue
index 018ef0f9..dcb09ec1 100644
--- a/src/views/layout/components/Navbar.vue
+++ b/src/views/layout/components/Navbar.vue
@@ -6,24 +6,26 @@
 
     <div class="right-menu">
       <template v-if="device!=='mobile'">
-        <error-log class="errLog-container right-menu-item"/>
+        <search class="right-menu-item" />
+
+        <error-log class="errLog-container right-menu-item hover-effect"/>
 
         <el-tooltip :content="$t('navbar.screenfull')" effect="dark" placement="bottom">
-          <screenfull class="right-menu-item"/>
+          <screenfull class="right-menu-item hover-effect"/>
         </el-tooltip>
 
         <el-tooltip :content="$t('navbar.size')" effect="dark" placement="bottom">
-          <size-select class="right-menu-item"/>
+          <size-select class="right-menu-item hover-effect"/>
         </el-tooltip>
 
-        <lang-select class="right-menu-item"/>
+        <lang-select class="right-menu-item hover-effect"/>
 
         <el-tooltip :content="$t('navbar.theme')" effect="dark" placement="bottom">
-          <theme-picker class="theme-picker right-menu-item"/>
+          <theme-picker class="right-menu-item hover-effect"/>
         </el-tooltip>
       </template>
 
-      <el-dropdown class="avatar-container right-menu-item" trigger="click">
+      <el-dropdown class="avatar-container right-menu-item hover-effect" trigger="click">
         <div class="avatar-wrapper">
           <img :src="avatar+'?imageView2/1/w/80/h/80'" class="user-avatar">
           <i class="el-icon-caret-bottom"/>
@@ -57,6 +59,7 @@ import Screenfull from '@/components/Screenfull'
 import SizeSelect from '@/components/SizeSelect'
 import LangSelect from '@/components/LangSelect'
 import ThemePicker from '@/components/ThemePicker'
+import Search from '@/components/HeaderSearch'
 
 export default {
   components: {
@@ -66,7 +69,8 @@ export default {
     Screenfull,
     SizeSelect,
     LangSelect,
-    ThemePicker
+    ThemePicker,
+    Search
   },
   computed: {
     ...mapGetters([
@@ -100,6 +104,7 @@ export default {
     float: left;
     cursor: pointer;
     transition: background .3s;
+
     &:hover {
       background: rgba(0, 0, 0, .025)
     }
@@ -124,24 +129,30 @@ export default {
     }
 
     .right-menu-item {
-      cursor: pointer;
       display: inline-block;
       padding: 0 8px;
       height: 100%;
-      font-size: 20px;
+      font-size: 18px;
       color: #5a5e66;
       vertical-align: text-bottom;
-      transition: background .3s;
-      &:hover {
-        background: rgba(0, 0, 0, .025)
+
+      &.hover-effect {
+        cursor: pointer;
+        transition: background .3s;
+
+        &:hover {
+          background: rgba(0, 0, 0, .025)
+        }
       }
     }
 
     .avatar-container {
       margin-right: 30px;
+
       .avatar-wrapper {
         margin-top: 5px;
         position: relative;
+
         .user-avatar {
           cursor: pointer;
           width: 40px;