Newer
Older
safe_production_front / src / views / system / role / functionPerm.vue
dutingting 15 days ago 7 KB bug修复
<script lang="ts" setup name="FunctionPerm">
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 { funcAuthor } from '@/api/system/role'
import { getResourceListByRole } from '@/api/system/resource'
import { getShowItem, toTreeList } from '@/utils/structure'
import { approvalAdd } from '@/api/system/user'

// ----------------------- 以下是字段定义 emits props ---------------------
const emits = defineEmits(['closeRefresh'])
const useApproval = ref('') // 是否走审批
const pageType = ref('')

// 对话框是否显示
const dialogVisible = ref(false)
// 显示标题-角色名称
const roleName = ref('功能权限')
// 角色id
const roleId = ref('')
// 树列表配置项
const defaultProps = {
  label: 'name',
  children: 'children',
}
const filterText = ref('')
// 所有资源id
const resourceIds = 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>()

// 存储当前选中的节点ID和完整数据
const currentCheckedKeys = ref<string[]>([])
function handleCheckChange(data: any, checked: { checkedKeys: string[]; halfCheckedKeys: string[] }) {
  // 更新选中的节点ID
  currentCheckedKeys.value = checked.checkedKeys

  // 更新选中的节点完整数据
  currentCheckedNodes.value = tree.value.getCheckedNodes(false, true)

  console.log('选中状态更新:', currentCheckedKeys.value)
}

// 提交表单
function submitForm() {
  const ids: string[] = tree.value.getCheckedKeys()
  btnLoading.value = true
  if (useApproval.value !== 'true') {
    funcAuthor(roleId.value, ids).then((res) => {
      ElMessage.success('权限配置成功')
      btnLoading.value = false
      dialogClose()
    }).catch((_) => { // 异常情况,loading置为false
      btnLoading.value = false
    })
  }
  else {
    const params = {
      jsonContext: { roleId: roleId.value, ids }, // 操作内容
      operationRemark: '角色功能权限配置', // 操作备注
      title: '角色功能权限配置', // 申请标题
      status: '0',
      operationType: 'role_funcAuthor',
      id: '',
    }

    approvalAdd(params).then(() => {
      ElMessage.success('审批提交成功,请耐心等待审批!')
      btnLoading.value = false
      btnLoading.value = false
      dialogClose()
    }).catch(() => {
      ElMessage.warning('审批提交失败,请重新申请或联系管理员!')
      btnLoading.value = false
    })
  }
}

// 获取当前角色的功能权限
function fetchResourceTree(roleid: string, bizType: string) {
  loading.value = true
  getResourceListByRole(roleid, bizType).then((response) => {
    if (response.data) {
      let tempData = response.data
      if (pageType.value === 'detail') {
        tempData = tempData.map((item: any) => {
          return {
            ...item,
            disabled: true,
          }
        })
      }
      resourceIds.value = tempData.map((item: { id: string }) => item.id)
      treeList.value = toTreeList(tempData)
      const temp = getShowItem(tempData) // 获取展开项和选中项
      defaultExpanded.value = temp.expandList
      defaultChecked.value = pageType.value === 'detail' ? currentCheckedKeys.value : temp.openedList
      tree.value.setCheckedKeys(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 ? resourceIds.value : [])
}
const filterNode = (value: string, data: { name: string }) => data.name?.includes(value)

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

// ----------初始化、关闭对话框相关-----------------

function initDialog(row: any, useApprovalParam = '', type = '') {
  roleName.value = row.name
  roleId.value = row.id
  pageType.value = type
  useApproval.value = useApprovalParam
  dialogVisible.value = true
  btnLoading.value = false
  currentCheckedKeys.value = row.ids
  fetchResourceTree(row.id, row.bizType)
}
// 关闭弹窗
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" :disabled="pageType === 'detail'" style="margin-left: 16px;" @change="handleCheckedTreeNodeAll">
        全选
      </el-checkbox>
      <el-checkbox v-model="treeCheckStrictly" :disabled="pageType === 'detail'">
        父子联动
      </el-checkbox>
    </div>
    <el-input v-model="filterText" placeholder="关键词过滤" style="margin-bottom: 15px;" />
    <el-scrollbar height="400px">
      <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"
        @check="handleCheckChange"
      />
    </el-scrollbar>
    <template #footer>
      <div class="dialog-footer">
        <el-button v-if="pageType !== 'detail'" :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>