| | |
| | | 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.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.DaiguanDeviceFuzzyReportData; |
| | | import com.estate.expert.admin.stat.report.data.impl.DaiguanDeviceScoreReportData; |
| | | 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 { |
| | | |
| | | private static final String DAIGUAN_TECH_REMARK = "岱观科技"; |
| | | private static final String DAIGUAN_SYSTEM_TEMPLATE_FILE = "第三方评估报告new.docx"; |
| | | private static final String DAIGUAN_REMARK = "岱观科技"; |
| | | private static final String DAIGUAN_DEVICE_TEMPLATE_FILE = "设备风险评估报告new.docx"; |
| | | |
| | | @Resource |
| | | private ReportTemplateService reportTemplateService; |
| | |
| | | |
| | | @Resource |
| | | private ErrorRecordService errorRecordService; |
| | | |
| | | @Resource |
| | | private ErrorRecordRepository errorRecordRepository; |
| | | |
| | | @Resource |
| | | private CheckTaskRepository checkTaskRepository; |
| | | |
| | | @Resource |
| | | private DeviceService deviceService; |
| | |
| | | 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: |
| | | if (isDaiguanTechTemplate(reportTemplate)) { |
| | | return new SystemReportBuilder(userFileService, DAIGUAN_SYSTEM_TEMPLATE_FILE); |
| | | } |
| | | return new SystemReportBuilder(userFileService); |
| | | case DeviceReport: |
| | | if (DAIGUAN_REMARK.equals(reportTemplate.getRemark())) { |
| | | return new DeviceReportBuilder(userFileService, DAIGUAN_DEVICE_TEMPLATE_FILE); |
| | | } |
| | | return new DeviceReportBuilder(userFileService); |
| | | default: |
| | | throw new BizException(BizResultCode.BIZ_REPORT_TEMPLATE_TYPE_NOT_EXIST); |
| | |
| | | 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()) |
| | |
| | | .projectInfo(projectInfo) |
| | | .devices(devices) |
| | | .records(records) |
| | | .problemHazardCounts(problemFrequency.problemHazardCounts()) |
| | | .projectCheckCount(projectCheckCount) |
| | | .build() |
| | | .generate(); |
| | | } |
| | |
| | | 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()) |
| | |
| | | .projectInfo(projectInfo) |
| | | .devices(devices) |
| | | .records(records) |
| | | .problemHazardCounts(problemFrequency.problemHazardCounts()) |
| | | .projectCheckCount(projectCheckCount) |
| | | .build() |
| | | .generate(); |
| | | } |
| | | |
| | | private record ProblemFrequency(Map<Integer, Long> problemHazardCounts) { |
| | | } |
| | | |
| | | private record DeviceProblemFrequency(Map<String, Long> problemHazardCounts, Map<Integer, Long> deviceCheckCounts) { |
| | | } |
| | | |
| | | private ProblemFrequency buildSystemProblemFrequency(Integer projectId, List<com.estate.expert.admin.domain.exam.record.error.ErrorRecord> 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<Integer, Long> 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<String, Long> hazardCounts = new HashMap<>(); |
| | | for (var row : errorRecordRepository.countDeviceHazardsByTaskIds(taskIds)) { |
| | | collectDeviceProblemFrequency(row, hazardCounts); |
| | | } |
| | | |
| | | Map<Integer, Long> deviceCheckCounts = buildDeviceCheckFrequencyByCompletedTasks(projectId, clientId); |
| | | |
| | | return new DeviceProblemFrequency(hazardCounts, deviceCheckCounts); |
| | | } |
| | | |
| | | private void collectDeviceProblemFrequency(Object[] row, Map<String, Long> 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<Integer, Long> 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<Integer, Long> deviceCheckCounts = new HashMap<>(); |
| | | for (CheckTask task : tasks) { |
| | | for (Integer deviceId : collectTaskCheckedDeviceIds(task)) { |
| | | deviceCheckCounts.merge(deviceId, 1L, Long::sum); |
| | | } |
| | | } |
| | | return deviceCheckCounts; |
| | | } |
| | | |
| | | private Set<Integer> collectTaskCheckedDeviceIds(CheckTask task) { |
| | | Set<Integer> deviceIds = new HashSet<>(); |
| | | if (task == null) { |
| | | return deviceIds; |
| | | } |
| | | addDeviceIds(task.getDeviceFuzzyMap(), deviceIds); |
| | | addDeviceIds(task.getDeviceScoreMap(), deviceIds); |
| | | return deviceIds; |
| | | } |
| | | |
| | | private void addDeviceIds(Map<Integer, Float> deviceMap, Set<Integer> 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 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); |
| | | |
| | | if (isDaiguanTemplate(reportTemplate)) { |
| | | return DaiguanDeviceFuzzyReportData.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(); |
| | | } |
| | | |
| | | // 生成报告数据 |
| | | return DeviceFuzzyReportData.builder() |
| | |
| | | .projectInfo(projectInfo) |
| | | .devices(devices) |
| | | .records(records) |
| | | .deviceProblemHazardCounts(problemFrequency.problemHazardCounts()) |
| | | .deviceCheckCounts(problemFrequency.deviceCheckCounts()) |
| | | .build() |
| | | .generate(); |
| | | } |
| | |
| | | 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); |
| | | |
| | | if (isDaiguanTemplate(reportTemplate)) { |
| | | return DaiguanDeviceScoreReportData.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(); |
| | | } |
| | | |
| | | // 生成报告数据 |
| | | return DeviceScoreReportData.builder() |
| | |
| | | .projectInfo(projectInfo) |
| | | .devices(devices) |
| | | .records(records) |
| | | .deviceProblemHazardCounts(problemFrequency.problemHazardCounts()) |
| | | .deviceCheckCounts(problemFrequency.deviceCheckCounts()) |
| | | .build() |
| | | .generate(); |
| | | } |
| | | |
| | | private List<Integer> 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 boolean isDaiguanTemplate(ReportTemplate reportTemplate) { |
| | | return reportTemplate != null && DAIGUAN_REMARK.equals(reportTemplate.getRemark()); |
| | | } |
| | | |
| | | private boolean isDaiguanTechTemplate(ReportTemplate reportTemplate) { |
| | | if (reportTemplate == null || reportTemplate.getRemark() == null) { |
| | | return false; |
| | | } |
| | | return DAIGUAN_TECH_REMARK.equals(reportTemplate.getRemark().trim()); |
| | | } |
| | | |
| | | 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(); |
| | | } |
| | | |
| | | } |