package cn.teammodel.service.impl; import cn.hutool.core.lang.UUID; import cn.teammodel.common.ErrorCode; import cn.teammodel.common.PK; import cn.teammodel.config.exception.ServiceException; import cn.teammodel.model.dto.weekDuty.DeleteDutyNodeDto; import cn.teammodel.model.dto.weekDuty.DutyVoteDto; import cn.teammodel.model.dto.weekDuty.InsertDutyNodeDto; import cn.teammodel.model.dto.weekDuty.UpdateDutyNodeDto; import cn.teammodel.model.entity.User; import cn.teammodel.model.entity.school.ClassInfo; import cn.teammodel.model.entity.school.School; import cn.teammodel.model.entity.weekDuty.WeekDuty; import cn.teammodel.repository.ClassRepository; import cn.teammodel.repository.DutyRecordRepository; import cn.teammodel.repository.DutyRepository; import cn.teammodel.repository.SchoolRepository; import cn.teammodel.security.utils.SecurityUtil; import cn.teammodel.service.DutyService; import cn.teammodel.utils.SchoolDateUtil; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.time.Instant; import java.time.LocalDate; import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; /** * @author winter * @create 2024-01-03 10:08 */ @Service public class DutyServiceImpl implements DutyService { @Resource private ClassRepository classRepository; @Resource private SchoolRepository schoolRepository; @Resource private DutyRecordRepository dutyRecordRepository; @Resource private DutyRepository dutyRepository; @Override public WeekDuty getTree() { User user = SecurityUtil.getLoginUser(); String schoolId = user.getSchoolId(); WeekDuty duty = dutyRepository.findBySchoolIdAndCode(schoolId , PK.WEEK_DUTY); if (duty == null) { // copy from template duty = dutyRepository.findBySchoolIdAndCode("template", PK.WEEK_DUTY); if (duty == null) { throw new RuntimeException("值周模板不存在"); } duty.setId(null); duty.setSchoolId(schoolId); // 刷新值周树和 spots 的 id refreshDuty(duty); dutyRepository.save(duty); } return this.buildTree(duty); } @Override public WeekDuty insertNode(InsertDutyNodeDto insertDutyNodeDto) { String pid = insertDutyNodeDto.getPid(); String name = insertDutyNodeDto.getName(); Integer order = insertDutyNodeDto.getOrder(); Integer score = insertDutyNodeDto.getScore(); User user = SecurityUtil.getLoginUser(); String schoolId = user.getSchoolId(); WeekDuty duty = dutyRepository.findBySchoolIdAndCode(schoolId, PK.WEEK_DUTY); if (duty == null) { throw new ServiceException("值周树不存在"); } WeekDuty.DutyTreeNode newNode = new WeekDuty.DutyTreeNode(); List nodes = duty.getNodes(); // 非根节点(需考虑填充 path) if (StringUtils.isNotEmpty(pid)) { WeekDuty.DutyTreeNode parent = nodes.stream().filter(x -> pid.equals(x.getId())) .findFirst() .orElseThrow(() -> new ServiceException(ErrorCode.PARAMS_ERROR.getCode(), "pid 无效")); String level2 = parent.getName(); // 新节点是三级节点(二级节点不用特殊处理 String ppid = parent.getId(); if (ppid != null) { String[] path = new String[3]; WeekDuty.DutyTreeNode root = nodes.stream().filter(x -> ppid.equals(x.getId())) .findFirst() .orElseThrow(() -> new ServiceException(ErrorCode.SYSTEM_ERROR.getCode(), "值周树结构错误")); // 层数不为三级,抛出异常 if (root.getPid() != null) { throw new ServiceException(ErrorCode.SYSTEM_ERROR.getCode(), "值周树结构错误"); } String level1 = root.getName(); path[0] = level1; path[1] = level2; path[2] = name; newNode.setPath(path); } } newNode.setId(UUID.randomUUID().toString()); newNode.setPid(pid); newNode.setName(name); newNode.setScore(score); newNode.setOrder(order); newNode.setPositive(score >= 0); newNode.setCreator(user.getName()); newNode.setCreatorId(user.getId()); newNode.setCreateTime(Instant.now().toEpochMilli()); nodes.add(newNode); return buildTree(dutyRepository.save(duty)); } @Override public WeekDuty deleteNode(DeleteDutyNodeDto deleteDutyNodeDto) { String schoolId = SecurityUtil.getLoginUser().getSchoolId(); String nodeToDeleteId = deleteDutyNodeDto.getNodeId(); WeekDuty duty = dutyRepository.findBySchoolIdAndCode(schoolId, PK.WEEK_DUTY); if (duty == null) { throw new ServiceException("值周树不存在"); } List nodes = duty.getNodes(); List nodesToDelete = new ArrayList<>(); WeekDuty.DutyTreeNode node = nodes.stream() .filter(x -> nodeToDeleteId.equals(x.getId())) .findFirst() .orElseThrow(() -> new ServiceException(ErrorCode.PARAMS_ERROR.getCode(), "删除的节点不存在")); nodesToDelete.add(node); this.collectNodesToDelete(nodeToDeleteId, nodes, nodesToDelete); // 批量删除节点 nodes.removeAll(nodesToDelete); return buildTree(dutyRepository.save(duty)); } @Override public WeekDuty updateNode(UpdateDutyNodeDto updateDutyNodeDto) { String nodeId = updateDutyNodeDto.getId(); String newNodeName = updateDutyNodeDto.getName(); Integer newScore = updateDutyNodeDto.getScore(); String schoolId = SecurityUtil.getLoginUser().getSchoolId(); WeekDuty duty = dutyRepository.findBySchoolIdAndCode(schoolId, PK.WEEK_DUTY); if (duty == null) { throw new ServiceException("值周树不存在"); } List nodes = duty.getNodes(); WeekDuty.DutyTreeNode nodeToUpdate = nodes.stream().filter(x -> nodeId.equals(x.getId())) .findFirst() .orElseThrow(() -> new ServiceException("待更新的节点不存在")); String originNodeName = nodeToUpdate.getName(); // 更新当前节点 nodeToUpdate.setName(newNodeName); nodeToUpdate.setScore(newScore); nodeToUpdate.setOrder(updateDutyNodeDto.getOrder()); nodeToUpdate.setPositive(newScore >= 0); // 如果是一级,二级需同步更新三级节点的 path if (nodeToUpdate.getPath() != null) { int index = nodeToUpdate.getPid() == null ? 0 : 1; nodes.forEach(x -> { // 修改三级节点的 path if (x.getPath() == null) { return; } String[] path = x.getPath(); if (originNodeName.equals(path[index])) { path[index] = newNodeName; x.setPath(path); } }); } return buildTree(dutyRepository.save(duty)); } @Override public void vote(DutyVoteDto dutyVoteDto) { String classId = dutyVoteDto.getClassId(); String spotId = dutyVoteDto.getSpotId(); String dutyNodeId = dutyVoteDto.getDutyNodeId(); String note = dutyVoteDto.getNote(); String[] attachments = dutyVoteDto.getAttachments(); String schoolId = SecurityUtil.getLoginUser().getSchoolId(); ClassInfo classInfo = classRepository.findClassByIdAndCode(classId, String.format(PK.CLASS, schoolId)); if (classInfo == null) { throw new ServiceException(ErrorCode.PARAMS_ERROR.getCode(), "目标班级不存在"); } String className = classInfo.getName(); String periodId = classInfo.getPeriodId(); List semesters = schoolRepository.findSemestersById(schoolId, periodId); if (ObjectUtils.isEmpty(semesters)) { throw new ServiceException(ErrorCode.SYSTEM_ERROR.getCode(), "内部结构异常"); } String academicYearId = SchoolDateUtil.calculateAcademicYearId(semesters, LocalDate.now()); WeekDuty duty = dutyRepository.findBySchoolIdAndCode(schoolId, PK.WEEK_DUTY); WeekDuty.DutyTreeNode dutyNode = duty.getNodes().stream() .filter(x -> dutyNodeId.equals(x.getId())) .findFirst() .orElseThrow(() -> new ServiceException(ErrorCode.PARAMS_ERROR.getCode(), "评价节点不存在")); } /** * 刷新值周树和 spots 的 id */ private void refreshDuty(WeekDuty duty) { List nodes = duty.getNodes(); List spots = duty.getSpots(); // refresh tree nodes nodes.forEach(x -> { String oldId = x.getId(); String newId = UUID.randomUUID().toString(); x.setId(newId); // 将孩子节点的 pid 改为新的 id nodes.stream().filter(y -> oldId.equals(y.getPid())).forEach(y -> y.setPid(newId)); }); // refresh spot id spots.forEach(x -> x.setId(UUID.randomUUID().toString())); } /** * 递归收集要删除的节点 */ private void collectNodesToDelete(String nodeToDeleteId, List nodes, List nodesToDelete) { List children = nodes.stream() .filter(x -> nodeToDeleteId.equals(x.getPid())) .collect(Collectors.toList()); if (children.size() == 0) return; nodesToDelete.addAll(children); for (WeekDuty.DutyTreeNode child : children) { this.collectNodesToDelete(child.getId(), nodes, nodesToDelete); } } public WeekDuty buildTree(WeekDuty weekDuty) { if (weekDuty == null) { return null; } List nodes = weekDuty.getNodes(); List parents = new ArrayList<>(); // pid 为 null 或者 "" 则为 parents for (WeekDuty.DutyTreeNode node : nodes) { if (StringUtils.isBlank(node.getPid())) { parents.add(node); } } // 迭代构建孩子节点 for (WeekDuty.DutyTreeNode parent : parents) { buildChildren(parent, nodes); } // 根据 order 排序 parents = parents.stream().sorted(Comparator.comparing(WeekDuty.DutyTreeNode::getOrder)).collect(Collectors.toList()); weekDuty.setNodes(parents); return weekDuty; } private void buildChildren(WeekDuty.DutyTreeNode parent, List nodes) { List children = getChildren(parent, nodes); if (children.size() == 0) return; parent.setChildren(children); for (WeekDuty.DutyTreeNode child : children) { // 如果子节点还有孩子的话,就继续递归构建 if (getChildren(child, nodes).size() > 0) { buildChildren(child, nodes); } } } private List getChildren(WeekDuty.DutyTreeNode parent, List nodes) { List children = new ArrayList<>(); for (WeekDuty.DutyTreeNode node : nodes) { if (StringUtils.isNotBlank(node.getPid()) && node.getPid().equals(parent.getId())) { children.add(node); } } return children; } }