From b3fb3db3341ea98dac914f62dc94e59fe37e6b3f Mon Sep 17 00:00:00 2001
From: cl <1442464845@qq.com>
Date: 星期一, 13 四月 2026 09:00:30 +0800
Subject: [PATCH] 推送报警预写
---
rsf-open-api/src/main/java/com/vincent/rsf/openApi/controller/RcsTvCallbackController.java | 70 ++++++++++++++
rsf-open-api/src/main/java/com/vincent/rsf/openApi/service/RcsTvCallbackService.java | 146 +++++++++++++++++++++++++++++
rsf-open-api/src/main/java/com/vincent/rsf/openApi/tv/TvMonitorRedisKeys.java | 16 +++
rsf-open-api/src/main/java/com/vincent/rsf/openApi/config/TvMonitorRedisConfig.java | 43 ++++++++
4 files changed, 275 insertions(+), 0 deletions(-)
diff --git a/rsf-open-api/src/main/java/com/vincent/rsf/openApi/config/TvMonitorRedisConfig.java b/rsf-open-api/src/main/java/com/vincent/rsf/openApi/config/TvMonitorRedisConfig.java
new file mode 100644
index 0000000..1e67bd6
--- /dev/null
+++ b/rsf-open-api/src/main/java/com/vincent/rsf/openApi/config/TvMonitorRedisConfig.java
@@ -0,0 +1,43 @@
+package com.vincent.rsf.openApi.config;
+
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
+import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
+import org.springframework.data.redis.core.StringRedisTemplate;
+
+/**
+ * 鐢佃鏈哄悗鍙颁娇鐢ㄧ嫭绔� Redis DB 鏃讹紝姝ゅ涓� {@code tv-monitor.redis.database} 瀵归綈锛堥粯璁� 0锛屼笌 zy-monitor-admin 涓�鑷达級
+ */
+@Configuration
+public class TvMonitorRedisConfig {
+
+ @Value("${redis.host:127.0.0.1}")
+ private String host;
+ @Value("${redis.port:6379}")
+ private int port;
+ @Value("${redis.password:}")
+ private String password;
+ @Value("${tv-monitor.redis.database:0}")
+ private int database;
+
+ @Bean(name = "tvMonitorRedisConnectionFactory")
+ public LettuceConnectionFactory tvMonitorRedisConnectionFactory() {
+ RedisStandaloneConfiguration cfg = new RedisStandaloneConfiguration(host, port);
+ cfg.setDatabase(database);
+ if (password != null && !password.isEmpty()) {
+ cfg.setPassword(password);
+ }
+ return new LettuceConnectionFactory(cfg);
+ }
+
+ @Bean(name = "tvMonitorStringRedisTemplate")
+ public StringRedisTemplate tvMonitorStringRedisTemplate(
+ @Qualifier("tvMonitorRedisConnectionFactory") LettuceConnectionFactory tvMonitorRedisConnectionFactory) {
+ StringRedisTemplate t = new StringRedisTemplate();
+ t.setConnectionFactory(tvMonitorRedisConnectionFactory);
+ return t;
+ }
+}
diff --git a/rsf-open-api/src/main/java/com/vincent/rsf/openApi/controller/RcsTvCallbackController.java b/rsf-open-api/src/main/java/com/vincent/rsf/openApi/controller/RcsTvCallbackController.java
new file mode 100644
index 0000000..f134d70
--- /dev/null
+++ b/rsf-open-api/src/main/java/com/vincent/rsf/openApi/controller/RcsTvCallbackController.java
@@ -0,0 +1,70 @@
+package com.vincent.rsf.openApi.controller;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.vincent.rsf.openApi.service.RcsTvCallbackService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestHeader;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * RCS 鍚� WMS 鎺ㄩ�侊細杈撻�佺嚎寮傚父銆佺珯鐐逛换鍔″彿锛涘啓鍏ヤ笌鐢佃鏈哄悗鍙扮浉鍚岀殑 Redis锛堢數瑙嗘満涓� zy-monitor-admin 涓嶆敼浠g爜锛�
+ */
+@Slf4j
+@RestController
+@Api(tags = "RCS鐢佃鏈哄洖璋�")
+@RequestMapping("/rcs/callback/tv")
+public class RcsTvCallbackController {
+
+ @Resource
+ private RcsTvCallbackService rcsTvCallbackService;
+
+ @PostMapping("/station/error")
+ @ApiOperation("杈撻�佺嚎寮傚父鎺ㄩ�侊細鍐欏叆 Redis tvManualErrorMsg")
+ public Map<String, Object> stationError(
+ @RequestHeader(value = "X-Rcs-Token", required = false) String rcsToken,
+ @RequestBody(required = false) JsonNode body) {
+ try {
+ rcsTvCallbackService.assertToken(rcsToken);
+ return rcsTvCallbackService.handleStationError(body);
+ } catch (IllegalArgumentException e) {
+ return rcsFail(500, e.getMessage());
+ } catch (Exception e) {
+ log.error("RCS station/error 澶勭悊澶辫触", e);
+ return rcsFail(500, e.getMessage() != null ? e.getMessage() : "澶勭悊澶辫触");
+ }
+ }
+
+ @PostMapping("/station/taskNo")
+ @ApiOperation("杈撻�佺嚎浠诲姟鍙锋帹閫侊細鍐欏叆 Redis Hash tvRcsStationTaskNo")
+ public Map<String, Object> stationTaskNo(
+ @RequestHeader(value = "X-Rcs-Token", required = false) String rcsToken,
+ @RequestBody(required = false) JsonNode body) {
+ try {
+ rcsTvCallbackService.assertToken(rcsToken);
+ return rcsTvCallbackService.handleStationTaskNo(body);
+ } catch (IllegalArgumentException e) {
+ return rcsFail(500, e.getMessage());
+ } catch (Exception e) {
+ log.error("RCS station/taskNo 澶勭悊澶辫触", e);
+ return rcsFail(500, e.getMessage() != null ? e.getMessage() : "澶勭悊澶辫触");
+ }
+ }
+
+ private static Map<String, Object> rcsFail(int code, String message) {
+ Map<String, Object> m = new LinkedHashMap<>();
+ m.put("code", code);
+ m.put("message", message != null ? message : "澶辫触");
+ m.put("timestamp", System.currentTimeMillis());
+ m.put("data", null);
+ return m;
+ }
+}
diff --git a/rsf-open-api/src/main/java/com/vincent/rsf/openApi/service/RcsTvCallbackService.java b/rsf-open-api/src/main/java/com/vincent/rsf/openApi/service/RcsTvCallbackService.java
new file mode 100644
index 0000000..e796aa6
--- /dev/null
+++ b/rsf-open-api/src/main/java/com/vincent/rsf/openApi/service/RcsTvCallbackService.java
@@ -0,0 +1,146 @@
+package com.vincent.rsf.openApi.service;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.vincent.rsf.openApi.tv.TvMonitorRedisKeys;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.stereotype.Service;
+import org.springframework.util.StringUtils;
+
+import javax.annotation.Resource;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * RCS 鎺ㄩ�侊細鍐欏叆涓庣數瑙嗘満鍚庡彴鐩稿悓鐨� Redis 鏍煎紡锛堜笉淇敼 zy-monitor-admin / 鐢佃鏈猴級
+ */
+@Slf4j
+@Service
+public class RcsTvCallbackService {
+
+ @Resource
+ @Qualifier("tvMonitorStringRedisTemplate")
+ private StringRedisTemplate tvMonitorStringRedisTemplate;
+
+ @Value("${tv-monitor.rcs-callback-token:}")
+ private String rcsCallbackToken;
+
+ public void assertToken(String headerToken) {
+ if (!StringUtils.hasText(rcsCallbackToken)) {
+ return;
+ }
+ if (!rcsCallbackToken.equals(headerToken)) {
+ throw new IllegalArgumentException("X-Rcs-Token 鏃犳晥");
+ }
+ }
+
+ /**
+ * 瑙f瀽杈撻�佺嚎寮傚父鍒楄〃锛屽啓鍏� {@link TvMonitorRedisKeys#TV_MANUAL_ERROR_MSG}锛堝垎鍙锋嫾鎺ワ紝涓庢帹閫佺 join 椋庢牸涓�鑷达級
+ */
+ public Map<String, Object> handleStationError(JsonNode body) {
+ if (body != null && body.isObject() && body.has("clear") && body.get("clear").asBoolean(false)) {
+ tvMonitorStringRedisTemplate.delete(TvMonitorRedisKeys.TV_MANUAL_ERROR_MSG);
+ return rcsOk(null);
+ }
+ JsonNode arr = resolveErrorArray(body);
+ if (arr == null || !arr.isArray() || arr.size() == 0) {
+ tvMonitorStringRedisTemplate.delete(TvMonitorRedisKeys.TV_MANUAL_ERROR_MSG);
+ return rcsOk(null);
+ }
+ List<String> parts = new ArrayList<>();
+ for (JsonNode item : arr) {
+ if (item == null || !item.isObject()) {
+ continue;
+ }
+ String staNo = text(item.get("staNo"));
+ String err = text(item.get("error"));
+ String plc = text(item.get("plcDesc"));
+ String msg = StringUtils.hasText(err) ? err : plc;
+ if (!StringUtils.hasText(msg)) {
+ continue;
+ }
+ if (StringUtils.hasText(staNo)) {
+ parts.add("[" + staNo + "]" + msg);
+ } else {
+ parts.add(msg);
+ }
+ }
+ if (parts.isEmpty()) {
+ tvMonitorStringRedisTemplate.delete(TvMonitorRedisKeys.TV_MANUAL_ERROR_MSG);
+ return rcsOk(null);
+ }
+ String value = String.join("锛�", parts);
+ tvMonitorStringRedisTemplate.opsForValue().set(TvMonitorRedisKeys.TV_MANUAL_ERROR_MSG, value);
+ log.info("RCS 鎶ヨ宸插啓鍏� Redis tvManualErrorMsg锛屾潯鏁�={}", parts.size());
+ return rcsOk(value);
+ }
+
+ private static JsonNode resolveErrorArray(JsonNode body) {
+ if (body == null || body.isNull()) {
+ return null;
+ }
+ if (body.isArray()) {
+ return body;
+ }
+ if (body.isObject()) {
+ if (body.has("data") && body.get("data").isArray()) {
+ return body.get("data");
+ }
+ if (body.has("errors") && body.get("errors").isArray()) {
+ return body.get("errors");
+ }
+ }
+ return null;
+ }
+
+ private static String text(JsonNode n) {
+ if (n == null || n.isNull()) {
+ return "";
+ }
+ String s = n.asText("");
+ return s == null ? "" : s.trim();
+ }
+
+ /**
+ * 绔欑偣浠诲姟鍙峰啓鍏� Redis Hash锛屼緵鍚庣画鎵╁睍锛涚數瑙嗘満 led 浠诲姟鍙蜂粛鏉ヨ嚜 WCS 绔欑偣杞
+ */
+ public Map<String, Object> handleStationTaskNo(JsonNode body) {
+ if (body == null || body.isNull() || !body.isObject()) {
+ throw new IllegalArgumentException("body 椤讳负 JSON 瀵硅薄");
+ }
+ JsonNode dataNode = body.get("data");
+ JsonNode src = (dataNode != null && dataNode.isObject()) ? dataNode : body;
+ String staNo = text(body.get("staNo"));
+ if (!StringUtils.hasText(staNo)) {
+ staNo = text(src.get("staNo"));
+ }
+ String taskNo = text(src.get("taskNo"));
+ if (!StringUtils.hasText(staNo)) {
+ throw new IllegalArgumentException("staNo 涓嶈兘涓虹┖");
+ }
+ if (!StringUtils.hasText(taskNo)) {
+ tvMonitorStringRedisTemplate.opsForHash().delete(TvMonitorRedisKeys.TV_RCS_STATION_TASK_NO, staNo);
+ } else {
+ tvMonitorStringRedisTemplate.opsForHash()
+ .put(TvMonitorRedisKeys.TV_RCS_STATION_TASK_NO, staNo, taskNo);
+ }
+ log.info("RCS 浠诲姟鍙峰凡鍐欏叆 Redis Hash staNo={} taskNo={}", staNo, taskNo);
+ Map<String, Object> payload = new LinkedHashMap<>();
+ payload.put("staNo", staNo);
+ payload.put("taskNo", taskNo);
+ return rcsOk(payload);
+ }
+
+ private Map<String, Object> rcsOk(Object data) {
+ Map<String, Object> m = new LinkedHashMap<>();
+ m.put("code", 200);
+ m.put("message", "璇锋眰鎴愬姛");
+ m.put("timestamp", System.currentTimeMillis());
+ m.put("data", data);
+ return m;
+ }
+}
diff --git a/rsf-open-api/src/main/java/com/vincent/rsf/openApi/tv/TvMonitorRedisKeys.java b/rsf-open-api/src/main/java/com/vincent/rsf/openApi/tv/TvMonitorRedisKeys.java
new file mode 100644
index 0000000..dc337ae
--- /dev/null
+++ b/rsf-open-api/src/main/java/com/vincent/rsf/openApi/tv/TvMonitorRedisKeys.java
@@ -0,0 +1,16 @@
+package com.vincent.rsf.openApi.tv;
+
+/**
+ * 涓� zy-monitor-admin {@code RedisKeyType} 涓� key 瀛楃涓蹭繚鎸佷竴鑷达紝渚涚數瑙嗘満鍚庡彴鍘熸牱璇诲彇
+ */
+public final class TvMonitorRedisKeys {
+
+ /** 涓� {@code RedisKeyType.TV_MANUAL_ERROR_MSG} 涓�鑷达紝{@code TvDataPushService} 鐢ㄥ瓧绗︿覆鎺ㄩ�� error */
+ public static final String TV_MANUAL_ERROR_MSG = "tvManualErrorMsg";
+
+ /** RCS 绔欑偣浠诲姟鍙风紦瀛橈紙Hash锛歠ield=staNo, value=taskNo锛夛紱鐢佃鏈� led 浠诲姟鍙蜂粛渚濊禆 WCS 杞 stationMap锛屾湰閿緵鎵╁睍 */
+ public static final String TV_RCS_STATION_TASK_NO = "tvRcsStationTaskNo";
+
+ private TvMonitorRedisKeys() {
+ }
+}
--
Gitblit v1.9.1