package com.vincent.rsf.openApi.service;
|
|
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.tv.TvMonitorRedisKeys;
|
import lombok.extern.slf4j.Slf4j;
|
import org.springframework.beans.factory.annotation.Qualifier;
|
import org.springframework.data.redis.core.StringRedisTemplate;
|
import org.springframework.stereotype.Service;
|
import org.springframework.util.StringUtils;
|
|
import javax.annotation.Resource;
|
import java.util.LinkedHashMap;
|
import java.util.Map;
|
import java.util.Set;
|
|
/**
|
* WCS 站点状态:与 zy-wcs-gsl {@code OpenController#getStationStatus} 请求字段一致(stationIds);
|
* 查询结果字段与 zy-monitor {@code WcsStationTimer} 解析一致(data 数组含 superTaskNo、autoing、loading 等)
|
*/
|
@Slf4j
|
@Service
|
public class WcsStationStatusService {
|
|
@Resource
|
@Qualifier("tvMonitorStringRedisTemplate")
|
private StringRedisTemplate tvMonitorStringRedisTemplate;
|
@Resource
|
private ObjectMapper objectMapper;
|
|
public Map<String, Object> handle(JsonNode body) {
|
if (body == null || body.isNull()) {
|
return okEmptyData();
|
}
|
// 与 zy-wcs-gsl OpenController#getStationStatus(GetStationStatusParam) 一致:stationIds 为 null 或空则返回全部
|
if (body.has("stationIds")) {
|
JsonNode sidArr = body.get("stationIds");
|
if (sidArr.isNull()) {
|
return okQueryAll();
|
}
|
if (!sidArr.isArray()) {
|
return fail("stationIds 须为数组");
|
}
|
if (sidArr.size() == 0) {
|
return okQueryAll();
|
}
|
return okQuery(sidArr);
|
}
|
JsonNode data = body.get("data");
|
if (data == null && body.isArray()) {
|
data = body;
|
}
|
if (data != null && data.isArray()) {
|
savePush(data);
|
return okMsg("已写入站点状态");
|
}
|
// 未带 stationIds、data 上报时按全量查询,与 stationIds 空数组一致
|
return okQueryAll();
|
}
|
|
private Map<String, Object> okEmptyData() {
|
Map<String, Object> m = new LinkedHashMap<>();
|
m.put("code", 200);
|
m.put("data", objectMapper.createArrayNode());
|
return m;
|
}
|
|
/** Redis 中全部站点,对应 WCS 侧 stationIds 为空时 stationThread.getStatus() 全量 */
|
private Map<String, Object> okQueryAll() {
|
ArrayNode out = objectMapper.createArrayNode();
|
Set<Object> keys = tvMonitorStringRedisTemplate.opsForHash()
|
.keys(TvMonitorRedisKeys.TV_WCS_STATION_STATUS);
|
for (Object k : keys) {
|
if (k == null) {
|
continue;
|
}
|
String raw = (String) tvMonitorStringRedisTemplate.opsForHash()
|
.get(TvMonitorRedisKeys.TV_WCS_STATION_STATUS, k.toString());
|
if (!StringUtils.hasText(raw)) {
|
continue;
|
}
|
try {
|
int sid = Integer.parseInt(k.toString());
|
JsonNode stored = objectMapper.readTree(raw);
|
out.add(toMonitorRow(sid, stored));
|
} catch (Exception e) {
|
log.warn("站点 {} Redis 解析失败: {}", k, e.getMessage());
|
}
|
}
|
Map<String, Object> m = new LinkedHashMap<>();
|
m.put("code", 200);
|
m.put("data", out);
|
return m;
|
}
|
|
private Map<String, Object> okQuery(JsonNode stationIds) {
|
ArrayNode out = objectMapper.createArrayNode();
|
for (JsonNode idNode : stationIds) {
|
if (idNode == null || !idNode.isNumber()) {
|
continue;
|
}
|
int sid = idNode.asInt();
|
String raw = (String) tvMonitorStringRedisTemplate.opsForHash()
|
.get(TvMonitorRedisKeys.TV_WCS_STATION_STATUS, String.valueOf(sid));
|
if (!StringUtils.hasText(raw)) {
|
continue;
|
}
|
try {
|
JsonNode stored = objectMapper.readTree(raw);
|
out.add(toMonitorRow(sid, stored));
|
} catch (Exception e) {
|
log.warn("站点 {} Redis JSON 解析失败: {}", sid, e.getMessage());
|
}
|
}
|
Map<String, Object> m = new LinkedHashMap<>();
|
m.put("code", 200);
|
m.put("data", out);
|
return m;
|
}
|
|
private ObjectNode toMonitorRow(int stationId, JsonNode stored) {
|
ObjectNode row = objectMapper.createObjectNode();
|
row.put("stationId", stationId);
|
String taskNo = textFirst(stored, "taskNo", "superTaskNo");
|
row.put("superTaskNo", taskNo != null ? taskNo : "");
|
row.put("autoing", truthy(stored, "auto", "autoing"));
|
row.put("loading", truthy(stored, "loading"));
|
row.put("barcode", text(stored, "barcode"));
|
row.put("errorMsg", text(stored, "errorMsg"));
|
row.put("systemWarning", text(stored, "systemWarning"));
|
if (stored.has("wrkDetls") && !stored.get("wrkDetls").isNull()) {
|
row.set("wrkDetls", stored.get("wrkDetls"));
|
}
|
if (stored.has("ioType") && !stored.get("ioType").isNull()) {
|
row.set("ioType", stored.get("ioType"));
|
}
|
if (stored.has("orderNo") && !stored.get("orderNo").isNull()) {
|
row.put("orderNo", text(stored, "orderNo"));
|
}
|
return row;
|
}
|
|
private void savePush(JsonNode data) {
|
for (JsonNode item : data) {
|
if (item == null || !item.isObject()) {
|
continue;
|
}
|
JsonNode sidNode = item.get("stationId");
|
if (sidNode == null || !sidNode.isNumber()) {
|
continue;
|
}
|
int sid = sidNode.asInt();
|
ObjectNode norm = normalizeForStore(item);
|
try {
|
tvMonitorStringRedisTemplate.opsForHash().put(
|
TvMonitorRedisKeys.TV_WCS_STATION_STATUS,
|
String.valueOf(sid),
|
objectMapper.writeValueAsString(norm));
|
} catch (Exception e) {
|
log.warn("写入站点 {} 失败: {}", sid, e.getMessage());
|
}
|
}
|
log.info("WCS 站点状态已写入 Redis,条数={}", data.size());
|
}
|
|
/** 与 zy-monitor WcsStationDto 字段对齐,统一 taskNo/auto 数值 */
|
private ObjectNode normalizeForStore(JsonNode item) {
|
ObjectNode n = objectMapper.createObjectNode();
|
if (item.has("stationId")) {
|
n.put("stationId", item.get("stationId").asInt());
|
}
|
String taskNo = textFirst(item, "taskNo", "superTaskNo");
|
if (StringUtils.hasText(taskNo)) {
|
n.put("taskNo", taskNo);
|
}
|
n.put("auto", truthy(item, "auto", "autoing") ? 1 : 0);
|
n.put("loading", truthy(item, "loading") ? 1 : 0);
|
if (item.has("barcode")) {
|
n.put("barcode", text(item, "barcode"));
|
}
|
if (item.has("errorMsg")) {
|
n.put("errorMsg", text(item, "errorMsg"));
|
}
|
if (item.has("systemWarning")) {
|
n.put("systemWarning", text(item, "systemWarning"));
|
}
|
if (item.has("wrkDetls")) {
|
n.set("wrkDetls", item.get("wrkDetls"));
|
}
|
if (item.has("ioType")) {
|
n.set("ioType", item.get("ioType"));
|
}
|
if (item.has("orderNo")) {
|
n.put("orderNo", text(item, "orderNo"));
|
}
|
if (item.has("outboundSeq")) {
|
n.put("outboundSeq", text(item, "outboundSeq"));
|
}
|
return n;
|
}
|
|
private static String text(JsonNode n, String field) {
|
JsonNode v = n.get(field);
|
if (v == null || v.isNull()) {
|
return "";
|
}
|
return v.asText("");
|
}
|
|
private static String textFirst(JsonNode n, String... fields) {
|
for (String f : fields) {
|
if (n.hasNonNull(f)) {
|
String s = n.get(f).asText("");
|
if (StringUtils.hasText(s)) {
|
return s;
|
}
|
}
|
}
|
return null;
|
}
|
|
private static boolean truthy(JsonNode n, String... fields) {
|
for (String f : fields) {
|
if (!n.has(f) || n.get(f).isNull()) {
|
continue;
|
}
|
JsonNode v = n.get(f);
|
if (v.isBoolean()) {
|
return v.booleanValue();
|
}
|
if (v.isNumber()) {
|
return v.asInt() != 0;
|
}
|
if (v.isTextual()) {
|
return "1".equals(v.asText()) || "true".equalsIgnoreCase(v.asText());
|
}
|
}
|
return false;
|
}
|
|
private static Map<String, Object> okMsg(String msg) {
|
Map<String, Object> m = new LinkedHashMap<>();
|
m.put("code", 200);
|
m.put("message", msg);
|
return m;
|
}
|
|
private static Map<String, Object> fail(String msg) {
|
Map<String, Object> m = new LinkedHashMap<>();
|
m.put("code", 400);
|
m.put("message", msg);
|
return m;
|
}
|
|
/**
|
* RCS 轮询得到任务号后,合并 WMS queryTask(料箱号、ioType、wrkDetls 物料明细)到电视机 Redis
|
*/
|
public void upsertFromRcsPoll(String stationId, String taskNo, Map<String, Object> wmsData) {
|
if (!StringUtils.hasText(stationId)) {
|
return;
|
}
|
ObjectNode n = objectMapper.createObjectNode();
|
try {
|
n.put("stationId", Integer.parseInt(stationId.trim()));
|
} catch (NumberFormatException e) {
|
n.put("stationId", stationId);
|
}
|
String tn = taskNo != null ? taskNo.trim() : "";
|
n.put("taskNo", tn);
|
n.put("superTaskNo", tn);
|
n.put("auto", 1);
|
n.put("loading", StringUtils.hasText(tn) && !"0".equals(tn) ? 1 : 0);
|
if (wmsData != null) {
|
if (wmsData.get("barcode") != null) {
|
n.put("barcode", String.valueOf(wmsData.get("barcode")));
|
}
|
if (wmsData.get("ioType") != null) {
|
n.set("ioType", objectMapper.valueToTree(wmsData.get("ioType")));
|
}
|
if (wmsData.get("wrkDetls") != null) {
|
n.set("wrkDetls", objectMapper.valueToTree(wmsData.get("wrkDetls")));
|
}
|
}
|
try {
|
tvMonitorStringRedisTemplate.opsForHash().put(
|
TvMonitorRedisKeys.TV_WCS_STATION_STATUS,
|
stationId,
|
objectMapper.writeValueAsString(n));
|
} catch (Exception e) {
|
log.warn("tvWcsStationStatus stationId={} 写入失败: {}", stationId, e.getMessage());
|
}
|
}
|
|
public void clearStationSnapshot(String stationId) {
|
if (!StringUtils.hasText(stationId)) {
|
return;
|
}
|
tvMonitorStringRedisTemplate.opsForHash().delete(TvMonitorRedisKeys.TV_WCS_STATION_STATUS, stationId);
|
}
|
}
|