package org.dromara.qa.md.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import org.dromara.common.core.utils.DateUtils; import org.dromara.common.mybatis.core.page.PageQuery; import org.dromara.common.mybatis.core.page.TableDataInfo; import org.dromara.qa.md.domain.bo.BatchCalibrateBo; import org.dromara.qa.md.domain.bo.BatchConfigBo; import org.dromara.qa.md.domain.CalibrationRecord; import org.dromara.qa.md.domain.WeighingBox; import org.dromara.qa.md.mapper.WeighingBoxMapper; import org.dromara.qa.md.service.ICalibrationRecordService; import org.dromara.qa.md.service.IWeighingBoxService; import org.dromara.qa.md.service.INotificationService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.math.BigDecimal; import java.util.*; import java.util.concurrent.TimeUnit; /** * 称重盒子服务实现 * * @author ruoyi * @date 2026-04-09 */ @Service public class WeighingBoxServiceImpl extends ServiceImpl implements IWeighingBoxService { @Autowired private WeighingBoxMapper weighingBoxMapper; @Autowired private ICalibrationRecordService calibrationRecordService; @Autowired private INotificationService notificationService; @Override public TableDataInfo queryPageList(WeighingBox weighingBox, PageQuery pageQuery) { // 检查是否需要按校准状态过滤 if (weighingBox.getCalibStatus() != null && !weighingBox.getCalibStatus().isEmpty()) { // 使用带校准状态过滤的查询 long total = weighingBoxMapper.selectWeighingBoxCountWithCalibStatus(weighingBox); List records = weighingBoxMapper.selectWeighingBoxListWithCalibStatus(weighingBox); // 手动分页 int pageNum = pageQuery.getPageNum(); int pageSize = pageQuery.getPageSize(); int start = (pageNum - 1) * pageSize; int end = Math.min(start + pageSize, records.size()); List pageRecords = start < records.size() ? records.subList(start, end) : new ArrayList<>(); // 计算每个盒子的校准状态(保持与前端一致) for (WeighingBox box : pageRecords) { calculateCalibStatus(box); } // 构建返回结果 TableDataInfo tableDataInfo = new TableDataInfo<>(); tableDataInfo.setRows(pageRecords); tableDataInfo.setTotal(total); tableDataInfo.setCode(200); tableDataInfo.setMsg("查询成功"); return tableDataInfo; } else { // 使用常规分页查询 Page page = new Page<>(pageQuery.getPageNum(), pageQuery.getPageSize()); // 构建查询条件 LambdaQueryWrapper queryWrapper = new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<>(); queryWrapper.eq(WeighingBox::getDelFlag, 0); if (weighingBox.getName() != null && !weighingBox.getName().isEmpty()) { queryWrapper.like(WeighingBox::getName, weighingBox.getName()) .or().like(WeighingBox::getCode, weighingBox.getName()) .or().like(WeighingBox::getDescription, weighingBox.getName()) .or().like(WeighingBox::getLocation, weighingBox.getName()); } if (weighingBox.getActiveStatus() != null) { queryWrapper.eq(WeighingBox::getActiveStatus, weighingBox.getActiveStatus()); } queryWrapper.orderByDesc(WeighingBox::getCreateTime); // 执行分页查询 Page resultPage = baseMapper.selectPage(page, queryWrapper); // 计算每个盒子的校准状态 for (WeighingBox box : resultPage.getRecords()) { calculateCalibStatus(box); } return TableDataInfo.build(resultPage); } } @Override public List selectWeighingBoxList(WeighingBox weighingBox) { List list = weighingBoxMapper.selectWeighingBoxList(weighingBox); for (WeighingBox box : list) { calculateCalibStatus(box); } return list; } @Override public int insertWeighingBox(WeighingBox weighingBox) { // 计算下次校准日期 if (weighingBox.getLastCalibDate() != null && weighingBox.getCalibCycleDays() != null) { Date nextCalibDate = DateUtils.addDays(weighingBox.getLastCalibDate(), weighingBox.getCalibCycleDays()); weighingBox.setNextCalibDate(nextCalibDate); } return baseMapper.insert(weighingBox); } @Override public int updateWeighingBox(WeighingBox weighingBox) { // 计算下次校准日期 if (weighingBox.getLastCalibDate() != null && weighingBox.getCalibCycleDays() != null) { Date nextCalibDate = DateUtils.addDays(weighingBox.getLastCalibDate(), weighingBox.getCalibCycleDays()); weighingBox.setNextCalibDate(nextCalibDate); } return baseMapper.updateById(weighingBox); } @Override public int deleteWeighingBoxByIds(Long[] boxIds) { return baseMapper.deleteBatchIds(Arrays.asList(boxIds)); } @Override @Transactional public int calibrate(Long boxId, Date calibDate, BigDecimal actualWeight, String note) { WeighingBox box = baseMapper.selectById(boxId); if (box == null) { return 0; } // 保存校准前的状态 Date prevCalibDate = box.getLastCalibDate(); // 更新盒子信息 box.setLastCalibDate(calibDate); box.setNextCalibDate(DateUtils.addDays(calibDate, box.getCalibCycleDays())); baseMapper.updateById(box); // 计算偏差 BigDecimal deviation = null; BigDecimal deviationPct = null; if (actualWeight != null) { deviation = actualWeight.subtract(box.getWeight()); if (box.getWeight().compareTo(BigDecimal.ZERO) > 0) { deviationPct = deviation.divide(box.getWeight(), 3, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100)); } } // 创建校准记录 CalibrationRecord record = new CalibrationRecord(); record.setTargetType("weighing_box"); record.setTargetId(boxId); record.setTargetCode(box.getCode()); record.setTargetName(box.getName()); record.setCalibDate(calibDate); record.setCalibCycleDays(box.getCalibCycleDays()); record.setStandardWeight(box.getWeight()); record.setActualWeight(actualWeight); record.setDeviation(deviation); record.setDeviationPct(deviationPct); record.setPrevCalibDate(prevCalibDate); record.setNextCalibDate(box.getNextCalibDate()); record.setOperator("admin"); // 实际应该从当前用户获取 record.setNote(note); record.setCreateTime(new Date()); calibrationRecordService.save(record); return 1; } @Override @Transactional public Map batchCalibrate(BatchCalibrateBo batchCalibrateDTO) { List boxIds = batchCalibrateDTO.getBoxIds(); Date calibDate = batchCalibrateDTO.getCalibDate(); String note = batchCalibrateDTO.getNote(); List items = batchCalibrateDTO.getItems(); Map actualWeightMap = new HashMap<>(); if (items != null) { for (BatchCalibrateBo.CalibrateItem item : items) { actualWeightMap.put(item.getBoxId(), item.getActualWeight()); } } String batchId = UUID.randomUUID().toString(); List records = new ArrayList<>(); List> results = new ArrayList<>(); for (Long boxId : boxIds) { WeighingBox box = baseMapper.selectById(boxId); if (box == null) { continue; } // 保存校准前的状态 Date prevCalibDate = box.getLastCalibDate(); // 更新盒子信息 box.setLastCalibDate(calibDate); box.setNextCalibDate(DateUtils.addDays(calibDate, box.getCalibCycleDays())); baseMapper.updateById(box); // 计算偏差 BigDecimal actualWeight = actualWeightMap.get(boxId); BigDecimal deviation = null; BigDecimal deviationPct = null; if (actualWeight != null) { deviation = actualWeight.subtract(box.getWeight()); if (box.getWeight().compareTo(BigDecimal.ZERO) > 0) { deviationPct = deviation.divide(box.getWeight(), 3, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100)); } } // 创建校准记录 CalibrationRecord record = new CalibrationRecord(); record.setTargetType("weighing_box"); record.setTargetId(boxId); record.setTargetCode(box.getCode()); record.setTargetName(box.getName()); record.setCalibDate(calibDate); record.setCalibCycleDays(box.getCalibCycleDays()); record.setStandardWeight(box.getWeight()); record.setActualWeight(actualWeight); record.setDeviation(deviation); record.setDeviationPct(deviationPct); record.setPrevCalibDate(prevCalibDate); record.setNextCalibDate(box.getNextCalibDate()); record.setBatchId(batchId); record.setOperator("admin"); // 实际应该从当前用户获取 record.setNote(note); record.setCreateTime(new Date()); records.add(record); // 准备返回结果 Map result = new HashMap<>(); result.put("boxId", boxId); result.put("nextCalibDate", box.getNextCalibDate()); results.add(result); } // 批量插入校准记录 if (!records.isEmpty()) { calibrationRecordService.batchInsert(records); } Map resultMap = new HashMap<>(); resultMap.put("successCount", boxIds.size()); resultMap.put("failCount", 0); resultMap.put("results", results); return resultMap; } @Override @Transactional public int batchConfig(BatchConfigBo batchConfigDTO) { Integer calibCycleDays = batchConfigDTO.getCalibCycleDays(); Integer remindDays = batchConfigDTO.getRemindDays(); String applyScope = batchConfigDTO.getApplyScope(); List boxIds = batchConfigDTO.getBoxIds(); List targetBoxIds = new ArrayList<>(); if ("all".equals(applyScope)) { // 所有已启用的盒子 List boxes = weighingBoxMapper.selectActiveWeighingBoxes(); for (WeighingBox box : boxes) { targetBoxIds.add(box.getId()); } } else if ("selected".equals(applyScope) && boxIds != null) { targetBoxIds.addAll(boxIds); } if (targetBoxIds.isEmpty()) { return 0; } // 批量更新校准配置 int result = weighingBoxMapper.batchUpdateCalibConfig(targetBoxIds, calibCycleDays, remindDays); // 重新计算下次校准日期 for (Long boxId : targetBoxIds) { WeighingBox box = baseMapper.selectById(boxId); if (box.getLastCalibDate() != null) { box.setNextCalibDate(DateUtils.addDays(box.getLastCalibDate(), calibCycleDays)); baseMapper.updateById(box); } } return result; } @Override public int batchUpdateStatus(List boxIds, Integer activeStatus) { return weighingBoxMapper.batchUpdateStatus(boxIds, activeStatus); } @Override public Map copyBox(Long sourceId, Integer count) { WeighingBox sourceBox = baseMapper.selectById(sourceId); if (sourceBox == null) { throw new RuntimeException("源盒子不存在"); } Date nextCalibDate = null; List newIds = new ArrayList<>(); List newCodes = new ArrayList<>(); // 计算下次校准日期 if ( sourceBox.getCalibCycleDays() != null) { nextCalibDate = DateUtils.addDays(new Date(), sourceBox.getCalibCycleDays()); } for (int i = 1; i <= count; i++) { WeighingBox newBox = new WeighingBox(); newBox.setName(sourceBox.getName() + "-" + (char)('a' + i - 1)); newBox.setCode(sourceBox.getCode() + "-" + (char)('a' + i - 1)); newBox.setWeight(sourceBox.getWeight()); newBox.setUnit(sourceBox.getUnit()); newBox.setLocation(sourceBox.getLocation()); newBox.setCalibCycleDays(sourceBox.getCalibCycleDays()); newBox.setRemindDays(sourceBox.getRemindDays()); newBox.setActiveStatus(sourceBox.getActiveStatus()); newBox.setDescription(sourceBox.getDescription()); newBox.setLastCalibDate(new Date()); newBox.setNextCalibDate(nextCalibDate); newBox.setCreateBy("admin"); // 实际应该从当前用户获取 newBox.setCreateTime(new Date()); baseMapper.insert(newBox); newIds.add(newBox.getId()); newCodes.add(newBox.getCode()); } Map result = new HashMap<>(); result.put("ids", newIds); result.put("codes", newCodes); return result; } @Override public Map getStatistics() { Map statistics = new HashMap<>(); statistics.put("total", Math.toIntExact(baseMapper.selectCount(null))); // 已启用 int activeCount = Math.toIntExact(baseMapper.selectCount(new LambdaQueryWrapper() .eq(WeighingBox::getActiveStatus, 1) .eq(WeighingBox::getDelFlag, 0))); statistics.put("active", activeCount); // 已停用 int inactiveCount = Math.toIntExact(baseMapper.selectCount(new LambdaQueryWrapper() .eq(WeighingBox::getActiveStatus, 0) .eq(WeighingBox::getDelFlag, 0))); statistics.put("inactive", inactiveCount); // 校准状态统计 List boxes = baseMapper.selectList(new LambdaQueryWrapper() .eq(WeighingBox::getDelFlag, 0) .eq(WeighingBox::getActiveStatus, 1)); int normal = 0, warning = 0, overdue = 0, unset = 0; for (WeighingBox box : boxes) { calculateCalibStatus(box); String status = box.getCalibStatus(); if ("normal".equals(status)) normal++; else if ("warning".equals(status)) warning++; else if ("overdue".equals(status)) overdue++; else if ("unset".equals(status)) unset++; } statistics.put("normal", normal); statistics.put("warning", warning); statistics.put("overdue", overdue); statistics.put("unset", unset); return statistics; } @Override public WeighingBox calculateCalibStatus(WeighingBox weighingBox) { Date nextCalibDate = weighingBox.getNextCalibDate(); if (nextCalibDate == null) { weighingBox.setCalibStatus("unset"); weighingBox.setCalibDaysLeft(null); return weighingBox; } long daysLeft = DateUtils.getTimeDifference(new Date(), nextCalibDate, TimeUnit.DAYS); weighingBox.setCalibDaysLeft((int) daysLeft); if (daysLeft < 0) { weighingBox.setCalibStatus("overdue"); } else if (daysLeft <= weighingBox.getRemindDays()) { weighingBox.setCalibStatus("warning"); } else { weighingBox.setCalibStatus("normal"); } return weighingBox; } }