Files
klp-oa/klp-wms/src/main/java/com/klp/service/impl/WmsMaterialWarningServiceImpl.java
砂糖 b43b44d044 feat(wms): 新增钢卷告警历史批量处理功能
新增批量处理历史告警接口,支持将今天以前的告警标记为指定状态,前端添加对应操作按钮,可一键处理或忽略历史告警
2026-06-16 17:02:25 +08:00

347 lines
16 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package com.klp.service.impl;
import cn.hutool.core.bean.BeanUtil;
import com.klp.common.core.page.TableDataInfo;
import com.klp.common.core.domain.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.klp.common.core.service.ConfigService;
import com.klp.common.helper.LoginHelper;
import com.klp.common.utils.DateUtils;
import com.klp.common.utils.StringUtils;
import com.klp.domain.vo.WmsMaterialCoilVo;
import com.klp.mapper.WmsCoilPendingActionMapper;
import com.klp.mapper.WmsMaterialCoilMapper;
import com.klp.service.IWmsMaterialCoilService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import com.klp.domain.bo.WmsMaterialWarningBo;
import com.klp.domain.vo.WmsMaterialWarningVo;
import com.klp.domain.WmsMaterialCoil;
import com.klp.domain.WmsMaterialWarning;
import com.klp.domain.WmsCoilPendingAction;
import com.klp.domain.bo.WmsMaterialCoilBo;
import com.klp.mapper.WmsMaterialWarningMapper;
import com.klp.service.IWmsMaterialWarningService;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Collection;
import java.util.stream.Collectors;
/**
* 钢卷通用维度告警(长度/厚度/宽度Service业务层处理
*
* @author klp
* @date 2026-06-06
*/
@Slf4j
@RequiredArgsConstructor
@Service
public class WmsMaterialWarningServiceImpl implements IWmsMaterialWarningService {
private final WmsMaterialWarningMapper baseMapper;
private final ConfigService configService;
private final WmsCoilPendingActionMapper wmsCoilPendingActionMapper;
/**
* 查询钢卷通用维度告警(长度/厚度/宽度)
*/
@Override
public WmsMaterialWarningVo queryById(Long warningId){
return baseMapper.selectVoById(warningId);
}
/**
* 查询钢卷通用维度告警(长度/厚度/宽度)列表
*/
@Override
public TableDataInfo<WmsMaterialWarningVo> queryPageList(WmsMaterialWarningBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<WmsMaterialWarning> lqw = buildQueryWrapper(bo);
Page<WmsMaterialWarningVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
/**
* 查询钢卷通用维度告警(长度/厚度/宽度)列表
*/
@Override
public List<WmsMaterialWarningVo> queryList(WmsMaterialWarningBo bo) {
LambdaQueryWrapper<WmsMaterialWarning> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
private LambdaQueryWrapper<WmsMaterialWarning> buildQueryWrapper(WmsMaterialWarningBo bo) {
Map<String, Object> params = bo.getParams();
LambdaQueryWrapper<WmsMaterialWarning> lqw = Wrappers.lambdaQuery();
lqw.eq(bo.getCoilId() != null, WmsMaterialWarning::getCoilId, bo.getCoilId());
// 批量钢卷ID过滤逗号分隔
if (StringUtils.isNotBlank(bo.getCoilIds())) {
String[] ids = bo.getCoilIds().split(",");
List<Long> idList = new ArrayList<>();
for (String id : ids) {
try {
idList.add(Long.parseLong(id.trim()));
} catch (NumberFormatException ignored) {
}
}
if (!idList.isEmpty()) {
lqw.in(WmsMaterialWarning::getCoilId, idList);
}
}
lqw.eq(StringUtils.isNotBlank(bo.getWarningType()), WmsMaterialWarning::getWarningType, bo.getWarningType());
lqw.eq(bo.getActionType() !=null, WmsMaterialWarning::getActionType, bo.getActionType());
lqw.eq(bo.getTheoreticalVal() != null, WmsMaterialWarning::getTheoreticalVal, bo.getTheoreticalVal());
lqw.eq(bo.getActualVal() != null, WmsMaterialWarning::getActualVal, bo.getActualVal());
lqw.eq(bo.getAllowDeviation() != null, WmsMaterialWarning::getAllowDeviation, bo.getAllowDeviation());
lqw.eq(bo.getDeviationValue() != null, WmsMaterialWarning::getDeviationValue, bo.getDeviationValue());
lqw.eq(bo.getDeviationRate() != null, WmsMaterialWarning::getDeviationRate, bo.getDeviationRate());
lqw.eq(StringUtils.isNotBlank(bo.getWarningLevel()), WmsMaterialWarning::getWarningLevel, bo.getWarningLevel());
lqw.eq(StringUtils.isNotBlank(bo.getWarningMsg()), WmsMaterialWarning::getWarningMsg, bo.getWarningMsg());
lqw.eq(bo.getWarningStatus() != null, WmsMaterialWarning::getWarningStatus, bo.getWarningStatus());
lqw.eq(StringUtils.isNotBlank(bo.getHandleBy()), WmsMaterialWarning::getHandleBy, bo.getHandleBy());
lqw.eq(bo.getHandleTime() != null, WmsMaterialWarning::getHandleTime, bo.getHandleTime());
lqw.eq(StringUtils.isNotBlank(bo.getHandleRemark()), WmsMaterialWarning::getHandleRemark, bo.getHandleRemark());
lqw.ge(bo.getCreateStartTime() != null, WmsMaterialWarning::getCreateTime, bo.getCreateStartTime());
lqw.le(bo.getCreateEndTime() != null, WmsMaterialWarning::getCreateTime, bo.getCreateEndTime());
// 根据创建时间倒叙
lqw.orderByDesc(WmsMaterialWarning::getCreateTime);
return lqw;
}
/**
* 新增钢卷通用维度告警(长度/厚度/宽度)
*/
@Override
public Boolean insertByBo(WmsMaterialWarningBo bo) {
WmsMaterialWarning add = BeanUtil.toBean(bo, WmsMaterialWarning.class);
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setWarningId(add.getWarningId());
}
return flag;
}
/**
* 修改钢卷通用维度告警(长度/厚度/宽度)
*/
@Override
public Boolean updateByBo(WmsMaterialWarningBo bo) {
WmsMaterialWarning update = BeanUtil.toBean(bo, WmsMaterialWarning.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(WmsMaterialWarning entity){
//TODO 做一些数据校验,如唯一约束
}
/**
* 批量删除钢卷通用维度告警(长度/厚度/宽度)
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if(isValid){
//TODO 做一些业务上的校验,判断是否需要校验
}
return baseMapper.deleteBatchIds(ids) > 0;
}
/**
* 批量处理告警(填写处理人、处理时间、处理状态、处理备注)
*/
@Override
public Boolean batchHandle(WmsMaterialWarningBo bo) {
bo.setHandleBy(LoginHelper.getNickName());
bo.setHandleTime(DateUtils.getNowDate());
LambdaUpdateWrapper<WmsMaterialWarning> luw = Wrappers.lambdaUpdate();
luw.set(WmsMaterialWarning::getWarningStatus, bo.getWarningStatus())
.set(StringUtils.isNotBlank(bo.getHandleBy()), WmsMaterialWarning::getHandleBy, bo.getHandleBy())
.set(bo.getHandleTime() != null, WmsMaterialWarning::getHandleTime, bo.getHandleTime())
.set(StringUtils.isNotBlank(bo.getHandleRemark()), WmsMaterialWarning::getHandleRemark, bo.getHandleRemark())
.in(WmsMaterialWarning::getWarningId, bo.getWarningIds());
return baseMapper.update(null, luw) > 0;
}
/**
* 批量处理历史告警(标记今天以前的所有记录为指定状态)
*/
@Override
public Boolean batchHandleHistory(WmsMaterialWarningBo bo) {
bo.setHandleBy(LoginHelper.getNickName());
bo.setHandleTime(DateUtils.getNowDate());
java.util.Date todayStart = DateUtils.toDate(java.time.LocalDate.now());
LambdaUpdateWrapper<WmsMaterialWarning> luw = Wrappers.lambdaUpdate();
luw.set(WmsMaterialWarning::getWarningStatus, bo.getWarningStatus())
.set(StringUtils.isNotBlank(bo.getHandleBy()), WmsMaterialWarning::getHandleBy, bo.getHandleBy())
.set(bo.getHandleTime() != null, WmsMaterialWarning::getHandleTime, bo.getHandleTime())
.set(StringUtils.isNotBlank(bo.getHandleRemark()), WmsMaterialWarning::getHandleRemark, bo.getHandleRemark())
.lt(WmsMaterialWarning::getCreateTime, todayStart)
.eq(WmsMaterialWarning::getWarningStatus, 0);
return baseMapper.update(null, luw) > 0;
}
/**
* 检查钢卷长度/厚度偏差并批量插入告警记录
*
* 长度规则ABS((实测长度 - 理论长度) / 理论长度) > 阈值 → WARNING
* 阈值从 sys_config(material.warning.length) 读取,默认 0.1
* 厚度规则:理论厚度 - 实测厚度 > 阈值 → ERROR
* 阈值从 sys_config(material.warning.thickness) 读取(绝对值差 mm默认 -0.01
*/
@Override
public void checkAndInsertWarnings(WmsMaterialCoil coil, WmsMaterialCoilBo bo) {
try {
doCheckAndInsertWarnings(coil, bo);
} catch (Exception e) {
log.error("钢卷告警检查异常, coilId={}, 不影响原流程", coil != null ? coil.getCoilId() : null, e);
}
}
private void doCheckAndInsertWarnings(WmsMaterialCoil coil, WmsMaterialCoilBo bo) {
if (coil == null || coil.getCoilId() == null) {
return;
}
List<WmsMaterialWarning> warnings = new ArrayList<>();
// ========== 长度检查 ==========
checkLength(coil, warnings);
// ========== 厚度检查 ==========
checkThickness(coil, bo, warnings);
// 批量插入(查询产线类型并设置)
if (!warnings.isEmpty()) {
Integer actionType = null;
if (bo != null && bo.getActionId() != null) {
try {
WmsCoilPendingAction action = wmsCoilPendingActionMapper.selectById(bo.getActionId());
if (action != null) {
actionType = action.getActionType();
}
} catch (Exception e) {
log.warn("查询产线类型失败, actionId={}", bo.getActionId(), e);
}
}
// 兜底如果没有actionId如退火工序不创建代操作记录直接使用bo中的actionType
if (actionType == null && bo != null && bo.getActionType() != null) {
actionType = bo.getActionType();
}
if (actionType != null) {
for (WmsMaterialWarning w : warnings) {
w.setActionType(actionType);
}
}
try {
baseMapper.insertBatch(warnings);
log.info("批量插入钢卷告警记录成功, coilId={}, 告警数={}", coil.getCoilId(), warnings.size());
} catch (Exception e) {
log.error("批量插入钢卷告警记录失败, coilId={}", coil.getCoilId(), e);
}
}
}
/**
* 长度偏差检查
* ABS((actualLength - theoreticalLength) / theoreticalLength) > 阈值 → WARNING
* 阈值从 sys_config(material.warning.length) 读取,默认 0.1
*/
private void checkLength(WmsMaterialCoil coil, List<WmsMaterialWarning> warnings) {
Long actualLength = coil.getActualLength();
BigDecimal theoreticalLength = coil.getTheoreticalLength();
if (actualLength == null || theoreticalLength == null
|| theoreticalLength.compareTo(BigDecimal.ZERO) == 0) {
return;
}
// 读取配置阈值,默认 0.110%
BigDecimal threshold;
try {
String val = configService.getConfigValue("material.warning.length");
threshold = StringUtils.isNotBlank(val) ? new BigDecimal(val.trim()) : new BigDecimal("0.1");
} catch (Exception e) {
log.warn("读取长度告警阈值失败,使用默认值 0.1", e);
threshold = new BigDecimal("0.1");
}
BigDecimal actual = new BigDecimal(actualLength);
BigDecimal diff = actual.subtract(theoreticalLength).abs();
BigDecimal rate = diff.divide(theoreticalLength, 10, RoundingMode.HALF_UP);
if (rate.compareTo(threshold) > 0) {
WmsMaterialWarning warning = new WmsMaterialWarning();
warning.setCoilId(coil.getCoilId());
warning.setWarningType("LENGTH");
warning.setTheoreticalVal(theoreticalLength.setScale(3, RoundingMode.HALF_UP));
warning.setActualVal(actual.setScale(3, RoundingMode.HALF_UP));
warning.setAllowDeviation(threshold.setScale(3, RoundingMode.HALF_UP));
warning.setDeviationValue(actual.subtract(theoreticalLength).setScale(3, RoundingMode.HALF_UP));
warning.setDeviationRate(rate.multiply(new BigDecimal("100")).setScale(1, RoundingMode.HALF_UP));
warning.setWarningLevel("WARNING");
warning.setWarningMsg("钢卷长度偏差超过阈值,理论长度=" + theoreticalLength.setScale(3, RoundingMode.HALF_UP) + "m实测长度=" + actualLength + "mm");
warning.setWarningStatus(0);
warnings.add(warning);
}
}
/**
* 厚度偏差检查
* 规则:理论厚度 - 规格厚度 > 阈值 → WARNING
* 规格厚度从 BO 中取得calculateTheoretical 已解析)
* 阈值从 sys_config(material.warning.thickness) 读取,默认 -0.01
*/
private void checkThickness(WmsMaterialCoil coil, WmsMaterialCoilBo bo, List<WmsMaterialWarning> warnings) {
BigDecimal theoreticalThickness = coil.getTheoreticalThickness();
BigDecimal specThickness = bo != null ? bo.getSpecThickness() : null;
if (theoreticalThickness == null || specThickness == null
|| specThickness.compareTo(BigDecimal.ZERO) == 0) {
return;
}
// 读取配置阈值(单位 mm默认 -0.01
BigDecimal threshold;
try {
String val = configService.getConfigValue("material.warning.thickness");
threshold = StringUtils.isNotBlank(val) ? new BigDecimal(val.trim()) : new BigDecimal("-0.01");
} catch (Exception e) {
log.warn("读取厚度告警阈值失败,使用默认值 -0.01", e);
threshold = new BigDecimal("-0.01");
}
// 理论厚度 - 规格厚度 > 阈值 → 触发
// 先统一 round 到 3 位小数再比较,避免理论厚度公式计算引入的高精度尾数
// 导致比较结果与存储值不一致(如 diff=-0.0096 > -0.01 触发,但存储时都 round 成 -0.010
BigDecimal diff = theoreticalThickness.subtract(specThickness).setScale(3, RoundingMode.HALF_UP);
BigDecimal scaledThreshold = threshold.setScale(3, RoundingMode.HALF_UP);
if (diff.compareTo(scaledThreshold) > 0) {
WmsMaterialWarning warning = new WmsMaterialWarning();
warning.setCoilId(coil.getCoilId());
warning.setWarningType("THICKNESS");
warning.setTheoreticalVal(theoreticalThickness.setScale(3, RoundingMode.HALF_UP));
warning.setActualVal(specThickness.setScale(3, RoundingMode.HALF_UP));
warning.setAllowDeviation(scaledThreshold);
warning.setDeviationValue(diff);
BigDecimal rate = diff.divide(specThickness.setScale(3, RoundingMode.HALF_UP), 10, RoundingMode.HALF_UP)
.multiply(new BigDecimal("100")).setScale(1, RoundingMode.HALF_UP);
warning.setDeviationRate(rate);
warning.setWarningLevel("WARNING");
warning.setWarningMsg("钢卷厚度偏差超出允许范围,理论厚度=" + theoreticalThickness.setScale(3, RoundingMode.HALF_UP) + "mm规格厚度=" + specThickness.setScale(3, RoundingMode.HALF_UP) + "mm");
warning.setWarningStatus(0);
warnings.add(warning);
}
}
}