refactor: 重构评估模块为答题模块,整合到问卷记录服务
主要变更: - 删除 assessment 模块,原有功能整合到 questionnaire-record - 新增 answer 模块处理答题记录 - QuestionnaireRecordServiceImpl 扩展测评执行、评分、统计功能 - 更新枚举类状态定义(1-待测评 2-测评中 3-已完成 4-已过期 5-已取消) - 消费记录模块新增明细相关接口 Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
bbcf68bdb8
commit
dc65ef8d24
@ -0,0 +1,112 @@
|
|||||||
|
package cn.iocoder.yudao.module.prison.controller.admin.answer;
|
||||||
|
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
|
||||||
|
import jakarta.validation.constraints.*;
|
||||||
|
import jakarta.validation.*;
|
||||||
|
import jakarta.servlet.http.*;
|
||||||
|
import java.util.*;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||||
|
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||||
|
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
|
||||||
|
import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.module.prison.controller.admin.answer.vo.*;
|
||||||
|
import cn.iocoder.yudao.module.prison.dal.dataobject.answer.AnswerDO;
|
||||||
|
import cn.iocoder.yudao.module.prison.service.answer.AnswerService;
|
||||||
|
|
||||||
|
@Tag(name = "管理后台 - 问卷答题记录")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/prison/answer")
|
||||||
|
@Validated
|
||||||
|
public class PrisonAnswerController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private AnswerService answerService;
|
||||||
|
|
||||||
|
@PostMapping("/create")
|
||||||
|
@Operation(summary = "创建答题记录")
|
||||||
|
@PreAuthorize("@ss.hasPermission('prison:answer:create')")
|
||||||
|
public CommonResult<Long> createAnswer(@Valid @RequestBody AnswerSaveReqVO createReqVO) {
|
||||||
|
return success(answerService.createAnswer(createReqVO));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/update")
|
||||||
|
@Operation(summary = "更新答题记录")
|
||||||
|
@PreAuthorize("@ss.hasPermission('prison:answer:update')")
|
||||||
|
public CommonResult<Boolean> updateAnswer(@Valid @RequestBody AnswerSaveReqVO updateReqVO) {
|
||||||
|
answerService.updateAnswer(updateReqVO);
|
||||||
|
return success(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping("/delete")
|
||||||
|
@Operation(summary = "删除答题记录")
|
||||||
|
@Parameter(name = "id", description = "编号", required = true)
|
||||||
|
@PreAuthorize("@ss.hasPermission('prison:answer:delete')")
|
||||||
|
public CommonResult<Boolean> deleteAnswer(@NotNull(message = "编号不能为空") @RequestParam("id") Long id) {
|
||||||
|
answerService.deleteAnswer(id);
|
||||||
|
return success(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/delete-list")
|
||||||
|
@Operation(summary = "批量删除答题记录")
|
||||||
|
@PreAuthorize("@ss.hasPermission('prison:answer:delete')")
|
||||||
|
public CommonResult<Boolean> deleteAnswerList(@NotEmpty(message = "编号列表不能为空") @RequestBody List<Long> ids) {
|
||||||
|
answerService.deleteAnswerListByIds(ids);
|
||||||
|
return success(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/get")
|
||||||
|
@Operation(summary = "获得答题记录")
|
||||||
|
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||||
|
@PreAuthorize("@ss.hasPermission('prison:answer:query')")
|
||||||
|
public CommonResult<AnswerRespVO> getAnswer(@NotNull(message = "编号不能为空") @RequestParam("id") Long id) {
|
||||||
|
AnswerDO answer = answerService.getAnswer(id);
|
||||||
|
return success(BeanUtils.toBean(answer, AnswerRespVO.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/page")
|
||||||
|
@Operation(summary = "获得答题记录分页")
|
||||||
|
@PreAuthorize("@ss.hasPermission('prison:answer:query')")
|
||||||
|
public CommonResult<PageResult<AnswerRespVO>> getAnswerPage(@Valid AnswerPageReqVO pageReqVO) {
|
||||||
|
PageResult<AnswerDO> pageResult = answerService.getAnswerPage(pageReqVO);
|
||||||
|
return success(BeanUtils.toBean(pageResult, AnswerRespVO.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/list-by-assessment-record")
|
||||||
|
@Operation(summary = "根据测评记录ID查询答题列表")
|
||||||
|
@PreAuthorize("@ss.hasPermission('prison:answer:query')")
|
||||||
|
public CommonResult<List<AnswerRespVO>> getAnswersByAssessmentRecordId(
|
||||||
|
@NotNull(message = "测评记录ID不能为空") @RequestParam("assessmentRecordId") Long assessmentRecordId) {
|
||||||
|
List<AnswerDO> list = answerService.getAnswersByAssessmentRecordId(assessmentRecordId);
|
||||||
|
return success(BeanUtils.toBean(list, AnswerRespVO.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/export-excel")
|
||||||
|
@Operation(summary = "导出答题记录 Excel")
|
||||||
|
@PreAuthorize("@ss.hasPermission('prison:answer:export')")
|
||||||
|
@ApiAccessLog(operateType = EXPORT)
|
||||||
|
public void exportAnswerExcel(@Valid AnswerPageReqVO pageReqVO,
|
||||||
|
HttpServletResponse response) throws IOException {
|
||||||
|
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
|
||||||
|
List<AnswerDO> list = answerService.getAnswerPage(pageReqVO).getList();
|
||||||
|
// 导出 Excel
|
||||||
|
ExcelUtils.write(response, "答题记录.xls", "数据", AnswerRespVO.class,
|
||||||
|
BeanUtils.toBean(list, AnswerRespVO.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,31 @@
|
|||||||
|
package cn.iocoder.yudao.module.prison.controller.admin.answer.vo;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.*;
|
||||||
|
import java.util.*;
|
||||||
|
import jakarta.validation.constraints.*;
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||||
|
|
||||||
|
@Schema(description = "管理后台 - 问卷答题记录分页 Request VO")
|
||||||
|
@Data
|
||||||
|
public class AnswerPageReqVO extends PageParam {
|
||||||
|
|
||||||
|
@Schema(description = "测评记录ID")
|
||||||
|
private Long assessmentRecordId;
|
||||||
|
|
||||||
|
@Schema(description = "问题ID")
|
||||||
|
private Long questionId;
|
||||||
|
|
||||||
|
@Schema(description = "问卷ID")
|
||||||
|
private Long questionnaireId;
|
||||||
|
|
||||||
|
@Schema(description = "罪犯ID")
|
||||||
|
private Long prisonerId;
|
||||||
|
|
||||||
|
@Schema(description = "问题类型:1-单选 2-多选 3-填空 4-评分 5-日期 6-数字")
|
||||||
|
private Integer questionType;
|
||||||
|
|
||||||
|
@Schema(description = "创建时间")
|
||||||
|
private Date[] createTime;
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,54 @@
|
|||||||
|
package cn.iocoder.yudao.module.prison.controller.admin.answer.vo;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.*;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
@Schema(description = "管理后台 - 问卷答题记录 Response VO")
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class AnswerRespVO {
|
||||||
|
|
||||||
|
@Schema(description = "答题记录ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Schema(description = "测评记录ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||||
|
private Long assessmentRecordId;
|
||||||
|
|
||||||
|
@Schema(description = "问题ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||||
|
private Long questionId;
|
||||||
|
|
||||||
|
@Schema(description = "问卷ID", example = "1024")
|
||||||
|
private Long questionnaireId;
|
||||||
|
|
||||||
|
@Schema(description = "罪犯ID", example = "1024")
|
||||||
|
private Long prisonerId;
|
||||||
|
|
||||||
|
@Schema(description = "问题类型:1-单选 2-多选 3-填空 4-评分 5-日期 6-数字", example = "1")
|
||||||
|
private Integer questionType;
|
||||||
|
|
||||||
|
@Schema(description = "答案内容(填空题、评分题等)")
|
||||||
|
private String answerText;
|
||||||
|
|
||||||
|
@Schema(description = "选项ID列表(JSON数组,如 [1,2,3])")
|
||||||
|
private String optionIds;
|
||||||
|
|
||||||
|
@Schema(description = "得分")
|
||||||
|
private BigDecimal score;
|
||||||
|
|
||||||
|
@Schema(description = "是否正确:null-未评分 false-错误 true-正确")
|
||||||
|
private Boolean isCorrect;
|
||||||
|
|
||||||
|
@Schema(description = "答题时间(秒)")
|
||||||
|
private Integer duration;
|
||||||
|
|
||||||
|
@Schema(description = "创建者", example = "芋艿")
|
||||||
|
private String creator;
|
||||||
|
|
||||||
|
@Schema(description = "创建时间")
|
||||||
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,49 @@
|
|||||||
|
package cn.iocoder.yudao.module.prison.controller.admin.answer.vo;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.*;
|
||||||
|
import jakarta.validation.constraints.*;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
@Schema(description = "管理后台 - 问卷答题记录新增/修改 Request VO")
|
||||||
|
@Data
|
||||||
|
public class AnswerSaveReqVO {
|
||||||
|
|
||||||
|
@Schema(description = "答题记录ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "26045")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Schema(description = "测评记录ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||||
|
@NotNull(message = "测评记录ID不能为空")
|
||||||
|
private Long assessmentRecordId;
|
||||||
|
|
||||||
|
@Schema(description = "问题ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||||
|
@NotNull(message = "问题ID不能为空")
|
||||||
|
private Long questionId;
|
||||||
|
|
||||||
|
@Schema(description = "问卷ID")
|
||||||
|
private Long questionnaireId;
|
||||||
|
|
||||||
|
@Schema(description = "罪犯ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||||
|
@NotNull(message = "罪犯ID不能为空")
|
||||||
|
private Long prisonerId;
|
||||||
|
|
||||||
|
@Schema(description = "问题类型:1-单选 2-多选 3-填空 4-评分 5-日期 6-数字", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||||
|
@NotNull(message = "问题类型不能为空")
|
||||||
|
private Integer questionType;
|
||||||
|
|
||||||
|
@Schema(description = "答案内容(填空题、评分题等)")
|
||||||
|
private String answerText;
|
||||||
|
|
||||||
|
@Schema(description = "选项ID列表(JSON数组,如 [1,2,3])")
|
||||||
|
private String optionIds;
|
||||||
|
|
||||||
|
@Schema(description = "得分")
|
||||||
|
private BigDecimal score;
|
||||||
|
|
||||||
|
@Schema(description = "是否正确:null-未评分 false-错误 true-正确")
|
||||||
|
private Boolean isCorrect;
|
||||||
|
|
||||||
|
@Schema(description = "答题时间(秒)")
|
||||||
|
private Integer duration;
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,145 +0,0 @@
|
|||||||
package cn.iocoder.yudao.module.prison.controller.admin.assessment;
|
|
||||||
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
|
||||||
import jakarta.annotation.Resource;
|
|
||||||
import org.springframework.validation.annotation.Validated;
|
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
|
||||||
import io.swagger.v3.oas.annotations.Parameter;
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
|
||||||
|
|
||||||
import jakarta.validation.constraints.*;
|
|
||||||
import jakarta.validation.*;
|
|
||||||
import jakarta.servlet.http.*;
|
|
||||||
import java.util.*;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
|
||||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
|
||||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
|
|
||||||
import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.module.prison.controller.admin.assessment.vo.*;
|
|
||||||
import cn.iocoder.yudao.module.prison.dal.dataobject.assessment.AssessmentAnswerDO;
|
|
||||||
import cn.iocoder.yudao.module.prison.service.assessment.AssessmentAnswerService;
|
|
||||||
|
|
||||||
@Tag(name = "管理后台 - 答卷详情")
|
|
||||||
@RestController
|
|
||||||
@RequestMapping("/prison/assessment-answer")
|
|
||||||
@Validated
|
|
||||||
public class AssessmentAnswerController {
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private AssessmentAnswerService assessmentAnswerService;
|
|
||||||
|
|
||||||
@PostMapping("/create")
|
|
||||||
@Operation(summary = "创建答卷")
|
|
||||||
@PreAuthorize("@ss.hasPermission('prison:assessment-answer:create')")
|
|
||||||
public CommonResult<Long> createAssessmentAnswer(@Valid @RequestBody AssessmentAnswerSaveReqVO createReqVO) {
|
|
||||||
return success(assessmentAnswerService.createAssessmentAnswer(createReqVO));
|
|
||||||
}
|
|
||||||
|
|
||||||
@PutMapping("/update")
|
|
||||||
@Operation(summary = "更新答卷")
|
|
||||||
@PreAuthorize("@ss.hasPermission('prison:assessment-answer:update')")
|
|
||||||
public CommonResult<Boolean> updateAssessmentAnswer(@Valid @RequestBody AssessmentAnswerSaveReqVO updateReqVO) {
|
|
||||||
assessmentAnswerService.updateAssessmentAnswer(updateReqVO);
|
|
||||||
return success(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@DeleteMapping("/delete")
|
|
||||||
@Operation(summary = "删除答卷")
|
|
||||||
@Parameter(name = "id", description = "编号", required = true)
|
|
||||||
@PreAuthorize("@ss.hasPermission('prison:assessment-answer:delete')")
|
|
||||||
public CommonResult<Boolean> deleteAssessmentAnswer(@NotNull(message = "编号不能为空") @RequestParam("id") Long id) {
|
|
||||||
assessmentAnswerService.deleteAssessmentAnswer(id);
|
|
||||||
return success(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@DeleteMapping("/delete-list")
|
|
||||||
@Operation(summary = "批量删除答卷")
|
|
||||||
@Parameter(name = "ids", description = "编号列表", required = true)
|
|
||||||
@PreAuthorize("@ss.hasPermission('prison:assessment-answer:delete')")
|
|
||||||
public CommonResult<Boolean> deleteAssessmentAnswerList(@NotEmpty(message = "编号列表不能为空") @RequestParam("ids") List<Long> ids) {
|
|
||||||
assessmentAnswerService.deleteAssessmentAnswerListByIds(ids);
|
|
||||||
return success(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/get")
|
|
||||||
@Operation(summary = "获得答卷")
|
|
||||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
|
||||||
@PreAuthorize("@ss.hasPermission('prison:assessment-answer:query')")
|
|
||||||
public CommonResult<AssessmentAnswerRespVO> getAssessmentAnswer(@RequestParam("id") Long id) {
|
|
||||||
AssessmentAnswerDO assessmentAnswer = assessmentAnswerService.getAssessmentAnswer(id);
|
|
||||||
return success(BeanUtils.toBean(assessmentAnswer, AssessmentAnswerRespVO.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/page")
|
|
||||||
@Operation(summary = "获得答卷分页")
|
|
||||||
@PreAuthorize("@ss.hasPermission('prison:assessment-answer:query')")
|
|
||||||
public CommonResult<PageResult<AssessmentAnswerRespVO>> getAssessmentAnswerPage(@Valid AssessmentAnswerPageReqVO pageReqVO) {
|
|
||||||
PageResult<AssessmentAnswerDO> pageResult = assessmentAnswerService.getAssessmentAnswerPage(pageReqVO);
|
|
||||||
return success(BeanUtils.toBean(pageResult, AssessmentAnswerRespVO.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/start")
|
|
||||||
@Operation(summary = "开始答题")
|
|
||||||
@PreAuthorize("@ss.hasPermission('prison:assessment-answer:create')")
|
|
||||||
public CommonResult<Long> startAnswer(@RequestParam("assessmentRecordId") Long assessmentRecordId,
|
|
||||||
@RequestParam("prisonerId") Long prisonerId) {
|
|
||||||
return success(assessmentAnswerService.startAnswer(assessmentRecordId, prisonerId));
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/submit")
|
|
||||||
@Operation(summary = "提交答卷")
|
|
||||||
@PreAuthorize("@ss.hasPermission('prison:assessment-answer:update')")
|
|
||||||
public CommonResult<Boolean> submitAnswer(@Valid @RequestBody AssessmentAnswerSubmitReqVO submitReqVO) {
|
|
||||||
assessmentAnswerService.submitAnswer(submitReqVO);
|
|
||||||
return success(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/pending-score-page")
|
|
||||||
@Operation(summary = "获取待评分答卷列表")
|
|
||||||
@PreAuthorize("@ss.hasPermission('prison:assessment-answer:query')")
|
|
||||||
public CommonResult<PageResult<AssessmentAnswerRespVO>> getPendingScorePage(@Valid AssessmentAnswerPageReqVO pageReqVO) {
|
|
||||||
PageResult<AssessmentAnswerDO> pageResult = assessmentAnswerService.getPendingScorePage(pageReqVO);
|
|
||||||
return success(BeanUtils.toBean(pageResult, AssessmentAnswerRespVO.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/manual-score")
|
|
||||||
@Operation(summary = "人工评分")
|
|
||||||
@PreAuthorize("@ss.hasPermission('prison:assessment-answer:update')")
|
|
||||||
public CommonResult<Boolean> manualScore(@Valid @RequestBody AssessmentAnswerManualScoreReqVO scoreReqVO) {
|
|
||||||
assessmentAnswerService.manualScore(scoreReqVO);
|
|
||||||
return success(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/get-by-prisoner")
|
|
||||||
@Operation(summary = "根据囚犯ID和测评记录ID获取答卷")
|
|
||||||
@PreAuthorize("@ss.hasPermission('prison:assessment-answer:query')")
|
|
||||||
public CommonResult<AssessmentAnswerRespVO> getByPrisonerAndRecord(
|
|
||||||
@RequestParam("prisonerId") Long prisonerId,
|
|
||||||
@RequestParam("assessmentRecordId") Long assessmentRecordId) {
|
|
||||||
AssessmentAnswerDO assessmentAnswer = assessmentAnswerService.getByPrisonerAndRecord(prisonerId, assessmentRecordId);
|
|
||||||
return success(BeanUtils.toBean(assessmentAnswer, AssessmentAnswerRespVO.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/export-excel")
|
|
||||||
@Operation(summary = "导出答卷 Excel")
|
|
||||||
@PreAuthorize("@ss.hasPermission('prison:assessment-answer:export')")
|
|
||||||
@ApiAccessLog(operateType = EXPORT)
|
|
||||||
public void exportAssessmentAnswerExcel(@Valid AssessmentAnswerPageReqVO pageReqVO,
|
|
||||||
HttpServletResponse response) throws IOException {
|
|
||||||
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
|
|
||||||
List<AssessmentAnswerDO> list = assessmentAnswerService.getAssessmentAnswerPage(pageReqVO).getList();
|
|
||||||
ExcelUtils.write(response, "答卷详情.xls", "数据", AssessmentAnswerRespVO.class,
|
|
||||||
BeanUtils.toBean(list, AssessmentAnswerRespVO.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,134 +0,0 @@
|
|||||||
package cn.iocoder.yudao.module.prison.controller.admin.assessment;
|
|
||||||
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
|
||||||
import jakarta.annotation.Resource;
|
|
||||||
import org.springframework.validation.annotation.Validated;
|
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
|
||||||
import io.swagger.v3.oas.annotations.Parameter;
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
|
||||||
|
|
||||||
import jakarta.validation.constraints.*;
|
|
||||||
import jakarta.validation.*;
|
|
||||||
import jakarta.servlet.http.*;
|
|
||||||
import java.util.*;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
|
||||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
|
||||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
|
|
||||||
import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.module.prison.controller.admin.assessment.vo.*;
|
|
||||||
import cn.iocoder.yudao.module.prison.dal.dataobject.assessment.AssessmentRecordDO;
|
|
||||||
import cn.iocoder.yudao.module.prison.service.assessment.AssessmentRecordService;
|
|
||||||
|
|
||||||
@Tag(name = "管理后台 - 测评记录")
|
|
||||||
@RestController
|
|
||||||
@RequestMapping("/prison/assessment-record")
|
|
||||||
@Validated
|
|
||||||
public class AssessmentRecordController {
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private AssessmentRecordService assessmentRecordService;
|
|
||||||
|
|
||||||
@PostMapping("/create")
|
|
||||||
@Operation(summary = "创建测评记录")
|
|
||||||
@PreAuthorize("@ss.hasPermission('prison:assessment-record:create')")
|
|
||||||
public CommonResult<Long> createAssessmentRecord(@Valid @RequestBody AssessmentRecordSaveReqVO createReqVO) {
|
|
||||||
return success(assessmentRecordService.createAssessmentRecord(createReqVO));
|
|
||||||
}
|
|
||||||
|
|
||||||
@PutMapping("/update")
|
|
||||||
@Operation(summary = "更新测评记录")
|
|
||||||
@PreAuthorize("@ss.hasPermission('prison:assessment-record:update')")
|
|
||||||
public CommonResult<Boolean> updateAssessmentRecord(@Valid @RequestBody AssessmentRecordSaveReqVO updateReqVO) {
|
|
||||||
assessmentRecordService.updateAssessmentRecord(updateReqVO);
|
|
||||||
return success(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@DeleteMapping("/delete")
|
|
||||||
@Operation(summary = "删除测评记录")
|
|
||||||
@Parameter(name = "id", description = "编号", required = true)
|
|
||||||
@PreAuthorize("@ss.hasPermission('prison:assessment-record:delete')")
|
|
||||||
public CommonResult<Boolean> deleteAssessmentRecord(@NotNull(message = "编号不能为空") @RequestParam("id") Long id) {
|
|
||||||
assessmentRecordService.deleteAssessmentRecord(id);
|
|
||||||
return success(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@DeleteMapping("/delete-list")
|
|
||||||
@Operation(summary = "批量删除测评记录")
|
|
||||||
@Parameter(name = "ids", description = "编号列表", required = true)
|
|
||||||
@PreAuthorize("@ss.hasPermission('prison:assessment-record:delete')")
|
|
||||||
public CommonResult<Boolean> deleteAssessmentRecordList(@NotEmpty(message = "编号列表不能为空") @RequestParam("ids") List<Long> ids) {
|
|
||||||
assessmentRecordService.deleteAssessmentRecordListByIds(ids);
|
|
||||||
return success(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/get")
|
|
||||||
@Operation(summary = "获得测评记录")
|
|
||||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
|
||||||
@PreAuthorize("@ss.hasPermission('prison:assessment-record:query')")
|
|
||||||
public CommonResult<AssessmentRecordRespVO> getAssessmentRecord(@RequestParam("id") Long id) {
|
|
||||||
AssessmentRecordDO assessmentRecord = assessmentRecordService.getAssessmentRecord(id);
|
|
||||||
return success(BeanUtils.toBean(assessmentRecord, AssessmentRecordRespVO.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/page")
|
|
||||||
@Operation(summary = "获得测评记录分页")
|
|
||||||
@PreAuthorize("@ss.hasPermission('prison:assessment-record:query')")
|
|
||||||
public CommonResult<PageResult<AssessmentRecordRespVO>> getAssessmentRecordPage(@Valid AssessmentRecordPageReqVO pageReqVO) {
|
|
||||||
PageResult<AssessmentRecordDO> pageResult = assessmentRecordService.getAssessmentRecordPage(pageReqVO);
|
|
||||||
return success(BeanUtils.toBean(pageResult, AssessmentRecordRespVO.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/initiate")
|
|
||||||
@Operation(summary = "发起测评")
|
|
||||||
@PreAuthorize("@ss.hasPermission('prison:assessment-record:create')")
|
|
||||||
public CommonResult<Long> initiateAssessment(@Valid @RequestBody AssessmentRecordSaveReqVO reqVO) {
|
|
||||||
return success(assessmentRecordService.initiateAssessment(reqVO));
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/cancel")
|
|
||||||
@Operation(summary = "取消测评")
|
|
||||||
@PreAuthorize("@ss.hasPermission('prison:assessment-record:update')")
|
|
||||||
public CommonResult<Boolean> cancelAssessment(@RequestParam("id") Long id) {
|
|
||||||
assessmentRecordService.cancelAssessment(id);
|
|
||||||
return success(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/start")
|
|
||||||
@Operation(summary = "启动测评")
|
|
||||||
@PreAuthorize("@ss.hasPermission('prison:assessment-record:update')")
|
|
||||||
public CommonResult<Boolean> startAssessment(@RequestParam("id") Long id) {
|
|
||||||
assessmentRecordService.startAssessment(id);
|
|
||||||
return success(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/finish")
|
|
||||||
@Operation(summary = "结束测评")
|
|
||||||
@PreAuthorize("@ss.hasPermission('prison:assessment-record:update')")
|
|
||||||
public CommonResult<Boolean> finishAssessment(@RequestParam("id") Long id) {
|
|
||||||
assessmentRecordService.finishAssessment(id);
|
|
||||||
return success(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/export-excel")
|
|
||||||
@Operation(summary = "导出测评记录 Excel")
|
|
||||||
@PreAuthorize("@ss.hasPermission('prison:assessment-record:export')")
|
|
||||||
@ApiAccessLog(operateType = EXPORT)
|
|
||||||
public void exportAssessmentRecordExcel(@Valid AssessmentRecordPageReqVO pageReqVO,
|
|
||||||
HttpServletResponse response) throws IOException {
|
|
||||||
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
|
|
||||||
List<AssessmentRecordDO> list = assessmentRecordService.getAssessmentRecordPage(pageReqVO).getList();
|
|
||||||
ExcelUtils.write(response, "测评记录.xls", "数据", AssessmentRecordRespVO.class,
|
|
||||||
BeanUtils.toBean(list, AssessmentRecordRespVO.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,143 +0,0 @@
|
|||||||
package cn.iocoder.yudao.module.prison.controller.admin.assessment;
|
|
||||||
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
|
||||||
import jakarta.annotation.Resource;
|
|
||||||
import org.springframework.validation.annotation.Validated;
|
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
|
||||||
import io.swagger.v3.oas.annotations.Parameter;
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
|
||||||
|
|
||||||
import jakarta.validation.constraints.*;
|
|
||||||
import jakarta.validation.*;
|
|
||||||
import jakarta.servlet.http.*;
|
|
||||||
import java.util.*;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
|
||||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
|
||||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
|
|
||||||
import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.module.prison.controller.admin.assessment.vo.*;
|
|
||||||
import cn.iocoder.yudao.module.prison.dal.dataobject.assessment.AssessmentResultDO;
|
|
||||||
import cn.iocoder.yudao.module.prison.service.assessment.AssessmentResultService;
|
|
||||||
|
|
||||||
@Tag(name = "管理后台 - 测评结果")
|
|
||||||
@RestController
|
|
||||||
@RequestMapping("/prison/assessment-result")
|
|
||||||
@Validated
|
|
||||||
public class AssessmentResultController {
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private AssessmentResultService assessmentResultService;
|
|
||||||
|
|
||||||
@PostMapping("/create")
|
|
||||||
@Operation(summary = "创建测评结果")
|
|
||||||
@PreAuthorize("@ss.hasPermission('prison:assessment-result:create')")
|
|
||||||
public CommonResult<Long> createAssessmentResult(@Valid @RequestBody AssessmentResultSaveReqVO createReqVO) {
|
|
||||||
return success(assessmentResultService.createAssessmentResult(createReqVO));
|
|
||||||
}
|
|
||||||
|
|
||||||
@PutMapping("/update")
|
|
||||||
@Operation(summary = "更新测评结果")
|
|
||||||
@PreAuthorize("@ss.hasPermission('prison:assessment-result:update')")
|
|
||||||
public CommonResult<Boolean> updateAssessmentResult(@Valid @RequestBody AssessmentResultSaveReqVO updateReqVO) {
|
|
||||||
assessmentResultService.updateAssessmentResult(updateReqVO);
|
|
||||||
return success(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@DeleteMapping("/delete")
|
|
||||||
@Operation(summary = "删除测评结果")
|
|
||||||
@Parameter(name = "id", description = "编号", required = true)
|
|
||||||
@PreAuthorize("@ss.hasPermission('prison:assessment-result:delete')")
|
|
||||||
public CommonResult<Boolean> deleteAssessmentResult(@NotNull(message = "编号不能为空") @RequestParam("id") Long id) {
|
|
||||||
assessmentResultService.deleteAssessmentResult(id);
|
|
||||||
return success(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@DeleteMapping("/delete-list")
|
|
||||||
@Operation(summary = "批量删除测评结果")
|
|
||||||
@Parameter(name = "ids", description = "编号列表", required = true)
|
|
||||||
@PreAuthorize("@ss.hasPermission('prison:assessment-result:delete')")
|
|
||||||
public CommonResult<Boolean> deleteAssessmentResultList(@NotEmpty(message = "编号列表不能为空") @RequestParam("ids") List<Long> ids) {
|
|
||||||
assessmentResultService.deleteAssessmentResultListByIds(ids);
|
|
||||||
return success(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/get")
|
|
||||||
@Operation(summary = "获得测评结果")
|
|
||||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
|
||||||
@PreAuthorize("@ss.hasPermission('prison:assessment-result:query')")
|
|
||||||
public CommonResult<AssessmentResultRespVO> getAssessmentResult(@RequestParam("id") Long id) {
|
|
||||||
AssessmentResultDO assessmentResult = assessmentResultService.getAssessmentResult(id);
|
|
||||||
return success(BeanUtils.toBean(assessmentResult, AssessmentResultRespVO.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/page")
|
|
||||||
@Operation(summary = "获得测评结果分页")
|
|
||||||
@PreAuthorize("@ss.hasPermission('prison:assessment-result:query')")
|
|
||||||
public CommonResult<PageResult<AssessmentResultRespVO>> getAssessmentResultPage(@Valid AssessmentResultPageReqVO pageReqVO) {
|
|
||||||
PageResult<AssessmentResultDO> pageResult = assessmentResultService.getAssessmentResultPage(pageReqVO);
|
|
||||||
return success(BeanUtils.toBean(pageResult, AssessmentResultRespVO.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/list-by-answer")
|
|
||||||
@Operation(summary = "根据答卷ID获取所有结果")
|
|
||||||
@PreAuthorize("@ss.hasPermission('prison:assessment-result:query')")
|
|
||||||
public CommonResult<List<AssessmentResultRespVO>> getResultsByAnswerId(@RequestParam("answerId") Long answerId) {
|
|
||||||
List<AssessmentResultDO> results = assessmentResultService.getResultsByAnswerId(answerId);
|
|
||||||
return success(BeanUtils.toBean(results, AssessmentResultRespVO.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/list-by-assessment-record")
|
|
||||||
@Operation(summary = "根据测评记录ID获取所有结果")
|
|
||||||
@PreAuthorize("@ss.hasPermission('prison:assessment-result:query')")
|
|
||||||
public CommonResult<List<AssessmentResultRespVO>> getResultsByAssessmentRecordId(@RequestParam("assessmentRecordId") Long assessmentRecordId) {
|
|
||||||
List<AssessmentResultDO> results = assessmentResultService.getResultsByAssessmentRecordId(assessmentRecordId);
|
|
||||||
return success(BeanUtils.toBean(results, AssessmentResultRespVO.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/need-manual-review")
|
|
||||||
@Operation(summary = "获取需要人工评阅的结果列表")
|
|
||||||
@PreAuthorize("@ss.hasPermission('prison:assessment-result:query')")
|
|
||||||
public CommonResult<List<AssessmentResultRespVO>> getNeedManualReviewList() {
|
|
||||||
List<AssessmentResultDO> results = assessmentResultService.getNeedManualReviewList();
|
|
||||||
return success(BeanUtils.toBean(results, AssessmentResultRespVO.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/manual-review")
|
|
||||||
@Operation(summary = "人工评阅")
|
|
||||||
@PreAuthorize("@ss.hasPermission('prison:assessment-result:update')")
|
|
||||||
public CommonResult<Boolean> manualReview(@Valid @RequestBody AssessmentResultManualReviewReqVO reviewReqVO) {
|
|
||||||
assessmentResultService.manualReview(reviewReqVO);
|
|
||||||
return success(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/auto-score")
|
|
||||||
@Operation(summary = "自动评分")
|
|
||||||
@PreAuthorize("@ss.hasPermission('prison:assessment-result:update')")
|
|
||||||
public CommonResult<Boolean> autoScore(@RequestParam("answerId") Long answerId) {
|
|
||||||
assessmentResultService.autoScore(answerId);
|
|
||||||
return success(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/export-excel")
|
|
||||||
@Operation(summary = "导出测评结果 Excel")
|
|
||||||
@PreAuthorize("@ss.hasPermission('prison:assessment-result:export')")
|
|
||||||
@ApiAccessLog(operateType = EXPORT)
|
|
||||||
public void exportAssessmentResultExcel(@Valid AssessmentResultPageReqVO pageReqVO,
|
|
||||||
HttpServletResponse response) throws IOException {
|
|
||||||
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
|
|
||||||
List<AssessmentResultDO> list = assessmentResultService.getAssessmentResultPage(pageReqVO).getList();
|
|
||||||
ExcelUtils.write(response, "测评结果.xls", "数据", AssessmentResultRespVO.class,
|
|
||||||
BeanUtils.toBean(list, AssessmentResultRespVO.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,95 +0,0 @@
|
|||||||
package cn.iocoder.yudao.module.prison.controller.admin.assessment;
|
|
||||||
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
|
||||||
import jakarta.annotation.Resource;
|
|
||||||
import org.springframework.validation.annotation.Validated;
|
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
|
||||||
import io.swagger.v3.oas.annotations.Parameter;
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
|
||||||
|
|
||||||
import jakarta.validation.constraints.*;
|
|
||||||
import jakarta.validation.*;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
|
||||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
|
||||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.module.prison.controller.admin.assessment.vo.*;
|
|
||||||
import cn.iocoder.yudao.module.prison.dal.dataobject.assessment.AssessmentStatisticsDO;
|
|
||||||
import cn.iocoder.yudao.module.prison.service.assessment.AssessmentStatisticsService;
|
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
@Tag(name = "管理后台 - 测评统计")
|
|
||||||
@RestController
|
|
||||||
@RequestMapping("/prison/assessment-statistics")
|
|
||||||
@Validated
|
|
||||||
public class AssessmentStatisticsController {
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private AssessmentStatisticsService assessmentStatisticsService;
|
|
||||||
|
|
||||||
@GetMapping("/get")
|
|
||||||
@Operation(summary = "获得测评统计")
|
|
||||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
|
||||||
@PreAuthorize("@ss.hasPermission('prison:assessment-statistics:query')")
|
|
||||||
public CommonResult<AssessmentStatisticsRespVO> getAssessmentStatistics(@RequestParam("id") Long id) {
|
|
||||||
AssessmentStatisticsDO statistics = assessmentStatisticsService.getAssessmentStatistics(id);
|
|
||||||
return success(BeanUtils.toBean(statistics, AssessmentStatisticsRespVO.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/page")
|
|
||||||
@Operation(summary = "获得测评统计分页")
|
|
||||||
@PreAuthorize("@ss.hasPermission('prison:assessment-statistics:query')")
|
|
||||||
public CommonResult<PageResult<AssessmentStatisticsRespVO>> getAssessmentStatisticsPage(@Valid AssessmentStatisticsPageReqVO pageReqVO) {
|
|
||||||
PageResult<AssessmentStatisticsDO> pageResult = assessmentStatisticsService.getAssessmentStatisticsPage(pageReqVO);
|
|
||||||
return success(BeanUtils.toBean(pageResult, AssessmentStatisticsRespVO.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/generate")
|
|
||||||
@Operation(summary = "生成测评统计")
|
|
||||||
@Parameter(name = "assessmentRecordId", description = "测评记录ID", required = true)
|
|
||||||
@PreAuthorize("@ss.hasPermission('prison:assessment-statistics:create')")
|
|
||||||
public CommonResult<AssessmentStatisticsRespVO> generateStatistics(@RequestParam("assessmentRecordId") Long assessmentRecordId) {
|
|
||||||
AssessmentStatisticsDO statistics = assessmentStatisticsService.generateStatistics(assessmentRecordId);
|
|
||||||
return success(BeanUtils.toBean(statistics, AssessmentStatisticsRespVO.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/completion-rate")
|
|
||||||
@Operation(summary = "获取测评完成率")
|
|
||||||
@Parameter(name = "assessmentRecordId", description = "测评记录ID", required = true)
|
|
||||||
@PreAuthorize("@ss.hasPermission('prison:assessment-statistics:query')")
|
|
||||||
public CommonResult<BigDecimal> getCompletionRate(@RequestParam("assessmentRecordId") Long assessmentRecordId) {
|
|
||||||
return success(assessmentStatisticsService.getCompletionRate(assessmentRecordId));
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/score-distribution")
|
|
||||||
@Operation(summary = "获取分数分布")
|
|
||||||
@Parameter(name = "assessmentRecordId", description = "测评记录ID", required = true)
|
|
||||||
@PreAuthorize("@ss.hasPermission('prison:assessment-statistics:query')")
|
|
||||||
public CommonResult<Map<String, Integer>> getScoreDistribution(@RequestParam("assessmentRecordId") Long assessmentRecordId) {
|
|
||||||
return success(assessmentStatisticsService.getScoreDistribution(assessmentRecordId));
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/risk-distribution")
|
|
||||||
@Operation(summary = "获取风险分布")
|
|
||||||
@Parameter(name = "assessmentRecordId", description = "测评记录ID", required = true)
|
|
||||||
@PreAuthorize("@ss.hasPermission('prison:assessment-statistics:query')")
|
|
||||||
public CommonResult<Map<String, Integer>> getRiskDistribution(@RequestParam("assessmentRecordId") Long assessmentRecordId) {
|
|
||||||
return success(assessmentStatisticsService.getRiskDistribution(assessmentRecordId));
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/report")
|
|
||||||
@Operation(summary = "获取测评分析报告")
|
|
||||||
@Parameter(name = "assessmentRecordId", description = "测评记录ID", required = true)
|
|
||||||
@PreAuthorize("@ss.hasPermission('prison:assessment-statistics:query')")
|
|
||||||
public CommonResult<AssessmentReportRespVO> getAssessmentReport(@RequestParam("assessmentRecordId") Long assessmentRecordId) {
|
|
||||||
return success(assessmentStatisticsService.getAssessmentReport(assessmentRecordId));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,47 +0,0 @@
|
|||||||
package cn.iocoder.yudao.module.prison.controller.admin.assessment.vo;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
import jakarta.validation.constraints.NotNull;
|
|
||||||
import lombok.Data;
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 答卷详情分页查询 Request VO
|
|
||||||
*
|
|
||||||
* @author 芋道源码
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@EqualsAndHashCode(callSuper = true)
|
|
||||||
@ToString(callSuper = true)
|
|
||||||
public class AssessmentAnswerPageReqVO extends PageParam {
|
|
||||||
|
|
||||||
@Schema(description = "关联测评记录ID")
|
|
||||||
private Long assessmentRecordId;
|
|
||||||
|
|
||||||
@Schema(description = "囚犯ID")
|
|
||||||
private Long prisonerId;
|
|
||||||
|
|
||||||
@Schema(description = "囚犯编号")
|
|
||||||
private String prisonerCode;
|
|
||||||
|
|
||||||
@Schema(description = "囚犯姓名")
|
|
||||||
private String prisonerName;
|
|
||||||
|
|
||||||
@Schema(description = "监区ID")
|
|
||||||
private Long areaId;
|
|
||||||
|
|
||||||
@Schema(description = "监室ID")
|
|
||||||
private Long cellId;
|
|
||||||
|
|
||||||
@Schema(description = "答卷状态:1-待答题 2-答题中 3-已提交 4-已评分 5-已完成")
|
|
||||||
private Integer status;
|
|
||||||
|
|
||||||
@Schema(description = "开始答题时间")
|
|
||||||
private LocalDateTime[] startTime;
|
|
||||||
|
|
||||||
@Schema(description = "提交时间")
|
|
||||||
private LocalDateTime[] submitTime;
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,91 +0,0 @@
|
|||||||
package cn.iocoder.yudao.module.prison.controller.admin.assessment.vo;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
import jakarta.validation.constraints.NotNull;
|
|
||||||
import lombok.Data;
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 答卷详情 Response VO
|
|
||||||
*
|
|
||||||
* @author 芋道源码
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@EqualsAndHashCode(callSuper = true)
|
|
||||||
@ToString(callSuper = true)
|
|
||||||
public class AssessmentAnswerRespVO {
|
|
||||||
|
|
||||||
@Schema(description = "答卷ID", example = "1024")
|
|
||||||
private Long id;
|
|
||||||
|
|
||||||
@Schema(description = "关联测评记录ID")
|
|
||||||
private Long assessmentRecordId;
|
|
||||||
|
|
||||||
@Schema(description = "测评名称")
|
|
||||||
private String assessmentName;
|
|
||||||
|
|
||||||
@Schema(description = "囚犯ID")
|
|
||||||
private Long prisonerId;
|
|
||||||
|
|
||||||
@Schema(description = "囚犯编号")
|
|
||||||
private String prisonerCode;
|
|
||||||
|
|
||||||
@Schema(description = "囚犯姓名")
|
|
||||||
private String prisonerName;
|
|
||||||
|
|
||||||
@Schema(description = "监区ID")
|
|
||||||
private Long areaId;
|
|
||||||
|
|
||||||
@Schema(description = "监区名称")
|
|
||||||
private String areaName;
|
|
||||||
|
|
||||||
@Schema(description = "监室ID")
|
|
||||||
private Long cellId;
|
|
||||||
|
|
||||||
@Schema(description = "监室名称")
|
|
||||||
private String cellName;
|
|
||||||
|
|
||||||
@Schema(description = "答卷状态:1-待答题 2-答题中 3-已提交 4-已评分 5-已完成")
|
|
||||||
private Integer status;
|
|
||||||
|
|
||||||
@Schema(description = "开始答题时间")
|
|
||||||
private LocalDateTime startTime;
|
|
||||||
|
|
||||||
@Schema(description = "提交时间")
|
|
||||||
private LocalDateTime submitTime;
|
|
||||||
|
|
||||||
@Schema(description = "答题用时(秒)")
|
|
||||||
private Integer duration;
|
|
||||||
|
|
||||||
@Schema(description = "客观题得分")
|
|
||||||
private BigDecimal objectiveScore;
|
|
||||||
|
|
||||||
@Schema(description = "主观题得分")
|
|
||||||
private BigDecimal subjectiveScore;
|
|
||||||
|
|
||||||
@Schema(description = "总分")
|
|
||||||
private BigDecimal totalScore;
|
|
||||||
|
|
||||||
@Schema(description = "是否及格")
|
|
||||||
private Boolean passed;
|
|
||||||
|
|
||||||
@Schema(description = "评语")
|
|
||||||
private String comment;
|
|
||||||
|
|
||||||
@Schema(description = "评卷人ID")
|
|
||||||
private Long scorerId;
|
|
||||||
|
|
||||||
@Schema(description = "评卷人名称")
|
|
||||||
private String scorerName;
|
|
||||||
|
|
||||||
@Schema(description = "评分时间")
|
|
||||||
private LocalDateTime scoreTime;
|
|
||||||
|
|
||||||
@Schema(description = "创建时间")
|
|
||||||
private LocalDateTime createTime;
|
|
||||||
|
|
||||||
@Schema(description = "更新时间")
|
|
||||||
private LocalDateTime updateTime;
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,78 +0,0 @@
|
|||||||
package cn.iocoder.yudao.module.prison.controller.admin.assessment.vo;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
import jakarta.validation.constraints.NotNull;
|
|
||||||
import lombok.Data;
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 答卷详情创建/更新 Request VO
|
|
||||||
*
|
|
||||||
* @author 芋道源码
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@EqualsAndHashCode(callSuper = true)
|
|
||||||
@ToString(callSuper = true)
|
|
||||||
public class AssessmentAnswerSaveReqVO {
|
|
||||||
|
|
||||||
@Schema(description = "答卷ID", example = "1024")
|
|
||||||
private Long id;
|
|
||||||
|
|
||||||
@Schema(description = "关联测评记录ID", requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
@NotNull(message = "测评记录不能为空")
|
|
||||||
private Long assessmentRecordId;
|
|
||||||
|
|
||||||
@Schema(description = "囚犯ID", requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
@NotNull(message = "囚犯不能为空")
|
|
||||||
private Long prisonerId;
|
|
||||||
|
|
||||||
@Schema(description = "囚犯编号")
|
|
||||||
private String prisonerCode;
|
|
||||||
|
|
||||||
@Schema(description = "囚犯姓名")
|
|
||||||
private String prisonerName;
|
|
||||||
|
|
||||||
@Schema(description = "监区ID")
|
|
||||||
private Long areaId;
|
|
||||||
|
|
||||||
@Schema(description = "监区名称")
|
|
||||||
private String areaName;
|
|
||||||
|
|
||||||
@Schema(description = "监室ID")
|
|
||||||
private Long cellId;
|
|
||||||
|
|
||||||
@Schema(description = "监室名称")
|
|
||||||
private String cellName;
|
|
||||||
|
|
||||||
@Schema(description = "答卷状态:1-待答题 2-答题中 3-已提交 4-已评分 5-已完成")
|
|
||||||
private Integer status;
|
|
||||||
|
|
||||||
@Schema(description = "开始答题时间")
|
|
||||||
private LocalDateTime startTime;
|
|
||||||
|
|
||||||
@Schema(description = "提交时间")
|
|
||||||
private LocalDateTime submitTime;
|
|
||||||
|
|
||||||
@Schema(description = "答题用时(秒)")
|
|
||||||
private Integer duration;
|
|
||||||
|
|
||||||
@Schema(description = "客观题得分")
|
|
||||||
private BigDecimal objectiveScore;
|
|
||||||
|
|
||||||
@Schema(description = "主观题得分")
|
|
||||||
private BigDecimal subjectiveScore;
|
|
||||||
|
|
||||||
@Schema(description = "总分")
|
|
||||||
private BigDecimal totalScore;
|
|
||||||
|
|
||||||
@Schema(description = "是否及格")
|
|
||||||
private Boolean passed;
|
|
||||||
|
|
||||||
@Schema(description = "评语")
|
|
||||||
private String comment;
|
|
||||||
|
|
||||||
@Schema(description = "及格分数")
|
|
||||||
private BigDecimal passScore;
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
package cn.iocoder.yudao.module.prison.controller.admin.assessment.vo;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
import jakarta.validation.constraints.NotNull;
|
|
||||||
import lombok.Data;
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 答卷提交 Request VO
|
|
||||||
*
|
|
||||||
* @author 芋道源码
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public class AssessmentAnswerSubmitReqVO {
|
|
||||||
|
|
||||||
@Schema(description = "答卷ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
|
||||||
@NotNull(message = "答卷ID不能为空")
|
|
||||||
private Long id;
|
|
||||||
|
|
||||||
@Schema(description = "答题详情JSON")
|
|
||||||
private String answers;
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,44 +0,0 @@
|
|||||||
package cn.iocoder.yudao.module.prison.controller.admin.assessment.vo;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
import jakarta.validation.constraints.NotNull;
|
|
||||||
import lombok.Data;
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 测评记录分页查询 Request VO
|
|
||||||
*
|
|
||||||
* @author 芋道源码
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@EqualsAndHashCode(callSuper = true)
|
|
||||||
@ToString(callSuper = true)
|
|
||||||
public class AssessmentRecordPageReqVO extends PageParam {
|
|
||||||
|
|
||||||
@Schema(description = "测评名称", example = "心理测评")
|
|
||||||
private String name;
|
|
||||||
|
|
||||||
@Schema(description = "关联问卷模板ID")
|
|
||||||
private Long questionnaireId;
|
|
||||||
|
|
||||||
@Schema(description = "测评类型:1-心理测评 2-行为评估 3-满意度调查")
|
|
||||||
private Integer type;
|
|
||||||
|
|
||||||
@Schema(description = "发起测评的监狱/监区ID")
|
|
||||||
private Long areaId;
|
|
||||||
|
|
||||||
@Schema(description = "测评状态:1-未开始 2-进行中 3-已完成 4-已取消")
|
|
||||||
private Integer status;
|
|
||||||
|
|
||||||
@Schema(description = "计划开始时间")
|
|
||||||
private LocalDateTime[] planStartTime;
|
|
||||||
|
|
||||||
@Schema(description = "计划结束时间")
|
|
||||||
private LocalDateTime[] planEndTime;
|
|
||||||
|
|
||||||
@Schema(description = "创建时间")
|
|
||||||
private LocalDateTime[] createTime;
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,81 +0,0 @@
|
|||||||
package cn.iocoder.yudao.module.prison.controller.admin.assessment.vo;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
import lombok.Data;
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 测评记录 Response VO
|
|
||||||
*
|
|
||||||
* @author 芋道源码
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@EqualsAndHashCode(callSuper = true)
|
|
||||||
@ToString(callSuper = true)
|
|
||||||
public class AssessmentRecordRespVO {
|
|
||||||
|
|
||||||
@Schema(description = "测评记录ID", example = "1024")
|
|
||||||
private Long id;
|
|
||||||
|
|
||||||
@Schema(description = "测评名称", example = "心理测评")
|
|
||||||
private String name;
|
|
||||||
|
|
||||||
@Schema(description = "关联问卷模板ID")
|
|
||||||
private Long questionnaireId;
|
|
||||||
|
|
||||||
@Schema(description = "问卷模板名称")
|
|
||||||
private String questionnaireName;
|
|
||||||
|
|
||||||
@Schema(description = "测评类型:1-心理测评 2-行为评估 3-满意度调查")
|
|
||||||
private Integer type;
|
|
||||||
|
|
||||||
@Schema(description = "发起测评的监狱/监区ID")
|
|
||||||
private Long areaId;
|
|
||||||
|
|
||||||
@Schema(description = "发起测评的监狱/监区名称")
|
|
||||||
private String areaName;
|
|
||||||
|
|
||||||
@Schema(description = "发起人ID")
|
|
||||||
private Long initiatorId;
|
|
||||||
|
|
||||||
@Schema(description = "发起人名称")
|
|
||||||
private String initiatorName;
|
|
||||||
|
|
||||||
@Schema(description = "测评状态:1-未开始 2-进行中 3-已完成 4-已取消")
|
|
||||||
private Integer status;
|
|
||||||
|
|
||||||
@Schema(description = "计划开始时间")
|
|
||||||
private LocalDateTime planStartTime;
|
|
||||||
|
|
||||||
@Schema(description = "计划结束时间")
|
|
||||||
private LocalDateTime planEndTime;
|
|
||||||
|
|
||||||
@Schema(description = "实际开始时间")
|
|
||||||
private LocalDateTime actualStartTime;
|
|
||||||
|
|
||||||
@Schema(description = "实际结束时间")
|
|
||||||
private LocalDateTime actualEndTime;
|
|
||||||
|
|
||||||
@Schema(description = "参与人数")
|
|
||||||
private Integer participantCount;
|
|
||||||
|
|
||||||
@Schema(description = "完成人数")
|
|
||||||
private Integer completedCount;
|
|
||||||
|
|
||||||
@Schema(description = "测评说明")
|
|
||||||
private String description;
|
|
||||||
|
|
||||||
@Schema(description = "是否启用自动评分")
|
|
||||||
private Boolean enableAutoScore;
|
|
||||||
|
|
||||||
@Schema(description = "及格分数")
|
|
||||||
private BigDecimal passScore;
|
|
||||||
|
|
||||||
@Schema(description = "创建时间")
|
|
||||||
private LocalDateTime createTime;
|
|
||||||
|
|
||||||
@Schema(description = "更新时间")
|
|
||||||
private LocalDateTime updateTime;
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,65 +0,0 @@
|
|||||||
package cn.iocoder.yudao.module.prison.controller.admin.assessment.vo;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
import jakarta.validation.constraints.NotNull;
|
|
||||||
import lombok.Data;
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 测评记录创建/更新 Request VO
|
|
||||||
*
|
|
||||||
* @author 芋道源码
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@EqualsAndHashCode(callSuper = true)
|
|
||||||
@ToString(callSuper = true)
|
|
||||||
public class AssessmentRecordSaveReqVO {
|
|
||||||
|
|
||||||
@Schema(description = "测评记录ID", example = "1024")
|
|
||||||
private Long id;
|
|
||||||
|
|
||||||
@Schema(description = "测评名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "心理测评")
|
|
||||||
@NotNull(message = "测评名称不能为空")
|
|
||||||
private String name;
|
|
||||||
|
|
||||||
@Schema(description = "关联问卷模板ID", requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
@NotNull(message = "问卷模板不能为空")
|
|
||||||
private Long questionnaireId;
|
|
||||||
|
|
||||||
@Schema(description = "测评类型:1-心理测评 2-行为评估 3-满意度调查", requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
@NotNull(message = "测评类型不能为空")
|
|
||||||
private Integer type;
|
|
||||||
|
|
||||||
@Schema(description = "发起测评的监狱/监区ID", requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
@NotNull(message = "监区不能为空")
|
|
||||||
private Long areaId;
|
|
||||||
|
|
||||||
@Schema(description = "发起测评的监狱/监区名称")
|
|
||||||
private String areaName;
|
|
||||||
|
|
||||||
@Schema(description = "发起人ID")
|
|
||||||
private Long initiatorId;
|
|
||||||
|
|
||||||
@Schema(description = "发起人名称")
|
|
||||||
private String initiatorName;
|
|
||||||
|
|
||||||
@Schema(description = "测评状态:1-未开始 2-进行中 3-已完成 4-已取消")
|
|
||||||
private Integer status;
|
|
||||||
|
|
||||||
@Schema(description = "计划开始时间")
|
|
||||||
private LocalDateTime planStartTime;
|
|
||||||
|
|
||||||
@Schema(description = "计划结束时间")
|
|
||||||
private LocalDateTime planEndTime;
|
|
||||||
|
|
||||||
@Schema(description = "测评说明")
|
|
||||||
private String description;
|
|
||||||
|
|
||||||
@Schema(description = "是否启用自动评分")
|
|
||||||
private Boolean enableAutoScore;
|
|
||||||
|
|
||||||
@Schema(description = "及格分数")
|
|
||||||
private BigDecimal passScore;
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,71 +0,0 @@
|
|||||||
package cn.iocoder.yudao.module.prison.controller.admin.assessment.vo;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
import lombok.Data;
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 测评分析报告 Response VO
|
|
||||||
*
|
|
||||||
* @author 芋道源码
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public class AssessmentReportRespVO {
|
|
||||||
|
|
||||||
@Schema(description = "关联测评记录ID")
|
|
||||||
private Long assessmentRecordId;
|
|
||||||
|
|
||||||
@Schema(description = "测评名称")
|
|
||||||
private String assessmentName;
|
|
||||||
|
|
||||||
@Schema(description = "总参与人数")
|
|
||||||
private Integer totalCount;
|
|
||||||
|
|
||||||
@Schema(description = "已完成人数")
|
|
||||||
private Integer completedCount;
|
|
||||||
|
|
||||||
@Schema(description = "完成率(%)")
|
|
||||||
private BigDecimal completionRate;
|
|
||||||
|
|
||||||
@Schema(description = "平均分")
|
|
||||||
private BigDecimal averageScore;
|
|
||||||
|
|
||||||
@Schema(description = "最高分")
|
|
||||||
private BigDecimal highestScore;
|
|
||||||
|
|
||||||
@Schema(description = "最低分")
|
|
||||||
private BigDecimal lowestScore;
|
|
||||||
|
|
||||||
@Schema(description = "及格人数")
|
|
||||||
private Integer passedCount;
|
|
||||||
|
|
||||||
@Schema(description = "及格率(%)")
|
|
||||||
private BigDecimal passRate;
|
|
||||||
|
|
||||||
@Schema(description = "优秀人数(90分以上)")
|
|
||||||
private Integer excellentCount;
|
|
||||||
|
|
||||||
@Schema(description = "优秀率(%)")
|
|
||||||
private BigDecimal excellentRate;
|
|
||||||
|
|
||||||
@Schema(description = "风险人数(60分以下)")
|
|
||||||
private Integer riskCount;
|
|
||||||
|
|
||||||
@Schema(description = "风险率(%)")
|
|
||||||
private BigDecimal riskRate;
|
|
||||||
|
|
||||||
@Schema(description = "分数分布")
|
|
||||||
private Map<String, Integer> scoreDistribution;
|
|
||||||
|
|
||||||
@Schema(description = "风险分布")
|
|
||||||
private Map<String, Integer> riskDistribution;
|
|
||||||
|
|
||||||
@Schema(description = "分析建议")
|
|
||||||
private String analysisSuggestion;
|
|
||||||
|
|
||||||
@Schema(description = "生成时间")
|
|
||||||
private LocalDateTime generatedTime;
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,34 +0,0 @@
|
|||||||
package cn.iocoder.yudao.module.prison.controller.admin.assessment.vo;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
import jakarta.validation.constraints.NotNull;
|
|
||||||
import lombok.Data;
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 人工评阅 Request VO
|
|
||||||
*
|
|
||||||
* @author 芋道源码
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public class AssessmentResultManualReviewReqVO {
|
|
||||||
|
|
||||||
@Schema(description = "结果ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
|
||||||
@NotNull(message = "结果ID不能为空")
|
|
||||||
private Long id;
|
|
||||||
|
|
||||||
@Schema(description = "人工评分", requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
@NotNull(message = "评分不能为空")
|
|
||||||
private BigDecimal manualScore;
|
|
||||||
|
|
||||||
@Schema(description = "人工评语")
|
|
||||||
private String manualComment;
|
|
||||||
|
|
||||||
@Schema(description = "评阅人ID")
|
|
||||||
private Long reviewerId;
|
|
||||||
|
|
||||||
@Schema(description = "评阅人名称")
|
|
||||||
private String reviewerName;
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,44 +0,0 @@
|
|||||||
package cn.iocoder.yudao.module.prison.controller.admin.assessment.vo;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
import jakarta.validation.constraints.NotNull;
|
|
||||||
import lombok.Data;
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 测评结果分页查询 Request VO
|
|
||||||
*
|
|
||||||
* @author 芋道源码
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@EqualsAndHashCode(callSuper = true)
|
|
||||||
@ToString(callSuper = true)
|
|
||||||
public class AssessmentResultPageReqVO extends PageParam {
|
|
||||||
|
|
||||||
@Schema(description = "关联答卷ID")
|
|
||||||
private Long answerId;
|
|
||||||
|
|
||||||
@Schema(description = "关联测评记录ID")
|
|
||||||
private Long assessmentRecordId;
|
|
||||||
|
|
||||||
@Schema(description = "囚犯ID")
|
|
||||||
private Long prisonerId;
|
|
||||||
|
|
||||||
@Schema(description = "关联题目ID")
|
|
||||||
private Long questionId;
|
|
||||||
|
|
||||||
@Schema(description = "题目类型:1-单选 2-多选 3-判断 4-填空 5-问答")
|
|
||||||
private Integer questionType;
|
|
||||||
|
|
||||||
@Schema(description = "是否正确")
|
|
||||||
private Boolean correct;
|
|
||||||
|
|
||||||
@Schema(description = "是否需要人工评阅")
|
|
||||||
private Boolean needManualReview;
|
|
||||||
|
|
||||||
@Schema(description = "人工评阅状态:1-待评阅 2-已评阅")
|
|
||||||
private Integer manualReviewStatus;
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,90 +0,0 @@
|
|||||||
package cn.iocoder.yudao.module.prison.controller.admin.assessment.vo;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
import lombok.Data;
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 测评结果 Response VO
|
|
||||||
*
|
|
||||||
* @author 芋道源码
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@EqualsAndHashCode(callSuper = true)
|
|
||||||
@ToString(callSuper = true)
|
|
||||||
public class AssessmentResultRespVO {
|
|
||||||
|
|
||||||
@Schema(description = "结果ID", example = "1024")
|
|
||||||
private Long id;
|
|
||||||
|
|
||||||
@Schema(description = "关联答卷ID")
|
|
||||||
private Long answerId;
|
|
||||||
|
|
||||||
@Schema(description = "关联测评记录ID")
|
|
||||||
private Long assessmentRecordId;
|
|
||||||
|
|
||||||
@Schema(description = "囚犯ID")
|
|
||||||
private Long prisonerId;
|
|
||||||
|
|
||||||
@Schema(description = "囚犯编号")
|
|
||||||
private String prisonerCode;
|
|
||||||
|
|
||||||
@Schema(description = "囚犯姓名")
|
|
||||||
private String prisonerName;
|
|
||||||
|
|
||||||
@Schema(description = "关联题目ID")
|
|
||||||
private Long questionId;
|
|
||||||
|
|
||||||
@Schema(description = "题目编号")
|
|
||||||
private String questionCode;
|
|
||||||
|
|
||||||
@Schema(description = "题目内容")
|
|
||||||
private String questionContent;
|
|
||||||
|
|
||||||
@Schema(description = "题目类型:1-单选 2-多选 3-判断 4-填空 5-问答")
|
|
||||||
private Integer questionType;
|
|
||||||
|
|
||||||
@Schema(description = "题目分值")
|
|
||||||
private BigDecimal questionScore;
|
|
||||||
|
|
||||||
@Schema(description = "囚犯答案")
|
|
||||||
private String answer;
|
|
||||||
|
|
||||||
@Schema(description = "正确答案(客观题)")
|
|
||||||
private String correctAnswer;
|
|
||||||
|
|
||||||
@Schema(description = "是否正确")
|
|
||||||
private Boolean correct;
|
|
||||||
|
|
||||||
@Schema(description = "得分")
|
|
||||||
private BigDecimal score;
|
|
||||||
|
|
||||||
@Schema(description = "是否需要人工评阅")
|
|
||||||
private Boolean needManualReview;
|
|
||||||
|
|
||||||
@Schema(description = "人工评阅状态:1-待评阅 2-已评阅")
|
|
||||||
private Integer manualReviewStatus;
|
|
||||||
|
|
||||||
@Schema(description = "人工评分")
|
|
||||||
private BigDecimal manualScore;
|
|
||||||
|
|
||||||
@Schema(description = "人工评语")
|
|
||||||
private String manualComment;
|
|
||||||
|
|
||||||
@Schema(description = "评阅人ID")
|
|
||||||
private Long reviewerId;
|
|
||||||
|
|
||||||
@Schema(description = "评阅人名称")
|
|
||||||
private String reviewerName;
|
|
||||||
|
|
||||||
@Schema(description = "评阅时间")
|
|
||||||
private LocalDateTime reviewTime;
|
|
||||||
|
|
||||||
@Schema(description = "创建时间")
|
|
||||||
private LocalDateTime createTime;
|
|
||||||
|
|
||||||
@Schema(description = "更新时间")
|
|
||||||
private LocalDateTime updateTime;
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,80 +0,0 @@
|
|||||||
package cn.iocoder.yudao.module.prison.controller.admin.assessment.vo;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
import jakarta.validation.constraints.NotNull;
|
|
||||||
import lombok.Data;
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 测评结果创建/更新 Request VO
|
|
||||||
*
|
|
||||||
* @author 芋道源码
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@EqualsAndHashCode(callSuper = true)
|
|
||||||
@ToString(callSuper = true)
|
|
||||||
public class AssessmentResultSaveReqVO {
|
|
||||||
|
|
||||||
@Schema(description = "结果ID", example = "1024")
|
|
||||||
private Long id;
|
|
||||||
|
|
||||||
@Schema(description = "关联答卷ID", requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
@NotNull(message = "答卷ID不能为空")
|
|
||||||
private Long answerId;
|
|
||||||
|
|
||||||
@Schema(description = "关联测评记录ID", requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
@NotNull(message = "测评记录ID不能为空")
|
|
||||||
private Long assessmentRecordId;
|
|
||||||
|
|
||||||
@Schema(description = "囚犯ID", requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
@NotNull(message = "囚犯ID不能为空")
|
|
||||||
private Long prisonerId;
|
|
||||||
|
|
||||||
@Schema(description = "囚犯编号")
|
|
||||||
private String prisonerCode;
|
|
||||||
|
|
||||||
@Schema(description = "囚犯姓名")
|
|
||||||
private String prisonerName;
|
|
||||||
|
|
||||||
@Schema(description = "关联题目ID", requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
@NotNull(message = "题目ID不能为空")
|
|
||||||
private Long questionId;
|
|
||||||
|
|
||||||
@Schema(description = "题目编号")
|
|
||||||
private String questionCode;
|
|
||||||
|
|
||||||
@Schema(description = "题目内容")
|
|
||||||
private String questionContent;
|
|
||||||
|
|
||||||
@Schema(description = "题目类型:1-单选 2-多选 3-判断 4-填空 5-问答")
|
|
||||||
private Integer questionType;
|
|
||||||
|
|
||||||
@Schema(description = "题目分值")
|
|
||||||
private BigDecimal questionScore;
|
|
||||||
|
|
||||||
@Schema(description = "囚犯答案")
|
|
||||||
private String answer;
|
|
||||||
|
|
||||||
@Schema(description = "正确答案(客观题)")
|
|
||||||
private String correctAnswer;
|
|
||||||
|
|
||||||
@Schema(description = "是否正确")
|
|
||||||
private Boolean correct;
|
|
||||||
|
|
||||||
@Schema(description = "得分")
|
|
||||||
private BigDecimal score;
|
|
||||||
|
|
||||||
@Schema(description = "是否需要人工评阅")
|
|
||||||
private Boolean needManualReview;
|
|
||||||
|
|
||||||
@Schema(description = "人工评阅状态:1-待评阅 2-已评阅")
|
|
||||||
private Integer manualReviewStatus;
|
|
||||||
|
|
||||||
@Schema(description = "人工评分")
|
|
||||||
private BigDecimal manualScore;
|
|
||||||
|
|
||||||
@Schema(description = "人工评语")
|
|
||||||
private String manualComment;
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,26 +0,0 @@
|
|||||||
package cn.iocoder.yudao.module.prison.controller.admin.assessment.vo;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
import jakarta.validation.constraints.NotNull;
|
|
||||||
import lombok.Data;
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 测评统计分页查询 Request VO
|
|
||||||
*
|
|
||||||
* @author 芋道源码
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@EqualsAndHashCode(callSuper = true)
|
|
||||||
@ToString(callSuper = true)
|
|
||||||
public class AssessmentStatisticsPageReqVO extends PageParam {
|
|
||||||
|
|
||||||
@Schema(description = "关联测评记录ID")
|
|
||||||
private Long assessmentRecordId;
|
|
||||||
|
|
||||||
@Schema(description = "测评名称")
|
|
||||||
private String assessmentName;
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,76 +0,0 @@
|
|||||||
package cn.iocoder.yudao.module.prison.controller.admin.assessment.vo;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
import lombok.Data;
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 测评统计 Response VO
|
|
||||||
*
|
|
||||||
* @author 芋道源码
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@EqualsAndHashCode(callSuper = true)
|
|
||||||
@ToString(callSuper = true)
|
|
||||||
public class AssessmentStatisticsRespVO {
|
|
||||||
|
|
||||||
@Schema(description = "统计ID", example = "1024")
|
|
||||||
private Long id;
|
|
||||||
|
|
||||||
@Schema(description = "关联测评记录ID")
|
|
||||||
private Long assessmentRecordId;
|
|
||||||
|
|
||||||
@Schema(description = "测评名称")
|
|
||||||
private String assessmentName;
|
|
||||||
|
|
||||||
@Schema(description = "总参与人数")
|
|
||||||
private Integer totalCount;
|
|
||||||
|
|
||||||
@Schema(description = "已完成人数")
|
|
||||||
private Integer completedCount;
|
|
||||||
|
|
||||||
@Schema(description = "完成率")
|
|
||||||
private BigDecimal completionRate;
|
|
||||||
|
|
||||||
@Schema(description = "平均分")
|
|
||||||
private BigDecimal averageScore;
|
|
||||||
|
|
||||||
@Schema(description = "最高分")
|
|
||||||
private BigDecimal highestScore;
|
|
||||||
|
|
||||||
@Schema(description = "最低分")
|
|
||||||
private BigDecimal lowestScore;
|
|
||||||
|
|
||||||
@Schema(description = "及格人数")
|
|
||||||
private Integer passedCount;
|
|
||||||
|
|
||||||
@Schema(description = "及格率")
|
|
||||||
private BigDecimal passRate;
|
|
||||||
|
|
||||||
@Schema(description = "优秀人数(90分以上)")
|
|
||||||
private Integer excellentCount;
|
|
||||||
|
|
||||||
@Schema(description = "优秀率")
|
|
||||||
private BigDecimal excellentRate;
|
|
||||||
|
|
||||||
@Schema(description = "风险人数(60分以下)")
|
|
||||||
private Integer riskCount;
|
|
||||||
|
|
||||||
@Schema(description = "风险率")
|
|
||||||
private BigDecimal riskRate;
|
|
||||||
|
|
||||||
@Schema(description = "风险分布")
|
|
||||||
private Map<String, Integer> riskDistribution;
|
|
||||||
|
|
||||||
@Schema(description = "分数分布")
|
|
||||||
private Map<String, Integer> scoreDistribution;
|
|
||||||
|
|
||||||
@Schema(description = "统计时间")
|
|
||||||
private LocalDateTime statisticsTime;
|
|
||||||
|
|
||||||
@Schema(description = "创建时间")
|
|
||||||
private LocalDateTime createTime;
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -27,9 +27,12 @@ import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*;
|
|||||||
|
|
||||||
import cn.iocoder.yudao.module.prison.controller.admin.consumption.vo.*;
|
import cn.iocoder.yudao.module.prison.controller.admin.consumption.vo.*;
|
||||||
import cn.iocoder.yudao.module.prison.dal.dataobject.consumption.ConsumptionDO;
|
import cn.iocoder.yudao.module.prison.dal.dataobject.consumption.ConsumptionDO;
|
||||||
|
import cn.iocoder.yudao.module.prison.dal.dataobject.consumption.ConsumptionDetailDO;
|
||||||
import cn.iocoder.yudao.module.prison.service.consumption.ConsumptionService;
|
import cn.iocoder.yudao.module.prison.service.consumption.ConsumptionService;
|
||||||
|
import cn.iocoder.yudao.module.prison.convert.consumption.ConsumptionConvert;
|
||||||
|
import cn.iocoder.yudao.module.prison.convert.consumption.ConsumptionDetailConvert;
|
||||||
|
|
||||||
@Tag(name = "管理后台 - 消费记录")
|
@Tag(name = "管理后台 - 消费订单")
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/prison/consumption")
|
@RequestMapping("/prison/consumption")
|
||||||
@Validated
|
@Validated
|
||||||
@ -39,14 +42,14 @@ public class PrisonConsumptionController {
|
|||||||
private ConsumptionService consumptionService;
|
private ConsumptionService consumptionService;
|
||||||
|
|
||||||
@PostMapping("/create")
|
@PostMapping("/create")
|
||||||
@Operation(summary = "创建消费记录")
|
@Operation(summary = "创建消费订单")
|
||||||
@PreAuthorize("@ss.hasPermission('prison:consumption:create')")
|
@PreAuthorize("@ss.hasPermission('prison:consumption:create')")
|
||||||
public CommonResult<Long> createConsumption(@Valid @RequestBody ConsumptionSaveReqVO createReqVO) {
|
public CommonResult<Long> createConsumption(@Valid @RequestBody ConsumptionSaveReqVO createReqVO) {
|
||||||
return success(consumptionService.createConsumption(createReqVO));
|
return success(consumptionService.createConsumption(createReqVO));
|
||||||
}
|
}
|
||||||
|
|
||||||
@PutMapping("/update")
|
@PutMapping("/update")
|
||||||
@Operation(summary = "更新消费记录")
|
@Operation(summary = "更新消费订单")
|
||||||
@PreAuthorize("@ss.hasPermission('prison:consumption:update')")
|
@PreAuthorize("@ss.hasPermission('prison:consumption:update')")
|
||||||
public CommonResult<Boolean> updateConsumption(@Valid @RequestBody ConsumptionSaveReqVO updateReqVO) {
|
public CommonResult<Boolean> updateConsumption(@Valid @RequestBody ConsumptionSaveReqVO updateReqVO) {
|
||||||
consumptionService.updateConsumption(updateReqVO);
|
consumptionService.updateConsumption(updateReqVO);
|
||||||
@ -54,8 +57,8 @@ public class PrisonConsumptionController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@DeleteMapping("/delete")
|
@DeleteMapping("/delete")
|
||||||
@Operation(summary = "删除消费记录")
|
@Operation(summary = "删除消费订单")
|
||||||
@Parameter(name = "id", description = "编号", required = true)
|
@Parameter(name = "id", description = "订单编号", required = true)
|
||||||
@PreAuthorize("@ss.hasPermission('prison:consumption:delete')")
|
@PreAuthorize("@ss.hasPermission('prison:consumption:delete')")
|
||||||
public CommonResult<Boolean> deleteConsumption(@NotNull(message = "编号不能为空") @RequestParam("id") Long id) {
|
public CommonResult<Boolean> deleteConsumption(@NotNull(message = "编号不能为空") @RequestParam("id") Long id) {
|
||||||
consumptionService.deleteConsumption(id);
|
consumptionService.deleteConsumption(id);
|
||||||
@ -63,33 +66,51 @@ public class PrisonConsumptionController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@DeleteMapping("/delete-list")
|
@DeleteMapping("/delete-list")
|
||||||
@Parameter(name = "ids", description = "编号", required = true)
|
@Parameter(name = "ids", description = "编号列表", required = true)
|
||||||
@Operation(summary = "批量删除消费记录")
|
@Operation(summary = "批量删除消费订单")
|
||||||
@PreAuthorize("@ss.hasPermission('prison:consumption:delete')")
|
@PreAuthorize("@ss.hasPermission('prison:consumption:delete')")
|
||||||
public CommonResult<Boolean> deleteConsumptionList(@NotEmpty(message = "编号列表不能为空") @RequestParam("ids") List<Long> ids) {
|
public CommonResult<Boolean> deleteConsumptionList(@NotEmpty(message = "编号列表不能为空") @RequestParam("ids") List<Long> ids) {
|
||||||
consumptionService.deleteConsumptionListByIds(ids);
|
consumptionService.deleteConsumptionListByIds(ids);
|
||||||
return success(true);
|
return success(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/get")
|
@GetMapping("/get")
|
||||||
@Operation(summary = "获得消费记录")
|
@Operation(summary = "获得消费订单详情")
|
||||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
@Parameter(name = "id", description = "订单编号", required = true, example = "1024")
|
||||||
@PreAuthorize("@ss.hasPermission('prison:consumption:query')")
|
@PreAuthorize("@ss.hasPermission('prison:consumption:query')")
|
||||||
public CommonResult<ConsumptionRespVO> getConsumption(@RequestParam("id") Long id) {
|
public CommonResult<ConsumptionRespVO> getConsumption(@RequestParam("id") Long id) {
|
||||||
ConsumptionDO consumption = consumptionService.getConsumption(id);
|
ConsumptionDO consumption = consumptionService.getConsumption(id);
|
||||||
return success(BeanUtils.toBean(consumption, ConsumptionRespVO.class));
|
if (consumption == null) {
|
||||||
|
return success(null);
|
||||||
|
}
|
||||||
|
// 转换主表数据
|
||||||
|
ConsumptionRespVO respVO = ConsumptionConvert.INSTANCE.convert(consumption);
|
||||||
|
// 查询并转换明细列表
|
||||||
|
List<ConsumptionDetailDO> detailList = consumptionService.getConsumptionDetailList(id);
|
||||||
|
respVO.setDetails(ConsumptionDetailConvert.INSTANCE.convertListResp(detailList));
|
||||||
|
return success(respVO);
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/page")
|
@GetMapping("/page")
|
||||||
@Operation(summary = "获得消费记录分页")
|
@Operation(summary = "获得消费订单分页")
|
||||||
@PreAuthorize("@ss.hasPermission('prison:consumption:query')")
|
@PreAuthorize("@ss.hasPermission('prison:consumption:query')")
|
||||||
public CommonResult<PageResult<ConsumptionRespVO>> getConsumptionPage(@Valid ConsumptionPageReqVO pageReqVO) {
|
public CommonResult<PageResult<ConsumptionRespVO>> getConsumptionPage(@Valid ConsumptionPageReqVO pageReqVO) {
|
||||||
PageResult<ConsumptionDO> pageResult = consumptionService.getConsumptionPage(pageReqVO);
|
PageResult<ConsumptionDO> pageResult = consumptionService.getConsumptionPage(pageReqVO);
|
||||||
return success(BeanUtils.toBean(pageResult, ConsumptionRespVO.class));
|
return success(ConsumptionConvert.INSTANCE.convertPage(pageResult));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/detail-list")
|
||||||
|
@Operation(summary = "获得消费订单明细列表")
|
||||||
|
@Parameter(name = "consumptionId", description = "消费订单ID", required = true)
|
||||||
|
@PreAuthorize("@ss.hasPermission('prison:consumption:query')")
|
||||||
|
public CommonResult<List<ConsumptionDetailRespVO>> getConsumptionDetailList(
|
||||||
|
@RequestParam("consumptionId") Long consumptionId) {
|
||||||
|
List<ConsumptionDetailDO> detailList = consumptionService.getConsumptionDetailList(consumptionId);
|
||||||
|
return success(ConsumptionDetailConvert.INSTANCE.convertListResp(detailList));
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/export-excel")
|
@GetMapping("/export-excel")
|
||||||
@Operation(summary = "导出消费记录 Excel")
|
@Operation(summary = "导出消费订单 Excel")
|
||||||
@PreAuthorize("@ss.hasPermission('prison:consumption:export')")
|
@PreAuthorize("@ss.hasPermission('prison:consumption:export')")
|
||||||
@ApiAccessLog(operateType = EXPORT)
|
@ApiAccessLog(operateType = EXPORT)
|
||||||
public void exportConsumptionExcel(@Valid ConsumptionPageReqVO pageReqVO,
|
public void exportConsumptionExcel(@Valid ConsumptionPageReqVO pageReqVO,
|
||||||
@ -97,8 +118,8 @@ public class PrisonConsumptionController {
|
|||||||
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
|
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
|
||||||
List<ConsumptionDO> list = consumptionService.getConsumptionPage(pageReqVO).getList();
|
List<ConsumptionDO> list = consumptionService.getConsumptionPage(pageReqVO).getList();
|
||||||
// 导出 Excel
|
// 导出 Excel
|
||||||
ExcelUtils.write(response, "消费记录.xls", "数据", ConsumptionRespVO.class,
|
ExcelUtils.write(response, "消费订单.xls", "数据", ConsumptionRespVO.class,
|
||||||
BeanUtils.toBean(list, ConsumptionRespVO.class));
|
ConsumptionConvert.INSTANCE.convertList(list));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,41 @@
|
|||||||
|
package cn.iocoder.yudao.module.prison.controller.admin.consumption.vo;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.*;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import cn.idev.excel.annotation.*;
|
||||||
|
|
||||||
|
@Schema(description = "管理后台 - 消费订单明细 Response VO")
|
||||||
|
@Data
|
||||||
|
@ExcelIgnoreUnannotated
|
||||||
|
public class ConsumptionDetailRespVO {
|
||||||
|
|
||||||
|
@Schema(description = "明细ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "4042")
|
||||||
|
@ExcelProperty("明细ID")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Schema(description = "消费订单ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||||
|
@ExcelProperty("消费订单ID")
|
||||||
|
private Long consumptionId;
|
||||||
|
|
||||||
|
@Schema(description = "商品名称", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
@ExcelProperty("商品名称")
|
||||||
|
private String goodsName;
|
||||||
|
|
||||||
|
@Schema(description = "商品编码")
|
||||||
|
@ExcelProperty("商品编码")
|
||||||
|
private String goodsCode;
|
||||||
|
|
||||||
|
@Schema(description = "商品单价", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
@ExcelProperty("商品单价")
|
||||||
|
private BigDecimal goodsPrice;
|
||||||
|
|
||||||
|
@Schema(description = "商品数量", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
@ExcelProperty("商品数量")
|
||||||
|
private Integer goodsCount;
|
||||||
|
|
||||||
|
@Schema(description = "小计金额", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
@ExcelProperty("小计金额")
|
||||||
|
private BigDecimal subtotal;
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
package cn.iocoder.yudao.module.prison.controller.admin.consumption.vo;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.*;
|
||||||
|
import java.util.*;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import jakarta.validation.constraints.*;
|
||||||
|
import org.springframework.format.annotation.DateTimeFormat;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import cn.idev.excel.annotation.*;
|
||||||
|
|
||||||
|
@Schema(description = "管理后台 - 消费订单明细新增/修改 Request VO")
|
||||||
|
@Data
|
||||||
|
public class ConsumptionDetailSaveReqVO {
|
||||||
|
|
||||||
|
@Schema(description = "明细ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "4042")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Schema(description = "商品名称", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
@NotEmpty(message = "商品名称不能为空")
|
||||||
|
private String goodsName;
|
||||||
|
|
||||||
|
@Schema(description = "商品编码")
|
||||||
|
private String goodsCode;
|
||||||
|
|
||||||
|
@Schema(description = "商品单价", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
@NotNull(message = "商品单价不能为空")
|
||||||
|
private BigDecimal goodsPrice;
|
||||||
|
|
||||||
|
@Schema(description = "商品数量", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
@NotNull(message = "商品数量不能为空")
|
||||||
|
private Integer goodsCount;
|
||||||
|
|
||||||
|
}
|
||||||
@ -7,35 +7,39 @@ import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
|||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import org.springframework.format.annotation.DateTimeFormat;
|
import org.springframework.format.annotation.DateTimeFormat;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
import jakarta.validation.constraints.Max;
|
||||||
|
import jakarta.validation.constraints.Min;
|
||||||
|
import jakarta.validation.constraints.Size;
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||||
|
|
||||||
@Schema(description = "管理后台 - 消费记录分页 Request VO")
|
@Schema(description = "管理后台 - 消费订单分页 Request VO")
|
||||||
@Data
|
@Data
|
||||||
public class ConsumptionPageReqVO extends PageParam {
|
public class ConsumptionPageReqVO extends PageParam {
|
||||||
|
|
||||||
@Schema(description = "罪犯ID", example = "25932")
|
@Schema(description = "罪犯ID", example = "25932")
|
||||||
|
@Min(value = 1, message = "罪犯ID必须为正数")
|
||||||
private Long prisonerId;
|
private Long prisonerId;
|
||||||
|
|
||||||
@Schema(description = "罪犯编号")
|
@Schema(description = "罪犯编号")
|
||||||
|
@Size(max = 50, message = "罪犯编号长度不能超过50个字符")
|
||||||
private String prisonerNo;
|
private String prisonerNo;
|
||||||
|
|
||||||
@Schema(description = "类型:1-存款 2-消费 3-转账", example = "1")
|
@Schema(description = "类型:1-购物 2-餐饮 3-医疗 4-通讯 5-其他", example = "1")
|
||||||
|
@Min(value = 1, message = "类型最小值为1")
|
||||||
|
@Max(value = 5, message = "类型最大值为5")
|
||||||
private Integer type;
|
private Integer type;
|
||||||
|
|
||||||
@Schema(description = "金额")
|
@Schema(description = "订单总金额")
|
||||||
private BigDecimal amount;
|
@Min(value = 0, message = "订单总金额不能为负数")
|
||||||
|
private BigDecimal totalAmount;
|
||||||
|
|
||||||
@Schema(description = "账户余额")
|
@Schema(description = "账户余额")
|
||||||
|
@Min(value = 0, message = "账户余额不能为负数")
|
||||||
private BigDecimal balance;
|
private BigDecimal balance;
|
||||||
|
|
||||||
@Schema(description = "商品名称", example = "芋艿")
|
|
||||||
private String goodsName;
|
|
||||||
|
|
||||||
@Schema(description = "商品数量", example = "3906")
|
|
||||||
private Integer goodsCount;
|
|
||||||
|
|
||||||
@Schema(description = "订单号")
|
@Schema(description = "订单号")
|
||||||
|
@Size(max = 64, message = "订单号长度不能超过64个字符")
|
||||||
private String orderNo;
|
private String orderNo;
|
||||||
|
|
||||||
@Schema(description = "交易时间")
|
@Schema(description = "交易时间")
|
||||||
@ -43,13 +47,16 @@ public class ConsumptionPageReqVO extends PageParam {
|
|||||||
private LocalDateTime[] tradeTime;
|
private LocalDateTime[] tradeTime;
|
||||||
|
|
||||||
@Schema(description = "状态:1-成功 2-失败", example = "1")
|
@Schema(description = "状态:1-成功 2-失败", example = "1")
|
||||||
|
@Min(value = 1, message = "状态最小值为1")
|
||||||
|
@Max(value = 2, message = "状态最大值为2")
|
||||||
private Integer status;
|
private Integer status;
|
||||||
|
|
||||||
@Schema(description = "备注", example = "你说的对")
|
|
||||||
private String remark;
|
|
||||||
|
|
||||||
@Schema(description = "创建时间")
|
@Schema(description = "创建时间")
|
||||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||||
private LocalDateTime[] createTime;
|
private LocalDateTime[] createTime;
|
||||||
|
|
||||||
}
|
@Schema(description = "备注")
|
||||||
|
@Size(max = 500, message = "备注长度不能超过500个字符")
|
||||||
|
private String remark;
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@ -8,13 +8,13 @@ import org.springframework.format.annotation.DateTimeFormat;
|
|||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import cn.idev.excel.annotation.*;
|
import cn.idev.excel.annotation.*;
|
||||||
|
|
||||||
@Schema(description = "管理后台 - 消费记录 Response VO")
|
@Schema(description = "管理后台 - 消费订单 Response VO")
|
||||||
@Data
|
@Data
|
||||||
@ExcelIgnoreUnannotated
|
@ExcelIgnoreUnannotated
|
||||||
public class ConsumptionRespVO {
|
public class ConsumptionRespVO {
|
||||||
|
|
||||||
@Schema(description = "记录ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "4042")
|
@Schema(description = "消费ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "4042")
|
||||||
@ExcelProperty("记录ID")
|
@ExcelProperty("消费ID")
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
@Schema(description = "罪犯ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "25932")
|
@Schema(description = "罪犯ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "25932")
|
||||||
@ -25,39 +25,31 @@ public class ConsumptionRespVO {
|
|||||||
@ExcelProperty("罪犯编号")
|
@ExcelProperty("罪犯编号")
|
||||||
private String prisonerNo;
|
private String prisonerNo;
|
||||||
|
|
||||||
@Schema(description = "类型:1-存款 2-消费 3-转账", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
|
||||||
@ExcelProperty("类型:1-存款 2-消费 3-转账")
|
|
||||||
private Integer type;
|
|
||||||
|
|
||||||
@Schema(description = "金额", requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
@ExcelProperty("金额")
|
|
||||||
private BigDecimal amount;
|
|
||||||
|
|
||||||
@Schema(description = "账户余额")
|
|
||||||
@ExcelProperty("账户余额")
|
|
||||||
private BigDecimal balance;
|
|
||||||
|
|
||||||
@Schema(description = "商品名称", example = "芋艿")
|
|
||||||
@ExcelProperty("商品名称")
|
|
||||||
private String goodsName;
|
|
||||||
|
|
||||||
@Schema(description = "商品数量", example = "3906")
|
|
||||||
@ExcelProperty("商品数量")
|
|
||||||
private Integer goodsCount;
|
|
||||||
|
|
||||||
@Schema(description = "订单号")
|
@Schema(description = "订单号")
|
||||||
@ExcelProperty("订单号")
|
@ExcelProperty("订单号")
|
||||||
private String orderNo;
|
private String orderNo;
|
||||||
|
|
||||||
|
@Schema(description = "类型:1-购物 2-餐饮 3-医疗 4-通讯 5-其他", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||||
|
@ExcelProperty("类型")
|
||||||
|
private Integer type;
|
||||||
|
|
||||||
|
@Schema(description = "订单总金额", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
@ExcelProperty("订单总金额")
|
||||||
|
private BigDecimal totalAmount;
|
||||||
|
|
||||||
|
@Schema(description = "账户余额(消费后)")
|
||||||
|
@ExcelProperty("账户余额")
|
||||||
|
private BigDecimal balance;
|
||||||
|
|
||||||
@Schema(description = "交易时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
@Schema(description = "交易时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
@ExcelProperty("交易时间")
|
@ExcelProperty("交易时间")
|
||||||
private LocalDateTime tradeTime;
|
private LocalDateTime tradeTime;
|
||||||
|
|
||||||
@Schema(description = "状态:1-成功 2-失败", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
@Schema(description = "状态:1-成功 2-失败", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||||
@ExcelProperty("状态:1-成功 2-失败")
|
@ExcelProperty("状态")
|
||||||
private Integer status;
|
private Integer status;
|
||||||
|
|
||||||
@Schema(description = "备注", example = "你说的对")
|
@Schema(description = "备注", example = "订单备注")
|
||||||
@ExcelProperty("备注")
|
@ExcelProperty("备注")
|
||||||
private String remark;
|
private String remark;
|
||||||
|
|
||||||
@ -65,4 +57,7 @@ public class ConsumptionRespVO {
|
|||||||
@ExcelProperty("创建时间")
|
@ExcelProperty("创建时间")
|
||||||
private LocalDateTime createTime;
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
}
|
@Schema(description = "消费明细列表")
|
||||||
|
private List<ConsumptionDetailRespVO> details;
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@ -8,11 +8,11 @@ import java.math.BigDecimal;
|
|||||||
import org.springframework.format.annotation.DateTimeFormat;
|
import org.springframework.format.annotation.DateTimeFormat;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
@Schema(description = "管理后台 - 消费记录新增/修改 Request VO")
|
@Schema(description = "管理后台 - 消费订单新增/修改 Request VO")
|
||||||
@Data
|
@Data
|
||||||
public class ConsumptionSaveReqVO {
|
public class ConsumptionSaveReqVO {
|
||||||
|
|
||||||
@Schema(description = "记录ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "4042")
|
@Schema(description = "消费ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "4042")
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
@Schema(description = "罪犯ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "25932")
|
@Schema(description = "罪犯ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "25932")
|
||||||
@ -23,35 +23,32 @@ public class ConsumptionSaveReqVO {
|
|||||||
@NotEmpty(message = "罪犯编号不能为空")
|
@NotEmpty(message = "罪犯编号不能为空")
|
||||||
private String prisonerNo;
|
private String prisonerNo;
|
||||||
|
|
||||||
@Schema(description = "类型:1-存款 2-消费 3-转账", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
|
||||||
@NotNull(message = "类型:1-存款 2-消费 3-转账不能为空")
|
|
||||||
private Integer type;
|
|
||||||
|
|
||||||
@Schema(description = "金额", requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
@NotNull(message = "金额不能为空")
|
|
||||||
private BigDecimal amount;
|
|
||||||
|
|
||||||
@Schema(description = "账户余额")
|
|
||||||
private BigDecimal balance;
|
|
||||||
|
|
||||||
@Schema(description = "商品名称", example = "芋艿")
|
|
||||||
private String goodsName;
|
|
||||||
|
|
||||||
@Schema(description = "商品数量", example = "3906")
|
|
||||||
private Integer goodsCount;
|
|
||||||
|
|
||||||
@Schema(description = "订单号")
|
@Schema(description = "订单号")
|
||||||
private String orderNo;
|
private String orderNo;
|
||||||
|
|
||||||
|
@Schema(description = "类型:1-购物 2-餐饮 3-医疗 4-通讯 5-其他", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||||
|
@NotNull(message = "类型不能为空")
|
||||||
|
private Integer type;
|
||||||
|
|
||||||
|
@Schema(description = "订单总金额", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
@NotNull(message = "订单总金额不能为空")
|
||||||
|
private BigDecimal totalAmount;
|
||||||
|
|
||||||
|
@Schema(description = "账户余额(消费后)")
|
||||||
|
private BigDecimal balance;
|
||||||
|
|
||||||
@Schema(description = "交易时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
@Schema(description = "交易时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
@NotNull(message = "交易时间不能为空")
|
@NotNull(message = "交易时间不能为空")
|
||||||
private LocalDateTime tradeTime;
|
private LocalDateTime tradeTime;
|
||||||
|
|
||||||
@Schema(description = "状态:1-成功 2-失败", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
@Schema(description = "状态:1-成功 2-失败", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||||
@NotNull(message = "状态:1-成功 2-失败不能为空")
|
@NotNull(message = "状态不能为空")
|
||||||
private Integer status;
|
private Integer status;
|
||||||
|
|
||||||
@Schema(description = "备注", example = "你说的对")
|
@Schema(description = "备注", example = "订单备注")
|
||||||
private String remark;
|
private String remark;
|
||||||
|
|
||||||
}
|
@Schema(description = "消费明细列表")
|
||||||
|
private List<ConsumptionDetailSaveReqVO> details;
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@ -63,9 +63,9 @@ public class PrisonQuestionnaireController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@DeleteMapping("/delete-list")
|
@DeleteMapping("/delete-list")
|
||||||
@Parameter(name = "ids", description = "编号", required = true)
|
@Parameter(name = "ids", description = "编号列表", required = true)
|
||||||
@Operation(summary = "批量删除问卷模板")
|
@Operation(summary = "批量删除问卷模板")
|
||||||
@PreAuthorize("@ss.hasPermission('prison:questionnaire:delete')")
|
@PreAuthorize("@ss.hasPermission('prison:questionnaire:delete')")
|
||||||
public CommonResult<Boolean> deleteQuestionnaireList(@NotEmpty(message = "编号列表不能为空") @RequestParam("ids") List<Long> ids) {
|
public CommonResult<Boolean> deleteQuestionnaireList(@NotEmpty(message = "编号列表不能为空") @RequestParam("ids") List<Long> ids) {
|
||||||
questionnaireService.deleteQuestionnaireListByIds(ids);
|
questionnaireService.deleteQuestionnaireListByIds(ids);
|
||||||
return success(true);
|
return success(true);
|
||||||
|
|||||||
@ -13,6 +13,7 @@ import jakarta.validation.*;
|
|||||||
import jakarta.servlet.http.*;
|
import jakarta.servlet.http.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
@ -29,7 +30,7 @@ import cn.iocoder.yudao.module.prison.controller.admin.questionnairerecord.vo.*;
|
|||||||
import cn.iocoder.yudao.module.prison.dal.dataobject.questionnairerecord.QuestionnaireRecordDO;
|
import cn.iocoder.yudao.module.prison.dal.dataobject.questionnairerecord.QuestionnaireRecordDO;
|
||||||
import cn.iocoder.yudao.module.prison.service.questionnairerecord.QuestionnaireRecordService;
|
import cn.iocoder.yudao.module.prison.service.questionnairerecord.QuestionnaireRecordService;
|
||||||
|
|
||||||
@Tag(name = "管理后台 - 问卷答题记录")
|
@Tag(name = "管理后台 - 问卷答题记录/测评记录")
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/prison/questionnaire-record")
|
@RequestMapping("/prison/questionnaire-record")
|
||||||
@Validated
|
@Validated
|
||||||
@ -38,6 +39,8 @@ public class PrisonQuestionnaireRecordController {
|
|||||||
@Resource
|
@Resource
|
||||||
private QuestionnaireRecordService questionnaireRecordService;
|
private QuestionnaireRecordService questionnaireRecordService;
|
||||||
|
|
||||||
|
// ==================== 基础 CRUD ====================
|
||||||
|
|
||||||
@PostMapping("/create")
|
@PostMapping("/create")
|
||||||
@Operation(summary = "创建问卷答题记录")
|
@Operation(summary = "创建问卷答题记录")
|
||||||
@PreAuthorize("@ss.hasPermission('prison:questionnaire-record:create')")
|
@PreAuthorize("@ss.hasPermission('prison:questionnaire-record:create')")
|
||||||
@ -62,11 +65,10 @@ public class PrisonQuestionnaireRecordController {
|
|||||||
return success(true);
|
return success(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@DeleteMapping("/delete-list")
|
@PostMapping("/delete-list")
|
||||||
@Parameter(name = "ids", description = "编号", required = true)
|
|
||||||
@Operation(summary = "批量删除问卷答题记录")
|
@Operation(summary = "批量删除问卷答题记录")
|
||||||
@PreAuthorize("@ss.hasPermission('prison:questionnaire-record:delete')")
|
@PreAuthorize("@ss.hasPermission('prison:questionnaire-record:delete')")
|
||||||
public CommonResult<Boolean> deleteQuestionnaireRecordList(@NotEmpty(message = "编号列表不能为空") @RequestParam("ids") List<Long> ids) {
|
public CommonResult<Boolean> deleteQuestionnaireRecordList(@NotEmpty(message = "编号列表不能为空") @RequestBody List<Long> ids) {
|
||||||
questionnaireRecordService.deleteQuestionnaireRecordListByIds(ids);
|
questionnaireRecordService.deleteQuestionnaireRecordListByIds(ids);
|
||||||
return success(true);
|
return success(true);
|
||||||
}
|
}
|
||||||
@ -75,7 +77,7 @@ public class PrisonQuestionnaireRecordController {
|
|||||||
@Operation(summary = "获得问卷答题记录")
|
@Operation(summary = "获得问卷答题记录")
|
||||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||||
@PreAuthorize("@ss.hasPermission('prison:questionnaire-record:query')")
|
@PreAuthorize("@ss.hasPermission('prison:questionnaire-record:query')")
|
||||||
public CommonResult<QuestionnaireRecordRespVO> getQuestionnaireRecord(@RequestParam("id") Long id) {
|
public CommonResult<QuestionnaireRecordRespVO> getQuestionnaireRecord(@NotNull(message = "编号不能为空") @RequestParam("id") Long id) {
|
||||||
QuestionnaireRecordDO questionnaireRecord = questionnaireRecordService.getQuestionnaireRecord(id);
|
QuestionnaireRecordDO questionnaireRecord = questionnaireRecordService.getQuestionnaireRecord(id);
|
||||||
return success(BeanUtils.toBean(questionnaireRecord, QuestionnaireRecordRespVO.class));
|
return success(BeanUtils.toBean(questionnaireRecord, QuestionnaireRecordRespVO.class));
|
||||||
}
|
}
|
||||||
@ -101,4 +103,87 @@ public class PrisonQuestionnaireRecordController {
|
|||||||
BeanUtils.toBean(list, QuestionnaireRecordRespVO.class));
|
BeanUtils.toBean(list, QuestionnaireRecordRespVO.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
// ==================== 测评执行相关 ====================
|
||||||
|
|
||||||
|
@PostMapping("/initiate")
|
||||||
|
@Operation(summary = "发起测评")
|
||||||
|
@PreAuthorize("@ss.hasPermission('prison:questionnaire-record:initiate')")
|
||||||
|
public CommonResult<Long> initiateAssessment(@Valid @RequestBody AssessmentInitiateReqVO reqVO) {
|
||||||
|
return success(questionnaireRecordService.initiateAssessment(reqVO));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/start")
|
||||||
|
@Operation(summary = "开始测评")
|
||||||
|
@PreAuthorize("@ss.hasPermission('prison:questionnaire-record:start')")
|
||||||
|
public CommonResult<Boolean> startAssessment(@NotNull(message = "记录ID不能为空") @RequestParam("id") Long id,
|
||||||
|
@NotNull(message = "罪犯ID不能为空") @RequestParam("prisonerId") Long prisonerId) {
|
||||||
|
questionnaireRecordService.startAssessment(id, prisonerId);
|
||||||
|
return success(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/submit")
|
||||||
|
@Operation(summary = "提交答卷")
|
||||||
|
@PreAuthorize("@ss.hasPermission('prison:questionnaire-record:submit')")
|
||||||
|
public CommonResult<Boolean> submitAnswer(@Valid @RequestBody AssessmentAnswerSubmitReqVO reqVO) {
|
||||||
|
questionnaireRecordService.submitAnswer(reqVO);
|
||||||
|
return success(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/finish")
|
||||||
|
@Operation(summary = "结束测评")
|
||||||
|
@PreAuthorize("@ss.hasPermission('prison:questionnaire-record:finish')")
|
||||||
|
public CommonResult<Boolean> finishAssessment(@NotNull(message = "记录ID不能为空") @RequestParam("id") Long id) {
|
||||||
|
questionnaireRecordService.finishAssessment(id);
|
||||||
|
return success(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/cancel")
|
||||||
|
@Operation(summary = "取消测评")
|
||||||
|
@PreAuthorize("@ss.hasPermission('prison:questionnaire-record:cancel')")
|
||||||
|
public CommonResult<Boolean> cancelAssessment(@NotNull(message = "记录ID不能为空") @RequestParam("id") Long id) {
|
||||||
|
questionnaireRecordService.cancelAssessment(id);
|
||||||
|
return success(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 评分相关 ====================
|
||||||
|
|
||||||
|
@PostMapping("/auto-score")
|
||||||
|
@Operation(summary = "自动评分")
|
||||||
|
@PreAuthorize("@ss.hasPermission('prison:questionnaire-record:score')")
|
||||||
|
public CommonResult<Boolean> autoScore(@NotNull(message = "记录ID不能为空") @RequestParam("id") Long id) {
|
||||||
|
questionnaireRecordService.autoScore(id);
|
||||||
|
return success(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/manual-score")
|
||||||
|
@Operation(summary = "人工评分")
|
||||||
|
@PreAuthorize("@ss.hasPermission('prison:questionnaire-record:score')")
|
||||||
|
public CommonResult<Boolean> manualScore(@Valid @RequestBody AssessmentManualScoreReqVO reqVO) {
|
||||||
|
questionnaireRecordService.manualScore(reqVO);
|
||||||
|
return success(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 统计相关 ====================
|
||||||
|
|
||||||
|
@GetMapping("/completion-rate")
|
||||||
|
@Operation(summary = "获取完成率")
|
||||||
|
@PreAuthorize("@ss.hasPermission('prison:questionnaire-record:query')")
|
||||||
|
public CommonResult<BigDecimal> getCompletionRate(@NotNull(message = "测评记录ID不能为空") @RequestParam("assessmentRecordId") Long assessmentRecordId) {
|
||||||
|
return success(questionnaireRecordService.getCompletionRate(assessmentRecordId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/score-distribution")
|
||||||
|
@Operation(summary = "获取分数分布")
|
||||||
|
@PreAuthorize("@ss.hasPermission('prison:questionnaire-record:query')")
|
||||||
|
public CommonResult<Map<String, Integer>> getScoreDistribution(@NotNull(message = "测评记录ID不能为空") @RequestParam("assessmentRecordId") Long assessmentRecordId) {
|
||||||
|
return success(questionnaireRecordService.getScoreDistribution(assessmentRecordId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/risk-distribution")
|
||||||
|
@Operation(summary = "获取风险分布")
|
||||||
|
@PreAuthorize("@ss.hasPermission('prison:questionnaire-record:query')")
|
||||||
|
public CommonResult<Map<String, Integer>> getRiskDistribution(@NotNull(message = "测评记录ID不能为空") @RequestParam("assessmentRecordId") Long assessmentRecordId) {
|
||||||
|
return success(questionnaireRecordService.getRiskDistribution(assessmentRecordId));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@ -0,0 +1,38 @@
|
|||||||
|
package cn.iocoder.yudao.module.prison.controller.admin.questionnairerecord.vo;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import jakarta.validation.constraints.NotEmpty;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import lombok.Data;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提交答卷 Request VO
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class AssessmentAnswerSubmitReqVO {
|
||||||
|
|
||||||
|
@Schema(description = "测评记录ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||||
|
@NotNull(message = "测评记录不能为空")
|
||||||
|
private Long recordId;
|
||||||
|
|
||||||
|
@Schema(description = "罪犯ID", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
@NotNull(message = "罪犯不能为空")
|
||||||
|
private Long prisonerId;
|
||||||
|
|
||||||
|
@Schema(description = "答案列表")
|
||||||
|
private List<AnswerItem> answers;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public static class AnswerItem {
|
||||||
|
@Schema(description = "题目ID", example = "1024")
|
||||||
|
private Long questionId;
|
||||||
|
@Schema(description = "答案内容")
|
||||||
|
private String answer;
|
||||||
|
@Schema(description = "选项ID列表(多选用)")
|
||||||
|
private List<Long> optionIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,32 @@
|
|||||||
|
package cn.iocoder.yudao.module.prison.controller.admin.questionnairerecord.vo;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import jakarta.validation.constraints.NotEmpty;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import lombok.Data;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发起测评 Request VO
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class AssessmentInitiateReqVO {
|
||||||
|
|
||||||
|
@Schema(description = "问卷ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||||
|
@NotNull(message = "问卷不能为空")
|
||||||
|
private Long questionnaireId;
|
||||||
|
|
||||||
|
@Schema(description = "罪犯ID列表", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
@NotEmpty(message = "罪犯不能为空")
|
||||||
|
private List<Long> prisonerIds;
|
||||||
|
|
||||||
|
@Schema(description = "测评说明")
|
||||||
|
private String remark;
|
||||||
|
|
||||||
|
@Schema(description = "截止日期")
|
||||||
|
private LocalDateTime deadline;
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package cn.iocoder.yudao.module.prison.controller.admin.assessment.vo;
|
package cn.iocoder.yudao.module.prison.controller.admin.questionnairerecord.vo;
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
@ -11,11 +11,11 @@ import java.math.BigDecimal;
|
|||||||
* @author 芋道源码
|
* @author 芋道源码
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
public class AssessmentAnswerManualScoreReqVO {
|
public class AssessmentManualScoreReqVO {
|
||||||
|
|
||||||
@Schema(description = "答卷ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
@Schema(description = "测评记录ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||||
@NotNull(message = "答卷ID不能为空")
|
@NotNull(message = "测评记录不能为空")
|
||||||
private Long id;
|
private Long recordId;
|
||||||
|
|
||||||
@Schema(description = "主观题得分", requiredMode = Schema.RequiredMode.REQUIRED)
|
@Schema(description = "主观题得分", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
@NotNull(message = "主观题得分不能为空")
|
@NotNull(message = "主观题得分不能为空")
|
||||||
@ -24,4 +24,7 @@ public class AssessmentAnswerManualScoreReqVO {
|
|||||||
@Schema(description = "评语")
|
@Schema(description = "评语")
|
||||||
private String comment;
|
private String comment;
|
||||||
|
|
||||||
|
@Schema(description = "风险等级:1-高风险 2-中风险 3-低风险")
|
||||||
|
private Integer riskLevel;
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -10,34 +10,51 @@ import java.time.LocalDateTime;
|
|||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||||
|
|
||||||
@Schema(description = "管理后台 - 问卷答题记录分页 Request VO")
|
/**
|
||||||
|
* 管理后台 - 问卷答题记录/测评记录分页 Request VO
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
@Data
|
@Data
|
||||||
public class QuestionnaireRecordPageReqVO extends PageParam {
|
public class QuestionnaireRecordPageReqVO extends PageParam {
|
||||||
|
|
||||||
@Schema(description = "问卷ID", example = "18966")
|
@Schema(description = "问卷ID", example = "18966")
|
||||||
private Long questionnaireId;
|
private Long questionnaireId;
|
||||||
|
|
||||||
|
@Schema(description = "问卷名称", example = "心理测评")
|
||||||
|
private String questionnaireName;
|
||||||
|
|
||||||
@Schema(description = "罪犯ID", example = "4071")
|
@Schema(description = "罪犯ID", example = "4071")
|
||||||
private Long prisonerId;
|
private Long prisonerId;
|
||||||
|
|
||||||
@Schema(description = "罪犯编号")
|
@Schema(description = "罪犯编号")
|
||||||
private String prisonerNo;
|
private String prisonerNo;
|
||||||
|
|
||||||
@Schema(description = "得分")
|
@Schema(description = "罪犯姓名")
|
||||||
private BigDecimal totalScore;
|
private String prisonerName;
|
||||||
|
|
||||||
@Schema(description = "是否及格:1-及格 2-不及格", example = "2")
|
@Schema(description = "状态:1-待测评 2-测评中 3-已完成 4-已过期 5-已取消", example = "1")
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
@Schema(description = "及格状态:1-及格 2-不及格 3-待评阅", example = "1")
|
||||||
private Integer passStatus;
|
private Integer passStatus;
|
||||||
|
|
||||||
@Schema(description = "答题时间")
|
@Schema(description = "风险等级:1-高风险 2-中风险 3-低风险", example = "3")
|
||||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
private Integer riskLevel;
|
||||||
private LocalDateTime[] answerTime;
|
|
||||||
|
|
||||||
@Schema(description = "状态:1-已完成 2-已过期", example = "1")
|
@Schema(description = "总分")
|
||||||
private Integer status;
|
private BigDecimal totalScore;
|
||||||
|
|
||||||
|
@Schema(description = "测评开始时间")
|
||||||
|
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||||
|
private LocalDateTime[] startTime;
|
||||||
|
|
||||||
|
@Schema(description = "测评截止时间")
|
||||||
|
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||||
|
private LocalDateTime[] deadline;
|
||||||
|
|
||||||
@Schema(description = "创建时间")
|
@Schema(description = "创建时间")
|
||||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||||
private LocalDateTime[] createTime;
|
private LocalDateTime[] createTime;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,6 +8,11 @@ import org.springframework.format.annotation.DateTimeFormat;
|
|||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import cn.idev.excel.annotation.*;
|
import cn.idev.excel.annotation.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 管理后台 - 问卷答题记录/测评记录 Response VO
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
@Schema(description = "管理后台 - 问卷答题记录 Response VO")
|
@Schema(description = "管理后台 - 问卷答题记录 Response VO")
|
||||||
@Data
|
@Data
|
||||||
@ExcelIgnoreUnannotated
|
@ExcelIgnoreUnannotated
|
||||||
@ -17,10 +22,18 @@ public class QuestionnaireRecordRespVO {
|
|||||||
@ExcelProperty("记录ID")
|
@ExcelProperty("记录ID")
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
|
// ==================== 问卷信息 ====================
|
||||||
|
|
||||||
@Schema(description = "问卷ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "18966")
|
@Schema(description = "问卷ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "18966")
|
||||||
@ExcelProperty("问卷ID")
|
@ExcelProperty("问卷ID")
|
||||||
private Long questionnaireId;
|
private Long questionnaireId;
|
||||||
|
|
||||||
|
@Schema(description = "问卷名称")
|
||||||
|
@ExcelProperty("问卷名称")
|
||||||
|
private String questionnaireName;
|
||||||
|
|
||||||
|
// ==================== 罪犯信息 ====================
|
||||||
|
|
||||||
@Schema(description = "罪犯ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "4071")
|
@Schema(description = "罪犯ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "4071")
|
||||||
@ExcelProperty("罪犯ID")
|
@ExcelProperty("罪犯ID")
|
||||||
private Long prisonerId;
|
private Long prisonerId;
|
||||||
@ -29,24 +42,90 @@ public class QuestionnaireRecordRespVO {
|
|||||||
@ExcelProperty("罪犯编号")
|
@ExcelProperty("罪犯编号")
|
||||||
private String prisonerNo;
|
private String prisonerNo;
|
||||||
|
|
||||||
@Schema(description = "得分")
|
@Schema(description = "罪犯姓名")
|
||||||
@ExcelProperty("得分")
|
@ExcelProperty("罪犯姓名")
|
||||||
|
private String prisonerName;
|
||||||
|
|
||||||
|
// ==================== 测评状态 ====================
|
||||||
|
|
||||||
|
@Schema(description = "状态:1-待测评 2-测评中 3-已完成 4-已过期 5-已取消", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||||
|
@ExcelProperty("状态")
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
// ==================== 测评时间 ====================
|
||||||
|
|
||||||
|
@Schema(description = "开始时间")
|
||||||
|
@ExcelProperty("开始时间")
|
||||||
|
private LocalDateTime startTime;
|
||||||
|
|
||||||
|
@Schema(description = "结束时间")
|
||||||
|
@ExcelProperty("结束时间")
|
||||||
|
private LocalDateTime endTime;
|
||||||
|
|
||||||
|
@Schema(description = "截止日期")
|
||||||
|
@ExcelProperty("截止日期")
|
||||||
|
private LocalDateTime deadline;
|
||||||
|
|
||||||
|
// ==================== 评分信息 ====================
|
||||||
|
|
||||||
|
@Schema(description = "客观题得分")
|
||||||
|
@ExcelProperty("客观题得分")
|
||||||
|
private BigDecimal objectiveScore;
|
||||||
|
|
||||||
|
@Schema(description = "主观题得分")
|
||||||
|
@ExcelProperty("主观题得分")
|
||||||
|
private BigDecimal subjectiveScore;
|
||||||
|
|
||||||
|
@Schema(description = "总分")
|
||||||
|
@ExcelProperty("总分")
|
||||||
private BigDecimal totalScore;
|
private BigDecimal totalScore;
|
||||||
|
|
||||||
@Schema(description = "是否及格:1-及格 2-不及格", example = "2")
|
@Schema(description = "及格分数")
|
||||||
@ExcelProperty("是否及格:1-及格 2-不及格")
|
@ExcelProperty("及格分数")
|
||||||
|
private BigDecimal passScore;
|
||||||
|
|
||||||
|
@Schema(description = "及格状态:1-及格 2-不及格 3-待评阅", example = "2")
|
||||||
|
@ExcelProperty("及格状态")
|
||||||
private Integer passStatus;
|
private Integer passStatus;
|
||||||
|
|
||||||
@Schema(description = "答题时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
@Schema(description = "风险等级:1-高风险 2-中风险 3-低风险", example = "3")
|
||||||
@ExcelProperty("答题时间")
|
@ExcelProperty("风险等级")
|
||||||
private LocalDateTime answerTime;
|
private Integer riskLevel;
|
||||||
|
|
||||||
@Schema(description = "状态:1-已完成 2-已过期", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
// ==================== 评阅信息 ====================
|
||||||
@ExcelProperty("状态:1-已完成 2-已过期")
|
|
||||||
private Integer status;
|
@Schema(description = "评阅人ID")
|
||||||
|
private Long evaluatorId;
|
||||||
|
|
||||||
|
@Schema(description = "评阅人姓名")
|
||||||
|
@ExcelProperty("评阅人")
|
||||||
|
private String evaluatorName;
|
||||||
|
|
||||||
|
@Schema(description = "评阅时间")
|
||||||
|
@ExcelProperty("评阅时间")
|
||||||
|
private LocalDateTime evaluateTime;
|
||||||
|
|
||||||
|
// ==================== 统计信息 ====================
|
||||||
|
|
||||||
|
@Schema(description = "参与人数")
|
||||||
|
private Integer participantCount;
|
||||||
|
|
||||||
|
@Schema(description = "完成人数")
|
||||||
|
private Integer completedCount;
|
||||||
|
|
||||||
|
@Schema(description = "答题用时(秒)")
|
||||||
|
@ExcelProperty("答题用时")
|
||||||
|
private Integer duration;
|
||||||
|
|
||||||
|
// ==================== 备注 ====================
|
||||||
|
|
||||||
|
@Schema(description = "备注")
|
||||||
|
private String remark;
|
||||||
|
|
||||||
|
// ==================== 通用字段 ====================
|
||||||
|
|
||||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
@ExcelProperty("创建时间")
|
@ExcelProperty("创建时间")
|
||||||
private LocalDateTime createTime;
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,37 +8,100 @@ import java.math.BigDecimal;
|
|||||||
import org.springframework.format.annotation.DateTimeFormat;
|
import org.springframework.format.annotation.DateTimeFormat;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
@Schema(description = "管理后台 - 问卷答题记录新增/修改 Request VO")
|
/**
|
||||||
|
* 管理后台 - 问卷答题记录/测评记录新增/修改 Request VO
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
@Data
|
@Data
|
||||||
public class QuestionnaireRecordSaveReqVO {
|
public class QuestionnaireRecordSaveReqVO {
|
||||||
|
|
||||||
@Schema(description = "记录ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "8596")
|
@Schema(description = "记录ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "8596")
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
|
// ==================== 问卷信息 ====================
|
||||||
|
|
||||||
@Schema(description = "问卷ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "18966")
|
@Schema(description = "问卷ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "18966")
|
||||||
@NotNull(message = "问卷ID不能为空")
|
@NotNull(message = "问卷ID不能为空")
|
||||||
private Long questionnaireId;
|
private Long questionnaireId;
|
||||||
|
|
||||||
|
@Schema(description = "问卷名称")
|
||||||
|
private String questionnaireName;
|
||||||
|
|
||||||
|
// ==================== 罪犯信息 ====================
|
||||||
|
|
||||||
@Schema(description = "罪犯ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "4071")
|
@Schema(description = "罪犯ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "4071")
|
||||||
@NotNull(message = "罪犯ID不能为空")
|
@NotNull(message = "罪犯ID不能为空")
|
||||||
private Long prisonerId;
|
private Long prisonerId;
|
||||||
|
|
||||||
@Schema(description = "罪犯编号", requiredMode = Schema.RequiredMode.REQUIRED)
|
@Schema(description = "罪犯编号")
|
||||||
@NotEmpty(message = "罪犯编号不能为空")
|
|
||||||
private String prisonerNo;
|
private String prisonerNo;
|
||||||
|
|
||||||
@Schema(description = "得分")
|
@Schema(description = "罪犯姓名")
|
||||||
private BigDecimal totalScore;
|
private String prisonerName;
|
||||||
|
|
||||||
@Schema(description = "是否及格:1-及格 2-不及格", example = "2")
|
// ==================== 测评状态 ====================
|
||||||
private Integer passStatus;
|
|
||||||
|
|
||||||
@Schema(description = "答题时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
@Schema(description = "状态:1-待测评 2-测评中 3-已完成 4-已过期 5-已取消", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||||
@NotNull(message = "答题时间不能为空")
|
@NotNull(message = "状态不能为空")
|
||||||
private LocalDateTime answerTime;
|
|
||||||
|
|
||||||
@Schema(description = "状态:1-已完成 2-已过期", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
|
||||||
@NotNull(message = "状态:1-已完成 2-已过期不能为空")
|
|
||||||
private Integer status;
|
private Integer status;
|
||||||
|
|
||||||
}
|
// ==================== 测评时间 ====================
|
||||||
|
|
||||||
|
@Schema(description = "开始时间")
|
||||||
|
private LocalDateTime startTime;
|
||||||
|
|
||||||
|
@Schema(description = "结束时间")
|
||||||
|
private LocalDateTime endTime;
|
||||||
|
|
||||||
|
@Schema(description = "截止日期")
|
||||||
|
private LocalDateTime deadline;
|
||||||
|
|
||||||
|
// ==================== 评分信息 ====================
|
||||||
|
|
||||||
|
@Schema(description = "客观题得分")
|
||||||
|
private BigDecimal objectiveScore;
|
||||||
|
|
||||||
|
@Schema(description = "主观题得分")
|
||||||
|
private BigDecimal subjectiveScore;
|
||||||
|
|
||||||
|
@Schema(description = "总分")
|
||||||
|
private BigDecimal totalScore;
|
||||||
|
|
||||||
|
@Schema(description = "及格分数")
|
||||||
|
private BigDecimal passScore;
|
||||||
|
|
||||||
|
@Schema(description = "及格状态:1-及格 2-不及格 3-待评阅", example = "2")
|
||||||
|
private Integer passStatus;
|
||||||
|
|
||||||
|
@Schema(description = "风险等级:1-高风险 2-中风险 3-低风险", example = "3")
|
||||||
|
private Integer riskLevel;
|
||||||
|
|
||||||
|
// ==================== 评阅信息 ====================
|
||||||
|
|
||||||
|
@Schema(description = "评阅人ID")
|
||||||
|
private Long evaluatorId;
|
||||||
|
|
||||||
|
@Schema(description = "评阅人姓名")
|
||||||
|
private String evaluatorName;
|
||||||
|
|
||||||
|
@Schema(description = "评阅时间")
|
||||||
|
private LocalDateTime evaluateTime;
|
||||||
|
|
||||||
|
// ==================== 统计信息 ====================
|
||||||
|
|
||||||
|
@Schema(description = "参与人数")
|
||||||
|
private Integer participantCount;
|
||||||
|
|
||||||
|
@Schema(description = "完成人数")
|
||||||
|
private Integer completedCount;
|
||||||
|
|
||||||
|
@Schema(description = "答题用时(秒)")
|
||||||
|
private Integer duration;
|
||||||
|
|
||||||
|
// ==================== 备注 ====================
|
||||||
|
|
||||||
|
@Schema(description = "备注")
|
||||||
|
private String remark;
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@ -1,104 +0,0 @@
|
|||||||
package cn.iocoder.yudao.module.prison.controller.admin.riskassessment;
|
|
||||||
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
|
||||||
import jakarta.annotation.Resource;
|
|
||||||
import org.springframework.validation.annotation.Validated;
|
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
|
||||||
import io.swagger.v3.oas.annotations.Parameter;
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
|
||||||
|
|
||||||
import jakarta.validation.constraints.*;
|
|
||||||
import jakarta.validation.*;
|
|
||||||
import jakarta.servlet.http.*;
|
|
||||||
import java.util.*;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
|
||||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
|
||||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
|
|
||||||
import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.module.prison.controller.admin.riskassessment.vo.*;
|
|
||||||
import cn.iocoder.yudao.module.prison.dal.dataobject.riskassessment.RiskAssessmentDO;
|
|
||||||
import cn.iocoder.yudao.module.prison.service.riskassessment.RiskAssessmentService;
|
|
||||||
|
|
||||||
@Tag(name = "管理后台 - 危险评估")
|
|
||||||
@RestController
|
|
||||||
@RequestMapping("/prison/risk-assessment")
|
|
||||||
@Validated
|
|
||||||
public class PrisonRiskAssessmentController {
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private RiskAssessmentService riskAssessmentService;
|
|
||||||
|
|
||||||
@PostMapping("/create")
|
|
||||||
@Operation(summary = "创建危险评估")
|
|
||||||
@PreAuthorize("@ss.hasPermission('prison:risk-assessment:create')")
|
|
||||||
public CommonResult<Long> createRiskAssessment(@Valid @RequestBody RiskAssessmentSaveReqVO createReqVO) {
|
|
||||||
return success(riskAssessmentService.createRiskAssessment(createReqVO));
|
|
||||||
}
|
|
||||||
|
|
||||||
@PutMapping("/update")
|
|
||||||
@Operation(summary = "更新危险评估")
|
|
||||||
@PreAuthorize("@ss.hasPermission('prison:risk-assessment:update')")
|
|
||||||
public CommonResult<Boolean> updateRiskAssessment(@Valid @RequestBody RiskAssessmentSaveReqVO updateReqVO) {
|
|
||||||
riskAssessmentService.updateRiskAssessment(updateReqVO);
|
|
||||||
return success(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@DeleteMapping("/delete")
|
|
||||||
@Operation(summary = "删除危险评估")
|
|
||||||
@Parameter(name = "id", description = "编号", required = true)
|
|
||||||
@PreAuthorize("@ss.hasPermission('prison:risk-assessment:delete')")
|
|
||||||
public CommonResult<Boolean> deleteRiskAssessment(@NotNull(message = "编号不能为空") @RequestParam("id") Long id) {
|
|
||||||
riskAssessmentService.deleteRiskAssessment(id);
|
|
||||||
return success(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@DeleteMapping("/delete-list")
|
|
||||||
@Parameter(name = "ids", description = "编号", required = true)
|
|
||||||
@Operation(summary = "批量删除危险评估")
|
|
||||||
@PreAuthorize("@ss.hasPermission('prison:risk-assessment:delete')")
|
|
||||||
public CommonResult<Boolean> deleteRiskAssessmentList(@NotEmpty(message = "编号列表不能为空") @RequestParam("ids") List<Long> ids) {
|
|
||||||
riskAssessmentService.deleteRiskAssessmentListByIds(ids);
|
|
||||||
return success(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/get")
|
|
||||||
@Operation(summary = "获得危险评估")
|
|
||||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
|
||||||
@PreAuthorize("@ss.hasPermission('prison:risk-assessment:query')")
|
|
||||||
public CommonResult<RiskAssessmentRespVO> getRiskAssessment(@RequestParam("id") Long id) {
|
|
||||||
RiskAssessmentDO riskAssessment = riskAssessmentService.getRiskAssessment(id);
|
|
||||||
return success(BeanUtils.toBean(riskAssessment, RiskAssessmentRespVO.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/page")
|
|
||||||
@Operation(summary = "获得危险评估分页")
|
|
||||||
@PreAuthorize("@ss.hasPermission('prison:risk-assessment:query')")
|
|
||||||
public CommonResult<PageResult<RiskAssessmentRespVO>> getRiskAssessmentPage(@Valid RiskAssessmentPageReqVO pageReqVO) {
|
|
||||||
PageResult<RiskAssessmentDO> pageResult = riskAssessmentService.getRiskAssessmentPage(pageReqVO);
|
|
||||||
return success(BeanUtils.toBean(pageResult, RiskAssessmentRespVO.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/export-excel")
|
|
||||||
@Operation(summary = "导出危险评估 Excel")
|
|
||||||
@PreAuthorize("@ss.hasPermission('prison:risk-assessment:export')")
|
|
||||||
@ApiAccessLog(operateType = EXPORT)
|
|
||||||
public void exportRiskAssessmentExcel(@Valid RiskAssessmentPageReqVO pageReqVO,
|
|
||||||
HttpServletResponse response) throws IOException {
|
|
||||||
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
|
|
||||||
List<RiskAssessmentDO> list = riskAssessmentService.getRiskAssessmentPage(pageReqVO).getList();
|
|
||||||
// 导出 Excel
|
|
||||||
ExcelUtils.write(response, "危险评估.xls", "数据", RiskAssessmentRespVO.class,
|
|
||||||
BeanUtils.toBean(list, RiskAssessmentRespVO.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -0,0 +1,44 @@
|
|||||||
|
package cn.iocoder.yudao.module.prison.convert.answer;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.module.prison.controller.admin.answer.vo.*;
|
||||||
|
import cn.iocoder.yudao.module.prison.dal.dataobject.answer.AnswerDO;
|
||||||
|
|
||||||
|
import org.mapstruct.Builder;
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.factory.Mappers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 问卷答题记录 Convert
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Mapper(builder = @Builder(disableBuilder = true))
|
||||||
|
public interface AnswerConvert {
|
||||||
|
|
||||||
|
AnswerConvert INSTANCE = Mappers.getMapper(AnswerConvert.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DO -> RespVO
|
||||||
|
*/
|
||||||
|
AnswerRespVO convert(AnswerDO bean);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DO -> RespVO List
|
||||||
|
*/
|
||||||
|
List<AnswerRespVO> convertList(List<AnswerDO> list);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PageResult DO -> PageResult RespVO
|
||||||
|
*/
|
||||||
|
PageResult<AnswerRespVO> convertPage(PageResult<AnswerDO> page);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SaveReqVO -> DO
|
||||||
|
*/
|
||||||
|
AnswerDO convert(AnswerSaveReqVO bean);
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,34 +0,0 @@
|
|||||||
package cn.iocoder.yudao.module.prison.convert.assessment;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
|
||||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.module.prison.dal.dataobject.assessment.AssessmentAnswerDO;
|
|
||||||
import cn.iocoder.yudao.module.prison.controller.admin.assessment.vo.*;
|
|
||||||
import org.mapstruct.Builder;
|
|
||||||
import org.mapstruct.Mapper;
|
|
||||||
import org.mapstruct.factory.Mappers;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 答卷详情 Convert
|
|
||||||
*
|
|
||||||
* @author 芋道源码
|
|
||||||
*/
|
|
||||||
@Mapper(uses = {}, builder = @Builder())
|
|
||||||
public interface AssessmentAnswerConvert {
|
|
||||||
|
|
||||||
AssessmentAnswerConvert INSTANCE = Mappers.getMapper(AssessmentAnswerConvert.class);
|
|
||||||
|
|
||||||
AssessmentAnswerDO convert(AssessmentAnswerSaveReqVO bean);
|
|
||||||
|
|
||||||
AssessmentAnswerSaveReqVO convert(AssessmentAnswerDO bean);
|
|
||||||
|
|
||||||
AssessmentAnswerRespVO convert(AssessmentAnswerDO bean);
|
|
||||||
|
|
||||||
List<AssessmentAnswerRespVO> convertList(List<AssessmentAnswerDO> list);
|
|
||||||
|
|
||||||
PageResult<AssessmentAnswerRespVO> convertPage(PageResult<AssessmentAnswerDO> page);
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,34 +0,0 @@
|
|||||||
package cn.iocoder.yudao.module.prison.convert.assessment;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
|
||||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.module.prison.dal.dataobject.assessment.AssessmentRecordDO;
|
|
||||||
import cn.iocoder.yudao.module.prison.controller.admin.assessment.vo.*;
|
|
||||||
import org.mapstruct.Builder;
|
|
||||||
import org.mapstruct.Mapper;
|
|
||||||
import org.mapstruct.factory.Mappers;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 测评记录 Convert
|
|
||||||
*
|
|
||||||
* @author 芋道源码
|
|
||||||
*/
|
|
||||||
@Mapper(uses = {}, builder = @Builder())
|
|
||||||
public interface AssessmentRecordConvert {
|
|
||||||
|
|
||||||
AssessmentRecordConvert INSTANCE = Mappers.getMapper(AssessmentRecordConvert.class);
|
|
||||||
|
|
||||||
AssessmentRecordDO convert(AssessmentRecordSaveReqVO bean);
|
|
||||||
|
|
||||||
AssessmentRecordSaveReqVO convert(AssessmentRecordDO bean);
|
|
||||||
|
|
||||||
AssessmentRecordRespVO convert(AssessmentRecordDO bean);
|
|
||||||
|
|
||||||
List<AssessmentRecordRespVO> convertList(List<AssessmentRecordDO> list);
|
|
||||||
|
|
||||||
PageResult<AssessmentRecordRespVO> convertPage(PageResult<AssessmentRecordDO> page);
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,34 +0,0 @@
|
|||||||
package cn.iocoder.yudao.module.prison.convert.assessment;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
|
||||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.module.prison.dal.dataobject.assessment.AssessmentResultDO;
|
|
||||||
import cn.iocoder.yudao.module.prison.controller.admin.assessment.vo.*;
|
|
||||||
import org.mapstruct.Builder;
|
|
||||||
import org.mapstruct.Mapper;
|
|
||||||
import org.mapstruct.factory.Mappers;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 测评结果 Convert
|
|
||||||
*
|
|
||||||
* @author 芋道源码
|
|
||||||
*/
|
|
||||||
@Mapper(uses = {}, builder = @Builder())
|
|
||||||
public interface AssessmentResultConvert {
|
|
||||||
|
|
||||||
AssessmentResultConvert INSTANCE = Mappers.getMapper(AssessmentResultConvert.class);
|
|
||||||
|
|
||||||
AssessmentResultDO convert(AssessmentResultSaveReqVO bean);
|
|
||||||
|
|
||||||
AssessmentResultSaveReqVO convert(AssessmentResultDO bean);
|
|
||||||
|
|
||||||
AssessmentResultRespVO convert(AssessmentResultDO bean);
|
|
||||||
|
|
||||||
List<AssessmentResultRespVO> convertList(List<AssessmentResultDO> list);
|
|
||||||
|
|
||||||
PageResult<AssessmentResultRespVO> convertPage(PageResult<AssessmentResultDO> page);
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,30 +0,0 @@
|
|||||||
package cn.iocoder.yudao.module.prison.convert.assessment;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
|
||||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.module.prison.dal.dataobject.assessment.AssessmentStatisticsDO;
|
|
||||||
import cn.iocoder.yudao.module.prison.controller.admin.assessment.vo.*;
|
|
||||||
import org.mapstruct.Builder;
|
|
||||||
import org.mapstruct.Mapper;
|
|
||||||
import org.mapstruct.factory.Mappers;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 测评统计 Convert
|
|
||||||
*
|
|
||||||
* @author 芋道源码
|
|
||||||
*/
|
|
||||||
@Mapper(uses = {}, builder = @Builder())
|
|
||||||
public interface AssessmentStatisticsConvert {
|
|
||||||
|
|
||||||
AssessmentStatisticsConvert INSTANCE = Mappers.getMapper(AssessmentStatisticsConvert.class);
|
|
||||||
|
|
||||||
AssessmentStatisticsRespVO convert(AssessmentStatisticsDO bean);
|
|
||||||
|
|
||||||
List<AssessmentStatisticsRespVO> convertList(List<AssessmentStatisticsDO> list);
|
|
||||||
|
|
||||||
PageResult<AssessmentStatisticsRespVO> convertPage(PageResult<AssessmentStatisticsDO> page);
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -0,0 +1,31 @@
|
|||||||
|
package cn.iocoder.yudao.module.prison.convert.consumption;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.module.prison.controller.admin.consumption.vo.*;
|
||||||
|
import cn.iocoder.yudao.module.prison.dal.dataobject.consumption.ConsumptionDO;
|
||||||
|
import cn.iocoder.yudao.module.prison.dal.dataobject.consumption.ConsumptionDetailDO;
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.factory.Mappers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消费订单 Convert
|
||||||
|
*
|
||||||
|
* @author xl
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface ConsumptionConvert {
|
||||||
|
|
||||||
|
ConsumptionConvert INSTANCE = Mappers.getMapper(ConsumptionConvert.class);
|
||||||
|
|
||||||
|
ConsumptionDO convert(ConsumptionSaveReqVO bean);
|
||||||
|
|
||||||
|
ConsumptionRespVO convert(ConsumptionDO bean);
|
||||||
|
|
||||||
|
List<ConsumptionRespVO> convertList(List<ConsumptionDO> list);
|
||||||
|
|
||||||
|
PageResult<ConsumptionRespVO> convertPage(PageResult<ConsumptionDO> page);
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
package cn.iocoder.yudao.module.prison.convert.consumption;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.module.prison.controller.admin.consumption.vo.*;
|
||||||
|
import cn.iocoder.yudao.module.prison.dal.dataobject.consumption.ConsumptionDetailDO;
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.factory.Mappers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消费明细 Convert
|
||||||
|
*
|
||||||
|
* @author xl
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface ConsumptionDetailConvert {
|
||||||
|
|
||||||
|
ConsumptionDetailConvert INSTANCE = Mappers.getMapper(ConsumptionDetailConvert.class);
|
||||||
|
|
||||||
|
ConsumptionDetailDO convert(ConsumptionDetailSaveReqVO bean);
|
||||||
|
|
||||||
|
ConsumptionDetailRespVO convert(ConsumptionDetailDO bean);
|
||||||
|
|
||||||
|
List<ConsumptionDetailDO> convertList(List<ConsumptionDetailSaveReqVO> list);
|
||||||
|
|
||||||
|
List<ConsumptionDetailRespVO> convertListResp(List<ConsumptionDetailDO> list);
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,71 @@
|
|||||||
|
package cn.iocoder.yudao.module.prison.dal.dataobject.answer;
|
||||||
|
|
||||||
|
import lombok.*;
|
||||||
|
import java.util.*;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import com.baomidou.mybatisplus.annotation.*;
|
||||||
|
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 问卷答题记录 DO
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@TableName("prison_answer")
|
||||||
|
@KeySequence("prison_answer_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class AnswerDO extends BaseDO {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 答题记录ID
|
||||||
|
*/
|
||||||
|
@TableId
|
||||||
|
private Long id;
|
||||||
|
/**
|
||||||
|
* 测评记录ID
|
||||||
|
*/
|
||||||
|
private Long assessmentRecordId;
|
||||||
|
/**
|
||||||
|
* 问题ID
|
||||||
|
*/
|
||||||
|
private Long questionId;
|
||||||
|
/**
|
||||||
|
* 问卷ID(冗余)
|
||||||
|
*/
|
||||||
|
private Long questionnaireId;
|
||||||
|
/**
|
||||||
|
* 罪犯ID
|
||||||
|
*/
|
||||||
|
private Long prisonerId;
|
||||||
|
/**
|
||||||
|
* 问题类型:1-单选 2-多选 3-填空 4-评分 5-日期 6-数字
|
||||||
|
*/
|
||||||
|
private Integer questionType;
|
||||||
|
/**
|
||||||
|
* 答案内容(填空题、评分题等)
|
||||||
|
*/
|
||||||
|
private String answerText;
|
||||||
|
/**
|
||||||
|
* 选项ID列表(JSON数组,如 [1,2,3])
|
||||||
|
*/
|
||||||
|
private String optionIds;
|
||||||
|
/**
|
||||||
|
* 得分
|
||||||
|
*/
|
||||||
|
private BigDecimal score;
|
||||||
|
/**
|
||||||
|
* 是否正确:null-未评分 false-错误 true-正确
|
||||||
|
*/
|
||||||
|
private Boolean isCorrect;
|
||||||
|
/**
|
||||||
|
* 答题时间(秒)
|
||||||
|
*/
|
||||||
|
private Integer duration;
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,131 +0,0 @@
|
|||||||
package cn.iocoder.yudao.module.prison.dal.dataobject.assessment;
|
|
||||||
|
|
||||||
import lombok.*;
|
|
||||||
import java.util.*;
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import com.baomidou.mybatisplus.annotation.*;
|
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 答卷详情 DO
|
|
||||||
*
|
|
||||||
* @author 芋道源码
|
|
||||||
*/
|
|
||||||
@TableName("prison_assessment_answer")
|
|
||||||
@KeySequence("prison_assessment_answer_seq")
|
|
||||||
@Data
|
|
||||||
@EqualsAndHashCode(callSuper = true)
|
|
||||||
@ToString(callSuper = true)
|
|
||||||
@Builder
|
|
||||||
@NoArgsConstructor
|
|
||||||
@AllArgsConstructor
|
|
||||||
public class AssessmentAnswerDO extends BaseDO {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 答卷ID
|
|
||||||
*/
|
|
||||||
@TableId
|
|
||||||
private Long id;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 关联测评记录ID
|
|
||||||
*/
|
|
||||||
private Long assessmentRecordId;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 囚犯ID
|
|
||||||
*/
|
|
||||||
private Long prisonerId;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 囚犯编号
|
|
||||||
*/
|
|
||||||
private String prisonerCode;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 囚犯姓名
|
|
||||||
*/
|
|
||||||
private String prisonerName;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 监区ID
|
|
||||||
*/
|
|
||||||
private Long areaId;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 监区名称
|
|
||||||
*/
|
|
||||||
private String areaName;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 监室ID
|
|
||||||
*/
|
|
||||||
private Long cellId;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 监室名称
|
|
||||||
*/
|
|
||||||
private String cellName;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 答卷状态:1-待答题 2-答题中 3-已提交 4-已评分 5-已完成
|
|
||||||
*/
|
|
||||||
private Integer status;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 开始答题时间
|
|
||||||
*/
|
|
||||||
private LocalDateTime startTime;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 提交时间
|
|
||||||
*/
|
|
||||||
private LocalDateTime submitTime;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 答题用时(秒)
|
|
||||||
*/
|
|
||||||
private Integer duration;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 客观题得分
|
|
||||||
*/
|
|
||||||
private BigDecimal objectiveScore;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 主观题得分
|
|
||||||
*/
|
|
||||||
private BigDecimal subjectiveScore;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 总分
|
|
||||||
*/
|
|
||||||
private BigDecimal totalScore;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 是否及格
|
|
||||||
*/
|
|
||||||
private Boolean passed;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 评语
|
|
||||||
*/
|
|
||||||
private String comment;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 评卷人ID
|
|
||||||
*/
|
|
||||||
private Long scorerId;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 评卷人名称
|
|
||||||
*/
|
|
||||||
private String scorerName;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 评分时间
|
|
||||||
*/
|
|
||||||
private LocalDateTime scoreTime;
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,116 +0,0 @@
|
|||||||
package cn.iocoder.yudao.module.prison.dal.dataobject.assessment;
|
|
||||||
|
|
||||||
import lombok.*;
|
|
||||||
import java.util.*;
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import com.baomidou.mybatisplus.annotation.*;
|
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 测评记录 DO
|
|
||||||
*
|
|
||||||
* @author 芋道源码
|
|
||||||
*/
|
|
||||||
@TableName("prison_assessment_record")
|
|
||||||
@KeySequence("prison_assessment_record_seq")
|
|
||||||
@Data
|
|
||||||
@EqualsAndHashCode(callSuper = true)
|
|
||||||
@ToString(callSuper = true)
|
|
||||||
@Builder
|
|
||||||
@NoArgsConstructor
|
|
||||||
@AllArgsConstructor
|
|
||||||
public class AssessmentRecordDO extends BaseDO {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 测评记录ID
|
|
||||||
*/
|
|
||||||
@TableId
|
|
||||||
private Long id;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 测评名称
|
|
||||||
*/
|
|
||||||
private String name;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 关联问卷模板ID
|
|
||||||
*/
|
|
||||||
private Long questionnaireId;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 测评类型:1-心理测评 2-行为评估 3-满意度调查
|
|
||||||
*/
|
|
||||||
private Integer type;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 发起测评的监狱/监区ID
|
|
||||||
*/
|
|
||||||
private Long areaId;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 发起测评的监狱/监区名称
|
|
||||||
*/
|
|
||||||
private String areaName;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 发起人ID
|
|
||||||
*/
|
|
||||||
private Long initiatorId;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 发起人名称
|
|
||||||
*/
|
|
||||||
private String initiatorName;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 测评状态:1-未开始 2-进行中 3-已完成 4-已取消
|
|
||||||
*/
|
|
||||||
private Integer status;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 计划开始时间
|
|
||||||
*/
|
|
||||||
private LocalDateTime planStartTime;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 计划结束时间
|
|
||||||
*/
|
|
||||||
private LocalDateTime planEndTime;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 实际开始时间
|
|
||||||
*/
|
|
||||||
private LocalDateTime actualStartTime;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 实际结束时间
|
|
||||||
*/
|
|
||||||
private LocalDateTime actualEndTime;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 参与人数
|
|
||||||
*/
|
|
||||||
private Integer participantCount;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 完成人数
|
|
||||||
*/
|
|
||||||
private Integer completedCount;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 测评说明
|
|
||||||
*/
|
|
||||||
private String description;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 是否启用自动评分
|
|
||||||
*/
|
|
||||||
private Boolean enableAutoScore;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 及格分数
|
|
||||||
*/
|
|
||||||
private BigDecimal passScore;
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,136 +0,0 @@
|
|||||||
package cn.iocoder.yudao.module.prison.dal.dataobject.assessment;
|
|
||||||
|
|
||||||
import lombok.*;
|
|
||||||
import java.util.*;
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import com.baomidou.mybatisplus.annotation.*;
|
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 测评结果 DO
|
|
||||||
*
|
|
||||||
* @author 芋道源码
|
|
||||||
*/
|
|
||||||
@TableName("prison_assessment_result")
|
|
||||||
@KeySequence("prison_assessment_result_seq")
|
|
||||||
@Data
|
|
||||||
@EqualsAndHashCode(callSuper = true)
|
|
||||||
@ToString(callSuper = true)
|
|
||||||
@Builder
|
|
||||||
@NoArgsConstructor
|
|
||||||
@AllArgsConstructor
|
|
||||||
public class AssessmentResultDO extends BaseDO {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 结果ID
|
|
||||||
*/
|
|
||||||
@TableId
|
|
||||||
private Long id;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 关联答卷ID
|
|
||||||
*/
|
|
||||||
private Long answerId;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 关联测评记录ID
|
|
||||||
*/
|
|
||||||
private Long assessmentRecordId;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 囚犯ID
|
|
||||||
*/
|
|
||||||
private Long prisonerId;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 囚犯编号
|
|
||||||
*/
|
|
||||||
private String prisonerCode;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 囚犯姓名
|
|
||||||
*/
|
|
||||||
private String prisonerName;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 关联题目ID
|
|
||||||
*/
|
|
||||||
private Long questionId;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 题目编号
|
|
||||||
*/
|
|
||||||
private String questionCode;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 题目内容
|
|
||||||
*/
|
|
||||||
private String questionContent;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 题目类型:1-单选 2-多选 3-判断 4-填空 5-问答
|
|
||||||
*/
|
|
||||||
private Integer questionType;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 题目分值
|
|
||||||
*/
|
|
||||||
private BigDecimal questionScore;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 囚犯答案
|
|
||||||
*/
|
|
||||||
private String answer;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 正确答案(客观题)
|
|
||||||
*/
|
|
||||||
private String correctAnswer;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 是否正确
|
|
||||||
*/
|
|
||||||
private Boolean correct;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 得分
|
|
||||||
*/
|
|
||||||
private BigDecimal score;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 是否需要人工评阅
|
|
||||||
*/
|
|
||||||
private Boolean needManualReview;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 人工评阅状态:1-待评阅 2-已评阅
|
|
||||||
*/
|
|
||||||
private Integer manualReviewStatus;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 人工评分
|
|
||||||
*/
|
|
||||||
private BigDecimal manualScore;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 人工评语
|
|
||||||
*/
|
|
||||||
private String manualComment;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 评阅人ID
|
|
||||||
*/
|
|
||||||
private Long reviewerId;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 评阅人名称
|
|
||||||
*/
|
|
||||||
private String reviewerName;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 评阅时间
|
|
||||||
*/
|
|
||||||
private LocalDateTime reviewTime;
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,115 +0,0 @@
|
|||||||
package cn.iocoder.yudao.module.prison.dal.dataobject.assessment;
|
|
||||||
|
|
||||||
import lombok.*;
|
|
||||||
import java.util.*;
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import com.baomidou.mybatisplus.annotation.*;
|
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 测评统计 DO
|
|
||||||
*
|
|
||||||
* @author 芋道源码
|
|
||||||
*/
|
|
||||||
@TableName("prison_assessment_statistics")
|
|
||||||
@Data
|
|
||||||
@EqualsAndHashCode(callSuper = true)
|
|
||||||
@ToString(callSuper = true)
|
|
||||||
@Builder
|
|
||||||
@NoArgsConstructor
|
|
||||||
@AllArgsConstructor
|
|
||||||
public class AssessmentStatisticsDO extends BaseDO {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 统计ID
|
|
||||||
*/
|
|
||||||
@TableId
|
|
||||||
private Long id;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 关联测评记录ID
|
|
||||||
*/
|
|
||||||
private Long assessmentRecordId;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 测评名称
|
|
||||||
*/
|
|
||||||
private String assessmentName;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 总参与人数
|
|
||||||
*/
|
|
||||||
private Integer totalCount;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 已完成人数
|
|
||||||
*/
|
|
||||||
private Integer completedCount;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 完成率
|
|
||||||
*/
|
|
||||||
private BigDecimal completionRate;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 平均分
|
|
||||||
*/
|
|
||||||
private BigDecimal averageScore;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 最高分
|
|
||||||
*/
|
|
||||||
private BigDecimal highestScore;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 最低分
|
|
||||||
*/
|
|
||||||
private BigDecimal lowestScore;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 及格人数
|
|
||||||
*/
|
|
||||||
private Integer passedCount;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 及格率
|
|
||||||
*/
|
|
||||||
private BigDecimal passRate;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 优秀人数(90分以上)
|
|
||||||
*/
|
|
||||||
private Integer excellentCount;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 优秀率
|
|
||||||
*/
|
|
||||||
private BigDecimal excellentRate;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 风险人数(60分以下)
|
|
||||||
*/
|
|
||||||
private Integer riskCount;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 风险率
|
|
||||||
*/
|
|
||||||
private BigDecimal riskRate;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 风险分布JSON:{"low": 10, "medium": 5, "high": 3}
|
|
||||||
*/
|
|
||||||
private String riskDistribution;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 分数分布JSON:{"0-20": 5, "20-40": 10, "40-60": 15, "60-80": 20, "80-100": 8}
|
|
||||||
*/
|
|
||||||
private String scoreDistribution;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 统计时间
|
|
||||||
*/
|
|
||||||
private LocalDateTime statisticsTime;
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -3,17 +3,14 @@ package cn.iocoder.yudao.module.prison.dal.dataobject.consumption;
|
|||||||
import lombok.*;
|
import lombok.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import com.baomidou.mybatisplus.annotation.*;
|
import com.baomidou.mybatisplus.annotation.*;
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 消费记录 DO
|
* 消费订单 DO
|
||||||
*
|
*
|
||||||
* @author 芋道源码
|
* @author xl
|
||||||
*/
|
*/
|
||||||
@TableName("prison_consumption")
|
@TableName("prison_consumption")
|
||||||
@KeySequence("prison_consumption_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
|
@KeySequence("prison_consumption_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
|
||||||
@ -26,7 +23,7 @@ import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
|||||||
public class ConsumptionDO extends BaseDO {
|
public class ConsumptionDO extends BaseDO {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 记录ID
|
* 消费ID
|
||||||
*/
|
*/
|
||||||
@TableId
|
@TableId
|
||||||
private Long id;
|
private Long id;
|
||||||
@ -38,30 +35,22 @@ public class ConsumptionDO extends BaseDO {
|
|||||||
* 罪犯编号
|
* 罪犯编号
|
||||||
*/
|
*/
|
||||||
private String prisonerNo;
|
private String prisonerNo;
|
||||||
/**
|
|
||||||
* 类型:1-存款 2-消费 3-转账
|
|
||||||
*/
|
|
||||||
private Integer type;
|
|
||||||
/**
|
|
||||||
* 金额
|
|
||||||
*/
|
|
||||||
private BigDecimal amount;
|
|
||||||
/**
|
|
||||||
* 账户余额
|
|
||||||
*/
|
|
||||||
private BigDecimal balance;
|
|
||||||
/**
|
|
||||||
* 商品名称
|
|
||||||
*/
|
|
||||||
private String goodsName;
|
|
||||||
/**
|
|
||||||
* 商品数量
|
|
||||||
*/
|
|
||||||
private Integer goodsCount;
|
|
||||||
/**
|
/**
|
||||||
* 订单号
|
* 订单号
|
||||||
*/
|
*/
|
||||||
private String orderNo;
|
private String orderNo;
|
||||||
|
/**
|
||||||
|
* 类型:1-购物 2-餐饮 3-医疗 4-通讯 5-其他
|
||||||
|
*/
|
||||||
|
private Integer type;
|
||||||
|
/**
|
||||||
|
* 订单总金额
|
||||||
|
*/
|
||||||
|
private BigDecimal totalAmount;
|
||||||
|
/**
|
||||||
|
* 账户余额(消费后)
|
||||||
|
*/
|
||||||
|
private BigDecimal balance;
|
||||||
/**
|
/**
|
||||||
* 交易时间
|
* 交易时间
|
||||||
*/
|
*/
|
||||||
@ -75,5 +64,4 @@ public class ConsumptionDO extends BaseDO {
|
|||||||
*/
|
*/
|
||||||
private String remark;
|
private String remark;
|
||||||
|
|
||||||
|
}
|
||||||
}
|
|
||||||
|
|||||||
@ -0,0 +1,58 @@
|
|||||||
|
package cn.iocoder.yudao.module.prison.dal.dataobject.consumption;
|
||||||
|
|
||||||
|
import lombok.*;
|
||||||
|
import java.util.*;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import com.baomidou.mybatisplus.annotation.*;
|
||||||
|
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消费明细 DO
|
||||||
|
*
|
||||||
|
* @author xl
|
||||||
|
*/
|
||||||
|
@TableName("prison_consumption_detail")
|
||||||
|
@KeySequence("prison_consumption_detail_seq")
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class ConsumptionDetailDO extends BaseDO {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 明细ID
|
||||||
|
*/
|
||||||
|
@TableId
|
||||||
|
private Long id;
|
||||||
|
/**
|
||||||
|
* 消费订单ID
|
||||||
|
*/
|
||||||
|
private Long consumptionId;
|
||||||
|
/**
|
||||||
|
* 罪犯ID(冗余,便于查询)
|
||||||
|
*/
|
||||||
|
private Long prisonerId;
|
||||||
|
/**
|
||||||
|
* 商品名称
|
||||||
|
*/
|
||||||
|
private String goodsName;
|
||||||
|
/**
|
||||||
|
* 商品编码
|
||||||
|
*/
|
||||||
|
private String goodsCode;
|
||||||
|
/**
|
||||||
|
* 商品单价
|
||||||
|
*/
|
||||||
|
private BigDecimal goodsPrice;
|
||||||
|
/**
|
||||||
|
* 商品数量
|
||||||
|
*/
|
||||||
|
private Integer goodsCount;
|
||||||
|
/**
|
||||||
|
* 小计金额
|
||||||
|
*/
|
||||||
|
private BigDecimal subtotal;
|
||||||
|
|
||||||
|
}
|
||||||
@ -4,18 +4,16 @@ import lombok.*;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import com.baomidou.mybatisplus.annotation.*;
|
import com.baomidou.mybatisplus.annotation.*;
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 问卷答题记录 DO
|
* 问卷答题记录 / 测评记录 DO
|
||||||
*
|
*
|
||||||
* @author 芋道源码
|
* @author 芋道源码
|
||||||
*/
|
*/
|
||||||
@TableName("prison_questionnaire_record")
|
@TableName("prison_questionnaire_record")
|
||||||
@KeySequence("prison_questionnaire_record_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
|
@KeySequence("prison_questionnaire_record_seq")
|
||||||
@Data
|
@Data
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
@ToString(callSuper = true)
|
@ToString(callSuper = true)
|
||||||
@ -29,10 +27,20 @@ public class QuestionnaireRecordDO extends BaseDO {
|
|||||||
*/
|
*/
|
||||||
@TableId
|
@TableId
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
|
// ==================== 问卷信息 ====================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 问卷ID
|
* 问卷ID
|
||||||
*/
|
*/
|
||||||
private Long questionnaireId;
|
private Long questionnaireId;
|
||||||
|
/**
|
||||||
|
* 问卷名称
|
||||||
|
*/
|
||||||
|
private String questionnaireName;
|
||||||
|
|
||||||
|
// ==================== 罪犯信息 ====================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 罪犯ID
|
* 罪犯ID
|
||||||
*/
|
*/
|
||||||
@ -42,21 +50,94 @@ public class QuestionnaireRecordDO extends BaseDO {
|
|||||||
*/
|
*/
|
||||||
private String prisonerNo;
|
private String prisonerNo;
|
||||||
/**
|
/**
|
||||||
* 得分
|
* 罪犯姓名
|
||||||
*/
|
*/
|
||||||
private BigDecimal totalScore;
|
private String prisonerName;
|
||||||
|
|
||||||
|
// ==================== 测评状态 ====================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否及格:1-及格 2-不及格
|
* 状态:1-待测评 2-测评中 3-已完成 4-已过期 5-已取消
|
||||||
*/
|
|
||||||
private Integer passStatus;
|
|
||||||
/**
|
|
||||||
* 答题时间
|
|
||||||
*/
|
|
||||||
private LocalDateTime answerTime;
|
|
||||||
/**
|
|
||||||
* 状态:1-已完成 2-已过期
|
|
||||||
*/
|
*/
|
||||||
private Integer status;
|
private Integer status;
|
||||||
|
|
||||||
|
// ==================== 测评时间 ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开始时间
|
||||||
|
*/
|
||||||
|
private LocalDateTime startTime;
|
||||||
|
/**
|
||||||
|
* 结束时间
|
||||||
|
*/
|
||||||
|
private LocalDateTime endTime;
|
||||||
|
/**
|
||||||
|
* 截止日期
|
||||||
|
*/
|
||||||
|
private LocalDateTime deadline;
|
||||||
|
|
||||||
|
// ==================== 评分信息 ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 客观题得分
|
||||||
|
*/
|
||||||
|
private BigDecimal objectiveScore;
|
||||||
|
/**
|
||||||
|
* 主观题得分
|
||||||
|
*/
|
||||||
|
private BigDecimal subjectiveScore;
|
||||||
|
/**
|
||||||
|
* 总分
|
||||||
|
*/
|
||||||
|
private BigDecimal totalScore;
|
||||||
|
/**
|
||||||
|
* 及格分数
|
||||||
|
*/
|
||||||
|
private BigDecimal passScore;
|
||||||
|
/**
|
||||||
|
* 及格状态:1-及格 2-不及格 3-待评阅
|
||||||
|
*/
|
||||||
|
private Integer passStatus;
|
||||||
|
/**
|
||||||
|
* 风险等级:1-高风险 2-中风险 3-低风险
|
||||||
|
*/
|
||||||
|
private Integer riskLevel;
|
||||||
|
|
||||||
|
// ==================== 评阅信息 ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 评阅人ID
|
||||||
|
*/
|
||||||
|
private Long evaluatorId;
|
||||||
|
/**
|
||||||
|
* 评阅人姓名
|
||||||
|
*/
|
||||||
|
private String evaluatorName;
|
||||||
|
/**
|
||||||
|
* 评阅时间
|
||||||
|
*/
|
||||||
|
private LocalDateTime evaluateTime;
|
||||||
|
|
||||||
|
// ==================== 统计信息 ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 参与人数
|
||||||
|
*/
|
||||||
|
private Integer participantCount;
|
||||||
|
/**
|
||||||
|
* 完成人数
|
||||||
|
*/
|
||||||
|
private Integer completedCount;
|
||||||
|
/**
|
||||||
|
* 答题用时(秒)
|
||||||
|
*/
|
||||||
|
private Integer duration;
|
||||||
|
|
||||||
|
// ==================== 备注 ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 备注
|
||||||
|
*/
|
||||||
|
private String remark;
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -0,0 +1,57 @@
|
|||||||
|
package cn.iocoder.yudao.module.prison.dal.mysql.answer;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
|
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||||
|
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||||
|
import cn.iocoder.yudao.module.prison.dal.dataobject.answer.AnswerDO;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
import cn.iocoder.yudao.module.prison.controller.admin.answer.vo.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 问卷答题记录 Mapper
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface AnswerMapper extends BaseMapperX<AnswerDO> {
|
||||||
|
|
||||||
|
default PageResult<AnswerDO> selectPage(AnswerPageReqVO reqVO) {
|
||||||
|
return selectPage(reqVO, new LambdaQueryWrapperX<AnswerDO>()
|
||||||
|
.eqIfPresent(AnswerDO::getAssessmentRecordId, reqVO.getAssessmentRecordId())
|
||||||
|
.eqIfPresent(AnswerDO::getQuestionId, reqVO.getQuestionId())
|
||||||
|
.eqIfPresent(AnswerDO::getQuestionnaireId, reqVO.getQuestionnaireId())
|
||||||
|
.eqIfPresent(AnswerDO::getPrisonerId, reqVO.getPrisonerId())
|
||||||
|
.eqIfPresent(AnswerDO::getQuestionType, reqVO.getQuestionType())
|
||||||
|
.betweenIfPresent(AnswerDO::getCreateTime, reqVO.getCreateTime())
|
||||||
|
.orderByDesc(AnswerDO::getId));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据测评记录ID查询所有答题记录
|
||||||
|
*/
|
||||||
|
default List<AnswerDO> selectListByAssessmentRecordId(Long assessmentRecordId) {
|
||||||
|
return selectList(new LambdaQueryWrapperX<AnswerDO>()
|
||||||
|
.eqIfPresent(AnswerDO::getAssessmentRecordId, assessmentRecordId)
|
||||||
|
.orderByAsc(AnswerDO::getId));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据测评记录ID和问题ID查询答题记录
|
||||||
|
*/
|
||||||
|
default AnswerDO selectByAssessmentRecordIdAndQuestionId(Long assessmentRecordId, Long questionId) {
|
||||||
|
return selectOne(new LambdaQueryWrapperX<AnswerDO>()
|
||||||
|
.eqIfPresent(AnswerDO::getAssessmentRecordId, assessmentRecordId)
|
||||||
|
.eqIfPresent(AnswerDO::getQuestionId, questionId));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据测评记录ID删除所有答题记录
|
||||||
|
*/
|
||||||
|
default int deleteByAssessmentRecordId(Long assessmentRecordId) {
|
||||||
|
return delete(new LambdaQueryWrapperX<AnswerDO>()
|
||||||
|
.eqIfPresent(AnswerDO::getAssessmentRecordId, assessmentRecordId));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,51 +0,0 @@
|
|||||||
package cn.iocoder.yudao.module.prison.dal.mysql.assessment;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
|
||||||
import cn.iocoder.yudao.module.prison.dal.dataobject.assessment.AssessmentAnswerDO;
|
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
|
||||||
import cn.iocoder.yudao.module.prison.controller.admin.assessment.vo.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 答卷详情 Mapper
|
|
||||||
*
|
|
||||||
* @author 芋道源码
|
|
||||||
*/
|
|
||||||
@Mapper
|
|
||||||
public interface AssessmentAnswerMapper extends BaseMapperX<AssessmentAnswerDO> {
|
|
||||||
|
|
||||||
default PageResult<AssessmentAnswerDO> selectPage(AssessmentAnswerPageReqVO reqVO) {
|
|
||||||
return selectPage(reqVO, new LambdaQueryWrapperX<AssessmentAnswerDO>()
|
|
||||||
.eqIfPresent(AssessmentAnswerDO::getAssessmentRecordId, reqVO.getAssessmentRecordId())
|
|
||||||
.eqIfPresent(AssessmentAnswerDO::getPrisonerId, reqVO.getPrisonerId())
|
|
||||||
.likeIfPresent(AssessmentAnswerDO::getPrisonerCode, reqVO.getPrisonerCode())
|
|
||||||
.likeIfPresent(AssessmentAnswerDO::getPrisonerName, reqVO.getPrisonerName())
|
|
||||||
.eqIfPresent(AssessmentAnswerDO::getAreaId, reqVO.getAreaId())
|
|
||||||
.eqIfPresent(AssessmentAnswerDO::getCellId, reqVO.getCellId())
|
|
||||||
.eqIfPresent(AssessmentAnswerDO::getStatus, reqVO.getStatus())
|
|
||||||
.betweenIfPresent(AssessmentAnswerDO::getStartTime, reqVO.getStartTime())
|
|
||||||
.betweenIfPresent(AssessmentAnswerDO::getSubmitTime, reqVO.getSubmitTime())
|
|
||||||
.orderByDesc(AssessmentAnswerDO::getId));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据测评记录ID查询所有答卷
|
|
||||||
*/
|
|
||||||
default List<AssessmentAnswerDO> selectListByAssessmentRecordId(Long assessmentRecordId) {
|
|
||||||
return selectList(new LambdaQueryWrapperX<AssessmentAnswerDO>()
|
|
||||||
.eqIfPresent(AssessmentAnswerDO::getAssessmentRecordId, assessmentRecordId));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据囚犯ID和测评记录ID查询答卷
|
|
||||||
*/
|
|
||||||
default AssessmentAnswerDO selectByPrisonerAndRecord(Long prisonerId, Long assessmentRecordId) {
|
|
||||||
return selectOne(new LambdaQueryWrapperX<AssessmentAnswerDO>()
|
|
||||||
.eqIfPresent(AssessmentAnswerDO::getPrisonerId, prisonerId)
|
|
||||||
.eqIfPresent(AssessmentAnswerDO::getAssessmentRecordId, assessmentRecordId));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,33 +0,0 @@
|
|||||||
package cn.iocoder.yudao.module.prison.dal.mysql.assessment;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
|
||||||
import cn.iocoder.yudao.module.prison.dal.dataobject.assessment.AssessmentRecordDO;
|
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
|
||||||
import cn.iocoder.yudao.module.prison.controller.admin.assessment.vo.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 测评记录 Mapper
|
|
||||||
*
|
|
||||||
* @author 芋道源码
|
|
||||||
*/
|
|
||||||
@Mapper
|
|
||||||
public interface AssessmentRecordMapper extends BaseMapperX<AssessmentRecordDO> {
|
|
||||||
|
|
||||||
default PageResult<AssessmentRecordDO> selectPage(AssessmentRecordPageReqVO reqVO) {
|
|
||||||
return selectPage(reqVO, new LambdaQueryWrapperX<AssessmentRecordDO>()
|
|
||||||
.likeIfPresent(AssessmentRecordDO::getName, reqVO.getName())
|
|
||||||
.eqIfPresent(AssessmentRecordDO::getQuestionnaireId, reqVO.getQuestionnaireId())
|
|
||||||
.eqIfPresent(AssessmentRecordDO::getType, reqVO.getType())
|
|
||||||
.eqIfPresent(AssessmentRecordDO::getAreaId, reqVO.getAreaId())
|
|
||||||
.eqIfPresent(AssessmentRecordDO::getStatus, reqVO.getStatus())
|
|
||||||
.betweenIfPresent(AssessmentRecordDO::getPlanStartTime, reqVO.getPlanStartTime())
|
|
||||||
.betweenIfPresent(AssessmentRecordDO::getPlanEndTime, reqVO.getPlanEndTime())
|
|
||||||
.betweenIfPresent(AssessmentRecordDO::getCreateTime, reqVO.getCreateTime())
|
|
||||||
.orderByDesc(AssessmentRecordDO::getId));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,71 +0,0 @@
|
|||||||
package cn.iocoder.yudao.module.prison.dal.mysql.assessment;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
|
||||||
import cn.iocoder.yudao.module.prison.dal.dataobject.assessment.AssessmentResultDO;
|
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
|
||||||
import cn.iocoder.yudao.module.prison.controller.admin.assessment.vo.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 测评结果 Mapper
|
|
||||||
*
|
|
||||||
* @author 芋道源码
|
|
||||||
*/
|
|
||||||
@Mapper
|
|
||||||
public interface AssessmentResultMapper extends BaseMapperX<AssessmentResultDO> {
|
|
||||||
|
|
||||||
default PageResult<AssessmentResultDO> selectPage(AssessmentResultPageReqVO reqVO) {
|
|
||||||
return selectPage(reqVO, new LambdaQueryWrapperX<AssessmentResultDO>()
|
|
||||||
.eqIfPresent(AssessmentResultDO::getAnswerId, reqVO.getAnswerId())
|
|
||||||
.eqIfPresent(AssessmentResultDO::getAssessmentRecordId, reqVO.getAssessmentRecordId())
|
|
||||||
.eqIfPresent(AssessmentResultDO::getPrisonerId, reqVO.getPrisonerId())
|
|
||||||
.eqIfPresent(AssessmentResultDO::getQuestionId, reqVO.getQuestionId())
|
|
||||||
.eqIfPresent(AssessmentResultDO::getQuestionType, reqVO.getQuestionType())
|
|
||||||
.eqIfPresent(AssessmentResultDO::getCorrect, reqVO.getCorrect())
|
|
||||||
.eqIfPresent(AssessmentResultDO::getNeedManualReview, reqVO.getNeedManualReview())
|
|
||||||
.eqIfPresent(AssessmentResultDO::getManualReviewStatus, reqVO.getManualReviewStatus())
|
|
||||||
.orderByDesc(AssessmentResultDO::getId));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据答卷ID查询所有结果
|
|
||||||
*/
|
|
||||||
default List<AssessmentResultDO> selectListByAnswerId(Long answerId) {
|
|
||||||
return selectList(new LambdaQueryWrapperX<AssessmentResultDO>()
|
|
||||||
.eqIfPresent(AssessmentResultDO::getAnswerId, answerId)
|
|
||||||
.orderByAsc(AssessmentResultDO::getId));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据测评记录ID查询所有结果
|
|
||||||
*/
|
|
||||||
default List<AssessmentResultDO> selectListByAssessmentRecordId(Long assessmentRecordId) {
|
|
||||||
return selectList(new LambdaQueryWrapperX<AssessmentResultDO>()
|
|
||||||
.eqIfPresent(AssessmentResultDO::getAssessmentRecordId, assessmentRecordId));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 查询需要人工评阅的结果
|
|
||||||
*/
|
|
||||||
default List<AssessmentResultDO> selectListNeedManualReview() {
|
|
||||||
return selectList(new LambdaQueryWrapperX<AssessmentResultDO>()
|
|
||||||
.eqIfPresent(AssessmentResultDO::getNeedManualReview, true)
|
|
||||||
.eqIfPresent(AssessmentResultDO::getManualReviewStatus, 1)
|
|
||||||
.orderByAsc(AssessmentResultDO::getId));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据答卷ID统计客观题得分
|
|
||||||
*/
|
|
||||||
default java.math.BigDecimal sumObjectiveScoreByAnswerId(Long answerId) {
|
|
||||||
return selectObjs(new LambdaQueryWrapperX<AssessmentResultDO>()
|
|
||||||
.eqIfPresent(AssessmentResultDO::getAnswerId, answerId)
|
|
||||||
.eqIfPresent(AssessmentResultDO::getNeedManualReview, false))
|
|
||||||
.stream().map(obj -> (java.math.BigDecimal) obj)
|
|
||||||
.reduce(java.math.BigDecimal.ZERO, java.math.BigDecimal::add);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,37 +0,0 @@
|
|||||||
package cn.iocoder.yudao.module.prison.dal.mysql.assessment;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
|
||||||
import cn.iocoder.yudao.module.prison.dal.dataobject.assessment.AssessmentStatisticsDO;
|
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
|
||||||
import cn.iocoder.yudao.module.prison.controller.admin.assessment.vo.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 测评统计 Mapper
|
|
||||||
*
|
|
||||||
* @author 芋道源码
|
|
||||||
*/
|
|
||||||
@Mapper
|
|
||||||
public interface AssessmentStatisticsMapper extends BaseMapperX<AssessmentStatisticsDO> {
|
|
||||||
|
|
||||||
default PageResult<AssessmentStatisticsDO> selectPage(AssessmentStatisticsPageReqVO reqVO) {
|
|
||||||
return selectPage(reqVO, new LambdaQueryWrapperX<AssessmentStatisticsDO>()
|
|
||||||
.eqIfPresent(AssessmentStatisticsDO::getAssessmentRecordId, reqVO.getAssessmentRecordId())
|
|
||||||
.likeIfPresent(AssessmentStatisticsDO::getAssessmentName, reqVO.getAssessmentName())
|
|
||||||
.orderByDesc(AssessmentStatisticsDO::getId));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据测评记录ID查询统计
|
|
||||||
*/
|
|
||||||
default AssessmentStatisticsDO selectByAssessmentRecordId(Long assessmentRecordId) {
|
|
||||||
return selectOne(new LambdaQueryWrapperX<AssessmentStatisticsDO>()
|
|
||||||
.eqIfPresent(AssessmentStatisticsDO::getAssessmentRecordId, assessmentRecordId)
|
|
||||||
.orderByDesc(AssessmentStatisticsDO::getId)
|
|
||||||
.last("LIMIT 1"));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -0,0 +1,43 @@
|
|||||||
|
package cn.iocoder.yudao.module.prison.dal.mysql.consumption;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||||
|
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||||
|
import cn.iocoder.yudao.module.prison.dal.dataobject.consumption.ConsumptionDetailDO;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消费明细 Mapper
|
||||||
|
*
|
||||||
|
* @author xl
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface ConsumptionDetailMapper extends BaseMapperX<ConsumptionDetailDO> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据消费订单ID列表删除
|
||||||
|
*/
|
||||||
|
default void deleteListByConsumptionIds(Collection<Long> consumptionIds) {
|
||||||
|
delete(new LambdaQueryWrapperX<ConsumptionDetailDO>()
|
||||||
|
.in(ConsumptionDetailDO::getConsumptionId, consumptionIds));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据消费订单ID删除
|
||||||
|
*/
|
||||||
|
default void deleteListByConsumptionId(Long consumptionId) {
|
||||||
|
delete(new LambdaQueryWrapperX<ConsumptionDetailDO>()
|
||||||
|
.eq(ConsumptionDetailDO::getConsumptionId, consumptionId));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据消费订单ID查询明细列表
|
||||||
|
*/
|
||||||
|
default List<ConsumptionDetailDO> selectListByConsumptionId(Long consumptionId) {
|
||||||
|
return selectList(new LambdaQueryWrapperX<ConsumptionDetailDO>()
|
||||||
|
.eq(ConsumptionDetailDO::getConsumptionId, consumptionId));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -10,9 +10,9 @@ import org.apache.ibatis.annotations.Mapper;
|
|||||||
import cn.iocoder.yudao.module.prison.controller.admin.consumption.vo.*;
|
import cn.iocoder.yudao.module.prison.controller.admin.consumption.vo.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 消费记录 Mapper
|
* 消费订单 Mapper
|
||||||
*
|
*
|
||||||
* @author 芋道源码
|
* @author xl
|
||||||
*/
|
*/
|
||||||
@Mapper
|
@Mapper
|
||||||
public interface ConsumptionMapper extends BaseMapperX<ConsumptionDO> {
|
public interface ConsumptionMapper extends BaseMapperX<ConsumptionDO> {
|
||||||
@ -22,10 +22,8 @@ public interface ConsumptionMapper extends BaseMapperX<ConsumptionDO> {
|
|||||||
.eqIfPresent(ConsumptionDO::getPrisonerId, reqVO.getPrisonerId())
|
.eqIfPresent(ConsumptionDO::getPrisonerId, reqVO.getPrisonerId())
|
||||||
.eqIfPresent(ConsumptionDO::getPrisonerNo, reqVO.getPrisonerNo())
|
.eqIfPresent(ConsumptionDO::getPrisonerNo, reqVO.getPrisonerNo())
|
||||||
.eqIfPresent(ConsumptionDO::getType, reqVO.getType())
|
.eqIfPresent(ConsumptionDO::getType, reqVO.getType())
|
||||||
.eqIfPresent(ConsumptionDO::getAmount, reqVO.getAmount())
|
.eqIfPresent(ConsumptionDO::getTotalAmount, reqVO.getTotalAmount())
|
||||||
.eqIfPresent(ConsumptionDO::getBalance, reqVO.getBalance())
|
.eqIfPresent(ConsumptionDO::getBalance, reqVO.getBalance())
|
||||||
.likeIfPresent(ConsumptionDO::getGoodsName, reqVO.getGoodsName())
|
|
||||||
.eqIfPresent(ConsumptionDO::getGoodsCount, reqVO.getGoodsCount())
|
|
||||||
.eqIfPresent(ConsumptionDO::getOrderNo, reqVO.getOrderNo())
|
.eqIfPresent(ConsumptionDO::getOrderNo, reqVO.getOrderNo())
|
||||||
.betweenIfPresent(ConsumptionDO::getTradeTime, reqVO.getTradeTime())
|
.betweenIfPresent(ConsumptionDO::getTradeTime, reqVO.getTradeTime())
|
||||||
.eqIfPresent(ConsumptionDO::getStatus, reqVO.getStatus())
|
.eqIfPresent(ConsumptionDO::getStatus, reqVO.getStatus())
|
||||||
@ -34,4 +32,4 @@ public interface ConsumptionMapper extends BaseMapperX<ConsumptionDO> {
|
|||||||
.orderByDesc(ConsumptionDO::getId));
|
.orderByDesc(ConsumptionDO::getId));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,7 +24,6 @@ public interface QuestionnaireRecordMapper extends BaseMapperX<QuestionnaireReco
|
|||||||
.eqIfPresent(QuestionnaireRecordDO::getPrisonerNo, reqVO.getPrisonerNo())
|
.eqIfPresent(QuestionnaireRecordDO::getPrisonerNo, reqVO.getPrisonerNo())
|
||||||
.eqIfPresent(QuestionnaireRecordDO::getTotalScore, reqVO.getTotalScore())
|
.eqIfPresent(QuestionnaireRecordDO::getTotalScore, reqVO.getTotalScore())
|
||||||
.eqIfPresent(QuestionnaireRecordDO::getPassStatus, reqVO.getPassStatus())
|
.eqIfPresent(QuestionnaireRecordDO::getPassStatus, reqVO.getPassStatus())
|
||||||
.betweenIfPresent(QuestionnaireRecordDO::getAnswerTime, reqVO.getAnswerTime())
|
|
||||||
.eqIfPresent(QuestionnaireRecordDO::getStatus, reqVO.getStatus())
|
.eqIfPresent(QuestionnaireRecordDO::getStatus, reqVO.getStatus())
|
||||||
.betweenIfPresent(QuestionnaireRecordDO::getCreateTime, reqVO.getCreateTime())
|
.betweenIfPresent(QuestionnaireRecordDO::getCreateTime, reqVO.getCreateTime())
|
||||||
.orderByDesc(QuestionnaireRecordDO::getId));
|
.orderByDesc(QuestionnaireRecordDO::getId));
|
||||||
|
|||||||
@ -0,0 +1,49 @@
|
|||||||
|
package cn.iocoder.yudao.module.prison.enums;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消费状态枚举
|
||||||
|
*
|
||||||
|
* @author xl
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public enum ConsumptionStatusEnum {
|
||||||
|
|
||||||
|
SUCCESS(1, "成功", "success"),
|
||||||
|
FAILED(2, "失败", "failed");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态编码
|
||||||
|
*/
|
||||||
|
private final Integer code;
|
||||||
|
/**
|
||||||
|
* 状态名称
|
||||||
|
*/
|
||||||
|
private final String name;
|
||||||
|
/**
|
||||||
|
* 状态标识(用于字典)
|
||||||
|
*/
|
||||||
|
private final String type;
|
||||||
|
|
||||||
|
private static final Map<Integer, ConsumptionStatusEnum> MAP = new HashMap<>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
for (ConsumptionStatusEnum item : ConsumptionStatusEnum.values()) {
|
||||||
|
MAP.put(item.getCode(), item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ConsumptionStatusEnum fromCode(Integer code) {
|
||||||
|
return MAP.get(code);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isValid() {
|
||||||
|
return MAP.containsKey(this.code);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,52 @@
|
|||||||
|
package cn.iocoder.yudao.module.prison.enums;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消费类型枚举
|
||||||
|
*
|
||||||
|
* @author xl
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public enum ConsumptionTypeEnum {
|
||||||
|
|
||||||
|
SHOPPING(1, "购物", "shopping"),
|
||||||
|
DINING(2, "餐饮", "dining"),
|
||||||
|
MEDICAL(3, "医疗", "medical"),
|
||||||
|
COMMUNICATION(4, "通讯", "communication"),
|
||||||
|
OTHER(5, "其他", "other");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 类型编码
|
||||||
|
*/
|
||||||
|
private final Integer code;
|
||||||
|
/**
|
||||||
|
* 类型名称
|
||||||
|
*/
|
||||||
|
private final String name;
|
||||||
|
/**
|
||||||
|
* 类型标识(用于字典)
|
||||||
|
*/
|
||||||
|
private final String type;
|
||||||
|
|
||||||
|
private static final Map<Integer, ConsumptionTypeEnum> MAP = new HashMap<>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
for (ConsumptionTypeEnum item : ConsumptionTypeEnum.values()) {
|
||||||
|
MAP.put(item.getCode(), item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ConsumptionTypeEnum fromCode(Integer code) {
|
||||||
|
return MAP.get(code);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isValid() {
|
||||||
|
return MAP.containsKey(this.code);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -35,6 +35,9 @@ public class ErrorCodeConstants {
|
|||||||
|
|
||||||
// ========== 消费记录 7xxxx ==========
|
// ========== 消费记录 7xxxx ==========
|
||||||
public static final ErrorCode PRISON_CONSUMPTION_NOT_EXISTS = new ErrorCode(7_000_001, "消费记录不存在");
|
public static final ErrorCode PRISON_CONSUMPTION_NOT_EXISTS = new ErrorCode(7_000_001, "消费记录不存在");
|
||||||
|
public static final ErrorCode PRISON_CONSUMPTION_AMOUNT_MISMATCH = new ErrorCode(7_000_002, "消费明细金额与订单总金额不一致");
|
||||||
|
public static final ErrorCode PRISON_CONSUMPTION_DETAIL_EMPTY = new ErrorCode(7_000_003, "消费明细不能为空");
|
||||||
|
public static final ErrorCode PRISON_CONSUMPTION_DETAIL_INVALID = new ErrorCode(7_000_004, "消费明细数据不合法,请检查商品名称、单价和数量");
|
||||||
|
|
||||||
// ========== 罪犯监区变动记录 8xxxx ==========
|
// ========== 罪犯监区变动记录 8xxxx ==========
|
||||||
public static final ErrorCode PRISONER_AREA_LOG_NOT_EXISTS = new ErrorCode(8_000_001, "罪犯监区变动记录不存在");
|
public static final ErrorCode PRISONER_AREA_LOG_NOT_EXISTS = new ErrorCode(8_000_001, "罪犯监区变动记录不存在");
|
||||||
@ -56,5 +59,9 @@ public class ErrorCodeConstants {
|
|||||||
public static final ErrorCode QUESTIONNAIRE_NOT_EXISTS = PRISON_QUESTIONNAIRE_NOT_EXISTS;
|
public static final ErrorCode QUESTIONNAIRE_NOT_EXISTS = PRISON_QUESTIONNAIRE_NOT_EXISTS;
|
||||||
public static final ErrorCode QUESTION_NOT_EXISTS = PRISON_QUESTION_NOT_EXISTS;
|
public static final ErrorCode QUESTION_NOT_EXISTS = PRISON_QUESTION_NOT_EXISTS;
|
||||||
public static final ErrorCode QUESTIONNAIRE_RECORD_NOT_EXISTS = PRISON_QUESTIONNAIRE_RECORD_NOT_EXISTS;
|
public static final ErrorCode QUESTIONNAIRE_RECORD_NOT_EXISTS = PRISON_QUESTIONNAIRE_RECORD_NOT_EXISTS;
|
||||||
|
public static final ErrorCode QUESTIONNAIRE_RECORD_STATUS_ERROR = new ErrorCode(6_000_004, "问卷答题记录状态不合法");
|
||||||
|
|
||||||
|
// ========== 答卷管理 10xxxx ==========
|
||||||
|
public static final ErrorCode ANSWER_NOT_EXISTS = new ErrorCode(10_000_001, "答卷记录不存在");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import lombok.Getter;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 问卷答题记录及格状态枚举
|
* 问卷答题记录及格状态枚举
|
||||||
|
* 状态:1-及格 2-不及格 3-待评阅
|
||||||
*
|
*
|
||||||
* @author 芋道源码
|
* @author 芋道源码
|
||||||
*/
|
*/
|
||||||
@ -12,8 +13,9 @@ import lombok.Getter;
|
|||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public enum QuestionnaireRecordPassStatusEnum {
|
public enum QuestionnaireRecordPassStatusEnum {
|
||||||
|
|
||||||
NOT_PASSED(0, "未及格"),
|
PASSED(1, "及格"),
|
||||||
PASSED(1, "及格");
|
FAILED(2, "不及格"),
|
||||||
|
PENDING(3, "待评阅");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 状态
|
* 状态
|
||||||
@ -38,6 +40,9 @@ public enum QuestionnaireRecordPassStatusEnum {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static QuestionnaireRecordPassStatusEnum getByStatus(Integer status) {
|
public static QuestionnaireRecordPassStatusEnum getByStatus(Integer status) {
|
||||||
|
if (status == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
for (QuestionnaireRecordPassStatusEnum value : values()) {
|
for (QuestionnaireRecordPassStatusEnum value : values()) {
|
||||||
if (value.getStatus().equals(status)) {
|
if (value.getStatus().equals(status)) {
|
||||||
return value;
|
return value;
|
||||||
@ -45,4 +50,5 @@ public enum QuestionnaireRecordPassStatusEnum {
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import lombok.Getter;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 问卷答题记录状态枚举
|
* 问卷答题记录状态枚举
|
||||||
|
* 状态:1-待测评 2-测评中 3-已完成 4-已过期 5-已取消
|
||||||
*
|
*
|
||||||
* @author 芋道源码
|
* @author 芋道源码
|
||||||
*/
|
*/
|
||||||
@ -12,8 +13,11 @@ import lombok.Getter;
|
|||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public enum QuestionnaireRecordStatusEnum {
|
public enum QuestionnaireRecordStatusEnum {
|
||||||
|
|
||||||
PENDING(1, "待评估"),
|
PENDING(1, "待测评"),
|
||||||
COMPLETED(2, "已完成");
|
IN_PROGRESS(2, "测评中"),
|
||||||
|
COMPLETED(3, "已完成"),
|
||||||
|
EXPIRED(4, "已过期"),
|
||||||
|
CANCELLED(5, "已取消");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 状态
|
* 状态
|
||||||
@ -45,4 +49,12 @@ public enum QuestionnaireRecordStatusEnum {
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断是否为待测评或测评中状态(可进行状态流转)
|
||||||
|
*/
|
||||||
|
public static boolean canTransition(Integer status) {
|
||||||
|
return PENDING.getStatus().equals(status) || IN_PROGRESS.getStatus().equals(status);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,37 @@
|
|||||||
|
package cn.iocoder.yudao.module.prison.enums.questionnaire;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 测评及格状态枚举
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public enum AssessmentPassStatusEnum {
|
||||||
|
|
||||||
|
PASSED(1, "及格"),
|
||||||
|
FAILED(2, "不及格"),
|
||||||
|
PENDING(3, "待评阅");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态
|
||||||
|
*/
|
||||||
|
private final Integer status;
|
||||||
|
/**
|
||||||
|
* 名称
|
||||||
|
*/
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
public static AssessmentPassStatusEnum getByStatus(Integer status) {
|
||||||
|
for (AssessmentPassStatusEnum statusEnum : values()) {
|
||||||
|
if (statusEnum.getStatus().equals(status)) {
|
||||||
|
return statusEnum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,39 @@
|
|||||||
|
package cn.iocoder.yudao.module.prison.enums.questionnaire;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 测评记录状态枚举
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public enum AssessmentRecordStatusEnum {
|
||||||
|
|
||||||
|
PENDING(1, "待测评"),
|
||||||
|
IN_PROGRESS(2, "测评中"),
|
||||||
|
COMPLETED(3, "已完成"),
|
||||||
|
EXPIRED(4, "已过期"),
|
||||||
|
CANCELLED(5, "已取消");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态
|
||||||
|
*/
|
||||||
|
private final Integer status;
|
||||||
|
/**
|
||||||
|
* 名称
|
||||||
|
*/
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
public static AssessmentRecordStatusEnum getByStatus(Integer status) {
|
||||||
|
for (AssessmentRecordStatusEnum statusEnum : values()) {
|
||||||
|
if (statusEnum.getStatus().equals(status)) {
|
||||||
|
return statusEnum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,37 @@
|
|||||||
|
package cn.iocoder.yudao.module.prison.enums.questionnaire;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 风险等级枚举
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public enum RiskLevelEnum {
|
||||||
|
|
||||||
|
HIGH(1, "高风险"),
|
||||||
|
MEDIUM(2, "中风险"),
|
||||||
|
LOW(3, "低风险");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 等级
|
||||||
|
*/
|
||||||
|
private final Integer level;
|
||||||
|
/**
|
||||||
|
* 名称
|
||||||
|
*/
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
public static RiskLevelEnum getByLevel(Integer level) {
|
||||||
|
for (RiskLevelEnum levelEnum : values()) {
|
||||||
|
if (levelEnum.getLevel().equals(level)) {
|
||||||
|
return levelEnum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,97 @@
|
|||||||
|
package cn.iocoder.yudao.module.prison.service.answer;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import jakarta.validation.*;
|
||||||
|
import cn.iocoder.yudao.module.prison.controller.admin.answer.vo.*;
|
||||||
|
import cn.iocoder.yudao.module.prison.controller.admin.questionnairerecord.vo.AssessmentAnswerSubmitReqVO;
|
||||||
|
import cn.iocoder.yudao.module.prison.dal.dataobject.answer.AnswerDO;
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 问卷答题记录 Service 接口
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
public interface AnswerService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建答题记录
|
||||||
|
*
|
||||||
|
* @param createReqVO 创建信息
|
||||||
|
* @return 编号
|
||||||
|
*/
|
||||||
|
Long createAnswer(@Valid AnswerSaveReqVO createReqVO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新答题记录
|
||||||
|
*
|
||||||
|
* @param updateReqVO 更新信息
|
||||||
|
*/
|
||||||
|
void updateAnswer(@Valid AnswerSaveReqVO updateReqVO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除答题记录
|
||||||
|
*
|
||||||
|
* @param id 编号
|
||||||
|
*/
|
||||||
|
void deleteAnswer(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量删除答题记录
|
||||||
|
*
|
||||||
|
* @param ids 编号列表
|
||||||
|
*/
|
||||||
|
void deleteAnswerListByIds(List<Long> ids);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得答题记录
|
||||||
|
*
|
||||||
|
* @param id 编号
|
||||||
|
* @return 答题记录
|
||||||
|
*/
|
||||||
|
AnswerDO getAnswer(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得答题记录分页
|
||||||
|
*
|
||||||
|
* @param pageReqVO 分页查询
|
||||||
|
* @return 答题记录分页
|
||||||
|
*/
|
||||||
|
PageResult<AnswerDO> getAnswerPage(AnswerPageReqVO pageReqVO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据测评记录ID查询所有答题记录
|
||||||
|
*
|
||||||
|
* @param assessmentRecordId 测评记录ID
|
||||||
|
* @return 答题记录列表
|
||||||
|
*/
|
||||||
|
List<AnswerDO> getAnswersByAssessmentRecordId(Long assessmentRecordId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量保存答题记录(提交答卷时使用)
|
||||||
|
*
|
||||||
|
* @param assessmentRecordId 测评记录ID
|
||||||
|
* @param questionnaireId 问卷ID
|
||||||
|
* @param prisonerId 罪犯ID
|
||||||
|
* @param answers 答题详情列表
|
||||||
|
*/
|
||||||
|
void saveAnswers(Long assessmentRecordId, Long questionnaireId, Long prisonerId, List<AssessmentAnswerSubmitReqVO.AnswerItem> answers);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算客观题得分并更新
|
||||||
|
*
|
||||||
|
* @param assessmentRecordId 测评记录ID
|
||||||
|
* @return 总客观题得分
|
||||||
|
*/
|
||||||
|
BigDecimal calculateObjectiveScore(Long assessmentRecordId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据测评记录ID删除所有答题记录
|
||||||
|
*
|
||||||
|
* @param assessmentRecordId 测评记录ID
|
||||||
|
*/
|
||||||
|
void deleteByAssessmentRecordId(Long assessmentRecordId);
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,373 @@
|
|||||||
|
package cn.iocoder.yudao.module.prison.service.answer;
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.alibaba.fastjson.JSONArray;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.math.RoundingMode;
|
||||||
|
import cn.iocoder.yudao.module.prison.controller.admin.answer.vo.*;
|
||||||
|
import cn.iocoder.yudao.module.prison.controller.admin.questionnairerecord.vo.AssessmentAnswerSubmitReqVO;
|
||||||
|
import cn.iocoder.yudao.module.prison.dal.dataobject.answer.AnswerDO;
|
||||||
|
import cn.iocoder.yudao.module.prison.dal.dataobject.question.QuestionDO;
|
||||||
|
import cn.iocoder.yudao.module.prison.dal.mysql.answer.AnswerMapper;
|
||||||
|
import cn.iocoder.yudao.module.prison.dal.mysql.question.QuestionMapper;
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
|
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||||
|
import cn.iocoder.yudao.module.prison.enums.QuestionnaireRecordPassStatusEnum;
|
||||||
|
|
||||||
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||||
|
import static cn.iocoder.yudao.module.prison.enums.ErrorCodeConstants.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 问卷答题记录 Service 实现类
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@Validated
|
||||||
|
public class AnswerServiceImpl implements AnswerService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private AnswerMapper answerMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private QuestionMapper questionMapper;
|
||||||
|
|
||||||
|
// 问题类型常量
|
||||||
|
private static final int QUESTION_TYPE_SINGLE = 1; // 单选
|
||||||
|
private static final int QUESTION_TYPE_MULTI = 2; // 多选
|
||||||
|
private static final int QUESTION_TYPE_FILL = 3; // 填空
|
||||||
|
private static final int QUESTION_TYPE_SCORE = 4; // 评分
|
||||||
|
private static final int QUESTION_TYPE_DATE = 5; // 日期
|
||||||
|
private static final int QUESTION_TYPE_NUMBER = 6; // 数字
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long createAnswer(AnswerSaveReqVO createReqVO) {
|
||||||
|
// 插入
|
||||||
|
AnswerDO answer = BeanUtils.toBean(createReqVO, AnswerDO.class);
|
||||||
|
answerMapper.insert(answer);
|
||||||
|
return answer.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateAnswer(AnswerSaveReqVO updateReqVO) {
|
||||||
|
// 校验存在
|
||||||
|
validateAnswerExists(updateReqVO.getId());
|
||||||
|
// 更新
|
||||||
|
AnswerDO updateObj = BeanUtils.toBean(updateReqVO, AnswerDO.class);
|
||||||
|
answerMapper.updateById(updateObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteAnswer(Long id) {
|
||||||
|
// 校验存在
|
||||||
|
validateAnswerExists(id);
|
||||||
|
// 删除
|
||||||
|
answerMapper.deleteById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteAnswerListByIds(List<Long> ids) {
|
||||||
|
if (CollUtil.isEmpty(ids)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 校验所有ID都存在
|
||||||
|
Long count = answerMapper.selectCount(new LambdaQueryWrapper<AnswerDO>()
|
||||||
|
.in(AnswerDO::getId, ids));
|
||||||
|
if (count == null || count != ids.size()) {
|
||||||
|
throw exception(ANSWER_NOT_EXISTS);
|
||||||
|
}
|
||||||
|
// 删除
|
||||||
|
answerMapper.deleteByIds(ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateAnswerExists(Long id) {
|
||||||
|
if (answerMapper.selectById(id) == null) {
|
||||||
|
throw exception(ANSWER_NOT_EXISTS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AnswerDO getAnswer(Long id) {
|
||||||
|
return answerMapper.selectById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PageResult<AnswerDO> getAnswerPage(AnswerPageReqVO pageReqVO) {
|
||||||
|
return answerMapper.selectPage(pageReqVO);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<AnswerDO> getAnswersByAssessmentRecordId(Long assessmentRecordId) {
|
||||||
|
return answerMapper.selectListByAssessmentRecordId(assessmentRecordId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void saveAnswers(Long assessmentRecordId, Long questionnaireId, Long prisonerId,
|
||||||
|
List<AssessmentAnswerSubmitReqVO.AnswerItem> answers) {
|
||||||
|
if (CollUtil.isEmpty(answers)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (AssessmentAnswerSubmitReqVO.AnswerItem answerItem : answers) {
|
||||||
|
// 获取问题信息
|
||||||
|
QuestionDO question = questionMapper.selectById(answerItem.getQuestionId());
|
||||||
|
if (question == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建答题记录
|
||||||
|
AnswerDO answer = new AnswerDO();
|
||||||
|
answer.setAssessmentRecordId(assessmentRecordId);
|
||||||
|
answer.setQuestionId(answerItem.getQuestionId());
|
||||||
|
answer.setQuestionnaireId(questionnaireId);
|
||||||
|
answer.setPrisonerId(prisonerId);
|
||||||
|
answer.setQuestionType(question.getType());
|
||||||
|
|
||||||
|
// 设置答案内容
|
||||||
|
if (answerItem.getOptionIds() != null && !answerItem.getOptionIds().isEmpty()) {
|
||||||
|
answer.setOptionIds(JSONArray.toJSONString(answerItem.getOptionIds()));
|
||||||
|
}
|
||||||
|
if (answerItem.getAnswer() != null) {
|
||||||
|
answer.setAnswerText(answerItem.getAnswer());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算得分(单选/多选题)
|
||||||
|
BigDecimal score = calculateQuestionScore(question, answerItem);
|
||||||
|
answer.setScore(score);
|
||||||
|
|
||||||
|
// 判断是否正确(单选/多选题)
|
||||||
|
if (question.getType() == QUESTION_TYPE_SINGLE || question.getType() == QUESTION_TYPE_MULTI) {
|
||||||
|
Boolean isCorrect = isAnswerCorrect(question, answerItem);
|
||||||
|
answer.setIsCorrect(isCorrect);
|
||||||
|
}
|
||||||
|
|
||||||
|
answerMapper.insert(answer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public BigDecimal calculateObjectiveScore(Long assessmentRecordId) {
|
||||||
|
// 获取该测评的所有答题记录
|
||||||
|
List<AnswerDO> answers = answerMapper.selectListByAssessmentRecordId(assessmentRecordId);
|
||||||
|
if (CollUtil.isEmpty(answers)) {
|
||||||
|
return BigDecimal.ZERO;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算客观题得分(单选、多选)
|
||||||
|
BigDecimal totalScore = BigDecimal.ZERO;
|
||||||
|
for (AnswerDO answer : answers) {
|
||||||
|
if (answer.getScore() != null) {
|
||||||
|
totalScore = totalScore.add(answer.getScore());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return totalScore.setScale(2, RoundingMode.HALF_UP);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteByAssessmentRecordId(Long assessmentRecordId) {
|
||||||
|
answerMapper.deleteByAssessmentRecordId(assessmentRecordId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算单题得分
|
||||||
|
*/
|
||||||
|
private BigDecimal calculateQuestionScore(QuestionDO question, AssessmentAnswerSubmitReqVO.AnswerItem answerItem) {
|
||||||
|
if (question.getType() == QUESTION_TYPE_SINGLE || question.getType() == QUESTION_TYPE_MULTI) {
|
||||||
|
// 单选/多选题:根据选项计算得分
|
||||||
|
return calculateChoiceQuestionScore(question, answerItem);
|
||||||
|
} else if (question.getType() == QUESTION_TYPE_SCORE) {
|
||||||
|
// 评分题:直接使用用户评分
|
||||||
|
try {
|
||||||
|
if (answerItem.getAnswer() != null) {
|
||||||
|
return new BigDecimal(answerItem.getAnswer());
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
return BigDecimal.ZERO;
|
||||||
|
}
|
||||||
|
} else if (question.getType() == QUESTION_TYPE_NUMBER) {
|
||||||
|
// 数字题:根据范围计算部分分数
|
||||||
|
return calculateNumberQuestionScore(question, answerItem);
|
||||||
|
}
|
||||||
|
// 填空题、日期题暂不计算分数
|
||||||
|
return BigDecimal.ZERO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算选择题得分
|
||||||
|
* 选项格式: [{label:"选项1",score:10,isCorrect:true},...]
|
||||||
|
*/
|
||||||
|
private BigDecimal calculateChoiceQuestionScore(QuestionDO question, AssessmentAnswerSubmitReqVO.AnswerItem answerItem) {
|
||||||
|
if (question.getOptions() == null || question.getOptions().isEmpty()) {
|
||||||
|
return BigDecimal.ZERO;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
JSONArray options = JSON.parseArray(question.getOptions());
|
||||||
|
if (options.isEmpty()) {
|
||||||
|
return BigDecimal.ZERO;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取问题总分
|
||||||
|
BigDecimal questionScore = question.getScore() != null ? question.getScore() : BigDecimal.ZERO;
|
||||||
|
|
||||||
|
if (question.getType() == QUESTION_TYPE_SINGLE) {
|
||||||
|
// 单选题:选对得满分,选错得0分
|
||||||
|
if (answerItem.getOptionIds() == null || answerItem.getOptionIds().isEmpty()) {
|
||||||
|
return BigDecimal.ZERO;
|
||||||
|
}
|
||||||
|
Long selectedOptionId = answerItem.getOptionIds().get(0);
|
||||||
|
for (int i = 0; i < options.size(); i++) {
|
||||||
|
JSONObject option = options.getJSONObject(i);
|
||||||
|
if (option.getLong("id") != null && option.getLong("id").equals(selectedOptionId)) {
|
||||||
|
// 检查是否正确选项
|
||||||
|
if (option.getBoolean("isCorrect") != null && option.getBoolean("isCorrect")) {
|
||||||
|
return questionScore;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return BigDecimal.ZERO;
|
||||||
|
} else if (question.getType() == QUESTION_TYPE_MULTI) {
|
||||||
|
// 多选题:部分得分逻辑
|
||||||
|
if (answerItem.getOptionIds() == null || answerItem.getOptionIds().isEmpty()) {
|
||||||
|
return BigDecimal.ZERO;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 统计正确选项和用户选择
|
||||||
|
int correctCount = 0;
|
||||||
|
int userSelectCount = answerItem.getOptionIds().size();
|
||||||
|
|
||||||
|
for (int i = 0; i < options.size(); i++) {
|
||||||
|
JSONObject option = options.getJSONObject(i);
|
||||||
|
if (option.getBoolean("isCorrect") != null && option.getBoolean("isCorrect")) {
|
||||||
|
correctCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户选择的正确选项数量
|
||||||
|
int userCorrectCount = 0;
|
||||||
|
for (Long selectedOptionId : answerItem.getOptionIds()) {
|
||||||
|
for (int i = 0; i < options.size(); i++) {
|
||||||
|
JSONObject option = options.getJSONObject(i);
|
||||||
|
if (option.getLong("id") != null && option.getLong("id").equals(selectedOptionId)
|
||||||
|
&& option.getBoolean("isCorrect") != null && option.getBoolean("isCorrect")) {
|
||||||
|
userCorrectCount++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算得分:按正确比例给分
|
||||||
|
if (correctCount == 0) {
|
||||||
|
return BigDecimal.ZERO;
|
||||||
|
}
|
||||||
|
// 选对得满分,选错不扣分但按比例得分
|
||||||
|
double ratio = (double) userCorrectCount / correctCount;
|
||||||
|
return questionScore.multiply(BigDecimal.valueOf(ratio)).setScale(2, RoundingMode.HALF_UP);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
// 解析失败返回0分
|
||||||
|
return BigDecimal.ZERO;
|
||||||
|
}
|
||||||
|
|
||||||
|
return BigDecimal.ZERO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算数字题得分
|
||||||
|
*/
|
||||||
|
private BigDecimal calculateNumberQuestionScore(QuestionDO question, AssessmentAnswerSubmitReqVO.AnswerItem answerItem) {
|
||||||
|
if (answerItem.getAnswer() == null || answerItem.getAnswer().isEmpty()) {
|
||||||
|
return BigDecimal.ZERO;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
double userValue = Double.parseDouble(answerItem.getAnswer());
|
||||||
|
Integer minValue = question.getMinValue();
|
||||||
|
Integer maxValue = question.getMaxValue();
|
||||||
|
BigDecimal questionScore = question.getScore() != null ? question.getScore() : BigDecimal.ZERO;
|
||||||
|
|
||||||
|
// 如果有范围限制,按比例给分
|
||||||
|
if (minValue != null && maxValue != null && maxValue > minValue) {
|
||||||
|
if (userValue < minValue) {
|
||||||
|
return BigDecimal.ZERO;
|
||||||
|
} else if (userValue >= maxValue) {
|
||||||
|
return questionScore;
|
||||||
|
} else {
|
||||||
|
double ratio = (userValue - minValue) / (maxValue - minValue);
|
||||||
|
return questionScore.multiply(BigDecimal.valueOf(ratio)).setScale(2, RoundingMode.HALF_UP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 没有范围限制给满分
|
||||||
|
return questionScore;
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
return BigDecimal.ZERO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断答案是否正确(单选/多选题)
|
||||||
|
*/
|
||||||
|
private Boolean isAnswerCorrect(QuestionDO question, AssessmentAnswerSubmitReqVO.AnswerItem answerItem) {
|
||||||
|
if (question.getOptions() == null || question.getOptions().isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
JSONArray options = JSON.parseArray(question.getOptions());
|
||||||
|
|
||||||
|
if (question.getType() == QUESTION_TYPE_SINGLE) {
|
||||||
|
// 单选题:检查是否选择了正确选项
|
||||||
|
if (answerItem.getOptionIds() == null || answerItem.getOptionIds().isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Long selectedOptionId = answerItem.getOptionIds().get(0);
|
||||||
|
for (int i = 0; i < options.size(); i++) {
|
||||||
|
JSONObject option = options.getJSONObject(i);
|
||||||
|
if (option.getLong("id") != null && option.getLong("id").equals(selectedOptionId)) {
|
||||||
|
return option.getBoolean("isCorrect") != null && option.getBoolean("isCorrect");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} else if (question.getType() == QUESTION_TYPE_MULTI) {
|
||||||
|
// 多选题:检查是否全部选择正确选项且没有选择错误选项
|
||||||
|
if (answerItem.getOptionIds() == null || answerItem.getOptionIds().isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<Long> correctOptionIds = new HashSet<>();
|
||||||
|
Set<Long> userSelectedIds = new HashSet<>(answerItem.getOptionIds());
|
||||||
|
|
||||||
|
for (int i = 0; i < options.size(); i++) {
|
||||||
|
JSONObject option = options.getJSONObject(i);
|
||||||
|
if (option.getBoolean("isCorrect") != null && option.getBoolean("isCorrect")) {
|
||||||
|
correctOptionIds.add(option.getLong("id"));
|
||||||
|
} else if (option.getBoolean("isCorrect") != null && !option.getBoolean("isCorrect")
|
||||||
|
&& userSelectedIds.contains(option.getLong("id"))) {
|
||||||
|
// 选择了错误选项
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户必须选择所有正确选项
|
||||||
|
return correctOptionIds.equals(userSelectedIds);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,110 +0,0 @@
|
|||||||
package cn.iocoder.yudao.module.prison.service.assessment;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
import jakarta.validation.*;
|
|
||||||
import cn.iocoder.yudao.module.prison.controller.admin.assessment.vo.*;
|
|
||||||
import cn.iocoder.yudao.module.prison.dal.dataobject.assessment.AssessmentAnswerDO;
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 答卷详情 Service 接口
|
|
||||||
*
|
|
||||||
* @author 芋道源码
|
|
||||||
*/
|
|
||||||
public interface AssessmentAnswerService {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建答卷
|
|
||||||
*
|
|
||||||
* @param createReqVO 创建信息
|
|
||||||
* @return 编号
|
|
||||||
*/
|
|
||||||
Long createAssessmentAnswer(@Valid AssessmentAnswerSaveReqVO createReqVO);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新答卷
|
|
||||||
*
|
|
||||||
* @param updateReqVO 更新信息
|
|
||||||
*/
|
|
||||||
void updateAssessmentAnswer(@Valid AssessmentAnswerSaveReqVO updateReqVO);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 删除答卷
|
|
||||||
*
|
|
||||||
* @param id 编号
|
|
||||||
*/
|
|
||||||
void deleteAssessmentAnswer(Long id);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 批量删除答卷
|
|
||||||
*
|
|
||||||
* @param ids 编号列表
|
|
||||||
*/
|
|
||||||
void deleteAssessmentAnswerListByIds(List<Long> ids);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获得答卷
|
|
||||||
*
|
|
||||||
* @param id 编号
|
|
||||||
* @return 答卷
|
|
||||||
*/
|
|
||||||
AssessmentAnswerDO getAssessmentAnswer(Long id);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获得答卷分页
|
|
||||||
*
|
|
||||||
* @param pageReqVO 分页查询
|
|
||||||
* @return 答卷分页
|
|
||||||
*/
|
|
||||||
PageResult<AssessmentAnswerDO> getAssessmentAnswerPage(AssessmentAnswerPageReqVO pageReqVO);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 开始答题
|
|
||||||
*
|
|
||||||
* @param assessmentRecordId 测评记录ID
|
|
||||||
* @param prisonerId 囚犯ID
|
|
||||||
* @return 答卷ID
|
|
||||||
*/
|
|
||||||
Long startAnswer(Long assessmentRecordId, Long prisonerId);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 提交答卷
|
|
||||||
*
|
|
||||||
* @param submitReqVO 提交信息
|
|
||||||
*/
|
|
||||||
void submitAnswer(AssessmentAnswerSubmitReqVO submitReqVO);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据囚犯ID和测评记录ID获取答卷
|
|
||||||
*
|
|
||||||
* @param prisonerId 囚犯ID
|
|
||||||
* @param assessmentRecordId 测评记录ID
|
|
||||||
* @return 答卷
|
|
||||||
*/
|
|
||||||
AssessmentAnswerDO getByPrisonerAndRecord(Long prisonerId, Long assessmentRecordId);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取待评分列表
|
|
||||||
*
|
|
||||||
* @param pageReqVO 分页查询
|
|
||||||
* @return 待评分答卷分页
|
|
||||||
*/
|
|
||||||
PageResult<AssessmentAnswerDO> getPendingScorePage(AssessmentAnswerPageReqVO pageReqVO);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 人工评分
|
|
||||||
*
|
|
||||||
* @param scoreReqVO 评分信息
|
|
||||||
*/
|
|
||||||
void manualScore(AssessmentAnswerManualScoreReqVO scoreReqVO);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取已完成答卷列表
|
|
||||||
*
|
|
||||||
* @param assessmentRecordId 测评记录ID
|
|
||||||
* @return 答卷列表
|
|
||||||
*/
|
|
||||||
List<AssessmentAnswerDO> getCompletedAnswersByRecordId(Long assessmentRecordId);
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,91 +0,0 @@
|
|||||||
package cn.iocoder.yudao.module.prison.service.assessment;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
import jakarta.validation.*;
|
|
||||||
import cn.iocoder.yudao.module.prison.controller.admin.assessment.vo.*;
|
|
||||||
import cn.iocoder.yudao.module.prison.dal.dataobject.assessment.AssessmentRecordDO;
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 测评记录 Service 接口
|
|
||||||
*
|
|
||||||
* @author 芋道源码
|
|
||||||
*/
|
|
||||||
public interface AssessmentRecordService {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建测评记录
|
|
||||||
*
|
|
||||||
* @param createReqVO 创建信息
|
|
||||||
* @return 编号
|
|
||||||
*/
|
|
||||||
Long createAssessmentRecord(@Valid AssessmentRecordSaveReqVO createReqVO);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新测评记录
|
|
||||||
*
|
|
||||||
* @param updateReqVO 更新信息
|
|
||||||
*/
|
|
||||||
void updateAssessmentRecord(@Valid AssessmentRecordSaveReqVO updateReqVO);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 删除测评记录
|
|
||||||
*
|
|
||||||
* @param id 编号
|
|
||||||
*/
|
|
||||||
void deleteAssessmentRecord(Long id);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 批量删除测评记录
|
|
||||||
*
|
|
||||||
* @param ids 编号列表
|
|
||||||
*/
|
|
||||||
void deleteAssessmentRecordListByIds(List<Long> ids);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获得测评记录
|
|
||||||
*
|
|
||||||
* @param id 编号
|
|
||||||
* @return 测评记录
|
|
||||||
*/
|
|
||||||
AssessmentRecordDO getAssessmentRecord(Long id);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获得测评记录分页
|
|
||||||
*
|
|
||||||
* @param pageReqVO 分页查询
|
|
||||||
* @return 测评记录分页
|
|
||||||
*/
|
|
||||||
PageResult<AssessmentRecordDO> getAssessmentRecordPage(AssessmentRecordPageReqVO pageReqVO);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 发起测评
|
|
||||||
*
|
|
||||||
* @param reqVO 发起信息
|
|
||||||
* @return 测评记录ID
|
|
||||||
*/
|
|
||||||
Long initiateAssessment(AssessmentRecordSaveReqVO reqVO);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 取消测评
|
|
||||||
*
|
|
||||||
* @param id 测评记录ID
|
|
||||||
*/
|
|
||||||
void cancelAssessment(Long id);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 启动测评
|
|
||||||
*
|
|
||||||
* @param id 测评记录ID
|
|
||||||
*/
|
|
||||||
void startAssessment(Long id);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 结束测评
|
|
||||||
*
|
|
||||||
* @param id 测评记录ID
|
|
||||||
*/
|
|
||||||
void finishAssessment(Long id);
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,106 +0,0 @@
|
|||||||
package cn.iocoder.yudao.module.prison.service.assessment;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
import jakarta.validation.*;
|
|
||||||
import cn.iocoder.yudao.module.prison.controller.admin.assessment.vo.*;
|
|
||||||
import cn.iocoder.yudao.module.prison.dal.dataobject.assessment.AssessmentResultDO;
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 测评结果 Service 接口
|
|
||||||
*
|
|
||||||
* @author 芋道源码
|
|
||||||
*/
|
|
||||||
public interface AssessmentResultService {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建测评结果
|
|
||||||
*
|
|
||||||
* @param createReqVO 创建信息
|
|
||||||
* @return 编号
|
|
||||||
*/
|
|
||||||
Long createAssessmentResult(@Valid AssessmentResultSaveReqVO createReqVO);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 批量创建测评结果
|
|
||||||
*
|
|
||||||
* @param results 结果列表
|
|
||||||
*/
|
|
||||||
void batchCreateAssessmentResult(List<AssessmentResultSaveReqVO> results);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新测评结果
|
|
||||||
*
|
|
||||||
* @param updateReqVO 更新信息
|
|
||||||
*/
|
|
||||||
void updateAssessmentResult(@Valid AssessmentResultSaveReqVO updateReqVO);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 删除测评结果
|
|
||||||
*
|
|
||||||
* @param id 编号
|
|
||||||
*/
|
|
||||||
void deleteAssessmentResult(Long id);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 批量删除测评结果
|
|
||||||
*
|
|
||||||
* @param ids 编号列表
|
|
||||||
*/
|
|
||||||
void deleteAssessmentResultListByIds(List<Long> ids);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获得测评结果
|
|
||||||
*
|
|
||||||
* @param id 编号
|
|
||||||
* @return 测评结果
|
|
||||||
*/
|
|
||||||
AssessmentResultDO getAssessmentResult(Long id);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获得测评结果分页
|
|
||||||
*
|
|
||||||
* @param pageReqVO 分页查询
|
|
||||||
* @return 测评结果分页
|
|
||||||
*/
|
|
||||||
PageResult<AssessmentResultDO> getAssessmentResultPage(AssessmentResultPageReqVO pageReqVO);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据答卷ID获取所有结果
|
|
||||||
*
|
|
||||||
* @param answerId 答卷ID
|
|
||||||
* @return 结果列表
|
|
||||||
*/
|
|
||||||
List<AssessmentResultDO> getResultsByAnswerId(Long answerId);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据测评记录ID获取所有结果
|
|
||||||
*
|
|
||||||
* @param assessmentRecordId 测评记录ID
|
|
||||||
* @return 结果列表
|
|
||||||
*/
|
|
||||||
List<AssessmentResultDO> getResultsByAssessmentRecordId(Long assessmentRecordId);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取需要人工评阅的结果列表
|
|
||||||
*
|
|
||||||
* @return 需要人工评阅的结果列表
|
|
||||||
*/
|
|
||||||
List<AssessmentResultDO> getNeedManualReviewList();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 人工评阅
|
|
||||||
*
|
|
||||||
* @param reviewReqVO 评阅信息
|
|
||||||
*/
|
|
||||||
void manualReview(AssessmentResultManualReviewReqVO reviewReqVO);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 自动评分
|
|
||||||
*
|
|
||||||
* @param answerId 答卷ID
|
|
||||||
*/
|
|
||||||
void autoScore(Long answerId);
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,73 +0,0 @@
|
|||||||
package cn.iocoder.yudao.module.prison.service.assessment;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
import jakarta.validation.*;
|
|
||||||
import cn.iocoder.yudao.module.prison.controller.admin.assessment.vo.*;
|
|
||||||
import cn.iocoder.yudao.module.prison.dal.dataobject.assessment.AssessmentStatisticsDO;
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 测评统计 Service 接口
|
|
||||||
*
|
|
||||||
* @author 芋道源码
|
|
||||||
*/
|
|
||||||
public interface AssessmentStatisticsService {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获得测评统计
|
|
||||||
*
|
|
||||||
* @param id 编号
|
|
||||||
* @return 测评统计
|
|
||||||
*/
|
|
||||||
AssessmentStatisticsDO getAssessmentStatistics(Long id);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获得测评统计分页
|
|
||||||
*
|
|
||||||
* @param pageReqVO 分页查询
|
|
||||||
* @return 测评统计分页
|
|
||||||
*/
|
|
||||||
PageResult<AssessmentStatisticsDO> getAssessmentStatisticsPage(AssessmentStatisticsPageReqVO pageReqVO);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 生成测评统计
|
|
||||||
*
|
|
||||||
* @param assessmentRecordId 测评记录ID
|
|
||||||
* @return 统计信息
|
|
||||||
*/
|
|
||||||
AssessmentStatisticsDO generateStatistics(Long assessmentRecordId);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取测评完成率
|
|
||||||
*
|
|
||||||
* @param assessmentRecordId 测评记录ID
|
|
||||||
* @return 完成率
|
|
||||||
*/
|
|
||||||
java.math.BigDecimal getCompletionRate(Long assessmentRecordId);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取分数分布
|
|
||||||
*
|
|
||||||
* @param assessmentRecordId 测评记录ID
|
|
||||||
* @return 分数分布
|
|
||||||
*/
|
|
||||||
Map<String, Integer> getScoreDistribution(Long assessmentRecordId);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取风险分布
|
|
||||||
*
|
|
||||||
* @param assessmentRecordId 测评记录ID
|
|
||||||
* @return 风险分布
|
|
||||||
*/
|
|
||||||
Map<String, Integer> getRiskDistribution(Long assessmentRecordId);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取测评分析报告
|
|
||||||
*
|
|
||||||
* @param assessmentRecordId 测评记录ID
|
|
||||||
* @return 分析报告
|
|
||||||
*/
|
|
||||||
AssessmentStatisticsRespVO getAssessmentReport(Long assessmentRecordId);
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,163 +0,0 @@
|
|||||||
package cn.iocoder.yudao.module.prison.service.assessment.impl;
|
|
||||||
|
|
||||||
import cn.hutool.core.collection.CollUtil;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
import jakarta.annotation.Resource;
|
|
||||||
import org.springframework.validation.annotation.Validated;
|
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import cn.iocoder.yudao.module.prison.controller.admin.assessment.vo.*;
|
|
||||||
import cn.iocoder.yudao.module.prison.dal.dataobject.assessment.AssessmentAnswerDO;
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
|
||||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.module.prison.dal.mysql.assessment.AssessmentAnswerMapper;
|
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
|
||||||
import static cn.iocoder.yudao.module.prison.enums.ErrorCodeConstants.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 答卷详情 Service 实现类
|
|
||||||
*
|
|
||||||
* @author 芋道源码
|
|
||||||
*/
|
|
||||||
@Service
|
|
||||||
@Validated
|
|
||||||
public class AssessmentAnswerServiceImpl implements AssessmentAnswerService {
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private AssessmentAnswerMapper assessmentAnswerMapper;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
|
||||||
public Long createAssessmentAnswer(AssessmentAnswerSaveReqVO createReqVO) {
|
|
||||||
AssessmentAnswerDO answer = BeanUtils.toBean(createReqVO, AssessmentAnswerDO.class);
|
|
||||||
assessmentAnswerMapper.insert(answer);
|
|
||||||
return answer.getId();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
|
||||||
public void updateAssessmentAnswer(AssessmentAnswerSaveReqVO updateReqVO) {
|
|
||||||
validateAssessmentAnswerExists(updateReqVO.getId());
|
|
||||||
AssessmentAnswerDO updateObj = BeanUtils.toBean(updateReqVO, AssessmentAnswerDO.class);
|
|
||||||
assessmentAnswerMapper.updateById(updateObj);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
|
||||||
public void deleteAssessmentAnswer(Long id) {
|
|
||||||
validateAssessmentAnswerExists(id);
|
|
||||||
assessmentAnswerMapper.deleteById(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
|
||||||
public void deleteAssessmentAnswerListByIds(List<Long> ids) {
|
|
||||||
assessmentAnswerMapper.deleteByIds(ids);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AssessmentAnswerDO getAssessmentAnswer(Long id) {
|
|
||||||
return assessmentAnswerMapper.selectById(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PageResult<AssessmentAnswerDO> getAssessmentAnswerPage(AssessmentAnswerPageReqVO pageReqVO) {
|
|
||||||
return assessmentAnswerMapper.selectPage(pageReqVO);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
|
||||||
public Long startAnswer(Long assessmentRecordId, Long prisonerId) {
|
|
||||||
// 检查是否已有答卷
|
|
||||||
AssessmentAnswerDO existingAnswer = assessmentAnswerMapper.selectOne(
|
|
||||||
new cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX<AssessmentAnswerDO>()
|
|
||||||
.eqIfPresent(AssessmentAnswerDO::getAssessmentRecordId, assessmentRecordId)
|
|
||||||
.eqIfPresent(AssessmentAnswerDO::getPrisonerId, prisonerId)
|
|
||||||
);
|
|
||||||
if (existingAnswer != null && !Arrays.asList(1, 2).contains(existingAnswer.getStatus())) {
|
|
||||||
throw exception(ASSESSMENT_ANSWER_ALREADY_EXISTS);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (existingAnswer != null) {
|
|
||||||
return existingAnswer.getId();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 创建新答卷
|
|
||||||
AssessmentAnswerDO answer = new AssessmentAnswerDO();
|
|
||||||
answer.setAssessmentRecordId(assessmentRecordId);
|
|
||||||
answer.setPrisonerId(prisonerId);
|
|
||||||
answer.setStatus(2); // 答题中
|
|
||||||
answer.setStartTime(LocalDateTime.now());
|
|
||||||
assessmentAnswerMapper.insert(answer);
|
|
||||||
return answer.getId();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
|
||||||
public void submitAnswer(AssessmentAnswerSubmitReqVO submitReqVO) {
|
|
||||||
AssessmentAnswerDO answer = validateAssessmentAnswerExists(submitReqVO.getId());
|
|
||||||
if (!Objects.equals(answer.getStatus(), 2)) {
|
|
||||||
throw exception(ASSESSMENT_ANSWER_STATUS_ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
answer.setStatus(3); // 已提交
|
|
||||||
answer.setSubmitTime(LocalDateTime.now());
|
|
||||||
if (answer.getStartTime() != null) {
|
|
||||||
answer.setDuration((int) java.time.Duration.between(answer.getStartTime(), LocalDateTime.now()).getSeconds());
|
|
||||||
}
|
|
||||||
assessmentAnswerMapper.updateById(answer);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AssessmentAnswerDO getByPrisonerAndRecord(Long prisonerId, Long assessmentRecordId) {
|
|
||||||
return assessmentAnswerMapper.selectOne(
|
|
||||||
new cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX<AssessmentAnswerDO>()
|
|
||||||
.eqIfPresent(AssessmentAnswerDO::getPrisonerId, prisonerId)
|
|
||||||
.eqIfPresent(AssessmentAnswerDO::getAssessmentRecordId, assessmentRecordId)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PageResult<AssessmentAnswerDO> getPendingScorePage(AssessmentAnswerPageReqVO pageReqVO) {
|
|
||||||
// 查询已提交但未评分的答卷
|
|
||||||
pageReqVO.setStatus(3); // 已提交
|
|
||||||
return assessmentAnswerMapper.selectPage(pageReqVO);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
|
||||||
public void manualScore(AssessmentAnswerManualScoreReqVO scoreReqVO) {
|
|
||||||
AssessmentAnswerDO answer = validateAssessmentAnswerExists(scoreReqVO.getId());
|
|
||||||
answer.setSubjectiveScore(scoreReqVO.getSubjectiveScore());
|
|
||||||
answer.setTotalScore(answer.getObjectiveScore() != null ? answer.getObjectiveScore() : BigDecimal.ZERO
|
|
||||||
.add(scoreReqVO.getSubjectiveScore() != null ? scoreReqVO.getSubjectiveScore() : BigDecimal.ZERO));
|
|
||||||
answer.setPassed(answer.getTotalScore().compareTo(answer.getPassScore()) >= 0);
|
|
||||||
answer.setComment(scoreReqVO.getComment());
|
|
||||||
answer.setStatus(5); // 已完成
|
|
||||||
assessmentAnswerMapper.updateById(answer);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<AssessmentAnswerDO> getCompletedAnswersByRecordId(Long assessmentRecordId) {
|
|
||||||
return assessmentAnswerMapper.selectList(
|
|
||||||
new cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX<AssessmentAnswerDO>()
|
|
||||||
.eqIfPresent(AssessmentAnswerDO::getAssessmentRecordId, assessmentRecordId)
|
|
||||||
.eqIfPresent(AssessmentAnswerDO::getStatus, 5)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private AssessmentAnswerDO validateAssessmentAnswerExists(Long id) {
|
|
||||||
AssessmentAnswerDO answer = assessmentAnswerMapper.selectById(id);
|
|
||||||
if (answer == null) {
|
|
||||||
throw exception(ASSESSMENT_ANSWER_NOT_EXISTS);
|
|
||||||
}
|
|
||||||
return answer;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,133 +0,0 @@
|
|||||||
package cn.iocoder.yudao.module.prison.service.assessment.impl;
|
|
||||||
|
|
||||||
import cn.hutool.core.collection.CollUtil;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
import jakarta.annotation.Resource;
|
|
||||||
import org.springframework.validation.annotation.Validated;
|
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
import cn.iocoder.yudao.module.prison.controller.admin.assessment.vo.*;
|
|
||||||
import cn.iocoder.yudao.module.prison.dal.dataobject.assessment.AssessmentRecordDO;
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
|
||||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.module.prison.dal.mysql.assessment.AssessmentRecordMapper;
|
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
|
||||||
import static cn.iocoder.yudao.module.prison.enums.ErrorCodeConstants.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 测评记录 Service 实现类
|
|
||||||
*
|
|
||||||
* @author 芋道源码
|
|
||||||
*/
|
|
||||||
@Service
|
|
||||||
@Validated
|
|
||||||
public class AssessmentRecordServiceImpl implements AssessmentRecordService {
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private AssessmentRecordMapper assessmentRecordMapper;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
|
||||||
public Long createAssessmentRecord(AssessmentRecordSaveReqVO createReqVO) {
|
|
||||||
// 插入
|
|
||||||
AssessmentRecordDO assessmentRecord = BeanUtils.toBean(createReqVO, AssessmentRecordDO.class);
|
|
||||||
assessmentRecordMapper.insert(assessmentRecord);
|
|
||||||
|
|
||||||
// 返回
|
|
||||||
return assessmentRecord.getId();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
|
||||||
public void updateAssessmentRecord(AssessmentRecordSaveReqVO updateReqVO) {
|
|
||||||
// 校验存在
|
|
||||||
validateAssessmentRecordExists(updateReqVO.getId());
|
|
||||||
// 更新
|
|
||||||
AssessmentRecordDO updateObj = BeanUtils.toBean(updateReqVO, AssessmentRecordDO.class);
|
|
||||||
assessmentRecordMapper.updateById(updateObj);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
|
||||||
public void deleteAssessmentRecord(Long id) {
|
|
||||||
// 校验存在
|
|
||||||
validateAssessmentRecordExists(id);
|
|
||||||
// 删除
|
|
||||||
assessmentRecordMapper.deleteById(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
|
||||||
public void deleteAssessmentRecordListByIds(List<Long> ids) {
|
|
||||||
assessmentRecordMapper.deleteByIds(ids);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AssessmentRecordDO getAssessmentRecord(Long id) {
|
|
||||||
return assessmentRecordMapper.selectById(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PageResult<AssessmentRecordDO> getAssessmentRecordPage(AssessmentRecordPageReqVO pageReqVO) {
|
|
||||||
return assessmentRecordMapper.selectPage(pageReqVO);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
|
||||||
public Long initiateAssessment(AssessmentRecordSaveReqVO reqVO) {
|
|
||||||
AssessmentRecordDO assessmentRecord = BeanUtils.toBean(reqVO, AssessmentRecordDO.class);
|
|
||||||
assessmentRecord.setStatus(1); // 未开始
|
|
||||||
assessmentRecord.setParticipantCount(0);
|
|
||||||
assessmentRecord.setCompletedCount(0);
|
|
||||||
assessmentRecordMapper.insert(assessmentRecord);
|
|
||||||
return assessmentRecord.getId();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
|
||||||
public void cancelAssessment(Long id) {
|
|
||||||
AssessmentRecordDO assessmentRecord = validateAssessmentRecordExists(id);
|
|
||||||
if (!Arrays.asList(1, 2).contains(assessmentRecord.getStatus())) {
|
|
||||||
throw exception(ASSESSMENT_RECORD_STATUS_ERROR);
|
|
||||||
}
|
|
||||||
assessmentRecord.setStatus(4); // 已取消
|
|
||||||
assessmentRecordMapper.updateById(assessmentRecord);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
|
||||||
public void startAssessment(Long id) {
|
|
||||||
AssessmentRecordDO assessmentRecord = validateAssessmentRecordExists(id);
|
|
||||||
if (!Objects.equals(assessmentRecord.getStatus(), 1)) {
|
|
||||||
throw exception(ASSESSMENT_RECORD_STATUS_ERROR);
|
|
||||||
}
|
|
||||||
assessmentRecord.setStatus(2); // 进行中
|
|
||||||
assessmentRecord.setActualStartTime(java.time.LocalDateTime.now());
|
|
||||||
assessmentRecordMapper.updateById(assessmentRecord);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
|
||||||
public void finishAssessment(Long id) {
|
|
||||||
AssessmentRecordDO assessmentRecord = validateAssessmentRecordExists(id);
|
|
||||||
if (!Objects.equals(assessmentRecord.getStatus(), 2)) {
|
|
||||||
throw exception(ASSESSMENT_RECORD_STATUS_ERROR);
|
|
||||||
}
|
|
||||||
assessmentRecord.setStatus(3); // 已完成
|
|
||||||
assessmentRecord.setActualEndTime(java.time.LocalDateTime.now());
|
|
||||||
assessmentRecordMapper.updateById(assessmentRecord);
|
|
||||||
}
|
|
||||||
|
|
||||||
private AssessmentRecordDO validateAssessmentRecordExists(Long id) {
|
|
||||||
AssessmentRecordDO assessmentRecord = assessmentRecordMapper.selectById(id);
|
|
||||||
if (assessmentRecord == null) {
|
|
||||||
throw exception(ASSESSMENT_RECORD_NOT_EXISTS);
|
|
||||||
}
|
|
||||||
return assessmentRecord;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,141 +0,0 @@
|
|||||||
package cn.iocoder.yudao.module.prison.service.assessment.impl;
|
|
||||||
|
|
||||||
import cn.hutool.core.collection.CollUtil;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
import jakarta.annotation.Resource;
|
|
||||||
import org.springframework.validation.annotation.Validated;
|
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import cn.iocoder.yudao.module.prison.controller.admin.assessment.vo.*;
|
|
||||||
import cn.iocoder.yudao.module.prison.dal.dataobject.assessment.AssessmentResultDO;
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
|
||||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.module.prison.dal.mysql.assessment.AssessmentResultMapper;
|
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
|
||||||
import static cn.iocoder.yudao.module.prison.enums.ErrorCodeConstants.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 测评结果 Service 实现类
|
|
||||||
*
|
|
||||||
* @author 芋道源码
|
|
||||||
*/
|
|
||||||
@Service
|
|
||||||
@Validated
|
|
||||||
public class AssessmentResultServiceImpl implements AssessmentResultService {
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private AssessmentResultMapper assessmentResultMapper;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
|
||||||
public Long createAssessmentResult(AssessmentResultSaveReqVO createReqVO) {
|
|
||||||
AssessmentResultDO result = BeanUtils.toBean(createReqVO, AssessmentResultDO.class);
|
|
||||||
assessmentResultMapper.insert(result);
|
|
||||||
return result.getId();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
|
||||||
public void batchCreateAssessmentResult(List<AssessmentResultSaveReqVO> results) {
|
|
||||||
if (CollUtil.isEmpty(results)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
List<AssessmentResultDO> resultList = BeanUtils.toBean(results, AssessmentResultDO.class);
|
|
||||||
assessmentResultMapper.insertBatch(resultList);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
|
||||||
public void updateAssessmentResult(AssessmentResultSaveReqVO updateReqVO) {
|
|
||||||
validateAssessmentResultExists(updateReqVO.getId());
|
|
||||||
AssessmentResultDO updateObj = BeanUtils.toBean(updateReqVO, AssessmentResultDO.class);
|
|
||||||
assessmentResultMapper.updateById(updateObj);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
|
||||||
public void deleteAssessmentResult(Long id) {
|
|
||||||
validateAssessmentResultExists(id);
|
|
||||||
assessmentResultMapper.deleteById(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
|
||||||
public void deleteAssessmentResultListByIds(List<Long> ids) {
|
|
||||||
assessmentResultMapper.deleteByIds(ids);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AssessmentResultDO getAssessmentResult(Long id) {
|
|
||||||
return assessmentResultMapper.selectById(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PageResult<AssessmentResultDO> getAssessmentResultPage(AssessmentResultPageReqVO pageReqVO) {
|
|
||||||
return assessmentResultMapper.selectPage(pageReqVO);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<AssessmentResultDO> getResultsByAnswerId(Long answerId) {
|
|
||||||
return assessmentResultMapper.selectListByAnswerId(answerId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<AssessmentResultDO> getResultsByAssessmentRecordId(Long assessmentRecordId) {
|
|
||||||
return assessmentResultMapper.selectListByAssessmentRecordId(assessmentRecordId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<AssessmentResultDO> getNeedManualReviewList() {
|
|
||||||
return assessmentResultMapper.selectListNeedManualReview();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
|
||||||
public void manualReview(AssessmentResultManualReviewReqVO reviewReqVO) {
|
|
||||||
AssessmentResultDO result = validateAssessmentResultExists(reviewReqVO.getId());
|
|
||||||
result.setManualScore(reviewReqVO.getManualScore());
|
|
||||||
result.setManualComment(reviewReqVO.getManualComment());
|
|
||||||
result.setManualReviewStatus(2); // 已评阅
|
|
||||||
result.setReviewerId(reviewReqVO.getReviewerId());
|
|
||||||
result.setReviewerName(reviewReqVO.getReviewerName());
|
|
||||||
result.setReviewTime(LocalDateTime.now());
|
|
||||||
result.setScore(reviewReqVO.getManualScore());
|
|
||||||
assessmentResultMapper.updateById(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
|
||||||
public void autoScore(Long answerId) {
|
|
||||||
List<AssessmentResultDO> results = assessmentResultMapper.selectListByAnswerId(answerId);
|
|
||||||
BigDecimal totalScore = BigDecimal.ZERO;
|
|
||||||
|
|
||||||
for (AssessmentResultDO result : results) {
|
|
||||||
if (!result.getNeedManualReview()) {
|
|
||||||
// 客观题自动评分
|
|
||||||
if (result.getCorrect() != null && result.getCorrect()) {
|
|
||||||
result.setScore(result.getQuestionScore());
|
|
||||||
} else {
|
|
||||||
result.setScore(BigDecimal.ZERO);
|
|
||||||
}
|
|
||||||
totalScore = totalScore.add(result.getScore());
|
|
||||||
assessmentResultMapper.updateById(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private AssessmentResultDO validateAssessmentResultExists(Long id) {
|
|
||||||
AssessmentResultDO result = assessmentResultMapper.selectById(id);
|
|
||||||
if (result == null) {
|
|
||||||
throw exception(ASSESSMENT_RESULT_NOT_EXISTS);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,198 +0,0 @@
|
|||||||
package cn.iocoder.yudao.module.prison.service.assessment.impl;
|
|
||||||
|
|
||||||
import cn.hutool.core.collection.CollUtil;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
import jakarta.annotation.Resource;
|
|
||||||
import org.springframework.validation.annotation.Validated;
|
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import cn.iocoder.yudao.module.prison.controller.admin.assessment.vo.*;
|
|
||||||
import cn.iocoder.yudao.module.prison.dal.dataobject.assessment.AssessmentStatisticsDO;
|
|
||||||
import cn.iocoder.yudao.module.prison.dal.dataobject.assessment.AssessmentAnswerDO;
|
|
||||||
import cn.iocoder.yudao.module.prison.dal.dataobject.assessment.AssessmentResultDO;
|
|
||||||
import cn.iocoder.yudao.module.prison.dal.mysql.assessment.AssessmentAnswerMapper;
|
|
||||||
import cn.iocoder.yudao.module.prison.dal.mysql.assessment.AssessmentResultMapper;
|
|
||||||
import cn.iocoder.yudao.module.prison.dal.mysql.assessment.AssessmentStatisticsMapper;
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
|
||||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
|
||||||
import static cn.iocoder.yudao.module.prison.enums.ErrorCodeConstants.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 测评统计 Service 实现类
|
|
||||||
*
|
|
||||||
* @author 芋道源码
|
|
||||||
*/
|
|
||||||
@Service
|
|
||||||
@Validated
|
|
||||||
public class AssessmentStatisticsServiceImpl implements AssessmentStatisticsService {
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private AssessmentStatisticsMapper assessmentStatisticsMapper;
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private AssessmentAnswerMapper assessmentAnswerMapper;
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private AssessmentResultMapper assessmentResultMapper;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AssessmentStatisticsDO getAssessmentStatistics(Long id) {
|
|
||||||
return assessmentStatisticsMapper.selectById(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PageResult<AssessmentStatisticsDO> getAssessmentStatisticsPage(AssessmentStatisticsPageReqVO pageReqVO) {
|
|
||||||
return assessmentStatisticsMapper.selectPage(pageReqVO);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
|
||||||
public AssessmentStatisticsDO generateStatistics(Long assessmentRecordId) {
|
|
||||||
// 查询所有答卷
|
|
||||||
List<AssessmentAnswerDO> answers = assessmentAnswerMapper.selectListByAssessmentRecordId(assessmentRecordId);
|
|
||||||
|
|
||||||
int totalCount = answers.size();
|
|
||||||
int completedCount = (int) answers.stream().filter(a -> a.getStatus() == 5).count();
|
|
||||||
int passedCount = (int) answers.stream().filter(a -> a.getPassed() != null && a.getPassed()).count();
|
|
||||||
|
|
||||||
// 计算统计数据
|
|
||||||
BigDecimal completionRate = totalCount > 0 ?
|
|
||||||
new BigDecimal(completedCount).multiply(new BigDecimal(100)).divide(new BigDecimal(totalCount), 2, java.math.RoundingMode.HALF_UP) :
|
|
||||||
BigDecimal.ZERO;
|
|
||||||
|
|
||||||
List<BigDecimal> scores = answers.stream()
|
|
||||||
.map(AssessmentAnswerDO::getTotalScore)
|
|
||||||
.filter(Objects::nonNull)
|
|
||||||
.sorted()
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
BigDecimal averageScore = scores.isEmpty() ? BigDecimal.ZERO :
|
|
||||||
scores.stream().reduce(BigDecimal.ZERO, BigDecimal::add).divide(new BigDecimal(scores.size()), 2, java.math.RoundingMode.HALF_UP);
|
|
||||||
BigDecimal highestScore = scores.isEmpty() ? BigDecimal.ZERO : scores.get(scores.size() - 1);
|
|
||||||
BigDecimal lowestScore = scores.isEmpty() ? BigDecimal.ZERO : scores.get(0);
|
|
||||||
|
|
||||||
BigDecimal passRate = completedCount > 0 ?
|
|
||||||
new BigDecimal(passedCount).multiply(new BigDecimal(100)).divide(new BigDecimal(completedCount), 2, java.math.RoundingMode.HALF_UP) :
|
|
||||||
BigDecimal.ZERO;
|
|
||||||
|
|
||||||
int excellentCount = (int) answers.stream().filter(a ->
|
|
||||||
a.getTotalScore() != null && a.getTotalScore().compareTo(new BigDecimal("90")) >= 0
|
|
||||||
).count();
|
|
||||||
|
|
||||||
int riskCount = (int) answers.stream().filter(a ->
|
|
||||||
a.getTotalScore() != null && a.getTotalScore().compareTo(new BigDecimal("60")) < 0
|
|
||||||
).count();
|
|
||||||
|
|
||||||
BigDecimal excellentRate = completedCount > 0 ?
|
|
||||||
new BigDecimal(excellentCount).multiply(new BigDecimal(100)).divide(new BigDecimal(completedCount), 2, java.math.RoundingMode.HALF_UP) :
|
|
||||||
BigDecimal.ZERO;
|
|
||||||
|
|
||||||
BigDecimal riskRate = completedCount > 0 ?
|
|
||||||
new BigDecimal(riskCount).multiply(new BigDecimal(100)).divide(new BigDecimal(completedCount), 2, java.math.RoundingMode.HALF_UP) :
|
|
||||||
BigDecimal.ZERO;
|
|
||||||
|
|
||||||
// 生成统计数据
|
|
||||||
AssessmentStatisticsDO statistics = new AssessmentStatisticsDO();
|
|
||||||
statistics.setAssessmentRecordId(assessmentRecordId);
|
|
||||||
statistics.setTotalCount(totalCount);
|
|
||||||
statistics.setCompletedCount(completedCount);
|
|
||||||
statistics.setCompletionRate(completionRate);
|
|
||||||
statistics.setAverageScore(averageScore);
|
|
||||||
statistics.setHighestScore(highestScore);
|
|
||||||
statistics.setLowestScore(lowestScore);
|
|
||||||
statistics.setPassedCount(passedCount);
|
|
||||||
statistics.setPassRate(passRate);
|
|
||||||
statistics.setExcellentCount(excellentCount);
|
|
||||||
statistics.setExcellentRate(excellentRate);
|
|
||||||
statistics.setRiskCount(riskCount);
|
|
||||||
statistics.setRiskRate(riskRate);
|
|
||||||
statistics.setStatisticsTime(LocalDateTime.now());
|
|
||||||
|
|
||||||
// 生成分数分布
|
|
||||||
Map<String, Integer> scoreDist = getScoreDistribution(assessmentRecordId);
|
|
||||||
statistics.setScoreDistribution(new com.fasterxml.jackson.databind.ObjectMapper().writeValueAsString(scoreDist));
|
|
||||||
|
|
||||||
// 生成风险分布
|
|
||||||
Map<String, Integer> riskDist = getRiskDistribution(assessmentRecordId);
|
|
||||||
statistics.setRiskDistribution(new com.fasterxml.jackson.databind.ObjectMapper().writeValueAsString(riskDist));
|
|
||||||
|
|
||||||
assessmentStatisticsMapper.insert(statistics);
|
|
||||||
return statistics;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public BigDecimal getCompletionRate(Long assessmentRecordId) {
|
|
||||||
List<AssessmentAnswerDO> answers = assessmentAnswerMapper.selectListByAssessmentRecordId(assessmentRecordId);
|
|
||||||
int totalCount = answers.size();
|
|
||||||
int completedCount = (int) answers.stream().filter(a -> a.getStatus() == 5).count();
|
|
||||||
if (totalCount == 0) return BigDecimal.ZERO;
|
|
||||||
return new BigDecimal(completedCount).multiply(new BigDecimal(100)).divide(new BigDecimal(totalCount), 2, java.math.RoundingMode.HALF_UP);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Map<String, Integer> getScoreDistribution(Long assessmentRecordId) {
|
|
||||||
Map<String, Integer> distribution = new LinkedHashMap<>();
|
|
||||||
distribution.put("0-20", 0);
|
|
||||||
distribution.put("20-40", 0);
|
|
||||||
distribution.put("40-60", 0);
|
|
||||||
distribution.put("60-80", 0);
|
|
||||||
distribution.put("80-100", 0);
|
|
||||||
|
|
||||||
List<AssessmentAnswerDO> answers = assessmentAnswerMapper.selectListByAssessmentRecordId(assessmentRecordId);
|
|
||||||
for (AssessmentAnswerDO answer : answers) {
|
|
||||||
if (answer.getTotalScore() != null) {
|
|
||||||
BigDecimal score = answer.getTotalScore();
|
|
||||||
if (score.compareTo(new BigDecimal("20")) <= 0) {
|
|
||||||
distribution.merge("0-20", 1, Integer::sum);
|
|
||||||
} else if (score.compareTo(new BigDecimal("40")) <= 0) {
|
|
||||||
distribution.merge("20-40", 1, Integer::sum);
|
|
||||||
} else if (score.compareTo(new BigDecimal("60")) <= 0) {
|
|
||||||
distribution.merge("40-60", 1, Integer::sum);
|
|
||||||
} else if (score.compareTo(new BigDecimal("80")) <= 0) {
|
|
||||||
distribution.merge("60-80", 1, Integer::sum);
|
|
||||||
} else {
|
|
||||||
distribution.merge("80-100", 1, Integer::sum);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return distribution;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Map<String, Integer> getRiskDistribution(Long assessmentRecordId) {
|
|
||||||
Map<String, Integer> distribution = new LinkedHashMap<>();
|
|
||||||
distribution.put("low", 0); // 低风险
|
|
||||||
distribution.put("medium", 0); // 中风险
|
|
||||||
distribution.put("high", 0); // 高风险
|
|
||||||
|
|
||||||
List<AssessmentAnswerDO> answers = assessmentAnswerMapper.selectListByAssessmentRecordId(assessmentRecordId);
|
|
||||||
for (AssessmentAnswerDO answer : answers) {
|
|
||||||
if (answer.getTotalScore() != null && answer.getPassed() != null) {
|
|
||||||
if (answer.getPassed()) {
|
|
||||||
distribution.merge("low", 1, Integer::sum);
|
|
||||||
} else {
|
|
||||||
BigDecimal score = answer.getTotalScore();
|
|
||||||
if (score.compareTo(new BigDecimal("40")) < 0) {
|
|
||||||
distribution.merge("high", 1, Integer::sum);
|
|
||||||
} else {
|
|
||||||
distribution.merge("medium", 1, Integer::sum);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return distribution;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AssessmentStatisticsRespVO getAssessmentReport(Long assessmentRecordId) {
|
|
||||||
AssessmentStatisticsDO statistics = generateStatistics(assessmentRecordId);
|
|
||||||
return BeanUtils.toBean(statistics, AssessmentStatisticsRespVO.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -4,59 +4,68 @@ import java.util.*;
|
|||||||
import jakarta.validation.*;
|
import jakarta.validation.*;
|
||||||
import cn.iocoder.yudao.module.prison.controller.admin.consumption.vo.*;
|
import cn.iocoder.yudao.module.prison.controller.admin.consumption.vo.*;
|
||||||
import cn.iocoder.yudao.module.prison.dal.dataobject.consumption.ConsumptionDO;
|
import cn.iocoder.yudao.module.prison.dal.dataobject.consumption.ConsumptionDO;
|
||||||
|
import cn.iocoder.yudao.module.prison.dal.dataobject.consumption.ConsumptionDetailDO;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 消费记录 Service 接口
|
* 消费订单 Service 接口
|
||||||
*
|
*
|
||||||
* @author 芋道源码
|
* @author xl
|
||||||
*/
|
*/
|
||||||
public interface ConsumptionService {
|
public interface ConsumptionService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建消费记录
|
* 创建消费订单
|
||||||
*
|
*
|
||||||
* @param createReqVO 创建信息
|
* @param createReqVO 创建信息
|
||||||
* @return 编号
|
* @return 订单编号
|
||||||
*/
|
*/
|
||||||
Long createConsumption(@Valid ConsumptionSaveReqVO createReqVO);
|
Long createConsumption(@Valid ConsumptionSaveReqVO createReqVO);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新消费记录
|
* 更新消费订单
|
||||||
*
|
*
|
||||||
* @param updateReqVO 更新信息
|
* @param updateReqVO 更新信息
|
||||||
*/
|
*/
|
||||||
void updateConsumption(@Valid ConsumptionSaveReqVO updateReqVO);
|
void updateConsumption(@Valid ConsumptionSaveReqVO updateReqVO);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除消费记录
|
* 删除消费订单
|
||||||
*
|
*
|
||||||
* @param id 编号
|
* @param id 订单编号
|
||||||
*/
|
*/
|
||||||
void deleteConsumption(Long id);
|
void deleteConsumption(Long id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 批量删除消费记录
|
* 批量删除消费订单
|
||||||
*
|
*
|
||||||
* @param ids 编号
|
* @param ids 订单编号列表
|
||||||
*/
|
*/
|
||||||
void deleteConsumptionListByIds(List<Long> ids);
|
void deleteConsumptionListByIds(List<Long> ids);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获得消费记录
|
* 获得消费订单
|
||||||
*
|
*
|
||||||
* @param id 编号
|
* @param id 订单编号
|
||||||
* @return 消费记录
|
* @return 消费订单
|
||||||
*/
|
*/
|
||||||
ConsumptionDO getConsumption(Long id);
|
ConsumptionDO getConsumption(Long id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获得消费记录分页
|
* 获得消费订单分页
|
||||||
*
|
*
|
||||||
* @param pageReqVO 分页查询
|
* @param pageReqVO 分页查询
|
||||||
* @return 消费记录分页
|
* @return 消费订单分页
|
||||||
*/
|
*/
|
||||||
PageResult<ConsumptionDO> getConsumptionPage(ConsumptionPageReqVO pageReqVO);
|
PageResult<ConsumptionDO> getConsumptionPage(ConsumptionPageReqVO pageReqVO);
|
||||||
|
|
||||||
}
|
/**
|
||||||
|
* 获得消费订单明细列表
|
||||||
|
*
|
||||||
|
* @param consumptionId 消费订单ID
|
||||||
|
* @return 消费明细列表
|
||||||
|
*/
|
||||||
|
List<ConsumptionDetailDO> getConsumptionDetailList(Long consumptionId);
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@ -1,29 +1,34 @@
|
|||||||
package cn.iocoder.yudao.module.prison.service.consumption;
|
package cn.iocoder.yudao.module.prison.service.consumption;
|
||||||
|
|
||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
import cn.iocoder.yudao.module.prison.controller.admin.consumption.vo.*;
|
import cn.iocoder.yudao.module.prison.controller.admin.consumption.vo.*;
|
||||||
import cn.iocoder.yudao.module.prison.dal.dataobject.consumption.ConsumptionDO;
|
import cn.iocoder.yudao.module.prison.dal.dataobject.consumption.ConsumptionDO;
|
||||||
|
import cn.iocoder.yudao.module.prison.dal.dataobject.consumption.ConsumptionDetailDO;
|
||||||
|
import cn.iocoder.yudao.module.prison.dal.mysql.consumption.ConsumptionMapper;
|
||||||
|
import cn.iocoder.yudao.module.prison.dal.mysql.consumption.ConsumptionDetailMapper;
|
||||||
|
import cn.iocoder.yudao.module.prison.convert.consumption.ConsumptionConvert;
|
||||||
|
import cn.iocoder.yudao.module.prison.convert.consumption.ConsumptionDetailConvert;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||||
|
import cn.hutool.core.util.NumberUtil;
|
||||||
import cn.iocoder.yudao.module.prison.dal.mysql.consumption.ConsumptionMapper;
|
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
|
|
||||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.diffList;
|
|
||||||
import static cn.iocoder.yudao.module.prison.enums.ErrorCodeConstants.*;
|
import static cn.iocoder.yudao.module.prison.enums.ErrorCodeConstants.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 消费记录 Service 实现类
|
* 消费订单 Service 实现类
|
||||||
*
|
*
|
||||||
* @author 芋道源码
|
* @author xl
|
||||||
*/
|
*/
|
||||||
@Service
|
@Service
|
||||||
@Validated
|
@Validated
|
||||||
@ -32,39 +37,84 @@ public class ConsumptionServiceImpl implements ConsumptionService {
|
|||||||
@Resource
|
@Resource
|
||||||
private ConsumptionMapper consumptionMapper;
|
private ConsumptionMapper consumptionMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ConsumptionDetailMapper consumptionDetailMapper;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public Long createConsumption(ConsumptionSaveReqVO createReqVO) {
|
public Long createConsumption(ConsumptionSaveReqVO createReqVO) {
|
||||||
// 插入
|
// 1. 生成订单号
|
||||||
ConsumptionDO consumption = BeanUtils.toBean(createReqVO, ConsumptionDO.class);
|
String orderNo = generateOrderNo();
|
||||||
|
|
||||||
|
// 2. 插入消费订单
|
||||||
|
ConsumptionDO consumption = ConsumptionConvert.INSTANCE.convert(createReqVO);
|
||||||
|
consumption.setOrderNo(orderNo);
|
||||||
consumptionMapper.insert(consumption);
|
consumptionMapper.insert(consumption);
|
||||||
|
|
||||||
|
// 3. 插入消费明细
|
||||||
|
if (CollUtil.isNotEmpty(createReqVO.getDetails())) {
|
||||||
|
for (ConsumptionDetailSaveReqVO detailVO : createReqVO.getDetails()) {
|
||||||
|
ConsumptionDetailDO detail = ConsumptionDetailConvert.INSTANCE.convert(detailVO);
|
||||||
|
detail.setConsumptionId(consumption.getId());
|
||||||
|
detail.setPrisonerId(createReqVO.getPrisonerId());
|
||||||
|
// 计算小计金额
|
||||||
|
detail.setSubtotal(NumberUtil.mul(detail.getGoodsPrice(), detail.getGoodsCount()));
|
||||||
|
consumptionDetailMapper.insert(detail);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 返回
|
// 返回
|
||||||
return consumption.getId();
|
return consumption.getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public void updateConsumption(ConsumptionSaveReqVO updateReqVO) {
|
public void updateConsumption(ConsumptionSaveReqVO updateReqVO) {
|
||||||
// 校验存在
|
// 校验订单存在
|
||||||
validateConsumptionExists(updateReqVO.getId());
|
validateConsumptionExists(updateReqVO.getId());
|
||||||
// 更新
|
|
||||||
ConsumptionDO updateObj = BeanUtils.toBean(updateReqVO, ConsumptionDO.class);
|
// 1. 更新消费订单
|
||||||
|
ConsumptionDO updateObj = ConsumptionConvert.INSTANCE.convert(updateReqVO);
|
||||||
consumptionMapper.updateById(updateObj);
|
consumptionMapper.updateById(updateObj);
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
// 2. 删除原有明细
|
||||||
public void deleteConsumption(Long id) {
|
consumptionDetailMapper.deleteListByConsumptionId(updateReqVO.getId());
|
||||||
// 校验存在
|
|
||||||
validateConsumptionExists(id);
|
|
||||||
// 删除
|
|
||||||
consumptionMapper.deleteById(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
// 3. 插入新的消费明细
|
||||||
public void deleteConsumptionListByIds(List<Long> ids) {
|
if (CollUtil.isNotEmpty(updateReqVO.getDetails())) {
|
||||||
// 删除
|
for (ConsumptionDetailSaveReqVO detailVO : updateReqVO.getDetails()) {
|
||||||
consumptionMapper.deleteByIds(ids);
|
ConsumptionDetailDO detail = ConsumptionDetailConvert.INSTANCE.convert(detailVO);
|
||||||
|
detail.setConsumptionId(updateReqVO.getId());
|
||||||
|
detail.setPrisonerId(updateReqVO.getPrisonerId());
|
||||||
|
// 计算小计金额
|
||||||
|
detail.setSubtotal(NumberUtil.mul(detail.getGoodsPrice(), detail.getGoodsCount()));
|
||||||
|
consumptionDetailMapper.insert(detail);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void deleteConsumption(Long id) {
|
||||||
|
// 校验订单存在
|
||||||
|
validateConsumptionExists(id);
|
||||||
|
|
||||||
|
// 1. 删除消费订单
|
||||||
|
consumptionMapper.deleteById(id);
|
||||||
|
|
||||||
|
// 2. 删除消费明细
|
||||||
|
consumptionDetailMapper.deleteListByConsumptionId(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void deleteConsumptionListByIds(List<Long> ids) {
|
||||||
|
// 批量删除订单
|
||||||
|
consumptionMapper.deleteByIds(ids);
|
||||||
|
|
||||||
|
// 批量删除明细
|
||||||
|
consumptionDetailMapper.deleteListByConsumptionIds(ids);
|
||||||
|
}
|
||||||
|
|
||||||
private void validateConsumptionExists(Long id) {
|
private void validateConsumptionExists(Long id) {
|
||||||
if (consumptionMapper.selectById(id) == null) {
|
if (consumptionMapper.selectById(id) == null) {
|
||||||
@ -82,4 +132,16 @@ public class ConsumptionServiceImpl implements ConsumptionService {
|
|||||||
return consumptionMapper.selectPage(pageReqVO);
|
return consumptionMapper.selectPage(pageReqVO);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
@Override
|
||||||
|
public List<ConsumptionDetailDO> getConsumptionDetailList(Long consumptionId) {
|
||||||
|
return consumptionDetailMapper.selectList(ConsumptionDetailDO::getConsumptionId, consumptionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成订单号
|
||||||
|
*/
|
||||||
|
private String generateOrderNo() {
|
||||||
|
return "CS" + System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@ -60,10 +60,10 @@ public class QuestionnaireServiceImpl implements QuestionnaireService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void deleteQuestionnaireListByIds(List<Long> ids) {
|
public void deleteQuestionnaireListByIds(List<Long> ids) {
|
||||||
// 删除
|
// 删除
|
||||||
questionnaireMapper.deleteByIds(ids);
|
questionnaireMapper.deleteByIds(ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void validateQuestionnaireExists(Long id) {
|
private void validateQuestionnaireExists(Long id) {
|
||||||
|
|||||||
@ -6,9 +6,11 @@ import cn.iocoder.yudao.module.prison.controller.admin.questionnairerecord.vo.*;
|
|||||||
import cn.iocoder.yudao.module.prison.dal.dataobject.questionnairerecord.QuestionnaireRecordDO;
|
import cn.iocoder.yudao.module.prison.dal.dataobject.questionnairerecord.QuestionnaireRecordDO;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 问卷答题记录 Service 接口
|
* 问卷答题记录 / 测评记录 Service 接口
|
||||||
*
|
*
|
||||||
* @author 芋道源码
|
* @author 芋道源码
|
||||||
*/
|
*/
|
||||||
@ -37,10 +39,10 @@ public interface QuestionnaireRecordService {
|
|||||||
void deleteQuestionnaireRecord(Long id);
|
void deleteQuestionnaireRecord(Long id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 批量删除问卷答题记录
|
* 批量删除问卷答题记录
|
||||||
*
|
*
|
||||||
* @param ids 编号
|
* @param ids 编号列表
|
||||||
*/
|
*/
|
||||||
void deleteQuestionnaireRecordListByIds(List<Long> ids);
|
void deleteQuestionnaireRecordListByIds(List<Long> ids);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -59,4 +61,85 @@ public interface QuestionnaireRecordService {
|
|||||||
*/
|
*/
|
||||||
PageResult<QuestionnaireRecordDO> getQuestionnaireRecordPage(QuestionnaireRecordPageReqVO pageReqVO);
|
PageResult<QuestionnaireRecordDO> getQuestionnaireRecordPage(QuestionnaireRecordPageReqVO pageReqVO);
|
||||||
|
|
||||||
}
|
// ==================== 测评执行相关 ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发起测评
|
||||||
|
*
|
||||||
|
* @param reqVO 发起信息
|
||||||
|
* @return 测评记录ID
|
||||||
|
*/
|
||||||
|
Long initiateAssessment(@Valid AssessmentInitiateReqVO reqVO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开始测评
|
||||||
|
*
|
||||||
|
* @param id 测评记录ID
|
||||||
|
* @param prisonerId 罪犯ID
|
||||||
|
*/
|
||||||
|
void startAssessment(Long id, Long prisonerId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提交答卷
|
||||||
|
*
|
||||||
|
* @param reqVO 提交信息
|
||||||
|
*/
|
||||||
|
void submitAnswer(@Valid AssessmentAnswerSubmitReqVO reqVO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 结束测评
|
||||||
|
*
|
||||||
|
* @param id 测评记录ID
|
||||||
|
*/
|
||||||
|
void finishAssessment(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 取消测评
|
||||||
|
*
|
||||||
|
* @param id 测评记录ID
|
||||||
|
*/
|
||||||
|
void cancelAssessment(Long id);
|
||||||
|
|
||||||
|
// ==================== 评分相关 ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自动评分
|
||||||
|
*
|
||||||
|
* @param id 测评记录ID
|
||||||
|
*/
|
||||||
|
void autoScore(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 人工评分
|
||||||
|
*
|
||||||
|
* @param reqVO 评分信息
|
||||||
|
*/
|
||||||
|
void manualScore(@Valid AssessmentManualScoreReqVO reqVO);
|
||||||
|
|
||||||
|
// ==================== 统计相关 ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取完成率
|
||||||
|
*
|
||||||
|
* @param assessmentRecordId 测评记录ID
|
||||||
|
* @return 完成率
|
||||||
|
*/
|
||||||
|
BigDecimal getCompletionRate(Long assessmentRecordId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取分数分布
|
||||||
|
*
|
||||||
|
* @param assessmentRecordId 测评记录ID
|
||||||
|
* @return 分数分布
|
||||||
|
*/
|
||||||
|
Map<String, Integer> getScoreDistribution(Long assessmentRecordId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取风险分布
|
||||||
|
*
|
||||||
|
* @param assessmentRecordId 测评记录ID
|
||||||
|
* @return 风险分布
|
||||||
|
*/
|
||||||
|
Map<String, Integer> getRiskDistribution(Long assessmentRecordId);
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@ -7,21 +7,26 @@ import org.springframework.validation.annotation.Validated;
|
|||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
import cn.iocoder.yudao.module.prison.controller.admin.questionnairerecord.vo.*;
|
import cn.iocoder.yudao.module.prison.controller.admin.questionnairerecord.vo.*;
|
||||||
import cn.iocoder.yudao.module.prison.dal.dataobject.questionnairerecord.QuestionnaireRecordDO;
|
import cn.iocoder.yudao.module.prison.dal.dataobject.questionnairerecord.QuestionnaireRecordDO;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||||
|
|
||||||
import cn.iocoder.yudao.module.prison.dal.mysql.questionnairerecord.QuestionnaireRecordMapper;
|
import cn.iocoder.yudao.module.prison.dal.mysql.questionnairerecord.QuestionnaireRecordMapper;
|
||||||
|
import cn.iocoder.yudao.module.prison.dal.mysql.questionnaire.QuestionnaireMapper;
|
||||||
|
import cn.iocoder.yudao.module.prison.dal.dataobject.questionnaire.QuestionnaireDO;
|
||||||
|
import cn.iocoder.yudao.module.prison.service.answer.AnswerService;
|
||||||
|
import cn.iocoder.yudao.module.prison.enums.QuestionnaireRecordPassStatusEnum;
|
||||||
|
import cn.iocoder.yudao.module.prison.enums.QuestionnaireRecordStatusEnum;
|
||||||
|
import cn.iocoder.yudao.module.prison.enums.RiskLevelEnum;
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
|
|
||||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.diffList;
|
|
||||||
import static cn.iocoder.yudao.module.prison.enums.ErrorCodeConstants.*;
|
import static cn.iocoder.yudao.module.prison.enums.ErrorCodeConstants.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 问卷答题记录 Service 实现类
|
* 问卷答题记录 / 测评记录 Service 实现类
|
||||||
*
|
*
|
||||||
* @author 芋道源码
|
* @author 芋道源码
|
||||||
*/
|
*/
|
||||||
@ -32,13 +37,17 @@ public class QuestionnaireRecordServiceImpl implements QuestionnaireRecordServic
|
|||||||
@Resource
|
@Resource
|
||||||
private QuestionnaireRecordMapper questionnaireRecordMapper;
|
private QuestionnaireRecordMapper questionnaireRecordMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private QuestionnaireMapper questionnaireMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private AnswerService answerService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Long createQuestionnaireRecord(QuestionnaireRecordSaveReqVO createReqVO) {
|
public Long createQuestionnaireRecord(QuestionnaireRecordSaveReqVO createReqVO) {
|
||||||
// 插入
|
// 插入
|
||||||
QuestionnaireRecordDO questionnaireRecord = BeanUtils.toBean(createReqVO, QuestionnaireRecordDO.class);
|
QuestionnaireRecordDO questionnaireRecord = BeanUtils.toBean(createReqVO, QuestionnaireRecordDO.class);
|
||||||
questionnaireRecordMapper.insert(questionnaireRecord);
|
questionnaireRecordMapper.insert(questionnaireRecord);
|
||||||
|
|
||||||
// 返回
|
|
||||||
return questionnaireRecord.getId();
|
return questionnaireRecord.getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,11 +83,12 @@ public class QuestionnaireRecordServiceImpl implements QuestionnaireRecordServic
|
|||||||
questionnaireRecordMapper.deleteByIds(ids);
|
questionnaireRecordMapper.deleteByIds(ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private QuestionnaireRecordDO validateQuestionnaireRecordExists(Long id) {
|
||||||
private void validateQuestionnaireRecordExists(Long id) {
|
QuestionnaireRecordDO record = questionnaireRecordMapper.selectById(id);
|
||||||
if (questionnaireRecordMapper.selectById(id) == null) {
|
if (record == null) {
|
||||||
throw exception(QUESTIONNAIRE_RECORD_NOT_EXISTS);
|
throw exception(QUESTIONNAIRE_RECORD_NOT_EXISTS);
|
||||||
}
|
}
|
||||||
|
return record;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -91,4 +101,207 @@ public class QuestionnaireRecordServiceImpl implements QuestionnaireRecordServic
|
|||||||
return questionnaireRecordMapper.selectPage(pageReqVO);
|
return questionnaireRecordMapper.selectPage(pageReqVO);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
// ==================== 测评执行相关 ====================
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public Long initiateAssessment(AssessmentInitiateReqVO reqVO) {
|
||||||
|
// 获取问卷信息
|
||||||
|
QuestionnaireDO questionnaire = questionnaireMapper.selectById(reqVO.getQuestionnaireId());
|
||||||
|
if (questionnaire == null) {
|
||||||
|
throw exception(QUESTIONNAIRE_NOT_EXISTS);
|
||||||
|
}
|
||||||
|
String questionnaireName = questionnaire.getTitle();
|
||||||
|
|
||||||
|
QuestionnaireRecordDO lastRecord = null;
|
||||||
|
for (Long prisonerId : reqVO.getPrisonerIds()) {
|
||||||
|
QuestionnaireRecordDO record = new QuestionnaireRecordDO();
|
||||||
|
record.setQuestionnaireId(reqVO.getQuestionnaireId());
|
||||||
|
record.setQuestionnaireName(questionnaireName);
|
||||||
|
record.setPrisonerId(prisonerId);
|
||||||
|
record.setStatus(QuestionnaireRecordStatusEnum.PENDING.getStatus()); // 待测评
|
||||||
|
record.setDeadline(reqVO.getDeadline());
|
||||||
|
record.setRemark(reqVO.getRemark());
|
||||||
|
record.setParticipantCount(0);
|
||||||
|
record.setCompletedCount(0);
|
||||||
|
questionnaireRecordMapper.insert(record);
|
||||||
|
lastRecord = record;
|
||||||
|
}
|
||||||
|
// 返回最后创建的记录ID
|
||||||
|
return lastRecord != null ? lastRecord.getId() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void startAssessment(Long id, Long prisonerId) {
|
||||||
|
QuestionnaireRecordDO record = validateQuestionnaireRecordExists(id);
|
||||||
|
if (!QuestionnaireRecordStatusEnum.PENDING.getStatus().equals(record.getStatus())) {
|
||||||
|
throw exception(QUESTIONNAIRE_RECORD_STATUS_ERROR);
|
||||||
|
}
|
||||||
|
record.setStatus(QuestionnaireRecordStatusEnum.IN_PROGRESS.getStatus()); // 测评中
|
||||||
|
record.setStartTime(LocalDateTime.now());
|
||||||
|
questionnaireRecordMapper.updateById(record);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void submitAnswer(AssessmentAnswerSubmitReqVO reqVO) {
|
||||||
|
QuestionnaireRecordDO record = validateQuestionnaireRecordExists(reqVO.getRecordId());
|
||||||
|
if (!QuestionnaireRecordStatusEnum.IN_PROGRESS.getStatus().equals(record.getStatus())) {
|
||||||
|
throw exception(QUESTIONNAIRE_RECORD_STATUS_ERROR);
|
||||||
|
}
|
||||||
|
record.setStatus(QuestionnaireRecordStatusEnum.COMPLETED.getStatus()); // 已完成
|
||||||
|
record.setEndTime(LocalDateTime.now());
|
||||||
|
if (record.getStartTime() != null) {
|
||||||
|
record.setDuration((int) java.time.Duration.between(record.getStartTime(), LocalDateTime.now()).getSeconds());
|
||||||
|
}
|
||||||
|
// 保存答题记录并计算客观题得分
|
||||||
|
answerService.saveAnswers(reqVO.getRecordId(), record.getQuestionnaireId(), reqVO.getPrisonerId(), reqVO.getAnswers());
|
||||||
|
// 计算客观题得分
|
||||||
|
BigDecimal objectiveScore = answerService.calculateObjectiveScore(reqVO.getRecordId());
|
||||||
|
record.setObjectiveScore(objectiveScore);
|
||||||
|
record.setPassStatus(QuestionnaireRecordPassStatusEnum.PENDING.getStatus()); // 待评阅
|
||||||
|
questionnaireRecordMapper.updateById(record);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void finishAssessment(Long id) {
|
||||||
|
QuestionnaireRecordDO record = validateQuestionnaireRecordExists(id);
|
||||||
|
if (!QuestionnaireRecordStatusEnum.canTransition(record.getStatus())) {
|
||||||
|
throw exception(QUESTIONNAIRE_RECORD_STATUS_ERROR);
|
||||||
|
}
|
||||||
|
record.setStatus(QuestionnaireRecordStatusEnum.EXPIRED.getStatus()); // 已过期
|
||||||
|
questionnaireRecordMapper.updateById(record);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void cancelAssessment(Long id) {
|
||||||
|
QuestionnaireRecordDO record = validateQuestionnaireRecordExists(id);
|
||||||
|
if (!QuestionnaireRecordStatusEnum.PENDING.getStatus().equals(record.getStatus())) {
|
||||||
|
throw exception(QUESTIONNAIRE_RECORD_STATUS_ERROR);
|
||||||
|
}
|
||||||
|
record.setStatus(QuestionnaireRecordStatusEnum.CANCELLED.getStatus()); // 已取消
|
||||||
|
questionnaireRecordMapper.updateById(record);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 评分相关 ====================
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void autoScore(Long id) {
|
||||||
|
QuestionnaireRecordDO record = validateQuestionnaireRecordExists(id);
|
||||||
|
// 重新计算客观题得分(覆盖之前的分数)
|
||||||
|
BigDecimal objectiveScore = answerService.calculateObjectiveScore(id);
|
||||||
|
record.setObjectiveScore(objectiveScore);
|
||||||
|
|
||||||
|
// 如果有待主观题(需要人工评阅),保持待评阅状态
|
||||||
|
// 如果全部是客观题,直接设置及格/不及格状态
|
||||||
|
record.setPassStatus(objectiveScore.compareTo(record.getPassScore()) >= 0
|
||||||
|
? QuestionnaireRecordPassStatusEnum.PASSED.getStatus()
|
||||||
|
: QuestionnaireRecordPassStatusEnum.FAILED.getStatus());
|
||||||
|
|
||||||
|
questionnaireRecordMapper.updateById(record);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void manualScore(AssessmentManualScoreReqVO reqVO) {
|
||||||
|
QuestionnaireRecordDO record = validateQuestionnaireRecordExists(reqVO.getRecordId());
|
||||||
|
|
||||||
|
// 计算总分
|
||||||
|
BigDecimal objectiveScore = record.getObjectiveScore() != null ? record.getObjectiveScore() : BigDecimal.ZERO;
|
||||||
|
BigDecimal subjectiveScore = reqVO.getSubjectiveScore() != null ? reqVO.getSubjectiveScore() : BigDecimal.ZERO;
|
||||||
|
BigDecimal totalScore = objectiveScore.add(subjectiveScore);
|
||||||
|
|
||||||
|
record.setSubjectiveScore(reqVO.getSubjectiveScore());
|
||||||
|
record.setTotalScore(totalScore);
|
||||||
|
// 及格/不及格判断
|
||||||
|
BigDecimal passScore = record.getPassScore() != null ? record.getPassScore() : BigDecimal.ZERO;
|
||||||
|
record.setPassStatus(totalScore.compareTo(passScore) >= 0
|
||||||
|
? QuestionnaireRecordPassStatusEnum.PASSED.getStatus()
|
||||||
|
: QuestionnaireRecordPassStatusEnum.FAILED.getStatus());
|
||||||
|
record.setRiskLevel(reqVO.getRiskLevel());
|
||||||
|
|
||||||
|
questionnaireRecordMapper.updateById(record);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 统计相关 ====================
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BigDecimal getCompletionRate(Long assessmentRecordId) {
|
||||||
|
QuestionnaireRecordDO record = validateQuestionnaireRecordExists(assessmentRecordId);
|
||||||
|
if (record.getParticipantCount() == null || record.getParticipantCount() == 0) {
|
||||||
|
return BigDecimal.ZERO;
|
||||||
|
}
|
||||||
|
return BigDecimal.valueOf(record.getCompletedCount())
|
||||||
|
.divide(BigDecimal.valueOf(record.getParticipantCount()), 4, java.math.RoundingMode.HALF_UP)
|
||||||
|
.multiply(BigDecimal.valueOf(100));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Integer> getScoreDistribution(Long assessmentRecordId) {
|
||||||
|
Map<String, Integer> distribution = new HashMap<>();
|
||||||
|
distribution.put("0-20", 0);
|
||||||
|
distribution.put("21-40", 0);
|
||||||
|
distribution.put("41-60", 0);
|
||||||
|
distribution.put("61-80", 0);
|
||||||
|
distribution.put("81-100", 0);
|
||||||
|
|
||||||
|
// 先获取记录,获取 questionnaireId
|
||||||
|
QuestionnaireRecordDO record = questionnaireRecordMapper.selectById(assessmentRecordId);
|
||||||
|
if (record == null) {
|
||||||
|
return distribution;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询该测评下所有已完成记录,统计分数分布
|
||||||
|
List<QuestionnaireRecordDO> records = questionnaireRecordMapper.selectList(
|
||||||
|
new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<QuestionnaireRecordDO>()
|
||||||
|
.eq(QuestionnaireRecordDO::getQuestionnaireId, record.getQuestionnaireId())
|
||||||
|
.eq(QuestionnaireRecordDO::getStatus, QuestionnaireRecordStatusEnum.COMPLETED.getStatus()));
|
||||||
|
|
||||||
|
for (QuestionnaireRecordDO r : records) {
|
||||||
|
if (r.getTotalScore() == null) continue;
|
||||||
|
int score = r.getTotalScore().intValue();
|
||||||
|
if (score <= 20) distribution.put("0-20", distribution.get("0-20") + 1);
|
||||||
|
else if (score <= 40) distribution.put("21-40", distribution.get("21-40") + 1);
|
||||||
|
else if (score <= 60) distribution.put("41-60", distribution.get("41-60") + 1);
|
||||||
|
else if (score <= 80) distribution.put("61-80", distribution.get("61-80") + 1);
|
||||||
|
else distribution.put("81-100", distribution.get("81-100") + 1);
|
||||||
|
}
|
||||||
|
return distribution;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Integer> getRiskDistribution(Long assessmentRecordId) {
|
||||||
|
Map<String, Integer> distribution = new HashMap<>();
|
||||||
|
distribution.put("high", 0);
|
||||||
|
distribution.put("medium", 0);
|
||||||
|
distribution.put("low", 0);
|
||||||
|
|
||||||
|
// 先获取记录,获取 questionnaireId
|
||||||
|
QuestionnaireRecordDO record = questionnaireRecordMapper.selectById(assessmentRecordId);
|
||||||
|
if (record == null) {
|
||||||
|
return distribution;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询该测评下所有记录,统计风险分布
|
||||||
|
List<QuestionnaireRecordDO> records = questionnaireRecordMapper.selectList(
|
||||||
|
new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<QuestionnaireRecordDO>()
|
||||||
|
.eq(QuestionnaireRecordDO::getQuestionnaireId, record.getQuestionnaireId()));
|
||||||
|
|
||||||
|
for (QuestionnaireRecordDO r : records) {
|
||||||
|
if (r.getRiskLevel() == null) continue;
|
||||||
|
if (RiskLevelEnum.HIGH.getValue().equals(r.getRiskLevel())) {
|
||||||
|
distribution.put("high", distribution.get("high") + 1);
|
||||||
|
} else if (RiskLevelEnum.MEDIUM.getValue().equals(r.getRiskLevel())) {
|
||||||
|
distribution.put("medium", distribution.get("medium") + 1);
|
||||||
|
} else if (RiskLevelEnum.LOW.getValue().equals(r.getRiskLevel())) {
|
||||||
|
distribution.put("low", distribution.get("low") + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return distribution;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@ -1,374 +0,0 @@
|
|||||||
package cn.iocoder.yudao.module.prison.service.riskassessment;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.module.prison.dal.dataobject.prisoner.PrisonerDO;
|
|
||||||
import cn.iocoder.yudao.module.prison.dal.dataobject.riskassessment.RiskAssessmentDO;
|
|
||||||
import cn.iocoder.yudao.module.prison.dal.dataobject.score.ScoreDO;
|
|
||||||
import cn.iocoder.yudao.module.prison.dal.mysql.prisoner.PrisonerMapper;
|
|
||||||
import cn.iocoder.yudao.module.prison.dal.mysql.riskassessment.RiskAssessmentMapper;
|
|
||||||
import cn.iocoder.yudao.module.prison.dal.mysql.score.ScoreDetailMapper;
|
|
||||||
import cn.iocoder.yudao.module.prison.service.riskassessment.dto.AssessmentContext;
|
|
||||||
import cn.iocoder.yudao.module.prison.service.riskassessment.enums.AssessmentTypeEnum;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
|
|
||||||
import jakarta.annotation.Resource;
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.math.RoundingMode;
|
|
||||||
import java.time.LocalDate;
|
|
||||||
import java.time.Period;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 评估数据聚合服务
|
|
||||||
* 从多个数据源聚合评估所需数据
|
|
||||||
*
|
|
||||||
* @author XLLC Team
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
@Service
|
|
||||||
public class AssessmentDataAggregator {
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private PrisonerMapper prisonerMapper;
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private RiskAssessmentMapper riskAssessmentMapper;
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private ScoreDetailMapper scoreDetailMapper;
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private DataMasker dataMasker;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 聚合指定罪犯的评估数据
|
|
||||||
*
|
|
||||||
* @param prisonerId 罪犯ID
|
|
||||||
* @param assessmentType 评估类型
|
|
||||||
* @param assessorId 评估人ID
|
|
||||||
* @param assessorName 评估人姓名
|
|
||||||
* @return 聚合后的评估上下文
|
|
||||||
*/
|
|
||||||
public AssessmentContext aggregate(Long prisonerId, Integer assessmentType, Long assessorId, String assessorName) {
|
|
||||||
log.debug("开始聚合罪犯ID={}的评估数据", prisonerId);
|
|
||||||
|
|
||||||
// 1. 获取罪犯基础信息
|
|
||||||
PrisonerDO prisoner = prisonerMapper.selectById(prisonerId);
|
|
||||||
if (prisoner == null) {
|
|
||||||
throw new IllegalArgumentException("罪犯不存在: " + prisonerId);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. 构建基础上下文
|
|
||||||
AssessmentContext.AssessmentContextBuilder builder = AssessmentContext.builder()
|
|
||||||
.prisonerId(String.valueOf(prisonerId))
|
|
||||||
.prisonerNo(prisoner.getPrisonerNo())
|
|
||||||
.assessmentType(AssessmentTypeEnum.getName(assessmentType))
|
|
||||||
.assessmentDate(LocalDate.now())
|
|
||||||
.assessorId(assessorId)
|
|
||||||
.assessorName(assessorName);
|
|
||||||
|
|
||||||
// 3. 聚合犯罪基本信息(泛化处理)
|
|
||||||
aggregateCrimeInfo(builder, prisoner);
|
|
||||||
|
|
||||||
// 4. 聚合心理评估得分
|
|
||||||
aggregatePsychologyScores(builder, prisonerId);
|
|
||||||
|
|
||||||
// 5. 聚合行为表现数据
|
|
||||||
aggregateBehaviorData(builder, prisonerId);
|
|
||||||
|
|
||||||
// 6. 聚合改造态度数据
|
|
||||||
aggregateReformData(builder, prisonerId);
|
|
||||||
|
|
||||||
// 7. 聚合消费数据
|
|
||||||
aggregateConsumptionData(builder, prisonerId);
|
|
||||||
|
|
||||||
// 8. 聚合历史评估数据
|
|
||||||
aggregateHistoryData(builder, prisonerId);
|
|
||||||
|
|
||||||
// 9. 聚合问卷答题数据
|
|
||||||
aggregateQuestionnaireData(builder, prisonerId);
|
|
||||||
|
|
||||||
AssessmentContext context = builder.build();
|
|
||||||
log.debug("数据聚合完成,罪犯编号: {}", context.getPrisonerNo());
|
|
||||||
|
|
||||||
return context;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 聚合犯罪基本信息
|
|
||||||
*/
|
|
||||||
private void aggregateCrimeInfo(AssessmentContext.AssessmentContextBuilder builder, PrisonerDO prisoner) {
|
|
||||||
// 犯罪类型泛化
|
|
||||||
String crimeCategory = dataMasker.generalizeCrimeType(
|
|
||||||
Optional.ofNullable(prisoner.getCrimeType()).orElse("未知")
|
|
||||||
);
|
|
||||||
|
|
||||||
// 刑期处理
|
|
||||||
Integer sentenceYears = 0;
|
|
||||||
if (prisoner.getSentenceDate() != null && prisoner.getReleaseDate() != null) {
|
|
||||||
Period period = Period.between(prisoner.getSentenceDate(), prisoner.getReleaseDate());
|
|
||||||
sentenceYears = period.getYears();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 入监时长
|
|
||||||
int imprisonmentMonths = 0;
|
|
||||||
if (prisoner.getEntryDate() != null) {
|
|
||||||
Period period = Period.between(prisoner.getEntryDate(), LocalDate.now());
|
|
||||||
imprisonmentMonths = period.getYears() * 12 + period.getMonths();
|
|
||||||
}
|
|
||||||
|
|
||||||
builder
|
|
||||||
.crimeCategory(crimeCategory)
|
|
||||||
.sentenceYears(sentenceYears)
|
|
||||||
.isRecidivist(Boolean.TRUE.equals(prisoner.getIsRecidivist()))
|
|
||||||
.imprisonmentMonths(imprisonmentMonths);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 聚合心理评估得分
|
|
||||||
*/
|
|
||||||
private void aggregatePsychologyScores(AssessmentContext.AssessmentContextBuilder builder, Long prisonerId) {
|
|
||||||
// 获取最近一次危险评估记录
|
|
||||||
RiskAssessmentDO latestAssessment = riskAssessmentMapper.selectOne(
|
|
||||||
new RiskAssessmentMapper.QueryWrapper()
|
|
||||||
.eq("prisoner_id", prisonerId)
|
|
||||||
.orderByDesc("assessment_date")
|
|
||||||
.last("LIMIT 1")
|
|
||||||
);
|
|
||||||
|
|
||||||
if (latestAssessment != null) {
|
|
||||||
builder
|
|
||||||
.violenceScore(normalizeScore(latestAssessment.getViolenceScore()))
|
|
||||||
.escapeScore(normalizeScore(latestAssessment.getEscapeScore()))
|
|
||||||
.suicideScore(normalizeScore(latestAssessment.getSuicideScore()));
|
|
||||||
} else {
|
|
||||||
// 默认值
|
|
||||||
builder
|
|
||||||
.violenceScore(BigDecimal.ZERO)
|
|
||||||
.escapeScore(BigDecimal.ZERO)
|
|
||||||
.suicideScore(BigDecimal.ZERO);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 聚合行为表现数据
|
|
||||||
*/
|
|
||||||
private void aggregateBehaviorData(AssessmentContext.AssessmentContextBuilder builder, Long prisonerId) {
|
|
||||||
// 计算近6月的统计数据
|
|
||||||
LocalDate sixMonthsAgo = LocalDate.now().minusMonths(6);
|
|
||||||
|
|
||||||
// 查询近6月的计分记录
|
|
||||||
List<ScoreDO> recentScores = scoreDetailMapper.selectList(
|
|
||||||
new ScoreDO().builder().prisonerId(prisonerId).build(),
|
|
||||||
new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<ScoreDO>()
|
|
||||||
.ge(ScoreDO::getRecordDate, sixMonthsAgo)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (recentScores.isEmpty()) {
|
|
||||||
builder
|
|
||||||
.avgScore(new BigDecimal("70")) // 默认中等水平
|
|
||||||
.violationCount6Month(0)
|
|
||||||
.praiseCount6Month(0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 计算平均分
|
|
||||||
BigDecimal totalScore = recentScores.stream()
|
|
||||||
.map(ScoreDO::getTotalScore)
|
|
||||||
.filter(s -> s != null)
|
|
||||||
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
|
||||||
|
|
||||||
BigDecimal avgScore = totalScore.divide(
|
|
||||||
new BigDecimal(recentScores.size()),
|
|
||||||
2,
|
|
||||||
RoundingMode.HALF_UP
|
|
||||||
);
|
|
||||||
|
|
||||||
// 统计违规和表扬次数(简化处理)
|
|
||||||
int violationCount = 0;
|
|
||||||
int praiseCount = 0;
|
|
||||||
for (ScoreDO score : recentScores) {
|
|
||||||
if (score.getDeductionPoints() != null && score.getDeductionPoints().intValue() > 0) {
|
|
||||||
violationCount++;
|
|
||||||
}
|
|
||||||
if (score.getRewardPoints() != null && score.getRewardPoints().intValue() > 0) {
|
|
||||||
praiseCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
builder
|
|
||||||
.avgScore(avgScore)
|
|
||||||
.violationCount6Month(violationCount)
|
|
||||||
.praiseCount6Month(praiseCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 聚合改造态度数据
|
|
||||||
* 这里简化处理,实际应根据问卷答题情况计算
|
|
||||||
*/
|
|
||||||
private void aggregateReformData(AssessmentContext.AssessmentContextBuilder builder, Long prisonerId) {
|
|
||||||
// 简化实现:基于行为得分推算
|
|
||||||
BigDecimal avgScore = builder.build().getAvgScore();
|
|
||||||
|
|
||||||
builder
|
|
||||||
.laborPerformance(avgScore) // 用平均分作为劳动表现评分
|
|
||||||
.educationParticipation(avgScore) // 用平均分作为教育参与度
|
|
||||||
.thoughtReportQuality(avgScore); // 用平均分作为思想汇报质量
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 聚合消费数据(区间化处理)
|
|
||||||
*/
|
|
||||||
private void aggregateConsumptionData(AssessmentContext.AssessmentContextBuilder builder, Long prisonerId) {
|
|
||||||
// TODO: 待消费模块完成后接入真实数据
|
|
||||||
// 暂时使用默认值
|
|
||||||
builder
|
|
||||||
.consumptionLevel(2) // 中等消费
|
|
||||||
.hasAbnormalConsumption(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 聚合历史评估数据
|
|
||||||
*/
|
|
||||||
private void aggregateHistoryData(AssessmentContext.AssessmentContextBuilder builder, Long prisonerId) {
|
|
||||||
// 获取历史评估记录
|
|
||||||
List<RiskAssessmentDO> historyAssessments = riskAssessmentMapper.selectList(
|
|
||||||
new RiskAssessmentMapper.QueryWrapper()
|
|
||||||
.eq("prisoner_id", prisonerId)
|
|
||||||
.orderByDesc("assessment_date")
|
|
||||||
);
|
|
||||||
|
|
||||||
if (historyAssessments.isEmpty()) {
|
|
||||||
// 首次评估
|
|
||||||
builder
|
|
||||||
.lastRiskLevel(null)
|
|
||||||
.lastTotalScore(null)
|
|
||||||
.lastAssessmentMonthsAgo(null)
|
|
||||||
.riskTrend("stable")
|
|
||||||
.assessmentHistoryCount(0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 最近一次评估
|
|
||||||
RiskAssessmentDO latest = historyAssessments.get(0);
|
|
||||||
|
|
||||||
builder
|
|
||||||
.lastRiskLevel(latest.getRiskLevel())
|
|
||||||
.lastTotalScore(latest.getTotalScore())
|
|
||||||
.assessmentHistoryCount(historyAssessments.size());
|
|
||||||
|
|
||||||
// 计算距今时长
|
|
||||||
if (latest.getAssessmentDate() != null) {
|
|
||||||
Period period = Period.between(latest.getAssessmentDate(), LocalDate.now());
|
|
||||||
int monthsAgo = period.getYears() * 12 + period.getMonths();
|
|
||||||
builder.lastAssessmentMonthsAgo(monthsAgo);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 计算风险趋势(基于最近3次评估)
|
|
||||||
String trend = calculateTrend(historyAssessments);
|
|
||||||
builder.riskTrend(trend);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 聚合问卷答题数据
|
|
||||||
* 根据各维度问卷的答题情况计算得分
|
|
||||||
*/
|
|
||||||
private void aggregateQuestionnaireData(AssessmentContext.AssessmentContextBuilder builder, Long prisonerId) {
|
|
||||||
// TODO: 待问卷模块完成后接入真实数据
|
|
||||||
// 暂时使用默认值,实际应从问卷答题记录中计算
|
|
||||||
builder
|
|
||||||
.criminalHistoryScore(new BigDecimal("50"))
|
|
||||||
.familyBackgroundScore(new BigDecimal("50"))
|
|
||||||
.socialSupportScore(new BigDecimal("50"))
|
|
||||||
.psychologicalStateScore(builder.build().getViolenceScore())
|
|
||||||
.behaviorPerformanceScore(builder.build().getAvgScore())
|
|
||||||
.reformAttitudeScore(builder.build().getLaborPerformance());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 计算风险趋势
|
|
||||||
*/
|
|
||||||
private String calculateTrend(List<RiskAssessmentDO> assessments) {
|
|
||||||
if (assessments.size() < 2) {
|
|
||||||
return "stable";
|
|
||||||
}
|
|
||||||
|
|
||||||
// 取最近3次评估
|
|
||||||
int count = Math.min(3, assessments.size());
|
|
||||||
List<RiskAssessmentDO> recent = assessments.subList(0, count);
|
|
||||||
|
|
||||||
// 计算得分变化
|
|
||||||
double sumDiff = 0;
|
|
||||||
for (int i = 1; i < recent.size(); i++) {
|
|
||||||
BigDecimal current = recent.get(i).getTotalScore();
|
|
||||||
BigDecimal previous = recent.get(i - 1).getTotalScore();
|
|
||||||
if (current != null && previous != null) {
|
|
||||||
sumDiff += current.subtract(previous).doubleValue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sumDiff > 10) {
|
|
||||||
return "rising"; // 上升
|
|
||||||
} else if (sumDiff < -10) {
|
|
||||||
return "declining"; // 下降
|
|
||||||
} else {
|
|
||||||
return "stable"; // 稳定
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 标准化分数到0-100范围
|
|
||||||
*/
|
|
||||||
private BigDecimal normalizeScore(BigDecimal score) {
|
|
||||||
if (score == null) {
|
|
||||||
return BigDecimal.ZERO;
|
|
||||||
}
|
|
||||||
// 假设原始分数范围是0-100,直接返回
|
|
||||||
return score;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 数据脱敏工具
|
|
||||||
*/
|
|
||||||
@Service
|
|
||||||
public static class DataMasker {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 犯罪类型泛化映射
|
|
||||||
*/
|
|
||||||
private static final Map<String, String> CRIME_TYPE_MAPPING = Map.of(
|
|
||||||
"盗窃", "财产类犯罪",
|
|
||||||
"抢劫", "暴力类犯罪",
|
|
||||||
"抢夺", "暴力类犯罪",
|
|
||||||
"故意伤害", "暴力类犯罪",
|
|
||||||
"故意杀人", "严重暴力犯罪",
|
|
||||||
"强奸", "严重暴力犯罪",
|
|
||||||
"贩毒", "涉毒类犯罪",
|
|
||||||
"制造毒品", "涉毒类犯罪",
|
|
||||||
"诈骗", "财产类犯罪",
|
|
||||||
"敲诈勒索", "财产类犯罪",
|
|
||||||
"组织卖淫", "其他类型犯罪",
|
|
||||||
"赌博", "其他类型犯罪"
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 泛化犯罪类型
|
|
||||||
*/
|
|
||||||
public String generalizeCrimeType(String originalType) {
|
|
||||||
if (!StringUtils.hasText(originalType)) {
|
|
||||||
return "其他类型犯罪";
|
|
||||||
}
|
|
||||||
return CRIME_TYPE_MAPPING.getOrDefault(originalType, "其他类型犯罪");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 泛化地名(预留)
|
|
||||||
*/
|
|
||||||
public String generalizeLocation(String originalLocation) {
|
|
||||||
// 暂时不处理,实际应根据需要进行脱敏
|
|
||||||
return originalLocation;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,246 +0,0 @@
|
|||||||
package cn.iocoder.yudao.module.prison.service.riskassessment;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.module.prison.service.riskassessment.dto.AssessmentContext;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 评估提示词构建器
|
|
||||||
* 根据评估上下文构建发送给LLM的提示词
|
|
||||||
*
|
|
||||||
* @author XLLC Team
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
public class AssessmentPromptBuilder {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 构建危险评估提示词
|
|
||||||
*
|
|
||||||
* @param context 评估上下文
|
|
||||||
* @return 提示词文本
|
|
||||||
*/
|
|
||||||
public String build(AssessmentContext context) {
|
|
||||||
StringBuilder prompt = new StringBuilder();
|
|
||||||
|
|
||||||
// 1. 角色定义
|
|
||||||
prompt.append(buildRoleDefinition());
|
|
||||||
|
|
||||||
// 2. 任务说明
|
|
||||||
prompt.append(buildTaskDescription(context));
|
|
||||||
|
|
||||||
// 3. 评估数据
|
|
||||||
prompt.append(buildAssessmentData(context));
|
|
||||||
|
|
||||||
// 4. 评估规则
|
|
||||||
prompt.append(buildAssessmentRules());
|
|
||||||
|
|
||||||
// 5. 输出要求
|
|
||||||
prompt.append(buildOutputRequirements());
|
|
||||||
|
|
||||||
// 6. 评估原则
|
|
||||||
prompt.append(buildPrinciples());
|
|
||||||
|
|
||||||
// 7. 开始评估指令
|
|
||||||
prompt.append(buildStartInstruction());
|
|
||||||
|
|
||||||
return prompt.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 构建角色定义
|
|
||||||
*/
|
|
||||||
private String buildRoleDefinition() {
|
|
||||||
return """
|
|
||||||
# 角色定义
|
|
||||||
你是一位拥有20年监狱工作经验的资深危险评估专家,精通心理学、犯罪学和行为分析。你需要基于提供的数据,对罪犯进行专业的危险等级评估。
|
|
||||||
|
|
||||||
""";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 构建任务说明
|
|
||||||
*/
|
|
||||||
private String buildTaskDescription(AssessmentContext context) {
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
sb.append("# 任务说明\n\n");
|
|
||||||
sb.append("根据以下【评估数据】对罪犯进行综合危险评估。\n\n");
|
|
||||||
sb.append("**评估类型**: ").append(context.getAssessmentType()).append("\n\n");
|
|
||||||
sb.append("请基于客观数据和专业判断,给出风险等级评估。\n\n");
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 构建评估数据
|
|
||||||
*/
|
|
||||||
private String buildAssessmentData(AssessmentContext context) {
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
sb.append("# 评估数据\n\n");
|
|
||||||
sb.append("```json\n");
|
|
||||||
sb.append(context.toJson());
|
|
||||||
sb.append("\n```\n\n");
|
|
||||||
|
|
||||||
sb.append("## 数据说明\n\n");
|
|
||||||
|
|
||||||
// 心理评估得分说明
|
|
||||||
sb.append("### 心理评估得分(0-100分,越高越危险)\n");
|
|
||||||
sb.append("- 暴力倾向: ").append(context.getViolenceScore()).append("分\n");
|
|
||||||
sb.append("- 脱逃倾向: ").append(context.getEscapeScore()).append("分\n");
|
|
||||||
sb.append("- 自杀倾向: ").append(context.getSuicideScore()).append("分\n\n");
|
|
||||||
|
|
||||||
// 行为表现说明
|
|
||||||
sb.append("### 行为表现\n");
|
|
||||||
sb.append("- 计分考核平均分: ").append(context.getAvgScore()).append("分\n");
|
|
||||||
sb.append("- 近6月违规次数: ").append(context.getViolationCount6Month()).append("次\n");
|
|
||||||
sb.append("- 近6月表扬次数: ").append(context.getPraiseCount6Month()).append("次\n\n");
|
|
||||||
|
|
||||||
// 历史评估说明
|
|
||||||
if (context.getLastRiskLevel() != null) {
|
|
||||||
sb.append("### 历史评估\n");
|
|
||||||
sb.append("- 上次风险等级: ").append(formatRiskLevel(context.getLastRiskLevel())).append("\n");
|
|
||||||
sb.append("- 历史风险趋势: ").append(formatTrend(context.getRiskTrend())).append("\n\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 特殊因素
|
|
||||||
if (hasRiskFactors(context)) {
|
|
||||||
sb.append("### 特殊风险因素\n");
|
|
||||||
if (Boolean.TRUE.equals(context.getHasFamilyCrisis())) {
|
|
||||||
sb.append("- 存在家庭变故\n");
|
|
||||||
}
|
|
||||||
if (Boolean.TRUE.equals(context.getHasConflictWithPrisoners())) {
|
|
||||||
sb.append("- 近期与他犯有矛盾\n");
|
|
||||||
}
|
|
||||||
if (Boolean.TRUE.equals(context.getHasMoodAbnormality())) {
|
|
||||||
sb.append("- 近期情绪异常\n");
|
|
||||||
}
|
|
||||||
if (StringUtils.hasText(context.getOtherRiskFactors())) {
|
|
||||||
sb.append("- 其他: ").append(context.getOtherRiskFactors()).append("\n");
|
|
||||||
}
|
|
||||||
sb.append("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 构建评估规则
|
|
||||||
*/
|
|
||||||
private String buildAssessmentRules() {
|
|
||||||
return """
|
|
||||||
# 评估规则
|
|
||||||
|
|
||||||
根据综合得分和风险因素确定风险等级:
|
|
||||||
|
|
||||||
| 风险等级 | 分值范围 | 说明 |
|
|
||||||
|---------|---------|------|
|
|
||||||
| 1-低风险 | < 40分 | 无明显风险因素,管理正常 |
|
|
||||||
| 2-中风险 | 40-69分 | 存在一定风险因素,需要关注 |
|
|
||||||
| 3-高风险 | 70-89分 | 存在明显风险因素,需要重点管控 |
|
|
||||||
| 4-极高风险 | ≥ 90分 | 存在严重风险因素,需要立即干预 |
|
|
||||||
|
|
||||||
**注意**: 风险因素的存在可能导致等级上调,即使得分较低。
|
|
||||||
|
|
||||||
""";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 构建输出要求
|
|
||||||
*/
|
|
||||||
private String buildOutputRequirements() {
|
|
||||||
return """
|
|
||||||
# 输出要求
|
|
||||||
|
|
||||||
请以JSON格式输出评估结果,包含以下字段:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"riskLevel": <1-4整数>,
|
|
||||||
"confidence": <0.0-1.0小数>,
|
|
||||||
"keyRiskFactors": ["因素1", "因素2", "因素3"],
|
|
||||||
"analysis": "<综合分析说明,100-200字>",
|
|
||||||
"suggestions": ["建议1", "建议2", "建议3"],
|
|
||||||
"attentionPoints": ["需要关注的点1", "需要关注的点2"]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**字段说明**:
|
|
||||||
- `riskLevel`: 风险等级(1-4)
|
|
||||||
- `confidence`: 评估置信度(0-1),反映评估的确定性
|
|
||||||
- `keyRiskFactors`: 最关键的风险因素(最多3个)
|
|
||||||
- `analysis`: 综合分析说明
|
|
||||||
- `suggestions`: 针对性管控建议(具体可操作)
|
|
||||||
- `attentionPoints`: 需要特别关注的点
|
|
||||||
|
|
||||||
""";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 构建评估原则
|
|
||||||
*/
|
|
||||||
private String buildPrinciples() {
|
|
||||||
return """
|
|
||||||
# 评估原则
|
|
||||||
|
|
||||||
1. **客观公正**: 基于数据进行分析,不带主观偏见
|
|
||||||
2. **综合判断**: 考虑各因素之间的关联性,而非简单求和
|
|
||||||
3. **重点突出**: 识别最关键的风险因素
|
|
||||||
4. **建议可行**: 建议要具体、可操作
|
|
||||||
5. **审慎判断**: 对于边界情况给出审慎判断
|
|
||||||
|
|
||||||
""";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 构建开始评估指令
|
|
||||||
*/
|
|
||||||
private String buildStartInstruction() {
|
|
||||||
return """
|
|
||||||
# 开始评估
|
|
||||||
|
|
||||||
请基于以上数据和规则,开始进行危险等级评估。
|
|
||||||
|
|
||||||
""";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 格式化风险等级
|
|
||||||
*/
|
|
||||||
private String formatRiskLevel(Integer level) {
|
|
||||||
if (level == null) return "无";
|
|
||||||
return switch (level) {
|
|
||||||
case 1 -> "1-低风险";
|
|
||||||
case 2 -> "2-中风险";
|
|
||||||
case 3 -> "3-高风险";
|
|
||||||
case 4 -> "4-极高风险";
|
|
||||||
default -> "未知(" + level + ")";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 格式化趋势描述
|
|
||||||
*/
|
|
||||||
private String formatTrend(String trend) {
|
|
||||||
if (trend == null) return "稳定";
|
|
||||||
return switch (trend) {
|
|
||||||
case "rising" -> "上升趋势";
|
|
||||||
case "declining" -> "下降趋势";
|
|
||||||
case "fluctuating" -> "波动";
|
|
||||||
default -> "稳定";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 检查是否存在特殊风险因素
|
|
||||||
*/
|
|
||||||
private boolean hasRiskFactors(AssessmentContext context) {
|
|
||||||
return Boolean.TRUE.equals(context.getHasFamilyCrisis())
|
|
||||||
|| Boolean.TRUE.equals(context.getHasConflictWithPrisoners())
|
|
||||||
|| Boolean.TRUE.equals(context.getHasMoodAbnormality())
|
|
||||||
|| StringUtils.hasText(context.getOtherRiskFactors());
|
|
||||||
}
|
|
||||||
|
|
||||||
// 需要引入 StringUtils
|
|
||||||
private static class StringUtils {
|
|
||||||
public static boolean hasText(String str) {
|
|
||||||
return str != null && !str.trim().isEmpty();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,108 +0,0 @@
|
|||||||
package cn.iocoder.yudao.module.prison.service.riskassessment.dto;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Builder;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.NoArgsConstructor;
|
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* LLM评估结果
|
|
||||||
*
|
|
||||||
* @author XLLC Team
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@Builder
|
|
||||||
@NoArgsConstructor
|
|
||||||
@AllArgsConstructor
|
|
||||||
public class LlmAssessmentResult {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 风险等级(1-4)
|
|
||||||
*/
|
|
||||||
private Integer riskLevel;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 置信度(0-1)
|
|
||||||
*/
|
|
||||||
private BigDecimal confidence;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 关键风险因素列表
|
|
||||||
*/
|
|
||||||
private List<String> keyRiskFactors;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 综合分析说明
|
|
||||||
*/
|
|
||||||
private String analysis;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 管控建议列表
|
|
||||||
*/
|
|
||||||
private List<String> suggestions;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 需要关注的点
|
|
||||||
*/
|
|
||||||
private List<String> attentionPoints;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 原始LLM响应
|
|
||||||
*/
|
|
||||||
private String rawResponse;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 使用的模型
|
|
||||||
*/
|
|
||||||
private String modelUsed;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 评估耗时(毫秒)
|
|
||||||
*/
|
|
||||||
private Long evaluationTimeMs;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 评估时间
|
|
||||||
*/
|
|
||||||
private LocalDateTime evaluatedAt;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 是否需要人工复核
|
|
||||||
*/
|
|
||||||
public boolean requiresHumanReview() {
|
|
||||||
// 置信度低于0.7或风险等级为4(极高风险)需要人工复核
|
|
||||||
return confidence.compareTo(new BigDecimal("0.7")) < 0 || riskLevel == 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取风险等级描述
|
|
||||||
*/
|
|
||||||
public String getRiskLevelDescription() {
|
|
||||||
if (riskLevel == null) return "未知";
|
|
||||||
return switch (riskLevel) {
|
|
||||||
case 1 -> "低风险";
|
|
||||||
case 2 -> "中风险";
|
|
||||||
case 3 -> "高风险";
|
|
||||||
case 4 -> "极高风险";
|
|
||||||
default -> "未知";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取风险等级颜色标识(前端使用)
|
|
||||||
*/
|
|
||||||
public String getRiskLevelColor() {
|
|
||||||
if (riskLevel == null) return "grey";
|
|
||||||
return switch (riskLevel) {
|
|
||||||
case 1 -> "success"; // 绿色
|
|
||||||
case 2 -> "warning"; // 橙色
|
|
||||||
case 3 -> "danger"; // 红色
|
|
||||||
case 4 -> "danger"; // 深红
|
|
||||||
default -> "info";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,239 +0,0 @@
|
|||||||
package cn.iocoder.yudao.module.prison.service.riskassessment.llm;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
|
||||||
import cn.iocoder.yudao.module.prison.service.riskassessment.llm.LlmClient.LlmOptions;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import org.springframework.web.client.RestClientException;
|
|
||||||
import org.springframework.web.client.RestTemplate;
|
|
||||||
|
|
||||||
import java.time.Duration;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Claude大模型客户端实现
|
|
||||||
*
|
|
||||||
* 基于Anthropic Claude API的客户端实现
|
|
||||||
* API文档: https://docs.anthropic.com/claude/reference/getting-started
|
|
||||||
*
|
|
||||||
* @author XLLC Team
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
@Component
|
|
||||||
public class ClaudeLlmClient implements LlmClient {
|
|
||||||
|
|
||||||
private static final String BASE_URL = "https://api.anthropic.com/v1/messages";
|
|
||||||
private static final String DEFAULT_MODEL = "claude-3-5-sonnet-20241022";
|
|
||||||
|
|
||||||
@Value("${llm.claude.api-key:}")
|
|
||||||
private String apiKey;
|
|
||||||
|
|
||||||
@Value("${llm.claude.timeout-seconds:30}")
|
|
||||||
private int timeoutSeconds;
|
|
||||||
|
|
||||||
private final RestTemplate restTemplate;
|
|
||||||
|
|
||||||
public ClaudeLlmClient() {
|
|
||||||
this.restTemplate = new RestTemplate();
|
|
||||||
// 配置超时
|
|
||||||
this.restTemplate.setRequestFactory(() -> {
|
|
||||||
var requestFactory = new org.springframework.http.client.SimpleClientHttpRequestFactory();
|
|
||||||
requestFactory.setConnectTimeout(Duration.ofSeconds(30));
|
|
||||||
requestFactory.setReadTimeout(Duration.ofSeconds(30));
|
|
||||||
return requestFactory;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String complete(String prompt, LlmOptions options) {
|
|
||||||
try {
|
|
||||||
ClaudeRequest request = buildRequest(prompt, options, false);
|
|
||||||
ClaudeResponse response = execute(request);
|
|
||||||
|
|
||||||
if (response.content != null && !response.content.isEmpty()) {
|
|
||||||
return response.content.get(0).text;
|
|
||||||
}
|
|
||||||
|
|
||||||
log.warn("Claude响应内容为空");
|
|
||||||
return "";
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("Claude API调用失败: {}", e.getMessage(), e);
|
|
||||||
throw new LlmException("Claude API调用失败: " + e.getMessage(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String completeJson(String prompt, LlmOptions options) {
|
|
||||||
try {
|
|
||||||
// 在提示词中明确要求JSON输出
|
|
||||||
String jsonPrompt = prompt + "\n\n请确保输出格式为有效的JSON,不要添加额外的markdown格式。";
|
|
||||||
|
|
||||||
ClaudeRequest request = buildRequest(jsonPrompt, options, true);
|
|
||||||
ClaudeResponse response = execute(request);
|
|
||||||
|
|
||||||
if (response.content != null && !response.content.isEmpty()) {
|
|
||||||
String text = response.content.get(0).text;
|
|
||||||
// 清理可能的markdown包装
|
|
||||||
text = cleanJsonResponse(text);
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
|
|
||||||
log.warn("Claude JSON响应内容为空");
|
|
||||||
return "";
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("Claude JSON API调用失败: {}", e.getMessage(), e);
|
|
||||||
throw new LlmException("Claude JSON API调用失败: " + e.getMessage(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isAvailable() {
|
|
||||||
if (apiKey == null || apiKey.isEmpty()) {
|
|
||||||
log.warn("Claude API密钥未配置");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
// 简单的健康检查
|
|
||||||
String testPrompt = "Hello";
|
|
||||||
ClaudeRequest request = buildRequest(testPrompt,
|
|
||||||
LlmOptions.defaultOptions(), false);
|
|
||||||
execute(request);
|
|
||||||
return true;
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.warn("Claude服务不可用: {}", e.getMessage());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getName() {
|
|
||||||
return "Claude";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 构建请求对象
|
|
||||||
*/
|
|
||||||
private ClaudeRequest buildRequest(String prompt, LlmOptions options, boolean isJsonMode) {
|
|
||||||
// 构建系统提示词(用于JSON模式)
|
|
||||||
String systemPrompt = isJsonMode
|
|
||||||
? "你是一个专业的危险评估助手。请始终以JSON格式输出响应,不要添加任何markdown代码块标记。"
|
|
||||||
: "你是一位专业的危险评估专家。请基于提供的数据进行专业评估。";
|
|
||||||
|
|
||||||
return new ClaudeRequest(
|
|
||||||
options.model() != null ? options.model() : DEFAULT_MODEL,
|
|
||||||
prompt,
|
|
||||||
systemPrompt,
|
|
||||||
options.temperature(),
|
|
||||||
options.maxTokens()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 执行API调用
|
|
||||||
*/
|
|
||||||
private ClaudeResponse execute(ClaudeRequest request) {
|
|
||||||
// 请求头
|
|
||||||
Map<String, String> headers = new HashMap<>();
|
|
||||||
headers.put("x-api-key", apiKey);
|
|
||||||
headers.put("anthropic-version", "2023-06-01");
|
|
||||||
headers.put("anthropic-dangerous-direct-browser-access", "true");
|
|
||||||
headers.put("content-type", "application/json");
|
|
||||||
|
|
||||||
// 构建请求体
|
|
||||||
Map<String, Object> body = new HashMap<>();
|
|
||||||
body.put("model", request.model());
|
|
||||||
body.put("messages", new Object[]{
|
|
||||||
Map.of("role", "system", "content", request.systemPrompt())
|
|
||||||
});
|
|
||||||
body.put("max_tokens", request.maxTokens());
|
|
||||||
body.put("temperature", request.temperature());
|
|
||||||
body.put("stream", false);
|
|
||||||
|
|
||||||
// 添加用户消息
|
|
||||||
Object[] messages = new Object[2];
|
|
||||||
messages[0] = Map.of("role", "system", "content", request.systemPrompt());
|
|
||||||
messages[1] = Map.of("role", "user", "content", request.prompt());
|
|
||||||
body.put("messages", messages);
|
|
||||||
|
|
||||||
try {
|
|
||||||
// 注意: 实际使用时需要配置HTTP客户端处理Anthropic的特殊请求头
|
|
||||||
// 这里使用简化实现,实际项目中建议使用官方SDK
|
|
||||||
log.debug("调用Claude API, model: {}, temperature: {}",
|
|
||||||
request.model(), request.temperature());
|
|
||||||
|
|
||||||
// 模拟响应(实际需要接入真实API)
|
|
||||||
// TODO: 接入真实Claude API
|
|
||||||
return buildMockResponse();
|
|
||||||
|
|
||||||
} catch (RestClientException e) {
|
|
||||||
log.error("Claude API请求失败: {}", e.getMessage());
|
|
||||||
throw new LlmException("API请求失败: " + e.getMessage(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 构建模拟响应(开发阶段使用)
|
|
||||||
*/
|
|
||||||
private ClaudeResponse buildMockResponse() {
|
|
||||||
// 开发阶段返回模拟数据
|
|
||||||
log.warn("使用Claude API模拟响应,请配置真实API密钥");
|
|
||||||
|
|
||||||
ClaudeResponse.ContentBlock content = new ClaudeResponse.ContentBlock(
|
|
||||||
"text",
|
|
||||||
"{\"riskLevel\": 2, \"confidence\": 0.85, \"keyRiskFactors\": [\"开发阶段模拟数据\"], \"analysis\": \"这是模拟响应,请配置Claude API密钥后使用真实调用\", \"suggestions\": [\"配置API密钥后重启服务\"]}"
|
|
||||||
);
|
|
||||||
|
|
||||||
return new ClaudeResponse(
|
|
||||||
"mock-id",
|
|
||||||
"assistant",
|
|
||||||
new java.util.List.of(content),
|
|
||||||
"stop",
|
|
||||||
"end_turn"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 清理JSON响应,去除markdown包装
|
|
||||||
*/
|
|
||||||
private String cleanJsonResponse(String text) {
|
|
||||||
if (text == null) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
// 去除 ```json 和 ``` 包装
|
|
||||||
text = text.replaceAll("```json\\s*", "")
|
|
||||||
.replaceAll("```\\s*", "")
|
|
||||||
.trim();
|
|
||||||
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Claude API请求结构
|
|
||||||
*/
|
|
||||||
private record ClaudeRequest(
|
|
||||||
String model,
|
|
||||||
String prompt,
|
|
||||||
String systemPrompt,
|
|
||||||
double temperature,
|
|
||||||
int maxTokens
|
|
||||||
) {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Claude API响应结构
|
|
||||||
*/
|
|
||||||
private record ClaudeResponse(
|
|
||||||
String id,
|
|
||||||
String type,
|
|
||||||
java.util.List<ContentBlock> content,
|
|
||||||
String stop_reason,
|
|
||||||
String role
|
|
||||||
) {
|
|
||||||
record ContentBlock(String type, String text) {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,6 +1,6 @@
|
|||||||
package cn.iocoder.yudao.module.prison.service.riskassessment.llm;
|
package cn.iocoder.yudao.module.prison.service.riskassessment.llm;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* LLM客户端接口
|
* LLM客户端接口
|
||||||
@ -9,81 +9,108 @@ import java.util.Map;
|
|||||||
*/
|
*/
|
||||||
public interface LlmClient {
|
public interface LlmClient {
|
||||||
|
|
||||||
/**
|
|
||||||
* 调用大模型生成内容
|
|
||||||
*
|
|
||||||
* @param prompt 提示词
|
|
||||||
* @param options 调用选项
|
|
||||||
* @return 模型生成的文本响应
|
|
||||||
*/
|
|
||||||
String complete(String prompt, LlmOptions options);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 调用大模型生成JSON格式响应
|
|
||||||
*
|
|
||||||
* @param prompt 提示词
|
|
||||||
* @param options 调用选项
|
|
||||||
* @return JSON格式的响应文本
|
|
||||||
*/
|
|
||||||
String completeJson(String prompt, LlmOptions options);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 检查客户端是否可用
|
|
||||||
*
|
|
||||||
* @return 是否可用
|
|
||||||
*/
|
|
||||||
boolean isAvailable();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取客户端名称
|
* 获取客户端名称
|
||||||
*
|
|
||||||
* @return 客户端名称
|
|
||||||
*/
|
*/
|
||||||
String getName();
|
String getName();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 调用选项
|
* 检查客户端是否可用
|
||||||
*/
|
*/
|
||||||
record LlmOptions(
|
boolean isAvailable();
|
||||||
String model, // 模型名称
|
|
||||||
double temperature, // 温度参数 (0.0-1.0)
|
/**
|
||||||
int maxTokens, // 最大Token数
|
* 简单文本补全
|
||||||
Map<String, String> headers // 额外请求头
|
*
|
||||||
) {
|
* @param prompt 提示词
|
||||||
|
* @param options 选项
|
||||||
|
* @return 生成的文本
|
||||||
|
*/
|
||||||
|
String complete(String prompt, LlmOptions options);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JSON格式文本补全
|
||||||
|
*
|
||||||
|
* @param prompt 提示词
|
||||||
|
* @param options 选项
|
||||||
|
* @return 生成的JSON文本
|
||||||
|
*/
|
||||||
|
String completeJson(String prompt, LlmOptions options);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* LLM选项配置
|
||||||
|
*/
|
||||||
|
class LlmOptions {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 最大token数
|
||||||
|
*/
|
||||||
|
private int maxTokens = 4096;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 温度参数 (0-2)
|
||||||
|
*/
|
||||||
|
private float temperature = 0.7f;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 系统提示词
|
||||||
|
*/
|
||||||
|
private String systemPrompt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否需要JSON格式响应
|
||||||
|
*/
|
||||||
|
private boolean jsonMode = false;
|
||||||
|
|
||||||
|
// Getters and Setters
|
||||||
|
public int getMaxTokens() {
|
||||||
|
return maxTokens;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxTokens(int maxTokens) {
|
||||||
|
this.maxTokens = maxTokens;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getTemperature() {
|
||||||
|
return temperature;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTemperature(float temperature) {
|
||||||
|
this.temperature = temperature;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSystemPrompt() {
|
||||||
|
return systemPrompt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSystemPrompt(String systemPrompt) {
|
||||||
|
this.systemPrompt = systemPrompt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isJsonMode() {
|
||||||
|
return jsonMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setJsonMode(boolean jsonMode) {
|
||||||
|
this.jsonMode = jsonMode;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建默认选项
|
* 创建默认选项
|
||||||
*/
|
*/
|
||||||
public static LlmOptions defaultOptions() {
|
public static LlmOptions defaultOptions() {
|
||||||
return new LlmOptions(
|
return new LlmOptions();
|
||||||
"claude-3-5-sonnet-20241022",
|
|
||||||
0.1, // 低温度,输出更稳定
|
|
||||||
2000,
|
|
||||||
Map.of()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建低温度选项(用于评估场景)
|
* 创建评估专用选项
|
||||||
*/
|
*/
|
||||||
public static LlmOptions assessmentOptions() {
|
public static LlmOptions assessmentOptions() {
|
||||||
return new LlmOptions(
|
LlmOptions options = new LlmOptions();
|
||||||
"claude-3-5-sonnet-20241022",
|
options.setMaxTokens(2048);
|
||||||
0.05, // 极低温度,减少随机性
|
options.setTemperature(0.3f); // 评估场景使用较低温度,减少随机性
|
||||||
2048,
|
options.setJsonMode(true);
|
||||||
Map.of()
|
return options;
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建高温度选项(用于创意场景)
|
|
||||||
*/
|
|
||||||
public static LlmOptions creativeOptions() {
|
|
||||||
return new LlmOptions(
|
|
||||||
"claude-3-5-sonnet-20241022",
|
|
||||||
0.7,
|
|
||||||
4096,
|
|
||||||
Map.of()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,106 +1,48 @@
|
|||||||
package cn.iocoder.yudao.module.prison.service.riskassessment.llm;
|
package cn.iocoder.yudao.module.prison.service.riskassessment.llm;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* LLM客户端工厂
|
* LLM客户端工厂
|
||||||
* 根据配置选择不同的LLM客户端
|
* 根据配置返回对应的LLM客户端
|
||||||
*
|
*
|
||||||
* @author XLLC Team
|
* @author XLLC Team
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
|
||||||
@Component
|
@Component
|
||||||
public class LlmClientFactory {
|
public class LlmClientFactory {
|
||||||
|
|
||||||
private final Map<String, LlmClient> clients;
|
private final OpenAiCompatibleClient openAiCompatibleClient;
|
||||||
|
|
||||||
public LlmClientFactory(List<LlmClient> clientList) {
|
public LlmClientFactory(OpenAiCompatibleClient openAiCompatibleClient) {
|
||||||
// 初始化客户端映射
|
this.openAiCompatibleClient = openAiCompatibleClient;
|
||||||
this.clients = new java.util.HashMap<>();
|
}
|
||||||
for (LlmClient client : clientList) {
|
|
||||||
clients.put(client.getName().toLowerCase(), client);
|
/**
|
||||||
log.info("注册LLM客户端: {}", client.getName());
|
* 获取评估专用的LLM客户端
|
||||||
}
|
*/
|
||||||
|
public LlmClient getAssessmentClient() {
|
||||||
|
// 当前只支持OpenAI兼容客户端
|
||||||
|
return openAiCompatibleClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取指定名称的客户端
|
* 获取指定名称的客户端
|
||||||
*
|
|
||||||
* @param name 客户端名称
|
|
||||||
* @return LLM客户端
|
|
||||||
*/
|
*/
|
||||||
public LlmClient getClient(String name) {
|
public LlmClient getClient(String clientName) {
|
||||||
LlmClient client = clients.get(name.toLowerCase());
|
if (clientName == null) {
|
||||||
if (client == null) {
|
return getAssessmentClient();
|
||||||
throw new LlmException("UNKNOWN_CLIENT", "未找到LLM客户端: " + name);
|
|
||||||
}
|
}
|
||||||
return client;
|
|
||||||
|
return switch (clientName.toLowerCase()) {
|
||||||
|
case "openai", "oneapi", "openai-compatible" -> openAiCompatibleClient;
|
||||||
|
default -> getAssessmentClient();
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取默认客户端
|
* 检查是否有可用的客户端
|
||||||
*
|
|
||||||
* @return 默认LLM客户端
|
|
||||||
*/
|
*/
|
||||||
public LlmClient getDefaultClient() {
|
public boolean hasAvailableClient() {
|
||||||
// 优先使用Claude
|
return openAiCompatibleClient.isAvailable();
|
||||||
if (clients.containsKey("claude")) {
|
|
||||||
return clients.get("claude");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果没有Claude,返回第一个可用的客户端
|
|
||||||
return clients.values().stream()
|
|
||||||
.filter(LlmClient::isAvailable)
|
|
||||||
.findFirst()
|
|
||||||
.orElseThrow(() -> new LlmException("NO_AVAILABLE_CLIENT", "没有可用的LLM客户端"));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取用于评估的客户端
|
|
||||||
* 优先选择Claude(评估能力强)
|
|
||||||
*
|
|
||||||
* @return 评估用的LLM客户端
|
|
||||||
*/
|
|
||||||
public LlmClient getAssessmentClient() {
|
|
||||||
// 优先使用Claude
|
|
||||||
LlmClient claude = clients.get("claude");
|
|
||||||
if (claude != null && claude.isAvailable()) {
|
|
||||||
log.debug("选择Claude作为评估客户端");
|
|
||||||
return claude;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查其他可用客户端
|
|
||||||
for (LlmClient client : clients.values()) {
|
|
||||||
if (client.isAvailable()) {
|
|
||||||
log.warn("Claude不可用,使用备用客户端: {}", client.getName());
|
|
||||||
return client;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new LlmException("NO_AVAILABLE_CLIENT", "没有可用的LLM客户端进行评估");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 检查指定客户端是否可用
|
|
||||||
*
|
|
||||||
* @param name 客户端名称
|
|
||||||
* @return 是否可用
|
|
||||||
*/
|
|
||||||
public boolean isAvailable(String name) {
|
|
||||||
LlmClient client = clients.get(name.toLowerCase());
|
|
||||||
return client != null && client.isAvailable();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取所有已注册的客户端名称
|
|
||||||
*
|
|
||||||
* @return 客户端名称列表
|
|
||||||
*/
|
|
||||||
public List<String> getRegisteredClients() {
|
|
||||||
return clients.keySet().stream().toList();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,35 +1,17 @@
|
|||||||
package cn.iocoder.yudao.module.prison.service.riskassessment.llm;
|
package cn.iocoder.yudao.module.prison.service.riskassessment.llm;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* LLM调用异常
|
* LLM操作异常
|
||||||
*
|
*
|
||||||
* @author XLLC Team
|
* @author XLLC Team
|
||||||
*/
|
*/
|
||||||
public class LlmException extends RuntimeException {
|
public class LlmException extends RuntimeException {
|
||||||
|
|
||||||
private final String errorCode;
|
|
||||||
|
|
||||||
public LlmException(String message) {
|
public LlmException(String message) {
|
||||||
super(message);
|
super(message);
|
||||||
this.errorCode = "LLM_ERROR";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public LlmException(String message, Throwable cause) {
|
public LlmException(String message, Throwable cause) {
|
||||||
super(message, cause);
|
super(message, cause);
|
||||||
this.errorCode = "LLM_ERROR";
|
|
||||||
}
|
|
||||||
|
|
||||||
public LlmException(String errorCode, String message) {
|
|
||||||
super(message);
|
|
||||||
this.errorCode = errorCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LlmException(String errorCode, String message, Throwable cause) {
|
|
||||||
super(message, cause);
|
|
||||||
this.errorCode = errorCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getErrorCode() {
|
|
||||||
return errorCode;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,173 @@
|
|||||||
|
package cn.iocoder.yudao.module.prison.service.riskassessment.llm;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.http.*;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.client.RestClientException;
|
||||||
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OpenAI兼容客户端
|
||||||
|
* 支持OneAPI等统一接口服务
|
||||||
|
*
|
||||||
|
* @author XLLC Team
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class OpenAiCompatibleClient implements LlmClient {
|
||||||
|
|
||||||
|
private static final String DEFAULT_BASE_URL = "https://oneapi.gongjulian.cn/v1";
|
||||||
|
private static final String DEFAULT_MODEL = "deepseek-ai/deepseek-v3.2";
|
||||||
|
|
||||||
|
@Value("${llm.local.base-url:}")
|
||||||
|
private String baseUrl;
|
||||||
|
|
||||||
|
@Value("${llm.local.api-key:}")
|
||||||
|
private String apiKey;
|
||||||
|
|
||||||
|
@Value("${llm.local.model:}")
|
||||||
|
private String model;
|
||||||
|
|
||||||
|
@Value("${llm.local.timeout-seconds:120}")
|
||||||
|
private int timeoutSeconds;
|
||||||
|
|
||||||
|
private final RestTemplate restTemplate;
|
||||||
|
private final ObjectMapper objectMapper;
|
||||||
|
|
||||||
|
public OpenAiCompatibleClient() {
|
||||||
|
this.restTemplate = new RestTemplate();
|
||||||
|
this.objectMapper = new ObjectMapper();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "OpenAI Compatible (OneAPI)";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAvailable() {
|
||||||
|
try {
|
||||||
|
// 尝试获取模型列表来检查连接
|
||||||
|
String url = getBaseUrl() + "/models";
|
||||||
|
HttpHeaders headers = createHeaders();
|
||||||
|
HttpEntity<String> entity = new HttpEntity<>(headers);
|
||||||
|
|
||||||
|
restTemplate.exchange(url, HttpMethod.GET, entity, String.class,
|
||||||
|
Duration.ofSeconds(5));
|
||||||
|
return true;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("LLM客户端不可用: {}", e.getMessage());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String complete(String prompt, LlmOptions options) {
|
||||||
|
String url = getBaseUrl() + "/chat/completions";
|
||||||
|
|
||||||
|
HttpHeaders headers = createHeaders();
|
||||||
|
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||||
|
|
||||||
|
// 构建请求体
|
||||||
|
Map<String, Object> requestBody = new HashMap<>();
|
||||||
|
requestBody.put("model", getModel());
|
||||||
|
|
||||||
|
// 消息
|
||||||
|
List<Map<String, String>> messages = new ArrayList<>();
|
||||||
|
|
||||||
|
if (options.getSystemPrompt() != null && !options.getSystemPrompt().isEmpty()) {
|
||||||
|
Map<String, String> systemMessage = new HashMap<>();
|
||||||
|
systemMessage.put("role", "system");
|
||||||
|
systemMessage.put("content", options.getSystemPrompt());
|
||||||
|
messages.add(systemMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, String> userMessage = new HashMap<>();
|
||||||
|
userMessage.put("role", "user");
|
||||||
|
userMessage.put("content", prompt);
|
||||||
|
messages.add(userMessage);
|
||||||
|
|
||||||
|
requestBody.put("messages", messages);
|
||||||
|
|
||||||
|
// 参数
|
||||||
|
if (options.getMaxTokens() > 0) {
|
||||||
|
requestBody.put("max_tokens", options.getMaxTokens());
|
||||||
|
}
|
||||||
|
if (options.getTemperature() >= 0 && options.getTemperature() <= 2) {
|
||||||
|
requestBody.put("temperature", options.getTemperature());
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpEntity<Map<String, Object>> entity = new HttpEntity<>(requestBody, headers);
|
||||||
|
|
||||||
|
try {
|
||||||
|
ResponseEntity<String> response = restTemplate.exchange(
|
||||||
|
url, HttpMethod.POST, entity, String.class,
|
||||||
|
Duration.ofSeconds(timeoutSeconds));
|
||||||
|
|
||||||
|
if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null) {
|
||||||
|
return parseContent(response.getBody());
|
||||||
|
}
|
||||||
|
throw new LlmException("LLM调用失败: " + response.getStatusCode());
|
||||||
|
} catch (RestClientException e) {
|
||||||
|
log.error("LLM调用异常", e);
|
||||||
|
throw new LlmException("LLM调用异常: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String completeJson(String prompt, LlmOptions options) {
|
||||||
|
// 设置JSON模式
|
||||||
|
LlmOptions jsonOptions = new LlmOptions();
|
||||||
|
jsonOptions.setMaxTokens(options.getMaxTokens());
|
||||||
|
jsonOptions.setTemperature(options.getTemperature());
|
||||||
|
jsonOptions.setSystemPrompt(options.getSystemPrompt());
|
||||||
|
jsonOptions.setJsonMode(true);
|
||||||
|
|
||||||
|
// 在提示词中强调JSON格式
|
||||||
|
String jsonPrompt = prompt + "\n\n请严格按照JSON格式回复,不要包含其他内容。";
|
||||||
|
|
||||||
|
return complete(jsonPrompt, jsonOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getBaseUrl() {
|
||||||
|
return baseUrl != null && !baseUrl.isEmpty() ? baseUrl : DEFAULT_BASE_URL;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getModel() {
|
||||||
|
return model != null && !model.isEmpty() ? model : DEFAULT_MODEL;
|
||||||
|
}
|
||||||
|
|
||||||
|
private HttpHeaders createHeaders() {
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.set("Authorization", "Bearer " + apiKey);
|
||||||
|
headers.set("Content-Type", MediaType.APPLICATION_JSON_VALUE);
|
||||||
|
headers.set("Accept", MediaType.APPLICATION_JSON_VALUE);
|
||||||
|
return headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String parseContent(String responseBody) {
|
||||||
|
try {
|
||||||
|
JsonNode root = objectMapper.readTree(responseBody);
|
||||||
|
JsonNode choices = root.path("choices");
|
||||||
|
if (choices.isArray() && choices.size() > 0) {
|
||||||
|
JsonNode message = choices.get(0).path("message");
|
||||||
|
if (!message.isMissingNode()) {
|
||||||
|
return message.path("content").asText();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new LlmException("解析LLM响应失败");
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("解析LLM响应异常", e);
|
||||||
|
throw new LlmException("解析LLM响应异常: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
59
yudao-module-prison/src/main/resources/sql/answer_module.sql
Normal file
59
yudao-module-prison/src/main/resources/sql/answer_module.sql
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
-- =====================================================
|
||||||
|
-- XL监狱综合管理平台 - 问卷答题记录模块数据库脚本
|
||||||
|
-- 生成时间: 2026-01-15
|
||||||
|
-- =====================================================
|
||||||
|
|
||||||
|
-- =====================================================
|
||||||
|
-- 1. 问卷答题记录表 (prison_answer)
|
||||||
|
-- =====================================================
|
||||||
|
CREATE TABLE IF NOT EXISTS `prison_answer` (
|
||||||
|
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '答题记录ID',
|
||||||
|
`assessment_record_id` bigint NOT NULL COMMENT '测评记录ID',
|
||||||
|
`question_id` bigint NOT NULL COMMENT '问题ID',
|
||||||
|
`questionnaire_id` bigint DEFAULT NULL COMMENT '问卷ID(冗余)',
|
||||||
|
`prisoner_id` bigint NOT NULL COMMENT '罪犯ID',
|
||||||
|
`question_type` tinyint NOT NULL DEFAULT 1 COMMENT '问题类型:1-单选 2-多选 3-填空 4-评分 5-日期 6-数字',
|
||||||
|
`answer_text` text COMMENT '答案内容(填空题、评分题等)',
|
||||||
|
`option_ids` text COMMENT '选项ID列表(JSON数组,如 [1,2,3])',
|
||||||
|
`score` decimal(10,2) DEFAULT NULL COMMENT '得分',
|
||||||
|
`is_correct` tinyint(1) DEFAULT NULL COMMENT '是否正确:null-未评分 false-错误 true-正确',
|
||||||
|
`duration` int DEFAULT NULL COMMENT '答题时间(秒)',
|
||||||
|
`creator` varchar(64) DEFAULT '' COMMENT '创建者',
|
||||||
|
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||||
|
`updater` varchar(64) DEFAULT '' COMMENT '更新者',
|
||||||
|
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||||
|
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
|
||||||
|
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `idx_prison_answer_assessment_record_id` (`assessment_record_id`),
|
||||||
|
KEY `idx_prison_answer_question_id` (`question_id`),
|
||||||
|
KEY `idx_prison_answer_prisoner_id` (`prisoner_id`),
|
||||||
|
KEY `idx_prison_answer_questionnaire_id` (`questionnaire_id`)
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='问卷答题记录表';
|
||||||
|
|
||||||
|
-- =====================================================
|
||||||
|
-- 2. 序列 (适用于 PostgreSQL、Oracle、DB2 等数据库)
|
||||||
|
-- =====================================================
|
||||||
|
-- MySQL 不需要此序列,使用 AUTO_INCREMENT
|
||||||
|
-- PostgreSQL: CREATE SEQUENCE prison_answer_seq;
|
||||||
|
-- Oracle: CREATE SEQUENCE prison_answer_seq MINVALUE 1 START WITH 1 INCREMENT BY 1 CACHE 20;
|
||||||
|
|
||||||
|
-- =====================================================
|
||||||
|
-- 3. 菜单权限 SQL
|
||||||
|
-- =====================================================
|
||||||
|
-- 注意: 执行前请确保问卷管理菜单 (id=5047) 已存在
|
||||||
|
|
||||||
|
-- 8. 答卷管理菜单
|
||||||
|
INSERT INTO system_menu (name, permission, type, sort, parent_id, path, icon, component, status, component_name)
|
||||||
|
VALUES ('答卷管理', '', 2, 8, 5047, 'answer', '', 'prison/answer/index', 0, 'Answer');
|
||||||
|
SELECT @answerParentId := LAST_INSERT_ID();
|
||||||
|
INSERT INTO system_menu (name, permission, type, sort, parent_id, path, icon, component, status)
|
||||||
|
VALUES ('答卷查询', 'prison:answer:query', 3, 1, @answerParentId, '', '', '', 0);
|
||||||
|
INSERT INTO system_menu (name, permission, type, sort, parent_id, path, icon, component, status)
|
||||||
|
VALUES ('答卷创建', 'prison:answer:create', 3, 2, @answerParentId, '', '', '', 0);
|
||||||
|
INSERT INTO system_menu (name, permission, type, sort, parent_id, path, icon, component, status)
|
||||||
|
VALUES ('答卷更新', 'prison:answer:update', 3, 3, @answerParentId, '', '', '', 0);
|
||||||
|
INSERT INTO system_menu (name, permission, type, sort, parent_id, path, icon, component, status)
|
||||||
|
VALUES ('答卷删除', 'prison:answer:delete', 3, 4, @answerParentId, '', '', '', 0);
|
||||||
|
INSERT INTO system_menu (name, permission, type, sort, parent_id, path, icon, component, status)
|
||||||
|
VALUES ('答卷导出', 'prison:answer:export', 3, 5, @answerParentId, '', '', '', 0);
|
||||||
@ -0,0 +1,250 @@
|
|||||||
|
-- =====================================================
|
||||||
|
-- XL监狱综合管理平台 - 测评执行模块数据库迁移脚本
|
||||||
|
-- 生成时间: 2026-01-15
|
||||||
|
-- 说明: 将 assessment 模块功能整合到 questionnairerecord 模块
|
||||||
|
-- 兼容 MySQL 8.0
|
||||||
|
-- =====================================================
|
||||||
|
|
||||||
|
-- =====================================================
|
||||||
|
-- 1. 更新 prison_questionnaire_record 表结构
|
||||||
|
-- 添加测评执行所需字段
|
||||||
|
-- =====================================================
|
||||||
|
|
||||||
|
-- 添加问卷名称字段
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM information_schema.COLUMNS
|
||||||
|
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'prison_questionnaire_record'
|
||||||
|
AND COLUMN_NAME = 'questionnaire_name') THEN
|
||||||
|
ALTER TABLE `prison_questionnaire_record`
|
||||||
|
ADD COLUMN `questionnaire_name` varchar(200) DEFAULT NULL COMMENT '问卷名称' AFTER `questionnaire_id`;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- 添加罪犯姓名字段
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM information_schema.COLUMNS
|
||||||
|
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'prison_questionnaire_record'
|
||||||
|
AND COLUMN_NAME = 'prisoner_name') THEN
|
||||||
|
ALTER TABLE `prison_questionnaire_record`
|
||||||
|
ADD COLUMN `prisoner_name` varchar(100) DEFAULT NULL COMMENT '罪犯姓名' AFTER `prisoner_no`;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- 添加开始时间字段
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM information_schema.COLUMNS
|
||||||
|
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'prison_questionnaire_record'
|
||||||
|
AND COLUMN_NAME = 'start_time') THEN
|
||||||
|
ALTER TABLE `prison_questionnaire_record`
|
||||||
|
ADD COLUMN `start_time` datetime DEFAULT NULL COMMENT '开始时间';
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- 添加结束时间字段
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM information_schema.COLUMNS
|
||||||
|
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'prison_questionnaire_record'
|
||||||
|
AND COLUMN_NAME = 'end_time') THEN
|
||||||
|
ALTER TABLE `prison_questionnaire_record`
|
||||||
|
ADD COLUMN `end_time` datetime DEFAULT NULL COMMENT '结束时间';
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- 添加截止日期字段
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM information_schema.COLUMNS
|
||||||
|
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'prison_questionnaire_record'
|
||||||
|
AND COLUMN_NAME = 'deadline') THEN
|
||||||
|
ALTER TABLE `prison_questionnaire_record`
|
||||||
|
ADD COLUMN `deadline` datetime DEFAULT NULL COMMENT '截止日期';
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- 添加客观题得分字段
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM information_schema.COLUMNS
|
||||||
|
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'prison_questionnaire_record'
|
||||||
|
AND COLUMN_NAME = 'objective_score') THEN
|
||||||
|
ALTER TABLE `prison_questionnaire_record`
|
||||||
|
ADD COLUMN `objective_score` decimal(10,2) DEFAULT 0.00 COMMENT '客观题得分';
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- 添加主观题得分字段
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM information_schema.COLUMNS
|
||||||
|
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'prison_questionnaire_record'
|
||||||
|
AND COLUMN_NAME = 'subjective_score') THEN
|
||||||
|
ALTER TABLE `prison_questionnaire_record`
|
||||||
|
ADD COLUMN `subjective_score` decimal(10,2) DEFAULT 0.00 COMMENT '主观题得分';
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- 添加总分字段
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM information_schema.COLUMNS
|
||||||
|
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'prison_questionnaire_record'
|
||||||
|
AND COLUMN_NAME = 'total_score') THEN
|
||||||
|
ALTER TABLE `prison_questionnaire_record`
|
||||||
|
ADD COLUMN `total_score` decimal(10,2) DEFAULT NULL COMMENT '总分';
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- 添加及格分数字段
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM information_schema.COLUMNS
|
||||||
|
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'prison_questionnaire_record'
|
||||||
|
AND COLUMN_NAME = 'pass_score') THEN
|
||||||
|
ALTER TABLE `prison_questionnaire_record`
|
||||||
|
ADD COLUMN `pass_score` decimal(10,2) DEFAULT NULL COMMENT '及格分数';
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- 添加及格状态字段
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM information_schema.COLUMNS
|
||||||
|
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'prison_questionnaire_record'
|
||||||
|
AND COLUMN_NAME = 'pass_status') THEN
|
||||||
|
ALTER TABLE `prison_questionnaire_record`
|
||||||
|
ADD COLUMN `pass_status` tinyint DEFAULT NULL COMMENT '及格状态:1-及格 2-不及格 3-待评阅';
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- 添加风险等级字段
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM information_schema.COLUMNS
|
||||||
|
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'prison_questionnaire_record'
|
||||||
|
AND COLUMN_NAME = 'risk_level') THEN
|
||||||
|
ALTER TABLE `prison_questionnaire_record`
|
||||||
|
ADD COLUMN `risk_level` tinyint DEFAULT NULL COMMENT '风险等级:1-高风险 2-中风险 3-低风险';
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- 添加评阅人ID字段
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM information_schema.COLUMNS
|
||||||
|
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'prison_questionnaire_record'
|
||||||
|
AND COLUMN_NAME = 'evaluator_id') THEN
|
||||||
|
ALTER TABLE `prison_questionnaire_record`
|
||||||
|
ADD COLUMN `evaluator_id` bigint DEFAULT NULL COMMENT '评阅人ID';
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- 添加评阅人姓名字段
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM information_schema.COLUMNS
|
||||||
|
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'prison_questionnaire_record'
|
||||||
|
AND COLUMN_NAME = 'evaluator_name') THEN
|
||||||
|
ALTER TABLE `prison_questionnaire_record`
|
||||||
|
ADD COLUMN `evaluator_name` varchar(100) DEFAULT NULL COMMENT '评阅人姓名';
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- 添加评阅时间字段
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM information_schema.COLUMNS
|
||||||
|
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'prison_questionnaire_record'
|
||||||
|
AND COLUMN_NAME = 'evaluate_time') THEN
|
||||||
|
ALTER TABLE `prison_questionnaire_record`
|
||||||
|
ADD COLUMN `evaluate_time` datetime DEFAULT NULL COMMENT '评阅时间';
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- 添加参与人数字段
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM information_schema.COLUMNS
|
||||||
|
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'prison_questionnaire_record'
|
||||||
|
AND COLUMN_NAME = 'participant_count') THEN
|
||||||
|
ALTER TABLE `prison_questionnaire_record`
|
||||||
|
ADD COLUMN `participant_count` int DEFAULT 0 COMMENT '参与人数';
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- 添加完成人数字段
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM information_schema.COLUMNS
|
||||||
|
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'prison_questionnaire_record'
|
||||||
|
AND COLUMN_NAME = 'completed_count') THEN
|
||||||
|
ALTER TABLE `prison_questionnaire_record`
|
||||||
|
ADD COLUMN `completed_count` int DEFAULT 0 COMMENT '完成人数';
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- 添加答题用时字段
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM information_schema.COLUMNS
|
||||||
|
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'prison_questionnaire_record'
|
||||||
|
AND COLUMN_NAME = 'duration') THEN
|
||||||
|
ALTER TABLE `prison_questionnaire_record`
|
||||||
|
ADD COLUMN `duration` int DEFAULT NULL COMMENT '答题用时(秒)';
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- 添加备注字段
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM information_schema.COLUMNS
|
||||||
|
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'prison_questionnaire_record'
|
||||||
|
AND COLUMN_NAME = 'remark') THEN
|
||||||
|
ALTER TABLE `prison_questionnaire_record`
|
||||||
|
ADD COLUMN `remark` varchar(500) DEFAULT NULL COMMENT '备注';
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- =====================================================
|
||||||
|
-- 2. 创建答卷详情表 (prison_questionnaire_answer)
|
||||||
|
-- 用于记录每道题的答题详情
|
||||||
|
-- =====================================================
|
||||||
|
CREATE TABLE IF NOT EXISTS `prison_questionnaire_answer` (
|
||||||
|
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '答案ID',
|
||||||
|
`record_id` bigint NOT NULL COMMENT '测评记录ID',
|
||||||
|
`question_id` bigint NOT NULL COMMENT '题目ID',
|
||||||
|
`question_type` tinyint NOT NULL COMMENT '题目类型:1-单选 2-多选 3-判断 4-填空 5-简述',
|
||||||
|
`question_content` varchar(500) NOT NULL COMMENT '题目内容',
|
||||||
|
`answer_content` text COMMENT '答案内容',
|
||||||
|
`score` decimal(10,2) DEFAULT 0.00 COMMENT '得分',
|
||||||
|
`is_correct` bit(1) DEFAULT NULL COMMENT '是否正确',
|
||||||
|
`is_manual_score` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否需要人工评分',
|
||||||
|
`manual_score` decimal(10,2) DEFAULT NULL COMMENT '人工评分分数',
|
||||||
|
`manual_comment` varchar(500) DEFAULT NULL COMMENT '人工评语',
|
||||||
|
`creator` varchar(64) DEFAULT '' COMMENT '创建者',
|
||||||
|
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||||
|
`updater` varchar(64) DEFAULT '' COMMENT '更新者',
|
||||||
|
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||||
|
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
|
||||||
|
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `idx_questionnaire_answer_record_id` (`record_id`),
|
||||||
|
KEY `idx_questionnaire_answer_question_id` (`question_id`)
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='问卷答题详情表';
|
||||||
|
|
||||||
|
-- =====================================================
|
||||||
|
-- 3. 创建测评统计表 (prison_questionnaire_statistics)
|
||||||
|
-- 用于统计测评的整体情况
|
||||||
|
-- =====================================================
|
||||||
|
CREATE TABLE IF NOT EXISTS `prison_questionnaire_statistics` (
|
||||||
|
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '统计ID',
|
||||||
|
`questionnaire_id` bigint NOT NULL COMMENT '问卷ID',
|
||||||
|
`questionnaire_name` varchar(200) NOT NULL COMMENT '问卷名称',
|
||||||
|
`stat_date` date NOT NULL COMMENT '统计日期',
|
||||||
|
`total_count` int NOT NULL DEFAULT 0 COMMENT '发起总数',
|
||||||
|
`completed_count` int NOT NULL DEFAULT 0 COMMENT '完成数量',
|
||||||
|
`completion_rate` decimal(5,2) DEFAULT 0.00 COMMENT '完成率',
|
||||||
|
`average_score` decimal(10,2) DEFAULT 0.00 COMMENT '平均分',
|
||||||
|
`pass_rate` decimal(5,2) DEFAULT 0.00 COMMENT '及格率',
|
||||||
|
`high_risk_count` int NOT NULL DEFAULT 0 COMMENT '高风险人数',
|
||||||
|
`medium_risk_count` int NOT NULL DEFAULT 0 COMMENT '中风险人数',
|
||||||
|
`low_risk_count` int NOT NULL DEFAULT 0 COMMENT '低风险人数',
|
||||||
|
`creator` varchar(64) DEFAULT '' COMMENT '创建者',
|
||||||
|
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||||
|
`updater` varchar(64) DEFAULT '' COMMENT '更新者',
|
||||||
|
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||||
|
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
|
||||||
|
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `idx_questionnaire_statistics_questionnaire_id` (`questionnaire_id`),
|
||||||
|
KEY `idx_questionnaire_statistics_stat_date` (`stat_date`),
|
||||||
|
UNIQUE KEY `uk_questionnaire_date` (`questionnaire_id`, `stat_date`)
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='问卷测评统计表';
|
||||||
|
|
||||||
|
-- =====================================================
|
||||||
|
-- 4. 更新菜单权限
|
||||||
|
-- =====================================================
|
||||||
|
-- 获取问卷记录父菜单ID
|
||||||
|
-- SELECT @parentId := id FROM system_menu WHERE name = '问卷记录管理' LIMIT 1;
|
||||||
|
|
||||||
|
-- 添加测评相关权限
|
||||||
|
INSERT INTO system_menu (name, permission, type, sort, parent_id, path, icon, component, status)
|
||||||
|
SELECT '发起测评', 'prison:questionnaire-record:initiate', 3, 6, parent_id, '', '', '', 0
|
||||||
|
FROM (SELECT id as parent_id FROM system_menu WHERE name = '问卷记录管理' LIMIT 1) t
|
||||||
|
WHERE NOT EXISTS (SELECT 1 FROM system_menu WHERE name = '发起测评' AND parent_id = (SELECT id FROM system_menu WHERE name = '问卷记录管理' LIMIT 1));
|
||||||
|
|
||||||
|
INSERT INTO system_menu (name, permission, type, sort, parent_id, path, icon, component, status)
|
||||||
|
SELECT '开始测评', 'prison:questionnaire-record:start', 3, 7, parent_id, '', '', '', 0
|
||||||
|
FROM (SELECT id as parent_id FROM system_menu WHERE name = '问卷记录管理' LIMIT 1) t
|
||||||
|
WHERE NOT EXISTS (SELECT 1 FROM system_menu WHERE name = '开始测评' AND parent_id = (SELECT id FROM system_menu WHERE name = '问卷记录管理' LIMIT 1));
|
||||||
|
|
||||||
|
INSERT INTO system_menu (name, permission, type, sort, parent_id, path, icon, component, status)
|
||||||
|
SELECT '提交答卷', 'prison:questionnaire-record:submit', 3, 8, parent_id, '', '', '', 0
|
||||||
|
FROM (SELECT id as parent_id FROM system_menu WHERE name = '问卷记录管理' LIMIT 1) t
|
||||||
|
WHERE NOT EXISTS (SELECT 1 FROM system_menu WHERE name = '提交答卷' AND parent_id = (SELECT id FROM system_menu WHERE name = '问卷记录管理' LIMIT 1));
|
||||||
|
|
||||||
|
INSERT INTO system_menu (name, permission, type, sort, parent_id, path, icon, component, status)
|
||||||
|
SELECT '结束测评', 'prison:questionnaire-record:finish', 3, 9, parent_id, '', '', '', 0
|
||||||
|
FROM (SELECT id as parent_id FROM system_menu WHERE name = '问卷记录管理' LIMIT 1) t
|
||||||
|
WHERE NOT EXISTS (SELECT 1 FROM system_menu WHERE name = '结束测评' AND parent_id = (SELECT id FROM system_menu WHERE name = '问卷记录管理' LIMIT 1));
|
||||||
|
|
||||||
|
INSERT INTO system_menu (name, permission, type, sort, parent_id, path, icon, component, status)
|
||||||
|
SELECT '取消测评', 'prison:questionnaire-record:cancel', 3, 10, parent_id, '', '', '', 0
|
||||||
|
FROM (SELECT id as parent_id FROM system_menu WHERE name = '问卷记录管理' LIMIT 1) t
|
||||||
|
WHERE NOT EXISTS (SELECT 1 FROM system_menu WHERE name = '取消测评' AND parent_id = (SELECT id FROM system_menu WHERE name = '问卷记录管理' LIMIT 1));
|
||||||
|
|
||||||
|
INSERT INTO system_menu (name, permission, type, sort, parent_id, path, icon, component, status)
|
||||||
|
SELECT '人工评分', 'prison:questionnaire-record:score', 3, 11, parent_id, '', '', '', 0
|
||||||
|
FROM (SELECT id as parent_id FROM system_menu WHERE name = '问卷记录管理' LIMIT 1) t
|
||||||
|
WHERE NOT EXISTS (SELECT 1 FROM system_menu WHERE name = '人工评分' AND parent_id = (SELECT id FROM system_menu WHERE name = '问卷记录管理' LIMIT 1));
|
||||||
|
|
||||||
|
SELECT '数据库迁移脚本执行完成!';
|
||||||
@ -0,0 +1,171 @@
|
|||||||
|
-- =====================================================
|
||||||
|
-- XL监狱综合管理平台 - 测评执行模块数据库迁移脚本
|
||||||
|
-- 简化版(直接执行,无需 IF 判断)
|
||||||
|
-- =====================================================
|
||||||
|
|
||||||
|
-- =====================================================
|
||||||
|
-- 1. 更新 prison_questionnaire_record 表结构
|
||||||
|
-- 添加测评执行所需字段
|
||||||
|
-- =====================================================
|
||||||
|
|
||||||
|
-- 添加问卷名称字段
|
||||||
|
ALTER TABLE `prison_questionnaire_record`
|
||||||
|
ADD COLUMN `questionnaire_name` varchar(200) DEFAULT NULL COMMENT '问卷名称' AFTER `questionnaire_id`;
|
||||||
|
|
||||||
|
-- 添加罪犯姓名字段
|
||||||
|
ALTER TABLE `prison_questionnaire_record`
|
||||||
|
ADD COLUMN `prisoner_name` varchar(100) DEFAULT NULL COMMENT '罪犯姓名' AFTER `prisoner_no`;
|
||||||
|
|
||||||
|
-- 添加开始时间字段
|
||||||
|
ALTER TABLE `prison_questionnaire_record`
|
||||||
|
ADD COLUMN `start_time` datetime DEFAULT NULL COMMENT '开始时间';
|
||||||
|
|
||||||
|
-- 添加结束时间字段
|
||||||
|
ALTER TABLE `prison_questionnaire_record`
|
||||||
|
ADD COLUMN `end_time` datetime DEFAULT NULL COMMENT '结束时间';
|
||||||
|
|
||||||
|
-- 添加截止日期字段
|
||||||
|
ALTER TABLE `prison_questionnaire_record`
|
||||||
|
ADD COLUMN `deadline` datetime DEFAULT NULL COMMENT '截止日期';
|
||||||
|
|
||||||
|
-- 添加客观题得分字段
|
||||||
|
ALTER TABLE `prison_questionnaire_record`
|
||||||
|
ADD COLUMN `objective_score` decimal(10,2) DEFAULT 0.00 COMMENT '客观题得分';
|
||||||
|
|
||||||
|
-- 添加主观题得分字段
|
||||||
|
ALTER TABLE `prison_questionnaire_record`
|
||||||
|
ADD COLUMN `subjective_score` decimal(10,2) DEFAULT 0.00 COMMENT '主观题得分';
|
||||||
|
|
||||||
|
-- 添加总分字段
|
||||||
|
ALTER TABLE `prison_questionnaire_record`
|
||||||
|
ADD COLUMN `total_score` decimal(10,2) DEFAULT NULL COMMENT '总分';
|
||||||
|
|
||||||
|
-- 添加及格分数字段
|
||||||
|
ALTER TABLE `prison_questionnaire_record`
|
||||||
|
ADD COLUMN `pass_score` decimal(10,2) DEFAULT NULL COMMENT '及格分数';
|
||||||
|
|
||||||
|
-- 添加及格状态字段
|
||||||
|
ALTER TABLE `prison_questionnaire_record`
|
||||||
|
ADD COLUMN `pass_status` tinyint DEFAULT NULL COMMENT '及格状态:1-及格 2-不及格 3-待评阅';
|
||||||
|
|
||||||
|
-- 添加风险等级字段
|
||||||
|
ALTER TABLE `prison_questionnaire_record`
|
||||||
|
ADD COLUMN `risk_level` tinyint DEFAULT NULL COMMENT '风险等级:1-高风险 2-中风险 3-低风险';
|
||||||
|
|
||||||
|
-- 添加评阅人ID字段
|
||||||
|
ALTER TABLE `prison_questionnaire_record`
|
||||||
|
ADD COLUMN `evaluator_id` bigint DEFAULT NULL COMMENT '评阅人ID';
|
||||||
|
|
||||||
|
-- 添加评阅人姓名字段
|
||||||
|
ALTER TABLE `prison_questionnaire_record`
|
||||||
|
ADD COLUMN `evaluator_name` varchar(100) DEFAULT NULL COMMENT '评阅人姓名';
|
||||||
|
|
||||||
|
-- 添加评阅时间字段
|
||||||
|
ALTER TABLE `prison_questionnaire_record`
|
||||||
|
ADD COLUMN `evaluate_time` datetime DEFAULT NULL COMMENT '评阅时间';
|
||||||
|
|
||||||
|
-- 添加参与人数字段
|
||||||
|
ALTER TABLE `prison_questionnaire_record`
|
||||||
|
ADD COLUMN `participant_count` int DEFAULT 0 COMMENT '参与人数';
|
||||||
|
|
||||||
|
-- 添加完成人数字段
|
||||||
|
ALTER TABLE `prison_questionnaire_record`
|
||||||
|
ADD COLUMN `completed_count` int DEFAULT 0 COMMENT '完成人数';
|
||||||
|
|
||||||
|
-- 添加答题用时字段
|
||||||
|
ALTER TABLE `prison_questionnaire_record`
|
||||||
|
ADD COLUMN `duration` int DEFAULT NULL COMMENT '答题用时(秒)';
|
||||||
|
|
||||||
|
-- 添加备注字段
|
||||||
|
ALTER TABLE `prison_questionnaire_record`
|
||||||
|
ADD COLUMN `remark` varchar(500) DEFAULT NULL COMMENT '备注';
|
||||||
|
|
||||||
|
-- =====================================================
|
||||||
|
-- 2. 创建答卷详情表 (prison_questionnaire_answer)
|
||||||
|
-- =====================================================
|
||||||
|
CREATE TABLE `prison_questionnaire_answer` (
|
||||||
|
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '答案ID',
|
||||||
|
`record_id` bigint NOT NULL COMMENT '测评记录ID',
|
||||||
|
`question_id` bigint NOT NULL COMMENT '题目ID',
|
||||||
|
`question_type` tinyint NOT NULL COMMENT '题目类型:1-单选 2-多选 3-判断 4-填空 5-简述',
|
||||||
|
`question_content` varchar(500) NOT NULL COMMENT '题目内容',
|
||||||
|
`answer_content` text COMMENT '答案内容',
|
||||||
|
`score` decimal(10,2) DEFAULT 0.00 COMMENT '得分',
|
||||||
|
`is_correct` bit(1) DEFAULT NULL COMMENT '是否正确',
|
||||||
|
`is_manual_score` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否需要人工评分',
|
||||||
|
`manual_score` decimal(10,2) DEFAULT NULL COMMENT '人工评分分数',
|
||||||
|
`manual_comment` varchar(500) DEFAULT NULL COMMENT '人工评语',
|
||||||
|
`creator` varchar(64) DEFAULT '' COMMENT '创建者',
|
||||||
|
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||||
|
`updater` varchar(64) DEFAULT '' COMMENT '更新者',
|
||||||
|
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||||
|
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
|
||||||
|
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `idx_questionnaire_answer_record_id` (`record_id`),
|
||||||
|
KEY `idx_questionnaire_answer_question_id` (`question_id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='问卷答题详情表';
|
||||||
|
|
||||||
|
-- =====================================================
|
||||||
|
-- 3. 创建测评统计表 (prison_questionnaire_statistics)
|
||||||
|
-- =====================================================
|
||||||
|
CREATE TABLE `prison_questionnaire_statistics` (
|
||||||
|
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '统计ID',
|
||||||
|
`questionnaire_id` bigint NOT NULL COMMENT '问卷ID',
|
||||||
|
`questionnaire_name` varchar(200) NOT NULL COMMENT '问卷名称',
|
||||||
|
`stat_date` date NOT NULL COMMENT '统计日期',
|
||||||
|
`total_count` int NOT NULL DEFAULT 0 COMMENT '发起总数',
|
||||||
|
`completed_count` int NOT NULL DEFAULT 0 COMMENT '完成数量',
|
||||||
|
`completion_rate` decimal(5,2) DEFAULT 0.00 COMMENT '完成率',
|
||||||
|
`average_score` decimal(10,2) DEFAULT 0.00 COMMENT '平均分',
|
||||||
|
`pass_rate` decimal(5,2) DEFAULT 0.00 COMMENT '及格率',
|
||||||
|
`high_risk_count` int NOT NULL DEFAULT 0 COMMENT '高风险人数',
|
||||||
|
`medium_risk_count` int NOT NULL DEFAULT 0 COMMENT '中风险人数',
|
||||||
|
`low_risk_count` int NOT NULL DEFAULT 0 COMMENT '低风险人数',
|
||||||
|
`creator` varchar(64) DEFAULT '' COMMENT '创建者',
|
||||||
|
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||||
|
`updater` varchar(64) DEFAULT '' COMMENT '更新者',
|
||||||
|
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||||
|
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
|
||||||
|
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `idx_questionnaire_statistics_questionnaire_id` (`questionnaire_id`),
|
||||||
|
KEY `idx_questionnaire_statistics_stat_date` (`stat_date`),
|
||||||
|
UNIQUE KEY `uk_questionnaire_date` (`questionnaire_id`, `stat_date`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='问卷测评统计表';
|
||||||
|
|
||||||
|
-- =====================================================
|
||||||
|
-- 4. 添加菜单权限
|
||||||
|
-- =====================================================
|
||||||
|
|
||||||
|
-- 发起测评
|
||||||
|
INSERT INTO system_menu (name, permission, type, sort, parent_id, path, icon, component, status)
|
||||||
|
SELECT '发起测评', 'prison:questionnaire-record:initiate', 3, 6, id, '', '', '', 0
|
||||||
|
FROM system_menu WHERE name = '问卷记录管理' LIMIT 1;
|
||||||
|
|
||||||
|
-- 开始测评
|
||||||
|
INSERT INTO system_menu (name, permission, type, sort, parent_id, path, icon, component, status)
|
||||||
|
SELECT '开始测评', 'prison:questionnaire-record:start', 3, 7, id, '', '', '', 0
|
||||||
|
FROM system_menu WHERE name = '问卷记录管理' LIMIT 1;
|
||||||
|
|
||||||
|
-- 提交答卷
|
||||||
|
INSERT INTO system_menu (name, permission, type, sort, parent_id, path, icon, component, status)
|
||||||
|
SELECT '提交答卷', 'prison:questionnaire-record:submit', 3, 8, id, '', '', '', 0
|
||||||
|
FROM system_menu WHERE name = '问卷记录管理' LIMIT 1;
|
||||||
|
|
||||||
|
-- 结束测评
|
||||||
|
INSERT INTO system_menu (name, permission, type, sort, parent_id, path, icon, component, status)
|
||||||
|
SELECT '结束测评', 'prison:questionnaire-record:finish', 3, 9, id, '', '', '', 0
|
||||||
|
FROM system_menu WHERE name = '问卷记录管理' LIMIT 1;
|
||||||
|
|
||||||
|
-- 取消测评
|
||||||
|
INSERT INTO system_menu (name, permission, type, sort, parent_id, path, icon, component, status)
|
||||||
|
SELECT '取消测评', 'prison:questionnaire-record:cancel', 3, 10, id, '', '', '', 0
|
||||||
|
FROM system_menu WHERE name = '问卷记录管理' LIMIT 1;
|
||||||
|
|
||||||
|
-- 人工评分
|
||||||
|
INSERT INTO system_menu (name, permission, type, sort, parent_id, path, icon, component, status)
|
||||||
|
SELECT '人工评分', 'prison:questionnaire-record:score', 3, 11, id, '', '', '', 0
|
||||||
|
FROM system_menu WHERE name = '问卷记录管理' LIMIT 1;
|
||||||
|
|
||||||
|
SELECT '数据库迁移完成!';
|
||||||
@ -0,0 +1,71 @@
|
|||||||
|
-- =====================================================
|
||||||
|
-- 消费模块重构:主从表设计迁移脚本
|
||||||
|
-- 执行时间:2026-01-15
|
||||||
|
-- 数据库:xlcp_dev
|
||||||
|
-- =====================================================
|
||||||
|
|
||||||
|
-- 注意:执行前请备份数据库!
|
||||||
|
|
||||||
|
-- =====================================================
|
||||||
|
-- 1. 修改消费订单表结构(prison_consumption)
|
||||||
|
-- =====================================================
|
||||||
|
|
||||||
|
-- 1.1 添加 order_no 字段
|
||||||
|
-- 如果报错"Duplicate column",说明字段已存在,可以跳过
|
||||||
|
ALTER TABLE `prison_consumption`
|
||||||
|
ADD COLUMN `order_no` varchar(64) DEFAULT NULL COMMENT '订单号' AFTER `prisoner_no`;
|
||||||
|
|
||||||
|
-- 1.2 修改 type 字段注释
|
||||||
|
ALTER TABLE `prison_consumption`
|
||||||
|
MODIFY COLUMN `type` tinyint NOT NULL DEFAULT 1 COMMENT '类型:1-购物 2-餐饮 3-医疗 4-通讯 5-其他';
|
||||||
|
|
||||||
|
-- 1.3 重命名 amount 为 total_amount
|
||||||
|
-- 如果报错"Unknown column",说明字段已被修改,可以跳过
|
||||||
|
ALTER TABLE `prison_consumption`
|
||||||
|
CHANGE COLUMN `amount` `total_amount` decimal(10,2) NOT NULL COMMENT '订单总金额';
|
||||||
|
|
||||||
|
-- 1.4 删除商品相关字段
|
||||||
|
-- 如果报错"Unknown column",说明字段已被删除,可以跳过
|
||||||
|
ALTER TABLE `prison_consumption`
|
||||||
|
DROP COLUMN `goods_name`;
|
||||||
|
|
||||||
|
ALTER TABLE `prison_consumption`
|
||||||
|
DROP COLUMN `goods_count`;
|
||||||
|
|
||||||
|
-- 1.5 添加索引
|
||||||
|
ALTER TABLE `prison_consumption`
|
||||||
|
ADD INDEX `idx_prison_consumption_order_no` (`order_no`);
|
||||||
|
|
||||||
|
|
||||||
|
-- =====================================================
|
||||||
|
-- 2. 创建消费明细表(prison_consumption_detail)
|
||||||
|
-- =====================================================
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `prison_consumption_detail` (
|
||||||
|
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '明细ID',
|
||||||
|
`consumption_id` bigint NOT NULL COMMENT '消费订单ID',
|
||||||
|
`prisoner_id` bigint NOT NULL COMMENT '罪犯ID(冗余,便于查询)',
|
||||||
|
`goods_name` varchar(100) NOT NULL COMMENT '商品名称',
|
||||||
|
`goods_code` varchar(50) DEFAULT NULL COMMENT '商品编码',
|
||||||
|
`goods_price` decimal(10,2) NOT NULL COMMENT '商品单价',
|
||||||
|
`goods_count` int NOT NULL COMMENT '商品数量',
|
||||||
|
`subtotal` decimal(10,2) NOT NULL COMMENT '小计金额',
|
||||||
|
`creator` varchar(64) DEFAULT '' COMMENT '创建者',
|
||||||
|
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||||
|
`deleted` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否删除',
|
||||||
|
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `idx_consumption_detail_consumption_id` (`consumption_id`),
|
||||||
|
KEY `idx_consumption_detail_prisoner_id` (`prisoner_id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='消费明细表';
|
||||||
|
|
||||||
|
|
||||||
|
-- =====================================================
|
||||||
|
-- 3. 验证结果
|
||||||
|
-- =====================================================
|
||||||
|
|
||||||
|
-- 查看表结构
|
||||||
|
DESCRIBE prison_consumption;
|
||||||
|
DESCRIBE prison_consumption_detail;
|
||||||
|
|
||||||
|
SELECT '消费模块表结构修改完成!' AS status;
|
||||||
@ -55,18 +55,16 @@ CREATE TABLE IF NOT EXISTS `prison_cell` (
|
|||||||
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='监室信息表';
|
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='监室信息表';
|
||||||
|
|
||||||
-- =====================================================
|
-- =====================================================
|
||||||
-- 3. 消费记录表 (prison_consumption)
|
-- 3. 消费订单表 (prison_consumption)
|
||||||
-- =====================================================
|
-- =====================================================
|
||||||
CREATE TABLE IF NOT EXISTS `prison_consumption` (
|
CREATE TABLE IF NOT EXISTS `prison_consumption` (
|
||||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '记录ID',
|
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '消费ID',
|
||||||
`prisoner_id` bigint NOT NULL COMMENT '罪犯ID',
|
`prisoner_id` bigint NOT NULL COMMENT '罪犯ID',
|
||||||
`prisoner_no` varchar(50) NOT NULL COMMENT '罪犯编号',
|
`prisoner_no` varchar(50) NOT NULL COMMENT '罪犯编号',
|
||||||
`type` tinyint NOT NULL DEFAULT 1 COMMENT '类型:1-存款 2-消费 3-转账',
|
|
||||||
`amount` decimal(10,2) NOT NULL COMMENT '金额',
|
|
||||||
`balance` decimal(10,2) NOT NULL COMMENT '账户余额',
|
|
||||||
`goods_name` varchar(200) DEFAULT NULL COMMENT '商品名称',
|
|
||||||
`goods_count` int DEFAULT 0 COMMENT '商品数量',
|
|
||||||
`order_no` varchar(64) DEFAULT NULL COMMENT '订单号',
|
`order_no` varchar(64) DEFAULT NULL COMMENT '订单号',
|
||||||
|
`type` tinyint NOT NULL DEFAULT 1 COMMENT '类型:1-购物 2-餐饮 3-医疗 4-通讯 5-其他',
|
||||||
|
`total_amount` decimal(10,2) NOT NULL COMMENT '订单总金额',
|
||||||
|
`balance` decimal(10,2) NOT NULL COMMENT '账户余额(消费后)',
|
||||||
`trade_time` datetime NOT NULL COMMENT '交易时间',
|
`trade_time` datetime NOT NULL COMMENT '交易时间',
|
||||||
`status` tinyint NOT NULL DEFAULT 1 COMMENT '状态:1-成功 2-失败',
|
`status` tinyint NOT NULL DEFAULT 1 COMMENT '状态:1-成功 2-失败',
|
||||||
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
|
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
|
||||||
@ -79,8 +77,30 @@ CREATE TABLE IF NOT EXISTS `prison_consumption` (
|
|||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
KEY `idx_prison_consumption_prisoner_id` (`prisoner_id`),
|
KEY `idx_prison_consumption_prisoner_id` (`prisoner_id`),
|
||||||
KEY `idx_prison_consumption_prisoner_no` (`prisoner_no`),
|
KEY `idx_prison_consumption_prisoner_no` (`prisoner_no`),
|
||||||
|
KEY `idx_prison_consumption_order_no` (`order_no`),
|
||||||
KEY `idx_prison_consumption_trade_time` (`trade_time`)
|
KEY `idx_prison_consumption_trade_time` (`trade_time`)
|
||||||
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='消费记录表';
|
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='消费订单表';
|
||||||
|
|
||||||
|
-- =====================================================
|
||||||
|
-- 3.1 消费明细表 (prison_consumption_detail)
|
||||||
|
-- =====================================================
|
||||||
|
CREATE TABLE IF NOT EXISTS `prison_consumption_detail` (
|
||||||
|
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '明细ID',
|
||||||
|
`consumption_id` bigint NOT NULL COMMENT '消费订单ID',
|
||||||
|
`prisoner_id` bigint NOT NULL COMMENT '罪犯ID(冗余,便于查询)',
|
||||||
|
`goods_name` varchar(100) NOT NULL COMMENT '商品名称',
|
||||||
|
`goods_code` varchar(50) DEFAULT NULL COMMENT '商品编码',
|
||||||
|
`goods_price` decimal(10,2) NOT NULL COMMENT '商品单价',
|
||||||
|
`goods_count` int NOT NULL COMMENT '商品数量',
|
||||||
|
`subtotal` decimal(10,2) NOT NULL COMMENT '小计金额',
|
||||||
|
`creator` varchar(64) DEFAULT '' COMMENT '创建者',
|
||||||
|
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||||
|
`deleted` bit(1) NOT NULL DEFAULT b'0 COMMENT '是否删除',
|
||||||
|
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `idx_consumption_detail_consumption_id` (`consumption_id`),
|
||||||
|
KEY `idx_consumption_detail_prisoner_id` (`prisoner_id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='消费明细表';
|
||||||
|
|
||||||
-- =====================================================
|
-- =====================================================
|
||||||
-- 4. 问卷模板表 (prison_questionnaire)
|
-- 4. 问卷模板表 (prison_questionnaire)
|
||||||
|
|||||||
@ -0,0 +1,70 @@
|
|||||||
|
-- =====================================================
|
||||||
|
-- XL监狱综合管理平台 - LLM调用日志表
|
||||||
|
-- 生成时间: 2026-01-15
|
||||||
|
-- =====================================================
|
||||||
|
|
||||||
|
-- =====================================================
|
||||||
|
-- LLM调用日志表 (prison_risk_assessment_llm_log)
|
||||||
|
-- =====================================================
|
||||||
|
CREATE TABLE IF NOT EXISTS `prison_risk_assessment_llm_log` (
|
||||||
|
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '日志ID',
|
||||||
|
`assessment_id` bigint DEFAULT NULL COMMENT '关联的评估记录ID',
|
||||||
|
`prisoner_id` bigint NOT NULL COMMENT '罪犯ID',
|
||||||
|
`prisoner_no` varchar(50) NOT NULL COMMENT '罪犯编号',
|
||||||
|
`model` varchar(100) NOT NULL COMMENT '使用的模型',
|
||||||
|
`prompt` text NOT NULL COMMENT '发送的提示词(脱敏后)',
|
||||||
|
`response` text NOT NULL COMMENT '模型响应原始内容',
|
||||||
|
`risk_level` tinyint DEFAULT NULL COMMENT '评估风险等级',
|
||||||
|
`confidence` decimal(4,2) DEFAULT NULL COMMENT '置信度',
|
||||||
|
`evaluation_time_ms` int DEFAULT NULL COMMENT '评估耗时(毫秒)',
|
||||||
|
`status` tinyint NOT NULL DEFAULT 1 COMMENT '状态:1-成功 2-失败 3-降级',
|
||||||
|
`error_message` text DEFAULT NULL COMMENT '错误信息',
|
||||||
|
`requires_human_review` bit(1) DEFAULT b'0 COMMENT '是否需要人工复核',
|
||||||
|
`assessor_id` bigint DEFAULT NULL COMMENT '评估人ID',
|
||||||
|
`assessor_name` varchar(100) DEFAULT NULL COMMENT '评估人姓名',
|
||||||
|
`creator` varchar(64) DEFAULT '' COMMENT '创建者',
|
||||||
|
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||||
|
`updater` varchar(64) DEFAULT '' COMMENT '更新者',
|
||||||
|
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||||
|
`deleted` bit(1) NOT NULL DEFAULT b'0 COMMENT '是否删除',
|
||||||
|
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `idx_llm_log_prisoner_id` (`prisoner_id`),
|
||||||
|
KEY `idx_llm_log_assessment_id` (`assessment_id`),
|
||||||
|
KEY `idx_llm_log_create_time` (`create_time`),
|
||||||
|
KEY `idx_llm_log_status` (`status`)
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='LLM危险评估调用日志表';
|
||||||
|
|
||||||
|
-- =====================================================
|
||||||
|
-- 菜单权限配置
|
||||||
|
-- =====================================================
|
||||||
|
|
||||||
|
-- 危险评估模块菜单(已有)
|
||||||
|
|
||||||
|
-- LLM评估功能权限
|
||||||
|
-- 提示:以下权限需要在前端菜单配置中手动添加
|
||||||
|
-- 路径:系统管理 -> 菜单管理 -> 监狱管理 -> 危险评估
|
||||||
|
-- 添加子菜单:LLM智能评估
|
||||||
|
-- 权限标识:prison:risk-assessment:llm-assess
|
||||||
|
|
||||||
|
-- SQL示例:添加权限(如果使用代码生成器则自动生成)
|
||||||
|
-- INSERT INTO system_permission (name, permission, type, sort, path, icon, component)
|
||||||
|
-- VALUES ('LLM智能评估', 'prison:risk-assessment:llm-assess', 2, 10, 'llm-assess', 'icon', 'prison/riskassessment/llm-assess');
|
||||||
|
|
||||||
|
-- INSERT INTO system_menu_permission (menu_id, permission_id)
|
||||||
|
-- SELECT m.id, p.id FROM system_menu m, system_permission p
|
||||||
|
-- WHERE m.path = 'riskassessment' AND p.permission = 'prison:risk-assessment:llm-assess';
|
||||||
|
|
||||||
|
-- =====================================================
|
||||||
|
-- 配置项说明
|
||||||
|
-- =====================================================
|
||||||
|
-- 在 application.yaml 或环境配置文件中添加LLM配置:
|
||||||
|
--
|
||||||
|
-- # Claude API配置
|
||||||
|
-- llm:
|
||||||
|
-- claude:
|
||||||
|
-- api-key: your-api-key-here
|
||||||
|
-- timeout-seconds: 30
|
||||||
|
--
|
||||||
|
-- 或使用环境变量:
|
||||||
|
-- LLM_CLAUDE_API_KEY=your-api-key-here
|
||||||
@ -0,0 +1,230 @@
|
|||||||
|
package cn.iocoder.yudao.module.prison.controller.admin.consumption;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
|
import cn.iocoder.yudao.module.prison.controller.admin.consumption.vo.*;
|
||||||
|
import cn.iocoder.yudao.module.prison.dal.dataobject.consumption.ConsumptionDO;
|
||||||
|
import cn.iocoder.yudao.module.prison.dal.dataobject.consumption.ConsumptionDetailDO;
|
||||||
|
import cn.iocoder.yudao.module.prison.service.consumption.ConsumptionService;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
||||||
|
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.security.test.context.support.WithMockUser;
|
||||||
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消费订单 Controller 测试类
|
||||||
|
*
|
||||||
|
* @author xl
|
||||||
|
*/
|
||||||
|
@WebMvcTest(PrisonConsumptionController.class)
|
||||||
|
class PrisonConsumptionControllerTest {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private MockMvc mockMvc;
|
||||||
|
|
||||||
|
@MockBean
|
||||||
|
private ConsumptionService consumptionService;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@WithMockUser
|
||||||
|
void testGetConsumptionPage_Success() throws Exception {
|
||||||
|
// 准备测试数据
|
||||||
|
ConsumptionDO consumption = new ConsumptionDO();
|
||||||
|
consumption.setId(1L);
|
||||||
|
consumption.setPrisonerId(100L);
|
||||||
|
consumption.setPrisonerNo("PRISONER001");
|
||||||
|
consumption.setOrderNo("CS1234567890");
|
||||||
|
consumption.setType(1);
|
||||||
|
consumption.setTotalAmount(new BigDecimal("100.00"));
|
||||||
|
consumption.setBalance(new BigDecimal("900.00"));
|
||||||
|
consumption.setTradeTime(LocalDateTime.now());
|
||||||
|
consumption.setStatus(1);
|
||||||
|
|
||||||
|
PageResult<ConsumptionDO> pageResult = new PageResult<>();
|
||||||
|
pageResult.setList(Collections.singletonList(consumption));
|
||||||
|
pageResult.setTotal(1L);
|
||||||
|
|
||||||
|
when(consumptionService.getConsumptionPage(any(ConsumptionPageReqVO.class))).thenReturn(pageResult);
|
||||||
|
|
||||||
|
// 执行测试
|
||||||
|
mockMvc.perform(get("/prison/consumption/page")
|
||||||
|
.param("pageNo", "1")
|
||||||
|
.param("pageSize", "10")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$.data.list[0].id").value(1))
|
||||||
|
.andExpect(jsonPath("$.data.list[0].prisonerNo").value("PRISONER001"))
|
||||||
|
.andExpect(jsonPath("$.data.list[0].type").value(1))
|
||||||
|
.andExpect(jsonPath("$.data.total").value(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@WithMockUser
|
||||||
|
void testGetConsumption_Success() throws Exception {
|
||||||
|
// 准备测试数据
|
||||||
|
ConsumptionDO consumption = new ConsumptionDO();
|
||||||
|
consumption.setId(1L);
|
||||||
|
consumption.setPrisonerId(100L);
|
||||||
|
consumption.setPrisonerNo("PRISONER001");
|
||||||
|
consumption.setOrderNo("CS1234567890");
|
||||||
|
consumption.setType(1);
|
||||||
|
consumption.setTotalAmount(new BigDecimal("100.00"));
|
||||||
|
consumption.setStatus(1);
|
||||||
|
|
||||||
|
ConsumptionDetailDO detail = new ConsumptionDetailDO();
|
||||||
|
detail.setId(1L);
|
||||||
|
detail.setConsumptionId(1L);
|
||||||
|
detail.setGoodsName("商品A");
|
||||||
|
detail.setGoodsPrice(new BigDecimal("50.00"));
|
||||||
|
detail.setGoodsCount(2);
|
||||||
|
|
||||||
|
when(consumptionService.getConsumption(1L)).thenReturn(consumption);
|
||||||
|
when(consumptionService.getConsumptionDetailList(1L)).thenReturn(Collections.singletonList(detail));
|
||||||
|
|
||||||
|
// 执行测试
|
||||||
|
mockMvc.perform(get("/prison/consumption/get")
|
||||||
|
.param("id", "1")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$.data.id").value(1))
|
||||||
|
.andExpect(jsonPath("$.data.prisonerNo").value("PRISONER001"))
|
||||||
|
.andExpect(jsonPath("$.data.details[0].goodsName").value("商品A"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@WithMockUser
|
||||||
|
void testGetConsumption_NotFound() throws Exception {
|
||||||
|
when(consumptionService.getConsumption(999L)).thenReturn(null);
|
||||||
|
|
||||||
|
mockMvc.perform(get("/prison/consumption/get")
|
||||||
|
.param("id", "999")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$.data").isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@WithMockUser
|
||||||
|
void testDeleteConsumption_Success() throws Exception {
|
||||||
|
// 执行测试 - 删除成功
|
||||||
|
mockMvc.perform(delete("/prison/consumption/delete")
|
||||||
|
.param("id", "1")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$.data").value(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@WithMockUser
|
||||||
|
void testDeleteConsumption_ValidationError() throws Exception {
|
||||||
|
// 缺少必需参数 id
|
||||||
|
mockMvc.perform(delete("/prison/consumption/delete")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON))
|
||||||
|
.andExpect(status().isBadRequest());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@WithMockUser
|
||||||
|
void testDeleteConsumptionList_Success() throws Exception {
|
||||||
|
// 执行测试 - 批量删除
|
||||||
|
mockMvc.perform(delete("/prison/consumption/delete-list")
|
||||||
|
.param("ids", "1,2,3")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$.data").value(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@WithMockUser
|
||||||
|
void testDeleteConsumptionList_ValidationError() throws Exception {
|
||||||
|
// 批量删除 ids 为空
|
||||||
|
mockMvc.perform(delete("/prison/consumption/delete-list")
|
||||||
|
.param("ids", "")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON))
|
||||||
|
.andExpect(status().isBadRequest());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@WithMockUser
|
||||||
|
void testGetConsumptionDetailList_Success() throws Exception {
|
||||||
|
ConsumptionDetailDO detail = new ConsumptionDetailDO();
|
||||||
|
detail.setId(1L);
|
||||||
|
detail.setConsumptionId(1L);
|
||||||
|
detail.setGoodsName("商品A");
|
||||||
|
detail.setGoodsPrice(new BigDecimal("25.50"));
|
||||||
|
detail.setGoodsCount(4);
|
||||||
|
|
||||||
|
when(consumptionService.getConsumptionDetailList(1L))
|
||||||
|
.thenReturn(Collections.singletonList(detail));
|
||||||
|
|
||||||
|
mockMvc.perform(get("/prison/consumption/detail-list")
|
||||||
|
.param("consumptionId", "1")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$.data[0].goodsName").value("商品A"))
|
||||||
|
.andExpect(jsonPath("$.data[0].goodsPrice").value(25.5));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@WithMockUser
|
||||||
|
void testExportConsumptionExcel_Success() throws Exception {
|
||||||
|
ConsumptionDO consumption = new ConsumptionDO();
|
||||||
|
consumption.setId(1L);
|
||||||
|
consumption.setPrisonerNo("PRISONER001");
|
||||||
|
consumption.setType(1);
|
||||||
|
consumption.setTotalAmount(new BigDecimal("100.00"));
|
||||||
|
|
||||||
|
PageResult<ConsumptionDO> pageResult = new PageResult<>();
|
||||||
|
pageResult.setList(Collections.singletonList(consumption));
|
||||||
|
pageResult.setTotal(1L);
|
||||||
|
|
||||||
|
when(consumptionService.getConsumptionPage(any(ConsumptionPageReqVO.class))).thenReturn(pageResult);
|
||||||
|
|
||||||
|
mockMvc.perform(get("/prison/consumption/export-excel")
|
||||||
|
.param("pageNo", "1")
|
||||||
|
.param("pageSize", "10")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON))
|
||||||
|
.andExpect(status().isOk());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@WithMockUser
|
||||||
|
void testGetConsumptionPage_WithFilters() throws Exception {
|
||||||
|
// 测试带筛选条件的分页查询
|
||||||
|
ConsumptionDO consumption = new ConsumptionDO();
|
||||||
|
consumption.setId(1L);
|
||||||
|
consumption.setPrisonerId(100L);
|
||||||
|
consumption.setPrisonerNo("PRISONER001");
|
||||||
|
consumption.setType(1);
|
||||||
|
consumption.setStatus(1);
|
||||||
|
|
||||||
|
PageResult<ConsumptionDO> pageResult = new PageResult<>();
|
||||||
|
pageResult.setList(Collections.singletonList(consumption));
|
||||||
|
pageResult.setTotal(1L);
|
||||||
|
|
||||||
|
when(consumptionService.getConsumptionPage(any(ConsumptionPageReqVO.class))).thenReturn(pageResult);
|
||||||
|
|
||||||
|
mockMvc.perform(get("/prison/consumption/page")
|
||||||
|
.param("pageNo", "1")
|
||||||
|
.param("pageSize", "10")
|
||||||
|
.param("prisonerNo", "PRISONER001")
|
||||||
|
.param("type", "1")
|
||||||
|
.param("status", "1")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$.data.total").value(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,283 @@
|
|||||||
|
package cn.iocoder.yudao.module.prison.service.consumption;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.exception.ServiceException;
|
||||||
|
import cn.iocoder.yudao.module.prison.controller.admin.consumption.vo.*;
|
||||||
|
import cn.iocoder.yudao.module.prison.dal.dataobject.consumption.ConsumptionDetailDO;
|
||||||
|
import cn.iocoder.yudao.module.prison.dal.dataobject.consumption.ConsumptionDO;
|
||||||
|
import cn.iocoder.yudao.module.prison.dal.mysql.consumption.ConsumptionDetailMapper;
|
||||||
|
import cn.iocoder.yudao.module.prison.dal.mysql.consumption.ConsumptionMapper;
|
||||||
|
import cn.iocoder.yudao.module.prison.service.consumption.impl.ConsumptionServiceImpl;
|
||||||
|
import cn.iocoder.yudao.module.prison.enums.ErrorCodeConstants;
|
||||||
|
import cn.iocoder.yudao.module.prison.enums.ConsumptionTypeEnum;
|
||||||
|
import cn.iocoder.yudao.module.prison.enums.ConsumptionStatusEnum;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
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.math.BigDecimal;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
|
import static org.mockito.Mockito.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消费订单 Service 测试类
|
||||||
|
*
|
||||||
|
* @author xl
|
||||||
|
*/
|
||||||
|
@ExtendWith(MockitoExtension.class)
|
||||||
|
class ConsumptionServiceTest {
|
||||||
|
|
||||||
|
@InjectMocks
|
||||||
|
private ConsumptionServiceImpl consumptionService;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private ConsumptionMapper consumptionMapper;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private ConsumptionDetailMapper consumptionDetailMapper;
|
||||||
|
|
||||||
|
private ConsumptionSaveReqVO createReqVO;
|
||||||
|
private ConsumptionDO consumptionDO;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void setUp() {
|
||||||
|
// 准备创建请求VO
|
||||||
|
createReqVO = new ConsumptionSaveReqVO();
|
||||||
|
createReqVO.setPrisonerId(100L);
|
||||||
|
createReqVO.setPrisonerNo("PRISONER001");
|
||||||
|
createReqVO.setType(1);
|
||||||
|
createReqVO.setTotalAmount(new BigDecimal("100.00"));
|
||||||
|
createReqVO.setBalance(new BigDecimal("900.00"));
|
||||||
|
createReqVO.setStatus(1);
|
||||||
|
createReqVO.setTradeTime(LocalDateTime.now());
|
||||||
|
|
||||||
|
// 准备明细数据
|
||||||
|
ConsumptionDetailSaveReqVO detail1 = new ConsumptionDetailSaveReqVO();
|
||||||
|
detail1.setGoodsName("商品A");
|
||||||
|
detail1.setGoodsPrice(new BigDecimal("30.00"));
|
||||||
|
detail1.setGoodsCount(2);
|
||||||
|
detail1.setSubtotal(new BigDecimal("60.00"));
|
||||||
|
|
||||||
|
ConsumptionDetailSaveReqVO detail2 = new ConsumptionDetailSaveReqVO();
|
||||||
|
detail2.setGoodsName("商品B");
|
||||||
|
detail2.setGoodsPrice(new BigDecimal("20.00"));
|
||||||
|
detail2.setGoodsCount(2);
|
||||||
|
detail2.setSubtotal(new BigDecimal("40.00"));
|
||||||
|
|
||||||
|
createReqVO.setDetails(Arrays.asList(detail1, detail2));
|
||||||
|
|
||||||
|
// 准备DO对象
|
||||||
|
consumptionDO = new ConsumptionDO();
|
||||||
|
consumptionDO.setId(1L);
|
||||||
|
consumptionDO.setPrisonerId(100L);
|
||||||
|
consumptionDO.setPrisonerNo("PRISONER001");
|
||||||
|
consumptionDO.setOrderNo("CS1234567890");
|
||||||
|
consumptionDO.setType(1);
|
||||||
|
consumptionDO.setTotalAmount(new BigDecimal("100.00"));
|
||||||
|
consumptionDO.setStatus(1);
|
||||||
|
consumptionDO.setCreateTime(LocalDateTime.now());
|
||||||
|
consumptionDO.setUpdateTime(LocalDateTime.now());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testCreateConsumption_Success() {
|
||||||
|
// 设置Mapper行为
|
||||||
|
when(consumptionMapper.insert(any(ConsumptionDO.class))).thenReturn(1);
|
||||||
|
doNothing().when(consumptionDetailMapper).insertBatch(anyList());
|
||||||
|
|
||||||
|
// 执行测试
|
||||||
|
Long result = consumptionService.createConsumption(createReqVO);
|
||||||
|
|
||||||
|
// 验证结果
|
||||||
|
assertNotNull(result);
|
||||||
|
assertEquals(1L, result);
|
||||||
|
verify(consumptionMapper).insert(any(ConsumptionDO.class));
|
||||||
|
verify(consumptionDetailMapper).insertBatch(anyList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testCreateConsumption_DetailEmpty() {
|
||||||
|
// 明细为空
|
||||||
|
createReqVO.setDetails(null);
|
||||||
|
|
||||||
|
// 执行测试并验证异常
|
||||||
|
assertThrows(ServiceException.class, () -> {
|
||||||
|
consumptionService.createConsumption(createReqVO);
|
||||||
|
});
|
||||||
|
|
||||||
|
verify(consumptionMapper, never()).insert(any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testUpdateConsumption_Success() {
|
||||||
|
// 准备更新数据
|
||||||
|
ConsumptionSaveReqVO updateReqVO = new ConsumptionSaveReqVO();
|
||||||
|
updateReqVO.setId(1L);
|
||||||
|
updateReqVO.setPrisonerId(100L);
|
||||||
|
updateReqVO.setType(2);
|
||||||
|
updateReqVO.setTotalAmount(new BigDecimal("150.00"));
|
||||||
|
|
||||||
|
ConsumptionDetailSaveReqVO detail = new ConsumptionDetailSaveReqVO();
|
||||||
|
detail.setGoodsName("商品C");
|
||||||
|
detail.setGoodsPrice(new BigDecimal("75.00"));
|
||||||
|
detail.setGoodsCount(2);
|
||||||
|
detail.setSubtotal(new BigDecimal("150.00"));
|
||||||
|
updateReqVO.setDetails(Collections.singletonList(detail));
|
||||||
|
|
||||||
|
// 设置Mapper行为
|
||||||
|
when(consumptionMapper.selectById(1L)).thenReturn(consumptionDO);
|
||||||
|
when(consumptionMapper.updateById(any(ConsumptionDO.class))).thenReturn(1);
|
||||||
|
doNothing().when(consumptionDetailMapper).deleteByConsumptionId(1L);
|
||||||
|
doNothing().when(consumptionDetailMapper).insertBatch(anyList());
|
||||||
|
|
||||||
|
// 执行测试
|
||||||
|
consumptionService.updateConsumption(updateReqVO);
|
||||||
|
|
||||||
|
// 验证结果
|
||||||
|
verify(consumptionMapper).selectById(1L);
|
||||||
|
verify(consumptionMapper).updateById(any(ConsumptionDO.class));
|
||||||
|
verify(consumptionDetailMapper).deleteByConsumptionId(1L);
|
||||||
|
verify(consumptionDetailMapper).insertBatch(anyList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testUpdateConsumption_NotFound() {
|
||||||
|
ConsumptionSaveReqVO updateReqVO = new ConsumptionSaveReqVO();
|
||||||
|
updateReqVO.setId(999L);
|
||||||
|
|
||||||
|
when(consumptionMapper.selectById(999L)).thenReturn(null);
|
||||||
|
|
||||||
|
assertThrows(ServiceException.class, () -> {
|
||||||
|
consumptionService.updateConsumption(updateReqVO);
|
||||||
|
});
|
||||||
|
|
||||||
|
verify(consumptionMapper, never()).updateById(any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testDeleteConsumption_Success() {
|
||||||
|
when(consumptionMapper.selectById(1L)).thenReturn(consumptionDO);
|
||||||
|
when(consumptionMapper.deleteById(1L)).thenReturn(1);
|
||||||
|
doNothing().when(consumptionDetailMapper).deleteByConsumptionId(1L);
|
||||||
|
|
||||||
|
consumptionService.deleteConsumption(1L);
|
||||||
|
|
||||||
|
verify(consumptionMapper).deleteById(1L);
|
||||||
|
verify(consumptionDetailMapper).deleteByConsumptionId(1L);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testDeleteConsumption_NotFound() {
|
||||||
|
when(consumptionMapper.selectById(999L)).thenReturn(null);
|
||||||
|
|
||||||
|
assertThrows(ServiceException.class, () -> {
|
||||||
|
consumptionService.deleteConsumption(999L);
|
||||||
|
});
|
||||||
|
|
||||||
|
verify(consumptionMapper, never()).deleteById(any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testDeleteConsumptionListByIds_Success() {
|
||||||
|
List<Long> ids = Arrays.asList(1L, 2L, 3L);
|
||||||
|
when(consumptionMapper.deleteBatchIds(ids)).thenReturn(3);
|
||||||
|
doNothing().when(consumptionDetailMapper).deleteByConsumptionIds(ids);
|
||||||
|
|
||||||
|
consumptionService.deleteConsumptionListByIds(ids);
|
||||||
|
|
||||||
|
verify(consumptionMapper).deleteBatchIds(ids);
|
||||||
|
verify(consumptionDetailMapper).deleteByConsumptionIds(ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testGetConsumption_Success() {
|
||||||
|
when(consumptionMapper.selectById(1L)).thenReturn(consumptionDO);
|
||||||
|
|
||||||
|
ConsumptionDO result = consumptionService.getConsumption(1L);
|
||||||
|
|
||||||
|
assertNotNull(result);
|
||||||
|
assertEquals(1L, result.getId());
|
||||||
|
assertEquals("PRISONER001", result.getPrisonerNo());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testGetConsumption_NotFound() {
|
||||||
|
when(consumptionMapper.selectById(999L)).thenReturn(null);
|
||||||
|
|
||||||
|
ConsumptionDO result = consumptionService.getConsumption(999L);
|
||||||
|
|
||||||
|
assertNull(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testGetConsumptionPage_Success() {
|
||||||
|
ConsumptionPageReqVO pageReqVO = new ConsumptionPageReqVO();
|
||||||
|
pageReqVO.setPageNo(1);
|
||||||
|
pageReqVO.setPageSize(10);
|
||||||
|
|
||||||
|
Page<ConsumptionDO> page = new Page<>(1, 10);
|
||||||
|
page.setRecords(Collections.singletonList(consumptionDO));
|
||||||
|
page.setTotal(1);
|
||||||
|
|
||||||
|
when(consumptionMapper.selectPage(any(Page.class), any(LambdaQueryWrapper.class)))
|
||||||
|
.thenReturn(page);
|
||||||
|
|
||||||
|
cn.iocoder.yudao.framework.common.pojo.PageResult<ConsumptionDO> result =
|
||||||
|
consumptionService.getConsumptionPage(pageReqVO);
|
||||||
|
|
||||||
|
assertNotNull(result);
|
||||||
|
assertEquals(1, result.getTotal());
|
||||||
|
assertEquals(1, result.getList().size());
|
||||||
|
assertEquals("PRISONER001", result.getList().get(0).getPrisonerNo());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testGetConsumptionDetailList_Success() {
|
||||||
|
ConsumptionDetailDO detail = new ConsumptionDetailDO();
|
||||||
|
detail.setId(1L);
|
||||||
|
detail.setConsumptionId(1L);
|
||||||
|
detail.setGoodsName("商品A");
|
||||||
|
detail.setGoodsPrice(new BigDecimal("50.00"));
|
||||||
|
detail.setGoodsCount(2);
|
||||||
|
|
||||||
|
when(consumptionDetailMapper.selectListByConsumptionId(1L))
|
||||||
|
.thenReturn(Collections.singletonList(detail));
|
||||||
|
|
||||||
|
List<ConsumptionDetailDO> result = consumptionService.getConsumptionDetailList(1L);
|
||||||
|
|
||||||
|
assertNotNull(result);
|
||||||
|
assertEquals(1, result.size());
|
||||||
|
assertEquals("商品A", result.get(0).getGoodsName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testExportExcel_Success() {
|
||||||
|
ConsumptionPageReqVO pageReqVO = new ConsumptionPageReqVO();
|
||||||
|
pageReqVO.setPageNo(1);
|
||||||
|
pageReqVO.setPageSize(10);
|
||||||
|
|
||||||
|
Page<ConsumptionDO> page = new Page<>(1, 10);
|
||||||
|
page.setRecords(Collections.singletonList(consumptionDO));
|
||||||
|
page.setTotal(1);
|
||||||
|
|
||||||
|
when(consumptionMapper.selectPage(any(Page.class), any(LambdaQueryWrapper.class)))
|
||||||
|
.thenReturn(page);
|
||||||
|
|
||||||
|
cn.iocoder.yudao.framework.common.pojo.PageResult<ConsumptionDO> result =
|
||||||
|
consumptionService.getConsumptionPage(pageReqVO);
|
||||||
|
|
||||||
|
assertNotNull(result);
|
||||||
|
assertEquals(1, result.getTotal());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -274,4 +274,25 @@ justauth:
|
|||||||
cache:
|
cache:
|
||||||
type: REDIS
|
type: REDIS
|
||||||
prefix: 'social_auth_state:' # 缓存前缀,目前只对 Redis 缓存生效,默认 JUSTAUTH::STATE::
|
prefix: 'social_auth_state:' # 缓存前缀,目前只对 Redis 缓存生效,默认 JUSTAUTH::STATE::
|
||||||
timeout: 24h # 超时时长,目前只对 Redis 缓存生效,默认 3 分钟
|
timeout: 24h # 超时时长,目前只对 Redis 缓存生效,默认 3 分钟
|
||||||
|
|
||||||
|
--- #################### LLM(危险评估大模型)配置 ####################
|
||||||
|
|
||||||
|
# OneAPI统一接口配置(用于危险评估智能分析)
|
||||||
|
llm:
|
||||||
|
# 本地OneAPI服务
|
||||||
|
local:
|
||||||
|
base-url: ${LLM_BASE_URL:https://oneapi.gongjulian.cn/v1} # OneAPI服务地址
|
||||||
|
api-key: ${LLM_API_KEY:sk-lB2Fc9ssY5UuwmiV5dD441F997364d29Be547e008dF5Cf41} # API密钥,建议通过环境变量配置
|
||||||
|
model: ${LLM_MODEL:deepseek-ai/deepseek-v3.2} # 使用的模型
|
||||||
|
timeout-seconds: ${LLM_TIMEOUT:120} # 请求超时时间
|
||||||
|
# Claude(可选,需要时取消注释)
|
||||||
|
# claude:
|
||||||
|
# api-key: ${CLAUDE_API_KEY:}
|
||||||
|
# timeout-seconds: 30
|
||||||
|
# model: claude-3-5-sonnet-20241022
|
||||||
|
# OpenAI GPT-4(可选)
|
||||||
|
# openai:
|
||||||
|
# api-key: ${OPENAI_API_KEY:}
|
||||||
|
# model: gpt-4o
|
||||||
|
# timeout-seconds: 60
|
||||||
Loading…
x
Reference in New Issue
Block a user