+34
-1
@@ -4,12 +4,14 @@ import io.swagger.v3.oas.annotations.Operation;
|
|||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
import com.yunhai.bschclassmanage.config.Config;
|
import com.yunhai.bschclassmanage.config.Config;
|
||||||
|
import com.yunhai.bschclassmanage.model.oa.TeaTreeVO;
|
||||||
import com.yunhai.bschclassmanage.model.vo.oa.SchInfoVO;
|
import com.yunhai.bschclassmanage.model.vo.oa.SchInfoVO;
|
||||||
|
import com.yunhai.bschclassmanage.service.IComSchTreeService;
|
||||||
import com.yunhai.bschclassmanage.service.ISchInfoService;
|
import com.yunhai.bschclassmanage.service.ISchInfoService;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.http.ResponseEntity;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@Tag(name = "SchGroup", description = "SchGroup related APIs")
|
@Tag(name = "SchGroup", description = "SchGroup related APIs")
|
||||||
@@ -18,7 +20,38 @@ import java.util.List;
|
|||||||
@CrossOrigin(originPatterns = {"*"}, allowCredentials = "true")
|
@CrossOrigin(originPatterns = {"*"}, allowCredentials = "true")
|
||||||
public class SchGroupController {
|
public class SchGroupController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IComSchTreeService comSchTreeService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ISchInfoService schInfoService;
|
||||||
|
|
||||||
|
@GetMapping("GetTeaTree")
|
||||||
|
@Operation(summary = "获取学校教师组树+教师(SchSerID 与 schId 二选一)")
|
||||||
|
public List<TeaTreeVO> getTeaTree(@RequestParam(value = "SchSerID", required = false) String SchSerID,
|
||||||
|
@RequestParam(value = "schId", required = false) Integer schId) {
|
||||||
|
Integer resolvedSchId = resolveSchId(schId, SchSerID);
|
||||||
|
if (resolvedSchId == null) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
return comSchTreeService.getSchTeaTree(resolvedSchId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析学校ID:支持直接传 schId,或传 SchSerID 反查 schId,二者至少提供一个。
|
||||||
|
*
|
||||||
|
* @param schId 学校内部ID(优先使用)
|
||||||
|
* @param schSerID 学校外部序列号
|
||||||
|
* @return 学校内部ID,参数非法或查不到时返回 null
|
||||||
|
*/
|
||||||
|
private Integer resolveSchId(Integer schId, String schSerID) {
|
||||||
|
if (schId != null) {
|
||||||
|
return schId;
|
||||||
|
}
|
||||||
|
if (schSerID == null || schSerID.trim().isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
SchInfoVO schInfoVO = schInfoService.GetSchFirst(schSerID);
|
||||||
|
return schInfoVO == null ? null : schInfoVO.getUserSchSerId();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.yunhai.bschclassmanage.service;
|
package com.yunhai.bschclassmanage.service;
|
||||||
|
|
||||||
import com.yunhai.bschclassmanage.entity.BaseDicGrade;
|
import com.yunhai.bschclassmanage.entity.BaseDicGrade;
|
||||||
|
import com.yunhai.bschclassmanage.model.oa.TeaTreeVO;
|
||||||
import com.yunhai.bschclassmanage.model.vo.SchSystemTreeVO;
|
import com.yunhai.bschclassmanage.model.vo.SchSystemTreeVO;
|
||||||
import com.yunhai.bschclassmanage.model.vo.SelectIntVO;
|
import com.yunhai.bschclassmanage.model.vo.SelectIntVO;
|
||||||
import com.yunhai.bschclassmanage.model.vo.SelectStrVO;
|
import com.yunhai.bschclassmanage.model.vo.SelectStrVO;
|
||||||
@@ -28,6 +29,8 @@ public interface IComSchTreeService {
|
|||||||
|
|
||||||
BoaGroup getTeacherTree(Integer schId);
|
BoaGroup getTeacherTree(Integer schId);
|
||||||
|
|
||||||
|
List<TeaTreeVO> getSchTeaTree(Integer schId);
|
||||||
|
|
||||||
List<SelectIntVO> getSchoolList();
|
List<SelectIntVO> getSchoolList();
|
||||||
|
|
||||||
BoaGroup getTeaTree(Integer schId, Boolean withSub);
|
BoaGroup getTeaTree(Integer schId, Boolean withSub);
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import com.yunhai.bschclassmanage.entity.*;
|
|||||||
import com.yunhai.bschclassmanage.enums.AcademicStage;
|
import com.yunhai.bschclassmanage.enums.AcademicStage;
|
||||||
import com.yunhai.bschclassmanage.enums.NodeType;
|
import com.yunhai.bschclassmanage.enums.NodeType;
|
||||||
import com.yunhai.bschclassmanage.enums.SchType;
|
import com.yunhai.bschclassmanage.enums.SchType;
|
||||||
|
import com.yunhai.bschclassmanage.model.oa.TeaTreeVO;
|
||||||
import com.yunhai.bschclassmanage.model.vo.SchSystemTreeVO;
|
import com.yunhai.bschclassmanage.model.vo.SchSystemTreeVO;
|
||||||
import com.yunhai.bschclassmanage.model.vo.SelectIntVO;
|
import com.yunhai.bschclassmanage.model.vo.SelectIntVO;
|
||||||
import com.yunhai.bschclassmanage.service.*;
|
import com.yunhai.bschclassmanage.service.*;
|
||||||
@@ -433,6 +434,150 @@ public class ComSchTreeService implements IComSchTreeService {
|
|||||||
return teaTree;
|
return teaTree;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 教师叶子的"未分组"节点 ID(与 getTeacherTree 的默认组保持一致) */
|
||||||
|
private static final int UNGROUPED_ID = -1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 教师组树 + 教师(SchGroup/GetTeaTree 输出)。
|
||||||
|
* 结构:学校根(type=1) → 教师组(type=1) → 子组递归 + 教师叶子(type=2)。
|
||||||
|
* 节点字段:pid=父节点id(根为0)、no=组取 BoaGroup.sort / 教师固定 0、
|
||||||
|
* isParent=组true/教师false、photo 固定空串(本库无头像数据)。
|
||||||
|
* 返回单元素列表(学校根节点)。
|
||||||
|
*/
|
||||||
|
public List<TeaTreeVO> getSchTeaTree(Integer schId) {
|
||||||
|
// 1. 学校根节点(远程组树的根即学校节点,取不到时用学校名兜底)
|
||||||
|
List<BoaGroup> schTree = getSchTree(schId);
|
||||||
|
BoaGroup schRoot = (schTree == null || schTree.isEmpty()) ? null : schTree.get(0);
|
||||||
|
TeaTreeVO rootVo = new TeaTreeVO();
|
||||||
|
if (schRoot != null && schRoot.getId() != null) {
|
||||||
|
rootVo.setId(schRoot.getId());
|
||||||
|
rootVo.setName(schRoot.getName());
|
||||||
|
rootVo.setNo(schRoot.getSort());
|
||||||
|
} else {
|
||||||
|
rootVo.setId(schId);
|
||||||
|
rootVo.setName(getSchoolName(schId));
|
||||||
|
rootVo.setNo(0);
|
||||||
|
}
|
||||||
|
rootVo.setPid(0);
|
||||||
|
rootVo.setType(1);
|
||||||
|
rootVo.setIsParent(true);
|
||||||
|
rootVo.setChildren(new ArrayList<>());
|
||||||
|
|
||||||
|
// 2. 教师组骨架(type=7 子树)转 VO,同时建立 groupId -> 节点 映射供挂教师用
|
||||||
|
Map<Integer, TeaTreeVO> groupVoMap = new HashMap<>();
|
||||||
|
BoaGroup teaTree = getTeaTree(schId, true);
|
||||||
|
TeaTreeVO teaRootVo;
|
||||||
|
if (teaTree == null || teaTree.getId() == null) {
|
||||||
|
teaRootVo = newGroupNode(0, "教师组", rootVo.getId(), 1);
|
||||||
|
} else {
|
||||||
|
teaRootVo = convertGroupTree(teaTree, rootVo.getId(), groupVoMap);
|
||||||
|
}
|
||||||
|
groupVoMap.put(teaRootVo.getId(), teaRootVo);
|
||||||
|
rootVo.getChildren().add(teaRootVo);
|
||||||
|
|
||||||
|
// 3. 挂教师:多组各挂一份;无组或组不在树中的落到"未分组"
|
||||||
|
List<SchTeacher> teacherList = schTeacherService.getSchTeacherList(schId);
|
||||||
|
if (CollectionUtils.isNotEmpty(teacherList)) {
|
||||||
|
List<Integer> teaIds = teacherList.stream()
|
||||||
|
.map(SchTeacher::getTeaId)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
Map<Integer, List<Integer>> teaIdToGroupIds = schTeacherGroupRepository.findByTeaIdInAndSchId(teaIds, schId)
|
||||||
|
.stream()
|
||||||
|
.collect(Collectors.groupingBy(SchTeacherGroup::getTeaId,
|
||||||
|
Collectors.mapping(SchTeacherGroup::getGroupId, Collectors.toList())));
|
||||||
|
|
||||||
|
for (SchTeacher teacher : teacherList) {
|
||||||
|
if (teacher.getTeaId() == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
List<Integer> groupIds = teaIdToGroupIds.getOrDefault(teacher.getTeaId(), Collections.emptyList());
|
||||||
|
if (groupIds.isEmpty()) {
|
||||||
|
TeaTreeVO ungrouped = getOrCreateUngrouped(teaRootVo, groupVoMap);
|
||||||
|
ungrouped.getChildren().add(newTeacherNode(teacher, ungrouped.getId()));
|
||||||
|
} else {
|
||||||
|
for (Integer groupId : groupIds) {
|
||||||
|
TeaTreeVO groupVo = groupVoMap.get(groupId);
|
||||||
|
if (groupVo == null) {
|
||||||
|
groupVo = getOrCreateUngrouped(teaRootVo, groupVoMap);
|
||||||
|
}
|
||||||
|
// 同一节点下按 teaId 去重(防脏数据中同一组出现多条关联)
|
||||||
|
boolean exists = groupVo.getChildren().stream()
|
||||||
|
.anyMatch(c -> Integer.valueOf(2).equals(c.getType()) && c.getId().equals(teacher.getTeaId()));
|
||||||
|
if (!exists) {
|
||||||
|
groupVo.getChildren().add(newTeacherNode(teacher, groupVo.getId()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 每个节点 children 按 no 升序(nullsLast、稳定排序):教师 no=0 排在子组之前,
|
||||||
|
// 同 no 的教师保持 getSchTeacherList 的 sort 顺序
|
||||||
|
sortChildrenByNo(rootVo);
|
||||||
|
|
||||||
|
return Collections.singletonList(rootVo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 组节点 VO(type=1,isParent=true,children 初始化为空列表) */
|
||||||
|
private TeaTreeVO newGroupNode(Integer id, String name, Integer pid, Integer no) {
|
||||||
|
TeaTreeVO vo = new TeaTreeVO();
|
||||||
|
vo.setId(id);
|
||||||
|
vo.setName(name);
|
||||||
|
vo.setPid(pid);
|
||||||
|
vo.setNo(no);
|
||||||
|
vo.setType(1);
|
||||||
|
vo.setIsParent(true);
|
||||||
|
vo.setChildren(new ArrayList<>());
|
||||||
|
return vo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 教师叶子 VO(type=2,isParent=false,no 固定 0,children=null → JSON 省略) */
|
||||||
|
private TeaTreeVO newTeacherNode(SchTeacher teacher, Integer pid) {
|
||||||
|
TeaTreeVO vo = new TeaTreeVO();
|
||||||
|
vo.setId(teacher.getTeaId());
|
||||||
|
vo.setName(teacher.getName());
|
||||||
|
vo.setPid(pid);
|
||||||
|
vo.setNo(0);
|
||||||
|
vo.setType(2);
|
||||||
|
vo.setIsParent(false);
|
||||||
|
return vo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 递归把 BoaGroup 骨架转成 TeaTreeVO(type=1),pid 记录父节点 id,并收集 groupId -> 节点 */
|
||||||
|
private TeaTreeVO convertGroupTree(BoaGroup node, Integer pid, Map<Integer, TeaTreeVO> groupVoMap) {
|
||||||
|
TeaTreeVO vo = newGroupNode(node.getId(), node.getName(), pid, node.getSort());
|
||||||
|
groupVoMap.put(node.getId(), vo);
|
||||||
|
if (node.getChildren() != null) {
|
||||||
|
for (BoaGroup child : node.getChildren()) {
|
||||||
|
vo.getChildren().add(convertGroupTree(child, node.getId(), groupVoMap));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return vo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 获取或惰性创建"未分组"节点(挂在教师组根下) */
|
||||||
|
private TeaTreeVO getOrCreateUngrouped(TeaTreeVO teaRootVo, Map<Integer, TeaTreeVO> groupVoMap) {
|
||||||
|
TeaTreeVO ungrouped = groupVoMap.get(UNGROUPED_ID);
|
||||||
|
if (ungrouped == null) {
|
||||||
|
ungrouped = newGroupNode(UNGROUPED_ID, "未分组", teaRootVo.getId(), null);
|
||||||
|
teaRootVo.getChildren().add(ungrouped);
|
||||||
|
groupVoMap.put(UNGROUPED_ID, ungrouped);
|
||||||
|
}
|
||||||
|
return ungrouped;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 递归按 no 升序排序每个节点的 children(nullsLast、稳定排序) */
|
||||||
|
private void sortChildrenByNo(TeaTreeVO node) {
|
||||||
|
if (node == null || node.getChildren() == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
node.getChildren().sort(Comparator.comparing(TeaTreeVO::getNo, Comparator.nullsLast(Integer::compareTo)));
|
||||||
|
for (TeaTreeVO child : node.getChildren()) {
|
||||||
|
sortChildrenByNo(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 递归确保所有节点的 children 不为 null,若为 null 则设置为空列表 []
|
* 递归确保所有节点的 children 不为 null,若为 null 则设置为空列表 []
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user