|
|
package com.yf.exam.modules.sys.depart.service.impl;
|
|
|
|
|
|
// 导入 MyBatis-Plus 的查询条件构造器,用于构建数据库查询条件
|
|
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
|
|
// 导入 MyBatis-Plus 的分页元数据接口,用于处理分页查询结果
|
|
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
|
|
// 导入 MyBatis-Plus 的分页类,用于创建分页对象
|
|
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
|
// 导入 MyBatis-Plus 的服务实现基类,提供通用的服务层方法
|
|
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
|
// 导入自定义的分页请求数据传输对象类,用于封装分页查询请求参数
|
|
|
import com.yf.exam.core.api.dto.PagingReqDTO;
|
|
|
// 导入自定义的 Bean 映射工具类,用于对象属性的复制
|
|
|
import com.yf.exam.core.utils.BeanMapper;
|
|
|
// 导入系统部门数据传输对象类,用于在不同层之间传输部门信息
|
|
|
import com.yf.exam.modules.sys.depart.dto.SysDepartDTO;
|
|
|
// 导入系统部门树状数据传输对象类,用于返回部门的树状结构信息
|
|
|
import com.yf.exam.modules.sys.depart.dto.response.SysDepartTreeDTO;
|
|
|
// 导入系统部门实体类,对应数据库中的部门表
|
|
|
import com.yf.exam.modules.sys.depart.entity.SysDepart;
|
|
|
// 导入系统部门映射器接口,用于与数据库进行交互
|
|
|
import com.yf.exam.modules.sys.depart.mapper.SysDepartMapper;
|
|
|
// 导入系统部门服务接口,定义部门相关的业务方法
|
|
|
import com.yf.exam.modules.sys.depart.service.SysDepartService;
|
|
|
// 导入 Apache Commons Lang3 工具类,用于字符串操作
|
|
|
import org.apache.commons.lang3.StringUtils;
|
|
|
// 导入 Spring 工具类,用于集合操作
|
|
|
import org.springframework.util.CollectionUtils;
|
|
|
|
|
|
import java.util.ArrayList;
|
|
|
import java.util.HashMap;
|
|
|
import java.util.List;
|
|
|
import java.util.Map;
|
|
|
|
|
|
/**
|
|
|
* <p>
|
|
|
* 部门信息业务实现类,实现了系统部门服务接口,处理部门相关的业务逻辑
|
|
|
* </p>
|
|
|
*
|
|
|
* @author 聪明笨狗
|
|
|
* @since 2020-09-02 17:25
|
|
|
*/
|
|
|
// 将该类标记为 Spring 服务组件,使其可以被 Spring 容器管理
|
|
|
@Service
|
|
|
public class SysDepartServiceImpl extends ServiceImpl<SysDepartMapper, SysDepart> implements SysDepartService {
|
|
|
|
|
|
/**
|
|
|
* 0标识为顶级分类,作为根部门的标记
|
|
|
*/
|
|
|
private static final String ROOT_TAG = "0";
|
|
|
|
|
|
/**
|
|
|
* 保存或更新部门信息
|
|
|
* 如果传入的部门 ID 为空,则填充部门编码;否则,清空排序和部门编码信息
|
|
|
* @param reqDTO 部门信息数据传输对象,包含要保存或更新的部门信息
|
|
|
*/
|
|
|
@Override
|
|
|
public void save(SysDepartDTO reqDTO) {
|
|
|
// 判断传入的部门 ID 是否为空
|
|
|
if(StringUtils.isBlank(reqDTO.getId())) {
|
|
|
// 若为空,则填充部门编码
|
|
|
this.fillCode(reqDTO);
|
|
|
} else {
|
|
|
// 若不为空,则清空排序和部门编码信息
|
|
|
reqDTO.setSort(null);
|
|
|
reqDTO.setDeptCode(null);
|
|
|
}
|
|
|
|
|
|
// 创建一个新的部门实体对象
|
|
|
SysDepart entity = new SysDepart();
|
|
|
// 使用 BeanMapper 工具类将部门数据传输对象的属性复制到部门实体对象中
|
|
|
BeanMapper.copy(reqDTO, entity);
|
|
|
// 调用 MyBatis-Plus 的保存或更新方法,保存或更新部门信息
|
|
|
this.saveOrUpdate(entity);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 分页查询部门信息,并将结果转换为树状结构
|
|
|
* @param reqDTO 分页请求数据传输对象,包含分页查询的条件和参数
|
|
|
* @return 分页的部门树状结构数据传输对象列表
|
|
|
*/
|
|
|
@Override
|
|
|
public IPage<SysDepartTreeDTO> paging(PagingReqDTO<SysDepartDTO> reqDTO) {
|
|
|
// 创建分页对象,传入当前页码和每页记录数
|
|
|
Page query = new Page(reqDTO.getCurrent(), reqDTO.getSize());
|
|
|
// 获取请求参数中的部门信息
|
|
|
SysDepartDTO params = reqDTO.getParams();
|
|
|
// 调用映射器的分页查询方法,将结果转换为部门树状结构数据传输对象列表
|
|
|
IPage<SysDepartTreeDTO> pageData = baseMapper.paging(query, params);
|
|
|
|
|
|
return pageData;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 查找部门树状结构,调用重载方法,不传入部门 ID 列表
|
|
|
* @return 部门树状结构数据传输对象列表
|
|
|
*/
|
|
|
@Override
|
|
|
public List<SysDepartTreeDTO> findTree() {
|
|
|
return this.findTree(null);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 根据指定的部门 ID 列表查找部门树状结构
|
|
|
* @param ids 部门 ID 列表,若为空则查找所有部门的树状结构
|
|
|
* @return 部门树状结构数据传输对象列表
|
|
|
*/
|
|
|
@Override
|
|
|
public List<SysDepartTreeDTO> findTree(List<String> ids) {
|
|
|
// 创建查询条件构造器
|
|
|
QueryWrapper<SysDepart> wrapper = new QueryWrapper();
|
|
|
// 按部门排序字段升序排序
|
|
|
wrapper.lambda().orderByAsc(SysDepart::getSort);
|
|
|
|
|
|
// 判断传入的部门 ID 列表是否不为空
|
|
|
if(!CollectionUtils.isEmpty(ids)) {
|
|
|
// 存储所有相关部门 ID 的列表
|
|
|
List<String> fullIds = new ArrayList<>();
|
|
|
// 遍历传入的部门 ID 列表
|
|
|
for(String id: ids) {
|
|
|
// 递归获取该部门及其所有父部门的 ID 并添加到 fullIds 列表中
|
|
|
this.cycleAllParent(fullIds, id);
|
|
|
}
|
|
|
|
|
|
// 判断 fullIds 列表是否不为空
|
|
|
if(!CollectionUtils.isEmpty(fullIds)) {
|
|
|
// 将查询条件限制为 fullIds 列表中的部门 ID
|
|
|
wrapper.lambda().in(SysDepart::getId, fullIds);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 根据查询条件获取所有部门列表
|
|
|
List<SysDepart> list = this.list(wrapper);
|
|
|
// 使用 BeanMapper 工具类将部门实体列表转换为部门树状结构数据传输对象列表
|
|
|
List<SysDepartTreeDTO> dtoList = BeanMapper.mapList(list, SysDepartTreeDTO.class);
|
|
|
|
|
|
// 存储每个父部门 ID 对应的子部门列表的映射
|
|
|
Map<String,List<SysDepartTreeDTO>> map = new HashMap<>(16);
|
|
|
|
|
|
// 遍历部门树状结构数据传输对象列表
|
|
|
for(SysDepartTreeDTO item: dtoList) {
|
|
|
// 判断映射中是否已存在该父部门 ID
|
|
|
if(map.containsKey(item.getParentId())) {
|
|
|
// 若存在,则将该部门添加到对应的子部门列表中
|
|
|
map.get(item.getParentId()).add(item);
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
// 若不存在,则创建一个新的子部门列表,并将该部门添加到列表中
|
|
|
List<SysDepartTreeDTO> a = new ArrayList<>();
|
|
|
a.add(item);
|
|
|
// 将该父部门 ID 和对应的子部门列表添加到映射中
|
|
|
map.put(item.getParentId(), a);
|
|
|
}
|
|
|
|
|
|
// 获取根部门(父部门 ID 为 0)的子部门列表
|
|
|
List<SysDepartTreeDTO> topList = map.get(ROOT_TAG);
|
|
|
// 判断根部门的子部门列表是否不为空
|
|
|
if(!CollectionUtils.isEmpty(topList)) {
|
|
|
// 遍历根部门的子部门列表
|
|
|
for(SysDepartTreeDTO item: topList) {
|
|
|
// 递归填充每个部门的子部门信息
|
|
|
this.fillChildren(map, item);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return topList;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 对部门进行排序操作,可实现部门的上升或下降排序
|
|
|
* @param id 要排序的部门 ID
|
|
|
* @param sort 排序方式,0 表示上升,1 表示下降
|
|
|
*/
|
|
|
@Override
|
|
|
public void sort(String id, Integer sort) {
|
|
|
// 根据部门 ID 获取要排序的部门实体对象
|
|
|
SysDepart depart = this.getById(id);
|
|
|
// 用于交换排序的部门实体对象
|
|
|
SysDepart exchange = null;
|
|
|
|
|
|
// 创建查询条件构造器
|
|
|
QueryWrapper<SysDepart> wrapper = new QueryWrapper<>();
|
|
|
// 限制查询条件为与要排序的部门同级(父部门相同)
|
|
|
wrapper.lambda()
|
|
|
.eq(SysDepart::getParentId, depart.getParentId());
|
|
|
// 限制查询结果只返回一条记录
|
|
|
wrapper.last("LIMIT 1");
|
|
|
|
|
|
// 判断排序方式是否为上升
|
|
|
if(sort == 0) {
|
|
|
// 限制查询条件为排序值小于要排序部门的排序值,并按排序值降序排序
|
|
|
wrapper.lambda()
|
|
|
.lt(SysDepart::getSort, depart.getSort())
|
|
|
.orderByDesc(SysDepart::getSort);
|
|
|
// 获取满足条件的部门实体对象
|
|
|
exchange = this.getOne(wrapper, false);
|
|
|
}
|
|
|
|
|
|
// 判断排序方式是否为下降
|
|
|
if(sort == 1) {
|
|
|
// 限制查询条件为排序值大于要排序部门的排序值,并按排序值升序排序
|
|
|
wrapper.lambda()
|
|
|
.gt(SysDepart::getSort, depart.getSort())
|
|
|
.orderByAsc(SysDepart::getSort);
|
|
|
// 获取满足条件的部门实体对象
|
|
|
exchange = this.getOne(wrapper, false);
|
|
|
}
|
|
|
|
|
|
// 判断是否找到可交换排序的部门实体对象
|
|
|
if(exchange != null) {
|
|
|
// 创建一个新的部门实体对象,用于更新要排序的部门的排序值
|
|
|
SysDepart a = new SysDepart();
|
|
|
a.setId(id);
|
|
|
a.setSort(exchange.getSort());
|
|
|
// 创建一个新的部门实体对象,用于更新可交换排序的部门的排序值
|
|
|
SysDepart b = new SysDepart();
|
|
|
b.setId(exchange.getId());
|
|
|
b.setSort(depart.getSort());
|
|
|
// 调用 MyBatis-Plus 的更新方法,更新两个部门的排序值
|
|
|
this.updateById(a);
|
|
|
this.updateById(b);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 填充部门编码,根据父部门信息和同级部门排序生成新的部门编码
|
|
|
* @param reqDTO 部门信息数据传输对象,用于填充部门编码
|
|
|
*/
|
|
|
private void fillCode(SysDepartDTO reqDTO) {
|
|
|
// 部门编码的前缀
|
|
|
String code = "";
|
|
|
|
|
|
// 判断传入的父部门 ID 是否不为空且不为根部门 ID
|
|
|
if(StringUtils.isNotBlank(reqDTO.getParentId())
|
|
|
&& !ROOT_TAG.equals(reqDTO.getParentId())) {
|
|
|
// 根据父部门 ID 获取父部门实体对象
|
|
|
SysDepart parent = this.getById(reqDTO.getParentId());
|
|
|
// 将父部门的编码作为前缀
|
|
|
code = parent.getDeptCode();
|
|
|
}
|
|
|
|
|
|
// 创建查询条件构造器
|
|
|
QueryWrapper<SysDepart> wrapper = new QueryWrapper<>();
|
|
|
// 限制查询条件为与要填充编码的部门同级(父部门相同),并按排序值降序排序
|
|
|
wrapper.lambda()
|
|
|
.eq(SysDepart::getParentId, reqDTO.getParentId())
|
|
|
.orderByDesc(SysDepart::getSort);
|
|
|
// 限制查询结果只返回一条记录
|
|
|
wrapper.last("LIMIT 1");
|
|
|
// 获取满足条件的部门实体对象
|
|
|
SysDepart depart = this.getOne(wrapper, false);
|
|
|
|
|
|
// 判断是否找到同级部门实体对象
|
|
|
if(depart != null) {
|
|
|
// 生成新的部门编码,将同级部门的排序值加 1 并格式化后添加到前缀后面
|
|
|
code += this.formatCode(depart.getSort() + 1);
|
|
|
// 设置要填充编码的部门的排序值为同级部门的排序值加 1
|
|
|
reqDTO.setSort(depart.getSort() + 1);
|
|
|
} else {
|
|
|
// 若未找到同级部门实体对象,则生成新的部门编码,排序值为 1 并格式化后添加到前缀后面
|
|
|
code += this.formatCode(1);
|
|
|
// 设置要填充编码的部门的排序值为 1
|
|
|
reqDTO.setSort(1);
|
|
|
}
|
|
|
|
|
|
// 设置要填充编码的部门的部门编码
|
|
|
reqDTO.setDeptCode(code);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 格式化排序值,根据排序值生成对应的部门编码前缀
|
|
|
* @param sort 排序值
|
|
|
* @return 格式化后的部门编码前缀
|
|
|
*/
|
|
|
private String formatCode(Integer sort) {
|
|
|
// 判断排序值是否小于 10
|
|
|
if(sort < 10) {
|
|
|
// 若小于 10,则在排序值前添加 "A0"
|
|
|
return "A0" + sort;
|
|
|
}
|
|
|
// 若不小于 10,则在排序值前添加 "A"
|
|
|
return "A" + sort;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 递归填充部门的子部门信息
|
|
|
* @param map 存储每个父部门 ID 对应的子部门列表的映射
|
|
|
* @param item 当前要填充子部门信息的部门树状结构数据传输对象
|
|
|
*/
|
|
|
private void fillChildren(Map<String,List<SysDepartTreeDTO>> map, SysDepartTreeDTO item) {
|
|
|
// 判断映射中是否存在该部门 ID 对应的子部门列表
|
|
|
if(map.containsKey(item.getId())) {
|
|
|
// 获取该部门 ID 对应的子部门列表
|
|
|
List<SysDepartTreeDTO> children = map.get(item.getId());
|
|
|
// 判断子部门列表是否不为空
|
|
|
if(!CollectionUtils.isEmpty(children)) {
|
|
|
// 遍历子部门列表
|
|
|
for(SysDepartTreeDTO sub: children) {
|
|
|
// 递归填充每个子部门的子部门信息
|
|
|
this.fillChildren(map, sub);
|
|
|
}
|
|
|
}
|
|
|
// 设置该部门的子部门列表
|
|
|
item.setChildren(children);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 获取指定部门及其所有子部门的 ID 列表
|
|
|
* @param id 要获取子部门 ID 列表的部门 ID
|
|
|
* @return 包含指定部门及其所有子部门 ID 的列表
|
|
|
*/
|
|
|
@Override
|
|
|
public List<String> listAllSubIds( String id) {
|
|
|
// 存储指定部门及其所有子部门 ID 的列表
|
|
|
List<String> ids = new ArrayList<>();
|
|
|
// 递归获取指定部门及其所有子部门的 ID 并添加到列表中
|
|
|
this.cycleAllSubs(ids, id);
|
|
|
return ids;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 递归获取指定部门及其所有子部门的 ID 并添加到列表中
|
|
|
* @param list 存储部门 ID 的列表
|
|
|
* @param id 当前要处理的部门 ID
|
|
|
*/
|
|
|
private void cycleAllSubs(List<String> list, String id) {
|
|
|
// 将当前部门 ID 添加到列表中
|
|
|
list.add(id);
|
|
|
|
|
|
// 创建查询条件构造器
|
|
|
QueryWrapper<SysDepart> wrapper = new QueryWrapper<>();
|
|
|
// 限制查询条件为父部门 ID 等于当前部门 ID,并按排序值降序排序
|
|
|
wrapper.lambda()
|
|
|
.eq(SysDepart::getParentId, id)
|
|
|
.orderByDesc(SysDepart::getSort);
|
|
|
// 获取满足条件的子部门列表
|
|
|
List<SysDepart> subList = this.list(wrapper);
|
|
|
// 判断子部门列表是否不为空
|
|
|
if(!CollectionUtils.isEmpty(subList)) {
|
|
|
// 遍历子部门列表
|
|
|
for(SysDepart item: subList) {
|
|
|
// 递归处理每个子部门
|
|
|
this.cycleAllSubs(list, item.getId());
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 递归获取指定部门及其所有父部门的 ID 并添加到列表中
|
|
|
* @param list 存储部门 ID 的列表
|
|
|
* @param id 当前要处理的部门 ID
|
|
|
*/
|
|
|
private void cycleAllParent(List<String> list, String id) {
|
|
|
// 将当前部门 ID 添加到列表中
|
|
|
list.add(id);
|
|
|
// 根据部门 ID 获取部门实体对象
|
|
|
SysDepart depart = this.getById(id);
|
|
|
|
|
|
// 判断该部门的父部门 ID 是否不为空且不为根部门 ID
|
|
|
if(StringUtils.isNotBlank(depart.getParentId())
|
|
|
&& !ROOT_TAG.equals(depart.getParentId())) {
|
|
|
// 递归处理该部门的父部门
|
|
|
this.cycleAllParent(list, depart.getParentId());
|
|
|
}
|
|
|
}
|
|
|
}
|