Tree display and search for department management
The data display page is a tree. We can load the data at one time, and we can also query the sub-departments by clicking the id load once. We get the json data once and load it. If there is not much data, we can use
recursion. If there is a lot of data, we can use lazy loading. The way
Since the sub-department is relatively deep, it is not suitable, as shown in the menu between permission group roles
Write the backend interface
DepartmentController
@RestController
@RequestMapping("/system/basic/department")
public class DepartmentController {
@Autowired
DepartmentService departmentService;
@GetMapping("/")
public List<Department> getAllDepartments(){
return departmentService.getAllDepartments();
}
}
DepartmentService
@Service
public class DepartmentService {
@Autowired
DepartmentMapper departmentMapper;
public List<Department> getAllDepartments() {
//传递-1直接查询最顶级的股东会然后根据mybatis语句进行递归
return departmentMapper.getAllDepartmentsByParentId(-1);
}
}
DepartmentMapper
<resultMap id="DepartmentWithChildren" type="com.xyg.pojo.Department" extends="BaseResultMap"> <!--当查询的时候会以children属性会调用select把当前id传进去,然后新查询的同会继续调用,形成一个递归-->
<collection property="children" ofType="com.xyg.pojo.Department" select="com.xyg.mapper.DepartmentMapper.getAllDepartmentsByParentId" column="id" ></collection>
</resultMap>
<select id="getAllDepartmentsByParentId" resultMap="DepartmentWithChildren">
select * from department where parentid = #{pid}
</select>
Entity class adds a children field one-to-many
test
front-end writing
Add elementui component
DemMarna.vue
<div style="width: 500px">
<el-input
prefix-icon="el-icon-search"
placeholder="输入部门名称进行搜索"
v-model="filterText">
</el-input>
<el-tree
:data="deps"
:props="defaultProps"
default-expand-all
:filter-node-method="filterNode" //过滤的方法
ref="tree">
</el-tree>
</div>
data(){
return{
filterText:"",
deps:[],
defaultProps: {
children: 'children',
label: 'name'
}
}
},
mounted(){
this.getDeps()
},
methods: {
getDeps(){
this.getRequest("/system/basic/department/").then(resp=>{
if(resp){
this.deps=resp
}
})
},
Data display effect
Front-end query filtering
filterNode(value, data) {
//过滤的方法,value传过来的最新值,data的Json数组得出每一项,
if (!value) return true; //进行比较,如果value不存在的话直接返回true,表示当前的data留着,否则剔除掉
return data.name.indexOf(value) !== -1;//ata.name是否包含这个值,如果不等于-1就返回值这个值
}
watch: {
//监控filterText值发生变化
filterText(val) {
this.$refs.tree.filter(val);//会触发这个方法
}
},
In short, it is to monitor the variables bound to the input box to monitor whether there is any change, trigger the filter method, and
realize the front-end query through the method
Department tree shows adding and deleting
Use this
to paste into the tree component
and use this method to solve it : expand-on-click-node="false" Whether to expand or shrink the node when the node is clicked, the default value is true, if it is false, there is only an arrow icon Only when the node is expanded or contracted.
<!-- :expand-on-click-node="false" 是否在点击节点的时候展开或者收缩节点, 默认值为 true,如果为 false,则只有点箭头图标的时候才会展开或者收缩节点。-->
<el-tree
:data="deps"
node-key="id"
:props="defaultProps"
:expand-on-click-node="false"
:filter-node-method="filterNode"
ref="tree">
<!--slot-scope="{ node, data } node指当前的元素( :props="defaultProps"),data值得到就是服务端返回的json对象-->
<span class="custom-tree-node" style="display: flex; justify-content: space-between; width: 100%" slot-scope="{ node, data }">
<span>{
{
data.name }}</span>
<span>
<el-button
class="depBtn"
type="primary"
size="mini"
@click="() => showAddDep(data)">
添加部门
</el-button>
<el-button
class="depBtn"
type="danger"
size="mini"
@click="() => delDeps(node, data)">
删除部门
</el-button>
</span>
</span>
</el-tree>
</div>
Effect
Addition of backend department tree
If you add a department on the board of directors, it is a sub-department of the board of directors, so the parameters to be passed are the id of the parent department and the name of the added department
The first step is to add the name, and partentid fields, and the id will be automatically generated. The
second step is to query the partentid according to the generated id to generate its own depPath. The third step isParent has no sub-departments for flash. true if it has its own subdepartment
This is not difficult, write service plus transaction in three steps
DepartmentController
@PostMapping("/")
public RespBean AddDep(@RequestBody Department department) {
if(department.getName()!=""){
Department department1 = departmentService.AddDep(department);
if (department1 != null) {
return RespBean.ok("添加成功",department1);
}
}
return RespBean.err("添加失败");
}
DepartmentService
@Transactional
public Department AddDep(Department department) {
//第一步做添加操作把name,和partentid字段加进来,id会自动生成,数据库返回新增的id
departmentMapper.insertDep(department);
//第二步就要去根据生成的id,查询到他partentid生成组成自己的depPath,
//根据id查询出自己的对象
Department dep = departmentMapper.selectByPrimaryKey(department.getId());
//获取当前对象父id的对象
Department parDep = departmentMapper.selectParentDepath(dep.getParentid());
//获取父id的deppath加自己的id,生成自己Deppath
String Deppath=parDep.getDeppath()+'.'+department.getId();
if (Deppath.toString().startsWith("null")){
throw new RuntimeException("操作错误");
}
//设置自己Deppath
department.setDeppath(Deppath);
//设自己是可启用
department.setEnabled(true);
//设置自己刚添加是没有子部门
department.setIsparent(false);
//进行更新操作
departmentMapper.updateByPrimaryKey(department);
//如果有新数据进行添加如果有父部门,都把父部门的Isparent 更新为 true
Department department1 = departmentMapper.selectByPrimaryKey(department.getParentid());
department1.setIsparent(true);
departmentMapper.updateByPrimaryKey(department1);
return departmentMapper.selectByPrimaryKey(department.getId());
}
DepartmentMapper
The mapper only writes this interface, and the others exist
int insertDep(Department record);
<!--useGeneratedKeys="true" keyProperty="id" 实现id回调,获取插入数据库的id-->
<insert id="insertDep" parameterType="com.xyg.pojo.Department" useGeneratedKeys="true" keyProperty="id" >
insert into department (id, name, parentId,
depPath, enabled, isParent)
values (#{id,jdbcType=INTEGER}, #{name,jdbcType=VARCHAR}, #{parentid,jdbcType=INTEGER},
#{deppath,jdbcType=VARCHAR}, #{enabled,jdbcType=BIT}, #{isparent,jdbcType=BIT})
</insert>
Front-end docking
When clicking add, the input box should pop up
<el-dialog
title="添加部门"
:visible.sync="dialogVisible"
width="30%">
<div>
<el-tag size="small">上级部门</el-tag>
<span >{
{
this.parDep.name}}</span>
</div>
<div style="margin-top: 8px">
<el-tag size="small">部门名称</el-tag>
<el-input size="mini" v-model="chalDep.name" placeholder="请输入部门名称" style="width: 200px"></el-input>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="cannelChal">取 消</el-button>
<el-button type="primary" @click="chalAdd">确 定</el-button>
</span>
</el-dialog>
showAddDep(data){
console.log(data)
this.dialogVisible=true
this.parDep=data
this.chalDep.parentid=data.id
},
#Interface docking
cannelChal(){
this.dialogVisible=false;
this.chalDep.name=""
},
chalAdd(){
this.postRequest("/system/basic/department/",this.chalDep).then(resp=>{
if (resp){
this.getDeps()
this.chalDep.name=""
this.dialogVisible=false
}
})
},
Deletion of the backend department
DepartmentController
@DeleteMapping("/{id}")
public RespBean delDep(@PathVariable Integer id){
if(departmentService.delDep(id)==1){
return RespBean.ok("删除成功");
}
return RespBean.err("删除失败");
}
DepartmentService
public Integer delDep(Integer id) {
return departmentMapper.delDep(id);
}
DepartmentMapper
Integer delDep(Integer id) ;
<delete id="delDep" >
delete from department where id=#{id}
</delete>
Front-end docking
delDeps(node,data){
this.$confirm('此操作将永久删除, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.deleteRequest("/system/basic/department/"+data.id).then(resp=>{
if(resp){
this.getDeps()
}
})
}).catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
});
});
},
getDeps(){
this.getRequest("/system/basic/department/").then(resp=>{
if(resp){
this.deps=resp
}
})
},
filterNode(value, data) {
//过滤的方法,value传过来的最新值,data的Json数组得出每一项,
if (!value) return true; //进行比较,如果value不存在的话直接返回true,表示当前的data留着,否则剔除掉
return data.name.indexOf(value) !== -1;//ata.name是否包含这个值,如果不等于-1就返回值这个值
}
},
watch: {
//监控filterText值发生变化
filterText(val) {
this.$refs.tree.filter(val);//会触发这个方法
}
},
Fix tree component addition and removal shrinkage issues
After the el-tree in element-ui adds or deletes child nodes, that is, the tree will be closed every time the data is refreshed, but if we still need to perform follow-up operations under the current node, and there are many layers of nodes , it is very troublesome, and the user experience is very poor, so how to solve it?
Solution: Define an array, and then when you click on a tree node, save it and store it in the data. After refreshing, the nodes that were expanded before the tree can still be expanded.
handleNodeClick(data) {
this.defaultExpandKeys.push(data.id) ;//记录当前点击节点,并赋值给默认展开的节点的 key 的数组
},