AppMenuAuthDialog.vue 7.92 KB
<template>
  <el-dialog
    title="资源授权"
    width="1200px"
    :visible.sync="dialogVisible"
    :close-on-click-modal="false"
    append-to-body
  >
    <template v-if="dialogVisible">
      <el-alert
        title="请先给用户进行应用权限才能进行菜单授权"
        type="warning"
        :closable="false"
      />
      <div class="container">
        <div class="left-panel">
          <div class="header">角色列表</div>
          <div class="main">
            <el-scrollbar class="content-height">
              <app-role-selector @select="selectRole" />
            </el-scrollbar>
          </div>
        </div>
        <div class="right-panel">
          <div class="header">资源授权</div>
          <div class="main">
            <el-tree
              :data="menus"
              node-key="alias"
              default-expand-all
              :expand-on-click-node="false"
              :props="defaultProps"
              ref="elTreeRef"
            >
              <span class="custom-tree-node" slot-scope="{node, data}">
                <span>{{ node.label }}</span>
                <span>
                  <el-checkbox-group v-model="data.authorization">
                    <el-checkbox
                      label="view"
                      @change="handleCheckboxChange($event, node, 'view')"
                      :indeterminate="data.viewIndeterminate"
                      >查看</el-checkbox
                    >
                  </el-checkbox-group>
                </span>
              </span>
            </el-tree>
          </div>
        </div>
      </div>
      <div slot="footer">
        <el-button @click="dialogVisible = false">取消</el-button>
        <el-button type="primary" @click="confirm">确定</el-button>
      </div>
    </template>
  </el-dialog>
</template>

<script>
import AppRoleSelector from './AppRoleSelector.vue'
import {mapState} from 'vuex'
import portal from '@/api/portal'
import util from '@/hotent-ui-util'
export default {
  name: 'AppMenuAuthDialog',
  components: {
    AppRoleSelector,
  },
  data() {
    return {
      dialogVisible: false,
      roles: [],
      defaultProps: {
        children: 'children',
        label: 'name',
      },
      activeRole: '',
      appId: '',
      appName: '',
      menus: [],
      checkedParameters: [],
      valueMap: {},
    }
  },
  computed: mapState({
    appMenus: (state) => {
      return state.menu.appMenus || []
    },
  }),
  methods: {
    initAuth() {
      if (this.activeRole && this.appId) {
        portal
          .getAppMenuAuthorization(this.appId, this.activeRole.code)
          .then((resp) => {
            this.menus = [
              {
                name: this.appName,
                top: true,
                children: util.tile2nest(resp.data),
                authorization: [],
              },
            ]
            this.initIndeterminate()
            this.initCheck(resp.data)
          })
      }
    },
    initCheck(data) {
      let checkedLength = data.filter((item) =>
        item.authorization.includes('view')
      ).length
      let length = data.length
      if (length === checkedLength) {
        this.menus[0].authorization.push('view')
      }
    },
    initIndeterminate() {
      this.dfs(this.menus, 'view')
    },
    dfs(menus, type) {
      let length = 0
      let oneOfIndeterminate = false
      for (let i = 0; i < menus.length; i++) {
        let menu = menus[i]
        if (menu.children && menu.children.length > 0) {
          let isIndeterminate = this.dfs(menu.children, type)
          if (isIndeterminate) {
            oneOfIndeterminate = true
            this.$set(menu, type + 'Indeterminate', true)
            menu.authorization = []
          }
        }
        if (menu.authorization.includes(type)) {
          length++
        }
      }
      return oneOfIndeterminate || (length > 0 && length < menus.length)
    },
    open(appId, appName) {
      this.dialogVisible = true
      this.appId = appId
      this.appName = appName
    },
    confirm() {
      let param = {
        appId: this.appId,
        roleAlias: this.activeRole.code,
        authorization: this.getCheckedData('view'),
      }
      portal.saveAppMenuAuthorization(param).then((resp) => {
        if (resp.data.state) {
          this.$message.success(resp.data.message)
          this.dialogVisible = false
        }
      })
    },
    selectRole(role) {
      this.activeRole = role
      this.initAuth()
    },
    handleCheckboxChange(value, node, type) {
      debugger
      if (node.childNodes) {
        this.setChildNodes(node.childNodes, value, type)
      }
      this.setIndeterminate(node, value, type)
      if (node.parent) {
        this.setParentNodes(node.parent, value, type)
      }
    },
    getCheckedData(type) {
      let rtn = []
      util.nestForEach(this.menus, 'children', (item) => {
        if (item.top) {
          return
        }
        if (
          item.authorization.includes(type) ||
          !!item[type + 'Indeterminate']
        ) {
          rtn.push(`${item.alias}_${type}`)
        }
      })
      return rtn
    },
    setParentNodes(node, value, type) {
      if (node.data instanceof Array) {
        return
      }

      let {checkedLength, length} = this.getLength(node.childNodes, type)
      if (!value || checkedLength === length) {
        this.addList(node.data.authorization, type, value)
      }

      this.setIndeterminate(node, value, type)
      this.setParentNodes(node.parent, value, type)
    },
    setChildNodes(nodes, value, type) {
      nodes.forEach((node) => {
        this.addList(node.data.authorization, type, value)

        if (node.childNodes && node.childNodes.length > 0) {
          this.setChildNodes(node.childNodes, value, type)
          this.setIndeterminate(node, value, type)
        }
      })
    },
    setIndeterminate(node, value, type) {
      let indeterminateLength = node.childNodes.filter(
        (node) => !!node.data[type + 'Indeterminate']
      ).length
      if (indeterminateLength > 0) {
        this.$set(node.data, type + 'Indeterminate', true)
        return
      }
      let checkedLength = node.childNodes.filter(
        (node) =>
          node.data.authorization.includes(type) &&
          !node.data[type + 'Indeterminate']
      ).length
      let length = node.childNodes.length

      this.$set(
        node.data,
        type + 'Indeterminate',
        checkedLength > 0 && checkedLength < length
      )
    },
    addList(list, item, add) {
      if (add) {
        if (!list.includes(item)) {
          list.push(item)
        }
      } else {
        let index = list.indexOf(item)
        list.splice(index, 1)
      }
    },
    getLength(nodes, type) {
      let checkedLength = nodes.filter((node) =>
        node.data.authorization.includes(type)
      ).length
      let length = nodes.length
      return {
        checkedLength,
        length,
      }
    },
  },
}
</script>

<style lang="scss" scoped>
.container {
  display: flex;
  margin-top: 24px;
  height: 620px;
  justify-content: space-between;

  .left-panel {
    width: 240px;
    border: 1px solid #ebebeb;

    .header {
      margin-bottom: 16px;
    }

    .main {
      overflow: auto;
      height: 553px;
    }
  }

  .right-panel {
    width: 888px;
    border: 1px solid #ebebeb;

    .main {
      overflow: auto;
      height: 569px;
    }

    .custom-tree-node {
      flex: 1;
      display: flex;
      align-items: center;
      justify-content: space-between;
      font-size: 14px;
      padding-right: 8px;
    }
  }

  .header {
    background: #f9f9f9;
    padding: 12px 24px;
    border-bottom: 1px solid #ebebeb;
    line-height: 24px;
    font-size: 16px;
    font-weight: 500;
    color: #262626;
  }
}
::v-deep {
  .el-dialog__header {
    padding: 16px 24px;
  }
  .el-dialog__body {
    padding: 24px;
  }
  .el-dialog__footer {
    padding: 16px 24px;
    box-shadow: inset 0 1px 0 1px #ebebeb;
  }

  .el-tree-node__content {
    height: 52px;
  }
}
</style>