同步规程同步代码和录入监测代码

This commit is contained in:
2026-05-23 19:34:52 +08:00
parent 6b58f37616
commit 35ad50a79d
29 changed files with 2357 additions and 329 deletions

View File

@@ -210,5 +210,8 @@ public class WmsMaterialCoil extends BaseEntity {
* 调拨类型
*/
private String transferType;
private Long specId;
private Long versionId;
}

View File

@@ -7,6 +7,8 @@ import com.klp.common.core.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.math.BigDecimal;
/**
* 规程版本对象 wms_process_spec_version
*
@@ -46,4 +48,14 @@ public class WmsProcessSpecVersion extends BaseEntity {
private Integer delFlag;
private String remark;
private BigDecimal matchEntryThickMin;
private BigDecimal matchEntryThickMax;
private BigDecimal matchExitThickMin;
private BigDecimal matchExitThickMax;
private BigDecimal matchEntryWidthMin;
private BigDecimal matchEntryWidthMax;
private BigDecimal matchExitWidthMin;
private BigDecimal matchExitWidthMax;
private String matchSteelGrade;
}

View File

@@ -50,4 +50,9 @@ public class WmsProductionLine extends BaseEntity {
*/
private String remark;
/**
* 产线支持的操作类型逗号分隔1=分卷2=合卷3=更新)
*/
private String actionType;
}

View File

@@ -378,5 +378,8 @@ public class WmsMaterialCoilBo extends BaseEntity {
*/
@TableField(exist = false)
private Boolean onlyEmptyPackingStatus;
private Long specId;
private Long versionId;
}

View File

@@ -8,6 +8,7 @@ import lombok.EqualsAndHashCode;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
/**
* 规程版本业务对象 wms_process_spec_version
@@ -38,4 +39,14 @@ public class WmsProcessSpecVersionBo extends BaseEntity {
private String status;
private String remark;
private BigDecimal matchEntryThickMin;
private BigDecimal matchEntryThickMax;
private BigDecimal matchExitThickMin;
private BigDecimal matchExitThickMax;
private BigDecimal matchEntryWidthMin;
private BigDecimal matchEntryWidthMax;
private BigDecimal matchExitWidthMin;
private BigDecimal matchExitWidthMax;
private String matchSteelGrade;
}

View File

@@ -334,5 +334,10 @@ public class WmsMaterialCoilVo extends BaseEntity {
* 关联的订单列表通过wms_coil_contract_rel中间表JOIN crm_order
*/
private List<com.klp.domain.vo.WmsCoilContractRelVo> orderList;
private Long specId;
private Long versionId;
private String specCode;
private String versionCode;
}

View File

@@ -5,6 +5,7 @@ import com.alibaba.excel.annotation.ExcelProperty;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
/**
@@ -41,4 +42,18 @@ public class WmsProcessSpecVersionVo {
@ExcelProperty(value = "更新时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date updateTime;
private BigDecimal matchEntryThickMin;
private BigDecimal matchEntryThickMax;
private BigDecimal matchExitThickMin;
private BigDecimal matchExitThickMax;
private BigDecimal matchEntryWidthMin;
private BigDecimal matchEntryWidthMax;
private BigDecimal matchExitWidthMin;
private BigDecimal matchExitWidthMax;
private String matchSteelGrade;
private String specCode;
private String specName;
private Long lineId;
}

View File

@@ -64,6 +64,11 @@ public class WmsProductionLineVo {
@ExcelProperty(value = "备注")
private String remark;
/**
* 产线支持的操作类型逗号分隔1=分卷2=合卷3=更新)
*/
private String actionType;
/**
* 关联的排产计划明细数量
*/

View File

@@ -7,6 +7,7 @@ import com.klp.domain.WmsCoilPendingAction;
import com.klp.domain.vo.WmsCoilPendingActionVo;
import com.klp.domain.vo.WmsCoilPendingActionIdCoilVo;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* 钢卷待操作Mapper接口
@@ -44,5 +45,29 @@ public interface WmsCoilPendingActionMapper extends BaseMapperPlus<WmsCoilPendin
* @return 待操作记录
*/
WmsCoilPendingAction selectByActionIdAndDelFlag(@Param("actionId") Long actionId, @Param("delFlag") Integer delFlag);
/**
* 批量查询:找出 processed_coil_ids 中包含给定 coilId 列表中任意一个的记录,
* 只返回 action_type 和 processed_coil_ids 两列(供规程同步线路匹配用)。
*/
List<WmsCoilPendingAction> selectActionTypeByProcessedCoilIds(@Param("coilIds") List<Long> coilIds);
/**
* 获取所有有效待操作记录的 processed_coil_ids 字符串列表(供规程同步主键展开用)。
*/
List<String> selectAllProcessedCoilIdStrings();
/**
* 获取所有有效待操作记录的 processed_coil_ids + action_status + action_type
* 供规程同步页面同时构建"已处理钢卷 ID 集"和"录入状态"映射。
*/
List<WmsCoilPendingAction> selectAllProcessedCoilIdsAndActionStatus();
/**
* 规程同步:按 actionType 集合查询全部待操作记录(含未录入和已录入)。
* 返回 action_id / coil_id / action_type / action_status / processed_coil_ids 五列。
*/
List<WmsCoilPendingAction> selectPendingByActionTypes(
@Param("actionTypes") java.util.Collection<Integer> actionTypes);
}

View File

@@ -47,6 +47,8 @@ public interface WmsMaterialCoilMapper extends BaseMapperPlus<WmsMaterialCoilMap
List<WmsMaterialCoilVo> selectVoListWithDynamicJoin(@Param("ew")QueryWrapper<WmsMaterialCoil> lqw);
Map<String, Object> selectCountForSpecSync(@Param("ew") QueryWrapper<WmsMaterialCoil> qw);
List<Map<String, Object>> getDistributionByActualWarehouse(@Param("itemType") String itemType, @Param("itemId") Long itemId);
List<Map<String, Object>> getDistributionByActualItemType(@Param("itemType")String itemType,@Param("itemId") Long itemId);

View File

@@ -55,6 +55,44 @@ public interface IWmsMaterialCoilService {
*/
List<WmsMaterialCoilVo> queryList(WmsMaterialCoilBo bo);
/**
* 按入场卷号批量查询供规程同步分页列表使用IN 查询避免 N 次单查)
*/
List<WmsMaterialCoilVo> queryByEnterCoilNos(List<String> enterCoilNos);
/**
* 规程同步专用DB 层分页查询(避免全表加载),支持 material LIKE 过滤和 syncStatus 过滤。
* specIds 不为空时追加 mc.spec_id IN (...) 条件。
*/
List<WmsMaterialCoilVo> queryPageForSpecSync(WmsMaterialCoilBo bo, int pageNum, int pageSize,
String syncStatus, String material, java.util.Set<Long> specIds);
/**
* 规程同步专用:一次 SQL 返回 total/synced/unsynced 三个计数。
*/
Map<String, Object> countForSpecSync(WmsMaterialCoilBo bo, String material, java.util.Set<Long> specIds);
/**
* 规程同步专用:以 processed_coil_ids 展开后的 coilId 集合为主,分页查 L3 钢卷(含 item join
*/
List<WmsMaterialCoilVo> queryByProcessedCoilIds(java.util.Collection<Long> coilIds,
String enterCoilNo, String currentCoilNo, String material, String qualityStatus,
String syncStatus, java.util.Set<Long> filterSpecIds, int offset, int pageSize);
/**
* 规程同步专用:以 processed_coil_ids 展开后的 coilId 集合为主,计算满足 L3 过滤条件的总数。
*/
long countByProcessedCoilIds(java.util.Collection<Long> coilIds,
String enterCoilNo, String currentCoilNo, String material, String qualityStatus,
String syncStatus, java.util.Set<Long> filterSpecIds);
/**
* 规程同步专用:不区分 syncStatus一次查询返回 total/synced/unsynced/movedOn 整体汇总(用于统计条)。
*/
java.util.Map<String, Long> getOverallSyncStats(java.util.Collection<Long> coilIds,
String enterCoilNo, String currentCoilNo, String material, String qualityStatus,
java.util.Set<Long> filterSpecIds);
/**
* 统计筛选条件下的全量汇总数据高性能只查sum/count
* 独立的统计接口,不影响分页查询

View File

@@ -5,6 +5,7 @@ import com.klp.common.core.page.TableDataInfo;
import com.klp.domain.bo.WmsProcessSpecVersionBo;
import com.klp.domain.vo.WmsProcessSpecVersionVo;
import java.math.BigDecimal;
import java.util.Collection;
import java.util.List;
@@ -31,4 +32,25 @@ public interface IWmsProcessSpecVersionService {
* 将指定版本设为当前规程下唯一生效版本
*/
Boolean activateVersion(Long versionId);
/**
* 根据L2实绩参数匹配最佳规程版本。
* 对所有 isActive=1 的版本评分命中条件最多者胜出返回匹配的版本VO含specCode/specName无匹配返回null。
* lineId 不为空时,只在属于该产线的规程版本中匹配。
*/
WmsProcessSpecVersionVo matchBestVersion(BigDecimal entryThick, BigDecimal exitThick,
BigDecimal entryWidth, BigDecimal exitWidth,
String grade, Long lineId);
/**
* 加载所有生效版本并批量填充 specCode/specName供分页列表一次性预加载使用。
* lineId 不为空时只返回属于该产线的版本。
*/
List<WmsProcessSpecVersionVo> queryActiveVersionsEnriched(Long lineId);
/**
* 加载全部版本(含非生效版本)并批量填充 specCode/specName/lineId。
* 用于展示已绑定规程信息,避免钢卷绑定旧版本后查不到名称。
*/
List<WmsProcessSpecVersionVo> queryAllVersionsEnriched();
}

View File

@@ -1181,6 +1181,122 @@ public class WmsMaterialCoilServiceImpl implements IWmsMaterialCoilService {
return list;
}
@Override
public List<WmsMaterialCoilVo> queryByEnterCoilNos(List<String> enterCoilNos) {
if (enterCoilNos == null || enterCoilNos.isEmpty()) {
return Collections.emptyList();
}
QueryWrapper<WmsMaterialCoil> qw = new QueryWrapper<>();
qw.in("mc.enter_coil_no", enterCoilNos).eq("mc.del_flag", 0);
return baseMapper.selectVoListWithDynamicJoin(qw);
}
@Override
public List<WmsMaterialCoilVo> queryPageForSpecSync(WmsMaterialCoilBo bo, int pageNum, int pageSize,
String syncStatus, String material, java.util.Set<Long> specIds) {
QueryWrapper<WmsMaterialCoil> qw = buildQueryWrapperPlus(bo);
applySpecSyncExtras(qw, syncStatus, material, specIds);
int offset = Math.max(0, (pageNum - 1) * pageSize);
qw.last("LIMIT " + offset + ", " + pageSize);
return baseMapper.selectVoListWithDynamicJoin(qw);
}
@Override
public Map<String, Object> countForSpecSync(WmsMaterialCoilBo bo, String material, java.util.Set<Long> specIds) {
QueryWrapper<WmsMaterialCoil> qw = buildQueryWrapperPlus(bo);
applySpecSyncExtras(qw, null, material, specIds);
return baseMapper.selectCountForSpecSync(qw);
}
private void applySpecSyncExtras(QueryWrapper<WmsMaterialCoil> qw, String syncStatus,
String material, java.util.Set<Long> specIds) {
if (StringUtils.isNotBlank(material)) {
String like = "%" + material.toLowerCase() + "%";
qw.apply("LOWER(CASE WHEN mc.item_type = 'raw_material' THEN COALESCE(rm.material,'') "
+ "ELSE COALESCE(p.material,'') END) LIKE {0}", like);
}
if (specIds != null && !specIds.isEmpty()) {
qw.in("mc.spec_id", specIds);
}
if ("synced".equals(syncStatus)) qw.isNotNull("mc.spec_id");
else if ("unsynced".equals(syncStatus)) qw.isNull("mc.spec_id");
}
@Override
public List<WmsMaterialCoilVo> queryByProcessedCoilIds(java.util.Collection<Long> coilIds,
String enterCoilNo, String currentCoilNo, String material, String qualityStatus,
String syncStatus, java.util.Set<Long> filterSpecIds, int offset, int pageSize) {
if (coilIds == null || coilIds.isEmpty()) return Collections.emptyList();
QueryWrapper<WmsMaterialCoil> qw = buildProcessedCoilQw(coilIds, enterCoilNo, currentCoilNo,
material, qualityStatus, syncStatus, filterSpecIds);
qw.last("LIMIT " + offset + ", " + pageSize);
return baseMapper.selectVoListWithDynamicJoin(qw);
}
@Override
public long countByProcessedCoilIds(java.util.Collection<Long> coilIds,
String enterCoilNo, String currentCoilNo, String material, String qualityStatus,
String syncStatus, java.util.Set<Long> filterSpecIds) {
if (coilIds == null || coilIds.isEmpty()) return 0L;
QueryWrapper<WmsMaterialCoil> qw = buildProcessedCoilQw(coilIds, enterCoilNo, currentCoilNo,
material, qualityStatus, syncStatus, filterSpecIds);
Map<String, Object> result = baseMapper.selectCountForSpecSync(qw);
if (result == null) return 0L;
Object total = result.get("total");
if (total == null) return 0L;
try { return Long.parseLong(total.toString()); } catch (NumberFormatException e) { return 0L; }
}
@Override
public java.util.Map<String, Long> getOverallSyncStats(java.util.Collection<Long> coilIds,
String enterCoilNo, String currentCoilNo, String material, String qualityStatus,
java.util.Set<Long> filterSpecIds) {
java.util.Map<String, Long> stats = new java.util.LinkedHashMap<>();
stats.put("total", 0L);
stats.put("synced", 0L);
stats.put("unsynced", 0L);
stats.put("movedOn", 0L);
if (coilIds == null || coilIds.isEmpty()) return stats;
// syncStatus=null → 不加 version_id 过滤,一次查出全量分组
QueryWrapper<WmsMaterialCoil> qw = buildProcessedCoilQw(
coilIds, enterCoilNo, currentCoilNo, material, qualityStatus, null, filterSpecIds);
Map<String, Object> raw = baseMapper.selectCountForSpecSync(qw);
if (raw == null) return stats;
stats.put("total", safeLong(raw, "total"));
stats.put("synced", safeLong(raw, "synced"));
stats.put("unsynced", safeLong(raw, "unsynced"));
stats.put("movedOn", safeLong(raw, "movedOn"));
return stats;
}
private long safeLong(Map<String, Object> map, String key) {
Object v = map.get(key);
if (v == null) return 0L;
try { return Long.parseLong(v.toString()); } catch (NumberFormatException e) { return 0L; }
}
private QueryWrapper<WmsMaterialCoil> buildProcessedCoilQw(java.util.Collection<Long> coilIds,
String enterCoilNo, String currentCoilNo, String material, String qualityStatus,
String syncStatus, java.util.Set<Long> filterSpecIds) {
QueryWrapper<WmsMaterialCoil> qw = new QueryWrapper<>();
// 不过滤 data_typedata_type=0已流转/历史)和 data_type=1当前均展示
// movedOn 状态仅作页面标记,不阻断规程绑定
qw.in("mc.coil_id", coilIds).eq("mc.del_flag", 0);
if (StringUtils.isNotBlank(enterCoilNo)) qw.like("mc.enter_coil_no", enterCoilNo);
if (StringUtils.isNotBlank(currentCoilNo)) qw.like("mc.current_coil_no", currentCoilNo);
if (StringUtils.isNotBlank(qualityStatus)) qw.eq("mc.quality_status", qualityStatus);
if (StringUtils.isNotBlank(material)) {
qw.apply("LOWER(CASE WHEN mc.item_type = 'raw_material' THEN COALESCE(rm.material,'') "
+ "ELSE COALESCE(p.material,'') END) LIKE {0}", "%" + material.toLowerCase() + "%");
}
if (filterSpecIds != null && !filterSpecIds.isEmpty()) qw.in("mc.spec_id", filterSpecIds);
// 用 version_id 判断是否已绑规程,与控制层 coil.getVersionId()!=null 的逻辑保持一致
// spec_id 有时可能为空(老数据只写了 version_id用 version_id 更可靠
if ("synced".equals(syncStatus)) qw.isNotNull("mc.version_id");
if ("unsynced".equals(syncStatus)) qw.isNull("mc.version_id");
return qw;
}
@Override
public String queryQualityStatusByWarehouseIdAndCurrentCoilNo(Long warehouseId, String currentCoilNo) {
if (warehouseId == null || StringUtils.isBlank(currentCoilNo)) {

View File

@@ -24,8 +24,12 @@ import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
/**
* 规程版本Service实现
@@ -139,6 +143,135 @@ public class WmsProcessSpecVersionServiceImpl implements IWmsProcessSpecVersionS
return baseMapper.updateById(one) > 0;
}
@Override
public WmsProcessSpecVersionVo matchBestVersion(BigDecimal entryThick, BigDecimal exitThick,
BigDecimal entryWidth, BigDecimal exitWidth,
String grade, Long lineId) {
LambdaQueryWrapper<WmsProcessSpecVersion> lqw = Wrappers.lambdaQuery();
lqw.eq(WmsProcessSpecVersion::getIsActive, 1);
List<WmsProcessSpecVersionVo> versions = baseMapper.selectVoList(lqw);
if (versions.isEmpty()) {
return null;
}
// 按产线ID过滤只匹配属于指定产线的规程版本
if (lineId != null) {
List<Long> specIds = versions.stream()
.map(WmsProcessSpecVersionVo::getSpecId).distinct().collect(Collectors.toList());
LambdaQueryWrapper<WmsProcessSpec> slqw = Wrappers.lambdaQuery();
slqw.in(WmsProcessSpec::getSpecId, specIds);
slqw.eq(WmsProcessSpec::getLineId, lineId);
Set<Long> validSpecIds = wmsProcessSpecMapper.selectList(slqw)
.stream().map(WmsProcessSpec::getSpecId).collect(Collectors.toSet());
versions = versions.stream()
.filter(v -> validSpecIds.contains(v.getSpecId())).collect(Collectors.toList());
if (versions.isEmpty()) {
return null;
}
}
WmsProcessSpecVersionVo best = null;
int bestScore = -1;
for (WmsProcessSpecVersionVo v : versions) {
int score = 0;
if (entryThick != null && v.getMatchEntryThickMin() != null && v.getMatchEntryThickMax() != null
&& entryThick.compareTo(v.getMatchEntryThickMin()) >= 0
&& entryThick.compareTo(v.getMatchEntryThickMax()) <= 0) {
score++;
}
if (exitThick != null && v.getMatchExitThickMin() != null && v.getMatchExitThickMax() != null
&& exitThick.compareTo(v.getMatchExitThickMin()) >= 0
&& exitThick.compareTo(v.getMatchExitThickMax()) <= 0) {
score++;
}
if (entryWidth != null && v.getMatchEntryWidthMin() != null && v.getMatchEntryWidthMax() != null
&& entryWidth.compareTo(v.getMatchEntryWidthMin()) >= 0
&& entryWidth.compareTo(v.getMatchEntryWidthMax()) <= 0) {
score++;
}
if (exitWidth != null && v.getMatchExitWidthMin() != null && v.getMatchExitWidthMax() != null
&& exitWidth.compareTo(v.getMatchExitWidthMin()) >= 0
&& exitWidth.compareTo(v.getMatchExitWidthMax()) <= 0) {
score++;
}
if (StringUtils.isNotBlank(grade) && StringUtils.isNotBlank(v.getMatchSteelGrade())
&& grade.toLowerCase().contains(v.getMatchSteelGrade().toLowerCase())) {
score++;
}
if (score > bestScore) {
bestScore = score;
best = v;
}
}
if (best == null || bestScore == 0) {
return null;
}
WmsProcessSpec spec = wmsProcessSpecMapper.selectById(best.getSpecId());
if (spec != null) {
best.setSpecCode(spec.getSpecCode());
best.setSpecName(spec.getSpecName());
}
return best;
}
@Override
public List<WmsProcessSpecVersionVo> queryActiveVersionsEnriched(Long lineId) {
LambdaQueryWrapper<WmsProcessSpecVersion> lqw = Wrappers.lambdaQuery();
lqw.eq(WmsProcessSpecVersion::getIsActive, 1);
List<WmsProcessSpecVersionVo> versions = baseMapper.selectVoList(lqw);
if (versions.isEmpty()) {
return versions;
}
if (lineId != null) {
List<Long> specIds = versions.stream()
.map(WmsProcessSpecVersionVo::getSpecId).distinct().collect(Collectors.toList());
LambdaQueryWrapper<WmsProcessSpec> slqw = Wrappers.lambdaQuery();
slqw.in(WmsProcessSpec::getSpecId, specIds);
slqw.eq(WmsProcessSpec::getLineId, lineId);
Set<Long> validSpecIds = wmsProcessSpecMapper.selectList(slqw)
.stream().map(WmsProcessSpec::getSpecId).collect(Collectors.toSet());
versions = versions.stream()
.filter(v -> validSpecIds.contains(v.getSpecId())).collect(Collectors.toList());
if (versions.isEmpty()) {
return versions;
}
}
enrichVersionsWithSpec(versions);
return versions;
}
@Override
public List<WmsProcessSpecVersionVo> queryAllVersionsEnriched() {
// 不过滤 isActive获取全部版本含历史版本用于展示已绑定规程名称
List<WmsProcessSpecVersionVo> versions = baseMapper.selectVoList(Wrappers.lambdaQuery());
if (versions.isEmpty()) return versions;
enrichVersionsWithSpec(versions);
return versions;
}
/** 批量填充 specCode / specName / lineId公共逻辑 */
private void enrichVersionsWithSpec(List<WmsProcessSpecVersionVo> versions) {
List<Long> specIds = versions.stream()
.map(WmsProcessSpecVersionVo::getSpecId).distinct().collect(Collectors.toList());
LambdaQueryWrapper<WmsProcessSpec> sq = Wrappers.lambdaQuery();
sq.in(WmsProcessSpec::getSpecId, specIds);
Map<Long, WmsProcessSpec> specMap = wmsProcessSpecMapper.selectList(sq).stream()
.collect(Collectors.toMap(WmsProcessSpec::getSpecId, s -> s, (a, b) -> a));
for (WmsProcessSpecVersionVo v : versions) {
WmsProcessSpec spec = specMap.get(v.getSpecId());
if (spec != null) {
v.setSpecCode(spec.getSpecCode());
v.setSpecName(spec.getSpecName());
v.setLineId(spec.getLineId());
}
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {