<template>
  <div class="header-search">
    <svg-icon class-name="search-icon" icon-class="search" @click.stop="click" />
    <el-dialog
      :visible.sync="show"
      :close-on-click-modal="true"
      width="560px"
      append-to-body
      :show-close="false"
      custom-class="header-search-dialog"
      @opened="$refs.searchInput && $refs.searchInput.focus()"
    >
      <div class="search-body">
        <div class="search-input-wrap">
          <svg-icon class-name="search-prefix" icon-class="search" />
          <input
            ref="searchInput"
            v-model="search"
            class="search-input"
            placeholder="搜索菜单"
            @input="querySearch($event.target.value)"
          />
        </div>
        <ul v-if="options.length" class="search-results">
          <li
            v-for="option in options"
            :key="option.item.path"
            class="search-result-item"
            @click="change(option.item)"
          >
            <span>{{ option.item.title.join(' > ') }}</span>
          </li>
        </ul>
        <div v-if="search && options.length === 0" class="no-result">
          无匹配结果
        </div>
      </div>
    </el-dialog>
  </div>
</template>

<script>
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)
    }
  },
  mounted() {
    this.searchPool = this.generateRoutes(this.routes)
  },
  methods: {
    click() {
      this.show = true
      this.search = ''
      this.options = []
    },
    change(val) {
      if (this.ishttp(val.path)) {
        const pindex = val.path.indexOf('http')
        window.open(val.path.substr(pindex, val.path.length), '_blank')
      } else {
        this.$router.push(val.path)
      }
      this.show = false
      this.search = ''
      this.options = []
    },
    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
        }]
      })
    },
    generateRoutes(routes, basePath = '/', prefixTitle = []) {
      let res = []

      for (const router of routes) {
        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') {
            res.push(data)
          }
        }

        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 {
  .search-icon {
    cursor: pointer;
    font-size: 18px;
    vertical-align: middle;
  }
}
</style>

<style lang="scss">
.header-search-dialog {
  border-radius: 8px;

  .el-dialog__header {
    padding: 0;
  }

  .el-dialog__body {
    padding: 0;
  }

  .search-body {
    .search-input-wrap {
      display: flex;
      align-items: center;
      margin: 12px 20px;
      padding-bottom: 12px;
      border-bottom: 1px solid #e8e8e8;

      .search-prefix {
        font-size: 18px;
        color: #999;
        flex-shrink: 0;
        margin-right: 12px;
      }

      .search-input {
        flex: 1;
        border: none;
        outline: none;
        font-size: 16px;
        line-height: 32px;
        height: 32px;
        background: transparent;

        &::placeholder {
          color: #bfbfbf;
        }
      }
    }

    .search-results {
      max-height: 360px;
      overflow-y: auto;
      padding: 0;
      margin: 0;
      list-style: none;

      .search-result-item {
        padding: 10px 20px;
        cursor: pointer;
        font-size: 14px;
        color: #333;
        transition: background 0.15s;

        &:hover {
          background: #f0f2f5;
        }
      }
    }

    .no-result {
      padding: 32px 0;
      text-align: center;
      color: #999;
      font-size: 14px;
    }
  }
}
</style>
