You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

301 lines
12 KiB

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<WeekDuty.DutyTreeNode> 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<WeekDuty.DutyTreeNode> nodes = duty.getNodes();
List<WeekDuty.DutyTreeNode> 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<WeekDuty.DutyTreeNode> 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<School.Semester> 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<WeekDuty.DutyTreeNode> nodes = duty.getNodes();
List<WeekDuty.DutySpot> 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<WeekDuty.DutyTreeNode> nodes, List<WeekDuty.DutyTreeNode> nodesToDelete) {
List<WeekDuty.DutyTreeNode> 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<WeekDuty.DutyTreeNode> nodes = weekDuty.getNodes();
List<WeekDuty.DutyTreeNode> 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<WeekDuty.DutyTreeNode> nodes) {
List<WeekDuty.DutyTreeNode> 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<WeekDuty.DutyTreeNode> getChildren(WeekDuty.DutyTreeNode parent, List<WeekDuty.DutyTreeNode> nodes) {
List<WeekDuty.DutyTreeNode> children = new ArrayList<>();
for (WeekDuty.DutyTreeNode node : nodes) {
if (StringUtils.isNotBlank(node.getPid()) && node.getPid().equals(parent.getId())) {
children.add(node);
}
}
return children;
}
}