feat: complete review workflow support
This commit is contained in:
@@ -52,6 +52,11 @@
|
|||||||
<artifactId>mockito-junit-jupiter</artifactId>
|
<artifactId>mockito-junit-jupiter</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.h2database</groupId>
|
||||||
|
<artifactId>h2</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.flywaydb</groupId>
|
<groupId>org.flywaydb</groupId>
|
||||||
<artifactId>flyway-core</artifactId>
|
<artifactId>flyway-core</artifactId>
|
||||||
|
|||||||
@@ -2,11 +2,17 @@ package com.guo.learningprogresstracker.controller;
|
|||||||
|
|
||||||
import com.guo.learningprogresstracker.dto.ReviewFeedItem;
|
import com.guo.learningprogresstracker.dto.ReviewFeedItem;
|
||||||
import com.guo.learningprogresstracker.dto.ReviewTaskStats;
|
import com.guo.learningprogresstracker.dto.ReviewTaskStats;
|
||||||
|
import com.guo.learningprogresstracker.dto.request.CreateReviewApplicationRequest;
|
||||||
|
import com.guo.learningprogresstracker.dto.request.UpdateReviewApplicationRequest;
|
||||||
|
import com.guo.learningprogresstracker.dto.request.UpsertReviewMindMapRequest;
|
||||||
import com.guo.learningprogresstracker.entity.CommonResult;
|
import com.guo.learningprogresstracker.entity.CommonResult;
|
||||||
|
import com.guo.learningprogresstracker.entity.ReviewApplicationEntity;
|
||||||
|
import com.guo.learningprogresstracker.entity.ReviewMindMapEntity;
|
||||||
import com.guo.learningprogresstracker.entity.StudyReportFragmentsEntity;
|
import com.guo.learningprogresstracker.entity.StudyReportFragmentsEntity;
|
||||||
import com.guo.learningprogresstracker.entity.StudyReportsEntity;
|
import com.guo.learningprogresstracker.entity.StudyReportsEntity;
|
||||||
import com.guo.learningprogresstracker.exception.NotFindEntitiesException;
|
import com.guo.learningprogresstracker.exception.NotFindEntitiesException;
|
||||||
import com.guo.learningprogresstracker.service.impl.ReviewServiceImpl;
|
import com.guo.learningprogresstracker.service.ReviewService;
|
||||||
|
import jakarta.validation.Valid;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
@@ -22,15 +28,16 @@ import java.util.List;
|
|||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class ReviewController {
|
public class ReviewController {
|
||||||
|
|
||||||
private final ReviewServiceImpl reviewService;
|
private final ReviewService reviewService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取复习 feed,合并报告和残片按时间倒序
|
* 获取复习 feed,合并报告和残片按时间倒序
|
||||||
*/
|
*/
|
||||||
@GetMapping("/feed")
|
@GetMapping("/feed")
|
||||||
public CommonResult<List<ReviewFeedItem>> getReviewFeed(
|
public CommonResult<List<ReviewFeedItem>> getReviewFeed(
|
||||||
@RequestParam(defaultValue = "30") int limit) {
|
@RequestParam(defaultValue = "30") int limit,
|
||||||
return CommonResult.success(reviewService.getReviewFeed(limit));
|
@RequestParam(defaultValue = "recent") String mode) {
|
||||||
|
return CommonResult.success(reviewService.getReviewFeed(limit, mode));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -72,4 +79,58 @@ public class ReviewController {
|
|||||||
public CommonResult<StudyReportFragmentsEntity> getFragmentDetail(@PathVariable int id) throws NotFindEntitiesException {
|
public CommonResult<StudyReportFragmentsEntity> getFragmentDetail(@PathVariable int id) throws NotFindEntitiesException {
|
||||||
return CommonResult.success(reviewService.getFragmentDetail(id));
|
return CommonResult.success(reviewService.getFragmentDetail(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取指定任务的应用场景列表
|
||||||
|
*/
|
||||||
|
@GetMapping("/applications/{taskNum}")
|
||||||
|
public CommonResult<List<ReviewApplicationEntity>> getApplications(@PathVariable String taskNum) throws NotFindEntitiesException {
|
||||||
|
return CommonResult.success(reviewService.getApplications(taskNum));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建应用场景
|
||||||
|
*/
|
||||||
|
@PostMapping("/applications")
|
||||||
|
public CommonResult<ReviewApplicationEntity> createApplication(
|
||||||
|
@Valid @RequestBody CreateReviewApplicationRequest request) throws NotFindEntitiesException {
|
||||||
|
return CommonResult.success(reviewService.createApplication(request));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新应用场景
|
||||||
|
*/
|
||||||
|
@PutMapping("/applications/{id}")
|
||||||
|
public CommonResult<ReviewApplicationEntity> updateApplication(
|
||||||
|
@PathVariable Integer id,
|
||||||
|
@Valid @RequestBody UpdateReviewApplicationRequest request) throws NotFindEntitiesException {
|
||||||
|
return CommonResult.success(reviewService.updateApplication(id, request));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除应用场景
|
||||||
|
*/
|
||||||
|
@DeleteMapping("/applications/{id}")
|
||||||
|
public CommonResult<Void> deleteApplication(@PathVariable Integer id) throws NotFindEntitiesException {
|
||||||
|
reviewService.deleteApplication(id);
|
||||||
|
return CommonResult.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取指定任务的思维导图
|
||||||
|
*/
|
||||||
|
@GetMapping("/mind-map/{taskNum}")
|
||||||
|
public CommonResult<ReviewMindMapEntity> getMindMap(@PathVariable String taskNum) throws NotFindEntitiesException {
|
||||||
|
return CommonResult.success(reviewService.getMindMap(taskNum));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建或更新指定任务的思维导图
|
||||||
|
*/
|
||||||
|
@PutMapping("/mind-map/{taskNum}")
|
||||||
|
public CommonResult<ReviewMindMapEntity> upsertMindMap(
|
||||||
|
@PathVariable String taskNum,
|
||||||
|
@Valid @RequestBody UpsertReviewMindMapRequest request) throws NotFindEntitiesException {
|
||||||
|
return CommonResult.success(reviewService.upsertMindMap(taskNum, request));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ public class TaskController {
|
|||||||
@PostMapping
|
@PostMapping
|
||||||
@Operation(summary = "添加新任务")
|
@Operation(summary = "添加新任务")
|
||||||
public CommonResult<String> addTask(@RequestBody @Validated({Ops.CreateG.class}) TaskRequest taskRequest) throws ErrorParameterException {
|
public CommonResult<String> addTask(@RequestBody @Validated({Ops.CreateG.class}) TaskRequest taskRequest) throws ErrorParameterException {
|
||||||
return CommonResult.success(tasksService.addTask(taskRequest));
|
return CommonResult.success("请求成功", tasksService.addTask(taskRequest));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Operation(summary = "任务详情API")
|
@Operation(summary = "任务详情API")
|
||||||
|
|||||||
+20
@@ -0,0 +1,20 @@
|
|||||||
|
package com.guo.learningprogresstracker.dto.request;
|
||||||
|
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class CreateReviewApplicationRequest {
|
||||||
|
|
||||||
|
@NotBlank(message = "任务编号不可为空")
|
||||||
|
private String taskNum;
|
||||||
|
|
||||||
|
@NotBlank(message = "应用项目标题不可为空")
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
private String resourceUrl;
|
||||||
|
|
||||||
|
private String status;
|
||||||
|
}
|
||||||
+17
@@ -0,0 +1,17 @@
|
|||||||
|
package com.guo.learningprogresstracker.dto.request;
|
||||||
|
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class UpdateReviewApplicationRequest {
|
||||||
|
|
||||||
|
@NotBlank(message = "应用项目标题不可为空")
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
private String resourceUrl;
|
||||||
|
|
||||||
|
private String status;
|
||||||
|
}
|
||||||
+16
@@ -0,0 +1,16 @@
|
|||||||
|
package com.guo.learningprogresstracker.dto.request;
|
||||||
|
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class UpsertReviewMindMapRequest {
|
||||||
|
|
||||||
|
@NotBlank(message = "思维导图标题不可为空")
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
@NotBlank(message = "思维导图内容不可为空")
|
||||||
|
private String content;
|
||||||
|
|
||||||
|
private String contentFormat;
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package com.guo.learningprogresstracker.entity;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
@TableName(value = "review_applications")
|
||||||
|
@Data
|
||||||
|
public class ReviewApplicationEntity extends BaseEntity implements Serializable {
|
||||||
|
|
||||||
|
@TableId(value = "id", type = IdType.AUTO)
|
||||||
|
private Integer id;
|
||||||
|
|
||||||
|
@TableField(value = "task_num")
|
||||||
|
private String taskNum;
|
||||||
|
|
||||||
|
@TableField(value = "title")
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
@TableField(value = "description")
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
@TableField(value = "resource_url")
|
||||||
|
private String resourceUrl;
|
||||||
|
|
||||||
|
@TableField(value = "status")
|
||||||
|
private String status;
|
||||||
|
|
||||||
|
@TableField(exist = false)
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package com.guo.learningprogresstracker.entity;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
@TableName(value = "review_mind_maps")
|
||||||
|
@Data
|
||||||
|
public class ReviewMindMapEntity extends BaseEntity implements Serializable {
|
||||||
|
|
||||||
|
@TableId(value = "id", type = IdType.AUTO)
|
||||||
|
private Integer id;
|
||||||
|
|
||||||
|
@TableField(value = "task_num")
|
||||||
|
private String taskNum;
|
||||||
|
|
||||||
|
@TableField(value = "title")
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
@TableField(value = "content")
|
||||||
|
private String content;
|
||||||
|
|
||||||
|
@TableField(value = "content_format")
|
||||||
|
private String contentFormat;
|
||||||
|
|
||||||
|
@TableField(exist = false)
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package com.guo.learningprogresstracker.enums;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
@AllArgsConstructor
|
||||||
|
public enum ReviewApplicationStatusEnum {
|
||||||
|
TODO("TODO", "待应用"),
|
||||||
|
DOING("DOING", "应用中"),
|
||||||
|
DONE("DONE", "已完成");
|
||||||
|
|
||||||
|
private final String code;
|
||||||
|
private final String description;
|
||||||
|
|
||||||
|
public String getCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ReviewApplicationStatusEnum fromCodeOrDefault(String code) {
|
||||||
|
if (code == null || code.trim().isEmpty()) {
|
||||||
|
return TODO;
|
||||||
|
}
|
||||||
|
String normalized = code.trim().toUpperCase(Locale.ROOT);
|
||||||
|
return Arrays.stream(values())
|
||||||
|
.filter(status -> status.code.equals(normalized))
|
||||||
|
.findFirst()
|
||||||
|
.orElse(TODO);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package com.guo.learningprogresstracker.mapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import com.guo.learningprogresstracker.entity.ReviewApplicationEntity;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface ReviewApplicationMapper extends BaseMapper<ReviewApplicationEntity> {
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package com.guo.learningprogresstracker.mapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import com.guo.learningprogresstracker.entity.ReviewMindMapEntity;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface ReviewMindMapMapper extends BaseMapper<ReviewMindMapEntity> {
|
||||||
|
}
|
||||||
@@ -2,6 +2,11 @@ package com.guo.learningprogresstracker.service;
|
|||||||
|
|
||||||
import com.guo.learningprogresstracker.dto.ReviewFeedItem;
|
import com.guo.learningprogresstracker.dto.ReviewFeedItem;
|
||||||
import com.guo.learningprogresstracker.dto.ReviewTaskStats;
|
import com.guo.learningprogresstracker.dto.ReviewTaskStats;
|
||||||
|
import com.guo.learningprogresstracker.dto.request.CreateReviewApplicationRequest;
|
||||||
|
import com.guo.learningprogresstracker.dto.request.UpdateReviewApplicationRequest;
|
||||||
|
import com.guo.learningprogresstracker.dto.request.UpsertReviewMindMapRequest;
|
||||||
|
import com.guo.learningprogresstracker.entity.ReviewApplicationEntity;
|
||||||
|
import com.guo.learningprogresstracker.entity.ReviewMindMapEntity;
|
||||||
import com.guo.learningprogresstracker.entity.StudyReportFragmentsEntity;
|
import com.guo.learningprogresstracker.entity.StudyReportFragmentsEntity;
|
||||||
import com.guo.learningprogresstracker.entity.StudyReportsEntity;
|
import com.guo.learningprogresstracker.entity.StudyReportsEntity;
|
||||||
import com.guo.learningprogresstracker.exception.NotFindEntitiesException;
|
import com.guo.learningprogresstracker.exception.NotFindEntitiesException;
|
||||||
@@ -16,7 +21,7 @@ public interface ReviewService {
|
|||||||
/**
|
/**
|
||||||
* 获取复习 feed 列表,合并报告和残片按时间倒序
|
* 获取复习 feed 列表,合并报告和残片按时间倒序
|
||||||
*/
|
*/
|
||||||
List<ReviewFeedItem> getReviewFeed(int limit);
|
List<ReviewFeedItem> getReviewFeed(int limit, String mode);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取所有任务的复习统计数据
|
* 获取所有任务的复习统计数据
|
||||||
@@ -42,4 +47,34 @@ public interface ReviewService {
|
|||||||
* 获取残片详情
|
* 获取残片详情
|
||||||
*/
|
*/
|
||||||
StudyReportFragmentsEntity getFragmentDetail(int id) throws NotFindEntitiesException;
|
StudyReportFragmentsEntity getFragmentDetail(int id) throws NotFindEntitiesException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取指定任务的应用场景列表
|
||||||
|
*/
|
||||||
|
List<ReviewApplicationEntity> getApplications(String taskNum) throws NotFindEntitiesException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建应用场景
|
||||||
|
*/
|
||||||
|
ReviewApplicationEntity createApplication(CreateReviewApplicationRequest request) throws NotFindEntitiesException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新应用场景
|
||||||
|
*/
|
||||||
|
ReviewApplicationEntity updateApplication(Integer id, UpdateReviewApplicationRequest request) throws NotFindEntitiesException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除应用场景
|
||||||
|
*/
|
||||||
|
void deleteApplication(Integer id) throws NotFindEntitiesException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取指定任务的思维导图
|
||||||
|
*/
|
||||||
|
ReviewMindMapEntity getMindMap(String taskNum) throws NotFindEntitiesException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建或更新指定任务的思维导图
|
||||||
|
*/
|
||||||
|
ReviewMindMapEntity upsertMindMap(String taskNum, UpsertReviewMindMapRequest request) throws NotFindEntitiesException;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,11 +3,19 @@ package com.guo.learningprogresstracker.service.impl;
|
|||||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||||
import com.guo.learningprogresstracker.dto.ReviewFeedItem;
|
import com.guo.learningprogresstracker.dto.ReviewFeedItem;
|
||||||
import com.guo.learningprogresstracker.dto.ReviewTaskStats;
|
import com.guo.learningprogresstracker.dto.ReviewTaskStats;
|
||||||
|
import com.guo.learningprogresstracker.dto.request.CreateReviewApplicationRequest;
|
||||||
|
import com.guo.learningprogresstracker.dto.request.UpdateReviewApplicationRequest;
|
||||||
|
import com.guo.learningprogresstracker.dto.request.UpsertReviewMindMapRequest;
|
||||||
|
import com.guo.learningprogresstracker.entity.ReviewApplicationEntity;
|
||||||
|
import com.guo.learningprogresstracker.entity.ReviewMindMapEntity;
|
||||||
import com.guo.learningprogresstracker.entity.StudyReportFragmentsEntity;
|
import com.guo.learningprogresstracker.entity.StudyReportFragmentsEntity;
|
||||||
import com.guo.learningprogresstracker.entity.StudyReportsEntity;
|
import com.guo.learningprogresstracker.entity.StudyReportsEntity;
|
||||||
import com.guo.learningprogresstracker.entity.StudySessionsEntity;
|
import com.guo.learningprogresstracker.entity.StudySessionsEntity;
|
||||||
import com.guo.learningprogresstracker.entity.TaskEntity;
|
import com.guo.learningprogresstracker.entity.TaskEntity;
|
||||||
|
import com.guo.learningprogresstracker.enums.ReviewApplicationStatusEnum;
|
||||||
import com.guo.learningprogresstracker.exception.NotFindEntitiesException;
|
import com.guo.learningprogresstracker.exception.NotFindEntitiesException;
|
||||||
|
import com.guo.learningprogresstracker.mapper.ReviewApplicationMapper;
|
||||||
|
import com.guo.learningprogresstracker.mapper.ReviewMindMapMapper;
|
||||||
import com.guo.learningprogresstracker.mapper.StudyReportFragmentsMapper;
|
import com.guo.learningprogresstracker.mapper.StudyReportFragmentsMapper;
|
||||||
import com.guo.learningprogresstracker.mapper.StudyReportsMapper;
|
import com.guo.learningprogresstracker.mapper.StudyReportsMapper;
|
||||||
import com.guo.learningprogresstracker.mapper.StudySessionsMapper;
|
import com.guo.learningprogresstracker.mapper.StudySessionsMapper;
|
||||||
@@ -31,24 +39,42 @@ import java.util.stream.Stream;
|
|||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class ReviewServiceImpl implements ReviewService {
|
public class ReviewServiceImpl implements ReviewService {
|
||||||
|
|
||||||
|
private static final int DEFAULT_LIMIT = 30;
|
||||||
|
private static final int MAX_LIMIT = 100;
|
||||||
|
private static final String RANDOM_MODE = "random";
|
||||||
|
private static final String DEFAULT_MIND_MAP_FORMAT = "TEXT";
|
||||||
|
|
||||||
private final StudyReportsMapper studyReportsMapper;
|
private final StudyReportsMapper studyReportsMapper;
|
||||||
private final StudyReportFragmentsMapper studyReportFragmentsMapper;
|
private final StudyReportFragmentsMapper studyReportFragmentsMapper;
|
||||||
private final StudySessionsMapper studySessionsMapper;
|
private final StudySessionsMapper studySessionsMapper;
|
||||||
private final TasksMapper tasksMapper;
|
private final TasksMapper tasksMapper;
|
||||||
|
private final ReviewApplicationMapper reviewApplicationMapper;
|
||||||
|
private final ReviewMindMapMapper reviewMindMapMapper;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<ReviewFeedItem> getReviewFeed(int limit) {
|
public List<ReviewFeedItem> getReviewFeed(int limit, String mode) {
|
||||||
List<StudyReportsEntity> reports = studyReportsMapper.selectList(
|
int safeLimit = normalizeLimit(limit);
|
||||||
Wrappers.<StudyReportsEntity>lambdaQuery()
|
boolean random = RANDOM_MODE.equalsIgnoreCase(mode);
|
||||||
|
|
||||||
|
List<StudyReportsEntity> reports = random
|
||||||
|
? studyReportsMapper.selectList(Wrappers.<StudyReportsEntity>lambdaQuery()
|
||||||
|
.last("ORDER BY RAND() LIMIT " + safeLimit))
|
||||||
|
: studyReportsMapper.selectList(Wrappers.<StudyReportsEntity>lambdaQuery()
|
||||||
.orderByDesc(StudyReportsEntity::getCreatedTime)
|
.orderByDesc(StudyReportsEntity::getCreatedTime)
|
||||||
.last("LIMIT " + limit));
|
.last("LIMIT " + safeLimit));
|
||||||
|
|
||||||
List<StudyReportFragmentsEntity> fragments = studyReportFragmentsMapper.selectList(
|
List<StudyReportFragmentsEntity> fragments = random
|
||||||
Wrappers.<StudyReportFragmentsEntity>lambdaQuery()
|
? studyReportFragmentsMapper.selectList(Wrappers.<StudyReportFragmentsEntity>lambdaQuery()
|
||||||
|
.last("ORDER BY RAND() LIMIT " + safeLimit))
|
||||||
|
: studyReportFragmentsMapper.selectList(Wrappers.<StudyReportFragmentsEntity>lambdaQuery()
|
||||||
.orderByDesc(StudyReportFragmentsEntity::getCreatedTime)
|
.orderByDesc(StudyReportFragmentsEntity::getCreatedTime)
|
||||||
.last("LIMIT " + limit));
|
.last("LIMIT " + safeLimit));
|
||||||
|
|
||||||
return mergeAndConvert(reports, fragments);
|
List<ReviewFeedItem> items = mergeAndConvert(reports, fragments);
|
||||||
|
if (random) {
|
||||||
|
Collections.shuffle(items);
|
||||||
|
}
|
||||||
|
return items.stream().limit(safeLimit).collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -119,6 +145,77 @@ public class ReviewServiceImpl implements ReviewService {
|
|||||||
.orElseThrow(() -> new NotFindEntitiesException("学习残片[" + id + "]不存在"));
|
.orElseThrow(() -> new NotFindEntitiesException("学习残片[" + id + "]不存在"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ReviewApplicationEntity> getApplications(String taskNum) throws NotFindEntitiesException {
|
||||||
|
ensureTaskExists(taskNum);
|
||||||
|
return reviewApplicationMapper.selectList(
|
||||||
|
Wrappers.<ReviewApplicationEntity>lambdaQuery()
|
||||||
|
.eq(ReviewApplicationEntity::getTaskNum, taskNum)
|
||||||
|
.orderByDesc(ReviewApplicationEntity::getLastModifiedTime)
|
||||||
|
.orderByDesc(ReviewApplicationEntity::getCreatedTime));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ReviewApplicationEntity createApplication(CreateReviewApplicationRequest request) throws NotFindEntitiesException {
|
||||||
|
ensureTaskExists(request.getTaskNum());
|
||||||
|
ReviewApplicationEntity entity = new ReviewApplicationEntity();
|
||||||
|
entity.setTaskNum(request.getTaskNum());
|
||||||
|
entity.setTitle(request.getTitle());
|
||||||
|
entity.setDescription(request.getDescription());
|
||||||
|
entity.setResourceUrl(request.getResourceUrl());
|
||||||
|
entity.setStatus(normalizeApplicationStatus(request.getStatus()));
|
||||||
|
reviewApplicationMapper.insert(entity);
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ReviewApplicationEntity updateApplication(Integer id, UpdateReviewApplicationRequest request) throws NotFindEntitiesException {
|
||||||
|
ReviewApplicationEntity existing = Optional.ofNullable(reviewApplicationMapper.selectById(id))
|
||||||
|
.orElseThrow(() -> new NotFindEntitiesException("应用场景[" + id + "]不存在"));
|
||||||
|
existing.setTitle(request.getTitle());
|
||||||
|
existing.setDescription(request.getDescription());
|
||||||
|
existing.setResourceUrl(request.getResourceUrl());
|
||||||
|
existing.setStatus(normalizeApplicationStatus(request.getStatus()));
|
||||||
|
reviewApplicationMapper.updateById(existing);
|
||||||
|
return existing;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteApplication(Integer id) throws NotFindEntitiesException {
|
||||||
|
ReviewApplicationEntity existing = Optional.ofNullable(reviewApplicationMapper.selectById(id))
|
||||||
|
.orElseThrow(() -> new NotFindEntitiesException("应用场景[" + id + "]不存在"));
|
||||||
|
reviewApplicationMapper.deleteById(existing.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ReviewMindMapEntity getMindMap(String taskNum) throws NotFindEntitiesException {
|
||||||
|
ensureTaskExists(taskNum);
|
||||||
|
return reviewMindMapMapper.selectOne(
|
||||||
|
Wrappers.<ReviewMindMapEntity>lambdaQuery()
|
||||||
|
.eq(ReviewMindMapEntity::getTaskNum, taskNum)
|
||||||
|
.last("LIMIT 1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ReviewMindMapEntity upsertMindMap(String taskNum, UpsertReviewMindMapRequest request) throws NotFindEntitiesException {
|
||||||
|
ensureTaskExists(taskNum);
|
||||||
|
ReviewMindMapEntity entity = getMindMap(taskNum);
|
||||||
|
boolean create = entity == null;
|
||||||
|
if (create) {
|
||||||
|
entity = new ReviewMindMapEntity();
|
||||||
|
entity.setTaskNum(taskNum);
|
||||||
|
}
|
||||||
|
entity.setTitle(request.getTitle());
|
||||||
|
entity.setContent(request.getContent());
|
||||||
|
entity.setContentFormat(normalizeMindMapFormat(request.getContentFormat()));
|
||||||
|
if (create) {
|
||||||
|
reviewMindMapMapper.insert(entity);
|
||||||
|
} else {
|
||||||
|
reviewMindMapMapper.updateById(entity);
|
||||||
|
}
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将报告和残片合并转换为 ReviewFeedItem 列表,按创建时间倒序排列
|
* 将报告和残片合并转换为 ReviewFeedItem 列表,按创建时间倒序排列
|
||||||
*/
|
*/
|
||||||
@@ -197,6 +294,35 @@ public class ReviewServiceImpl implements ReviewService {
|
|||||||
return stats;
|
return stats;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int normalizeLimit(int limit) {
|
||||||
|
if (limit <= 0) {
|
||||||
|
return DEFAULT_LIMIT;
|
||||||
|
}
|
||||||
|
return Math.min(limit, MAX_LIMIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ensureTaskExists(String taskNum) throws NotFindEntitiesException {
|
||||||
|
if (!StringUtils.hasText(taskNum) || !tasksMapper.exists(
|
||||||
|
Wrappers.<TaskEntity>lambdaQuery().eq(TaskEntity::getTaskNum, taskNum))) {
|
||||||
|
throw new NotFindEntitiesException("任务[" + taskNum + "]不存在");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String normalizeApplicationStatus(String status) {
|
||||||
|
return ReviewApplicationStatusEnum.fromCodeOrDefault(status).getCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String normalizeMindMapFormat(String contentFormat) {
|
||||||
|
if (!StringUtils.hasText(contentFormat)) {
|
||||||
|
return DEFAULT_MIND_MAP_FORMAT;
|
||||||
|
}
|
||||||
|
String normalized = contentFormat.trim().toUpperCase(Locale.ROOT);
|
||||||
|
if (!Set.of("TEXT", "MERMAID", "JSON").contains(normalized)) {
|
||||||
|
return DEFAULT_MIND_MAP_FORMAT;
|
||||||
|
}
|
||||||
|
return normalized;
|
||||||
|
}
|
||||||
|
|
||||||
private void fillReviewTaskStats(List<ReviewTaskStats> statsList) {
|
private void fillReviewTaskStats(List<ReviewTaskStats> statsList) {
|
||||||
Map<String, ReviewTaskStats> statsByTaskNum = statsList.stream()
|
Map<String, ReviewTaskStats> statsByTaskNum = statsList.stream()
|
||||||
.filter(item -> StringUtils.hasText(item.getTaskNum()))
|
.filter(item -> StringUtils.hasText(item.getTaskNum()))
|
||||||
|
|||||||
+36
@@ -0,0 +1,36 @@
|
|||||||
|
create table review_applications
|
||||||
|
(
|
||||||
|
id int auto_increment comment 'id无业务含义'
|
||||||
|
primary key,
|
||||||
|
task_num varchar(255) not null comment '任务编码',
|
||||||
|
title varchar(255) not null comment '应用项目标题',
|
||||||
|
description text null comment '应用项目描述',
|
||||||
|
resource_url varchar(1024) null comment '相关链接',
|
||||||
|
status varchar(30) not null default 'TODO' comment '状态:TODO/DOING/DONE',
|
||||||
|
created_time datetime not null comment '创建时间',
|
||||||
|
created_by varchar(255) null,
|
||||||
|
last_modified_time datetime null,
|
||||||
|
last_modified_by varchar(255) null,
|
||||||
|
device_info varchar(50) null comment '操作者设备类型',
|
||||||
|
deleted int default 0 not null comment '逻辑删除符',
|
||||||
|
index idx_review_applications_task_num (task_num)
|
||||||
|
)
|
||||||
|
comment '复习模块:学习内容可应用项目';
|
||||||
|
|
||||||
|
create table review_mind_maps
|
||||||
|
(
|
||||||
|
id int auto_increment comment 'id无业务含义'
|
||||||
|
primary key,
|
||||||
|
task_num varchar(255) not null comment '任务编码',
|
||||||
|
title varchar(255) not null comment '思维导图标题',
|
||||||
|
content text not null comment '思维导图内容',
|
||||||
|
content_format varchar(30) not null default 'TEXT' comment '内容格式:TEXT/MERMAID/JSON',
|
||||||
|
created_time datetime not null comment '创建时间',
|
||||||
|
created_by varchar(255) null,
|
||||||
|
last_modified_time datetime null,
|
||||||
|
last_modified_by varchar(255) null,
|
||||||
|
device_info varchar(50) null comment '操作者设备类型',
|
||||||
|
deleted int default 0 not null comment '逻辑删除符',
|
||||||
|
unique key uk_review_mind_maps_task_num (task_num)
|
||||||
|
)
|
||||||
|
comment '复习模块:任务思维导图';
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
package com.guo.learningprogresstracker;
|
package com.guo.learningprogresstracker;
|
||||||
|
|
||||||
|
import cn.dev33.satoken.stp.StpUtil;
|
||||||
import com.guo.learningprogresstracker.entity.TestTableEntity;
|
import com.guo.learningprogresstracker.entity.TestTableEntity;
|
||||||
import com.guo.learningprogresstracker.service.impl.TestTableServiceImpl;
|
import com.guo.learningprogresstracker.service.impl.TestTableServiceImpl;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.test.context.SpringBootTest;
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
@@ -19,6 +21,11 @@ public class DataSourceTest {
|
|||||||
@Autowired
|
@Autowired
|
||||||
TestTableServiceImpl testTableService;
|
TestTableServiceImpl testTableService;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void setUp() {
|
||||||
|
StpUtil.login("1", "test_driver");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAdd(){
|
public void testAdd(){
|
||||||
TestTableEntity testTableEntity = new TestTableEntity();
|
TestTableEntity testTableEntity = new TestTableEntity();
|
||||||
@@ -30,8 +37,12 @@ public class DataSourceTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDelete(){
|
public void testDelete(){
|
||||||
|
TestTableEntity testTableEntity = new TestTableEntity();
|
||||||
|
testTableEntity.setIdName("guo_test_delete");
|
||||||
|
testTableService.save(testTableEntity);
|
||||||
|
|
||||||
HashMap<String, Object> stringStringHashMap = new HashMap<>();
|
HashMap<String, Object> stringStringHashMap = new HashMap<>();
|
||||||
stringStringHashMap.put("id_name", "guo_test");
|
stringStringHashMap.put("id_name", "guo_test_delete");
|
||||||
boolean delete = testTableService.removeByMap(stringStringHashMap);
|
boolean delete = testTableService.removeByMap(stringStringHashMap);
|
||||||
|
|
||||||
assertTrue(delete,"删除idName为guo_test的数据失败");
|
assertTrue(delete,"删除idName为guo_test的数据失败");
|
||||||
|
|||||||
@@ -18,8 +18,6 @@ import org.springframework.test.web.servlet.MockMvc;
|
|||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
import static org.mockito.Mockito.mock;
|
|
||||||
import static org.mockito.Mockito.when;
|
|
||||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
|
||||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||||
@@ -45,12 +43,12 @@ class TaskControllerTest {
|
|||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
void setUp() {
|
void setUp() {
|
||||||
StpUtil.login("测试用户-创建任务", "test_driver");
|
StpUtil.login("1", "test_driver");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void addTask() throws Exception {
|
void addTask() throws Exception {
|
||||||
TaskRequest taskRequest = getTaskRequest();
|
TaskRequest taskRequest = getTaskRequest("测试任务名称-" + System.nanoTime());
|
||||||
log.info("testInfo");
|
log.info("testInfo");
|
||||||
String s = jacksonObjectMapper.writeValueAsString(taskRequest);
|
String s = jacksonObjectMapper.writeValueAsString(taskRequest);
|
||||||
System.out.println("Token Value: " + StpUtil.getTokenValue());
|
System.out.println("Token Value: " + StpUtil.getTokenValue());
|
||||||
@@ -63,30 +61,16 @@ class TaskControllerTest {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static TaskRequest getTaskRequest() {
|
private static TaskRequest getTaskRequest(String taskName) {
|
||||||
TaskRequest taskRequest = mock(TaskRequest.class);
|
TaskRequest taskRequest = new TaskRequest();
|
||||||
|
taskRequest.setTaskName(taskName);
|
||||||
when(taskRequest.getId()).thenReturn(null);
|
taskRequest.setTaskDescription("测试任务描述");
|
||||||
// 设置学习任务的名称
|
taskRequest.setMaterialUrl("http://example.com/material");
|
||||||
when(taskRequest.getTaskName()).thenReturn("测试任务名称");
|
taskRequest.setUrgency(5);
|
||||||
|
taskRequest.setImportance(3);
|
||||||
// 设置学习材料的存储URL
|
taskRequest.setContentDifficulty(4);
|
||||||
when(taskRequest.getMaterialUrl()).thenReturn("http://example.com/material");
|
taskRequest.setFutureValue(4);
|
||||||
|
taskRequest.setSubjectivePriority(1);
|
||||||
// 设置用户设置的任务紧急性
|
|
||||||
when(taskRequest.getUrgency()).thenReturn(5);
|
|
||||||
|
|
||||||
// 设置用户设置的任务重要性
|
|
||||||
when(taskRequest.getImportance()).thenReturn(3);
|
|
||||||
|
|
||||||
// 设置任务的内容难度
|
|
||||||
when(taskRequest.getContentDifficulty()).thenReturn(4);
|
|
||||||
|
|
||||||
// 设置任务的未来价值
|
|
||||||
when(taskRequest.getFutureValue()).thenReturn(4);
|
|
||||||
|
|
||||||
// 设置用户对任务的主观优先级
|
|
||||||
when(taskRequest.getSubjectivePriority()).thenReturn(1);
|
|
||||||
return taskRequest;
|
return taskRequest;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,10 +92,8 @@ class TaskControllerTest {
|
|||||||
@Test
|
@Test
|
||||||
void updateTask() throws Exception {
|
void updateTask() throws Exception {
|
||||||
|
|
||||||
TaskRequest taskRequest = mock(TaskRequest.class);
|
TaskRequest taskRequest = getTaskRequest("测试数据名称");
|
||||||
when(taskRequest.getTaskName()).thenReturn("测试数据名称");
|
taskRequest.setId(1);
|
||||||
when(taskRequest.getMaterialUrl()).thenReturn("http://example.com/material");
|
|
||||||
when(taskRequest.getId()).thenReturn(1);
|
|
||||||
String s = jacksonObjectMapper.writeValueAsString(taskRequest);
|
String s = jacksonObjectMapper.writeValueAsString(taskRequest);
|
||||||
|
|
||||||
mockMvc.perform(put("/tasks/"+taskRequest.getId())
|
mockMvc.perform(put("/tasks/"+taskRequest.getId())
|
||||||
@@ -126,9 +108,9 @@ class TaskControllerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
void deleteTask() throws Exception {
|
void deleteTask() throws Exception {
|
||||||
CommonResult commonResult = taskController.addTask(getTaskRequest());
|
CommonResult commonResult = taskController.addTask(getTaskRequest("待删除任务-" + System.nanoTime()));
|
||||||
assertEquals(commonResult.getCode(),200);
|
assertEquals(commonResult.getCode(),200);
|
||||||
TaskEntity taskEntity = tasksServiceImpl.getOne(Wrappers.<TaskEntity>lambdaQuery().eq(TaskEntity::getTaskNum, commonResult.getMessage()));
|
TaskEntity taskEntity = tasksServiceImpl.getOne(Wrappers.<TaskEntity>lambdaQuery().eq(TaskEntity::getTaskNum, commonResult.getData()));
|
||||||
assertNotNull(taskEntity,"未能找到新创建的任务实体");
|
assertNotNull(taskEntity,"未能找到新创建的任务实体");
|
||||||
mockMvc.perform(delete("/tasks/"+taskEntity.getId())
|
mockMvc.perform(delete("/tasks/"+taskEntity.getId())
|
||||||
.header("satoken",StpUtil.getTokenValue()))
|
.header("satoken",StpUtil.getTokenValue()))
|
||||||
|
|||||||
+175
@@ -0,0 +1,175 @@
|
|||||||
|
package com.guo.learningprogresstracker.service.impl;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.MybatisConfiguration;
|
||||||
|
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
|
||||||
|
import com.guo.learningprogresstracker.dto.ReviewFeedItem;
|
||||||
|
import com.guo.learningprogresstracker.dto.request.CreateReviewApplicationRequest;
|
||||||
|
import com.guo.learningprogresstracker.dto.request.UpsertReviewMindMapRequest;
|
||||||
|
import com.guo.learningprogresstracker.entity.ReviewApplicationEntity;
|
||||||
|
import com.guo.learningprogresstracker.entity.ReviewMindMapEntity;
|
||||||
|
import com.guo.learningprogresstracker.entity.StudyReportFragmentsEntity;
|
||||||
|
import com.guo.learningprogresstracker.entity.StudyReportsEntity;
|
||||||
|
import com.guo.learningprogresstracker.entity.StudySessionsEntity;
|
||||||
|
import com.guo.learningprogresstracker.entity.TaskEntity;
|
||||||
|
import com.guo.learningprogresstracker.enums.ReviewApplicationStatusEnum;
|
||||||
|
import com.guo.learningprogresstracker.mapper.ReviewApplicationMapper;
|
||||||
|
import com.guo.learningprogresstracker.mapper.ReviewMindMapMapper;
|
||||||
|
import com.guo.learningprogresstracker.mapper.StudyReportFragmentsMapper;
|
||||||
|
import com.guo.learningprogresstracker.mapper.StudyReportsMapper;
|
||||||
|
import com.guo.learningprogresstracker.mapper.StudySessionsMapper;
|
||||||
|
import com.guo.learningprogresstracker.mapper.TasksMapper;
|
||||||
|
import org.apache.ibatis.builder.MapperBuilderAssistant;
|
||||||
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
import org.mockito.InjectMocks;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
@ExtendWith(MockitoExtension.class)
|
||||||
|
class ReviewServiceImplTest {
|
||||||
|
|
||||||
|
@BeforeAll
|
||||||
|
static void initTableInfo() {
|
||||||
|
MybatisConfiguration configuration = new MybatisConfiguration();
|
||||||
|
TableInfoHelper.initTableInfo(new MapperBuilderAssistant(configuration, ""), StudyReportsEntity.class);
|
||||||
|
TableInfoHelper.initTableInfo(new MapperBuilderAssistant(configuration, ""), StudyReportFragmentsEntity.class);
|
||||||
|
TableInfoHelper.initTableInfo(new MapperBuilderAssistant(configuration, ""), StudySessionsEntity.class);
|
||||||
|
TableInfoHelper.initTableInfo(new MapperBuilderAssistant(configuration, ""), TaskEntity.class);
|
||||||
|
TableInfoHelper.initTableInfo(new MapperBuilderAssistant(configuration, ""), ReviewApplicationEntity.class);
|
||||||
|
TableInfoHelper.initTableInfo(new MapperBuilderAssistant(configuration, ""), ReviewMindMapEntity.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@InjectMocks
|
||||||
|
private ReviewServiceImpl reviewService;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private StudyReportsMapper studyReportsMapper;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private StudyReportFragmentsMapper studyReportFragmentsMapper;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private StudySessionsMapper studySessionsMapper;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private TasksMapper tasksMapper;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private ReviewApplicationMapper reviewApplicationMapper;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private ReviewMindMapMapper reviewMindMapMapper;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void getReviewFeed_shouldApplyFinalLimitAfterMerge() {
|
||||||
|
StudyReportsEntity report = new StudyReportsEntity();
|
||||||
|
report.setId(1);
|
||||||
|
report.setSessionNum("S1");
|
||||||
|
report.setContent("report");
|
||||||
|
report.setCreatedTime(LocalDateTime.now());
|
||||||
|
|
||||||
|
StudyReportFragmentsEntity fragment = new StudyReportFragmentsEntity();
|
||||||
|
fragment.setId(2);
|
||||||
|
fragment.setSessionNum("S1");
|
||||||
|
fragment.setContent("fragment");
|
||||||
|
fragment.setCreatedTime(LocalDateTime.now().minusMinutes(1));
|
||||||
|
|
||||||
|
StudySessionsEntity session = new StudySessionsEntity();
|
||||||
|
session.setSessionNum("S1");
|
||||||
|
session.setTaskNum("T1");
|
||||||
|
|
||||||
|
TaskEntity task = new TaskEntity();
|
||||||
|
task.setTaskNum("T1");
|
||||||
|
task.setTaskName("Task");
|
||||||
|
|
||||||
|
when(studyReportsMapper.selectList(any())).thenReturn(List.of(report));
|
||||||
|
when(studyReportFragmentsMapper.selectList(any())).thenReturn(List.of(fragment));
|
||||||
|
when(studySessionsMapper.selectList(any())).thenReturn(List.of(session));
|
||||||
|
when(tasksMapper.selectList(any())).thenReturn(List.of(task));
|
||||||
|
|
||||||
|
List<ReviewFeedItem> items = reviewService.getReviewFeed(1, "recent");
|
||||||
|
|
||||||
|
assertEquals(1, items.size());
|
||||||
|
assertEquals("REPORT", items.get(0).getSourceType());
|
||||||
|
assertEquals("Task", items.get(0).getTaskName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void createApplication_shouldUseDefaultStatusWhenStatusInvalid() throws Exception {
|
||||||
|
when(tasksMapper.exists(any())).thenReturn(true);
|
||||||
|
when(reviewApplicationMapper.insert(any())).thenAnswer(invocation -> {
|
||||||
|
ReviewApplicationEntity entity = invocation.getArgument(0);
|
||||||
|
entity.setId(7);
|
||||||
|
return 1;
|
||||||
|
});
|
||||||
|
|
||||||
|
CreateReviewApplicationRequest request = new CreateReviewApplicationRequest();
|
||||||
|
request.setTaskNum("T1");
|
||||||
|
request.setTitle("Build a demo");
|
||||||
|
request.setStatus("invalid");
|
||||||
|
|
||||||
|
ReviewApplicationEntity entity = reviewService.createApplication(request);
|
||||||
|
|
||||||
|
assertEquals(7, entity.getId());
|
||||||
|
assertEquals(ReviewApplicationStatusEnum.TODO.getCode(), entity.getStatus());
|
||||||
|
verify(reviewApplicationMapper).insert(any(ReviewApplicationEntity.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void upsertMindMap_shouldCreateWhenMissing() throws Exception {
|
||||||
|
when(tasksMapper.exists(any())).thenReturn(true);
|
||||||
|
when(reviewMindMapMapper.selectOne(any())).thenReturn(null);
|
||||||
|
when(reviewMindMapMapper.insert(any())).thenAnswer(invocation -> {
|
||||||
|
ReviewMindMapEntity entity = invocation.getArgument(0);
|
||||||
|
entity.setId(3);
|
||||||
|
return 1;
|
||||||
|
});
|
||||||
|
|
||||||
|
UpsertReviewMindMapRequest request = new UpsertReviewMindMapRequest();
|
||||||
|
request.setTitle("Map");
|
||||||
|
request.setContent("root");
|
||||||
|
request.setContentFormat("mermaid");
|
||||||
|
|
||||||
|
ReviewMindMapEntity entity = reviewService.upsertMindMap("T1", request);
|
||||||
|
|
||||||
|
assertNotNull(entity.getId());
|
||||||
|
assertEquals("T1", entity.getTaskNum());
|
||||||
|
assertEquals("MERMAID", entity.getContentFormat());
|
||||||
|
verify(reviewMindMapMapper).insert(any(ReviewMindMapEntity.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void upsertMindMap_shouldUpdateExisting() throws Exception {
|
||||||
|
ReviewMindMapEntity existing = new ReviewMindMapEntity();
|
||||||
|
existing.setId(5);
|
||||||
|
existing.setTaskNum("T1");
|
||||||
|
existing.setTitle("Old");
|
||||||
|
existing.setContent("old");
|
||||||
|
existing.setContentFormat("TEXT");
|
||||||
|
|
||||||
|
when(tasksMapper.exists(any())).thenReturn(true);
|
||||||
|
when(reviewMindMapMapper.selectOne(any())).thenReturn(existing);
|
||||||
|
|
||||||
|
UpsertReviewMindMapRequest request = new UpsertReviewMindMapRequest();
|
||||||
|
request.setTitle("New");
|
||||||
|
request.setContent("new");
|
||||||
|
request.setContentFormat("json");
|
||||||
|
|
||||||
|
ReviewMindMapEntity entity = reviewService.upsertMindMap("T1", request);
|
||||||
|
|
||||||
|
assertEquals(5, entity.getId());
|
||||||
|
assertEquals("New", entity.getTitle());
|
||||||
|
assertEquals("JSON", entity.getContentFormat());
|
||||||
|
verify(reviewMindMapMapper).updateById(existing);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
spring:
|
||||||
|
datasource:
|
||||||
|
driver-class-name: org.h2.Driver
|
||||||
|
url: jdbc:h2:mem:lpt_test;MODE=MySQL;DATABASE_TO_LOWER=TRUE;CASE_INSENSITIVE_IDENTIFIERS=TRUE;NON_KEYWORDS=USER;DB_CLOSE_DELAY=-1
|
||||||
|
username: sa
|
||||||
|
password:
|
||||||
|
flyway:
|
||||||
|
enabled: true
|
||||||
|
locations: classpath:db/migration
|
||||||
|
baseline-on-migrate: true
|
||||||
|
jackson:
|
||||||
|
time-zone: UTC
|
||||||
|
date-format: yyyy-MM-dd'T'HH:mm:ss'Z'
|
||||||
|
|
||||||
|
mybatis-plus:
|
||||||
|
configuration:
|
||||||
|
log-impl: org.apache.ibatis.logging.nologging.NoLoggingImpl
|
||||||
|
|
||||||
|
sa-token:
|
||||||
|
token-name: satoken
|
||||||
|
timeout: 2592000
|
||||||
|
active-timeout: -1
|
||||||
|
is-concurrent: true
|
||||||
|
is-share: true
|
||||||
|
token-style: uuid
|
||||||
|
is-log: false
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
insert into user (id, user_name, user_password, created_time, deleted)
|
||||||
|
values ('1', 'admin', '$2a$10$skdiSwut4R9pAvt2ZK5ct.6QNualPyJGiaxngFObdLrpAxRnzehBS', now(), 0);
|
||||||
|
|
||||||
|
insert into tasks (
|
||||||
|
id,
|
||||||
|
task_num,
|
||||||
|
task_name,
|
||||||
|
task_description,
|
||||||
|
urgency,
|
||||||
|
importance,
|
||||||
|
content_difficulty,
|
||||||
|
future_value,
|
||||||
|
subjective_priority,
|
||||||
|
calculated_priority,
|
||||||
|
material_url,
|
||||||
|
last_learning_status,
|
||||||
|
created_by,
|
||||||
|
created_time,
|
||||||
|
deleted
|
||||||
|
)
|
||||||
|
values (
|
||||||
|
1,
|
||||||
|
'TASK_TEST',
|
||||||
|
'测试任务名称',
|
||||||
|
'测试任务描述',
|
||||||
|
3,
|
||||||
|
3,
|
||||||
|
3,
|
||||||
|
3,
|
||||||
|
3,
|
||||||
|
3,
|
||||||
|
'http://example.com/material',
|
||||||
|
'未开始',
|
||||||
|
'1',
|
||||||
|
now(),
|
||||||
|
0
|
||||||
|
);
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
mock-maker-subclass
|
||||||
Reference in New Issue
Block a user