feat(report): 新增质检报表功能模块

- 新增QmsReportController,提供IQC、PDI、工单、超时统计报表接口
- 实现QmsReportControllerService,完成IQC报表核心逻辑计算
- 设计QmsIqcReportVO、QmsPdiReportVO、QmsTicketReportVO、QmsOverdueReportVO数据结构
- 增加QmsReportMapper及对应XML,实现检测项分布和物料不合格率数据库查询
- 支持时间区间、周度合格率、供应商和检测人统计等多维度报表数据计算
- 针对IQC报表实现总工单、已完成、待检测数合格率等关键指标统计及变化率分析
- PDI、工单和超时统计报表接口预留,待后续功能完善
This commit is contained in:
funny 2026-05-15 17:58:00 +08:00
parent 59849f0136
commit ac7c021bd1
9 changed files with 1037 additions and 0 deletions

View File

@ -0,0 +1,56 @@
package com.nflg.qms.admin.controller;
import com.nflg.qms.admin.service.QmsReportControllerService;
import com.nflg.wms.common.pojo.ApiResult;
import com.nflg.wms.common.pojo.qo.QmsReportQueryQO;
import com.nflg.wms.common.pojo.vo.*;
import com.nflg.wms.starter.BaseController;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
/**
* 报表管理
*/
@RestController
@RequestMapping("/report")
public class QmsReportController extends BaseController {
@Resource
private QmsReportControllerService reportControllerService;
/**
* IQC报表数据
*/
@PostMapping("iqc")
public ApiResult<QmsIqcReportVO> getIqcReport(@Valid @RequestBody QmsReportQueryQO request) {
return ApiResult.success(reportControllerService.getIqcReport(request));
}
/**
* PDI报表数据
*/
@PostMapping("pdi")
public ApiResult<QmsPdiReportVO> getPdiReport(@Valid @RequestBody QmsReportQueryQO request) {
return ApiResult.success(reportControllerService.getPdiReport(request));
}
/**
* 工单报表数据
*/
@PostMapping("ticket")
public ApiResult<QmsTicketReportVO> getTicketReport(@Valid @RequestBody QmsReportQueryQO request) {
return ApiResult.success(reportControllerService.getTicketReport(request));
}
/**
* 超时统计数据
*/
@PostMapping("overdue")
public ApiResult<QmsOverdueReportVO> getOverdueReport() {
return ApiResult.success(reportControllerService.getOverdueReport());
}
}

View File

@ -0,0 +1,469 @@
package com.nflg.qms.admin.service;
import com.nflg.wms.common.pojo.qo.QmsReportQueryQO;
import com.nflg.wms.common.pojo.vo.*;
import com.nflg.wms.repository.entity.*;
import com.nflg.wms.repository.service.*;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import java.time.DayOfWeek;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.stream.Collectors;
/**
* 报表管理 ControllerService
*/
@Service
public class QmsReportControllerService {
@Resource
private IQmsIncomingInspectionTaskService incomingInspectionTaskService;
@Resource
private IQmsQcMaterialService qcMaterialService;
@Resource
private IQmsQcMaterialCategoryService qcMaterialCategoryService;
@Resource
private IQmsIncomingInspectionTaskRecordService incomingInspectionTaskRecordService;
@Resource
private IQmsIncomingInspectionTaskRecordItemService incomingInspectionTaskRecordItemService;
@Resource
private IQmsInspectionStandardItemContentService inspectionStandardItemContentService;
@Resource
private com.nflg.wms.repository.mapper.QmsReportMapper reportMapper;
@Resource
private IUserService userService;
/**
* IQC报表数据
*/
public QmsIqcReportVO getIqcReport(QmsReportQueryQO request) {
QmsIqcReportVO vo = new QmsIqcReportVO();
// 计算时间范围
LocalDateTime currentStart = request.getStartTime();
LocalDateTime currentEnd = request.getEndTime();
boolean hasTimeRange = currentStart != null || currentEnd != null;
// 如果都没传查询全部
if (!hasTimeRange) {
currentStart = LocalDateTime.MIN;
currentEnd = LocalDateTime.MAX;
} else {
if (currentStart == null) currentStart = LocalDateTime.MIN;
if (currentEnd == null) currentEnd = LocalDateTime.MAX;
}
// 计算上周期
long daysBetween = java.time.temporal.ChronoUnit.DAYS.between(currentStart, currentEnd);
LocalDateTime previousStart = currentStart.minusDays(daysBetween);
LocalDateTime previousEnd = currentStart;
// 1. 总工单统计
Map<String, Object> totalStats = calculateTotalTasks(currentStart, currentEnd, previousStart, previousEnd, hasTimeRange);
vo.setTotalTasks((Integer) totalStats.get("currentTotal"));
vo.setPreviousTotalTasks((Integer) totalStats.get("previousTotal"));
vo.setTotalTasksChangeRate((Double) totalStats.get("changeRate"));
// 2. 已完成数统计
Map<String, Object> completedStats = calculateCompletedTasks(currentStart, currentEnd, previousStart, previousEnd, hasTimeRange);
vo.setCompletedCount((Integer) completedStats.get("currentCompleted"));
vo.setPreviousCompletedCount((Integer) completedStats.get("previousCompleted"));
vo.setCompletedChangeRate((Double) completedStats.get("changeRate"));
vo.setAvgCompletedTime((String) completedStats.get("avgTime"));
// 3. 待检测任务数
vo.setPendingCount(calculatePendingTasks(currentStart, currentEnd));
// 4. 合格率
vo.setPassRate(calculatePassRate(currentStart, currentEnd));
// 5. 每周合格率
vo.setWeeklyPassRates(calculateWeeklyPassRates(currentStart, currentEnd));
// 6. 检测分布类别前5
vo.setCategoryDistributions(calculateCategoryDistribution(currentStart, currentEnd));
// 7. 供应商合格率最高5+最低2
vo.setSupplierPassRates(calculateSupplierPassRate(currentStart, currentEnd));
// 8. 物料类别不合格率前5
vo.setMaterialCategoryFailRates(calculateMaterialCategoryFailRate(currentStart, currentEnd));
// 9. 检测人效率前5
vo.setInspectorEfficiencies(calculateInspectorEfficiency(currentStart, currentEnd));
return vo;
}
/**
* 计算总工单统计
*/
private Map<String, Object> calculateTotalTasks(LocalDateTime currentStart, LocalDateTime currentEnd,
LocalDateTime previousStart, LocalDateTime previousEnd,
boolean hasTimeRange) {
Map<String, Object> result = new HashMap<>();
// 当前周期总工单
long currentTotal = incomingInspectionTaskService.lambdaQuery()
.ge(QmsIncomingInspectionTask::getSubmitTime, currentStart)
.le(QmsIncomingInspectionTask::getSubmitTime, currentEnd)
.count();
// 上周期总工单
long previousTotal = 0;
if (hasTimeRange) {
previousTotal = incomingInspectionTaskService.lambdaQuery()
.ge(QmsIncomingInspectionTask::getSubmitTime, previousStart)
.le(QmsIncomingInspectionTask::getSubmitTime, previousEnd)
.count();
}
// 增减百分比
double changeRate = 0;
if (previousTotal > 0) {
changeRate = ((double) (currentTotal - previousTotal) / previousTotal) * 100;
}
result.put("currentTotal", (int) currentTotal);
result.put("previousTotal", (int) previousTotal);
result.put("changeRate", changeRate);
return result;
}
/**
* 计算已完成任务统计
*/
private Map<String, Object> calculateCompletedTasks(LocalDateTime currentStart, LocalDateTime currentEnd,
LocalDateTime previousStart, LocalDateTime previousEnd,
boolean hasTimeRange) {
Map<String, Object> result = new HashMap<>();
// 当前周期已完成
long currentCompleted = incomingInspectionTaskService.lambdaQuery()
.eq(QmsIncomingInspectionTask::getInspectionStatus, (short) 2)
.ge(QmsIncomingInspectionTask::getSubmitTime, currentStart)
.le(QmsIncomingInspectionTask::getSubmitTime, currentEnd)
.count();
// 上周期已完成
long previousCompleted = 0;
if (hasTimeRange) {
previousCompleted = incomingInspectionTaskService.lambdaQuery()
.eq(QmsIncomingInspectionTask::getInspectionStatus, (short) 2)
.ge(QmsIncomingInspectionTask::getSubmitTime, previousStart)
.le(QmsIncomingInspectionTask::getSubmitTime, previousEnd)
.count();
}
// 增减百分比
double changeRate = 0;
if (previousCompleted > 0) {
changeRate = ((double) (currentCompleted - previousCompleted) / previousCompleted) * 100;
}
// 平均耗时当前周期
String avgTime = "0小时0分钟";
if (currentCompleted > 0) {
List<QmsIncomingInspectionTask> completedTasks = incomingInspectionTaskService.lambdaQuery()
.eq(QmsIncomingInspectionTask::getInspectionStatus, (short) 2)
.ge(QmsIncomingInspectionTask::getSubmitTime, currentStart)
.le(QmsIncomingInspectionTask::getSubmitTime, currentEnd)
.isNotNull(QmsIncomingInspectionTask::getInspectionStartTime)
.isNotNull(QmsIncomingInspectionTask::getInspectionFinishTime)
.list();
if (!completedTasks.isEmpty()) {
long totalSeconds = 0;
for (QmsIncomingInspectionTask task : completedTasks) {
Duration duration = Duration.between(task.getInspectionStartTime(), task.getInspectionFinishTime());
totalSeconds += duration.getSeconds();
}
long avgSeconds = totalSeconds / completedTasks.size();
avgTime = formatDuration(avgSeconds);
}
}
result.put("currentCompleted", (int) currentCompleted);
result.put("previousCompleted", (int) previousCompleted);
result.put("changeRate", changeRate);
result.put("avgTime", avgTime);
return result;
}
/**
* 计算待检测任务数
*/
private int calculatePendingTasks(LocalDateTime currentStart, LocalDateTime currentEnd) {
long count = incomingInspectionTaskService.lambdaQuery()
.in(QmsIncomingInspectionTask::getInspectionStatus, (short) 0, (short) 1)
.ge(QmsIncomingInspectionTask::getSubmitTime, currentStart)
.le(QmsIncomingInspectionTask::getSubmitTime, currentEnd)
.count();
return (int) count;
}
/**
* 计算合格率
*/
private double calculatePassRate(LocalDateTime currentStart, LocalDateTime currentEnd) {
long completedCount = incomingInspectionTaskService.lambdaQuery()
.eq(QmsIncomingInspectionTask::getInspectionStatus, (short) 2)
.ge(QmsIncomingInspectionTask::getSubmitTime, currentStart)
.le(QmsIncomingInspectionTask::getSubmitTime, currentEnd)
.count();
if (completedCount == 0) return 0;
long qualifiedCount = incomingInspectionTaskService.lambdaQuery()
.eq(QmsIncomingInspectionTask::getInspectionStatus, (short) 2)
.eq(QmsIncomingInspectionTask::getInspectionResult, true)
.ge(QmsIncomingInspectionTask::getSubmitTime, currentStart)
.le(QmsIncomingInspectionTask::getSubmitTime, currentEnd)
.count();
return ((double) qualifiedCount / completedCount) * 100;
}
/**
* 计算每周合格率
*/
private List<QmsIqcReportVO.WeeklyPassRate> calculateWeeklyPassRates(LocalDateTime currentStart, LocalDateTime currentEnd) {
// 补全到完整的周
LocalDateTime weekStart = currentStart.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
LocalDateTime weekEnd = currentEnd.with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY));
List<QmsIqcReportVO.WeeklyPassRate> weeklyRates = new ArrayList<>();
// 按周遍历
LocalDateTime currentWeekStart = weekStart;
int weekNum = 1;
while (currentWeekStart.isBefore(weekEnd) || currentWeekStart.isEqual(weekEnd)) {
LocalDateTime currentWeekEnd = currentWeekStart.plusDays(6).withHour(23).withMinute(59).withSecond(59);
// 该周已完成数
long weekCompleted = incomingInspectionTaskService.lambdaQuery()
.eq(QmsIncomingInspectionTask::getInspectionStatus, (short) 2)
.ge(QmsIncomingInspectionTask::getSubmitTime, currentWeekStart)
.le(QmsIncomingInspectionTask::getSubmitTime, currentWeekEnd)
.count();
// 该周合格数
long weekQualified = 0;
if (weekCompleted > 0) {
weekQualified = incomingInspectionTaskService.lambdaQuery()
.eq(QmsIncomingInspectionTask::getInspectionStatus, (short) 2)
.eq(QmsIncomingInspectionTask::getInspectionResult, true)
.ge(QmsIncomingInspectionTask::getSubmitTime, currentWeekStart)
.le(QmsIncomingInspectionTask::getSubmitTime, currentWeekEnd)
.count();
}
double passRate = weekCompleted > 0 ? ((double) weekQualified / weekCompleted) * 100 : 0;
QmsIqcReportVO.WeeklyPassRate weekRate = new QmsIqcReportVO.WeeklyPassRate();
weekRate.setWeek("week" + weekNum);
weekRate.setPassRate(passRate);
weeklyRates.add(weekRate);
currentWeekStart = currentWeekEnd.plusSeconds(1);
weekNum++;
}
return weeklyRates;
}
/**
* 计算检测分布类别前5
*/
private List<QmsIqcReportVO.InspectionCategoryDistribution> calculateCategoryDistribution(LocalDateTime currentStart, LocalDateTime currentEnd) {
List<Map<String, Object>> results = reportMapper.getInspectionItemDistribution(currentStart, currentEnd);
// 只取前5项
List<Map<String, Object>> top5 = results.stream().limit(5).collect(Collectors.toList());
// 计算前5项的总数
long top5Total = top5.stream()
.mapToLong(m -> ((Number) m.get("itemCount")).longValue())
.sum();
List<QmsIqcReportVO.InspectionCategoryDistribution> distributions = new ArrayList<>();
for (Map<String, Object> row : top5) {
QmsIqcReportVO.InspectionCategoryDistribution dist = new QmsIqcReportVO.InspectionCategoryDistribution();
dist.setItemName((String) row.get("itemName"));
long itemCount = ((Number) row.get("itemCount")).longValue();
double percentage = top5Total > 0 ? ((double) itemCount / top5Total) * 100 : 0;
dist.setPercentage(percentage);
distributions.add(dist);
}
return distributions;
}
/**
* 计算供应商合格率最高5+最低2
*/
private List<QmsIqcReportVO.SupplierPassRate> calculateSupplierPassRate(LocalDateTime currentStart, LocalDateTime currentEnd) {
// 查询所有供应商
List<QmsIncomingInspectionTask> tasks = incomingInspectionTaskService.lambdaQuery()
.ge(QmsIncomingInspectionTask::getSubmitTime, currentStart)
.le(QmsIncomingInspectionTask::getSubmitTime, currentEnd)
.isNotNull(QmsIncomingInspectionTask::getSupplierCode)
.list();
// 按供应商分组统计
Map<String, List<QmsIncomingInspectionTask>> supplierMap = tasks.stream()
.collect(Collectors.groupingBy(QmsIncomingInspectionTask::getSupplierCode));
List<QmsIqcReportVO.SupplierPassRate> supplierRates = new ArrayList<>();
for (Map.Entry<String, List<QmsIncomingInspectionTask>> entry : supplierMap.entrySet()) {
String supplierCode = entry.getKey();
List<QmsIncomingInspectionTask> supplierTasks = entry.getValue();
long total = supplierTasks.size();
long qualified = supplierTasks.stream()
.filter(t -> Boolean.TRUE.equals(t.getInspectionResult()))
.count();
double passRate = total > 0 ? ((double) qualified / total) * 100 : 0;
QmsIqcReportVO.SupplierPassRate rate = new QmsIqcReportVO.SupplierPassRate();
rate.setSupplierCode(supplierCode);
rate.setSupplierName(supplierTasks.get(0).getSupplierName());
rate.setPassRate(passRate);
supplierRates.add(rate);
}
// 排序按合格率降序
supplierRates.sort(Comparator.comparingDouble(QmsIqcReportVO.SupplierPassRate::getPassRate).reversed()
.thenComparing(QmsIqcReportVO.SupplierPassRate::getSupplierCode));
// 取最高5个
List<QmsIqcReportVO.SupplierPassRate> top5 = supplierRates.stream().limit(5).collect(Collectors.toList());
// 取最低2个如果总数>5
List<QmsIqcReportVO.SupplierPassRate> bottom2 = new ArrayList<>();
if (supplierRates.size() > 5) {
bottom2 = supplierRates.stream()
.skip(Math.max(0, supplierRates.size() - 2))
.collect(Collectors.toList());
}
// 合并
List<QmsIqcReportVO.SupplierPassRate> result = new ArrayList<>(top5);
result.addAll(bottom2);
return result;
}
/**
* 计算物料类别不合格率前5
*/
private List<QmsIqcReportVO.MaterialCategoryFailRate> calculateMaterialCategoryFailRate(LocalDateTime currentStart, LocalDateTime currentEnd) {
List<Map<String, Object>> results = reportMapper.getMaterialCategoryFailRate(currentStart, currentEnd);
// 只取前5个不合格数量最多的
List<Map<String, Object>> top5 = results.stream().limit(5).collect(Collectors.toList());
// 计算前5个的不合格总数
long top5FailTotal = top5.stream()
.mapToLong(m -> ((Number) m.get("failCount")).longValue())
.sum();
List<QmsIqcReportVO.MaterialCategoryFailRate> failRates = new ArrayList<>();
for (Map<String, Object> row : top5) {
QmsIqcReportVO.MaterialCategoryFailRate rate = new QmsIqcReportVO.MaterialCategoryFailRate();
rate.setCategoryName((String) row.get("categoryName"));
long failCount = ((Number) row.get("failCount")).longValue();
double failRate = top5FailTotal > 0 ? ((double) failCount / top5FailTotal) * 100 : 0;
rate.setFailRate(failRate);
failRates.add(rate);
}
return failRates;
}
/**
* 计算检测人效率前5
*/
private List<QmsIqcReportVO.InspectorEfficiency> calculateInspectorEfficiency(LocalDateTime currentStart, LocalDateTime currentEnd) {
// 查询所有任务
List<QmsIncomingInspectionTask> tasks = incomingInspectionTaskService.lambdaQuery()
.ge(QmsIncomingInspectionTask::getSubmitTime, currentStart)
.le(QmsIncomingInspectionTask::getSubmitTime, currentEnd)
.isNotNull(QmsIncomingInspectionTask::getInspectorId)
.list();
// 按检测人分组统计
Map<Long, List<QmsIncomingInspectionTask>> inspectorMap = tasks.stream()
.collect(Collectors.groupingBy(QmsIncomingInspectionTask::getInspectorId));
List<QmsIqcReportVO.InspectorEfficiency> efficiencies = new ArrayList<>();
for (Map.Entry<Long, List<QmsIncomingInspectionTask>> entry : inspectorMap.entrySet()) {
Long inspectorId = entry.getKey();
List<QmsIncomingInspectionTask> inspectorTasks = entry.getValue();
long total = inspectorTasks.size();
long completed = inspectorTasks.stream()
.filter(t -> t.getInspectionStatus() != null && t.getInspectionStatus() == 2)
.count();
double efficiency = total > 0 ? ((double) completed / total) * 100 : 0;
QmsIqcReportVO.InspectorEfficiency eff = new QmsIqcReportVO.InspectorEfficiency();
eff.setInspectorId(inspectorId);
eff.setInspectorName(inspectorTasks.get(0).getInspectorName());
eff.setCompletedCount((int) completed);
eff.setEfficiency(efficiency);
efficiencies.add(eff);
}
// 按效率降序取前5
efficiencies.sort(Comparator.comparingDouble(QmsIqcReportVO.InspectorEfficiency::getEfficiency).reversed());
return efficiencies.stream().limit(5).collect(Collectors.toList());
}
/**
* 格式化时长 -> xx小时xx分钟
*/
private String formatDuration(long seconds) {
long hours = seconds / 3600;
long minutes = (seconds % 3600) / 60;
return hours + "小时" + minutes + "分钟";
}
/**
* PDI报表数据
*/
public QmsPdiReportVO getPdiReport(QmsReportQueryQO request) {
// TODO: 实现逻辑
return new QmsPdiReportVO();
}
/**
* 工单报表数据
*/
public QmsTicketReportVO getTicketReport(QmsReportQueryQO request) {
// TODO: 实现逻辑
return new QmsTicketReportVO();
}
/**
* 超时统计数据
*/
public QmsOverdueReportVO getOverdueReport() {
// TODO: 实现逻辑
return new QmsOverdueReportVO();
}
}

View File

@ -0,0 +1,22 @@
package com.nflg.wms.common.pojo.qo;
import lombok.Data;
import java.time.LocalDateTime;
/**
* 报表查询请求QO
*/
@Data
public class QmsReportQueryQO {
/**
* 开始时间可选
*/
private LocalDateTime startTime;
/**
* 结束时间可选
*/
private LocalDateTime endTime;
}

View File

@ -0,0 +1,152 @@
package com.nflg.wms.common.pojo.vo;
import lombok.Data;
import java.util.List;
/**
* IQC报表VO
*/
@Data
public class QmsIqcReportVO {
/**
* 总工单数
*/
private Integer totalTasks;
/**
* 已完成数
*/
private Integer completedCount;
/**
* 待检测任务数
*/
private Integer pendingCount;
/**
* 合格率百分比
*/
private Double passRate;
/**
* 每周合格率列表
*/
private List<WeeklyPassRate> weeklyPassRates;
/**
* 检测分布类别列表
*/
private List<InspectionCategoryDistribution> categoryDistributions;
/**
* 供应商合格率列表
*/
private List<SupplierPassRate> supplierPassRates;
/**
* 物料类别不合格率列表
*/
private List<MaterialCategoryFailRate> materialCategoryFailRates;
/**
* 检测人效率列表
*/
private List<InspectorEfficiency> inspectorEfficiencies;
/**
* 每周合格率
*/
@Data
public static class WeeklyPassRate {
/**
* 周数week1week2...
*/
private String week;
/**
* 合格率百分比
*/
private Double passRate;
}
/**
* 检测分布类别
*/
@Data
public static class InspectionCategoryDistribution {
/**
* 检测项名称
*/
private String itemName;
/**
* 占比百分比
*/
private Double percentage;
}
/**
* 供应商合格率
*/
@Data
public static class SupplierPassRate {
/**
* 供应商编码
*/
private String supplierCode;
/**
* 供应商名称
*/
private String supplierName;
/**
* 合格率百分比
*/
private Double passRate;
}
/**
* 物料类别不合格率
*/
@Data
public static class MaterialCategoryFailRate {
/**
* 物料类别名称
*/
private String categoryName;
/**
* 不合格率百分比
*/
private Double failRate;
}
/**
* 检测人效率
*/
@Data
public static class InspectorEfficiency {
/**
* 检测人姓名
*/
private String inspectorName;
/**
* 检测人ID
*/
private Long inspectorId;
/**
* 完成数量
*/
private Integer completedCount;
/**
* 效率百分比
*/
private Double efficiency;
}
}

View File

@ -0,0 +1,83 @@
package com.nflg.wms.common.pojo.vo;
import lombok.Data;
import java.util.List;
/**
* 超时统计报表VO
*/
@Data
public class QmsOverdueReportVO {
/**
* 超时任务总数
*/
private Integer totalOverdueCount;
/**
* 平均超时时间格式xx小时xx分钟xx秒
*/
private String avgOverdueTime;
/**
* 严重超时数阈值待定
*/
private Integer severeOverdueCount;
/**
* IQC超时任务列表
*/
private List<OverdueTaskItem> iqcOverdueTasks;
/**
* PDI超时任务列表
*/
private List<OverdueTaskItem> pdiOverdueTasks;
/**
* 工单超时任务列表
*/
private List<OverdueTaskItem> ticketOverdueTasks;
/**
* 超时任务项
*/
@Data
public static class OverdueTaskItem {
/**
* 工单编号
*/
private String taskNo;
/**
* 类型IQC/PDI/工单类型
*/
private String type;
/**
* 处理人姓名列表
*/
private List<String> handlerNames;
/**
* 处理人ID列表
*/
private List<Long> handlerIds;
/**
* 创建日期
*/
private String createDate;
/**
* 要求完成时间
*/
private String requiredCompletionTime;
/**
* 超时时长格式xx小时xx分钟xx秒
*/
private String overdueDuration;
}
}

View File

@ -0,0 +1,84 @@
package com.nflg.wms.common.pojo.vo;
import lombok.Data;
import java.util.List;
/**
* PDI报表VO
*/
@Data
public class QmsPdiReportVO {
/**
* 总单数
*/
private Integer totalTasks;
/**
* 已完成检测数
*/
private Integer completedCount;
/**
* 待检数量
*/
private Integer pendingCount;
/**
* 平均检测时间格式xx小时xx分钟xx秒
*/
private String avgInspectionTime;
/**
* 计划达成率百分比
*/
private Double planCompletionRate;
/**
* 不合格率百分比
*/
private Double failRate;
/**
* 每周合格率列表
*/
private List<WeeklyPassRate> weeklyPassRates;
/**
* 部件描述比例列表
*/
private List<ComponentDistribution> componentDistributions;
/**
* 每周合格率
*/
@Data
public static class WeeklyPassRate {
/**
* 周数week1week2...
*/
private String week;
/**
* 合格率百分比
*/
private Double passRate;
}
/**
* 部件描述比例
*/
@Data
public static class ComponentDistribution {
/**
* 机型编号
*/
private String machineNo;
/**
* 占比百分比
*/
private Double percentage;
}
}

View File

@ -0,0 +1,110 @@
package com.nflg.wms.common.pojo.vo;
import lombok.Data;
import java.util.List;
/**
* 工单报表VO
*/
@Data
public class QmsTicketReportVO {
/**
* 总工单数
*/
private Integer totalTickets;
/**
* 已完成数
*/
private Integer completedCount;
/**
* 未完成数
*/
private Integer unfinishedCount;
/**
* 总体完成率百分比
*/
private Double completionRate;
/**
* 平均处理耗时格式xx小时xx分钟xx秒
*/
private String avgProcessingTime;
/**
* 各状态占比列表
*/
private List<StatusDistribution> statusDistributions;
/**
* 问题类别数量列表
*/
private List<IssueTypeCount> issueTypeCounts;
/**
* 用户完成率列表
*/
private List<UserCompletionRate> userCompletionRates;
/**
* 状态分布
*/
@Data
public static class StatusDistribution {
/**
* 状态0=待流转,1=处理中,2=已完成
*/
private Short status;
/**
* 状态名称
*/
private String statusName;
/**
* 占比百分比
*/
private Double percentage;
}
/**
* 问题类别数量
*/
@Data
public static class IssueTypeCount {
/**
* 问题类别名称
*/
private String issueTypeName;
/**
* 数量
*/
private Integer count;
}
/**
* 用户完成率
*/
@Data
public static class UserCompletionRate {
/**
* 用户姓名
*/
private String userName;
/**
* 用户ID
*/
private Long userId;
/**
* 完成率百分比
*/
private Double completionRate;
}
}

View File

@ -0,0 +1,27 @@
package com.nflg.wms.repository.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.nflg.wms.repository.entity.QmsIncomingInspectionTask;
import org.apache.ibatis.annotations.Param;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
/**
* 报表统计 Mapper
*/
public interface QmsReportMapper extends BaseMapper<QmsIncomingInspectionTask> {
/**
* 查询检测项分布按检测项名称统计数量
*/
List<Map<String, Object>> getInspectionItemDistribution(@Param("startTime") LocalDateTime startTime,
@Param("endTime") LocalDateTime endTime);
/**
* 查询物料类别不合格率
*/
List<Map<String, Object>> getMaterialCategoryFailRate(@Param("startTime") LocalDateTime startTime,
@Param("endTime") LocalDateTime endTime);
}

View File

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.nflg.wms.repository.mapper.QmsReportMapper">
<!-- 查询检测项分布(按检测项名称统计数量) -->
<select id="getInspectionItemDistribution" resultType="map">
SELECT
sic.name AS itemName,
COUNT(*) AS itemCount
FROM qms_incoming_inspection_task t
INNER JOIN qms_incoming_inspection_task_record r ON r.task_id = t.id
INNER JOIN qms_incoming_inspection_task_record_item ri ON ri.record_id = r.id
INNER JOIN qms_inspection_standard_item_content sic ON sic.id = ri.inspection_standard_item_content_id
WHERE t.submit_time &gt;= #{startTime}
AND t.submit_time &lt;= #{endTime}
GROUP BY sic.name
ORDER BY itemCount DESC
</select>
<!-- 查询物料类别不合格率(按不合格数量排序) -->
<select id="getMaterialCategoryFailRate" resultType="map">
SELECT
mc.name AS categoryName,
SUM(CASE WHEN t.inspection_result = false THEN 1 ELSE 0 END) AS failCount
FROM qms_incoming_inspection_task t
INNER JOIN qms_qc_material m ON m.id = t.material_id
INNER JOIN qms_qc_material_category mc ON mc.id = m.category_id
WHERE t.submit_time &gt;= #{startTime}
AND t.submit_time &lt;= #{endTime}
GROUP BY mc.name
ORDER BY failCount DESC
</select>
</mapper>