<template>
  <div class="dc-left-menu-container">
    <div class="dc-left-menu-box">
      <a-menu v-model:selectedKeys="selectedKeys" :openKeys="openKeys" :inlineIndent="16" @openChange="onOpenChange" @click="handleMenuClick" class="dc-left-menu" :inline-collapsed="enableInlineCollapsed ? collapsed : undefined" mode="inline" theme="light">
        <template v-for="menu in menus" :key="menu.key">
          <a-menu-item v-if="!menu.children" :key="menu.key">
            <template #icon>
              <span class="iconfont dc-iconfont" v-if="menu.icon" :class="menu.icon"></span>
              <appstore-outlined v-else />
            </template>
            <div class="dc-text">{{ menu.title }}</div>
          </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" @click="toggleCollapsed">
        <template v-if="collapsed">
          <menu-unfold-outlined />
        </template>
        <template v-else>
          <menu-fold-outlined />
        </template>
        <div class="dc-menu-fold-btn-text" v-if="!collapsed">收起导航</div>
      </a-button>
    </div>
  </div>
</template>

<script lang="ts">
import SubMenu from "./SubMenu.vue";
import { NavMenu } from "../../model/domain/NavMenu";
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/domain/RestfulResponse";
import { RestApi } from "../../model/domain/RestApi";
import sysMenuInfoApi from "../../constants/api/sys-menu-info.api";
import { SysMenuInfo } from "../../model/entity/SysMenuInfo";
import { ConnectType } from "../../constants/enum/connect-type.enum";
import { menuTreeConvertService } from "../../services/menu-tree-convert.service";
import { Options, Vue } from "vue-class-component";
import { Prop, Watch } from "vue-property-decorator";

interface Props {
  collapsed: boolean;
  staticMenus: NavMenu[];
  dynamic: boolean;
}

@Options({
  name: "LeftMenu",
  components: {
    "sub-menu": SubMenu,
  },
})
export default class LeftMenu extends Vue {
  @Prop({ default: false }) readonly collapsed!: boolean; // 折叠状态
  @Prop({ default: [] }) readonly staticMenus!: NavMenu[]; // 菜单信息
  @Prop({ default: true }) readonly dynamic!: boolean; // 菜单信息
  @Prop({ default: true }) readonly enableInlineCollapsed!: boolean; // 启用内联菜单-解决插件外置使用BUG

  selectedKeys: string[] = []; // 当前激活的菜单编号集合
  openKeys: string[] = []; // 当前展开的菜单编号集合-暂未使用
  menus: NavMenu[] = []; // 动态菜单列表

  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
   */
  toggleCollapsed() {
    this.$emit("update:collapsed", !this.collapsed);
  }

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

  /**
   * @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) === -1);
    if (this.menus.findIndex((item) => item.key === latestOpenKey) === -1) {
      this.openKeys = openKeys;
    } 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";
      }
      :deep {
        .ant-menu-item {
          height: 50px;
          line-height: 50px;
          margin-top: 0;
          margin-bottom: 0;
          color: #333333;
          font-size: 14px;
          .dc-iconfont {
            font-size: 20px;
            color: #9fc9f9;
          }
          .anticon {
            color: #9fc9f9;
          }
          &.ant-menu-item-active {
            background-color: #ebf5fe;
            color: rgb(64, 148, 243);
          }
          &.ant-menu-item-selected {
            background-color: #ebf5fe;
            color: #0e70c8;
            .anticon,
            .dc-iconfont {
              color: #1f7acc;
            }
            &::before {
              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: 3px solid #0e70c8;
              content: "";
            }
            &::after {
              display: none;
            }
          }
        }
        .ant-menu-submenu {
          .ant-menu-submenu-title {
            height: 50px;
            line-height: 50px;
            margin-top: 0;
            margin-bottom: 0;
            .ant-menu-title-content {
              color: #333333;
              font-size: 14px;
            }
          }
          .dc-iconfont {
            font-size: 20px;
            white-space: nowrap;
            color: #9fc9f9;
          }
          .anticon {
            color: #9fc9f9;
          }
          &.ant-menu-submenu-active {
            background-color: #ebf5fe;
            .ant-menu-submenu-title {
              .ant-menu-title-content {
                color: rgb(64, 148, 243);
              }
            }
          }
          &.ant-menu-submenu-selected {
            background-color: #ebf5fe;
            .anticon,
            .dc-iconfont {
              color: #1f7acc;
            }
            .ant-menu-submenu-title {
              .ant-menu-title-content {
                color: #0e70c8;
                display: block;
              }
              &::before {
                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: 3px solid #0e70c8;
                content: "";
              }
              &::after {
                display: none;
              }
            }
          }
          .ant-menu-sub {
            background-color: #fafafa;
            .ant-menu-item {
              height: 40px;
              margin-top: 4px;
              margin-bottom: 8px;
              &::before {
                display: none;
              }
              &.ant-menu-item-active {
                color: #0e70c8;
                background-color: #ebf5fe;
              }
              &.ant-menu-item-selected {
                color: #245fac;
                background-color: #ebf5fe;
                .dc-rectangle {
                  background-color: #245fac;
                }
              }
            }
          }
        }
      }
    }
  }
  .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;
      :deep {
        .anticon {
          display: block;
          font-size: 16px;
        }
      }
      .dc-menu-fold-btn-text {
        font-size: 12px;
        margin-left: 10px;
      }
    }
  }
  :deep {
    @for $i from 15 through 20 {
      .dc-iconfont-#{$i} {
        font-size: $i + px !important;
      }
    }
  }
}
:global(.dc-sub-menu-item-li) {
  display: flex !important;
  align-items: center;
  .dc-rectangle-box {
    display: block;
  }
  .ant-menu-title-content {
    display: block;
  }
}
</style>
