diff --git a/src/main/java/cn/lihongjie/coal/base/dao/BaseRepository.java b/src/main/java/cn/lihongjie/coal/base/dao/BaseRepository.java index 36c4bc2c..bdf85633 100644 --- a/src/main/java/cn/lihongjie/coal/base/dao/BaseRepository.java +++ b/src/main/java/cn/lihongjie/coal/base/dao/BaseRepository.java @@ -16,6 +16,8 @@ public interface BaseRepository extends JpaRepository, JpaSpecific return findById(id).orElseThrow(() -> new RuntimeException("数据不存在: " + id)); } + + default List findByOrganizationId(String organizationId) { return findAll( (root, query, cb) -> { diff --git a/src/main/java/cn/lihongjie/coal/common/TreeUtils.java b/src/main/java/cn/lihongjie/coal/common/TreeUtils.java index 960a2bc7..79e483d3 100644 --- a/src/main/java/cn/lihongjie/coal/common/TreeUtils.java +++ b/src/main/java/cn/lihongjie/coal/common/TreeUtils.java @@ -15,6 +15,31 @@ import java.util.function.Function; @UtilityClass public class TreeUtils { + + + public static Iterable buildTreeFromList(Iterable src, Function idGetter, Function parentIdGetter, Function2 childrenAppender) { + Map map = new HashMap<>(); + List roots = new ArrayList<>(); + for (T t : src) { + map.put(idGetter.apply(t), t); + } + for (T t : src) { + String parentId = parentIdGetter.apply(t); + if (parentId == null || parentId.isEmpty()) { + roots.add(t); + } else { + T parent = map.get(parentId); + if (parent == null) { + throw new BizException("父节点不存在 " + parentId); + } + + childrenAppender.apply(parent, t); + } + } + return roots; + } + + public static Iterable allChildren(T src, Function> childrenGetter) { ArrayList ans = new ArrayList<>(); diff --git a/src/main/java/cn/lihongjie/coal/dbFunctions/DbFunctionService.java b/src/main/java/cn/lihongjie/coal/dbFunctions/DbFunctionService.java new file mode 100644 index 00000000..e6eabb06 --- /dev/null +++ b/src/main/java/cn/lihongjie/coal/dbFunctions/DbFunctionService.java @@ -0,0 +1,70 @@ +package cn.lihongjie.coal.dbFunctions; + +import io.hypersistence.utils.hibernate.type.array.StringArrayType; + +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; +import jakarta.persistence.Query; + +import org.hibernate.query.TypedParameterValue; +import org.springframework.stereotype.Service; + +import java.util.*; + +@Service +public class DbFunctionService { + + + @PersistenceContext + EntityManager entityManager; + + + public List selfAndChildrenIds(String tableName, List ids) { + return selfAndChildrenIds(tableName, ids, true); + } + + public List selfAndChildrenIds(String tableName, List ids, Boolean includeSelf){ + + + Query nativeQuery = entityManager.createNativeQuery(""" + + select self_and_children_ids(:tableName, :ids, :includeSelf) + + """); + + nativeQuery.setParameter("tableName", tableName); + nativeQuery.unwrap(org.hibernate.query.Query.class).setParameter("ids", new TypedParameterValue(StringArrayType.INSTANCE, ids.toArray())); + nativeQuery.setParameter("includeSelf", includeSelf); + List resultList = nativeQuery.getResultList(); + + if (resultList.isEmpty()){ + return Collections.emptyList(); + } + return Arrays.stream(((String[]) resultList.get(0))).toList(); + } + + + public List selfAndParentIds(String tableName, List ids) { + return selfAndParentIds(tableName, ids, true); + } + + public List selfAndParentIds(String tableName, List ids, Boolean includeSelf){ + + + Query nativeQuery = entityManager.createNativeQuery(""" + + select self_and_parent_ids(:tableName, :ids, :includeSelf) + + """); + + nativeQuery.setParameter("tableName", tableName); + nativeQuery.unwrap(org.hibernate.query.Query.class).setParameter("ids", new TypedParameterValue(StringArrayType.INSTANCE, ids.toArray())); + nativeQuery.setParameter("includeSelf", includeSelf); + List resultList = nativeQuery.getResultList(); + + if (resultList.isEmpty()){ + return Collections.emptyList(); + } + return Arrays.stream(((String[]) resultList.get(0))).toList(); + } +} diff --git a/src/main/java/cn/lihongjie/coal/department/controller/DepartmentController.java b/src/main/java/cn/lihongjie/coal/department/controller/DepartmentController.java index 79d8d755..5441baec 100644 --- a/src/main/java/cn/lihongjie/coal/department/controller/DepartmentController.java +++ b/src/main/java/cn/lihongjie/coal/department/controller/DepartmentController.java @@ -58,8 +58,8 @@ public class DepartmentController { @PostMapping("/roots") - public List roots() { - return this.service.getRoots(); + public List roots(@RequestBody CommonQuery request) { + return this.service.getRoots(request); } @PostMapping("/treeByIds") diff --git a/src/main/java/cn/lihongjie/coal/department/dto/DepartmentDto.java b/src/main/java/cn/lihongjie/coal/department/dto/DepartmentDto.java index d409df83..84104ec8 100644 --- a/src/main/java/cn/lihongjie/coal/department/dto/DepartmentDto.java +++ b/src/main/java/cn/lihongjie/coal/department/dto/DepartmentDto.java @@ -4,9 +4,15 @@ import cn.lihongjie.coal.base.dto.OrgCommonDto; import lombok.Data; +import java.util.List; + @Data public class DepartmentDto extends OrgCommonDto { private String parent; - private Integer empCount; + private List allEmpIds; + + private List childrenEmpIds; + + private List selfEmpIds; } diff --git a/src/main/java/cn/lihongjie/coal/department/dto/DepartmentTreeDto.java b/src/main/java/cn/lihongjie/coal/department/dto/DepartmentTreeDto.java index 858d2596..cd03b763 100644 --- a/src/main/java/cn/lihongjie/coal/department/dto/DepartmentTreeDto.java +++ b/src/main/java/cn/lihongjie/coal/department/dto/DepartmentTreeDto.java @@ -8,7 +8,11 @@ import java.util.List; @Data public class DepartmentTreeDto extends OrgCommonDto { - private Integer empCount; + private List allEmpIds; + + private List childrenEmpIds; + + private List selfEmpIds; private String parent; private List children; } diff --git a/src/main/java/cn/lihongjie/coal/department/entity/DepartmentEntity.java b/src/main/java/cn/lihongjie/coal/department/entity/DepartmentEntity.java index 582f4c7d..b39fe06f 100644 --- a/src/main/java/cn/lihongjie/coal/department/entity/DepartmentEntity.java +++ b/src/main/java/cn/lihongjie/coal/department/entity/DepartmentEntity.java @@ -2,16 +2,16 @@ package cn.lihongjie.coal.department.entity; import cn.lihongjie.coal.base.entity.OrgCommonEntity; -import jakarta.persistence.CascadeType; -import jakarta.persistence.Entity; -import jakarta.persistence.ManyToOne; -import jakarta.persistence.OneToMany; +import io.hypersistence.utils.hibernate.type.array.ListArrayType; + +import jakarta.persistence.*; import lombok.Getter; import lombok.Setter; import org.hibernate.annotations.Comment; import org.hibernate.annotations.Formula; +import org.hibernate.annotations.Type; import java.util.List; @@ -21,8 +21,21 @@ import java.util.List; @Setter public class DepartmentEntity extends OrgCommonEntity { - @Formula("(select count(*) from t_employee e where e.department_id = any(self_and_children_ids('t_department', id)))") - private Integer empCount; + + @Type(ListArrayType.class) + @Formula("(select array_agg(e.id) from t_employee e where e.department_id = any(self_and_children_ids('t_department', id, true)))") + private List allEmpIds; + + @Type(ListArrayType.class) + @Formula("(select array_agg(e.id) from t_employee e where e.department_id = any(self_and_children_ids('t_department', id, false)))") + private List childrenEmpIds; + + @Type(ListArrayType.class) + @Formula("(select array_agg(e.id) from t_employee e where e.department_id = id)") + private List selfEmpIds; + + + @OneToMany(mappedBy = "parent", cascade = CascadeType.ALL) private List children; diff --git a/src/main/java/cn/lihongjie/coal/department/mapper/DepartmentMapper.java b/src/main/java/cn/lihongjie/coal/department/mapper/DepartmentMapper.java index a6400ee9..bd5351ad 100644 --- a/src/main/java/cn/lihongjie/coal/department/mapper/DepartmentMapper.java +++ b/src/main/java/cn/lihongjie/coal/department/mapper/DepartmentMapper.java @@ -7,17 +7,28 @@ import cn.lihongjie.coal.department.dto.DepartmentTreeDto; import cn.lihongjie.coal.department.dto.UpdateDepartmentDto; import cn.lihongjie.coal.department.entity.DepartmentEntity; -import org.mapstruct.Mapper; -import org.mapstruct.MappingConstants; +import org.mapstruct.*; import org.mapstruct.control.DeepClone; @Mapper( componentModel = MappingConstants.ComponentModel.SPRING, - uses = {cn.lihongjie.coal.base.mapper.CommonMapper.class, cn.lihongjie.coal.base.mapper.CommonEntityMapper.class}, + uses = { + cn.lihongjie.coal.base.mapper.CommonMapper.class, + cn.lihongjie.coal.base.mapper.CommonEntityMapper.class + }, mappingControl = DeepClone.class) public interface DepartmentMapper extends BaseMapper< DepartmentEntity, DepartmentDto, CreateDepartmentDto, UpdateDepartmentDto> { + @Mappings({ + @Mapping(target = "children", qualifiedByName = "toTreeDto") + }) + @Named("toTreeDto") DepartmentTreeDto toTreeDto(DepartmentEntity departmentEntity); + + @Mappings({ + @Mapping(target = "children", ignore = true) + }) + DepartmentTreeDto toTreeDtoExcludeChildren(DepartmentEntity departmentEntity); } diff --git a/src/main/java/cn/lihongjie/coal/department/repository/DepartmentRepository.java b/src/main/java/cn/lihongjie/coal/department/repository/DepartmentRepository.java index 76dac28e..5dab43f2 100644 --- a/src/main/java/cn/lihongjie/coal/department/repository/DepartmentRepository.java +++ b/src/main/java/cn/lihongjie/coal/department/repository/DepartmentRepository.java @@ -6,4 +6,6 @@ import cn.lihongjie.coal.department.entity.DepartmentEntity; import org.springframework.stereotype.Repository; @Repository -public interface DepartmentRepository extends BaseRepository {} +public interface DepartmentRepository extends BaseRepository { + +} diff --git a/src/main/java/cn/lihongjie/coal/department/service/DepartmentService.java b/src/main/java/cn/lihongjie/coal/department/service/DepartmentService.java index 2c817778..98e18018 100644 --- a/src/main/java/cn/lihongjie/coal/department/service/DepartmentService.java +++ b/src/main/java/cn/lihongjie/coal/department/service/DepartmentService.java @@ -3,6 +3,8 @@ package cn.lihongjie.coal.department.service; import cn.lihongjie.coal.base.dto.CommonQuery; import cn.lihongjie.coal.base.dto.IdRequest; import cn.lihongjie.coal.base.service.BaseService; +import cn.lihongjie.coal.common.TreeUtils; +import cn.lihongjie.coal.dbFunctions.DbFunctionService; import cn.lihongjie.coal.department.dto.CreateDepartmentDto; import cn.lihongjie.coal.department.dto.DepartmentDto; import cn.lihongjie.coal.department.dto.DepartmentTreeDto; @@ -15,6 +17,7 @@ import jakarta.annotation.PostConstruct; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.CollectionUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.convert.ConversionService; import org.springframework.data.domain.Page; @@ -26,6 +29,7 @@ import org.springframework.transaction.annotation.Transactional; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; +import java.util.stream.StreamSupport; @Service @Slf4j @@ -70,10 +74,48 @@ class DepartmentService extends BaseService getRoots() { + @Autowired DbFunctionService dbFunctionService; + + public List getRoots(CommonQuery request) { + + if (CollectionUtils.isEmpty(request.getItems())){ + List roots = this.repository.findAll( (root, query, criteriaBuilder) -> criteriaBuilder.isNull(root.get("parent"))); + return roots.stream().map(de -> this.mapper.toTreeDto(de)).collect(Collectors.toList()); + }else { + Page page = + repository.findAll( + request.specification(conversionService), + PageRequest.of( + request.getPageNo(), + request.getPageSize(), + Sort.by(request.getOrders()))); + + List selfAndParentIds = + this.dbFunctionService.selfAndParentIds("t_department", + page.stream().map(x -> x.getId()).collect(Collectors.toList()), true); + + List selfAndParent = this.findAllByIds(selfAndParentIds).stream().map(x -> (this.mapper.toTreeDtoExcludeChildren(x))).collect(Collectors.toList()); + + + return StreamSupport.stream( + TreeUtils.buildTreeFromList( + selfAndParent, + DepartmentTreeDto::getId, + x -> x.getParent(), + (x, y) -> { + if (x.getChildren() == null) { + x.setChildren(new ArrayList<>()); + } + x.getChildren().add(y); + return null; + }) + .spliterator(), + false) + .collect(Collectors.toList()); + } + + - List roots = this.repository.findAll( (root, query, criteriaBuilder) -> criteriaBuilder.isNull(root.get("parent"))); - return roots.stream().map(de -> this.mapper.toTreeDto(de)).collect(Collectors.toList()); } diff --git a/src/main/java/cn/lihongjie/coal/dictionary/service/DictionaryService.java b/src/main/java/cn/lihongjie/coal/dictionary/service/DictionaryService.java index 4909effa..eafe095f 100644 --- a/src/main/java/cn/lihongjie/coal/dictionary/service/DictionaryService.java +++ b/src/main/java/cn/lihongjie/coal/dictionary/service/DictionaryService.java @@ -205,7 +205,7 @@ class DictionaryService extends BaseService