Newer
Older
IntegratedFront / src / views / system / role / dataPerm.vue
lyg on 1 Nov 5 KB first
<script lang="ts" setup name="DataPerm">
import type { Ref } from 'vue'
import { Switch } from '@element-plus/icons-vue'
import { ElButton, ElDialog, ElMessage } from 'element-plus'
import type { CheckboxValueType, FormInstance } from 'element-plus'
import type { RoleInfo } from './role-interface'
import { dataAuthor } from '@/api/system/role'
import { getDeptTreeByRole } from '@/api/system/dept'
import { getShowItem, toTreeList } from '@/utils/structure'

// ----------------------- 以下是字段定义 emits props ---------------------
const emits = defineEmits(['closeRefresh'])

// 对话框是否显示
const dialogVisible = ref(false)
// 显示标题-角色名称
const roleName = ref('数据权限')
// 角色id
const roleId = ref('')
// 树列表配置项
const defaultProps = {
  label: 'name',
  children: 'children',
}
// 过滤文字
const filterText = ref('')
// 全部组织id, 用于全选
const allDeptIds = ref([])
// 组织树列表数据
const treeList = ref([])
// 默认展开项
const defaultExpanded: Ref<string[]> = ref([])
// 默认选中项
const defaultChecked: Ref<string[]> = ref([])
// 树展开状态
const treeExpand = ref(false)
// 全选
const nodeCheckedAll = ref(false)
// 父子联动
const treeCheckStrictly = ref(false)
// 保存按钮加载状态
const btnLoading = ref(false)
// 列表加载状态
const loading = ref(false)

const tree = ref()

// ---------------表单提交--------------------------------
// 表单对象
const dataFormRef = ref<FormInstance>()

// 提交表单
function submitForm() {
  const ids: string[] = tree.value.getCheckedKeys()
  btnLoading.value = true
  dataAuthor(roleId.value, ids).then((res) => {
    ElMessage.success('权限配置成功')
    btnLoading.value = false
    dialogClose()
  }).catch((_) => { // 异常情况,loading置为false
    btnLoading.value = false
  })
}

// 获取当前角色的功能权限
function fetchDeptTree(roleid: string) {
  loading.value = true
  getDeptTreeByRole(roleid).then((response) => {
    if (response.data) {
      allDeptIds.value = response.data.map((item: { id: string }) => item.id)
      treeList.value = toTreeList(response.data)
      const temp = getShowItem(response.data) // 获取展开项和选中项
      defaultExpanded.value = temp.expandList
      defaultChecked.value = temp.openedList
      loading.value = false
    }
  })
}

interface treeItem {
  expanded: boolean
  childNodes?: treeItem[]
}
/**
     * 改变树节点展开状态,递归
     * @param node 改变的节点
     * @param value 展开/折叠
     */
function changeTreeNodeStatus(node: treeItem, value: boolean) {
  node.expanded = value // 给当前节点赋值
  if (node.childNodes) {
    for (let i = 0; i < node.childNodes.length; i++) { // 给子节点赋值
      node.childNodes[i].expanded = value
      if (node.childNodes[i].childNodes && node.childNodes[i].childNodes!.length > 0) { // 如果子节点还有子节点,递归
        changeTreeNodeStatus(node.childNodes[i], value)
      }
    }
  }
}
// 点击展开或折叠按钮
function expandOrCollapse() {
  treeExpand.value = !treeExpand.value
  changeTreeNodeStatus(tree.value.store.root, treeExpand.value)
}
// 全选或全不选
function handleCheckedTreeNodeAll(value: CheckboxValueType) {
  tree.value.setCheckedKeys(value ? allDeptIds.value : [])
}

const filterNode = (value: string, data: { name: string }) => data.name?.includes(value)

// 监控查询框
watch(filterText, (val) => {
  tree.value!.filter(val)
})

// ----------初始化、关闭对话框相关-----------------
function initDialog(row: RoleInfo) {
  roleName.value = row.name
  roleId.value = row.id
  dialogVisible.value = true
  btnLoading.value = false
  fetchDeptTree(row.id)
}
// 关闭弹窗
function dialogClose() {
  dialogVisible.value = false
}
// ----------------------- 以下是暴露的方法内容 ----------------------------
defineExpose({ initDialog })
</script>

<template>
  <el-dialog
    v-model="dialogVisible"
    :title="roleName"
    width="400"
    :before-close="dialogClose"
    append-to-body
    :open-delay="0"
    :close-on-click-modal="false"
  >
    <div class="tool-line">
      <el-button :icon="Switch" style="margin-bottom: 10px;" @click="expandOrCollapse">
        展开/折叠
      </el-button>
      <el-checkbox v-model="nodeCheckedAll" style="margin-left: 16px;" @change="handleCheckedTreeNodeAll">
        全选
      </el-checkbox>
      <el-checkbox v-model="treeCheckStrictly">
        父子联动
      </el-checkbox>
    </div>
    <el-input v-model="filterText" placeholder="关键词过滤" style="margin-bottom: 15px;" />
    <el-scrollbar height="300px">
      <el-tree
        ref="tree"
        v-loading="loading"
        :props="defaultProps"
        :data="treeList"
        :default-expanded-keys="defaultExpanded"
        :default-checked-keys="defaultChecked"
        :check-strictly="!treeCheckStrictly"
        :filter-node-method="filterNode"
        show-checkbox
        node-key="id"
      />
    </el-scrollbar>
    <template #footer>
      <div class="dialog-footer">
        <el-button :loading="btnLoading" type="primary" @click="submitForm">
          保存
        </el-button>
        <el-button @click="dialogClose">
          取消
        </el-button>
      </div>
    </template>
  </el-dialog>
</template>

<style lang="scss" scoped>
.tool-line {
  margin-bottom: 5px;
  margin-top: -15px;
}
</style>