feat(evaluation): 新增模板详情导出功能及代码优化

- 新增导出单个模板及其维度信息的接口
- 修复参数校验缺失问题,添加 @NotNull 校验
- 修复 N+1 查询问题,改用批量查询
- 优化 DateTimeFormatter 为静态常量
- 添加评论列表字段到 VO 类
This commit is contained in:
tangweijie 2026-01-22 12:23:15 +08:00
parent cff7832d5e
commit 1eb543d803
6 changed files with 150 additions and 0 deletions

View File

@ -28,6 +28,7 @@ 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.evaluationreport.vo.*;
import cn.iocoder.yudao.module.prison.controller.admin.evaluationreport.vo.EvaluationTemplateWithDimensionsRespVO;
import cn.iocoder.yudao.module.prison.dal.dataobject.evaluationreport.*;
import cn.iocoder.yudao.module.prison.service.evaluationreport.EvaluationReportService;
import cn.iocoder.yudao.module.prison.service.evaluationreport.dto.DimensionDataSourcesRespDTO;
@ -142,6 +143,17 @@ public class EvaluationReportController {
BeanUtils.toBean(list, EvaluationTemplateRespVO.class));
}
@GetMapping("/template/export-with-dimensions")
@Operation(summary = "导出单个模板及其维度信息 Excel")
@PreAuthorize("@ss.hasPermission('prison:evaluation-report:template:export')")
@ApiAccessLog(operateType = EXPORT)
public void exportTemplateWithDimensions(@NotNull(message = "编号不能为空") @RequestParam("id") Long id,
HttpServletResponse response) throws IOException {
EvaluationTemplateWithDimensionsRespVO templateWithDimensions = evaluationReportService.getTemplateWithDimensions(id);
ExcelUtils.write(response, "评估模板详情.xlsx", "模板详情", EvaluationTemplateWithDimensionsRespVO.class,
Collections.singletonList(templateWithDimensions));
}
// ========== 维度配置管理 ==========
@PostMapping("/dimension/create")

View File

@ -101,4 +101,7 @@ public class EvaluationDimensionRespVO {
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai")
private LocalDateTime createTime;
@Schema(description = "快捷评语列表")
private List<cn.iocoder.yudao.module.prison.dal.dataobject.evaluationreport.ReportCommentDO> commentList;
}

View File

@ -0,0 +1,72 @@
package cn.iocoder.yudao.module.prison.controller.admin.evaluationreport.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import cn.idev.excel.annotation.*;
import java.util.List;
@Schema(description = "管理后台 - 评估模板详情导出 VO")
@Data
@ExcelIgnoreUnannotated
public class EvaluationTemplateWithDimensionsRespVO {
@Schema(description = "模板ID", example = "19443")
@ExcelProperty("模板ID")
private Long id;
@Schema(description = "模板名称", example = "入监综合评估")
@ExcelProperty("模板名称")
private String name;
@Schema(description = "模板编码", example = "INCOMING_ASSESSMENT")
@ExcelProperty("模板编码")
private String code;
@Schema(description = "模板类型1-心理评估 2-危险性评估 3-改造表现评估 4-综合评估")
@ExcelProperty("模板类型")
private Integer type;
@Schema(description = "描述")
@ExcelProperty("描述")
private String description;
@Schema(description = "适用人群", example = "新入监罪犯")
@ExcelProperty("适用人群")
private String applicableCrowd;
@Schema(description = "评估周期1-月评 2-季评 3-半年评 4-年终评 5-入监评估 6-出监评估")
@ExcelProperty("评估周期")
private Integer evaluationCycle;
@Schema(description = "状态1-启用 2-禁用")
@ExcelProperty("状态")
private Integer status;
@Schema(description = "是否允许AI生成1-是 2-否")
@ExcelProperty("允许AI生成")
private Integer aiEnabled;
@Schema(description = "AI提示词")
@ExcelProperty("AI提示词")
private String aiPrompt;
@Schema(description = "排序")
@ExcelProperty("排序")
private Integer sort;
@Schema(description = "备注")
@ExcelProperty("备注")
private String remark;
@Schema(description = "创建人")
@ExcelProperty("创建人")
private String creator;
@Schema(description = "创建时间")
@ExcelProperty("创建时间")
private String createTime;
@Schema(description = "维度列表")
@ExcelProperty("维度列表")
private List<EvaluationDimensionRespVO> dimensions;
}

View File

@ -46,4 +46,15 @@ public interface ReportCommentMapper extends BaseMapperX<ReportCommentDO> {
.orderByDesc(ReportCommentDO::getUseCount));
}
default List<ReportCommentDO> selectListByDimensionIds(Collection<Long> dimensionIds) {
if (dimensionIds == null || dimensionIds.isEmpty()) {
return List.of();
}
return selectList(new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<ReportCommentDO>()
.in(ReportCommentDO::getDimensionId, dimensionIds)
.eq(ReportCommentDO::getStatus, 1)
.eq(ReportCommentDO::getDeleted, false)
.orderByDesc(ReportCommentDO::getUseCount));
}
}

View File

@ -53,6 +53,11 @@ public interface EvaluationReportService {
*/
List<EvaluationTemplateDO> getEnabledTemplateList();
/**
* 获取模板及其维度信息用于导出
*/
EvaluationTemplateWithDimensionsRespVO getTemplateWithDimensions(Long id);
// ========== 维度配置管理 ==========
/**

View File

@ -156,6 +156,53 @@ public class EvaluationReportServiceImpl implements EvaluationReportService {
.orderByAsc(EvaluationTemplateDO::getSort));
}
@Override
public EvaluationTemplateWithDimensionsRespVO getTemplateWithDimensions(Long id) {
EvaluationTemplateDO template = templateMapper.selectById(id);
if (template == null) {
throw exception(EVALUATION_TEMPLATE_NOT_EXISTS);
}
// 构造响应对象
EvaluationTemplateWithDimensionsRespVO respVO = new EvaluationTemplateWithDimensionsRespVO();
BeanUtils.copyProperties(template, respVO);
// 格式化创建时间
if (template.getCreateTime() != null) {
respVO.setCreateTime(template.getCreateTime().format(DATE_TIME_FORMATTER));
}
// 获取维度列表
List<EvaluationDimensionDO> dimensions = dimensionMapper.selectList(
new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<EvaluationDimensionDO>()
.eq(EvaluationDimensionDO::getTemplateId, id)
.eq(EvaluationDimensionDO::getDeleted, false)
.orderByAsc(EvaluationDimensionDO::getSort)
);
// 批量获取评论避免 N+1 查询问题
Set<Long> dimensionIds = dimensions.stream()
.map(EvaluationDimensionDO::getId)
.collect(Collectors.toSet());
Map<Long, List<ReportCommentDO>> commentsMap = new HashMap<>(dimensions.size());
if (!dimensionIds.isEmpty()) {
List<ReportCommentDO> allComments = commentMapper.selectListByDimensionIds(dimensionIds);
for (ReportCommentDO comment : allComments) {
commentsMap.computeIfAbsent(comment.getDimensionId(), k -> new ArrayList<>()).add(comment);
}
}
// 转换为 VO 并设置评论
List<EvaluationDimensionRespVO> dimensionVOList = BeanUtils.toBean(dimensions, EvaluationDimensionRespVO.class);
dimensionVOList.forEach(dim -> dim.setCommentList(commentsMap.getOrDefault(dim.getId(), List.of())));
respVO.setDimensions(dimensionVOList);
return respVO;
}
private static final DateTimeFormatter DATE_TIME_FORMATTER =
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
private void validateTemplateExists(Long id) {
if (templateMapper.selectById(id) == null) {
throw exception(EVALUATION_TEMPLATE_NOT_EXISTS);