<template>
  <div class="dc-left-menu-container">
    <div class="dc-left-menu-box">
      <a-menu v-model="selectedKeys" :openKeys.sync="!collapsed ? openKeys : openKeysOnCollapsed" :inline-fold="collapsed" :inline-indent="16" @openChange="onOpenChange" @click="handleMenuClick" class="dc-left-menu" mode="inline" theme="light">
        <template v-for="menu in menus">
          <a-menu-item v-if="!menu.children" :key="menu.key">
            <span class="anticon" v-if="menu.icon">
              <span class="dc-iconfont iconfont" :class="menu.icon"></span>
            </span>
            <img v-else class="anticon" style="width: 14px; height: 14px" :src="menuSvg" />
            <span class="dc-text">{{ menu.title }}</span>
          </a-menu-item>
          <sub-menu v-else :key="menu.key" :menu-info="menu" :collapsed="collapsed" />
        </template>
      </a-menu>
    </div>
    <div class="dc-menu-fold">
      <a-button type="link" class="dc-menu-fold-btn" block @click="toggleCollapsed">
        <a-icon :type="collapsed ? 'menu-unfold' : 'menu-fold'" />
        <div class="dc-menu-fold-btn-text" v-if="!collapsed">收起导航</div>
      </a-button>
    </div>
  </div>
</template>

<script lang="ts">
import { Component, Emit, Prop, Vue, Watch } from "vue-property-decorator";
import SubMenu from "./SubMenu.vue";
import { NavMenu } from "../../model/NavMenu";
import { Menu, Icon, Button } from "ant-design-vue";
import { beanUtilsService } from "../../services/bean-utils.service";
import { routeTopologyService } from "../../services/route-topology.service";
import { Code } from "../../constants/enum/code.enum";
import { apiService } from "../../services/api.service";
import { RestfulResponse } from "../../model/RestfulResponse";
import { RestApi } from "../../model/RestApi";
import sysMenuInfoApi from "../../constants/api/sys-menu-info.api";
import { SysMenuInfo } from "../../model/SysMenuInfo";
import { menuTreeConvertService } from "../../services/menu-tree-convert.service";
import { MENU_SVG_XML } from "../../constants/encode-assets/svg";
import { ConnectType } from "../../constants/enum/connect-type.enum";

@Component({
  name: "LeftMenu",
  components: {
    [Menu.name]: Menu,
    [Menu.Item.name]: Menu.Item,
    [Icon.name]: Icon,
    [Button.name]: Button,
    "sub-menu": SubMenu,
  },
})
export default class LeftMenu extends Vue {
  selectedKeys: string[] = []; // 当前激活的菜单编号集合
  openKeys: string[] = []; // 当前展开的菜单编号集合-暂未使用
  menus: NavMenu[] = []; // 动态菜单列表
  openKeysOnCollapsed: string[] = []; // 闭合时的父级菜单集合
  menuSvg: any = MENU_SVG_XML; // 默认菜单图标
  @Prop({ default: () => false }) collapsed!: boolean; // 左侧菜单闭合标识
  @Prop({ default: () => [] }) staticMenus!: NavMenu[]; // 静态菜单列表
  @Prop({ default: () => true }) dynamic!: boolean; // 是否动态加载

  mounted() {
    if (this.dynamic) {
      this.handleSearch();
    } else {
      this.onStaticMenusChange(this.staticMenus);
    }
  }

  /**
   * @description: 静态数据监听
   * @author ChenRui
   * @date 2021/9/15 16:01
   */
  @Watch("staticMenus")
  onStaticMenusChange(val: NavMenu[]): void {
    if (!this.dynamic) {
      this.menus = this.staticMenus || [];
    }
  }

  /**
   * @description: 闭合标识消息弹射
   * @author ChenRui
   * @date 2021/8/9 15:51
   */
  @Emit("update:collapsed")
  toggleCollapsed() {
    return !this.collapsed;
  }

  /**
   * @description: 路由变化监听
   * @author ChenRui
   * @date 2021/8/9 15:51
   */
  @Watch("$route")
  onRouteChanged() {
    this.navPosition();
  }

  @Watch("collapsed")
  onCollapsedChanged(newVal: boolean) {
    if (newVal) {
      this.openKeys = [];
    }
  }

  /**
   * @description: 动态查找菜单信息
   * @author ChenRui
   * @date 2021/8/9 15:12
   */
  handleSearch(): void {
    const query = {
      appId: this.$dc.sysId,
    };
    const restApi: RestApi = new RestApi(sysMenuInfoApi.queryAuthorizedMenuByAppId);
    restApi.url = this.$dc.baseApi + sysMenuInfoApi.queryAuthorizedMenuByAppId.url;
    apiService.general(restApi, query).then((response: RestfulResponse) => {
      if (response.code === Code.SUCCESS.code) {
        if (response.data && response.data.length > 0) {
          const sysMenuInfos: SysMenuInfo[] = response.data;
          const navMenus: NavMenu[] = menuTreeConvertService.menuToNavMenu(sysMenuInfos);
          this.menus = navMenus;
          this.navPosition();
        }
      }
    });
  }

  /**
   * @description: 菜单展开处理
   * @author ChenRui
   * @date 2020/7/29 17:18
   */
  onOpenChange(openKeys: string[]) {
    const latestOpenKey = openKeys.find((key) => this.openKeys.indexOf(key as never) === -1);
    if (this.menus.findIndex((item) => item.key === latestOpenKey) === -1) {
      this.openKeys = openKeys as any;
    } else {
      this.openKeys = latestOpenKey ? ([latestOpenKey] as any) : [];
    }
  }

  /**
   * @description: 动态切换导航及面包屑激活状态
   * @author ChenRui
   * @date 2020/7/29 17:07
   */
  navPosition(): void {
    const route = this.$route;
    const nodes = routeTopologyService.fetchNodes(route.path);
    if (nodes && nodes.length > 0) {
      for (const node of nodes) {
        const menus = this.recursionSerarchCurrentMenuTreeByUrl(this.menus, node.path);
        if (menus) {
          this.selectedKeys = [];
          this.openKeys = [];
          menus.forEach((menu: NavMenu) => {
            if (menu.url !== node.path) {
              this.openKeys.push(menu.key!);
            } else {
              this.selectedKeys.push(menu.key!);
            }
          });
          break;
        }
      }
    }
  }

  /**
   * @description: 菜单点击处理，切换导航
   * @author ChenRui
   * @date 2021/8/9 15:08
   */
  handleMenuClick(e: any) {
    if (e != null && e.key != null) {
      const menu: NavMenu | undefined = this.recursionSerarchMenuByKey(this.menus, e.key);
      if (menu && !!menu.url && menu.url !== this.$route.path) {
        if (menu.connectType === ConnectType.EXTERNAL.code) {
          window.open(menu.url);
        } else {
          this.$router.push(menu.url);
        }
      }
    }
  }

  /**
   * @description: 递归查找菜单信息
   * @author ChenRui
   * @date 2021/8/9 15:09
   */
  recursionSerarchMenuByKey(menus: NavMenu[], key: string): NavMenu | undefined {
    for (const i in menus) {
      if (menus[i].key === key) {
        return menus[i];
      } else if (!!menus[i].children && (menus[i].children || []).length > 0) {
        const mu: NavMenu = this.recursionSerarchMenuByKey(menus[i].children || [], key) as NavMenu;
        if (mu) {
          return mu;
        }
      }
    }
  }

  /**
   * @description: 根据url获取菜单导航树
   * @author ChenRui
   * @date 2020/7/29 17:16
   */
  recursionSerarchCurrentMenuTreeByUrl(menus: NavMenu[], url: string): NavMenu[] | undefined {
    for (const i in menus) {
      if (menus[i].url === url) {
        return [beanUtilsService.copy(menus[i])];
      } else if (menus[i].children) {
        const mus: NavMenu[] = this.recursionSerarchCurrentMenuTreeByUrl(menus[i].children || [], url) as NavMenu[];
        if (mus) {
          const menuCp = [beanUtilsService.copy(menus[i])];
          return [...menuCp, ...mus];
        }
      }
    }
  }
}
</script>

<style lang="scss" scoped>
.dc-left-menu-container {
  height: 100%;
  .dc-left-menu-box {
    height: calc(100% - 40px);
    scrollbar-width: none; /* firefox */
    -ms-overflow-style: none; /* IE 10+ */
    overflow-x: hidden;
    overflow-y: auto;
    padding-top: 2px;
    &::-webkit-scrollbar {
      display: none; /* Chrome Safari */
    }
    .dc-left-menu {
      .dc-text {
        font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
      }
      &.ant-menu-inline-collapsed {
        width: initial;
        ::v-deep {
          .ant-menu-submenu-title {
            padding-left: 22px !important;
          }
          & > {
            .ant-menu-item {
              padding-left: 22px !important;
            }
          }
          & > {
            .ant-menu-item,
            .ant-menu-submenu .ant-menu-submenu-title {
              &::after {
                display: none;
              }
            }
          }
        }
      }
      & > {
        .ant-menu-item-selected {
          background-color: #e0edff !important;
          color: #245fac;
          font-weight: 700;
          position: relative !important;
          .dc-iconfont {
            color: #245fac !important;
          }
          &::before {
            display: initial !important;
            content: "";
            transform: scaleY(1);
            opacity: 1;
            transition: transform 0.15s cubic-bezier(0.645, 0.045, 0.355, 1), opacity 0.15s cubic-bezier(0.645, 0.045, 0.355, 1);
            position: absolute;
            top: 0;
            left: 0;
            bottom: 0;
            border-right: 4px solid #245fac;
          }
        }
      }
      ::v-deep {
        & > {
          .ant-menu-item {
            display: flex;
            align-items: center;
          }
          .ant-menu-item,
          .ant-menu-submenu .ant-menu-submenu-title {
            height: 50px;
            line-height: 50px;
            padding-bottom: 5px;
            position: relative;
            margin-top: 0;
            margin-bottom: 0;
            &::after {
              content: "";
              position: absolute;
              left: 15px;
              top: auto;
              bottom: 0;
              right: auto;
              height: 1px;
              width: calc(100% - 30px);
              background-color: #e7e7e7;
            }
          }
        }
        .ant-menu-submenu,
        .ant-menu-item {
          color: #333333;
          .dc-iconfont {
            color: #a3b9e0;
          }
        }
        .ant-menu-submenu {
          .ant-menu-item {
            font-size: 12px;
            &.ant-menu-item-selected {
              .dc-rectangle {
                background-color: #245fac;
              }
              .dc-iconfont {
                color: #245fac;
              }
            }
          }
        }
        .ant-menu-submenu-selected {
          .ant-menu-submenu-title {
            background-color: #e0edff;
            color: #245fac;
            font-weight: 700;
            position: relative;
            &::before {
              content: "";
              transform: scaleY(1);
              opacity: 1;
              transition: transform 0.15s cubic-bezier(0.645, 0.045, 0.355, 1), opacity 0.15s cubic-bezier(0.645, 0.045, 0.355, 1);
              position: absolute;
              top: 0;
              left: 0;
              bottom: 0;
              border-right: 4px solid #245fac;
            }
            .dc-iconfont {
              color: #245fac !important;
            }
          }
        }
        .ant-menu-item-selected {
          color: #245fac;
          background-color: #fafafa;
          &::after {
            display: none;
          }
        }
      }
    }
  }
  .dc-menu-fold {
    margin-top: auto;
    height: 40px;
    display: flex;
    align-items: center;
    border-top: 1px solid #d8dce6;
    .dc-menu-fold-btn {
      display: flex;
      flex-direction: row;
      align-items: center;
      color: #bfbccc;
      ::v-deep {
        .anticon {
          display: block;
          margin-bottom: -2px;
          font-size: 16px;
        }
      }
      .dc-menu-fold-btn-text {
        font-size: 12px;
        margin-left: 10px;
      }
    }
  }
}
</style>
