From ab7ef76cf36f3ef1813425cd069a4fe5bc2e7387 Mon Sep 17 00:00:00 2001 From: luoweijian <1329394916@qq.com> Date: Fri, 30 Jan 2026 09:07:11 +0800 Subject: [PATCH] =?UTF-8?q?=E8=80=83=E8=AF=95=E4=BB=BB=E5=8A=A1=E7=AE=A1?= =?UTF-8?q?=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../impl/SearchUserDomainServiceImpl.java | 2 +- .../application/TaskApplicationService.java | 18 ++ .../impl/TaskApplicationServiceImpl.java | 48 ++++++ .../task/config/ExamScoreRatioConfig.java | 30 ++++ .../task/controller/TaskController.java | 46 +++++ .../com/project/task/domain/dto/TaskDTO.java | 41 +++++ .../task/domain/entity/ExamRecordEntity.java | 83 +++++++++ .../task/domain/entity/TaskEntity.java | 144 ++++++++++++++++ .../task/domain/entity/TaskUserEntity.java | 46 +++++ .../task/domain/enums/QuestionTypeEnum.java | 17 ++ .../task/domain/enums/TaskStatusEnum.java | 15 ++ .../task/domain/enums/TaskUserStatusEnum.java | 18 ++ .../project/task/domain/param/TaskParam.java | 13 ++ .../service/DeleteTaskDomainService.java | 11 ++ .../SaveOrUpdateTaskDomainService.java | 9 + .../service/SearchTaskDomainService.java | 12 ++ .../task/domain/service/TaskBaseService.java | 8 + .../domain/service/TaskUserBaseService.java | 7 + .../impl/DeleteTaskDomainServiceImpl.java | 31 ++++ .../SaveOrUpdateTaskDomainServiceImpl.java | 157 ++++++++++++++++++ .../impl/SearchTaskDomainServiceImpl.java | 65 ++++++++ .../service/impl/TaskBaseServiceImpl.java | 12 ++ .../service/impl/TaskUserBaseServiceImpl.java | 11 ++ .../com/project/task/mapper/TaskMapper.java | 9 + .../project/task/mapper/TaskUserMapper.java | 9 + 25 files changed, 861 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/project/task/application/TaskApplicationService.java create mode 100644 src/main/java/com/project/task/application/impl/TaskApplicationServiceImpl.java create mode 100644 src/main/java/com/project/task/config/ExamScoreRatioConfig.java create mode 100644 src/main/java/com/project/task/controller/TaskController.java create mode 100644 src/main/java/com/project/task/domain/dto/TaskDTO.java create mode 100644 src/main/java/com/project/task/domain/entity/ExamRecordEntity.java create mode 100644 src/main/java/com/project/task/domain/entity/TaskEntity.java create mode 100644 src/main/java/com/project/task/domain/entity/TaskUserEntity.java create mode 100644 src/main/java/com/project/task/domain/enums/QuestionTypeEnum.java create mode 100644 src/main/java/com/project/task/domain/enums/TaskStatusEnum.java create mode 100644 src/main/java/com/project/task/domain/enums/TaskUserStatusEnum.java create mode 100644 src/main/java/com/project/task/domain/param/TaskParam.java create mode 100644 src/main/java/com/project/task/domain/service/DeleteTaskDomainService.java create mode 100644 src/main/java/com/project/task/domain/service/SaveOrUpdateTaskDomainService.java create mode 100644 src/main/java/com/project/task/domain/service/SearchTaskDomainService.java create mode 100644 src/main/java/com/project/task/domain/service/TaskBaseService.java create mode 100644 src/main/java/com/project/task/domain/service/TaskUserBaseService.java create mode 100644 src/main/java/com/project/task/domain/service/impl/DeleteTaskDomainServiceImpl.java create mode 100644 src/main/java/com/project/task/domain/service/impl/SaveOrUpdateTaskDomainServiceImpl.java create mode 100644 src/main/java/com/project/task/domain/service/impl/SearchTaskDomainServiceImpl.java create mode 100644 src/main/java/com/project/task/domain/service/impl/TaskBaseServiceImpl.java create mode 100644 src/main/java/com/project/task/domain/service/impl/TaskUserBaseServiceImpl.java create mode 100644 src/main/java/com/project/task/mapper/TaskMapper.java create mode 100644 src/main/java/com/project/task/mapper/TaskUserMapper.java diff --git a/src/main/java/com/project/ding/domain/service/impl/SearchUserDomainServiceImpl.java b/src/main/java/com/project/ding/domain/service/impl/SearchUserDomainServiceImpl.java index bb3911f..18c9a33 100644 --- a/src/main/java/com/project/ding/domain/service/impl/SearchUserDomainServiceImpl.java +++ b/src/main/java/com/project/ding/domain/service/impl/SearchUserDomainServiceImpl.java @@ -48,7 +48,7 @@ public class SearchUserDomainServiceImpl implements SearchUserDomainService { // todo 构建考试信息 - return entity.toDTO(UserDTO::new); + return dto; } @Override diff --git a/src/main/java/com/project/task/application/TaskApplicationService.java b/src/main/java/com/project/task/application/TaskApplicationService.java new file mode 100644 index 0000000..a7521ae --- /dev/null +++ b/src/main/java/com/project/task/application/TaskApplicationService.java @@ -0,0 +1,18 @@ +package com.project.task.application; + +import com.project.base.domain.result.PageResult; +import com.project.base.domain.result.Result; +import com.project.task.domain.dto.TaskDTO; +import com.project.task.domain.param.TaskParam; + +import java.util.List; + +public interface TaskApplicationService { + Result saveOrUpdate(TaskDTO dto) throws Exception; + + Result batchDelete(List idList) throws Exception; + + Result> search(TaskParam param) throws Exception; + + Result getDetail(Long id) throws Exception; +} diff --git a/src/main/java/com/project/task/application/impl/TaskApplicationServiceImpl.java b/src/main/java/com/project/task/application/impl/TaskApplicationServiceImpl.java new file mode 100644 index 0000000..fe5cde9 --- /dev/null +++ b/src/main/java/com/project/task/application/impl/TaskApplicationServiceImpl.java @@ -0,0 +1,48 @@ +package com.project.task.application.impl; + +import com.project.base.domain.result.PageResult; +import com.project.base.domain.result.Result; +import com.project.task.application.TaskApplicationService; +import com.project.task.domain.dto.TaskDTO; +import com.project.task.domain.param.TaskParam; +import com.project.task.domain.service.DeleteTaskDomainService; +import com.project.task.domain.service.SaveOrUpdateTaskDomainService; +import com.project.task.domain.service.SearchTaskDomainService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + + +@Service +public class TaskApplicationServiceImpl implements TaskApplicationService { + @Autowired + private SaveOrUpdateTaskDomainService saveOrUpdateTaskDomainService; + + @Autowired + private DeleteTaskDomainService deleteTaskDomainService; + + @Autowired + private SearchTaskDomainService searchTaskDomainService; + + @Override + public Result saveOrUpdate(TaskDTO dto) throws Exception { + return saveOrUpdateTaskDomainService.saveOrUpdate(dto); + } + + + @Override + public Result batchDelete(List idList) throws Exception { + return deleteTaskDomainService.batchDelete(idList); + } + + @Override + public Result> search(TaskParam param) throws Exception { + return searchTaskDomainService.search(param); + } + + @Override + public Result getDetail(Long id) throws Exception { + return searchTaskDomainService.getDetail(id); + } +} diff --git a/src/main/java/com/project/task/config/ExamScoreRatioConfig.java b/src/main/java/com/project/task/config/ExamScoreRatioConfig.java new file mode 100644 index 0000000..de75848 --- /dev/null +++ b/src/main/java/com/project/task/config/ExamScoreRatioConfig.java @@ -0,0 +1,30 @@ +package com.project.task.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +@Data +@Component +@ConfigurationProperties(prefix = "exam.score-ratio") +public class ExamScoreRatioConfig { + /** + * 单选题权重,默认 2 + */ + private Integer single = 2; + + /** + * 多选题权重,默认 3 + */ + private Integer multiple = 3; + + /** + * 判断题权重,默认 1 + */ + private Integer trueFalse = 1; + + /** + * 总分固定 100 + */ + private Integer totalScore = 100; +} diff --git a/src/main/java/com/project/task/controller/TaskController.java b/src/main/java/com/project/task/controller/TaskController.java new file mode 100644 index 0000000..35715ea --- /dev/null +++ b/src/main/java/com/project/task/controller/TaskController.java @@ -0,0 +1,46 @@ +package com.project.task.controller; + + +import com.project.base.domain.result.PageResult; +import com.project.base.domain.result.Result; +import com.project.task.application.TaskApplicationService; +import com.project.task.domain.dto.TaskDTO; +import com.project.task.domain.param.TaskParam; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + + +@RestController +@Slf4j +@RequestMapping("/api/admin/task") +public class TaskController { + @Autowired + private TaskApplicationService taskApplicationService; + + @GetMapping("/search") + public Result> search(TaskParam param) throws Exception { + return taskApplicationService.search(param); + } + + @GetMapping("/getDetail") + public Result getDetail(Long id) throws Exception { + return taskApplicationService.getDetail(id); + } + + @PostMapping("/saveOrUpdate") + public Result save(TaskDTO dto) throws Exception { + return taskApplicationService.saveOrUpdate(dto); + } + + + @PostMapping("/batchDelete") + public Result batchDelete(List idList) throws Exception { + return taskApplicationService.batchDelete(idList); + } +} diff --git a/src/main/java/com/project/task/domain/dto/TaskDTO.java b/src/main/java/com/project/task/domain/dto/TaskDTO.java new file mode 100644 index 0000000..7bc127d --- /dev/null +++ b/src/main/java/com/project/task/domain/dto/TaskDTO.java @@ -0,0 +1,41 @@ +package com.project.task.domain.dto; + +import com.project.base.domain.dto.BaseDTO; +import lombok.Data; + +import java.util.Date; +import java.util.List; + +@Data +public class TaskDTO extends BaseDTO { + + private Long id; + private String name; + private Date startTime; + private Date endTime; + private Long lineId; + private String lineName; + private Long subLineId; + private String subLineName; + private Integer accurateGraspNum; + private Integer vagueGraspNum; + private Integer duration; + private Integer passScore; + private String note; + private List relatedDocumentList; + private Integer singleChoiceNum; + private Double singleChoiceScore; + private Integer multipleChoiceNum; + private Double multipleChoiceScore; + private Integer trueFalseNum; + private Double trueFalseScore; + private Double totalScore; + private Integer participantNum; + private Integer passNum; + private Boolean needAiGrading; + + private List participantUserIdList; + + private String statusText; + +} diff --git a/src/main/java/com/project/task/domain/entity/ExamRecordEntity.java b/src/main/java/com/project/task/domain/entity/ExamRecordEntity.java new file mode 100644 index 0000000..afe393b --- /dev/null +++ b/src/main/java/com/project/task/domain/entity/ExamRecordEntity.java @@ -0,0 +1,83 @@ +package com.project.task.domain.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 com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import com.project.base.domain.entity.BaseEntity; +import jakarta.persistence.*; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.hibernate.annotations.Comment; +import org.hibernate.annotations.JdbcTypeCode; +import org.hibernate.type.SqlTypes; + +import java.util.Date; +import java.util.List; +import java.util.Map; + +@Data +@Table(name = "evaluator_exam_record" , indexes = {@Index(name = "Idx_parentId", columnList = "parent_id")}) +@Entity +@TableName(value = "evaluator_exam_record" , autoResultMap = true) +@EqualsAndHashCode(callSuper = true) +public class ExamRecordEntity extends BaseEntity { + @TableId(type = IdType.ASSIGN_ID) + @Id + private Long id; + + @TableField("task_user_id") + @Column(name = "task_user_id" , columnDefinition="bigint(20) comment '关联TaskUserEntity'") + private Long taskUserId; + + @Comment("分数") + @Column(name = "score") + private Double score; + + @Column(name = "pass") + @Comment("是否通过") + private Boolean pass; + + + @Comment("开始时间") + @Column(name = "start_time") + @TableField("start_time") + private Date startTime; + + @Comment("提交时间") + @Column(name = "submit_time") + @TableField("submit_time") + private Date submitTime; + /** + * 考试快照(包含:题干、当时乱序后的选项内容、用户答案、正确答案、解析、是否正确) + */ + @TableField(value = "answer_snapshot" , typeHandler = JacksonTypeHandler.class) + @JdbcTypeCode(SqlTypes.JSON) + @Column(name = "answer_snapshot", columnDefinition = "json") + private List answerSnapshot; + + @Data + public static class QuestionSnapshot { + private Long questionId; + // 题干原文 + private String questionContent; + // 题型 + private Integer type; + // 用户看的选项:{"A":"xxx", "B":"yyy"} + private Map options; + // 正确项 + private String rightAnswer; + // 用户选的 + private String userAnswer; + // 判定正确 + private Boolean isRight; + // AI解析 + private String analysis; + // 该题是否已发起申诉 + private Boolean hasAppealed = false; + } + + +} diff --git a/src/main/java/com/project/task/domain/entity/TaskEntity.java b/src/main/java/com/project/task/domain/entity/TaskEntity.java new file mode 100644 index 0000000..64a8131 --- /dev/null +++ b/src/main/java/com/project/task/domain/entity/TaskEntity.java @@ -0,0 +1,144 @@ +package com.project.task.domain.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 com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import com.project.base.domain.entity.BaseEntity; +import jakarta.persistence.*; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.hibernate.annotations.Comment; +import org.hibernate.annotations.JdbcTypeCode; +import org.hibernate.type.SqlTypes; + +import java.util.Date; +import java.util.List; + +@Data +@Table(name = "evaluator_task" , + indexes = {@Index(name = "Idx_startTime_endTime" , columnList = "start_time,end_time") , + @Index(name = "Idx_endTime" , columnList = "end_time") , + @Index(name = "Idx_subLineId" , columnList = "sub_line_id") + }) +@Entity +@TableName(value = "evaluator_task", autoResultMap = true) +@EqualsAndHashCode(callSuper = true) + +public class TaskEntity extends BaseEntity { + @TableId(value = "id" , type = IdType.ASSIGN_ID) + @Id + private Long id; + + @Column(name = "name" , columnDefinition="varchar(50) comment '考试任务名称'") + private String name; + + @Comment("开始时间") + @Column(name = "start_time") + @TableField("start_time") + private Date startTime; + + @Comment("结束时间") + @Column(name = "end_time") + @TableField("end_time") + private Date endTime; + + @Column(name = "line_id") + @Comment("产品线ID") + @TableField("line_id") + private Long lineId; + + @Column(name = "line_name" , columnDefinition="varchar(550) comment '所属产品线名称'") + @Comment("产品线名称") + @TableField("line_name") + private String lineName; + + @Column(name = "sub_line_id") + @Comment("所属子产品线ID") + @TableField("sub_line_id") + private Long subLineId; + + @Column(name = "sub_line_name" , columnDefinition="varchar(550) comment '所属子产品线名称'") + @Comment("所属子产品线名称") + @TableField("sub_line_name") + private String subLineName; + + @Column(name = "accurate_grasp_num") + @Comment("精准掌握知识点数量") + private Integer accurateGraspNum; + + @Column(name = "vague_grasp_num") + @Comment("模糊掌握知识点数量") + private Integer vagueGraspNum; + + + @Column(name = "duration") + @Comment("考试时长") + private Integer duration; + + @Column(name = "pass_score") + @Comment("通过考试分数线") + private Integer passScore; + + @Column(name = "note" , columnDefinition="TEXT comment '注意事项'") + private String note; + + /** + * 关联文档idList + * 存储为 JSON 数组: [1, 10, 101] + */ + @TableField(value = "related_document_list" , typeHandler = JacksonTypeHandler.class) + @Column(name = "related_document_list", columnDefinition = "json comment '关联文档列表'") + @JdbcTypeCode(SqlTypes.JSON) + private List relatedDocumentList; + + + @Column(name = "single_choice_num") + @TableField("single_choice_num") + @Comment("单选题数量") + private Integer singleChoiceNum; + + @Column(name = "single_choice_score") + @TableField("single_choice_score") + @Comment("单选题分数") + private Double singleChoiceScore; + + + @Column(name = "multiple_choice_num") + @TableField("multiple_choice_num") + @Comment("多选题数量") + private Integer multipleChoiceNum; + + @Column(name = "multiple_choice_score") + @TableField("multiple_choice_score") + @Comment("多选题分数") + private Double multipleChoiceScore; + + @Column(name = "true_false_num") + @TableField("true_false_num") + @Comment("判断题数量") + private Integer trueFalseNum; + + @Column(name = "true_false_score") + @TableField("true_false_score") + @Comment("判断题分数") + private Double trueFalseScore; + + @Column(name = "total_score") + @Comment("总分") + private Double totalScore; + + @Column(name = "participant_num") + @Comment("参与用户人数") + private Integer participantNum; + + @Column(name = "pass_num") + @Comment("及格人数") + private Integer passNum = 0; + + @Column(name = "need_ai_grading") + @Comment("是否包含需要AI判分的题目") + private Boolean needAiGrading = false; +} diff --git a/src/main/java/com/project/task/domain/entity/TaskUserEntity.java b/src/main/java/com/project/task/domain/entity/TaskUserEntity.java new file mode 100644 index 0000000..d2da481 --- /dev/null +++ b/src/main/java/com/project/task/domain/entity/TaskUserEntity.java @@ -0,0 +1,46 @@ +package com.project.task.domain.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 com.project.base.domain.entity.BaseEntity; +import com.project.task.domain.enums.TaskUserStatusEnum; +import jakarta.persistence.*; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.hibernate.annotations.Comment; + +@Data +@Table(name = "evaluator_task_user" , indexes = {@Index(name = "Idx_parentId", columnList = "parent_id")}) +@Entity +@TableName(value = "evaluator_task_user" , autoResultMap = true) +@EqualsAndHashCode(callSuper = true) +public class TaskUserEntity extends BaseEntity { + @TableId(type = IdType.ASSIGN_ID) + @Id + private Long id; + + @TableField("task_id") + @Column(name = "task_id" , columnDefinition="bigint(20) comment '考试任务id'") + private Long taskId; + + @TableField("user_id") + @Column(name = "user_id" , columnDefinition="varchar(255) comment '用户id'") + private String userId; + + @Column(name = "status") + @Comment("考试状态:0-未考, 1-不通过, 2-已通过") + private Integer status = TaskUserStatusEnum.Not_Start.getValue(); + + @Comment("最近一次考试记录ID") + @Column(name = "last_record_id") + @TableField("last_record_id") + private Long lastRecordId; + + + @Comment("累计考试次数") + @Column(name = "attempt_num") + @TableField("attempt_num") + private Integer attemptNum = 0; +} diff --git a/src/main/java/com/project/task/domain/enums/QuestionTypeEnum.java b/src/main/java/com/project/task/domain/enums/QuestionTypeEnum.java new file mode 100644 index 0000000..de56c77 --- /dev/null +++ b/src/main/java/com/project/task/domain/enums/QuestionTypeEnum.java @@ -0,0 +1,17 @@ +package com.project.task.domain.enums; + + +import com.project.base.domain.enums.HasValueEnum; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +public enum QuestionTypeEnum implements HasValueEnum { + SINGLE_CHOICE(1, "单选题"), // 对应黄色背景 + MULTIPLE_CHOICE(2, "多选题"), // 对应黄色背景 + TRUE_FALSE(3, "判断题"); // 对应绿色背景 + + private final Integer value; + private final String description; +} diff --git a/src/main/java/com/project/task/domain/enums/TaskStatusEnum.java b/src/main/java/com/project/task/domain/enums/TaskStatusEnum.java new file mode 100644 index 0000000..bfba517 --- /dev/null +++ b/src/main/java/com/project/task/domain/enums/TaskStatusEnum.java @@ -0,0 +1,15 @@ +package com.project.task.domain.enums; + +import com.project.base.domain.enums.HasValueEnum; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public enum TaskStatusEnum implements HasValueEnum { + Not_Start("未开考") , + In_Progress("已开考") , + + Cut_Off("已截止"); + @Getter + private final String value; +} diff --git a/src/main/java/com/project/task/domain/enums/TaskUserStatusEnum.java b/src/main/java/com/project/task/domain/enums/TaskUserStatusEnum.java new file mode 100644 index 0000000..6f0a333 --- /dev/null +++ b/src/main/java/com/project/task/domain/enums/TaskUserStatusEnum.java @@ -0,0 +1,18 @@ +package com.project.task.domain.enums; + +import com.project.base.domain.enums.HasValueEnum; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +@Getter + +@RequiredArgsConstructor +public enum TaskUserStatusEnum implements HasValueEnum { + Not_Start(0 , "未参加") , + Fail(1 , "未通过") , + Pass(2 ,"已通过"); + + private final Integer value; + + private final String description; + +} diff --git a/src/main/java/com/project/task/domain/param/TaskParam.java b/src/main/java/com/project/task/domain/param/TaskParam.java new file mode 100644 index 0000000..1aa9b50 --- /dev/null +++ b/src/main/java/com/project/task/domain/param/TaskParam.java @@ -0,0 +1,13 @@ +package com.project.task.domain.param; + +import com.project.base.domain.param.BaseParam; +import lombok.Data; + +@Data +public class TaskParam extends BaseParam { + private String name; + + private Long lineId; + + private Long subLineId; +} diff --git a/src/main/java/com/project/task/domain/service/DeleteTaskDomainService.java b/src/main/java/com/project/task/domain/service/DeleteTaskDomainService.java new file mode 100644 index 0000000..2058e08 --- /dev/null +++ b/src/main/java/com/project/task/domain/service/DeleteTaskDomainService.java @@ -0,0 +1,11 @@ +package com.project.task.domain.service; + +import com.project.base.domain.result.Result; + +import java.util.List; + +public interface DeleteTaskDomainService { + + Result batchDelete(List idList) throws Exception; + +} diff --git a/src/main/java/com/project/task/domain/service/SaveOrUpdateTaskDomainService.java b/src/main/java/com/project/task/domain/service/SaveOrUpdateTaskDomainService.java new file mode 100644 index 0000000..8003bb8 --- /dev/null +++ b/src/main/java/com/project/task/domain/service/SaveOrUpdateTaskDomainService.java @@ -0,0 +1,9 @@ +package com.project.task.domain.service; + +import com.project.base.domain.result.Result; +import com.project.task.domain.dto.TaskDTO; + +public interface SaveOrUpdateTaskDomainService { + Result saveOrUpdate(TaskDTO dto) throws Exception; + +} diff --git a/src/main/java/com/project/task/domain/service/SearchTaskDomainService.java b/src/main/java/com/project/task/domain/service/SearchTaskDomainService.java new file mode 100644 index 0000000..f660739 --- /dev/null +++ b/src/main/java/com/project/task/domain/service/SearchTaskDomainService.java @@ -0,0 +1,12 @@ +package com.project.task.domain.service; + +import com.project.base.domain.result.PageResult; +import com.project.base.domain.result.Result; +import com.project.task.domain.dto.TaskDTO; +import com.project.task.domain.param.TaskParam; + +public interface SearchTaskDomainService { + Result> search(TaskParam param) throws Exception; + + Result getDetail(Long id) throws Exception; +} diff --git a/src/main/java/com/project/task/domain/service/TaskBaseService.java b/src/main/java/com/project/task/domain/service/TaskBaseService.java new file mode 100644 index 0000000..f09a07c --- /dev/null +++ b/src/main/java/com/project/task/domain/service/TaskBaseService.java @@ -0,0 +1,8 @@ +package com.project.task.domain.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.project.task.domain.entity.TaskEntity; + +public interface TaskBaseService extends IService { + +} diff --git a/src/main/java/com/project/task/domain/service/TaskUserBaseService.java b/src/main/java/com/project/task/domain/service/TaskUserBaseService.java new file mode 100644 index 0000000..e6c9d0d --- /dev/null +++ b/src/main/java/com/project/task/domain/service/TaskUserBaseService.java @@ -0,0 +1,7 @@ +package com.project.task.domain.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.project.task.domain.entity.TaskUserEntity; + +public interface TaskUserBaseService extends IService { +} diff --git a/src/main/java/com/project/task/domain/service/impl/DeleteTaskDomainServiceImpl.java b/src/main/java/com/project/task/domain/service/impl/DeleteTaskDomainServiceImpl.java new file mode 100644 index 0000000..7034af9 --- /dev/null +++ b/src/main/java/com/project/task/domain/service/impl/DeleteTaskDomainServiceImpl.java @@ -0,0 +1,31 @@ +package com.project.task.domain.service.impl; + +import cn.hutool.core.date.DateUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.project.base.domain.exception.BusinessErrorException; +import com.project.base.domain.result.Result; +import com.project.task.domain.entity.TaskEntity; +import com.project.task.domain.service.DeleteTaskDomainService; +import com.project.task.domain.service.TaskBaseService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.Date; +import java.util.List; + +@Service +public class DeleteTaskDomainServiceImpl implements DeleteTaskDomainService { + @Autowired + private TaskBaseService taskBaseService; + @Override + public Result batchDelete(List idList) throws Exception { + long count = taskBaseService.count(new LambdaQueryWrapper() + .in(TaskEntity::getId, idList) + .ge(TaskEntity::getStartTime, DateUtil.beginOfDay(new Date()))); + if (count > 0) { + throw new BusinessErrorException("已开考 、 已截止的考试任务不允许删除"); + } + taskBaseService.removeBatchByIds(idList); + return Result.success("删除成功"); + } +} diff --git a/src/main/java/com/project/task/domain/service/impl/SaveOrUpdateTaskDomainServiceImpl.java b/src/main/java/com/project/task/domain/service/impl/SaveOrUpdateTaskDomainServiceImpl.java new file mode 100644 index 0000000..560450c --- /dev/null +++ b/src/main/java/com/project/task/domain/service/impl/SaveOrUpdateTaskDomainServiceImpl.java @@ -0,0 +1,157 @@ +package com.project.task.domain.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.date.DateUnit; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.lang.Validator; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.project.base.domain.exception.BusinessErrorException; +import com.project.base.domain.result.Result; +import com.project.information.domain.entity.ProductLineEntity; +import com.project.information.domain.service.ProductLineBaseService; +import com.project.task.config.ExamScoreRatioConfig; +import com.project.task.domain.dto.TaskDTO; +import com.project.task.domain.entity.TaskEntity; +import com.project.task.domain.entity.TaskUserEntity; +import com.project.task.domain.service.SaveOrUpdateTaskDomainService; +import com.project.task.domain.service.TaskBaseService; +import com.project.task.domain.service.TaskUserBaseService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +@Service +public class SaveOrUpdateTaskDomainServiceImpl implements SaveOrUpdateTaskDomainService { + + @Autowired + private ExamScoreRatioConfig examScoreRatioConfig; + + @Autowired + private ProductLineBaseService productLineBaseService; + + @Autowired + private TaskUserBaseService taskUserBaseService; + + @Autowired + private TaskBaseService taskBaseService; + + + @Override + @Transactional(rollbackFor = Exception.class) + public Result saveOrUpdate(TaskDTO dto) throws Exception { + checkDTO(dto); + // 计算各题型赋分 + // 1. 计算总权重份额 + int totalUnit = dto.getSingleChoiceNum() * examScoreRatioConfig.getSingle() + + dto.getMultipleChoiceNum() * examScoreRatioConfig.getMultiple() + + dto.getTrueFalseNum() * examScoreRatioConfig.getTrueFalse(); + double base = examScoreRatioConfig.getTotalScore() * 1.0 / totalUnit; + // 2. 基础赋值:按比例初步分配并保留2位小数 + dto.setSingleChoiceScore(dto.getSingleChoiceNum() > 0 ? Math.round(base * examScoreRatioConfig.getSingle() * 100) / 100.0 : 0.0); + dto.setMultipleChoiceScore(dto.getMultipleChoiceNum() > 0 ? Math.round(base * examScoreRatioConfig.getMultiple() * 100) / 100.0 : 0.0); + dto.setTrueFalseScore(dto.getTrueFalseNum() > 0 ? Math.round(base * examScoreRatioConfig.getTrueFalse() * 100) / 100.0 : 0.0); + + // 3. 余数平差:从配置中读取总分进行逆向补齐,确保总分 100% 对应配置 + double configTotal = examScoreRatioConfig.getTotalScore().doubleValue(); + + if (dto.getTrueFalseNum() > 0) { + dto.setTrueFalseScore(Math.round((configTotal - dto.getSingleChoiceNum() * dto.getSingleChoiceScore() - dto.getMultipleChoiceNum() * dto.getMultipleChoiceScore()) / dto.getTrueFalseNum() * 100) / 100.0); + } else if (dto.getMultipleChoiceNum() > 0) { + dto.setMultipleChoiceScore(Math.round((configTotal - dto.getSingleChoiceNum() * dto.getSingleChoiceScore()) / dto.getMultipleChoiceNum() * 100) / 100.0); + } else if (dto.getSingleChoiceNum() > 0) { + dto.setSingleChoiceScore(Math.round(configTotal / dto.getSingleChoiceNum() * 100) / 100.0); + } + + dto.setTotalScore(configTotal); + // 补全冗余字段 + ProductLineEntity subProductLine = productLineBaseService.getById(dto.getSubLineId()); + dto.setSubLineName(subProductLine.getName()); + dto.setLineId(subProductLine.getParentId()); + dto.setLineName(subProductLine.getParentName()); + // todo 知识点分簇,预出题 + + // 保存 + TaskEntity saveEntity = dto.toEntity(TaskEntity::new); + taskBaseService.saveOrUpdate(saveEntity); + + // 保存关联表 TaskUserEntity + taskUserBaseService.remove(new LambdaQueryWrapper() + .eq(TaskUserEntity::getTaskId , saveEntity.getId())); + + List taskUserEntityList = new ArrayList<>(); + for (String userId : dto.getParticipantUserIdList()) { + TaskUserEntity taskUserEntity = new TaskUserEntity(); + taskUserEntity.setTaskId(saveEntity.getId()); + taskUserEntity.setUserId(userId); + taskUserEntityList.add(taskUserEntity); + } + taskUserBaseService.saveBatch(taskUserEntityList); + return Result.success(saveEntity.toDTO(TaskDTO::new)); + } + + private void checkDTO(TaskDTO dto) throws Exception { + if (StrUtil.isBlank(dto.getName())) { + throw new BusinessErrorException("考试任务名称不能为空"); + } + if (StrUtil.length(dto.getName()) > 10) { + throw new BusinessErrorException("考试任务名称过长"); + } + if (Objects.isNull(dto.getStartTime())) { + throw new BusinessErrorException("开始时间不能为空"); + } + if (Objects.isNull(dto.getEndTime())) { + throw new BusinessErrorException("截止时间不能为空"); + } + if (DateUtil.between(dto.getStartTime() , dto.getEndTime() , DateUnit.DAY) < 0) { + throw new BusinessErrorException("截止时间不能早于开始时间"); + } + if (Objects.isNull(dto.getSubLineId())) { + throw new BusinessErrorException("关联产品线不能为空"); + } + if (Objects.isNull(dto.getDuration())) { + throw new BusinessErrorException("考试时长不能为空"); + } + if (Objects.isNull(dto.getPassScore())) { + throw new BusinessErrorException("通过考试分数线不能为空"); + } + if (!Validator.isBetween(dto.getPassScore(), 1, 100)) { + throw new BusinessErrorException("通过考试分数线设置错误"); + } + if (StrUtil.isBlank(dto.getNote())) { + throw new BusinessErrorException("注意事项不能为空"); + } + if (Objects.isNull(dto.getSingleChoiceNum())) { + throw new BusinessErrorException("单选题数量不能为空"); + } + if (Objects.isNull(dto.getMultipleChoiceNum())) { + throw new BusinessErrorException("多选题数量不能为空"); + } + if (Objects.isNull(dto.getTrueFalseNum())) { + throw new BusinessErrorException("判断题数量不能为空"); + } + if (!Validator.isBetween(dto.getSingleChoiceNum() + + dto.getMultipleChoiceNum() + + dto.getTrueFalseNum() , 1, 100)) { + throw new BusinessErrorException("题目数量设置错误"); + } + if (CollUtil.isEmpty(dto.getParticipantUserIdList())) { + throw new BusinessErrorException("参与用户不能为空"); + } + if (CollUtil.isEmpty(dto.getRelatedDocumentList())) { + throw new BusinessErrorException("关联文档列表不能为空"); + } + if (Objects.isNull(dto.getAccurateGraspNum())) { + throw new BusinessErrorException("精准掌握知识点数量不能为空"); + } + if (Objects.isNull(dto.getVagueGraspNum())) { + throw new BusinessErrorException("模糊掌握知识点数量不能为空"); + } + } + + +} diff --git a/src/main/java/com/project/task/domain/service/impl/SearchTaskDomainServiceImpl.java b/src/main/java/com/project/task/domain/service/impl/SearchTaskDomainServiceImpl.java new file mode 100644 index 0000000..5e11954 --- /dev/null +++ b/src/main/java/com/project/task/domain/service/impl/SearchTaskDomainServiceImpl.java @@ -0,0 +1,65 @@ +package com.project.task.domain.service.impl; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.project.base.domain.result.PageResult; +import com.project.base.domain.result.Result; +import com.project.base.domain.utils.PageConverter; +import com.project.task.domain.dto.TaskDTO; +import com.project.task.domain.entity.TaskEntity; +import com.project.task.domain.enums.TaskStatusEnum; +import com.project.task.domain.param.TaskParam; +import com.project.task.domain.service.SearchTaskDomainService; +import com.project.task.mapper.TaskMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.Date; +import java.util.Objects; + +@Service +public class SearchTaskDomainServiceImpl implements SearchTaskDomainService { + + @Autowired + private TaskMapper taskMapper; + @Override + public Result> search(TaskParam param) throws Exception { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + if (StrUtil.isNotBlank(param.getName())) { + queryWrapper.like(TaskEntity::getName , param.getName()); + } + if (Objects.nonNull(param.getLineId())) { + queryWrapper.eq(TaskEntity::getLineId , param.getLineId()); + } + if (Objects.nonNull(param.getSubLineId())) { + queryWrapper.eq(TaskEntity::getSubLineId , param.getSubLineId()); + } + queryWrapper.orderByDesc(TaskEntity::getId); + IPage taskEntityPage = taskMapper.selectPage( + PageConverter.toMpPage(param), + queryWrapper); + IPage taskDTOIPage = taskEntityPage.convert(this::buildDTO); + return Result.page(taskDTOIPage); + } + + private TaskDTO buildDTO(TaskEntity entity) { + TaskDTO dto = entity.toDTO(TaskDTO::new); + // 开始时间晚于当前 + if (dto.getStartTime().after(new Date())) { + dto.setStatusText(TaskStatusEnum.Not_Start.getValue()); + } else if (DateUtil.isIn(new Date() , dto.getStartTime() , dto.getEndTime())) { + dto.setStatusText(TaskStatusEnum.In_Progress.getValue()); + } else { + dto.setStatusText(TaskStatusEnum.Cut_Off.getValue()); + } + return dto; + } + + @Override + public Result getDetail(Long id) throws Exception { + TaskEntity taskEntity = taskMapper.selectById(id); + return Result.success(buildDTO(taskEntity)); + } +} diff --git a/src/main/java/com/project/task/domain/service/impl/TaskBaseServiceImpl.java b/src/main/java/com/project/task/domain/service/impl/TaskBaseServiceImpl.java new file mode 100644 index 0000000..74b0bda --- /dev/null +++ b/src/main/java/com/project/task/domain/service/impl/TaskBaseServiceImpl.java @@ -0,0 +1,12 @@ +package com.project.task.domain.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.project.task.domain.entity.TaskEntity; +import com.project.task.domain.service.TaskBaseService; +import com.project.task.mapper.TaskMapper; +import org.springframework.stereotype.Service; + + +@Service +public class TaskBaseServiceImpl extends ServiceImpl implements TaskBaseService { +} diff --git a/src/main/java/com/project/task/domain/service/impl/TaskUserBaseServiceImpl.java b/src/main/java/com/project/task/domain/service/impl/TaskUserBaseServiceImpl.java new file mode 100644 index 0000000..1529274 --- /dev/null +++ b/src/main/java/com/project/task/domain/service/impl/TaskUserBaseServiceImpl.java @@ -0,0 +1,11 @@ +package com.project.task.domain.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.project.task.domain.entity.TaskUserEntity; +import com.project.task.domain.service.TaskUserBaseService; +import com.project.task.mapper.TaskUserMapper; +import org.springframework.stereotype.Service; + +@Service +public class TaskUserBaseServiceImpl extends ServiceImpl implements TaskUserBaseService { +} diff --git a/src/main/java/com/project/task/mapper/TaskMapper.java b/src/main/java/com/project/task/mapper/TaskMapper.java new file mode 100644 index 0000000..a78267d --- /dev/null +++ b/src/main/java/com/project/task/mapper/TaskMapper.java @@ -0,0 +1,9 @@ +package com.project.task.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.project.task.domain.entity.TaskEntity; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface TaskMapper extends BaseMapper { +} diff --git a/src/main/java/com/project/task/mapper/TaskUserMapper.java b/src/main/java/com/project/task/mapper/TaskUserMapper.java new file mode 100644 index 0000000..115935e --- /dev/null +++ b/src/main/java/com/project/task/mapper/TaskUserMapper.java @@ -0,0 +1,9 @@ +package com.project.task.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.project.task.domain.entity.TaskUserEntity; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface TaskUserMapper extends BaseMapper { +}