08335 / hivui-platform-template
hivui平台项目模板
Newer
Older
hivui-platform-template / project / hivuiMain / views / layout / components / conciseSidebar / index.vue
<template>
  <div class="pl-concise-sidebar">
    <div ref="conciseHead" class="pl-tabs-hd concise"></div>
    <div class="menus">
      <!-- 主菜单区域 -->
      <ul class="area">
        <!-- 全部功能按钮 -->
        <li>
          <div
            title="全部功能"
            ref="navMenuBtn"
            @mouseenter="handleNavMenuBtnMouseEnter"
            @mouseleave="handleNavMenuBtnMouseLeave"
          >
            <div class="tip">
              <i class="iconfont icon-func"></i>
            </div>
          </div>
        </li>
        <!-- 用户信息菜单项 -->
        <li>
          <template v-if="sysUserInfo.children && sysUserInfo.children.length">
            <div
              class="item"
              :title="sysUserInfo.name"
              @mouseenter="handleFuncMenus(sysUserInfo, $event)"
            >
              <div class="tip">
                <i class="iconfont" :class="sysUserInfo.iconClass"></i>
              </div>
            </div>
          </template>
        </li>
        <!-- 系统功能菜单项 -->
        <template v-for="item in sysFuncMenus">
          <li v-if="item.type != 'split'" :key="item.resId">
            <template v-if="item.type == 'withNumTips'">
              <div
                class="item"
                :title="item.name"
                @click.prevent="handleFuncMenus(item, $event)"
                @mouseenter="handleFuncMenus(item, $event, true)"
              >
                <div class="tip">
                  <i class="iconfont" :class="item.iconClass"></i>
                </div>
              </div>
            </template>

            <!-- 普通菜单项 -->
            <template v-else>
              <!-- 有子菜单的项 -->
              <template v-if="item.children && item.children.length">
                <div class="item" @mouseenter="handleFuncMenus(item, $event)">
                  <div class="tip">
                    <i class="iconfont" :class="item.iconClass"></i>
                  </div>
                </div>
              </template>

              <!-- 无子菜单的项 -->
              <template v-else>
                <div
                  class="item"
                  @click.prevent="handleFuncMenus(item, $event)"
                >
                  <div class="tip">
                    <i class="iconfont" :class="item.iconClass"></i>
                  </div>
                </div>
              </template>
            </template>
          </li>
        </template>

        <!-- 设置菜单项 -->
        <li v-if="hasSetting">
          <div class="item" :title="$t('hivuiMain_customWorkbench')">
            <a href="#design" target="_blank"
              ><i class="iconfont icon-set-fill"></i
            ></a>
          </div>
        </li>
      </ul>

      <!-- 系统功能菜单区域 -->
      <ul class="area">
        <!-- 项目管理菜单项 -->
        <li v-if="sysProjectManage">
          <a
            :href="sysProjectManage.url"
            target="_blank"
            class="item"
            :title="sysProjectManage.name"
          >
            <i class="iconfont" :class="sysProjectManage.iconClass"></i>
            <span class="title">{{ sysProjectManage.name }}</span>
          </a>
        </li>

        <!-- 语言切换菜单项 -->
        <li v-if="langList">
          <template v-if="langList.children && langList.children.length">
            <div
              class="item"
              :title="langList.name"
              @mouseenter="handleFuncMenus(langList, $event)"
            >
              <div class="tip">
                <i class="iconfont" :class="langList.iconClass"></i>
              </div>
            </div>
          </template>
        </li>

        <!-- 退出登录菜单项 -->
        <li>
          <div
            class="item"
            :title="$t('hivuiMain_logout')"
            @click="handleLogout"
            @mouseenter="handleFuncMenus(null, null, true)"
          >
            <a><i class="iconfont icon-tuichu"></i></a>
          </div>
        </li>
      </ul>
    </div>

    <!-- 右键上下文菜单组件 -->
    <vueContextMenu
      ref="cmp-funcMenu"
      :menu-items="menuItems"
      field="name"
      :is-bottom="true"
    ></vueContextMenu>

    <modifyPw></modifyPw>

    <!-- 导航菜单组件 -->
    <navmenu
      ref="navmenu"
      :targetElRect="navMenuBtnRect"
      @mouseenter.native="handleNavMenuMouseEnter"
      @mouseleave.native="handleNavMenuMouseLeave($event)"
    ></navmenu>
  </div>
</template>

<script>
import vueContextMenu from "@main/components/contextMenu";
import modifyPw from "@main/views/layout/components/modifyPw";
import navmenu from "./concisemenu.vue";
import { sortMapTurnArr } from "@main/utils/index";
import screenfull from "screenfull";
export default {
  components: { vueContextMenu, modifyPw, navmenu },
  inject: ["addTab", "showTab", "hideTab"],
  props: {},

  data() {
    return {
      menuItems: [], // 菜单项数据
      navMenuBtnRect: {}, // 导航菜单按钮位置信息
    };
  },

  computed: {
    /**
     * 是否显示设置按钮
     */
    hasSetting() {
      let cfg = this.$store.state.app.config || {};
      if (cfg.hideSettingBtn) {
        return false;
      }
      let _arr = sortMapTurnArr(cfg.sysSetTabs);
      return _arr && _arr.length;
    },

    /**
     * 系统列表
     */
    sysList() {
      let cfg = this.$store.state.app.config || {};
      return cfg.sysList || [];
    },

    /**
     * 语言列表
     */
    langList() {
      let cfg = this.$store.state.app.config || {};
      if (!cfg.showChangeLangBtn) {
        return;
      }
      let menus = cfg.langList || [];
      return menus;
    },

    /**
     * 用户信息菜单
     */
    sysUserInfo() {
      let me = this;
      let cfg = this.$store.state.app.config || {};

      // 替换数据中的变量
      function replaceData(str) {
        if (!str) return ["", false];
        var _arr = str.match(/\${(\S*?)}/g);
        var nullNum = 0;

        if (_arr && _arr.length > 0) {
          for (let i of _arr) {
            var _data = me.userInfo[i.match(/\${(\S*)}/)[1]];
            if (typeof _data != "undefined") {
              str = str.replace(i, _data);
            } else {
              str = str.replace(i, me.$t("hivuiMain_header_null"));
              nullNum++;
            }
          }
          return [str, nullNum == _arr.length ? false : true];
        }
        return [str, true];
      }

      // 多岗位信息文字模板格式化
      function orgBzTplFormat(str, item) {
        let fieldArr = str.match(/(?<=\${).*?(?=})/g);
        fieldArr.forEach((_i) => {
          if (typeof item[_i] != "undefined") {
            str = str.replaceAll("${" + _i + "}", item[_i]);
          }
        });
        return str;
      }

      let _userInfo = cfg.userInfo;
      if (_userInfo) {
        _userInfo.name = replaceData(_userInfo.name)[0];
        if (_userInfo.children && _userInfo.children.length > 0) {
          _userInfo.children = _userInfo.children.filter((item) => {
            let _rData = replaceData(item.name);
            item.name = _rData[0];

            // 根据不同类型设置处理函数
            switch (item.type) {
              case "modifyUserInfo":
                item.handler = me.modifyUserInfo;
                break;
              case "modifyPw":
                item.handler = me.modifyPw;
                break;
              case "personalCenter":
                item.handler = me.personalCenter;
                break;
              case "orgBz":
                if (Array.isArray(me.bzList) && me.bzList.length > 1) {
                  item.children = [];
                  for (let i of me.bzList) {
                    let _pushData = {
                      iconClass: "icon-user",
                      name: cfg.orgBzTpl
                        ? orgBzTplFormat(cfg.orgBzTpl, i)
                        : `${i.fbzname}/${i.fbzid}`,
                      handler: function () {
                        me.__changeOrgBz(`${i.fbzid}`);
                      },
                    };
                    item.children.push(_pushData);
                  }
                }
                break;
            }

            // 只返回有效的菜单项
            if (_rData[1]) {
              return item;
            }
          });
        }
      }
      return _userInfo || [];
    },

    /**
     * 系统功能菜单
     */
    sysFuncMenus() {
      let cfg = this.$store.state.app.config || {};
      let menus = sortMapTurnArr(cfg.sysFuncMenus) || [];
      return menus;
    },

    /**
     * 项目管理菜单
     */
    sysProjectManage() {
      let cfg = this.$store.state.app.config || {};
      let item = cfg.sysProjectMange || {},
        flag = false;

      this.$store.state.app.powerList.forEach((p) => {
        if (p.resUrl.indexOf(item.uri) > -1) {
          flag = true;
          return true;
        }
      });

      if (flag) {
        return cfg.sysProjectMange;
      } else {
        return null;
      }
    },

    /**
     * 用户信息
     */
    userInfo() {
      return this.$store.state.user.userInfo;
    },
    isFullscreen() {
      return screenfull.isFullscreen;
    },
  },

  methods: {
    /**
     * 更新导航菜单按钮位置信息
     */
    updateNavMenuBtnRect() {
      if (this.$refs && this.$refs.navMenuBtn) {
        this.navMenuBtnRect = this.$refs.navMenuBtn.getBoundingClientRect();
      }
    },

    /**
     * 鼠标进入导航菜单按钮处理
     */
    handleNavMenuBtnMouseEnter() {
      this.$refs["cmp-funcMenu"].close();
      if (this.$refs.navmenu) {
        this.$refs.navmenu.show();
      }
    },

    /**
     * 鼠标离开导航菜单按钮处理
     */
    handleNavMenuBtnMouseLeave() {
      // 延迟隐藏导航菜单
      setTimeout(() => {
        if (this.$refs.navmenu && !this.$refs.navmenu.isMouseOverMenu) {
          this.$refs.navmenu.hide();
        }
      }, 100);
    },

    /**
     * 鼠标进入导航菜单处理
     */
    handleNavMenuMouseEnter() {
      // 鼠标进入菜单区域,取消隐藏
      if (this.$refs.navmenu) {
        this.$refs.navmenu.isMouseOverMenu = true;
      }
    },

    /**
     * 鼠标离开导航菜单处理
     */
    handleNavMenuMouseLeave(e) {
      // 鼠标离开菜单区域,检查是否移向.pl-menus-item元素
      if (e) {
        const relatedTarget = e.relatedTarget || e.toElement;
        if (
          relatedTarget &&
          relatedTarget.closest &&
          relatedTarget.closest(".pl-menus-item")
        ) {
          // 如果移向.pl-menus-item元素,保持菜单显示
          if (this.$refs.navmenu) {
            this.$refs.navmenu.isMouseOverMenu = true;
          }
          return;
        }
      }

      if (this.$refs.navmenu) {
        this.$refs.navmenu.isMouseOverMenu = false;
        this.$refs.navmenu.hide();
      }
    },

    /**
     * 处理功能菜单点击
     * @param {Object} item - 菜单项
     * @param {Event} $event - 事件对象
     * @param {Boolean} isClose - 是否关闭菜单
     */
    handleFuncMenus(item, $event, isClose) {
      if (isClose) {
        this.$refs["cmp-funcMenu"].close();
        return;
      }

      $event && $event.stopPropagation();

      // 处理链接类型菜单
      if (item && item.type == "link") {
        window.open(item.resUrl, item.name);
        return;
      }

      // 处理带token的URL
      var _url = item ? item.url : "";
      if (item && (item.type == "widthToken" || item.type == "withToken")) {
        _url = item.url + "&access_token=" + this.token;
      }

      // 处理有URL的菜单项
      if (item && item.url) {
        item.target == "tab"
          ? this.addTab({
              resUrl: _url,
              name: item.name,
              resId: item.id,
              openType: item.openType,
            })
          : window.open(_url);
        return;
      } else {
        item && item.handler && item.handler();
      }

      if (item && item.children && item.children.length) {
        this.menuItems = item.children;
        this.$refs["cmp-funcMenu"].open($event);

        if (item.type == "lang") {
          item.children.forEach((__item, index) => {
            if (!__item.handler) {
              __item.handler = () => {
                window.localStorage.setItem(
                  "locale",
                  JSON.stringify({
                    desc: __item.name,
                    name: __item.key,
                  })
                );
                Cookies.set("locale", __item.key);
                window.location.reload();
              };
            }
          });
        }
      }
    },

    /**
     * 处理退出登录
     */
    async handleLogout() {
      if (window.customSysCofig.logoutBeforeCallback) {
        const bool = window.customSysCofig.logoutBeforeCallback();
        if (bool) {
          return;
        }
      }

      await this.$store.dispatch("user/logout").then(() => {
        window.sessionStorage.removeItem("bzid");

        if (window.customSysCofig.logoutCallback) {
          window.customSysCofig.logoutCallback();
        } else {
          if (
            window.HIVUI_SETTING.isSingleLogin &&
            window.HIVUI_SETTING.singleLogoutUrl
          ) {
            location = window.HIVUI_SETTING.singleLogoutUrl;
          } else {
            location = window.HIVUI_SETTING.loginUrl;
          }
        }
      });
    },
  },

  mounted() {
    this.updateNavMenuBtnRect();

    this.$store.dispatch("app/getSysConfig");

    this.sysFuncMenus.filter((item) => {
      if (item.type == "withNumTips" && item.numFunc) {
        const intervalFunc = () => {
          item
            .numFunc()
            .then((res) => {
              this.msgCount = res.num;
              if (res.num && !item.hideNotific) {
                window.SysPage.notificationFunc(
                  this.$t("hivuiMain_header_notification_title"),
                  item.messageText(res),
                  () => {
                    this.handleFuncMenus(item);
                  }
                );
              }
            })
            .catch((err) => {
              clearInterval(this.numTipTimer);
            });
        };

        clearInterval(this.numTipTimer);
        this.numTipTimer = setInterval(
          intervalFunc,
          item.numIntervalTime || 1000 * 30
        );
        intervalFunc();
      }
    });
  },
};
</script>

<style lang="less" scoped>
.pl-concise-sidebar {
  display: flex;
  flex-direction: column;
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  width: 36px;
  background: rgba(235, 241, 247, 1);
  border-right: 1px solid rgba(235, 241, 247, 1);
  // 重置默认样式
  ul,
  li {
    margin: 0;
    padding: 0;
    list-style: none;
  }
  &.showFuncMenu {
    .menus {
      margin-top: 40px;
    }
  }
  .menus {
    flex: 1;
    padding: 8px 4px;
    display: flex;
    flex-direction: column;
    justify-content: space-between;

    .area {
      display: flex;
      flex-direction: column;
      gap: 8px;
      
      li {
        cursor: pointer;
        line-height: 30px;
        background-color: transparent;
        transition: all 0.3s;

        &:hover {
          background-color: #c7d5e2;
          border-radius: 5px;
        }

        > div {
          width: 100%;
          height: 100%;
          display: flex;
          align-items: center;
          justify-content: center;
        }

        .item {
          display: flex;
          align-items: center;

          i{
            color: #4e5969;
          }
        }
      }
    }
  }
}
</style>