package cn.shlanbao.qms.service.impl; import cn.hutool.core.date.DateUtil; import cn.shlanbao.qms.domain.LbBatch; import cn.shlanbao.qms.domain.LbSensorResult; import cn.shlanbao.qms.domain.LbTestResult; import cn.shlanbao.qms.domain.bo.LbBatchBo; import cn.shlanbao.qms.domain.vo.LbBatchVo; import cn.shlanbao.qms.domain.vo.LbSensorResultVo; import cn.shlanbao.qms.domain.vo.LbTestResultVo; import cn.shlanbao.qms.mapper.LbBatchMapper; import cn.shlanbao.qms.mapper.LbSensorResultMapper; import cn.shlanbao.qms.mapper.LbTestResultMapper; import cn.shlanbao.qms.service.ILbQualityService; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import lombok.RequiredArgsConstructor; import org.dromara.common.core.utils.StringUtils; import org.dromara.common.mybatis.core.page.PageQuery; import org.dromara.common.mybatis.core.page.TableDataInfo; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; import java.text.SimpleDateFormat; import java.util.*; import java.util.stream.Collectors; @RequiredArgsConstructor @Service public class LbQualityServiceImpl implements ILbQualityService { private final LbBatchMapper batchMapper; private final LbSensorResultMapper sensorResultMapper; private final LbTestResultMapper testResultMapper; @Override public Map queryQualityHealth() { Map result = new HashMap<>(2); // 获取当前年份 int currentYear = DateUtil.year(DateUtil.date()); // 构建查询条件:查询当前年份的数据 QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.likeRight("batch_code", String.valueOf(currentYear)); // 查询数据 List sensorResultList = sensorResultMapper.selectVoList(queryWrapper); if (CollectionUtils.isEmpty(sensorResultList)) { result.put("xAxis", Collections.emptyList()); result.put("yAxis", Collections.emptyList()); return result; } // 按年月分组(batch_code前6位) Map> monthlyGroup = sensorResultList.stream() .filter(vo -> vo != null && StringUtils.isNotBlank(vo.getBatchCode())) .collect(Collectors.groupingBy(vo -> vo.getBatchCode().substring(0, 6))); // 准备x轴和y轴数据 List xAxis = new ArrayList<>(); List> yAxis = new ArrayList<>(); // 处理每个月的数据 monthlyGroup.entrySet().stream() .sorted(Map.Entry.comparingByKey()) .forEach(entry -> { String monthKey = entry.getKey(); List monthlyData = entry.getValue(); if (CollectionUtils.isEmpty(monthlyData)) { return; } // 添加x轴数据 xAxis.add(monthKey.substring(4, 6) + "月"); // 计算合格率 long passCount = monthlyData.stream() .filter(vo -> "OK".equalsIgnoreCase(vo.getJudgeResult())) .count(); double passRate = (double) passCount / monthlyData.size(); // 添加y轴数据 Map monthData = new HashMap<>(1); monthData.put("value", String.format("%.1f", (passRate * 10))); yAxis.add(monthData); }); result.put("xAxis", xAxis); result.put("yAxis", yAxis); return result; } @Override public TableDataInfo queryBatchList(LbBatchBo bo, PageQuery pageQuery) { LambdaQueryWrapper lqw = buildQueryWrapper(bo); Page result = batchMapper.selectVoPage(pageQuery.build(), lqw); List records = result.getRecords(); if (records.isEmpty()) { return TableDataInfo.build(result); } List batchCodes = records.stream() .map(LbBatchVo::getBatchCode) .collect(Collectors.toList()); LambdaQueryWrapper sensorResultWrapper = new LambdaQueryWrapper<>(); sensorResultWrapper.in(LbSensorResult::getBatchCode, batchCodes); List sensorResultVoList = sensorResultMapper.selectVoList(sensorResultWrapper); // 一次性统计OK和总数 Map statsMap = sensorResultVoList.stream() .collect(Collectors.groupingBy( LbSensorResultVo::getBatchCode, Collectors.collectingAndThen( Collectors.toList(), list -> { long okCount = list.stream() .filter(vo -> "OK".equals(vo.getJudgeResult())) .count(); return new BatchStats(okCount, list.size()); } ) )); // 批量设置统计结果 records.forEach(item -> { BatchStats stats = statsMap.get(item.getBatchCode()); if (stats != null) { item.setOkNum(stats.okCount); item.setNgNum(stats.totalCount - stats.okCount); } else { // 如果没有相关检测结果,设置为0 item.setOkNum(0L); item.setNgNum(item.getNum()); } }); return TableDataInfo.build(result); } @Override public Map queryPwbatchList() { Map res = new HashMap<>(2); // 准备x轴和y轴数据 List xAxis = new ArrayList<>(); List yAxis = new ArrayList<>(); LambdaQueryWrapper dateQuery = Wrappers.lambdaQuery(); dateQuery.select(LbBatch::getBatchTime) .groupBy(LbBatch::getBatchTime) .orderByDesc(LbBatch::getBatchTime) // 保持倒序查询最近7天 .last("LIMIT 30"); List dateVos = batchMapper.selectVoList(dateQuery); // 从 Vo 对象中提取 batchTime List recentDates = dateVos.stream() .map(LbBatchVo::getBatchTime) .filter(Objects::nonNull) .collect(Collectors.toList()); LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); lqw.in(LbBatch::getBatchTime, recentDates) .orderByAsc(LbBatch::getBatchTime); // 这里改为正序,确保数据按日期顺序 List records = batchMapper.selectVoList(lqw); List batchCodes = records.stream() .map(LbBatchVo::getBatchCode) .collect(Collectors.toList()); LambdaQueryWrapper sensorResultWrapper = new LambdaQueryWrapper<>(); sensorResultWrapper.in(LbSensorResult::getBatchCode, batchCodes); List sensorResultVoList = sensorResultMapper.selectVoList(sensorResultWrapper); // 计算每个日期的OK比例 Map dateOkRatioMap = sensorResultVoList.stream() .collect(Collectors.groupingBy( result -> { String batchCode = result.getBatchCode(); return records.stream() .filter(record -> record.getBatchCode().equals(batchCode)) .findFirst() .map(LbBatchVo::getBatchTime) .orElse(null); }, Collectors.collectingAndThen( Collectors.toList(), list -> { long okCount = list.stream() .filter(result -> "ok".equalsIgnoreCase(result.getJudgeResult())) .count(); return list.size() > 0 ? (double) okCount / list.size() : 0.0; } ) )) .entrySet().stream() .filter(entry -> entry.getKey() != null) .sorted(Map.Entry.comparingByKey()) // 改为正序排序 .collect(Collectors.toMap( Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new )); // 过滤掉yAxis小于80的数据 dateOkRatioMap.entrySet().stream() .filter(entry -> { double ratio = entry.getValue() * 100; // 转换为百分比 return ratio >= 80; // 只保留大于等于80的数据 }) .forEach(entry -> { Date date = entry.getKey(); double ratio = entry.getValue() * 100; // 转换为百分比 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); xAxis.add(sdf.format(date)); yAxis.add(String.format("%.1f", ratio)); }); res.put("xAxis", xAxis); res.put("yAxis", yAxis); return res; } @Override public Map queryNgrankList() { Map res = new HashMap<>(2); LambdaQueryWrapper lqwGroup = Wrappers.lambdaQuery(); lqwGroup.select(LbTestResult::getBatchCode) .groupBy(LbTestResult::getBatchCode) .orderByDesc(LbTestResult::getBatchCode) .last("LIMIT 30"); List groupResultVos = testResultMapper.selectVoList(lqwGroup); List batchCodeList = groupResultVos.stream() .map(LbTestResultVo::getBatchCode) .collect(Collectors.toList()); LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); lqw.in(LbTestResult::getBatchCode, batchCodeList); lqw.eq(LbTestResult::getTestResult, "NG"); List testResultVos = testResultMapper.selectVoList(lqw); // 1. 按testItem分组并统计数量(每行计为1) Map countByTestItem = testResultVos.stream() .filter(result -> "NG".equalsIgnoreCase(result.getTestResult())) .collect(Collectors.groupingBy( LbTestResultVo::getTestItem, Collectors.counting() )); // 2. 按数量降序排序并取前5大 List> top5Entries = countByTestItem.entrySet().stream() .sorted(Map.Entry.comparingByValue().reversed()) .limit(5) .collect(Collectors.toList()); // 3. 生成xAxis和yAxis数组 String[] xAxis = top5Entries.stream() .map(Map.Entry::getKey) .toArray(String[]::new); Long[] yAxis = top5Entries.stream() .map(Map.Entry::getValue) .toArray(Long[]::new); res.put("xAxis", xAxis); res.put("yAxis", yAxis); return res; } // 内部统计类 private static class BatchStats { long okCount; long totalCount; BatchStats(long okCount, long totalCount) { this.okCount = okCount; this.totalCount = totalCount; } } private LambdaQueryWrapper buildQueryWrapper(LbBatchBo bo) { Map params = bo.getParams(); LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); lqw.eq(StringUtils.isNotBlank(bo.getBatchCode()), LbBatch::getBatchCode, bo.getBatchCode()); lqw.eq(StringUtils.isNotBlank(bo.getProdModel()), LbBatch::getProdModel, bo.getProdModel()); lqw.eq(StringUtils.isNotBlank(bo.getDeviceCode()), LbBatch::getDeviceCode, bo.getDeviceCode()); lqw.eq(bo.getUserId() != null, LbBatch::getUserId, bo.getUserId()); lqw.eq(bo.getNum() != null, LbBatch::getNum, bo.getNum()); lqw.orderByDesc(LbBatch::getBatchCode); if (params != null && params.containsKey("startTime") && params.containsKey("endTime")) { lqw.between(LbBatch::getBatchTime, params.get("startTime"), params.get("endTime")); } return lqw; } }