同步规程同步代码和录入监测代码
This commit is contained in:
@@ -361,6 +361,59 @@ public class SqlServerApiClient {
|
||||
);
|
||||
}
|
||||
|
||||
public ExecuteSqlResponse queryPlanListByHotCoilIdLike(String hotCoilId, int page, int pageSize) {
|
||||
int endRow = page * pageSize;
|
||||
int startRow = endRow - pageSize;
|
||||
Map<String, Object> params = new java.util.HashMap<>();
|
||||
params.put("startRow", startRow);
|
||||
params.put("endRow", endRow);
|
||||
params.put("hotCoilId", "%" + hotCoilId + "%");
|
||||
return executeSql(
|
||||
"oracle",
|
||||
"select * from (select t.*, ROWNUM rn from (select * from JXPLTCM.PLTCM_PDI_PLAN where HOT_COILID LIKE :hotCoilId order by INSDATE desc) t where ROWNUM <= :endRow) where rn > :startRow",
|
||||
params
|
||||
);
|
||||
}
|
||||
|
||||
public ExecuteSqlResponse queryPlanCountByHotCoilIdLike(String hotCoilId) {
|
||||
return executeSql(
|
||||
"oracle",
|
||||
"select count(*) as total from JXPLTCM.PLTCM_PDI_PLAN where HOT_COILID LIKE :hotCoilId",
|
||||
singletonParam("hotCoilId", "%" + hotCoilId + "%")
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量按 EXCOILID 查询出口卷上线/下线时间(PLTCM_PDO_EXCOIL)
|
||||
*/
|
||||
public ExecuteSqlResponse queryExcoilTimesByCoilIds(List<String> coilIds) {
|
||||
if (coilIds == null || coilIds.isEmpty()) {
|
||||
return new ExecuteSqlResponse();
|
||||
}
|
||||
String inList = coilIds.stream()
|
||||
.filter(id -> id != null && !id.trim().isEmpty())
|
||||
.map(id -> "'" + id.replace("'", "''") + "'")
|
||||
.collect(java.util.stream.Collectors.joining(", "));
|
||||
if (inList.isEmpty()) return new ExecuteSqlResponse();
|
||||
String sql = "SELECT EXCOILID, START_DATE, END_DATE FROM JXPLTCM.PLTCM_PDO_EXCOIL WHERE EXCOILID IN (" + inList + ")";
|
||||
return executeSql("oracle", sql, emptyParams());
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量按 HOT_COILID 查询计划数据(IN 子句,一次 Oracle 调用获取整页数据)
|
||||
*/
|
||||
public ExecuteSqlResponse queryPlanDimsByHotCoilIds(List<String> hotCoilIds) {
|
||||
if (hotCoilIds == null || hotCoilIds.isEmpty()) {
|
||||
return new ExecuteSqlResponse();
|
||||
}
|
||||
String inList = hotCoilIds.stream()
|
||||
.map(id -> "'" + id.replace("'", "''") + "'")
|
||||
.collect(java.util.stream.Collectors.joining(", "));
|
||||
String sql = "SELECT HOT_COILID, ENTRY_THICK, EXIT_THICK, ENTRY_WIDTH, EXIT_WIDTH, GRADE, PROCESS_CODE, COILID " +
|
||||
"FROM JXPLTCM.PLTCM_PDI_PLAN WHERE HOT_COILID IN (" + inList + ")";
|
||||
return executeSql("oracle", sql, emptyParams());
|
||||
}
|
||||
|
||||
public ExecuteSqlResponse queryProSegByEncoilId(String encoilId) {
|
||||
return executeSql(
|
||||
"oracle",
|
||||
|
||||
@@ -66,6 +66,51 @@ public class SqlServerApiBusinessService {
|
||||
return PlanListView.fromExecuteSqlResponse(client.queryPlanListByStatus(status));
|
||||
}
|
||||
|
||||
public PlanListView getPlanListByHotCoilIdLike(String hotCoilId, int page, int pageSize) {
|
||||
return PlanListView.fromExecuteSqlResponse(client.queryPlanListByHotCoilIdLike(hotCoilId, page, pageSize));
|
||||
}
|
||||
|
||||
public long getPlanCountByHotCoilIdLike(String hotCoilId) {
|
||||
List<Map<String, Object>> rows = asRowList(client.queryPlanCountByHotCoilIdLike(hotCoilId));
|
||||
if (rows.isEmpty()) return 0L;
|
||||
Object total = rows.get(0).get("total");
|
||||
Number n = asNumber(total);
|
||||
return n == null ? 0L : n.longValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量获取 L2 计划维度数据(来回料厚/宽、钢种),一次 Oracle 调用覆盖整页。
|
||||
* 返回 Map<hotCoilId, firstRow>,同一 HOT_COILID 只保留第一行。
|
||||
*/
|
||||
/**
|
||||
* 批量查询出口卷上线/下线时间,返回 Map<excoilId, {START_DATE, END_DATE}>
|
||||
*/
|
||||
public Map<String, Map<String, Object>> getExcoilTimesByCoilIds(List<String> coilIds) {
|
||||
if (coilIds == null || coilIds.isEmpty()) return Collections.emptyMap();
|
||||
List<Map<String, Object>> rows = asRowList(client.queryExcoilTimesByCoilIds(coilIds));
|
||||
Map<String, Map<String, Object>> result = new LinkedHashMap<>();
|
||||
for (Map<String, Object> row : rows) {
|
||||
Object id = row.getOrDefault("EXCOILID", row.get("excoilid"));
|
||||
if (id != null) result.putIfAbsent(id.toString().trim(), row);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public Map<String, Map<String, Object>> getPlanDimsByHotCoilIds(List<String> hotCoilIds) {
|
||||
if (hotCoilIds == null || hotCoilIds.isEmpty()) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
List<Map<String, Object>> rows = asRowList(client.queryPlanDimsByHotCoilIds(hotCoilIds));
|
||||
Map<String, Map<String, Object>> result = new LinkedHashMap<>();
|
||||
for (Map<String, Object> row : rows) {
|
||||
Object hcId = row.getOrDefault("HOT_COILID", row.get("hot_coilid"));
|
||||
if (hcId != null) {
|
||||
result.putIfAbsent(hcId.toString().trim(), row);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 计划详情:按成品卷号查询单条计划。
|
||||
*/
|
||||
|
||||
502
klp-admin/src/main/java/com/klp/wms/WmsSpecSyncController.java
Normal file
502
klp-admin/src/main/java/com/klp/wms/WmsSpecSyncController.java
Normal file
@@ -0,0 +1,502 @@
|
||||
package com.klp.wms;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.klp.common.core.controller.BaseController;
|
||||
import com.klp.common.core.domain.R;
|
||||
import com.klp.domain.WmsCoilPendingAction;
|
||||
import com.klp.domain.WmsProductionLine;
|
||||
import com.klp.domain.bo.WmsMaterialCoilBo;
|
||||
import com.klp.domain.vo.WmsCoilPendingActionVo;
|
||||
import com.klp.domain.vo.WmsMaterialCoilVo;
|
||||
import com.klp.domain.vo.WmsProcessSpecVersionVo;
|
||||
import com.klp.framework.service.SqlServerApiBusinessService;
|
||||
import com.klp.mapper.WmsCoilPendingActionMapper;
|
||||
import com.klp.mapper.WmsProductionLineMapper;
|
||||
import com.klp.service.IWmsMaterialCoilService;
|
||||
import com.klp.service.IWmsProcessSpecVersionService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 规程同步接口(跨模块:同时依赖 klp-admin 的 L2 服务和 klp-wms 的规程/钢卷服务)
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/wms/specSync")
|
||||
public class WmsSpecSyncController extends BaseController {
|
||||
|
||||
private final SqlServerApiBusinessService sqlServerApiBusinessService;
|
||||
private final IWmsProcessSpecVersionService specVersionService;
|
||||
private final IWmsMaterialCoilService materialCoilService;
|
||||
private final WmsProductionLineMapper productionLineMapper;
|
||||
private final WmsCoilPendingActionMapper pendingActionMapper;
|
||||
|
||||
/**
|
||||
* 根据热卷号匹配最佳规程版本(供 typing.vue 在 L2 填入后调用)
|
||||
*/
|
||||
@GetMapping("/matchBest")
|
||||
public R<WmsProcessSpecVersionVo> matchBest(@RequestParam String hotCoilId,
|
||||
@RequestParam(required = false) Long lineId) {
|
||||
SqlServerApiBusinessService.PlanDetailView plan =
|
||||
sqlServerApiBusinessService.getPlanByHotCoilId(hotCoilId);
|
||||
if (plan == null || plan.getFirstRow().isEmpty()) {
|
||||
return R.ok(null);
|
||||
}
|
||||
Map<String, Object> row = plan.getFirstRow();
|
||||
BigDecimal entryThick = toBigDecimal(row, "ENTRY_THICK", "entry_thick");
|
||||
BigDecimal exitThick = toBigDecimal(row, "EXIT_THICK", "exit_thick");
|
||||
BigDecimal entryWidth = toBigDecimal(row, "ENTRY_WIDTH", "entry_width");
|
||||
BigDecimal exitWidth = toBigDecimal(row, "EXIT_WIDTH", "exit_width");
|
||||
String grade = toStr(row, "GRADE", "grade");
|
||||
|
||||
WmsProcessSpecVersionVo best = specVersionService.matchBestVersion(
|
||||
entryThick, exitThick, entryWidth, exitWidth, grade, lineId);
|
||||
return R.ok(best);
|
||||
}
|
||||
|
||||
/**
|
||||
* 规程同步分页列表。
|
||||
* 以 L3(WMS MySQL)为主维度:只展示在 wms_coil_pending_action.processed_coil_ids
|
||||
* 中出现过的钢卷(即生产后处理过的),再按 enter_coil_no = HOT_COILID 从 L2(Oracle)
|
||||
* 批量富化计划维度(入口/出口厚宽、钢种等)及上线/下线时间。
|
||||
*/
|
||||
@GetMapping("/pageList")
|
||||
public R<Map<String, Object>> pageList(
|
||||
@RequestParam(defaultValue = "1") int pageNum,
|
||||
@RequestParam(defaultValue = "40") int pageSize,
|
||||
@RequestParam(required = false) String enterCoilNo,
|
||||
@RequestParam(required = false) String currentCoilNo,
|
||||
@RequestParam(required = false) String material,
|
||||
@RequestParam(required = false) String qualityStatus,
|
||||
@RequestParam(required = false) String specCode,
|
||||
@RequestParam(required = false) String syncStatus,
|
||||
@RequestParam(required = false) Long lineId) {
|
||||
|
||||
// ── 1. 预加载规程版本 ──────────────────────────────────────────────────
|
||||
// 活跃版本:仅用于推荐候选匹配
|
||||
List<WmsProcessSpecVersionVo> allActive = specVersionService.queryActiveVersionsEnriched(null);
|
||||
List<WmsProcessSpecVersionVo> globalCandidates = lineId != null
|
||||
? allActive.stream().filter(v -> lineId.equals(v.getLineId())).collect(Collectors.toList())
|
||||
: allActive;
|
||||
// 全部版本(含历史版本):用于展示已绑定规程名称,避免旧版本查不到
|
||||
Map<Long, WmsProcessSpecVersionVo> allVersionById = specVersionService.queryAllVersionsEnriched().stream()
|
||||
.collect(Collectors.toMap(WmsProcessSpecVersionVo::getVersionId, v -> v, (a, b) -> a));
|
||||
|
||||
// specCode 过滤 → specId 集合(后置内存过滤,从全部版本里搜)
|
||||
final Set<Long> filterSpecIds;
|
||||
if (StringUtils.hasText(specCode)) {
|
||||
final String kw = specCode.trim().toLowerCase();
|
||||
filterSpecIds = allVersionById.values().stream()
|
||||
.filter(v -> (v.getSpecCode() != null && v.getSpecCode().toLowerCase().contains(kw))
|
||||
|| (v.getSpecName() != null && v.getSpecName().toLowerCase().contains(kw)))
|
||||
.map(WmsProcessSpecVersionVo::getSpecId)
|
||||
.collect(Collectors.toSet());
|
||||
} else {
|
||||
filterSpecIds = null;
|
||||
}
|
||||
|
||||
// ── 2. 预加载产线表 → actionType(int) → Set<lineId> ───────────────────
|
||||
// 有效产线:wms_production_line.action_type IS NOT NULL(即配置了操作类型的产线)
|
||||
List<WmsProductionLine> allLines = productionLineMapper.selectList(
|
||||
Wrappers.<WmsProductionLine>lambdaQuery()
|
||||
.isNotNull(WmsProductionLine::getActionType));
|
||||
Map<Integer, Set<Long>> actionTypeToLineIds = new HashMap<>();
|
||||
for (WmsProductionLine pl : allLines) {
|
||||
if (!StringUtils.hasText(pl.getActionType())) continue;
|
||||
for (String part : pl.getActionType().split(",")) {
|
||||
try {
|
||||
int at = Integer.parseInt(part.trim());
|
||||
actionTypeToLineIds.computeIfAbsent(at, k -> new HashSet<>()).add(pl.getLineId());
|
||||
} catch (NumberFormatException ignore) { /* 跳过非数字 */ }
|
||||
}
|
||||
}
|
||||
|
||||
// ── 3. 展开已录入(action_status=2)待操作的 processed_coil_ids → 输出钢卷 ID ──
|
||||
Set<Integer> validActionTypes = actionTypeToLineIds.keySet();
|
||||
Set<Long> typedCoilIds = new LinkedHashSet<>();
|
||||
Map<Long, Integer> allCoilIdToActionType = new HashMap<>();
|
||||
|
||||
if (!validActionTypes.isEmpty()) {
|
||||
List<WmsCoilPendingAction> allPaList =
|
||||
pendingActionMapper.selectAllProcessedCoilIdsAndActionStatus();
|
||||
for (WmsCoilPendingAction pa : allPaList) {
|
||||
if (pa.getActionType() == null || !validActionTypes.contains(pa.getActionType())) continue;
|
||||
if (!StringUtils.hasText(pa.getProcessedCoilIds())) continue;
|
||||
for (String idStr : pa.getProcessedCoilIds().split(",")) {
|
||||
try {
|
||||
long pid = Long.parseLong(idStr.trim());
|
||||
typedCoilIds.add(pid);
|
||||
allCoilIdToActionType.putIfAbsent(pid, pa.getActionType());
|
||||
} catch (NumberFormatException ignore) { /* 跳过非数字 */ }
|
||||
}
|
||||
}
|
||||
}
|
||||
final Map<Long, Integer> coilIdToActionType = allCoilIdToActionType;
|
||||
|
||||
// ── 4. 计数分页(仅已录入钢卷,按规程绑定状态过滤)────────────────────────
|
||||
final String effectiveSyncStatus;
|
||||
if ("synced".equals(syncStatus)) effectiveSyncStatus = "synced";
|
||||
else if ("unsynced".equals(syncStatus)) effectiveSyncStatus = "unsynced";
|
||||
else effectiveSyncStatus = null;
|
||||
|
||||
if (typedCoilIds.isEmpty()) {
|
||||
Map<String, Object> emptyResult = new LinkedHashMap<>();
|
||||
emptyResult.put("rows", Collections.emptyList());
|
||||
emptyResult.put("total", 0L);
|
||||
return R.ok(emptyResult);
|
||||
}
|
||||
|
||||
// ── 4a. 整体汇总统计(忽略 syncStatus 过滤,体现全量分布) ─────────────────
|
||||
Map<String, Long> overallStats = materialCoilService.getOverallSyncStats(
|
||||
typedCoilIds, enterCoilNo, currentCoilNo, material, qualityStatus, filterSpecIds);
|
||||
|
||||
int offset = (pageNum - 1) * pageSize;
|
||||
long total = materialCoilService.countByProcessedCoilIds(
|
||||
typedCoilIds, enterCoilNo, currentCoilNo, material, qualityStatus,
|
||||
effectiveSyncStatus, filterSpecIds);
|
||||
List<WmsMaterialCoilVo> l3Coils = materialCoilService.queryByProcessedCoilIds(
|
||||
typedCoilIds, enterCoilNo, currentCoilNo, material, qualityStatus,
|
||||
effectiveSyncStatus, filterSpecIds, offset, pageSize);
|
||||
|
||||
if (l3Coils.isEmpty()) {
|
||||
Map<String, Object> emptyResult = new LinkedHashMap<>();
|
||||
emptyResult.put("rows", Collections.emptyList());
|
||||
emptyResult.put("total", total);
|
||||
emptyResult.put("overallStats", overallStats);
|
||||
return R.ok(emptyResult);
|
||||
}
|
||||
|
||||
// ── 5. L2 富化:批量按 enter_coil_no(= HOT_COILID)查询计划维度 ──────────
|
||||
List<String> enterCoilNos = new ArrayList<>();
|
||||
Set<String> seenNos = new HashSet<>();
|
||||
for (WmsMaterialCoilVo c : l3Coils) {
|
||||
String primary = primaryEnterCoilNo(c.getEnterCoilNo());
|
||||
if (primary != null && seenNos.add(primary)) enterCoilNos.add(primary);
|
||||
}
|
||||
Map<String, Map<String, Object>> l2DimMap =
|
||||
sqlServerApiBusinessService.getPlanDimsByHotCoilIds(enterCoilNos);
|
||||
|
||||
// ── 6. 上线/下线时间:PLTCM_PDO_EXCOIL.EXCOILID = PLTCM_PDI_PLAN.COILID ──
|
||||
List<String> l2CoilIds = new ArrayList<>();
|
||||
for (Map<String, Object> dims : l2DimMap.values()) {
|
||||
String cid = toStr(dims, "COILID", "coilid");
|
||||
if (StringUtils.hasText(cid)) l2CoilIds.add(cid);
|
||||
}
|
||||
Map<String, Map<String, Object>> excoilTimeMap =
|
||||
sqlServerApiBusinessService.getExcoilTimesByCoilIds(l2CoilIds);
|
||||
|
||||
// ── 7. 组装行 ──────────────────────────────────────────────────────────────
|
||||
List<Map<String, Object>> rows = new ArrayList<>();
|
||||
for (WmsMaterialCoilVo coil : l3Coils) {
|
||||
Map<String, Object> row = new LinkedHashMap<>();
|
||||
String primaryNo = primaryEnterCoilNo(coil.getEnterCoilNo());
|
||||
|
||||
// ── L3 基础字段 ──
|
||||
row.put("wmsCoilId", coil.getCoilId());
|
||||
row.put("enterCoilNo", primaryNo);
|
||||
row.put("currentCoilNo", coil.getCurrentCoilNo());
|
||||
row.put("supplierCoilNo", coil.getSupplierCoilNo());
|
||||
row.put("netWeight", coil.getNetWeight());
|
||||
row.put("actualThickness", coil.getActualThickness());
|
||||
row.put("actualWidth", coil.getActualWidth());
|
||||
row.put("qualityStatus", coil.getQualityStatus());
|
||||
row.put("specification", coil.getSpecification());
|
||||
row.put("material", coil.getMaterial());
|
||||
|
||||
// 是否已流转(data_type=0)
|
||||
boolean movedOn = Integer.valueOf(0).equals(coil.getDataType());
|
||||
row.put("movedOn", movedOn);
|
||||
row.put("dataType", coil.getDataType());
|
||||
|
||||
// ── L2 数据有则富化,无则留空(不跳过,避免破坏分页偏移)──
|
||||
Map<String, Object> l2row = primaryNo != null ? l2DimMap.get(primaryNo) : null;
|
||||
BigDecimal entryThick = null, exitThick = null, entryWidth = null, exitWidth = null;
|
||||
String grade = null, l2CoilId = null;
|
||||
if (l2row != null) {
|
||||
entryThick = toBigDecimal(l2row, "ENTRY_THICK", "entry_thick");
|
||||
exitThick = toBigDecimal(l2row, "EXIT_THICK", "exit_thick");
|
||||
entryWidth = toBigDecimal(l2row, "ENTRY_WIDTH", "entry_width");
|
||||
exitWidth = toBigDecimal(l2row, "EXIT_WIDTH", "exit_width");
|
||||
grade = toStr(l2row, "GRADE", "grade");
|
||||
l2CoilId = toStr(l2row, "COILID", "coilid");
|
||||
row.put("entryThick", entryThick);
|
||||
row.put("exitThick", exitThick);
|
||||
row.put("entryWidth", entryWidth);
|
||||
row.put("exitWidth", exitWidth);
|
||||
row.put("grade", grade);
|
||||
row.put("processCode", toStr(l2row, "PROCESS_CODE", "process_code"));
|
||||
row.put("l2CoilId", l2CoilId);
|
||||
row.put("l2Found", true);
|
||||
}
|
||||
|
||||
// 上线/下线时间
|
||||
Map<String, Object> excoilTimes = StringUtils.hasText(l2CoilId)
|
||||
? excoilTimeMap.get(l2CoilId) : null;
|
||||
if (excoilTimes != null) {
|
||||
row.put("onlineTime", excoilTimes.getOrDefault("START_DATE", excoilTimes.get("start_date")));
|
||||
row.put("offlineTime", excoilTimes.getOrDefault("END_DATE", excoilTimes.get("end_date")));
|
||||
}
|
||||
|
||||
// ── 规程绑定状态 ──
|
||||
if (coil.getVersionId() != null) {
|
||||
WmsProcessSpecVersionVo bound = allVersionById.get(coil.getVersionId());
|
||||
if (bound != null) {
|
||||
row.put("specCode", bound.getSpecCode());
|
||||
row.put("specName", bound.getSpecName());
|
||||
row.put("versionCode", bound.getVersionCode());
|
||||
putMatchConds(row, bound);
|
||||
}
|
||||
row.put("syncStatus", "synced");
|
||||
} else {
|
||||
row.put("syncStatus", "unsynced");
|
||||
// 按产线限定候选规程(lineId=null 的规程不限定产线,始终纳入)
|
||||
Integer pendingAt = coilIdToActionType.get(coil.getCoilId());
|
||||
Set<Long> allowedLineIds = pendingAt != null
|
||||
? actionTypeToLineIds.getOrDefault(pendingAt, Collections.emptySet())
|
||||
: null;
|
||||
// 优先用同产线规程;若过滤后为空则兜底到全量活跃版本
|
||||
List<WmsProcessSpecVersionVo> candidates;
|
||||
if (allowedLineIds == null || allowedLineIds.isEmpty()) {
|
||||
candidates = globalCandidates;
|
||||
} else {
|
||||
candidates = globalCandidates.stream()
|
||||
.filter(v -> v.getLineId() == null || allowedLineIds.contains(v.getLineId()))
|
||||
.collect(Collectors.toList());
|
||||
if (candidates.isEmpty()) {
|
||||
candidates = globalCandidates; // 兜底:产线无匹配规程时展示全部
|
||||
}
|
||||
}
|
||||
WmsProcessSpecVersionVo best = null;
|
||||
int bestScore = -1;
|
||||
for (WmsProcessSpecVersionVo v : candidates) {
|
||||
int s = scoreVersion(v, entryThick, exitThick, entryWidth, exitWidth, grade);
|
||||
if (s > bestScore) { bestScore = s; best = v; }
|
||||
}
|
||||
// bestScore >= 0:只要存在候选规程就展示推荐(0 = 无维度条件匹配但仍有版本可绑)
|
||||
if (best != null && bestScore >= 0) {
|
||||
row.put("candidateSpecCode", best.getSpecCode());
|
||||
row.put("candidateSpecName", best.getSpecName());
|
||||
row.put("candidateVersionCode", best.getVersionCode());
|
||||
row.put("candidateVersionId", best.getVersionId());
|
||||
row.put("candidateSpecId", best.getSpecId());
|
||||
putMatchConds(row, best);
|
||||
}
|
||||
}
|
||||
rows.add(row);
|
||||
}
|
||||
|
||||
Map<String, Object> result = new LinkedHashMap<>();
|
||||
result.put("rows", rows);
|
||||
result.put("total", total);
|
||||
result.put("overallStats", overallStats);
|
||||
return R.ok(result);
|
||||
}
|
||||
|
||||
// ── 私有工具方法 ─────────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* enter_coil_no 字段可能存储了多个逗号分隔的热卷号(如 "26032550,26032550")。
|
||||
* 取第一个非空值作为主键,用于展示和 L2 关联查询。
|
||||
*/
|
||||
private String primaryEnterCoilNo(String raw) {
|
||||
if (!StringUtils.hasText(raw)) return null;
|
||||
String first = raw.split(",")[0].trim();
|
||||
return first.isEmpty() ? null : first;
|
||||
}
|
||||
|
||||
private int scoreVersion(WmsProcessSpecVersionVo v,
|
||||
BigDecimal entryThick, BigDecimal exitThick,
|
||||
BigDecimal entryWidth, BigDecimal exitWidth, String grade) {
|
||||
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.hasText(grade) && StringUtils.hasText(v.getMatchSteelGrade())
|
||||
&& grade.toLowerCase().contains(v.getMatchSteelGrade().toLowerCase())) score++;
|
||||
return score;
|
||||
}
|
||||
|
||||
private void putMatchConds(Map<String, Object> row, WmsProcessSpecVersionVo v) {
|
||||
row.put("matchEntryThickMin", v.getMatchEntryThickMin());
|
||||
row.put("matchEntryThickMax", v.getMatchEntryThickMax());
|
||||
row.put("matchExitThickMin", v.getMatchExitThickMin());
|
||||
row.put("matchExitThickMax", v.getMatchExitThickMax());
|
||||
row.put("matchEntryWidthMin", v.getMatchEntryWidthMin());
|
||||
row.put("matchEntryWidthMax", v.getMatchEntryWidthMax());
|
||||
row.put("matchExitWidthMin", v.getMatchExitWidthMin());
|
||||
row.put("matchExitWidthMax", v.getMatchExitWidthMax());
|
||||
row.put("matchSteelGrade", v.getMatchSteelGrade());
|
||||
}
|
||||
|
||||
/**
|
||||
* 待录入核查分页列表。
|
||||
* 数据源:wms_production_line 有效产线对应的待操作记录中 action_status != 2(尚未完成 typing)的条目。
|
||||
* 额外按入场卷号从 L2(Oracle)查询计划/实绩维度,供核查人员判断二级是否已有实绩。
|
||||
*/
|
||||
@GetMapping("/untypedPageList")
|
||||
public R<Map<String, Object>> untypedPageList(
|
||||
@RequestParam(defaultValue = "1") int pageNum,
|
||||
@RequestParam(defaultValue = "40") int pageSize,
|
||||
@RequestParam(required = false) String enterCoilNo,
|
||||
@RequestParam(required = false) String currentCoilNo,
|
||||
@RequestParam(required = false) String operatorName) {
|
||||
|
||||
// ── 1. 有效产线 actionType ──────────────────────────────────────────────
|
||||
List<WmsProductionLine> lines = productionLineMapper.selectList(
|
||||
Wrappers.<WmsProductionLine>lambdaQuery().isNotNull(WmsProductionLine::getActionType));
|
||||
Set<Integer> validAts = new HashSet<>();
|
||||
for (WmsProductionLine pl : lines) {
|
||||
if (!StringUtils.hasText(pl.getActionType())) continue;
|
||||
for (String part : pl.getActionType().split(",")) {
|
||||
try { validAts.add(Integer.parseInt(part.trim())); } catch (NumberFormatException ignore) {}
|
||||
}
|
||||
}
|
||||
if (validAts.isEmpty()) {
|
||||
Map<String, Object> empty = new LinkedHashMap<>();
|
||||
empty.put("rows", Collections.emptyList());
|
||||
empty.put("total", 0L);
|
||||
return R.ok(empty);
|
||||
}
|
||||
|
||||
// ── 2. 分页查询未录入待操作 ────────────────────────────────────────────────
|
||||
// 条件1:action_status IN (0,1) —— 0=待处理/1=进行中,2=已完成/3=已取消均排除
|
||||
// 条件2:processed_coil_ids 为空 —— 只有未写入产出卷 ID 的记录才是尚未录入的
|
||||
QueryWrapper<WmsCoilPendingAction> qw = new QueryWrapper<>();
|
||||
qw.eq("wcpa.del_flag", 0);
|
||||
qw.in("wcpa.action_type", validAts);
|
||||
qw.in("wcpa.action_status", java.util.Arrays.asList(0, 1));
|
||||
qw.and(w -> w.isNull("wcpa.processed_coil_ids")
|
||||
.or().eq("wcpa.processed_coil_ids", ""));
|
||||
if (StringUtils.hasText(enterCoilNo)) qw.like("wmc.enter_coil_no", enterCoilNo);
|
||||
if (StringUtils.hasText(currentCoilNo)) qw.like("wcpa.current_coil_no", currentCoilNo);
|
||||
if (StringUtils.hasText(operatorName)) qw.like("wcpa.operator_name", operatorName);
|
||||
qw.orderByDesc("wcpa.scan_time");
|
||||
|
||||
Page<WmsCoilPendingActionVo> voPage =
|
||||
pendingActionMapper.selectVoPagePlus(Page.of(pageNum, pageSize), qw);
|
||||
List<WmsCoilPendingActionVo> paList = voPage.getRecords();
|
||||
|
||||
if (paList.isEmpty()) {
|
||||
Map<String, Object> empty = new LinkedHashMap<>();
|
||||
empty.put("rows", Collections.emptyList());
|
||||
empty.put("total", voPage.getTotal());
|
||||
return R.ok(empty);
|
||||
}
|
||||
|
||||
// ── 3. L2 富化 ─────────────────────────────────────────────────────────
|
||||
List<String> nos = new ArrayList<>();
|
||||
Set<String> seen = new HashSet<>();
|
||||
for (WmsCoilPendingActionVo pa : paList) {
|
||||
String primary = primaryEnterCoilNo(pa.getEnterCoilNo());
|
||||
if (primary != null && seen.add(primary)) nos.add(primary);
|
||||
}
|
||||
Map<String, Map<String, Object>> l2DimMap = nos.isEmpty()
|
||||
? Collections.emptyMap()
|
||||
: sqlServerApiBusinessService.getPlanDimsByHotCoilIds(nos);
|
||||
|
||||
// ── 4. 组装行 ──────────────────────────────────────────────────────────
|
||||
List<Map<String, Object>> rows = new ArrayList<>();
|
||||
for (WmsCoilPendingActionVo pa : paList) {
|
||||
String primaryNo = primaryEnterCoilNo(pa.getEnterCoilNo());
|
||||
Map<String, Object> l2row = primaryNo != null ? l2DimMap.get(primaryNo) : null;
|
||||
Map<String, Object> row = new LinkedHashMap<>();
|
||||
row.put("actionId", pa.getActionId());
|
||||
row.put("coilId", pa.getCoilId());
|
||||
row.put("actionType", pa.getActionType());
|
||||
row.put("actionStatus", pa.getActionStatus());
|
||||
row.put("scanTime", pa.getScanTime());
|
||||
row.put("createTime", pa.getCreateTime());
|
||||
row.put("operatorName", pa.getOperatorName());
|
||||
row.put("warehouseName", pa.getWarehouseName());
|
||||
row.put("enterCoilNo", primaryNo);
|
||||
row.put("currentCoilNo", pa.getCurrentCoilNo());
|
||||
row.put("supplierCoilNo", pa.getSupplierCoilNo());
|
||||
row.put("material", pa.getMaterial());
|
||||
row.put("specification", pa.getSpecification());
|
||||
row.put("itemName", pa.getItemName());
|
||||
if (l2row != null) {
|
||||
row.put("entryThick", toBigDecimal(l2row, "ENTRY_THICK", "entry_thick"));
|
||||
row.put("exitThick", toBigDecimal(l2row, "EXIT_THICK", "exit_thick"));
|
||||
row.put("entryWidth", toBigDecimal(l2row, "ENTRY_WIDTH", "entry_width"));
|
||||
row.put("exitWidth", toBigDecimal(l2row, "EXIT_WIDTH", "exit_width"));
|
||||
row.put("grade", toStr(l2row, "GRADE", "grade"));
|
||||
row.put("processCode", toStr(l2row, "PROCESS_CODE", "process_code"));
|
||||
row.put("l2Found", true);
|
||||
} else {
|
||||
row.put("l2Found", false);
|
||||
}
|
||||
rows.add(row);
|
||||
}
|
||||
|
||||
Map<String, Object> result = new LinkedHashMap<>();
|
||||
result.put("rows", rows);
|
||||
result.put("total", voPage.getTotal());
|
||||
return R.ok(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量同步规程绑定。
|
||||
* 请求体:{ "bindings": [{ "coilId": 123, "specId": 456, "versionId": 789 }, ...] }
|
||||
* 前端已完成匹配计算,直接写入指定的 specId/versionId,不重新跑匹配算法。
|
||||
*/
|
||||
@PostMapping("/syncSpec")
|
||||
@SuppressWarnings("unchecked")
|
||||
public R<Void> syncSpec(@RequestBody Map<String, Object> body) {
|
||||
List<Map<String, Object>> bindings = (List<Map<String, Object>>) body.get("bindings");
|
||||
if (bindings == null || bindings.isEmpty()) {
|
||||
return R.fail("bindings 不能为空");
|
||||
}
|
||||
for (Map<String, Object> b : bindings) {
|
||||
try {
|
||||
Long coilId = toLong(b, "coilId");
|
||||
Long specId = toLong(b, "specId");
|
||||
Long versionId = toLong(b, "versionId");
|
||||
if (coilId == 0L || specId == 0L || versionId == 0L) continue;
|
||||
WmsMaterialCoilBo bo = new WmsMaterialCoilBo();
|
||||
bo.setCoilId(coilId);
|
||||
bo.setSpecId(specId);
|
||||
bo.setVersionId(versionId);
|
||||
materialCoilService.updateSimple(bo);
|
||||
} catch (Exception e) {
|
||||
log.warn("规程同步失败 binding={}", b, e);
|
||||
}
|
||||
}
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
private BigDecimal toBigDecimal(Map<String, Object> row, String upperKey, String lowerKey) {
|
||||
Object val = row.getOrDefault(upperKey, row.get(lowerKey));
|
||||
if (val == null) return null;
|
||||
try { return new BigDecimal(val.toString()); } catch (NumberFormatException e) { return null; }
|
||||
}
|
||||
|
||||
private String toStr(Map<String, Object> row, String upperKey, String lowerKey) {
|
||||
Object val = row.getOrDefault(upperKey, row.get(lowerKey));
|
||||
return val == null ? null : val.toString().trim();
|
||||
}
|
||||
|
||||
private long toLong(Map<String, Object> row, String key) {
|
||||
if (row == null) return 0L;
|
||||
Object v = row.get(key);
|
||||
if (v == null) return 0L;
|
||||
try { return Long.parseLong(v.toString()); } catch (NumberFormatException e) { return 0L; }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user