第三十二节:部门组织管理(el‑tree 组织树)
目标:实现部门树形管理,新增、编辑、删除部门;后续用户管理页面可以选择归属部门。
业务:部门是树形层级结构,支持一级部门、二级子部门。
1、mock 接口 src/mock/index.js
// 获取全部部门树
'/api/dept/tree': () => {
return {
code: 200,
data: [
{
id: 1,
deptName: '总公司',
parentId: 0,
children: [
{ id:11, deptName:'研发部', parentId:1, children:[] },
{ id:12, deptName:'市场部', parentId:1, children:[] }
]
}
]
}
},
//新增部门
'/api/dept/add':({body})=>{
return {code:200,msg:'新增部门成功'}
},
//编辑部门
'/api/dept/update':({body})=>{
return {code:200,msg:'编辑部门成功'}
},
//删除部门
'/api/dept/remove':({body})=>{
return {code:200,msg:'删除部门成功'}
}
2、新建 api/dept.js
import request from '@/utils/request'
//获取部门树
export function getDeptTree(){
return request({url:'/api/dept/tree',method:'get'})
}
//新增部门
export function addDept(data){
return request({url:'/api/dept/add',method:'post',data})
}
//编辑部门
export function updateDept(data){
return request({url:'/api/dept/update',method:'post',data})
}
//删除部门
export function deleteDept(data){
return request({url:'/api/dept/remove',method:'post',data})
}
3、封装部门弹窗组件 src/views/system/dept/components/DeptDialog.vue
<template>
<el-dialog
v-model="dialogVisible"
:title="isEdit ? '编辑部门' : '新增部门'"
width="460px"
@close="handleClose"
>
<el-form ref="formRef" :model="formData" :rules="formRules" label-width="90px">
<el-form-item prop="deptName" label="部门名称">
<el-input v-model="formData.deptName" placeholder="请输入部门名称"/>
</el-form-item>
<el-form-item prop="parentId" label="上级部门">
<!-- 简易下拉选择父部门,真实项目这里可以用el‑tree‑select -->
<el-select v-model="formData.parentId" placeholder="选择上级部门">
<el-option label="无(顶级部门)" :value="0"/>
<el-option label="总公司" :value="1"/>
<el-option label="研发部" :value="11"/>
</el-select>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="dialogVisible=false">取消</el-button>
<el-button type="primary" @click="submitForm">确定</el-button>
</template>
</el-dialog>
</template>
<script setup>
import {ref,watch} from 'vue'
import { ElMessage } from 'element-plus'
const props = defineProps({
visible:{type:Boolean,default:false},
rowData:{type:Object,default:null}
})
const emit = defineEmits(['update:visible','success'])
const dialogVisible = ref(false)
const formRef = ref(null)
const isEdit = ref(false)
const formData = ref({
id:null,
deptName:'',
parentId:0
})
const formRules = ref({
deptName:[{required:true,message:'请输入部门名称',trigger:'blur'}]
})
watch(()=>props.visible,val=>{
dialogVisible.value = val
if(val){
openDialog()
}
})
function openDialog(){
formRef.value?.resetFields()
if(props.rowData){
isEdit.value = true
formData.value = {...props.rowData}
}else{
isEdit.value = false
formData.value = {id:null,deptName:'',parentId:0}
}
}
async function submitForm(){
await formRef.value.validate()
emit('success',{form:formData.value,isEdit:isEdit.value})
dialogVisible.value = false
}
function handleClose(){
emit('update:visible',false)
}
</script>
4、部门管理主页面 src/views/system/dept/index.vue
<template>
<div class="dept-page">
<h2>部门管理</h2>
<div style="margin:12px 0;">
<el-button type="primary" @click="openAdd">新增部门</el-button>
</div>
<!-- 树形表格 el‑table‑tree 实现树形表格 -->
<el-table
:data="deptTreeData"
row-key="id"
border
>
<el-table-column label="部门名称" prop="deptName"/>
<el-table-column label="上级ID" prop="parentId"/>
<el-table-column label="操作">
<template #default="scope">
<el-link type="primary" @click="openEdit(scope.row)">编辑</el-link>
<el-link type="danger" style="margin‑left:10px" @click="handleDelete(scope.row)">删除</el-link>
</template>
</el-table-column>
</el-table>
<DeptDialog
v-model:visible="dialogShow"
:row-data="currentRow"
@success="handleDialogSuccess"
/>
</div>
</template>
<script setup>
import {ref,onMounted} from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import DeptDialog from './components/DeptDialog.vue'
import {getDeptTree,addDept,updateDept,deleteDept} from '@/api/dept'
const deptTreeData = ref([])
const dialogShow = ref(false)
const currentRow = ref(null)
async function getDeptList(){
const res = await getDeptTree()
deptTreeData.value = res.data
}
function openAdd(){
currentRow.value = null
dialogShow.value = true
}
function openEdit(row){
currentRow.value = row
dialogShow.value = true
}
async function handleDialogSuccess({form,isEdit}){
if(isEdit){
await updateDept(form)
ElMessage.success('编辑部门成功')
}else{
await addDept(form)
ElMessage.success('新增部门成功')
}
getDeptList()
}
async function handleDelete(row){
ElMessageBox.confirm('确定删除该部门?','提示',{type:'warning'})
.then(async ()=>{
await deleteDept({id:row.id})
ElMessage.success('删除成功')
getDeptList()
}).catch(()=>{})
}
onMounted(()=>{
getDeptList()
})
</script>
5、路由配置新增部门管理路由
打开router/index.js,在后端动态返回的菜单 mock 中增加部门管理路由。
{
path:'/system/dept',
component:'/system/dept/index',
meta:{title:'部门管理',icon:'OfficeBuilding'}
}
测试
- 进入部门管理页面,树形表格渲染,父子部门层级展示
- 新增顶级部门、新增子部门;编辑、删除部门,mock 接收请求。
