feat(report): 新增质检报表功能模块
- 新增QmsReportController,提供IQC、PDI、工单、超时统计报表接口 - 实现QmsReportControllerService,完成IQC报表核心逻辑计算 - 设计QmsIqcReportVO、QmsPdiReportVO、QmsTicketReportVO、QmsOverdueReportVO数据结构 - 增加QmsReportMapper及对应XML,实现检测项分布和物料不合格率数据库查询 - 支持时间区间、周度合格率、供应商和检测人统计等多维度报表数据计算 - 针对IQC报表实现总工单、已完成、待检测数合格率等关键指标统计及变化率分析 - PDI、工单和超时统计报表接口预留,待后续功能完善
This commit is contained in:
parent
59849f0136
commit
ac7c021bd1
|
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
@ -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 {
|
||||||
|
/**
|
||||||
|
* 周数(week1、week2...)
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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 {
|
||||||
|
/**
|
||||||
|
* 周数(week1、week2...)
|
||||||
|
*/
|
||||||
|
private String week;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 合格率(百分比)
|
||||||
|
*/
|
||||||
|
private Double passRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 部件描述比例
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public static class ComponentDistribution {
|
||||||
|
/**
|
||||||
|
* 机型编号
|
||||||
|
*/
|
||||||
|
private String machineNo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 占比(百分比)
|
||||||
|
*/
|
||||||
|
private Double percentage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
@ -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 >= #{startTime}
|
||||||
|
AND t.submit_time <= #{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 >= #{startTime}
|
||||||
|
AND t.submit_time <= #{endTime}
|
||||||
|
GROUP BY mc.name
|
||||||
|
ORDER BY failCount DESC
|
||||||
|
</select>
|
||||||
|
|
||||||
|
</mapper>
|
||||||
Loading…
Reference in New Issue