<template>
  <div class="ec-menu-view">
    <el-input v-if="showFilter" class="ec-filter" placeholder="菜单名称" :clearable="true" suffix-icon="el-icon-search" size="small" v-model="filterText" />
    <el-menu ref="menu" :default-active="defaultActive" class="ec-left-menu" @open="handleOpen" @close="handleClose" :collapse="collapse" @select="handleSelect" text-color="#999999">
      <template v-for="item of filterMenuData">
        <el-submenu :index="item.menuId" v-if="item.children && item.children.length" :key="item.menuId">
          <template slot="title">
            <i :class="[item.menuIcon, { 'ec-icon-active': indexPath.indexOf(item.menuId) > -1 }]" />
            <span class="ec-menu-title" :class="indexPath.indexOf(item.menuId) > -1 ? 'ec-title-active' : ''" v-html="item.menuTitle" />
          </template>
          <template v-for="subItem of item.children">
            <el-submenu :index="subItem.menuId" v-if="subItem.children && subItem.children.length" :key="subItem.menuId">
              <template slot="title">
                <i :class="[subItem.menuIcon, { 'ec-icon-active': indexPath.indexOf(subItem.menuId) > -1 }]" />
                <span :class="indexPath.indexOf(subItem.menuId) > -1 ? 'ec-title-active' : ''" v-html="subItem.menuTitle" />
              </template>
              <el-menu-item v-for="menu of subItem.children" :index="menu.menuId" :key="menu.menuId">
                <i :class="menu.menuIcon" />
                <span slot="title" v-html="menu.menuTitle" />
              </el-menu-item>
            </el-submenu>
            <el-menu-item :index="subItem.menuId" :key="subItem.menuId" v-else>
              <i :class="subItem.menuIcon" />
              <span slot="title" v-html="subItem.menuTitle" />
            </el-menu-item>
          </template>
        </el-submenu>
        <el-menu-item :index="item.menuId" :key="item.menuId" v-else>
          <i :class="item.menuIcon" />
          <span slot="title" class="ec-menu-title" v-html="item.menuTitle" />
        </el-menu-item>
      </template>
    </el-menu>
    <div class="ec-no-data" v-if="!filterMenuData || !filterMenuData.length">
      暂无菜单数据
    </div>
  </div>
</template>

<script lang="ts">
import { Prop, Watch } from "vue-property-decorator";
import Vue from "vue";
import Component from "vue-class-component";
import { Input, Menu, Submenu, MenuItem } from "element-ui";
import { MenuData } from "@/components/left-menu/model/MenuData";
import apiService from "@/components/services/api.service";
import { DataOutput } from "@/components/model/DataOutput";

/**
 * @Description: 左侧菜单组件
 * @author LiuBo
 * @date 2020/12/10
 * @time 9:16
 */
@Component({
  name: "EcLeftMenu",
  components: {
    "el-input": Input,
    "el-menu": Menu,
    "el-submenu": Submenu,
    "el-menu-item": MenuItem
  }
})
export default class LeftMenu extends Vue {
  filterText = null; // 搜索菜单的文字
  indexPath = []; // 选中的菜单项index集合
  $refs!: { menu: Menu }; // element-ui菜单对象
  @Prop({ default: false }) collapse: boolean | undefined; // 是否水平折叠收起菜单
  @Prop({ default: null }) defaultActive: string | undefined; // 当前激活菜单的 index
  @Prop({ default: true }) showFilter: boolean | undefined; // 是否显示搜索过滤栏
  @Prop({ default: null }) sysId: string | undefined; // 需要查询菜单的系统id
  menuData: MenuData[] | undefined = []; // 菜单数据
  filterMenuData: MenuData[] | undefined = []; // 过滤后的菜单数据
  openIdArr: any[] = []; // 已经打开的菜单编号集合

  @Watch("filterText") // 监听过滤框的数据
  getFilterText(val: string) {
    if (!val) {
      this.filterMenuData = this.menuData;
      for (const id of this.openIdArr) {
        this.close(id);
      }
      this.openIdArr = [];
    } else {
      this.filterMenu(val);
      for (const id of this.openIdArr) {
        if (this.filterMenuData && this.filterMenuData.length) {
          setTimeout(() => {
            this.open(id);
          });
        }
      }
    }
  }
  /**
   * @Description: 过滤菜单
   * @author LiuBo
   * @date 2020/12/10
   * @time 11:32
   * @param val 搜索关键字
   */
  private filterMenu(val: string) {
    const menuData = JSON.parse(JSON.stringify(this.menuData)); // 复制
    const replaceVal = `<span class="ec-search-text">${val}</span>`; // 替换的文字
    // 过滤一级菜单
    this.filterMenuData = menuData.filter((item: MenuData) => {
      if (item.children && item.children.length) {
        // 过滤二级菜单
        item.children = item.children.filter((subItem: MenuData) => {
          if (subItem.children && subItem.children.length) {
            // 过滤三级菜单
            subItem.children = subItem.children.filter((menu: MenuData) => {
              menu.menuTitle = menu.menuTitle.replace(val, replaceVal); // 文字高亮
              return menu.menuTitle.indexOf(val) > -1 || subItem.menuTitle.indexOf(val) > -1 || item.menuTitle.indexOf(val) > -1;
            });
            const hasLastMenu = !!subItem.children.length; // 是否过滤到数据
            if (hasLastMenu && !this.openIdArr.find(id => id === subItem.menuId)) {
              this.openIdArr.push(subItem.menuId); // 保存非叶子菜单的id
            }
            subItem.menuTitle = subItem.menuTitle.replace(val, replaceVal); // 文字高亮
            return hasLastMenu || item.menuTitle.indexOf(val) > -1;
          } else {
            subItem.menuTitle = subItem.menuTitle.replace(val, replaceVal); // 文字高亮
            return subItem.menuTitle.indexOf(val) > -1 || item.menuTitle.indexOf(val) > -1;
          }
        });
        const hasSubMenu = !!item.children.length; // 是否过滤到数据
        if (hasSubMenu && !this.openIdArr.find(id => id === item.menuId)) {
          this.openIdArr.push(item.menuId);
        }
        item.menuTitle = item.menuTitle.replace(val, replaceVal); // 文字高亮
        return hasSubMenu;
      } else {
        item.menuTitle = item.menuTitle.replace(val, replaceVal); // 文字高亮
        return item.menuTitle.indexOf(val) > -1;
      }
    });
  }
  /**折叠菜单打开事件*/
  handleOpen(key: any, keyPath: any) {
    this.$emit("open", key, keyPath);
  }
  /**折叠菜单关闭事件*/
  handleClose(key: any, keyPath: any) {
    this.$emit("close", key, keyPath);
  }
  /**叶子菜单选中事件*/
  handleSelect(index: any, indexPath: any) {
    this.indexPath = indexPath;
    let menuItem: any = {}; // 被选中的菜单数据对象
    for (const idx of indexPath) {
      if (!menuItem.path && this.menuData) {
        menuItem = this.menuData.find((val: MenuData) => val.menuId === idx);
      } else {
        menuItem = menuItem.children.find((val: MenuData) => val.menuId === idx);
      }
    }
    this.$emit("select", index, menuItem.path);
  }
  /**
   * @Description: 折叠菜单打开
   * @author LiuBo
   * @date 2020/12/9
   * @time 21:03
   * @param menuId  需要打开的 sub-menu 的 menuId
   */
  open(menuId: string) {
    try {
      this.$refs.menu.open(menuId);
    } catch (e) {
      console.log("open menu throw Error");
    }
  }
  /**
   * @Description: 折叠菜单关闭
   * @author LiuBo
   * @date 2020/12/9
   * @time 21:04
   * @param menuId  需要打开的 sub-menu 的 menuId
   */
  close(menuId: string) {
    this.$refs.menu.close(menuId);
  }
  /**
   * @Description: 查询菜单数据
   * @author LiuBo
   * @date 2020/12/10
   * @time 17:36
   */
  private selectMenuData() {
    apiService
      .fetch(
        "/api/ebtc/auth/router",
        null,
        {
          param: {
            userId: "liubo",
            sysId: this.sysId || "0017"
          }
        },
        "POST",
        apiService.createBasicHeaders()
      )
      .then((value: DataOutput<any>) => {
        if (value.code === 200) {
          this.menuData = this.filterMenuData = value.data;
        }
      })
      .catch(err => {
        console.error(err);
      });
  }
  /**初始化*/
  mounted(): void {
    this.selectMenuData();
  }
}
</script>

<style scoped lang="scss">
$color-333: #333333; /**颜色#333*/
/**整体样式*/
.ec-menu-view {
  width: 220px;
  max-height: calc(100vh - 64px);
  overflow-x: hidden;
  overflow-y: auto;
  min-height: 400px;
  -ms-overflow-style: none;
  overflow: -moz-scrollbars-none;
  & .ec-left-menu {
    border-right: none;
  }
  & .ec-menu-title {
    font-size: 16px;
  }
  & .ec-filter {
    width: 180px;
    margin: 8px 0 8px 20px;
  }
  & .ec-icon-active {
    color: #2858d6;
  }
  & .ec-title-active {
    font-weight: 700;
    color: $color-333;
  }
}
.ec-menu-view::-webkit-scrollbar {
  width: 0 !important;
}
/**被选中的字体高亮*/
::v-deep .ec-search-text {
  background: #e2e2ff;
  vertical-align: baseline;
}
/**菜单被选中时的效果*/
::v-deep .el-menu-item.is-active {
  font-weight: 700;
  color: $color-333;
  & span {
    color: $color-333;
  }
  & i {
    color: #2858d6;
  }
  background-color: transparent !important;
}
/**鼠标访问时的效果*/
::v-deep .el-submenu__title:hover {
  background-color: #f6f8ff !important;
}
::v-deep .el-menu-item:hover {
  background-color: #dde4f6 !important;
}
/**右侧箭头图标的大小*/
::v-deep .el-submenu__icon-arrow {
  font-size: 16px;
}
.ec-no-data {
  text-align: center;
  padding-top: calc(50% - 7px);
  font-size: 14px;
  color: #999999;
}
</style>
