package com.estate.expert.admin.service.impl; import com.alibaba.fastjson.JSONObject; import com.deepoove.poi.XWPFTemplate; import com.estate.expert.admin.domain.business.device.usage.DeviceUsage; import com.estate.expert.admin.domain.exam.eval.fuzzy.EvalFuzzyResult; import com.estate.expert.admin.domain.exam.eval.score.EvalScoreResult; import com.estate.expert.admin.domain.exam.record.error.ErrorRecordRepository; import com.estate.expert.admin.domain.exam.task.check.CheckTask; import com.estate.expert.admin.domain.exam.task.check.CheckTaskRepository; import com.estate.expert.admin.domain.report.ReportTemplate; import com.estate.expert.admin.domain.plan.PlanState; import com.estate.expert.admin.enums.BizResultCode; import com.estate.expert.admin.service.*; import com.estate.expert.admin.service.eval.EvalFuzzyService; import com.estate.expert.admin.service.eval.EvalScoreService; import com.estate.expert.admin.stat.report.builder.DeviceReportBuilder; import com.estate.expert.admin.stat.report.builder.ReportBuilderBase; import com.estate.expert.admin.stat.report.builder.SystemReportBuilder; import com.estate.expert.admin.stat.report.data.DeviceReportData; import com.estate.expert.admin.stat.report.data.impl.DeviceFuzzyReportData; import com.estate.expert.admin.stat.report.data.impl.DeviceScoreReportData; import com.estate.expert.admin.stat.report.data.impl.SystemFuzzyReportData; import com.estate.expert.admin.stat.report.data.impl.SystemScoreReportData; import com.estate.expert.common.exception.BizException; import fr.opensagres.poi.xwpf.converter.pdf.PdfConverter; import fr.opensagres.poi.xwpf.converter.pdf.PdfOptions; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.OutputStream; import java.util.Collections; import java.util.HashSet; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; /** * 报告数据服务实现类 **/ @Slf4j @Service public class ReportServiceImpl implements ReportService { @Resource private ReportTemplateService reportTemplateService; @Resource private ProjectInfoService projectInfoService; @Resource private DeviceUsageService deviceUsageService; @Resource private EvalFuzzyService evalFuzzyService; @Resource private EvalScoreService evalScoreService; @Resource private ErrorRecordService errorRecordService; @Resource private ErrorRecordRepository errorRecordRepository; @Resource private CheckTaskRepository checkTaskRepository; @Resource private DeviceService deviceService; @Resource private UserFileService userFileService; @Override public JSONObject fuzzyReportData(Integer checkTaskId, Integer templateId) { var evalFuzzyResult = evalFuzzyService.getByCheckTaskId(checkTaskId); BizResultCode.EVAL_FUZZY_RESULT_NOT_EXIST.check(evalFuzzyResult == null); var evalScoreResult = evalScoreService.getByCheckTaskId(checkTaskId); BizResultCode.EVAL_SCORE_RESULT_NOT_EXIST.check(evalScoreResult == null); var reportTemplate = reportTemplateService.get(templateId); BizResultCode.BIZ_REPORT_TEMPLATE_NOT_EXIST.check(reportTemplate == null); switch (reportTemplate.getType()) { case ThirdPartyReport: return buildFuzzySystemReportData(evalFuzzyResult, evalScoreResult, reportTemplate); case DeviceReport: return buildFuzzyDeviceReportData(evalFuzzyResult, evalScoreResult, reportTemplate); default: throw new BizException(BizResultCode.BIZ_REPORT_TEMPLATE_TYPE_NOT_EXIST); } } @Override public JSONObject scoreReportData(Integer checkTaskId, Integer templateId) { var evalFuzzyResult = evalFuzzyService.getByCheckTaskId(checkTaskId); BizResultCode.EVAL_FUZZY_RESULT_NOT_EXIST.check(evalFuzzyResult == null); var evalScoreResult = evalScoreService.getByCheckTaskId(checkTaskId); BizResultCode.EVAL_SCORE_RESULT_NOT_EXIST.check(evalScoreResult == null); var reportTemplate = reportTemplateService.get(templateId); BizResultCode.BIZ_REPORT_TEMPLATE_NOT_EXIST.check(reportTemplate == null); switch (reportTemplate.getType()) { case ThirdPartyReport: return buildScoreSystemReportData(evalFuzzyResult, evalScoreResult, reportTemplate); case DeviceReport: return buildScoreDeviceReportData(evalFuzzyResult, evalScoreResult, reportTemplate); default: throw new BizException(BizResultCode.BIZ_REPORT_TEMPLATE_TYPE_NOT_EXIST); } } @Override public XWPFTemplate fuzzyReport(Integer checkTaskId, Integer templateId) { var reportData = fuzzyReportData(checkTaskId, templateId); var builder = getReportBuilder(templateId); var template = reportTemplateService.get(templateId); // reportData to JSONObject return builder.buildReport(reportData, template.getConfig()); } @Override public XWPFTemplate scoreReport(Integer checkTaskId, Integer templateId) { var reportData = scoreReportData(checkTaskId, templateId); var builder = getReportBuilder(templateId); var template = reportTemplateService.get(templateId); // reportData to JSONObject return builder.buildReport(reportData, template.getConfig()); } @Override public void fuzzyReportPdf(Integer checkTaskId, Integer templateId, OutputStream outputStream) { try (var doc = fuzzyReport(checkTaskId, templateId)) { convertToPdf(doc, outputStream); } catch (Exception e) { log.error("生成模糊评价PDF报告失败", e); throw new BizException("生成模糊评价PDF报告失败"); } } @Override public void scoreReportPdf(Integer checkTaskId, Integer templateId, OutputStream outputStream) { try (var doc = scoreReport(checkTaskId, templateId)) { convertToPdf(doc, outputStream); } catch (Exception e) { log.error("生成打分评价PDF报告失败", e); throw new BizException("生成打分评价PDF报告失败"); } } /** * 将Word文档转换为PDF * @param template Word模板 * @param outputStream 输出流 */ private void convertToPdf(XWPFTemplate template, OutputStream outputStream) throws Exception { // 先将Word模板写入字节数组 ByteArrayOutputStream docOutputStream = new ByteArrayOutputStream(); template.write(docOutputStream); // 从字节数组读取Word文档 ByteArrayInputStream docInputStream = new ByteArrayInputStream(docOutputStream.toByteArray()); org.apache.poi.xwpf.usermodel.XWPFDocument document = new org.apache.poi.xwpf.usermodel.XWPFDocument(docInputStream); // 转换为PDF PdfOptions options = PdfOptions.create(); PdfConverter.getInstance().convert(document, outputStream, options); // 关闭资源 document.close(); docInputStream.close(); docOutputStream.close(); } private ReportBuilderBase getReportBuilder(Integer templateId) { var reportTemplate = reportTemplateService.get(templateId); BizResultCode.BIZ_REPORT_TEMPLATE_NOT_EXIST.check(reportTemplate == null); switch (reportTemplate.getType()) { case ThirdPartyReport: return new SystemReportBuilder(userFileService); case DeviceReport: return new DeviceReportBuilder(userFileService); default: throw new BizException(BizResultCode.BIZ_REPORT_TEMPLATE_TYPE_NOT_EXIST); } } private JSONObject buildFuzzySystemReportData(EvalFuzzyResult evalFuzzyResult, EvalScoreResult scoreResult, ReportTemplate reportTemplate) { // 查询必须要的数据 var records = errorRecordService.listSystemErrors(evalFuzzyResult.getTask().getId()); var project = evalFuzzyResult.getProject(); var projectInfo = evalFuzzyResult.getTask().getProjectInfo(); // var projectInfo = projectInfoService.getByCheckTaskId(evalFuzzyResult.getTask().getId()); var deviceUsages = deviceUsageService.listUsages(project.getId(), null); var devices= deviceUsages.stream().map(DeviceUsage::getDevice).toList(); var hierarchy = evalFuzzyResult.getPlan().getSystemScoreExpert().getModel().getHierarchy().getContent(); var problemFrequency = buildSystemProblemFrequency(project.getId(), records); var projectCheckCount = countProjectChecks(project.getId()); // 生成报告数据 return SystemFuzzyReportData.builder() .reportId(evalFuzzyResult.getId()) .systemHierarchy(hierarchy) .sysResult(evalFuzzyResult.getSystemRes()) .scoreResult(scoreResult.getSystemRes()) .template(reportTemplate) .project(project) .projectInfo(projectInfo) .devices(devices) .records(records) .problemHazardCounts(problemFrequency.problemHazardCounts()) .projectCheckCount(projectCheckCount) .build() .generate(); } private JSONObject buildScoreSystemReportData(EvalFuzzyResult evalFuzzyResult, EvalScoreResult scoreResult, ReportTemplate reportTemplate) { // 查询必须要的数据 var records = errorRecordService.listSystemErrors(evalFuzzyResult.getTask().getId()); var project = evalFuzzyResult.getProject(); // var projectInfo = projectInfoService.latest(evalFuzzyResult.getProject().getId()); var projectInfo = evalFuzzyResult.getTask().getProjectInfo(); var deviceUsages = deviceUsageService.listUsages(project.getId(), null); var devices= deviceUsages.stream().map(DeviceUsage::getDevice).toList(); var hierarchy = evalFuzzyResult.getPlan().getSystemScoreExpert().getModel().getHierarchy().getContent(); var problemFrequency = buildSystemProblemFrequency(project.getId(), records); var projectCheckCount = countProjectChecks(project.getId()); // 生成报告数据 return SystemScoreReportData.builder() .reportId(evalFuzzyResult.getId()) .systemHierarchy(hierarchy) .sysResult(evalFuzzyResult.getSystemRes()) .scoreResult(scoreResult.getSystemRes()) .template(reportTemplate) .project(project) .projectInfo(projectInfo) .devices(devices) .records(records) .problemHazardCounts(problemFrequency.problemHazardCounts()) .projectCheckCount(projectCheckCount) .build() .generate(); } private record ProblemFrequency(Map problemHazardCounts) { } private record DeviceProblemFrequency(Map problemHazardCounts, Map deviceCheckCounts) { } private ProblemFrequency buildSystemProblemFrequency(Integer projectId, List currentTaskRecords) { if (projectId == null || currentTaskRecords == null || currentTaskRecords.isEmpty()) { return new ProblemFrequency(Collections.emptyMap()); } var problemIds = currentTaskRecords.stream() .map(r -> r.getProblem() != null ? r.getProblem().getId() : null) .filter(java.util.Objects::nonNull) .distinct() .toList(); if (problemIds.isEmpty()) { return new ProblemFrequency(Collections.emptyMap()); } var taskIds = checkTaskRepository.listTaskIdsByProjectAndPlanState(projectId, PlanState.COMPLETE); if (taskIds == null || taskIds.isEmpty()) { return new ProblemFrequency(Collections.emptyMap()); } Map hazardCounts = new HashMap<>(); for (var row : errorRecordRepository.countSystemHazardsByTaskIdsAndProblemIds(taskIds, problemIds)) { if (row == null || row.length < 2 || row[0] == null || row[1] == null) { continue; } hazardCounts.put(((Number) row[0]).intValue(), ((Number) row[1]).longValue()); } return new ProblemFrequency(hazardCounts); } private DeviceProblemFrequency buildDeviceProblemFrequency(Integer projectId, Integer clientId) { var taskIds = listTaskIdsByProjectAndClient(projectId, clientId); if (taskIds.isEmpty()) { return new DeviceProblemFrequency(Collections.emptyMap(), Collections.emptyMap()); } Map hazardCounts = new HashMap<>(); for (var row : errorRecordRepository.countDeviceHazardsByTaskIds(taskIds)) { collectDeviceProblemFrequency(row, hazardCounts); } Map deviceCheckCounts = buildDeviceCheckFrequencyByCompletedTasks(projectId, clientId); return new DeviceProblemFrequency(hazardCounts, deviceCheckCounts); } private void collectDeviceProblemFrequency(Object[] row, Map target) { if (row == null || row.length < 3 || row[0] == null || row[2] == null) { return; } Integer deviceId = ((Number) row[0]).intValue(); Integer problemId = row[1] == null ? null : ((Number) row[1]).intValue(); Long count = ((Number) row[2]).longValue(); target.put(DeviceReportData.buildDeviceProblemKey(deviceId, problemId), count); } private Map buildDeviceCheckFrequencyByCompletedTasks(Integer projectId, Integer clientId) { if (projectId == null || clientId == null) { return Collections.emptyMap(); } var tasks = checkTaskRepository.listClosedByProjectAndClient(projectId, clientId); if (tasks == null || tasks.isEmpty()) { return Collections.emptyMap(); } Map deviceCheckCounts = new HashMap<>(); for (CheckTask task : tasks) { for (Integer deviceId : collectTaskCheckedDeviceIds(task)) { deviceCheckCounts.merge(deviceId, 1L, Long::sum); } } return deviceCheckCounts; } private Set collectTaskCheckedDeviceIds(CheckTask task) { Set deviceIds = new HashSet<>(); if (task == null) { return deviceIds; } addDeviceIds(task.getDeviceFuzzyMap(), deviceIds); addDeviceIds(task.getDeviceScoreMap(), deviceIds); return deviceIds; } private void addDeviceIds(Map deviceMap, Set target) { if (deviceMap == null || deviceMap.isEmpty()) { return; } for (Integer deviceId : deviceMap.keySet()) { if (deviceId == null) { continue; } target.add(deviceId); } } private JSONObject buildFuzzyDeviceReportData(EvalFuzzyResult evalFuzzyResult, EvalScoreResult scoreResult, ReportTemplate reportTemplate) { var records = errorRecordService.listDeviceErrors(evalFuzzyResult.getTask().getId()); var project = evalFuzzyResult.getProject(); var projectInfo = evalFuzzyResult.getTask().getProjectInfo(); // var projectInfo = projectInfoService.getByCheckTaskId(evalFuzzyResult.getTask().getId()); var deviceIds = evalFuzzyResult.getDeviceResMap().keySet(); var devices = deviceService.findAllById(deviceIds); var hierarchy = evalFuzzyResult.getPlan().getDeviceScoreExpert().getModel().getHierarchy().getContent(); var clientId = project.getClient() != null ? project.getClient().getId() : null; var problemFrequency = buildDeviceProblemFrequency(project.getId(), clientId); // 生成报告数据 return DeviceFuzzyReportData.builder() .reportId(evalFuzzyResult.getId()) .deviceResMap(evalFuzzyResult.getDeviceResMap()) .deviceHierarchy(hierarchy) .template(reportTemplate) .project(project) .projectInfo(projectInfo) .devices(devices) .records(records) .deviceProblemHazardCounts(problemFrequency.problemHazardCounts()) .deviceCheckCounts(problemFrequency.deviceCheckCounts()) .build() .generate(); } private JSONObject buildScoreDeviceReportData(EvalFuzzyResult evalFuzzyResult, EvalScoreResult evalScoreResult, ReportTemplate reportTemplate) { var records = errorRecordService.listDeviceErrors(evalFuzzyResult.getTask().getId()); var project = evalFuzzyResult.getProject(); // var projectInfo = projectInfoService.getByCheckTaskId(evalFuzzyResult.getTask().getId()); var projectInfo = evalFuzzyResult.getTask().getProjectInfo(); var deviceIds = evalFuzzyResult.getDeviceResMap().keySet(); var devices = deviceService.findAllById(deviceIds); var hierarchy = evalFuzzyResult.getPlan().getDeviceScoreExpert().getModel().getHierarchy().getContent(); var clientId = project.getClient() != null ? project.getClient().getId() : null; var problemFrequency = buildDeviceProblemFrequency(project.getId(), clientId); // 生成报告数据 return DeviceScoreReportData.builder() .reportId(evalFuzzyResult.getId()) .deviceResMap(evalFuzzyResult.getDeviceResMap()) .deviceScoreResMap(evalScoreResult.getDeviceResMap()) .deviceHierarchy(hierarchy) .template(reportTemplate) .project(project) .projectInfo(projectInfo) .devices(devices) .records(records) .deviceProblemHazardCounts(problemFrequency.problemHazardCounts()) .deviceCheckCounts(problemFrequency.deviceCheckCounts()) .build() .generate(); } private List listTaskIdsByProjectAndClient(Integer projectId, Integer clientId) { if (projectId == null || clientId == null) { return Collections.emptyList(); } var taskIds = checkTaskRepository.listTaskIdsByProjectAndClient(projectId, clientId); if (taskIds == null) { return Collections.emptyList(); } return taskIds; } private long countProjectChecks(Integer projectId) { if (projectId == null) { return 0L; } var taskIds = checkTaskRepository.listTaskIdsByProjectAndPlanState(projectId, PlanState.COMPLETE); if (taskIds == null) { return 0L; } return taskIds.size(); } }