index.vue 7.03 KB
<template>
  <div class="side-bar-container" :class="{ 'is-collapse': collapse }">
    <el-scrollbar class="side-left">
      <ul class="new-side-bar">
        <ht-logo />
        <li
          v-for="(route, index) in newRoutesChange"
          :key="`${route.name}_${route.path}`"
          class="new-side-bar-item"
          :class="{ active: isActive(route) }"
          @click="selectItem(route)"
          @mouseover="mouseover(index)"
          @mouseleave="mouseleave"
        >
          <img
            v-if="menuIcons[route.alias]"
            class="item-icon"
            :src="isActive(route) || overIndex === index
                ? menuIcons[`${route.alias}_active`]
                : menuIcons[route.alias]
            "
          />
          <i v-else class="item-icon ht-fa-icon" :class="route.meta.icon"></i>
          {{ route.meta.title }}
        </li>
      </ul>
    </el-scrollbar>
    <el-scrollbar v-show="!collapse" class="side-right">
      <ul>
        <li class="new-slide-bar-title">智慧燃气</li>
        <el-menu
          text-color="#333"
          active-text-color="#fff"
          :default-active="activeMenu"
          :unique-opened="uniqueOpened"
          :default-openeds="defaultOopeneds"
          mode="vertical"
        >
          <ht-side-bar-item
            v-for="menuItem in selectMenu"
            :key="`${menuItem.name}_${menuItem.path}`"
            :full-path="handlePath(currentPath, menuItem.path)"
            :item="menuItem"
          />
        </el-menu>
      </ul>
    </el-scrollbar>
  </div>
</template>
<script>
import variables from '@/styles/variables.scss'
import { mapGetters } from 'vuex'
import { uniqueOpened } from '@/config'
import setMenuMark from '@/mixins/setMenuMark'
import getValue from 'lodash/get'
import menuIcons from '@/assets/index_images'
import { isExternal } from '@/utils/validate'
import path from 'path'

export default {
  name: 'HtSideBar',
  mixins: [setMenuMark],
  data() {
    return {
      uniqueOpened,
      defFirMun: ['//appCenter', '/appCenter', '//personal', '/personal'],
      selectMenu: [],
      menuIcons,
      overIndex: -1,
      currentPath: '/index'
    }
  },

  computed: {
    ...mapGetters({
      collapse: 'settings/collapse',
      style: 'settings/style',
      routes: 'routes/routes',
      themeColor: 'settings/themeColor',
    }),
    newRoutesChange() {
      return _.cloneDeep(
        this.newRoutes?.filter((item) => {
          return (
            !this.defFirMun.includes(item.path) && item.meta && !item.hidden
          )
        })
      )
    },
    activeMenu() {
      const route = this.$route
      const { meta, path } = route
      if (meta.activeMenu) {
        return meta.activeMenu
      }
      return path
    },
    variables() {
      return variables
    },
    defaultOopeneds() {
      // 默认展开第一个子subItem
      const children = getValue(this.selectMenu, '[0].children', [])
      if (Array.isArray(children) && children.length > 0) {
        const fullPath = getValue(this.selectMenu, '[0].path', '/index')
        const routePath = fullPath
        if (isExternal(routePath)) {
          return [routePath]
        }
        if (isExternal(fullPath)) {
          return [fullPath]
        }
        return [path.resolve(fullPath, routePath)]
      }
      return []
    },
  },
  watch: {
    '$route.path': {
      handler() {
        this.initSelectItem()
      },
    },
  },
  mounted() {
    this.initSelectItem()
  },
  methods: {
    initSelectItem() {
      this.newRoutesChange.forEach((item) => {
        const isTrue = this.getActiveMenu(item, item.path)
        if (isTrue) {
          this.selectItem(item)
        }
      })
    },
    mouseleave() {
      this.overIndex = -1
    },
    mouseover(index) {
      this.overIndex = index
    },
    // 根据路由获取激活的菜单选项
    getActiveMenu(route, fullPath) {
      if (fullPath === this.$route.path) {
        return true
      }
      if (Array.isArray(route)) {
        return route.some((item) => {
          return this.getActiveMenu(
            item,
            this.handlePath(fullPath, item.path)
          )
        })
      }
      return this.getActiveMenu(
        getValue(route, 'children', []),
        this.handlePath(fullPath, route.path)
      )
    },
    selectItem(route) {
      if (route.type === 'page') {
        this.$router.push(route.path)
      }
      this.currentPath = route.path
      this.selectMenu = route.children
    },
    isActive(route) {
      return this.currentPath === getValue(route, 'path')
    },
    handlePath(fullPath, routePath) {
      if (isExternal(routePath)) {
        return routePath
      }
      if (isExternal(this.fullPath)) {
        return fullPath
      }
      return path.resolve(fullPath, routePath)
    },
  },
}
</script>
<style lang="scss" scoped>
@mixin dot-border-color {
  border-color: var(--themeColor);
}
$side-bar-color: rgb(33, 59, 106);
$side-bar-bg-color: #f2f2f2;
.side-bar-container {
  position: fixed;
  top: 0;
  bottom: 0;
  left: 0;
  z-index: $base-z-index;
  width: $base-left-menu-width;
  height: 100vh;
  overflow: hidden;
  background-color: $side-bar-bg-color;
  border-right: 1px solid $side-bar-bg-color;
  transition: width $base-transition-time;
  color: $side-bar-color;
  display: flex;
  .side-left {
    width: $base-left-menu-width-min;
  }
  .side-right {
    width: $base-right-content-width-min;
    background-color: #fff;
    transition: width $base-transition-time;
    position: relative;
    &:after{
      position: absolute;
      content: '';
      display: inline-block;
      bottom: 16px;
      left: 16px;
      right: 16px;
      height: 265px;
      background: url('~@/assets/index_images/side_bg.png') no-repeat center/100%;
    }
  }
  &.is-collapse {
    width: $base-left-menu-width-min;
  }
}

@mixin hover {
  background-color: var(--themeColor) !important;
  color: #fff !important;
}
.new-side-bar {
  display: flex;
  width: $base-left-menu-width-min;
  align-items: center;
  flex-flow: column;
  gap: 4px;
  flex-shrink: 0;
  .new-side-bar-item {
    width: calc(100% - 16px);
    height: 58px;
    display: flex;
    flex-flow: column;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    &.active,
    &:hover {
      @include hover;
    }
  }
  .item-icon {
    width: 24px;
    height: 24px;
    display: inline-block;
    object-fit: contain;
    margin-bottom: 6px;
    font-size: 26px;
    margin-right:inherit;
  }
}

.new-slide-bar-title {
  text-align: center;
  line-height: 62px;
  font-size: 22px;
  font-family: 楷体, sans-serif;
}
::v-deep {
  .logo-container-vertical {
    line-height: inherit;
    width: 100%;
    padding: 0;
    height: 58px;
    display: flex;
    align-items: center;
    justify-content: center;
    .logoImg {
      width: 36px;
      height: 36px;
    }
  }
  .el-menu {
    background-color: transparent;
    padding: 0 4px;
    border: none;
  }
  .el-menu-item {
    &:hover,
    &.is-active {
      @include hover;
    }
  }
  .el-submenu__icon-arrow {
    font-size: 20px;
    color: $side-bar-color;
  }
}
</style>