package com.vincent.rsf.openApi.tv; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; import com.vincent.rsf.openApi.feign.wms.WmsServerFeignClient; import com.vincent.rsf.openApi.service.RcsTvCallbackService; import com.vincent.rsf.openApi.service.WcsStationStatusService; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; import org.springframework.web.client.RestClientException; import org.springframework.web.client.RestTemplate; import javax.annotation.Resource; import java.util.HashMap; import java.util.Map; /** * 定时:GET RCS /station/getTaskNo;POST RCS /station/getError;任务号存在时调 WMS queryTask 合并料箱与物料明细进 Redis */ @Slf4j @Service public class TvRcsStationPollService { @Resource private RestTemplate restTemplate; @Resource private ObjectMapper objectMapper; @Resource private RcsTvCallbackService rcsTvCallbackService; @Resource private TvRcsStationPollProperties pollProperties; @Resource private WcsStationStatusService wcsStationStatusService; @Resource private WmsServerFeignClient wmsServerFeignClient; public void pollOnce() { String stationId = pollProperties.getTaskNoStationId(); if (StringUtils.hasText(pollProperties.getTaskNoPollUrl())) { try { String raw = restTemplate.getForObject(pollProperties.getTaskNoPollUrl(), String.class); String taskNo = applyTaskNoResponse(raw, stationId); enrichSnapshotFromWms(stationId, taskNo); } catch (RestClientException e) { log.warn("RCS 任务号轮询 HTTP 失败: {}", e.getMessage()); } catch (Exception e) { log.warn("RCS 任务号轮询处理失败", e); } } if (StringUtils.hasText(pollProperties.getErrorPollUrl())) { try { String raw = pollErrorRaw(); applyErrorResponse(raw, pollProperties.getErrorStationId()); } catch (RestClientException e) { log.warn("RCS 异常轮询 HTTP 失败: {}", e.getMessage()); } catch (Exception e) { log.warn("RCS 异常轮询处理失败", e); } } } private void enrichSnapshotFromWms(String stationId, String taskNo) { if (!pollProperties.isEnrichTaskFromWms()) { return; } if (!StringUtils.hasText(stationId)) { return; } if (!StringUtils.hasText(taskNo) || "0".equals(taskNo.trim())) { wcsStationStatusService.clearStationSnapshot(stationId); return; } Map req = new HashMap<>(); req.put("taskNo", taskNo); try { Map res = wmsServerFeignClient.openAsrsQueryTask(req); if (res == null) { wcsStationStatusService.upsertFromRcsPoll(stationId, taskNo, null); return; } Object codeObj = res.get("code"); int code = parseCode(codeObj); if (code != 200) { log.debug("WMS queryTask 非成功 code={} msg={}", code, res.get("msg")); wcsStationStatusService.upsertFromRcsPoll(stationId, taskNo, null); return; } Object data = res.get("data"); @SuppressWarnings("unchecked") Map dataMap = data instanceof Map ? (Map) data : null; wcsStationStatusService.upsertFromRcsPoll(stationId, taskNo, dataMap); } catch (Exception e) { log.warn("WMS queryTask 调用失败: {}", e.getMessage()); wcsStationStatusService.upsertFromRcsPoll(stationId, taskNo, null); } } private static int parseCode(Object codeObj) { if (codeObj == null) { return 0; } if (codeObj instanceof Number) { return ((Number) codeObj).intValue(); } try { return Integer.parseInt(String.valueOf(codeObj)); } catch (Exception e) { return 0; } } private String pollErrorRaw() throws Exception { if (pollProperties.isErrorPollUsePost()) { ObjectNode body = objectMapper.createObjectNode(); body.put("staNo", pollProperties.getErrorStationId()); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); HttpEntity entity = new HttpEntity<>(objectMapper.writeValueAsString(body), headers); ResponseEntity resp = restTemplate.exchange( pollProperties.getErrorPollUrl(), HttpMethod.POST, entity, String.class); return resp.getBody(); } return restTemplate.getForObject(pollProperties.getErrorPollUrl(), String.class); } /** 写入 tvRcs 任务号 Hash;返回解析出的 taskNo(用于 WMS 合并) */ private String applyTaskNoResponse(String raw, String staNo) { if (!StringUtils.hasText(staNo)) { return null; } if (!StringUtils.hasText(raw)) { rcsTvCallbackService.writeStationTaskNo(staNo, null); return null; } String trimmed = raw.trim(); try { JsonNode root = objectMapper.readTree(trimmed); if (!httpSuccess(root)) { rcsTvCallbackService.writeStationTaskNo(staNo, null); return null; } String taskNo = extractTaskNo(root); rcsTvCallbackService.writeStationTaskNo(staNo, taskNo); return taskNo; } catch (Exception e) { rcsTvCallbackService.writeStationTaskNo(staNo, trimmed); return trimmed; } } private static boolean httpSuccess(JsonNode root) { if (root == null || !root.isObject()) { return true; } JsonNode c = root.get("code"); if (c == null || c.isNull()) { return true; } return c.asInt(200) == 200; } private static String extractTaskNo(JsonNode root) { if (root == null || root.isNull()) { return null; } if (root.isValueNode()) { return textNode(root); } String[] paths = {"taskNo", "task_no", "taskCode", "seqNum"}; for (String p : paths) { JsonNode n = root.get(p); if (n != null && !n.isNull() && StringUtils.hasText(textNode(n))) { return textNode(n); } } JsonNode data = root.get("data"); if (data != null && !data.isNull()) { if (data.isObject()) { for (String p : paths) { JsonNode n = data.get(p); if (n != null && !n.isNull() && StringUtils.hasText(textNode(n))) { return textNode(n); } } } else if (data.isValueNode()) { return textNode(data); } } JsonNode result = root.get("result"); if (result != null && result.isObject()) { for (String p : paths) { JsonNode n = result.get(p); if (n != null && !n.isNull() && StringUtils.hasText(textNode(n))) { return textNode(n); } } } return null; } private static String textNode(JsonNode n) { if (n == null || n.isNull()) { return ""; } String s = n.asText(""); return s == null ? "" : s.trim(); } private void applyErrorResponse(String raw, String defaultStaNo) throws Exception { JsonNode body = buildErrorCallbackBody(raw, defaultStaNo); rcsTvCallbackService.handleStationError(body); } private JsonNode buildErrorCallbackBody(String raw, String defaultStaNo) throws Exception { if (!StringUtils.hasText(raw)) { return objectMapper.createArrayNode(); } String trimmed = raw.trim(); JsonNode root = objectMapper.readTree(trimmed); if (!httpSuccess(root)) { return objectMapper.createArrayNode(); } if (root.isArray()) { return fillStaNo((ArrayNode) root, defaultStaNo); } if (root.isObject()) { if (root.has("data") && root.get("data").isArray()) { ObjectNode o = objectMapper.createObjectNode(); o.set("data", fillStaNo((ArrayNode) root.get("data"), defaultStaNo)); return o; } if (root.has("errors") && root.get("errors").isArray()) { ObjectNode o = objectMapper.createObjectNode(); o.set("data", fillStaNo((ArrayNode) root.get("errors"), defaultStaNo)); return o; } String msg = firstMessageField(root); if (StringUtils.hasText(msg)) { return wrapSingleError(defaultStaNo, msg); } JsonNode data = root.get("data"); if (data != null && data.isTextual()) { return wrapSingleError(defaultStaNo, data.asText()); } } return wrapSingleError(defaultStaNo, trimmed); } private JsonNode wrapSingleError(String staNo, String msg) { ArrayNode arr = objectMapper.createArrayNode(); ObjectNode item = objectMapper.createObjectNode(); if (StringUtils.hasText(staNo)) { item.put("staNo", staNo); } item.put("error", msg); arr.add(item); ObjectNode body = objectMapper.createObjectNode(); body.set("data", arr); return body; } private static String firstMessageField(JsonNode o) { String[] keys = {"errorMsg", "message", "msg", "error", "plcDesc", "desc"}; for (String k : keys) { JsonNode n = o.get(k); if (n != null && !n.isNull() && StringUtils.hasText(n.asText("").trim())) { return n.asText("").trim(); } } return ""; } private ArrayNode fillStaNo(ArrayNode arr, String defaultStaNo) { for (int i = 0; i < arr.size(); i++) { JsonNode el = arr.get(i); if (!el.isObject()) { continue; } ObjectNode obj = (ObjectNode) el; if (!StringUtils.hasText(textNode(obj.get("staNo"))) && StringUtils.hasText(defaultStaNo)) { obj.put("staNo", defaultStaNo); } } return arr; } }