feat(analysis): 新增日报及分析结果分页接口与数据聚合
- 添加DailyReportAnalysisController,包含获取建议及分页查询接口 - 创建DailyReportSuggestionService接口及实现类分页方法 - 实现分页查询项目日报及其对应分析记录和建议功能 - 将日报与最新分析记录及建议数据整合为DailyReportWithAnalysisVO返回 - 增加接口调用的权限校验和错误处理 - 新增ApplyDailyReportSuggestionsRequest请求体及对应逻辑处理 - 补充分页参数默认值及状态筛选逻辑 - 优化查询条件,按日期及创建时间倒序排序
This commit is contained in:
@@ -3,12 +3,14 @@ package cn.yinlihupo.controller.analysis;
|
|||||||
import cn.yinlihupo.common.core.BaseResponse;
|
import cn.yinlihupo.common.core.BaseResponse;
|
||||||
import cn.yinlihupo.common.enums.ErrorCode;
|
import cn.yinlihupo.common.enums.ErrorCode;
|
||||||
import cn.yinlihupo.common.exception.BusinessException;
|
import cn.yinlihupo.common.exception.BusinessException;
|
||||||
|
import cn.yinlihupo.common.page.TableDataInfo;
|
||||||
import cn.yinlihupo.common.util.ResultUtils;
|
import cn.yinlihupo.common.util.ResultUtils;
|
||||||
import cn.yinlihupo.common.util.SecurityUtils;
|
import cn.yinlihupo.common.util.SecurityUtils;
|
||||||
import cn.yinlihupo.domain.dto.ApplyDailyReportSuggestionsRequest;
|
import cn.yinlihupo.domain.dto.ApplyDailyReportSuggestionsRequest;
|
||||||
import cn.yinlihupo.domain.entity.DailyReportUpdateSuggestion;
|
import cn.yinlihupo.domain.entity.DailyReportUpdateSuggestion;
|
||||||
import cn.yinlihupo.domain.vo.DailyReportAnalysisSuggestionsVO;
|
import cn.yinlihupo.domain.vo.DailyReportAnalysisSuggestionsVO;
|
||||||
import cn.yinlihupo.domain.vo.DailyReportUpdateSuggestionVO;
|
import cn.yinlihupo.domain.vo.DailyReportUpdateSuggestionVO;
|
||||||
|
import cn.yinlihupo.domain.vo.DailyReportWithAnalysisVO;
|
||||||
import cn.yinlihupo.mapper.DailyReportUpdateSuggestionMapper;
|
import cn.yinlihupo.mapper.DailyReportUpdateSuggestionMapper;
|
||||||
import cn.yinlihupo.service.analysis.DailyReportSuggestionService;
|
import cn.yinlihupo.service.analysis.DailyReportSuggestionService;
|
||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
@@ -57,6 +59,29 @@ public class DailyReportAnalysisController {
|
|||||||
return ResultUtils.success("查询成功", vo);
|
return ResultUtils.success("查询成功", vo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页获取项目日报及分析结果
|
||||||
|
*/
|
||||||
|
@GetMapping("/reports")
|
||||||
|
public BaseResponse<TableDataInfo<DailyReportWithAnalysisVO>> pageDailyReportsWithAnalysis(
|
||||||
|
@RequestParam Long projectId,
|
||||||
|
@RequestParam(required = false) LocalDate reportDate,
|
||||||
|
@RequestParam(defaultValue = "1") Integer pageNum,
|
||||||
|
@RequestParam(defaultValue = "10") Integer pageSize,
|
||||||
|
@RequestParam(required = false) String suggestionStatus) {
|
||||||
|
Long userId = SecurityUtils.getCurrentUserId();
|
||||||
|
if (userId == null) {
|
||||||
|
return ResultUtils.error(ErrorCode.NOT_LOGIN_ERROR, "用户未登录");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
TableDataInfo<DailyReportWithAnalysisVO> result = dailyReportSuggestionService.pageDailyReportsWithAnalysis(projectId, reportDate, pageNum, pageSize, suggestionStatus);
|
||||||
|
return ResultUtils.success("查询成功", result);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("查询日报及分析结果失败: {}", e.getMessage(), e);
|
||||||
|
return ResultUtils.error("查询失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 应用日报进度回写建议
|
* 应用日报进度回写建议
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
package cn.yinlihupo.domain.vo;
|
||||||
|
|
||||||
|
import cn.yinlihupo.domain.dto.DailyReportAnalysisResult;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class DailyReportWithAnalysisVO {
|
||||||
|
|
||||||
|
private Long reportId;
|
||||||
|
|
||||||
|
private Long projectId;
|
||||||
|
|
||||||
|
private LocalDate reportDate;
|
||||||
|
|
||||||
|
private String submitterUsername;
|
||||||
|
|
||||||
|
private Long submitterId;
|
||||||
|
|
||||||
|
private String workContent;
|
||||||
|
|
||||||
|
private String tomorrowPlan;
|
||||||
|
|
||||||
|
private Integer workIntensity;
|
||||||
|
|
||||||
|
private Boolean needHelp;
|
||||||
|
|
||||||
|
private String helpContent;
|
||||||
|
|
||||||
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
|
private Long analysisId;
|
||||||
|
|
||||||
|
private String analysisStatus;
|
||||||
|
|
||||||
|
private DailyReportAnalysisResult analysisResult;
|
||||||
|
|
||||||
|
private List<DailyReportUpdateSuggestionVO> analysisSuggestions;
|
||||||
|
}
|
||||||
@@ -2,6 +2,8 @@ package cn.yinlihupo.service.analysis;
|
|||||||
|
|
||||||
import cn.yinlihupo.domain.vo.DailyReportAnalysisSuggestionsVO;
|
import cn.yinlihupo.domain.vo.DailyReportAnalysisSuggestionsVO;
|
||||||
import cn.yinlihupo.domain.vo.DailyReportUpdateSuggestionVO;
|
import cn.yinlihupo.domain.vo.DailyReportUpdateSuggestionVO;
|
||||||
|
import cn.yinlihupo.domain.vo.DailyReportWithAnalysisVO;
|
||||||
|
import cn.yinlihupo.common.page.TableDataInfo;
|
||||||
|
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -14,5 +16,7 @@ public interface DailyReportSuggestionService {
|
|||||||
|
|
||||||
List<DailyReportUpdateSuggestionVO> listSuggestionsByProjectId(Long projectId, LocalDate reportDate, String status);
|
List<DailyReportUpdateSuggestionVO> listSuggestionsByProjectId(Long projectId, LocalDate reportDate, String status);
|
||||||
|
|
||||||
|
TableDataInfo<DailyReportWithAnalysisVO> pageDailyReportsWithAnalysis(Long projectId, LocalDate reportDate, Integer pageNum, Integer pageSize, String suggestionStatus);
|
||||||
|
|
||||||
int applySuggestions(Long projectId, List<Long> suggestionIds, Long appliedBy);
|
int applySuggestions(Long projectId, List<Long> suggestionIds, Long appliedBy);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package cn.yinlihupo.service.analysis.impl;
|
|||||||
|
|
||||||
import cn.yinlihupo.common.enums.ErrorCode;
|
import cn.yinlihupo.common.enums.ErrorCode;
|
||||||
import cn.yinlihupo.common.exception.BusinessException;
|
import cn.yinlihupo.common.exception.BusinessException;
|
||||||
|
import cn.yinlihupo.common.page.TableDataInfo;
|
||||||
import cn.yinlihupo.domain.dto.DailyReportAnalysisResult;
|
import cn.yinlihupo.domain.dto.DailyReportAnalysisResult;
|
||||||
import cn.yinlihupo.domain.entity.DailyReportAnalysisRecord;
|
import cn.yinlihupo.domain.entity.DailyReportAnalysisRecord;
|
||||||
import cn.yinlihupo.domain.entity.DailyReportUpdateSuggestion;
|
import cn.yinlihupo.domain.entity.DailyReportUpdateSuggestion;
|
||||||
@@ -10,12 +11,14 @@ import cn.yinlihupo.domain.entity.ProjectMilestone;
|
|||||||
import cn.yinlihupo.domain.entity.Task;
|
import cn.yinlihupo.domain.entity.Task;
|
||||||
import cn.yinlihupo.domain.vo.DailyReportAnalysisSuggestionsVO;
|
import cn.yinlihupo.domain.vo.DailyReportAnalysisSuggestionsVO;
|
||||||
import cn.yinlihupo.domain.vo.DailyReportUpdateSuggestionVO;
|
import cn.yinlihupo.domain.vo.DailyReportUpdateSuggestionVO;
|
||||||
|
import cn.yinlihupo.domain.vo.DailyReportWithAnalysisVO;
|
||||||
import cn.yinlihupo.mapper.DailyReportAnalysisRecordMapper;
|
import cn.yinlihupo.mapper.DailyReportAnalysisRecordMapper;
|
||||||
import cn.yinlihupo.mapper.DailyReportUpdateSuggestionMapper;
|
import cn.yinlihupo.mapper.DailyReportUpdateSuggestionMapper;
|
||||||
import cn.yinlihupo.mapper.ProjectDailyReportMapper;
|
import cn.yinlihupo.mapper.ProjectDailyReportMapper;
|
||||||
import cn.yinlihupo.mapper.ProjectMilestoneMapper;
|
import cn.yinlihupo.mapper.ProjectMilestoneMapper;
|
||||||
import cn.yinlihupo.mapper.TaskMapper;
|
import cn.yinlihupo.mapper.TaskMapper;
|
||||||
import cn.yinlihupo.service.analysis.DailyReportSuggestionService;
|
import cn.yinlihupo.service.analysis.DailyReportSuggestionService;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||||
@@ -129,6 +132,123 @@ public class DailyReportSuggestionServiceImpl implements DailyReportSuggestionSe
|
|||||||
return buildSuggestionVOList(projectId, suggestions);
|
return buildSuggestionVOList(projectId, suggestions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TableDataInfo<DailyReportWithAnalysisVO> pageDailyReportsWithAnalysis(Long projectId, LocalDate reportDate, Integer pageNum, Integer pageSize, String suggestionStatus) {
|
||||||
|
if (projectId == null) {
|
||||||
|
throw new BusinessException(ErrorCode.PARAMS_ERROR, "projectId不能为空");
|
||||||
|
}
|
||||||
|
int actualPageNum = pageNum == null || pageNum < 1 ? 1 : pageNum;
|
||||||
|
int actualPageSize = pageSize == null || pageSize < 1 ? 10 : pageSize;
|
||||||
|
String actualSuggestionStatus;
|
||||||
|
if (!StringUtils.hasText(suggestionStatus)) {
|
||||||
|
actualSuggestionStatus = "pending";
|
||||||
|
} else if ("all".equalsIgnoreCase(suggestionStatus)) {
|
||||||
|
actualSuggestionStatus = null;
|
||||||
|
} else {
|
||||||
|
actualSuggestionStatus = suggestionStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
Page<ProjectDailyReport> page = new Page<>(actualPageNum, actualPageSize);
|
||||||
|
LambdaQueryWrapper<ProjectDailyReport> reportWrapper = new LambdaQueryWrapper<ProjectDailyReport>()
|
||||||
|
.eq(ProjectDailyReport::getProjectId, projectId)
|
||||||
|
.eq(ProjectDailyReport::getDeleted, 0)
|
||||||
|
.eq(reportDate != null, ProjectDailyReport::getReportDate, reportDate)
|
||||||
|
.orderByDesc(ProjectDailyReport::getReportDate)
|
||||||
|
.orderByDesc(ProjectDailyReport::getCreateTime);
|
||||||
|
|
||||||
|
Page<ProjectDailyReport> reportPage = projectDailyReportMapper.selectPage(page, reportWrapper);
|
||||||
|
List<ProjectDailyReport> reports = reportPage.getRecords();
|
||||||
|
if (reports == null || reports.isEmpty()) {
|
||||||
|
return TableDataInfo.build(new Page<DailyReportWithAnalysisVO>(reportPage.getCurrent(), reportPage.getSize(), reportPage.getTotal())
|
||||||
|
.setRecords(new ArrayList<>()));
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Long> reportIds = reports.stream()
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.map(ProjectDailyReport::getId)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
Map<Long, DailyReportAnalysisRecord> latestAnalysisByReportId = new HashMap<>();
|
||||||
|
if (!reportIds.isEmpty()) {
|
||||||
|
List<DailyReportAnalysisRecord> analysisRecords = dailyReportAnalysisRecordMapper.selectList(
|
||||||
|
new LambdaQueryWrapper<DailyReportAnalysisRecord>()
|
||||||
|
.eq(DailyReportAnalysisRecord::getProjectId, projectId)
|
||||||
|
.in(DailyReportAnalysisRecord::getReportId, reportIds)
|
||||||
|
.eq(DailyReportAnalysisRecord::getDeleted, 0)
|
||||||
|
.orderByDesc(DailyReportAnalysisRecord::getCreateTime)
|
||||||
|
);
|
||||||
|
if (analysisRecords != null && !analysisRecords.isEmpty()) {
|
||||||
|
for (DailyReportAnalysisRecord record : analysisRecords) {
|
||||||
|
if (record == null || record.getReportId() == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
latestAnalysisByReportId.putIfAbsent(record.getReportId(), record);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Long> analysisIds = latestAnalysisByReportId.values().stream()
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.map(DailyReportAnalysisRecord::getId)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.distinct()
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
Map<Long, List<DailyReportUpdateSuggestionVO>> suggestionsByAnalysisId = Collections.emptyMap();
|
||||||
|
if (!analysisIds.isEmpty()) {
|
||||||
|
List<DailyReportUpdateSuggestion> suggestions = dailyReportUpdateSuggestionMapper.selectList(
|
||||||
|
new LambdaQueryWrapper<DailyReportUpdateSuggestion>()
|
||||||
|
.eq(DailyReportUpdateSuggestion::getProjectId, projectId)
|
||||||
|
.eq(DailyReportUpdateSuggestion::getDeleted, 0)
|
||||||
|
.eq(StringUtils.hasText(actualSuggestionStatus), DailyReportUpdateSuggestion::getStatus, actualSuggestionStatus)
|
||||||
|
.in(DailyReportUpdateSuggestion::getAnalysisId, analysisIds)
|
||||||
|
.orderByAsc(DailyReportUpdateSuggestion::getCreateTime)
|
||||||
|
);
|
||||||
|
List<DailyReportUpdateSuggestionVO> suggestionVOs = buildSuggestionVOList(projectId, suggestions);
|
||||||
|
suggestionsByAnalysisId = suggestionVOs.stream()
|
||||||
|
.filter(vo -> vo != null && vo.getAnalysisId() != null)
|
||||||
|
.collect(Collectors.groupingBy(DailyReportUpdateSuggestionVO::getAnalysisId));
|
||||||
|
}
|
||||||
|
|
||||||
|
List<DailyReportWithAnalysisVO> voList = new ArrayList<>();
|
||||||
|
for (ProjectDailyReport report : reports) {
|
||||||
|
if (report == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
DailyReportWithAnalysisVO vo = new DailyReportWithAnalysisVO();
|
||||||
|
vo.setReportId(report.getId());
|
||||||
|
vo.setProjectId(report.getProjectId());
|
||||||
|
vo.setReportDate(report.getReportDate());
|
||||||
|
vo.setSubmitterUsername(report.getSubmitterUsername());
|
||||||
|
vo.setSubmitterId(report.getSubmitterId());
|
||||||
|
vo.setWorkContent(report.getWorkContent());
|
||||||
|
vo.setTomorrowPlan(report.getTomorrowPlan());
|
||||||
|
vo.setWorkIntensity(report.getWorkIntensity());
|
||||||
|
vo.setNeedHelp(report.getNeedHelp());
|
||||||
|
vo.setHelpContent(report.getHelpContent());
|
||||||
|
vo.setCreateTime(report.getCreateTime());
|
||||||
|
|
||||||
|
DailyReportAnalysisRecord record = report.getId() != null ? latestAnalysisByReportId.get(report.getId()) : null;
|
||||||
|
if (record != null) {
|
||||||
|
vo.setAnalysisId(record.getId());
|
||||||
|
vo.setAnalysisStatus(record.getStatus());
|
||||||
|
if (record.getAnalysisResult() != null) {
|
||||||
|
DailyReportAnalysisResult analysisResult = OBJECT_MAPPER.convertValue(record.getAnalysisResult(), DailyReportAnalysisResult.class);
|
||||||
|
vo.setAnalysisResult(analysisResult);
|
||||||
|
}
|
||||||
|
vo.setAnalysisSuggestions(record.getId() != null ? suggestionsByAnalysisId.getOrDefault(record.getId(), List.of()) : List.of());
|
||||||
|
} else {
|
||||||
|
vo.setAnalysisSuggestions(List.of());
|
||||||
|
}
|
||||||
|
|
||||||
|
voList.add(vo);
|
||||||
|
}
|
||||||
|
|
||||||
|
return TableDataInfo.build(new Page<DailyReportWithAnalysisVO>(reportPage.getCurrent(), reportPage.getSize(), reportPage.getTotal())
|
||||||
|
.setRecords(voList));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public int applySuggestions(Long projectId, List<Long> suggestionIds, Long appliedBy) {
|
public int applySuggestions(Long projectId, List<Long> suggestionIds, Long appliedBy) {
|
||||||
|
|||||||
Reference in New Issue
Block a user