<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>