This commit is contained in:
砂糖
2026-03-04 16:15:16 +08:00
3 changed files with 55 additions and 109 deletions

View File

@@ -161,15 +161,15 @@ public class WmsMaterialCoilController extends BaseController {
/**
* 钢卷溯源查询
* 根据入场钢卷号查询二维码解析content中的steps然后根据steps中的钢卷号反向查询数据库
* 根据钢卷ID查询二维码解析content中的steps然后根据steps中的钢卷号反向查询数据库
*
* @param enterCoilNo 入场钢卷号
* @param coilId 钢卷ID
* @param currentCoilNo 当前钢卷号(可选参数,用于查询特定子钢卷)
*/
@GetMapping("/trace")
public R<Map<String, Object>> trace(@RequestParam @NotBlank(message = "入场钢卷号不能为空") String enterCoilNo,
public R<Map<String, Object>> trace(@RequestParam @NotNull(message = "钢卷ID不能为空") Long coilId,
@RequestParam(required = false) String currentCoilNo) {
Map<String, Object> traceResult = iWmsMaterialCoilService.queryTrace(enterCoilNo, currentCoilNo);
Map<String, Object> traceResult = iWmsMaterialCoilService.queryTrace(coilId, currentCoilNo);
return R.ok(traceResult);
}

View File

@@ -60,13 +60,13 @@ public interface IWmsMaterialCoilService {
/**
* 钢卷溯源查询
* 根据入场钢卷号查询二维码解析content中的steps然后根据steps中的钢卷号反向查询数据库
* 根据钢卷ID查询二维码解析content中的steps然后根据steps中的钢卷号反向查询数据库
*
* @param enterCoilNo 入场钢卷号
* @param coilId 钢卷ID
* @param currentCoilNo 当前钢卷号(可选,用于查询特定子钢卷)
* @return 溯源结果(包含二维码信息和数据库记录)
*/
Map<String, Object> queryTrace(String enterCoilNo, String currentCoilNo);
Map<String, Object> queryTrace(Long coilId, String currentCoilNo);
/**
* 查询各个库区中不同类型的钢卷分布情况

View File

@@ -1910,105 +1910,67 @@ public class WmsMaterialCoilServiceImpl implements IWmsMaterialCoilService {
/**
* 钢卷溯源查询
* 根据入场钢卷号查询二维码解析content中的steps然后根据steps中的钢卷号反向查询数据库
* 根据钢卷ID查询二维码解析content中的steps然后根据steps中的钢卷号反向查询数据库
*
* @param enterCoilNo 入场钢卷号
* @param coilId 钢卷ID
* @param currentCoilNo 当前钢卷号(可选,用于查询特定子钢卷)
* @return 溯源结果(包含二维码信息和数据库记录)
*/
@Override
public Map<String, Object> queryTrace(String enterCoilNo, String currentCoilNo) {
public Map<String, Object> queryTrace(Long coilId, String currentCoilNo) {
try {
// 优化1: 使用LIKE查询替代查询所有记录大幅提升性能
List<WmsGenerateRecordVo> allQrRecords = new ArrayList<>();
// 首先查询主二维码(以入场钢卷号为序列号的)
WmsGenerateRecordBo qrBo = new WmsGenerateRecordBo();
qrBo.setSerialNumber(enterCoilNo);
List<WmsGenerateRecordVo> mainQrRecords = generateRecordService.queryList(qrBo);
allQrRecords.addAll(mainQrRecords);
// 优化使用LIKE查询所有以该入场钢卷号开头的二维码分卷后的二维码
// 而不是查询所有记录然后在内存中过滤
LambdaQueryWrapper<com.klp.domain.WmsGenerateRecord> splitWrapper = Wrappers.lambdaQuery();
splitWrapper.like(com.klp.domain.WmsGenerateRecord::getSerialNumber, enterCoilNo + "-");
List<WmsGenerateRecordVo> splitRecords = generateRecordMapper.selectVoList(splitWrapper);
// 去重使用recordId作为唯一标识
Set<Long> existingRecordIds = allQrRecords.stream()
.map(WmsGenerateRecordVo::getRecordId)
.collect(Collectors.toSet());
for (WmsGenerateRecordVo record : splitRecords) {
if (record.getRecordId() != null && !existingRecordIds.contains(record.getRecordId())) {
allQrRecords.add(record);
existingRecordIds.add(record.getRecordId());
}
WmsMaterialCoilVo coilVo = baseMapper.selectVoById(coilId);
if (coilVo == null) {
throw new RuntimeException("未找到对应的钢卷记录");
}
if (allQrRecords.isEmpty()) {
Long qrcodeRecordId = coilVo.getQrcodeRecordId();
if (qrcodeRecordId == null) {
throw new RuntimeException("该钢卷未关联二维码记录");
}
WmsGenerateRecordVo qrRecord = generateRecordService.queryById(qrcodeRecordId);
if (qrRecord == null) {
throw new RuntimeException("未找到对应的二维码记录");
}
// 优化2: ObjectMapper在循环外创建避免重复创建
String enterCoilNo = coilVo.getEnterCoilNo();
ObjectMapper objectMapper = new ObjectMapper();
// 2. 合并所有二维码的steps信息去重并重新编号
Map<String, Map<String, Object>> uniqueSteps = new HashMap<>(); // 用于去重
Set<String> allCoilNos = new HashSet<>();
@SuppressWarnings("unchecked")
Map<String, Object> contentMap = objectMapper.readValue(qrRecord.getContent(), Map.class);
// 收集所有操作人用户名
@SuppressWarnings("unchecked")
List<Map<String, Object>> steps = (List<Map<String, Object>>) contentMap.get("steps");
Set<String> allCoilNos = new HashSet<>();
Set<String> operatorUsernames = new HashSet<>();
for (WmsGenerateRecordVo qrRecord : allQrRecords) {
@SuppressWarnings("unchecked")
Map<String, Object> contentMap = (Map<String, Object>) objectMapper.readValue(qrRecord.getContent(), Map.class);
if (steps != null) {
for (Map<String, Object> step : steps) {
extractCoilNo(step, "current_coil_no", allCoilNos);
extractCoilNo(step, "new_current_coil_no", allCoilNos);
extractCoilNo(step, "old_current_coil_no", allCoilNos);
extractCoilNo(step, "new_current_coil_nos", allCoilNos);
extractCoilNo(step, "merged_from", allCoilNos);
extractCoilNo(step, "parent_coil_nos", allCoilNos);
extractCoilId(step, "coil_id", allCoilNos);
extractCoilId(step, "old_coil_id", allCoilNos);
extractCoilId(step, "parent_coil_ids", allCoilNos);
extractCoilId(step, "child_coil_ids", allCoilNos);
@SuppressWarnings("unchecked")
List<Map<String, Object>> steps = (List<Map<String, Object>>) contentMap.get("steps");
if (steps != null) {
for (Map<String, Object> step : steps) {
// 创建唯一标识:操作类型 + 相关钢卷号
String stepKey = createStepKey(step);
// 如果是新的步骤,添加到唯一步骤集合中
if (!uniqueSteps.containsKey(stepKey)) {
Map<String, Object> uniqueStep = new HashMap<>(step);
uniqueStep.put("qrcode_serial", qrRecord.getSerialNumber());
uniqueStep.put("qrcode_id", qrRecord.getRecordId());
uniqueSteps.put(stepKey, uniqueStep);
// 收集操作人用户名
Object operator = step.get("operator");
if (operator != null) {
operatorUsernames.add(operator.toString());
}
}
// 提取钢卷号
extractCoilNo(step, "current_coil_no", allCoilNos);
extractCoilNo(step, "new_current_coil_no", allCoilNos);
extractCoilNo(step, "old_current_coil_no", allCoilNos);
extractCoilNo(step, "new_current_coil_nos", allCoilNos);
extractCoilNo(step, "merged_from", allCoilNos);
extractCoilNo(step, "parent_coil_nos", allCoilNos);
extractCoilId(step, "coil_id", allCoilNos);
extractCoilId(step, "old_coil_id", allCoilNos);
extractCoilId(step, "parent_coil_ids", allCoilNos);
// 从分卷步骤中提取子钢卷IDs
extractCoilId(step, "child_coil_ids", allCoilNos);
Object operator = step.get("operator");
if (operator != null) {
operatorUsernames.add(operator.toString());
}
}
}
// 获取操作人昵称映射
Map<String, String> operatorNicknameMap = getOperatorNicknames(operatorUsernames);
// 转换为列表并按原始步骤号排序(保持时间顺序)
List<Map<String, Object>> allSteps = new ArrayList<>(uniqueSteps.values());
List<Map<String, Object>> allSteps = new ArrayList<>(steps != null ? steps : new ArrayList<>());
// 按原始步骤号排序,保持实际操作的时间顺序
allSteps.sort((a, b) -> {
Integer stepA = (Integer) a.get("step");
Integer stepB = (Integer) b.get("step");
@@ -2017,13 +1979,12 @@ public class WmsMaterialCoilServiceImpl implements IWmsMaterialCoilService {
return stepA.compareTo(stepB);
});
// 重新编号(保持连续性)
for (int i = 0; i < allSteps.size(); i++) {
allSteps.get(i).put("display_step", i + 1);
// 保留原始步骤号用于调试
allSteps.get(i).put("original_step", allSteps.get(i).get("step"));
allSteps.get(i).put("qrcode_serial", qrRecord.getSerialNumber());
allSteps.get(i).put("qrcode_id", qrRecord.getRecordId());
// 替换操作人为昵称
Object operator = allSteps.get(i).get("operator");
if (operator != null) {
String username = operator.toString();
@@ -2032,7 +1993,6 @@ public class WmsMaterialCoilServiceImpl implements IWmsMaterialCoilService {
}
}
// 3. 如果指定了当前钢卷号,过滤出相关的钢卷号
Set<String> filteredCoilNos = allCoilNos;
if (currentCoilNo != null && !currentCoilNo.trim().isEmpty()) {
final String filterValue = currentCoilNo;
@@ -2041,20 +2001,16 @@ public class WmsMaterialCoilServiceImpl implements IWmsMaterialCoilService {
.collect(Collectors.toSet());
}
// 优化3: 使用IN查询替代多个OR条件提升查询性能
// 4. 根据提取的钢卷号反向查询数据库
List<WmsMaterialCoilVo> result = new ArrayList<>();
if (!filteredCoilNos.isEmpty()) {
LambdaQueryWrapper<WmsMaterialCoil> lqw = Wrappers.lambdaQuery();
lqw.eq(WmsMaterialCoil::getEnterCoilNo, enterCoilNo);
// 优化使用IN查询替代多个OR条件当钢卷号数量较少时
// 如果数量太多(>1000分批查询避免SQL过长
if (!filteredCoilNos.isEmpty() && StringUtils.isNotBlank(enterCoilNo)) {
List<String> coilNoList = new ArrayList<>(filteredCoilNos);
if (coilNoList.size() <= 1000) {
LambdaQueryWrapper<WmsMaterialCoil> lqw = Wrappers.lambdaQuery();
lqw.eq(WmsMaterialCoil::getEnterCoilNo, enterCoilNo);
lqw.in(WmsMaterialCoil::getCurrentCoilNo, coilNoList);
lqw.orderByAsc(WmsMaterialCoil::getCreateTime);
result = baseMapper.selectVoList(lqw);
} else {
// 分批查询
int batchSize = 1000;
for (int i = 0; i < coilNoList.size(); i += batchSize) {
int end = Math.min(i + batchSize, coilNoList.size());
@@ -2068,36 +2024,26 @@ public class WmsMaterialCoilServiceImpl implements IWmsMaterialCoilService {
}
}
if (coilNoList.size() <= 1000) {
lqw.orderByAsc(WmsMaterialCoil::getCreateTime);
result = baseMapper.selectVoList(lqw);
}
// 优化4: 批量填充关联对象避免N+1查询
if (!result.isEmpty()) {
fillRelatedObjectsBatch(result);
}
}
// 如果没有找到记录,尝试查询所有相关的钢卷(包括历史数据)
if (result.isEmpty()) {
if (result.isEmpty() && StringUtils.isNotBlank(enterCoilNo)) {
LambdaQueryWrapper<WmsMaterialCoil> lqw = Wrappers.lambdaQuery();
lqw.eq(WmsMaterialCoil::getEnterCoilNo, enterCoilNo);
lqw.orderByAsc(WmsMaterialCoil::getCreateTime);
result = baseMapper.selectVoList(lqw);
// 优化:批量填充关联对象
if (!result.isEmpty()) {
fillRelatedObjectsBatch(result);
}
}
// 5. 构建返回结果
Map<String, Object> resultMap = new HashMap<>();
resultMap.put("qrcode", allQrRecords.get(0)); // 主二维码
resultMap.put("all_qrcodes", allQrRecords); // 所有相关二维码
resultMap.put("steps", allSteps); // 所有步骤
resultMap.put("records", result); // 所有钢卷记录
resultMap.put("qrcode", qrRecord);
resultMap.put("steps", allSteps);
resultMap.put("records", result);
return resultMap;
} catch (Exception e) {