diff --git a/ruoyi-modules/hwmom-qms/src/main/java/org/dromara/qms/controller/ReportController.java b/ruoyi-modules/hwmom-qms/src/main/java/org/dromara/qms/controller/ReportController.java new file mode 100644 index 00000000..87338506 --- /dev/null +++ b/ruoyi-modules/hwmom-qms/src/main/java/org/dromara/qms/controller/ReportController.java @@ -0,0 +1,43 @@ +package org.dromara.qms.controller; + +import lombok.RequiredArgsConstructor; +import org.dromara.qms.domain.vo.report.DefectAnalysisReportVo; +import org.dromara.qms.domain.vo.report.WeeklyTestReportVo; +import org.dromara.qms.service.IReportService; +import org.dromara.common.core.domain.R; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +/** + * 报表控制器 + * + * @author yuex + * @date 2024-07-29 + */ +@RequiredArgsConstructor +@RestController +@RequestMapping("/report") +public class ReportController { + + private final IReportService reportService; + + /** + * 获取每周测试报告 + */ + @GetMapping("/weeklyTestReport") + public R getWeeklyTestReport(@RequestParam String startTime, @RequestParam String endTime) { + WeeklyTestReportVo weeklyTestReport = reportService.getWeeklyTestReport(startTime, endTime); + return R.ok(weeklyTestReport); + } + + /** + * 获取不良品分析报表 + */ + @GetMapping("/defectAnalysisReport") + public R getDefectAnalysisReport(@RequestParam String startTime, @RequestParam String endTime) { + DefectAnalysisReportVo defectAnalysisReport = reportService.getDefectAnalysisReport(startTime, endTime); + return R.ok(defectAnalysisReport); + } +} diff --git a/ruoyi-modules/hwmom-qms/src/main/java/org/dromara/qms/domain/dto/DefectAnalysisDto.java b/ruoyi-modules/hwmom-qms/src/main/java/org/dromara/qms/domain/dto/DefectAnalysisDto.java new file mode 100644 index 00000000..a003989f --- /dev/null +++ b/ruoyi-modules/hwmom-qms/src/main/java/org/dromara/qms/domain/dto/DefectAnalysisDto.java @@ -0,0 +1,34 @@ +package org.dromara.qms.domain.dto; + +import lombok.Data; +import java.math.BigDecimal; + +/** + * 不良品分析数据传输对象 + * + * @author yuex + * @date 2024-07-29 + */ +@Data +public class DefectAnalysisDto { + + /** + * 指标类型 + */ + private String metric; + + /** + * 业务日期 + */ + private String bizDate; + + /** + * 检测类型名称 + */ + private String typeName; + + /** + * 数值 + */ + private BigDecimal value; +} \ No newline at end of file diff --git a/ruoyi-modules/hwmom-qms/src/main/java/org/dromara/qms/domain/dto/DefectDataDto.java b/ruoyi-modules/hwmom-qms/src/main/java/org/dromara/qms/domain/dto/DefectDataDto.java new file mode 100644 index 00000000..88277615 --- /dev/null +++ b/ruoyi-modules/hwmom-qms/src/main/java/org/dromara/qms/domain/dto/DefectDataDto.java @@ -0,0 +1,32 @@ +package org.dromara.qms.domain.dto; + +public class DefectDataDto { + private String testDate; + private String defectType; + private Integer defectCount; + + // Getters and Setters + public String getTestDate() { + return testDate; + } + + public void setTestDate(String testDate) { + this.testDate = testDate; + } + + public String getDefectType() { + return defectType; + } + + public void setDefectType(String defectType) { + this.defectType = defectType; + } + + public Integer getDefectCount() { + return defectCount; + } + + public void setDefectCount(Integer defectCount) { + this.defectCount = defectCount; + } +} \ No newline at end of file diff --git a/ruoyi-modules/hwmom-qms/src/main/java/org/dromara/qms/domain/dto/InspectionCountDto.java b/ruoyi-modules/hwmom-qms/src/main/java/org/dromara/qms/domain/dto/InspectionCountDto.java new file mode 100644 index 00000000..78ebee47 --- /dev/null +++ b/ruoyi-modules/hwmom-qms/src/main/java/org/dromara/qms/domain/dto/InspectionCountDto.java @@ -0,0 +1,35 @@ +package org.dromara.qms.domain.dto; + +import java.math.BigDecimal; +import java.util.Date; + +public class InspectionCountDto { + private String testDate; + private BigDecimal inspectionQty; + private BigDecimal unqualifiedQty; + + // Getters and Setters + public String getTestDate() { + return testDate; + } + + public void setTestDate(String testDate) { + this.testDate = testDate; + } + + public BigDecimal getInspectionQty() { + return inspectionQty; + } + + public void setInspectionQty(BigDecimal inspectionQty) { + this.inspectionQty = inspectionQty; + } + + public BigDecimal getUnqualifiedQty() { + return unqualifiedQty; + } + + public void setUnqualifiedQty(BigDecimal unqualifiedQty) { + this.unqualifiedQty = unqualifiedQty; + } +} \ No newline at end of file diff --git a/ruoyi-modules/hwmom-qms/src/main/java/org/dromara/qms/domain/vo/report/DailyTestReportVo.java b/ruoyi-modules/hwmom-qms/src/main/java/org/dromara/qms/domain/vo/report/DailyTestReportVo.java new file mode 100644 index 00000000..0cd197ba --- /dev/null +++ b/ruoyi-modules/hwmom-qms/src/main/java/org/dromara/qms/domain/vo/report/DailyTestReportVo.java @@ -0,0 +1,16 @@ +package org.dromara.qms.domain.vo.report; + +import lombok.Data; + +import java.math.BigDecimal; +import java.util.Map; + +@Data +public class DailyTestReportVo { + private String date; + private String dayOfWeek; + private BigDecimal inspectionQty; + private BigDecimal defectQty; + private String defectRate; + private Map defectTypeSummary; +} \ No newline at end of file diff --git a/ruoyi-modules/hwmom-qms/src/main/java/org/dromara/qms/domain/vo/report/DefectAnalysisReportVo.java b/ruoyi-modules/hwmom-qms/src/main/java/org/dromara/qms/domain/vo/report/DefectAnalysisReportVo.java new file mode 100644 index 00000000..105bb853 --- /dev/null +++ b/ruoyi-modules/hwmom-qms/src/main/java/org/dromara/qms/domain/vo/report/DefectAnalysisReportVo.java @@ -0,0 +1,51 @@ +package org.dromara.qms.domain.vo.report; + +import lombok.Data; +import java.math.BigDecimal; +import java.util.List; +import java.util.Map; + +/** + * 不良品分析报表视图对象 + * + * @author yuex + * @date 2024-07-29 + */ +@Data +public class DefectAnalysisReportVo { + + /** + * 表格数据 + */ + private List> tableData; + + /** + * 日期列信息 + */ + private List dateColumns; + + /** + * 检测类型列表 + */ + private List inspectionTypes; + + /** + * 图表数据 + */ + private ChartData chartData; + + @Data + public static class DateColumnInfo { + private String date; + private String dayOfWeek; + private String prop; + } + + @Data + public static class ChartData { + private List dates; + private List inspectionData; + private List defectData; + private List defectRateData; + } +} \ No newline at end of file diff --git a/ruoyi-modules/hwmom-qms/src/main/java/org/dromara/qms/domain/vo/report/WeeklyTestReportVo.java b/ruoyi-modules/hwmom-qms/src/main/java/org/dromara/qms/domain/vo/report/WeeklyTestReportVo.java new file mode 100644 index 00000000..87fde4d5 --- /dev/null +++ b/ruoyi-modules/hwmom-qms/src/main/java/org/dromara/qms/domain/vo/report/WeeklyTestReportVo.java @@ -0,0 +1,16 @@ +package org.dromara.qms.domain.vo.report; + +import lombok.Data; + +import java.math.BigDecimal; +import java.util.List; +import java.util.Map; + +@Data +public class WeeklyTestReportVo { + private List dailyReports; + private BigDecimal totalInspectionQty; + private BigDecimal totalDefectQty; + private String totalDefectRate; + private Map totalDefectTypeSummary; +} \ No newline at end of file diff --git a/ruoyi-modules/hwmom-qms/src/main/java/org/dromara/qms/mapper/ReportMapper.java b/ruoyi-modules/hwmom-qms/src/main/java/org/dromara/qms/mapper/ReportMapper.java new file mode 100644 index 00000000..159bf531 --- /dev/null +++ b/ruoyi-modules/hwmom-qms/src/main/java/org/dromara/qms/mapper/ReportMapper.java @@ -0,0 +1,26 @@ +package org.dromara.qms.mapper; + +import org.apache.ibatis.annotations.Param; +import org.dromara.qms.domain.dto.DefectAnalysisDto; +import org.dromara.qms.domain.dto.DefectDataDto; +import org.dromara.qms.domain.dto.InspectionCountDto; + +import java.util.List; + +public interface ReportMapper { + + List selectInspectionCounts(@Param("startTime") String startTime, @Param("endTime") String endTime); + + List selectDefectData(@Param("startTime") String startTime, @Param("endTime") String endTime); + + /** + * 获取所有检测类型 + */ + List selectInspectionTypes(); + + /** + * 获取不良品分析报表数据 + */ + List selectDefectAnalysisData(@Param("startTime") String startTime, @Param("endTime") String endTime); + +} \ No newline at end of file diff --git a/ruoyi-modules/hwmom-qms/src/main/java/org/dromara/qms/service/IReportService.java b/ruoyi-modules/hwmom-qms/src/main/java/org/dromara/qms/service/IReportService.java new file mode 100644 index 00000000..2e609075 --- /dev/null +++ b/ruoyi-modules/hwmom-qms/src/main/java/org/dromara/qms/service/IReportService.java @@ -0,0 +1,23 @@ +package org.dromara.qms.service; + +import org.dromara.qms.domain.vo.report.DefectAnalysisReportVo; +import org.dromara.qms.domain.vo.report.WeeklyTestReportVo; + +/** + * 报表服务接口 + * + * @author yuex + * @date 2024-07-29 + */ +public interface IReportService { + + /** + * 获取每周测试报告 + */ + WeeklyTestReportVo getWeeklyTestReport(String startTime, String endTime); + + /** + * 获取不良品分析报表 + */ + DefectAnalysisReportVo getDefectAnalysisReport(String startTime, String endTime); +} \ No newline at end of file diff --git a/ruoyi-modules/hwmom-qms/src/main/java/org/dromara/qms/service/impl/ReportServiceImpl.java b/ruoyi-modules/hwmom-qms/src/main/java/org/dromara/qms/service/impl/ReportServiceImpl.java new file mode 100644 index 00000000..acd00c8f --- /dev/null +++ b/ruoyi-modules/hwmom-qms/src/main/java/org/dromara/qms/service/impl/ReportServiceImpl.java @@ -0,0 +1,297 @@ +package org.dromara.qms.service.impl; + +import lombok.RequiredArgsConstructor; +import org.dromara.qms.domain.dto.DefectAnalysisDto; +import org.dromara.qms.domain.dto.DefectDataDto; +import org.dromara.qms.domain.dto.InspectionCountDto; +import org.dromara.qms.domain.vo.report.DailyTestReportVo; +import org.dromara.qms.domain.vo.report.DefectAnalysisReportVo; +import org.dromara.qms.domain.vo.report.WeeklyTestReportVo; +import org.dromara.qms.mapper.ReportMapper; +import org.dromara.qms.service.IReportService; +import org.springframework.stereotype.Service; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.time.format.TextStyle; +import java.util.*; +import java.util.stream.Collectors; + +@RequiredArgsConstructor +@Service +public class ReportServiceImpl implements IReportService { + + private final ReportMapper reportMapper; + + @Override + public WeeklyTestReportVo getWeeklyTestReport(String startTime, String endTime) { + List dailyInspectionCount = reportMapper.selectInspectionCounts(startTime, endTime); + List dailyDefectData = reportMapper.selectDefectData(startTime, endTime); + + Map dailyReportMap = new HashMap<>(); + + for (InspectionCountDto inspectionCount : dailyInspectionCount) { + String date = inspectionCount.getTestDate(); + DailyTestReportVo dailyReport = dailyReportMap.computeIfAbsent(date, k -> new DailyTestReportVo()); + dailyReport.setDate(date); + dailyReport.setDayOfWeek(getDayOfWeek(date)); + dailyReport.setInspectionQty(inspectionCount.getInspectionQty() != null ? inspectionCount.getInspectionQty() : BigDecimal.ZERO); + dailyReport.setDefectQty(inspectionCount.getUnqualifiedQty() != null ? inspectionCount.getUnqualifiedQty() : BigDecimal.ZERO); + dailyReport.setDefectTypeSummary(new HashMap<>()); + } + + for (DefectDataDto defectData : dailyDefectData) { + String date = defectData.getTestDate(); + DailyTestReportVo dailyReport = dailyReportMap.get(date); + if (dailyReport != null && defectData.getDefectType() != null) { + dailyReport.getDefectTypeSummary().put(defectData.getDefectType(), defectData.getDefectCount()); + } + } + + List dailyReports = new ArrayList<>(dailyReportMap.values()); + for (DailyTestReportVo report : dailyReports) { + if (report.getInspectionQty().compareTo(BigDecimal.ZERO) > 0) { + BigDecimal defectRate = report.getDefectQty().divide(report.getInspectionQty(), 4, RoundingMode.HALF_UP).multiply(new BigDecimal(100)); + report.setDefectRate(String.format("%.2f%%", defectRate)); + } else { + report.setDefectRate("0.00%"); + } + } + + dailyReports.sort(Comparator.comparing(DailyTestReportVo::getDate)); + + WeeklyTestReportVo weeklyReport = new WeeklyTestReportVo(); + weeklyReport.setDailyReports(dailyReports); + + BigDecimal totalInspectionQty = dailyReports.stream().map(DailyTestReportVo::getInspectionQty).reduce(BigDecimal.ZERO, BigDecimal::add); + BigDecimal totalDefectQty = dailyReports.stream().map(DailyTestReportVo::getDefectQty).reduce(BigDecimal.ZERO, BigDecimal::add); + + weeklyReport.setTotalInspectionQty(totalInspectionQty); + weeklyReport.setTotalDefectQty(totalDefectQty); + + if (totalInspectionQty.compareTo(BigDecimal.ZERO) > 0) { + BigDecimal totalDefectRate = totalDefectQty.divide(totalInspectionQty, 4, RoundingMode.HALF_UP).multiply(new BigDecimal(100)); + weeklyReport.setTotalDefectRate(String.format("%.2f%%", totalDefectRate)); + } else { + weeklyReport.setTotalDefectRate("0.00%"); + } + + Map totalDefectTypeSummary = dailyReports.stream() + .flatMap(r -> r.getDefectTypeSummary().entrySet().stream()) + .collect(Collectors.groupingBy(Map.Entry::getKey, Collectors.summingInt(Map.Entry::getValue))); + + weeklyReport.setTotalDefectTypeSummary(totalDefectTypeSummary); + + return weeklyReport; + } + + @Override + public DefectAnalysisReportVo getDefectAnalysisReport(String startTime, String endTime) { + // 获取所有检测类型 + List inspectionTypes = reportMapper.selectInspectionTypes(); + + // 获取不良品分析数据 + List analysisData = reportMapper.selectDefectAnalysisData(startTime, endTime); + + // 生成日期范围 + List dateRange = generateDateRange(startTime, endTime); + + // 构建表格数据 + List> tableData = buildTableData(analysisData, inspectionTypes, dateRange); + + // 构建日期列信息 + List dateColumns = buildDateColumns(dateRange); + + // 构建图表数据 + DefectAnalysisReportVo.ChartData chartData = buildChartData(analysisData, dateRange); + + DefectAnalysisReportVo reportVo = new DefectAnalysisReportVo(); + reportVo.setTableData(tableData); + reportVo.setDateColumns(dateColumns); + reportVo.setInspectionTypes(inspectionTypes); + reportVo.setChartData(chartData); + + return reportVo; + } + + private List generateDateRange(String startTime, String endTime) { + List dateRange = new ArrayList<>(); + LocalDate start = LocalDate.parse(startTime); + LocalDate end = LocalDate.parse(endTime); + + LocalDate current = start; + while (!current.isAfter(end)) { + dateRange.add(current.toString()); + current = current.plusDays(1); + } + + return dateRange; + } + + private List> buildTableData(List analysisData, + List inspectionTypes, + List dateRange) { + List> tableData = new ArrayList<>(); + + // 按指标类型分组数据 + Map>> groupedData = analysisData.stream() + .collect(Collectors.groupingBy( + DefectAnalysisDto::getMetric, + Collectors.groupingBy( + DefectAnalysisDto::getBizDate, + Collectors.toMap( + DefectAnalysisDto::getTypeName, + DefectAnalysisDto::getValue, + (v1, v2) -> v1 + ) + ) + )); + + // 构建检验数量行 + Map inspectionRow = new HashMap<>(); + inspectionRow.put("metric", "检验数量 (单位: 个)"); + BigDecimal totalInspection = BigDecimal.ZERO; + + for (String date : dateRange) { + BigDecimal dayTotal = BigDecimal.ZERO; + Map> dateData = groupedData.get("检验数量(单位:个)"); + if (dateData != null && dateData.containsKey(date)) { + for (String type : inspectionTypes) { + BigDecimal value = dateData.get(date).getOrDefault(type, BigDecimal.ZERO); + dayTotal = dayTotal.add(value); + } + } + inspectionRow.put(date, dayTotal); + totalInspection = totalInspection.add(dayTotal); + } + inspectionRow.put("total", totalInspection); + tableData.add(inspectionRow); + + // 构建不良数量行 + Map defectRow = new HashMap<>(); + defectRow.put("metric", "不良数量 (单位: 个)"); + BigDecimal totalDefect = BigDecimal.ZERO; + + for (String date : dateRange) { + BigDecimal dayTotal = BigDecimal.ZERO; + Map> dateData = groupedData.get("不合格数(单位:个)"); + if (dateData != null && dateData.containsKey(date)) { + for (String type : inspectionTypes) { + BigDecimal value = dateData.get(date).getOrDefault(type, BigDecimal.ZERO); + dayTotal = dayTotal.add(value); + } + } + defectRow.put(date, dayTotal); + totalDefect = totalDefect.add(dayTotal); + } + defectRow.put("total", totalDefect); + tableData.add(defectRow); + + // 构建不良率行 + Map rateRow = new HashMap<>(); + rateRow.put("metric", "不良率 (单位: %)"); + + for (String date : dateRange) { + BigDecimal inspectionQty = (BigDecimal) inspectionRow.get(date); + BigDecimal defectQty = (BigDecimal) defectRow.get(date); + + if (inspectionQty.compareTo(BigDecimal.ZERO) > 0) { + BigDecimal rate = defectQty.divide(inspectionQty, 4, RoundingMode.HALF_UP).multiply(new BigDecimal(100)); + rateRow.put(date, rate.setScale(2, RoundingMode.HALF_UP)); + } else { + rateRow.put(date, BigDecimal.ZERO); + } + } + + // 计算总不良率 + if (totalInspection.compareTo(BigDecimal.ZERO) > 0) { + BigDecimal totalRate = totalDefect.divide(totalInspection, 4, RoundingMode.HALF_UP).multiply(new BigDecimal(100)); + rateRow.put("total", totalRate.setScale(2, RoundingMode.HALF_UP)); + } else { + rateRow.put("total", BigDecimal.ZERO); + } + tableData.add(rateRow); + + // 构建各检测类型行 + for (String type : inspectionTypes) { + Map typeRow = new HashMap<>(); + typeRow.put("metric", type + " (单位: 个)"); + BigDecimal typeTotal = BigDecimal.ZERO; + + for (String date : dateRange) { + BigDecimal value = BigDecimal.ZERO; + Map> dateData = groupedData.get("检验数量(单位:个)"); + if (dateData != null && dateData.containsKey(date)) { + value = dateData.get(date).getOrDefault(type, BigDecimal.ZERO); + } + typeRow.put(date, value); + typeTotal = typeTotal.add(value); + } + typeRow.put("total", typeTotal); + tableData.add(typeRow); + } + + return tableData; + } + + private List buildDateColumns(List dateRange) { + return dateRange.stream().map(date -> { + DefectAnalysisReportVo.DateColumnInfo columnInfo = new DefectAnalysisReportVo.DateColumnInfo(); + columnInfo.setDate(LocalDate.parse(date).format(DateTimeFormatter.ofPattern("M月d日"))); + columnInfo.setDayOfWeek(getDayOfWeek(date)); + columnInfo.setProp(date); + return columnInfo; + }).collect(Collectors.toList()); + } + + private DefectAnalysisReportVo.ChartData buildChartData(List analysisData, List dateRange) { + DefectAnalysisReportVo.ChartData chartData = new DefectAnalysisReportVo.ChartData(); + + List dates = dateRange.stream() + .map(date -> LocalDate.parse(date).format(DateTimeFormatter.ofPattern("M月d日"))) + .collect(Collectors.toList()); + + List inspectionData = new ArrayList<>(); + List defectData = new ArrayList<>(); + List defectRateData = new ArrayList<>(); + + // 按日期和指标分组数据 + Map> dailyData = new HashMap<>(); + + for (DefectAnalysisDto data : analysisData) { + dailyData.computeIfAbsent(data.getBizDate(), k -> new HashMap<>()) + .merge(data.getMetric(), data.getValue(), BigDecimal::add); + } + + for (String date : dateRange) { + Map dayData = dailyData.getOrDefault(date, new HashMap<>()); + + BigDecimal inspection = dayData.getOrDefault("检验数量(单位:个)", BigDecimal.ZERO); + BigDecimal defect = dayData.getOrDefault("不合格数(单位:个)", BigDecimal.ZERO); + + inspectionData.add(inspection); + defectData.add(defect); + + if (inspection.compareTo(BigDecimal.ZERO) > 0) { + BigDecimal rate = defect.divide(inspection, 4, RoundingMode.HALF_UP).multiply(new BigDecimal(100)); + defectRateData.add(rate.setScale(2, RoundingMode.HALF_UP)); + } else { + defectRateData.add(BigDecimal.ZERO); + } + } + + chartData.setDates(dates); + chartData.setInspectionData(inspectionData); + chartData.setDefectData(defectData); + chartData.setDefectRateData(defectRateData); + + return chartData; + } + + private String getDayOfWeek(String dateStr) { + LocalDate date = LocalDate.parse(dateStr, DateTimeFormatter.ofPattern("yyyy-MM-dd")); + return date.getDayOfWeek().getDisplayName(TextStyle.FULL, Locale.CHINESE); + } +} diff --git a/ruoyi-modules/hwmom-qms/src/main/resources/mapper/qms/ReportMapper.xml b/ruoyi-modules/hwmom-qms/src/main/resources/mapper/qms/ReportMapper.xml new file mode 100644 index 00000000..5a0a0648 --- /dev/null +++ b/ruoyi-modules/hwmom-qms/src/main/resources/mapper/qms/ReportMapper.xml @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + +