feat: 新增值周巡检数个接口

11111
winter 12 months ago
parent 65c8fd598f
commit eec45f6921

@ -1,6 +1,5 @@
package cn.teammodel.ai.listener; package cn.teammodel.ai.listener;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil; import cn.hutool.json.JSONUtil;
import cn.teammodel.ai.SseHelper; import cn.teammodel.ai.SseHelper;
import cn.teammodel.ai.domain.SparkChatResponse; import cn.teammodel.ai.domain.SparkChatResponse;
@ -65,7 +64,7 @@ public class SparkGptStreamListener extends WebSocketListener {
String msgSegment = sparkChatResponse.getPayload().getChoices().getText().get(0).getContent(); String msgSegment = sparkChatResponse.getPayload().getChoices().getText().get(0).getContent();
// 处理消息格式(空格和换行符) // 处理消息格式(空格和换行符)
// msgSegment = StrUtil.replace(msgSegment, " ", " ").replaceAll("\n", "&#92n"); // msgSegment = StrUtil.replace(msgSegment, " ", " ").replaceAll("\n", "&#92n");
msgSegment = StrUtil.replace(msgSegment, " ", "&#32;").replaceAll("\n", "<br/>"); // msgSegment = StrUtil.replace(msgSegment, " ", "&#32;").replaceAll("\n", "<br/>");
answer += msgSegment; answer += msgSegment;
SseHelper.send(sseEmitter, msgSegment); SseHelper.send(sseEmitter, msgSegment);

@ -24,6 +24,7 @@ public interface PK {
String STUDENT = "Base-%s"; String STUDENT = "Base-%s";
String CLASS = "Class-%s"; String CLASS = "Class-%s";
String CHAT_SESSION = "ChatSession"; String CHAT_SESSION = "ChatSession";
String WEEK_DUTY = "Duty";
/** /**
* *

@ -33,6 +33,7 @@ public final class ServiceException extends RuntimeException
public ServiceException(String message) public ServiceException(String message)
{ {
this.code = ErrorCode.SYSTEM_ERROR.getCode();
this.message = message; this.message = message;
} }

@ -13,7 +13,9 @@ import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.validation.Valid; import javax.validation.Valid;
import java.io.IOException;
import java.util.List; import java.util.List;
import java.util.concurrent.CompletableFuture;
@RestController @RestController
@RequestMapping("/ai") @RequestMapping("/ai")
@ -29,6 +31,40 @@ public class AiController {
return chatMessageService.chatCompletion(chatCompletionReqDto); return chatMessageService.chatCompletion(chatCompletionReqDto);
} }
@PostMapping("chat/test/completion")
@ApiOperation("与 spark 的流式对话")
public SseEmitter testCompletion(@RequestBody @Valid ChatCompletionReqDto chatCompletionReqDto) throws IOException, InterruptedException {
SseEmitter sseEmitter = new SseEmitter();
CompletableFuture.runAsync(() -> {
try {
sseEmitter.send("曾经以为我们");
Thread.sleep(1000);
sseEmitter.send("开始了就会走到最后,可是当分手之后才明白我想的");
Thread.sleep(1000);
sseEmitter.send("你不一定能做到,当我开始去遗忘我们");
Thread.sleep(1500);
sseEmitter.send("的经历时,却不知道遗忘已变成另一种开始,");
Thread.sleep(800);
sseEmitter.send("回忆是淡了,可是痛却还在,还是最真实。放手的时候微笑着说无所谓");
Thread.sleep(800);
sseEmitter.send(",离开了你我还可以过的很好");
Thread.sleep(1000);
sseEmitter.send(",而你却不知道微笑只是用来掩盖疼痛的伤疤。");
Thread.sleep(1200);
sseEmitter.send("离开你之后的自己陷入一种无助的状态,空洞的");
Thread.sleep(1300);
sseEmitter.send("双眼回忆不起曾经的你,那时候以为与世隔绝或许才是维护自己的最好方式。");
Thread.sleep(1100);
sseEmitter.send("[DONE]");
sseEmitter.complete();
} catch (IOException | InterruptedException e) {
throw new RuntimeException(e);
}
});
return sseEmitter;
}
@GetMapping("session/my") @GetMapping("session/my")
@ApiOperation("查询我的聊天会话") @ApiOperation("查询我的聊天会话")
public R<List<ChatSession>> listMySession() { public R<List<ChatSession>> listMySession() {

@ -43,6 +43,7 @@ public class AppraiseController {
@PostMapping("updateNode") @PostMapping("updateNode")
@ApiOperation(value = "更新评价树的节点", notes = "传递更新后的节点,而不是局部更新的值") @ApiOperation(value = "更新评价树的节点", notes = "传递更新后的节点,而不是局部更新的值")
public R<Appraise> updateTree(@RequestBody @Valid UpdateNodeDto updateNodeDto) { public R<Appraise> updateTree(@RequestBody @Valid UpdateNodeDto updateNodeDto) {
// fixme: 更新一二级节点应该同时更新三级的 path
Appraise appraise = evaluationService.updateNode(updateNodeDto); Appraise appraise = evaluationService.updateNode(updateNodeDto);
return R.success(appraise); return R.success(appraise);
} }

@ -0,0 +1,65 @@
package cn.teammodel.controller.frontend;
import cn.teammodel.common.R;
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.weekDuty.WeekDuty;
import cn.teammodel.service.DutyService;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.Valid;
/**
* @author winter
* @create 2024-01-03 10:06
*/
@RestController
@RequestMapping("/duty")
public class DutyController {
@Resource
private DutyService dutyService;
@GetMapping("/getTree")
@ApiOperation("获取值周评价标准树(不存在则拷贝模板)")
public R<WeekDuty> getTree() {
WeekDuty weekDuty = dutyService.getTree();
return R.success(weekDuty);
}
@PostMapping("/insertNode")
@ApiOperation("插入值周评价标准树节点")
public R<WeekDuty> insertNode(@RequestBody @Valid InsertDutyNodeDto insertDutyNodeDto) {
WeekDuty weekDuty = dutyService.insertNode(insertDutyNodeDto);
return R.success(weekDuty);
}
@PostMapping("/deleteNode")
@ApiOperation("删除值周评价标准树节点")
public R<WeekDuty> deleteNode(@RequestBody @Valid DeleteDutyNodeDto deleteDutyNodeDto) {
WeekDuty weekDuty = dutyService.deleteNode(deleteDutyNodeDto);
return R.success(weekDuty);
}
@PostMapping("/updateNode")
@ApiOperation("更新值周评价标准树节点")
public R<WeekDuty> updateNode(@RequestBody @Valid UpdateDutyNodeDto updateDutyNodeDto) {
WeekDuty weekDuty = dutyService.updateNode(updateDutyNodeDto);
return R.success(weekDuty);
}
@PostMapping("/vote")
@ApiOperation("值周评价投票")
public R<String> vote(@RequestBody @Valid DutyVoteDto dutyVoteDto) {
dutyService.vote(dutyVoteDto);
return R.success("评价成功");
}
}

@ -24,5 +24,5 @@ public class InsertNodeDto {
String logo; String logo;
Integer order = 0; Integer order = 0;
Integer score = 0; Integer score = 0;
boolean isPraise; Boolean isPraise = true;
} }

@ -0,0 +1,17 @@
package cn.teammodel.model.dto.weekDuty;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotNull;
/**
* @author winter
* @create 2024-01-03 10:56
*/
@Data
public class DeleteDutyNodeDto {
@ApiModelProperty("要删除的节点 id")
@NotNull
private String nodeId;
}

@ -0,0 +1,25 @@
package cn.teammodel.model.dto.weekDuty;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotNull;
/**
* @author winter
* @create 2024-01-03 15:05
*/
@Data
public class DutyVoteDto {
@NotNull
@ApiModelProperty(value = "班级id", required = true)
private String classId;
@NotNull
@ApiModelProperty(value = "评价地点 id", required = true)
private String spotId;
@NotNull
@ApiModelProperty(value = "评价节点id", required = true)
private String dutyNodeId;
private String note;
private String[] attachments;
}

@ -0,0 +1,23 @@
package cn.teammodel.model.dto.weekDuty;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
/**
* @author winter
* @create 2024-01-03 10:45
*/
@Data
public class InsertDutyNodeDto {
@ApiModelProperty(value = "父亲节点,不传则为根节点")
String pid;
@ApiModelProperty(value = "节点名称", required = true)
@NotBlank(message = "name 不能为空")
String name;
Integer order = 0;
Integer score = 0;
// Boolean positive = true;
}

@ -0,0 +1,23 @@
package cn.teammodel.model.dto.weekDuty;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotNull;
/**
* @author winter
* @create 2024-01-03 10:59
*/
@Data
@ApiModel("覆盖原节点")
public class UpdateDutyNodeDto {
@ApiModelProperty(value = "待修改的节点 id")
@NotNull
private String id;
private String name;
private Integer order = 0;
private Integer score = 0;
// boolean positive;
}

@ -6,6 +6,7 @@ import org.springframework.security.core.userdetails.UserDetails;
import java.util.Collection; import java.util.Collection;
/** /**
* @author winter * @author winter
* @create 2023-11-09 15:28 * @create 2023-11-09 15:28

@ -6,21 +6,53 @@ import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import java.util.List;
/** /**
* , * ()
* @author winter * @author winter
* @create 2023-12-29 15:53 * @create 2024-01-02 17:05
*/ */
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
@Container(containerName = "School") @Container(containerName = "School")
@Data @Data
@JsonInclude(JsonInclude.Include.NON_NULL) @JsonInclude(JsonInclude.Include.NON_NULL)
public class WeekDuty extends BaseItem { public class WeekDuty extends BaseItem {
private String classId; private String schoolId;
private String className; private List<DutyTreeNode> nodes;
/** /**
* *
*/ */
private String note; private List<DutySpot> spots;
private Long createTime;
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public static class DutyTreeNode {
private String id;
private String pid;
private String name;
private Integer score;
private Integer order;
/**
*
*/
private boolean positive;
/**
*
*/
private String[] path;
private List<DutyTreeNode> children;
private String creator;
private String creatorId;
private Long createTime;
}
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public static class DutySpot {
private String id;
private String name;
}
} }

@ -0,0 +1,48 @@
package cn.teammodel.model.entity.weekDuty;
import cn.teammodel.model.entity.BaseItem;
import com.azure.spring.data.cosmos.core.mapping.Container;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.List;
/**
* ,
* @author winter
* @create 2023-12-29 15:53
*/
@EqualsAndHashCode(callSuper = true)
@Container(containerName = "School")
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class WeekDutyRecord extends BaseItem {
private String classId;
private String className;
private String academicYearId;
/**
*
*/
private Integer score;
private List<WeekDutyItem> nodes;
private Long createTime;
@Data
public static class WeekDutyItem {
private String id;
private WeekDuty.DutyTreeNode dutyTreeNode;
private String spotId;
private String spotName;
/**
*
*/
private boolean spread;
private List<String> attachments;
/**
*
*/
private String note;
private Long createTime;
}
}

@ -0,0 +1,13 @@
package cn.teammodel.repository;
import cn.teammodel.model.entity.weekDuty.WeekDutyRecord;
import com.azure.spring.data.cosmos.repository.CosmosRepository;
import org.springframework.stereotype.Repository;
/**
* @author winter
* @create 2024-01-04 17:23
*/
@Repository
public interface DutyRecordRepository extends CosmosRepository<WeekDutyRecord, String> {
}

@ -0,0 +1,21 @@
package cn.teammodel.repository;
import cn.teammodel.model.entity.weekDuty.WeekDuty;
import com.azure.spring.data.cosmos.repository.CosmosRepository;
import com.azure.spring.data.cosmos.repository.Query;
import org.springframework.stereotype.Repository;
import java.util.List;
/**
* @author winter
* @create 2024-01-03 15:18
*/
@Repository
public interface DutyRepository extends CosmosRepository<WeekDuty, String> {
WeekDuty findBySchoolIdAndCode(String schoolId, String code);
@Query("select value n from c join n in c.nodes where c.schoolId = @schoolId and c.code = 'Duty' and n.id = @nodeId")
List<WeekDuty.DutyTreeNode> findDutyNodeById(String nodeId, String schoolId);
}

@ -0,0 +1,24 @@
package cn.teammodel.service;
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.weekDuty.WeekDuty;
/**
* @author winter
* @create 2024-01-03 10:07
*/
public interface DutyService {
WeekDuty insertNode(InsertDutyNodeDto insertDutyNodeDto);
WeekDuty getTree();
WeekDuty deleteNode(DeleteDutyNodeDto deleteDutyNodeDto);
WeekDuty updateNode(UpdateDutyNodeDto updateDutyNodeDto);
void vote(DutyVoteDto dutyVoteDto);
}

@ -0,0 +1,300 @@
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;
}
}

@ -84,7 +84,7 @@ public class EvaluationServiceImpl implements EvaluationService {
if (appraise == null) { if (appraise == null) {
appraise = RepositoryUtil.findOne(appraiseRepository.findTemplateTree(), "获取模板评价树失败"); appraise = RepositoryUtil.findOne(appraiseRepository.findTemplateTree(), "获取模板评价树失败");
if (appraise == null) { if (appraise == null) {
throw new ServiceException(); throw new ServiceException("模板评价树不存在");
} }
// refresh // refresh
refreshAppraiseTree(appraise); refreshAppraiseTree(appraise);
@ -173,6 +173,7 @@ public class EvaluationServiceImpl implements EvaluationService {
AppraiseTreeNode newNode = new AppraiseTreeNode(); AppraiseTreeNode newNode = new AppraiseTreeNode();
BeanUtils.copyProperties(insertNodeDto, newNode); BeanUtils.copyProperties(insertNodeDto, newNode);
// todo: build path
String newNodePid = newNode.getPid(); String newNodePid = newNode.getPid();
// 根节点直接添加 // 根节点直接添加
if (StringUtils.isNotEmpty(newNodePid)) { if (StringUtils.isNotEmpty(newNodePid)) {
@ -201,13 +202,12 @@ public class EvaluationServiceImpl implements EvaluationService {
.filter(item -> updateNodeId.equals(item.getId())) .filter(item -> updateNodeId.equals(item.getId()))
.findFirst() .findFirst()
.orElseThrow(() -> new ServiceException(ErrorCode.PARAMS_ERROR.getCode(), "更新节点不存在")); .orElseThrow(() -> new ServiceException(ErrorCode.PARAMS_ERROR.getCode(), "更新节点不存在"));
// 更新字段,考虑直接 copy properties // todo: 如果是一级,二级需同步更新三级节点的 path
updateNode.setName(updateNodeDto.getName()); updateNode.setName(updateNodeDto.getName());
updateNode.setPath(updateNodeDto.getPath()); updateNode.setPath(updateNodeDto.getPath());
updateNode.setLogo(updateNodeDto.getLogo()); updateNode.setLogo(updateNodeDto.getLogo());
updateNode.setOrder(updateNodeDto.getOrder()); updateNode.setOrder(updateNodeDto.getOrder());
updateNode.setPraise(updateNodeDto.isPraise()); updateNode.setPraise(updateNodeDto.isPraise());
// todo: 为新节点赋值必须参数 (id, creator), 可不可以添加默认值 order ?
return buildTree(appraiseRepository.save(appraise)); return buildTree(appraiseRepository.save(appraise));
} }
@ -219,13 +219,14 @@ public class EvaluationServiceImpl implements EvaluationService {
List<AppraiseTreeNode> nodes = appraise.getNodes(); List<AppraiseTreeNode> nodes = appraise.getNodes();
List<AppraiseTreeNode> nodesToDelete = new ArrayList<>(); List<AppraiseTreeNode> nodesToDelete = new ArrayList<>();
// 迭代器安全删除 // 收集需要删除的节点
for (AppraiseTreeNode node : nodes) { for (AppraiseTreeNode node : nodes) {
if (node.getId().equals(deleteNodeDto.getId())) { if (node.getId().equals(deleteNodeDto.getId())) {
// 删除当前节点 // 删除当前节点
nodesToDelete.add(node); nodesToDelete.add(node);
// 递归删除其孩子节点 // 递归删除其孩子节点
this.collectNodesToDelete(node.getId(), nodes, nodesToDelete); this.collectNodesToDelete(node.getId(), nodes, nodesToDelete);
break;
} }
} }
if (ObjectUtils.isEmpty(nodesToDelete)) { if (ObjectUtils.isEmpty(nodesToDelete)) {

@ -0,0 +1,27 @@
package cn.teammodel;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import java.io.File;
import java.io.IOException;
/**
* @author winter
* @create 2024-01-03 16:21
*/
@SpringBootTest
public class Scripts {
@Test
public void genDocFromJson() throws IOException {
String path = "C://Users/Administrator/Desktop/data.json";
ObjectMapper objectMapper = new ObjectMapper();
JsonNode root = objectMapper.readTree(new File(path));
System.out.println(root.get("content"));
}
}
Loading…
Cancel
Save