“mitao”
2026-03-25 309b5eb17c510c781daec96bbfef3b693f3a4d7e
admin-server/src/main/java/com/estate/expert/admin/service/impl/ReportServiceImpl.java
@@ -5,7 +5,12 @@
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.ErrorRecord;
import com.estate.expert.admin.domain.exam.record.error.ErrorRecordRepository;
import com.estate.expert.admin.domain.exam.record.RecordRepository;
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;
@@ -13,15 +18,25 @@
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.HashMap;
import java.util.List;
import java.util.Map;
/**
 * 报告数据服务实现类
@@ -47,6 +62,15 @@
    @Resource
    private ErrorRecordService errorRecordService;
    @Resource
    private ErrorRecordRepository errorRecordRepository;
    @Resource
    private RecordRepository recordRepository;
    @Resource
    private CheckTaskRepository checkTaskRepository;
    @Resource
    private DeviceService deviceService;
@@ -116,6 +140,50 @@
        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);
@@ -139,6 +207,8 @@
        var devices= deviceUsages.stream().map(DeviceUsage::getDevice).toList();
        var hierarchy = evalFuzzyResult.getPlan().getSystemScoreExpert().getModel().getHierarchy().getContent();
        var problemFrequency = buildSystemProblemFrequency(project.getId(), records);
        // 生成报告数据
        return SystemFuzzyReportData.builder()
                .reportId(evalFuzzyResult.getId())
@@ -150,6 +220,8 @@
                .projectInfo(projectInfo)
                .devices(devices)
                .records(records)
                .problemHazardCounts(problemFrequency.problemHazardCounts())
                .problemCheckCounts(problemFrequency.problemCheckCounts())
                .build()
                .generate();
    }
@@ -164,6 +236,8 @@
        var devices= deviceUsages.stream().map(DeviceUsage::getDevice).toList();
        var hierarchy = evalFuzzyResult.getPlan().getSystemScoreExpert().getModel().getHierarchy().getContent();
        var problemFrequency = buildSystemProblemFrequency(project.getId(), records);
        // 生成报告数据
        return SystemScoreReportData.builder()
                .reportId(evalFuzzyResult.getId())
@@ -175,8 +249,87 @@
                .projectInfo(projectInfo)
                .devices(devices)
                .records(records)
                .problemHazardCounts(problemFrequency.problemHazardCounts())
                .problemCheckCounts(problemFrequency.problemCheckCounts())
                .build()
                .generate();
    }
    private record ProblemFrequency(Map<Integer, Long> problemHazardCounts, Map<Integer, Long> problemCheckCounts) {
    }
    private record DeviceProblemFrequency(Map<String, Long> problemHazardCounts, Map<String, Long> problemCheckCounts) {
    }
    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(), 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(), Collections.emptyMap());
        }
        var taskIds = checkTaskRepository.listTaskIdsByProjectAndPlanState(projectId, PlanState.COMPLETE);
        if (taskIds == null || taskIds.isEmpty()) {
            return new ProblemFrequency(Collections.emptyMap(), 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());
        }
        Map<Integer, Long> checkCounts = new HashMap<>();
        for (var row : recordRepository.countSystemChecksByTaskIdsAndProblemIds(taskIds, problemIds)) {
            if (row == null || row.length < 2 || row[0] == null || row[1] == null) {
                continue;
            }
            checkCounts.put(((Number) row[0]).intValue(), ((Number) row[1]).longValue());
        }
        return new ProblemFrequency(hazardCounts, checkCounts);
    }
    private DeviceProblemFrequency buildDeviceProblemFrequency(Integer projectId) {
        if (projectId == null) {
            return new DeviceProblemFrequency(Collections.emptyMap(), Collections.emptyMap());
        }
        var taskIds = checkTaskRepository.listTaskIdsByProjectAndPlanState(projectId, PlanState.COMPLETE);
        if (taskIds == null || taskIds.isEmpty()) {
            return new DeviceProblemFrequency(Collections.emptyMap(), Collections.emptyMap());
        }
        Map<String, Long> hazardCounts = new HashMap<>();
        for (var row : errorRecordRepository.countDeviceHazardsByTaskIds(taskIds)) {
            collectDeviceFrequency(row, hazardCounts);
        }
        Map<String, Long> checkCounts = new HashMap<>();
        for (var row : recordRepository.countDeviceChecksByTaskIds(taskIds)) {
            collectDeviceFrequency(row, checkCounts);
        }
        return new DeviceProblemFrequency(hazardCounts, checkCounts);
    }
    private void collectDeviceFrequency(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 JSONObject buildFuzzyDeviceReportData(EvalFuzzyResult evalFuzzyResult, EvalScoreResult scoreResult,  ReportTemplate reportTemplate) {
@@ -187,6 +340,7 @@
        var deviceIds = evalFuzzyResult.getDeviceResMap().keySet();
        var devices = deviceService.findAllById(deviceIds);
        var hierarchy = evalFuzzyResult.getPlan().getDeviceScoreExpert().getModel().getHierarchy().getContent();
        var problemFrequency = buildDeviceProblemFrequency(project.getId());
        // 生成报告数据
        return DeviceFuzzyReportData.builder()
@@ -198,6 +352,8 @@
                .projectInfo(projectInfo)
                .devices(devices)
                .records(records)
                .deviceProblemHazardCounts(problemFrequency.problemHazardCounts())
                .deviceProblemCheckCounts(problemFrequency.problemCheckCounts())
                .build()
                .generate();
    }
@@ -210,6 +366,7 @@
        var deviceIds = evalFuzzyResult.getDeviceResMap().keySet();
        var devices = deviceService.findAllById(deviceIds);
        var hierarchy = evalFuzzyResult.getPlan().getDeviceScoreExpert().getModel().getHierarchy().getContent();
        var problemFrequency = buildDeviceProblemFrequency(project.getId());
        // 生成报告数据
        return DeviceScoreReportData.builder()
@@ -222,6 +379,8 @@
                .projectInfo(projectInfo)
                .devices(devices)
                .records(records)
                .deviceProblemHazardCounts(problemFrequency.problemHazardCounts())
                .deviceProblemCheckCounts(problemFrequency.problemCheckCounts())
                .build()
                .generate();
    }