数字孪生后台
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
package com.ruoyi.api.controller;
|
||||
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.tcp.TcpServerManager;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/tcp")
|
||||
public class TcpServerController {
|
||||
private final TcpServerManager manager;
|
||||
|
||||
public TcpServerController(TcpServerManager manager) {
|
||||
this.manager = manager;
|
||||
}
|
||||
|
||||
@GetMapping("/status")
|
||||
public AjaxResult status() {
|
||||
return AjaxResult.success(manager.status());
|
||||
}
|
||||
|
||||
@PostMapping("/send/{channel}")
|
||||
public AjaxResult send(@PathVariable String channel, @RequestBody String message) {
|
||||
boolean ok = manager.broadcast(channel, message);
|
||||
if (ok) return AjaxResult.success();
|
||||
return AjaxResult.error("channel not found");
|
||||
}
|
||||
}
|
||||
@@ -107,7 +107,7 @@ public class ScheduleThread {
|
||||
ssjList.put(deviceSsj.getDeviceCode(), deviceSsj);
|
||||
}
|
||||
//plc输送机读取线程
|
||||
PlcSsjRead plcSsjRead = new PlcSsjRead(ssjList, new PlcConnectInfo("127.0.0.1", 1502));
|
||||
PlcSsjRead plcSsjRead = new PlcSsjRead(ssjList, new PlcConnectInfo("172.16.100.9", 1502));
|
||||
Thread plcSsjReadThread = new Thread(plcSsjRead);
|
||||
plcSsjReadCustomThread = new CustomThread<PlcSsjRead>(plcSsjReadThread, plcSsjRead);
|
||||
|
||||
@@ -118,7 +118,7 @@ public class ScheduleThread {
|
||||
tsjList.put(t.getName(), t);
|
||||
}
|
||||
//plc提升机读取线程
|
||||
PlcTsjRead plcTsjRead = new PlcTsjRead(tsjList, new PlcConnectInfo("127.0.0.1", 1502));
|
||||
PlcTsjRead plcTsjRead = new PlcTsjRead(tsjList, new PlcConnectInfo("172.16.100.9", 1502));
|
||||
Thread plcTsjReadThread = new Thread(plcTsjRead);
|
||||
plcTsjReadCustomThread = new CustomThread<PlcTsjRead>(plcTsjReadThread, plcTsjRead);
|
||||
|
||||
|
||||
147
ruoyi-admin/src/main/java/com/ruoyi/tcp/GetDeviceAlarm.java
Normal file
147
ruoyi-admin/src/main/java/com/ruoyi/tcp/GetDeviceAlarm.java
Normal file
@@ -0,0 +1,147 @@
|
||||
package com.ruoyi.tcp;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.ruoyi.common.utils.DictUtils;
|
||||
import com.ruoyi.device.srgv.domain.DeviceSrgv;
|
||||
import com.ruoyi.device.ssj.domain.DeviceSsj;
|
||||
import com.ruoyi.device.tsj.domain.DeviceTsj;
|
||||
import com.ruoyi.schedule.plcRead.srgv.PlcSrgvRead;
|
||||
import com.ruoyi.schedule.plcRead.ssj.PlcSsjRead;
|
||||
import com.ruoyi.schedule.plcRead.tsj.PlcTsjRead;
|
||||
import lombok.Data;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.io.OutputStream;
|
||||
import java.net.Socket;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Component
|
||||
public class GetDeviceAlarm {
|
||||
private final TcpServerManager manager;
|
||||
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
/**
|
||||
* 构造函数:注入 TCP 管理器,用于管理 5555 端口客户端与广播
|
||||
*/
|
||||
public GetDeviceAlarm(TcpServerManager manager) {
|
||||
this.manager = manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化:注册 5555 端口的客户端连接监听,客户端第一次连接时立即发送报警数据
|
||||
*/
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
manager.setClientListener("port5555", this::handleConnect);
|
||||
}
|
||||
|
||||
/**
|
||||
* 客户端连接处理:构建报警数据并写入到 Socket 输出流
|
||||
*/
|
||||
private void handleConnect(Socket socket) {
|
||||
try {
|
||||
String payload = buildAlarmPayload();
|
||||
OutputStream os = socket.getOutputStream();
|
||||
os.write(((payload == null ? "" : payload) + "\n").getBytes(StandardCharsets.UTF_8));
|
||||
os.flush();
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 周期发送:每 2 秒检查 5555 端口是否有连接,有则广播报警数据,无连接不发送
|
||||
*/
|
||||
@Scheduled(fixedRate = 2000)
|
||||
public void send() {
|
||||
Integer count = manager.status().getOrDefault("port5555", 0);
|
||||
if (count != null && count > 0) {
|
||||
String payload = buildAlarmPayload();
|
||||
manager.broadcast("port5555", payload == null ? "" : payload);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建报警数据:汇总四向车、输送机、提升机报警
|
||||
* - 四向车:报警代码 > 1,字典类型 srgv_alarm
|
||||
* - 输送机:报警代码 > 2,字典类型 ssj_ex
|
||||
* - 提升机:报警代码 > 1000,字典类型 tsj_alarm
|
||||
* 返回 JSON 字符串格式:{"alarm":[{id,name,alarm,alarmMsg}]}
|
||||
*/
|
||||
private String buildAlarmPayload() {
|
||||
List<AlarmDto> alarms = new ArrayList<>();
|
||||
|
||||
Map<String, DeviceSrgv> srgvMap = PlcSrgvRead.deviceSrgvMap;
|
||||
if (srgvMap != null) {
|
||||
for (DeviceSrgv d : srgvMap.values()) {
|
||||
Integer code = d.getAlarm();
|
||||
if (code != null && code > 1) {
|
||||
AlarmDto dto = new AlarmDto();
|
||||
dto.setId(d.getDeviceId() == null ? "" : String.valueOf(d.getDeviceId()));
|
||||
dto.setName("四向车");
|
||||
dto.setAlarm(code == null ? "" : String.valueOf(code));
|
||||
dto.setAlarmMsg(DictUtils.getDictLabel("srgv_alarm", code == null ? "" : String.valueOf(code)));
|
||||
alarms.add(dto);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, DeviceSsj> ssjMap = PlcSsjRead.deviceSsjMap;
|
||||
if (ssjMap != null) {
|
||||
for (DeviceSsj d : ssjMap.values()) {
|
||||
Integer code = d.getException();
|
||||
if (code != null && code > 2) {
|
||||
AlarmDto dto = new AlarmDto();
|
||||
dto.setId(d.getDeviceCode() == null ? "" : d.getDeviceCode());
|
||||
dto.setName("输送机");
|
||||
dto.setAlarm(String.valueOf(code));
|
||||
dto.setAlarmMsg(DictUtils.getDictLabel("ssj_ex", String.valueOf(code)));
|
||||
alarms.add(dto);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, DeviceTsj> tsjMap = PlcTsjRead.deviceTsjMap;
|
||||
if (tsjMap != null) {
|
||||
for (Map.Entry<String, DeviceTsj> entry : tsjMap.entrySet()) {
|
||||
String codeId = entry.getKey();
|
||||
DeviceTsj d = entry.getValue();
|
||||
Integer code = d.getSbzt();
|
||||
if (code != null && code > 1000) {
|
||||
AlarmDto dto = new AlarmDto();
|
||||
dto.setId(codeId == null ? "" : codeId);
|
||||
dto.setName("提升机");
|
||||
dto.setAlarm(String.valueOf(code));
|
||||
dto.setAlarmMsg(DictUtils.getDictLabel("tsj_alarm", String.valueOf(code)));
|
||||
alarms.add(dto);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
Wrapper w = new Wrapper();
|
||||
w.setAlarm(alarms);
|
||||
return objectMapper.writeValueAsString(w);
|
||||
} catch (Exception e) {
|
||||
return "{\"alarm\":[]}";
|
||||
}
|
||||
}
|
||||
|
||||
@Data
|
||||
private static class Wrapper {
|
||||
private List<AlarmDto> alarm;
|
||||
}
|
||||
|
||||
@Data
|
||||
private static class AlarmDto {
|
||||
private String id;
|
||||
private String name;
|
||||
private String alarm;
|
||||
private String alarmMsg;
|
||||
}
|
||||
}
|
||||
140
ruoyi-admin/src/main/java/com/ruoyi/tcp/GetDeviceSrgvMap.java
Normal file
140
ruoyi-admin/src/main/java/com/ruoyi/tcp/GetDeviceSrgvMap.java
Normal file
@@ -0,0 +1,140 @@
|
||||
package com.ruoyi.tcp;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.ruoyi.device.srgv.domain.DeviceSrgv;
|
||||
import com.ruoyi.schedule.plcRead.srgv.PlcSrgvRead;
|
||||
import com.ruoyi.job.service.IMydoJobService;
|
||||
import com.ruoyi.job.domain.MydoJob;
|
||||
import com.ruoyi.common.utils.DictUtils;
|
||||
import lombok.Data;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.io.OutputStream;
|
||||
import java.net.Socket;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Component
|
||||
public class GetDeviceSrgvMap {
|
||||
private final TcpServerManager manager;
|
||||
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||
private final IMydoJobService mydoJobService;
|
||||
|
||||
/**
|
||||
* 构造函数:注入 TCP 管理器与作业服务,用于管理 2222 端口广播并根据任务号补全物料信息
|
||||
*/
|
||||
public GetDeviceSrgvMap(TcpServerManager manager, IMydoJobService mydoJobService) {
|
||||
this.manager = manager;
|
||||
this.mydoJobService = mydoJobService;
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化:注册 2222 端口的客户端连接监听,客户端第一次连接时立即发送 AGV 数据
|
||||
*/
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
manager.setClientListener("port2222", this::handleConnect);
|
||||
}
|
||||
|
||||
/**
|
||||
* 客户端连接处理:构建 AGV 数据并写入到 Socket 输出流
|
||||
*/
|
||||
private void handleConnect(Socket socket) {
|
||||
try {
|
||||
String payload = buildAgvPayload();
|
||||
OutputStream os = socket.getOutputStream();
|
||||
os.write(((payload == null ? "" : payload) + "\n").getBytes(StandardCharsets.UTF_8));
|
||||
os.flush();
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 周期发送:每 2 秒检查 2222 端口是否有连接,有则广播 AGV 数据,无连接不发送
|
||||
*/
|
||||
@Scheduled(fixedRate = 2000)
|
||||
public void send() {
|
||||
Integer count = manager.status().getOrDefault("port2222", 0);
|
||||
if (count != null && count > 0) {
|
||||
String payload = buildAgvPayload();
|
||||
manager.broadcast("port2222", payload == null ? "" : payload);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建 AGV 数据:从 PLC 缓存读取四向车状态并组装 JSON
|
||||
* - 计算在位与状态(基于执行阶段 workPhase)
|
||||
* - 报警码与文案:使用字典 srgv_alarm
|
||||
* - 当任务号有效时,查询 MydoJob 补齐托盘与物料信息
|
||||
* 返回 JSON 字符串格式:{"AGV":[{...}]}
|
||||
*/
|
||||
private String buildAgvPayload() {
|
||||
Map<String, DeviceSrgv> map = PlcSrgvRead.deviceSrgvMap;
|
||||
List<AgvDto> list = new ArrayList<>();
|
||||
if (map != null) {
|
||||
for (DeviceSrgv d : map.values()) {
|
||||
AgvDto dto = new AgvDto();
|
||||
dto.setId(d.getDeviceId() == null ? "" : String.format("%04d", d.getDeviceId()));
|
||||
dto.setTaskNo(d.getTaskNo() == null ? "" : String.valueOf(d.getTaskNo()));
|
||||
dto.setIsThere((d.getWorkPhase() >= 3 && d.getWorkPhase() < 6 ? "1" : "0"));
|
||||
Integer wp = d.getWorkPhase();
|
||||
String status = "0";
|
||||
if (wp != null) {
|
||||
if (wp == 3) status = "1";
|
||||
else if (wp == 6) status = "2";
|
||||
else if (wp == 24) status = "3";
|
||||
}
|
||||
dto.setStatus(status);
|
||||
dto.setLocation(d.getCurrSite() == null ? "" : d.getCurrSite());
|
||||
dto.setAlarm(d.getAlarm() == null ? "" : String.valueOf(d.getAlarm()));
|
||||
dto.setAlarmMsg(DictUtils.getDictLabel("srgv_alarm", d.getAlarm() == null ? "" : String.valueOf(d.getAlarm())));
|
||||
if (d.getTaskNo() != null && d.getTaskNo() > 0) {
|
||||
try {
|
||||
MydoJob job = mydoJobService.selectMydoJobByTaskNo(Long.valueOf(d.getTaskNo()));
|
||||
dto.setTrayCode(job == null || job.getTrayCode() == null ? "" : job.getTrayCode());
|
||||
dto.setProductCode(job == null || job.getProductId() == null ? "" : job.getProductId());
|
||||
dto.setProductName(job == null || job.getProductName() == null ? "" : job.getProductName());
|
||||
} catch (Exception e) {
|
||||
dto.setTrayCode("");
|
||||
dto.setProductCode("");
|
||||
dto.setProductName("");
|
||||
}
|
||||
} else {
|
||||
dto.setTrayCode("");
|
||||
dto.setProductCode("");
|
||||
dto.setProductName("");
|
||||
}
|
||||
list.add(dto);
|
||||
}
|
||||
}
|
||||
try {
|
||||
Wrapper w = new Wrapper();
|
||||
w.setAGV(list);
|
||||
return objectMapper.writeValueAsString(w);
|
||||
} catch (Exception e) {
|
||||
return "{\"AGV\":[]}";
|
||||
}
|
||||
}
|
||||
|
||||
@Data
|
||||
private static class Wrapper {
|
||||
private List<AgvDto> AGV;
|
||||
}
|
||||
|
||||
@Data
|
||||
private static class AgvDto {
|
||||
private String id;
|
||||
private String taskNo;
|
||||
private String isThere;
|
||||
private String status;
|
||||
private String location;
|
||||
private String alarm;
|
||||
private String alarmMsg;
|
||||
private String trayCode;
|
||||
private String productCode;
|
||||
private String productName;
|
||||
}
|
||||
}
|
||||
188
ruoyi-admin/src/main/java/com/ruoyi/tcp/GetDeviceSsjMap.java
Normal file
188
ruoyi-admin/src/main/java/com/ruoyi/tcp/GetDeviceSsjMap.java
Normal file
@@ -0,0 +1,188 @@
|
||||
package com.ruoyi.tcp;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.ruoyi.common.utils.DictUtils;
|
||||
import com.ruoyi.device.ssj.domain.DeviceSsj;
|
||||
import com.ruoyi.schedule.plcRead.ssj.PlcSsjRead;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import com.ruoyi.job.service.IMydoJobService;
|
||||
import com.ruoyi.job.domain.MydoJob;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.io.OutputStream;
|
||||
import java.net.Socket;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Component
|
||||
public class GetDeviceSsjMap {
|
||||
private final TcpServerManager manager;
|
||||
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||
private final IMydoJobService mydoJobService;
|
||||
|
||||
/**
|
||||
* 构造函数:注入 TCP 管理器与作业服务,用于管理 3333 端口广播并根据任务号补全物料信息
|
||||
*/
|
||||
public GetDeviceSsjMap(TcpServerManager manager, IMydoJobService mydoJobService) {
|
||||
this.manager = manager;
|
||||
this.mydoJobService = mydoJobService;
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化:注册 3333 端口的客户端连接监听,客户端第一次连接时立即发送输送机数据
|
||||
*/
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
manager.setClientListener("port3333", this::handleConnect);
|
||||
}
|
||||
|
||||
/**
|
||||
* 客户端连接处理:构建输送机数据并写入到 Socket 输出流
|
||||
*/
|
||||
private void handleConnect(Socket socket) {
|
||||
try {
|
||||
String payload = readConveyorsFromCache();
|
||||
OutputStream os = socket.getOutputStream();
|
||||
os.write(((payload == null ? "" : payload) + "\n").getBytes(StandardCharsets.UTF_8));
|
||||
os.flush();
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 周期发送:每 2 秒检查 3333 端口是否有连接,有则广播输送机数据,无连接不发送
|
||||
*/
|
||||
@Scheduled(fixedRate = 2000)
|
||||
public void send() {
|
||||
Integer count = manager.status().getOrDefault("port3333", 0);
|
||||
if (count != null && count > 0) {
|
||||
String payload = readConveyorsFromCache();
|
||||
manager.broadcast("port3333", payload == null ? "" : payload);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从 PLC 缓存读取输送机状态并组装 JSON
|
||||
* - 工作模式转换为中文标签
|
||||
* - 报警码与文案:使用字典 ssj_ex
|
||||
* - 当任务号有效时,查询 MydoJob 补齐托盘与物料信息
|
||||
* 返回 JSON 字符串格式:{"ssj":[{...}]}
|
||||
*/
|
||||
private String readConveyorsFromCache() {
|
||||
Map<String, DeviceSsj> map = PlcSsjRead.deviceSsjMap;
|
||||
List<SsjDto> list = new ArrayList<>();
|
||||
if (map == null || map.isEmpty()) {
|
||||
return toJson(list);
|
||||
}
|
||||
for (DeviceSsj d : map.values()) {
|
||||
SsjDto dto = new SsjDto();
|
||||
dto.setId(d.getDeviceCode());
|
||||
Integer cf = d.getModel();
|
||||
String mode = "0";
|
||||
if (cf != null) {
|
||||
if (cf == 1) {
|
||||
mode = "手动";
|
||||
}else if (cf == 2) {
|
||||
mode = "自动";
|
||||
}else {
|
||||
mode = String.valueOf(cf);
|
||||
}
|
||||
}
|
||||
dto.setWorkingMode(mode);
|
||||
dto.setTaskNo(String.valueOf(d.getTaskNo()));
|
||||
dto.setRotationDirection(calcRotationDirection(d.getTaskNo()));
|
||||
dto.setAlarm(String.valueOf(d.getException()));
|
||||
dto.setAlarmMsg(DictUtils.getDictLabel("ssj_ex", String.valueOf(d.getException())));
|
||||
dto.setDW(String.valueOf(d.getDw()));
|
||||
dto.setKX(String.valueOf(d.getKx()));
|
||||
if (d.getTaskNo() > 0) {
|
||||
try {
|
||||
MydoJob job = mydoJobService.selectMydoJobByTaskNo(Long.valueOf(d.getTaskNo()));
|
||||
dto.setTrayCode(job == null || job.getTrayCode() == null ? "" : job.getTrayCode());
|
||||
dto.setProductCode(job == null || job.getProductId() == null ? "" : job.getProductId());
|
||||
dto.setProductName(job == null || job.getProductName() == null ? "" : job.getProductName());
|
||||
} catch (Exception e) {
|
||||
dto.setTrayCode("");
|
||||
dto.setProductCode("");
|
||||
dto.setProductName("");
|
||||
}
|
||||
} else {
|
||||
dto.setTrayCode("");
|
||||
dto.setProductCode("");
|
||||
dto.setProductName("");
|
||||
}
|
||||
dto.setRunning("");
|
||||
list.add(dto);
|
||||
}
|
||||
return toJson(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算输送机旋转方向:依据作业 inOrOut 字段,>=20 返回 "2",<20 返回 "1"
|
||||
*/
|
||||
private String calcRotationDirection(int taskNo) {
|
||||
try {
|
||||
if (taskNo <= 0) return "0";
|
||||
MydoJob job = mydoJobService.selectMydoJobByTaskNo((long) taskNo);
|
||||
if (job == null || job.getInOrOut() == null) return "0";
|
||||
int val;
|
||||
try {
|
||||
val = Integer.parseInt(job.getInOrOut());
|
||||
} catch (NumberFormatException e) {
|
||||
return "0";
|
||||
}
|
||||
return val >= 20 ? "2" : "1";
|
||||
} catch (Exception e) {
|
||||
return "0";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表对象序列化为 JSON 字符串
|
||||
*/
|
||||
private String toJson(List<SsjDto> list) {
|
||||
try {
|
||||
Wrapper w = new Wrapper();
|
||||
w.setSsj(list);
|
||||
return objectMapper.writeValueAsString(w);
|
||||
} catch (Exception e) {
|
||||
return "{\"ssj\":[]}";
|
||||
}
|
||||
}
|
||||
|
||||
public static class Wrapper {
|
||||
private List<SsjDto> ssj;
|
||||
/**
|
||||
* 获取输送机列表
|
||||
*/
|
||||
public List<SsjDto> getSsj() { return ssj; }
|
||||
/**
|
||||
* 设置输送机列表
|
||||
*/
|
||||
public void setSsj(List<SsjDto> ssj) { this.ssj = ssj; }
|
||||
}
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public static class SsjDto {
|
||||
private String id;
|
||||
private String workingMode;
|
||||
private String taskNo;
|
||||
private String rotationDirection;
|
||||
private String alarm;
|
||||
private String alarmMsg;
|
||||
private String DW;
|
||||
private String KX;
|
||||
private String running;
|
||||
private String trayCode;
|
||||
private String productCode;
|
||||
private String productName;
|
||||
|
||||
}
|
||||
}
|
||||
151
ruoyi-admin/src/main/java/com/ruoyi/tcp/GetDeviceTsjMap.java
Normal file
151
ruoyi-admin/src/main/java/com/ruoyi/tcp/GetDeviceTsjMap.java
Normal file
@@ -0,0 +1,151 @@
|
||||
package com.ruoyi.tcp;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.ruoyi.common.utils.DictUtils;
|
||||
import com.ruoyi.device.tsj.domain.DeviceTsj;
|
||||
import com.ruoyi.job.domain.MydoJob;
|
||||
import com.ruoyi.job.service.IMydoJobService;
|
||||
import com.ruoyi.schedule.plcRead.tsj.PlcTsjRead;
|
||||
import lombok.Data;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.io.OutputStream;
|
||||
import java.net.Socket;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Component
|
||||
public class GetDeviceTsjMap {
|
||||
private final TcpServerManager manager;
|
||||
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||
private final IMydoJobService mydoJobService;
|
||||
|
||||
/**
|
||||
* 构造函数:注入 TCP 管理器与作业服务,用于管理 4444 端口广播并根据任务号补全物料信息
|
||||
*/
|
||||
public GetDeviceTsjMap(TcpServerManager manager, IMydoJobService mydoJobService) {
|
||||
this.manager = manager;
|
||||
this.mydoJobService = mydoJobService;
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化:注册 4444 端口的客户端连接监听,客户端第一次连接时立即发送提升机数据
|
||||
*/
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
manager.setClientListener("port4444", this::handleConnect);
|
||||
}
|
||||
|
||||
/**
|
||||
* 客户端连接处理:构建提升机数据并写入到 Socket 输出流
|
||||
*/
|
||||
private void handleConnect(Socket socket) {
|
||||
try {
|
||||
String payload = buildTsjPayload();
|
||||
OutputStream os = socket.getOutputStream();
|
||||
os.write(((payload == null ? "" : payload) + "\n").getBytes(StandardCharsets.UTF_8));
|
||||
os.flush();
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 周期发送:每 2 秒检查 4444 端口是否有连接,有则广播提升机数据,无连接不发送
|
||||
*/
|
||||
@Scheduled(fixedRate = 2000)
|
||||
public void send() {
|
||||
Integer count = manager.status().getOrDefault("port4444", 0);
|
||||
if (count != null && count > 0) {
|
||||
String payload = buildTsjPayload();
|
||||
manager.broadcast("port4444", payload == null ? "" : payload);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建提升机数据:从 PLC 缓存读取提升机状态并组装 JSON
|
||||
* - 工作模式转换为中文标签
|
||||
* - 报警码与文案:使用字典 tsj_alarm
|
||||
* - 当任务号有效时,查询 MydoJob 补齐托盘与物料信息
|
||||
* 返回 JSON 字符串格式:{"tsj":[{...}]}
|
||||
*/
|
||||
private String buildTsjPayload() {
|
||||
Map<String, DeviceTsj> map = PlcTsjRead.deviceTsjMap;
|
||||
List<TsjDto> list = new ArrayList<>();
|
||||
if (map != null) {
|
||||
for (Map.Entry<String, DeviceTsj> entry : map.entrySet()) {
|
||||
String code = entry.getKey();
|
||||
DeviceTsj d = entry.getValue();
|
||||
TsjDto dto = new TsjDto();
|
||||
dto.setId(String.valueOf(d.getId()));
|
||||
dto.setLayer(d.getDqcs() == null ? "" : String.valueOf(d.getDqcs()));
|
||||
dto.setTaskNo(d.getRwh() == null ? "" : String.valueOf(d.getRwh()));
|
||||
dto.setZxjd(d.getJdbz() == null ? "" : String.valueOf(d.getJdbz()));
|
||||
Integer cf = d.getCzfs();
|
||||
String mode = "0";
|
||||
if (cf != null) {
|
||||
if (cf == 1) {
|
||||
mode = "手动";
|
||||
}else if (cf == 2) {
|
||||
mode = "自动";
|
||||
}else {
|
||||
mode = String.valueOf(cf);
|
||||
}
|
||||
}
|
||||
dto.setWorkingMode(mode);
|
||||
dto.setSourceLayer(d.getYch() == null ? "" : String.valueOf(d.getYch()));
|
||||
dto.setTargetLayer(d.getMbch() == null ? "" : String.valueOf(d.getMbch()));
|
||||
dto.setAlarm(d.getSbzt() == null ? "" : String.valueOf(d.getSbzt()));
|
||||
dto.setAlarmMsg(DictUtils.getDictLabel("tsj_alarm", d.getSbzt() == null ? "" : String.valueOf(d.getSbzt())));
|
||||
if (d.getRwh() != null && d.getRwh() > 0) {
|
||||
try {
|
||||
MydoJob job = mydoJobService.selectMydoJobByTaskNo(Long.valueOf(d.getRwh()));
|
||||
dto.setTrayCode(job == null || job.getTrayCode() == null ? "" : job.getTrayCode());
|
||||
dto.setProductCode(job == null || job.getProductId() == null ? "" : job.getProductId());
|
||||
dto.setProductName(job == null || job.getProductName() == null ? "" : job.getProductName());
|
||||
} catch (Exception e) {
|
||||
dto.setTrayCode("");
|
||||
dto.setProductCode("");
|
||||
dto.setProductName("");
|
||||
}
|
||||
} else {
|
||||
dto.setTrayCode("");
|
||||
dto.setProductCode("");
|
||||
dto.setProductName("");
|
||||
}
|
||||
list.add(dto);
|
||||
}
|
||||
}
|
||||
try {
|
||||
Wrapper w = new Wrapper();
|
||||
w.setTsj(list);
|
||||
return objectMapper.writeValueAsString(w);
|
||||
} catch (Exception e) {
|
||||
return "{\"tsj\":[]}";
|
||||
}
|
||||
}
|
||||
|
||||
@Data
|
||||
private static class Wrapper {
|
||||
private List<TsjDto> tsj;
|
||||
}
|
||||
|
||||
@Data
|
||||
private static class TsjDto {
|
||||
private String id;
|
||||
private String taskNo;
|
||||
private String zxjd;
|
||||
private String workingMode;
|
||||
private String sourceLayer;
|
||||
private String targetLayer;
|
||||
private String alarm;
|
||||
private String alarmMsg;
|
||||
private String trayCode;
|
||||
private String productCode;
|
||||
private String productName;
|
||||
private String layer;
|
||||
}
|
||||
}
|
||||
149
ruoyi-admin/src/main/java/com/ruoyi/tcp/TcpServer.java
Normal file
149
ruoyi-admin/src/main/java/com/ruoyi/tcp/TcpServer.java
Normal file
@@ -0,0 +1,149 @@
|
||||
package com.ruoyi.tcp;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
@Slf4j
|
||||
public class TcpServer implements Runnable {
|
||||
@Getter
|
||||
private final String name;
|
||||
@Getter
|
||||
private final int port;
|
||||
private final AtomicBoolean running = new AtomicBoolean(false);
|
||||
private ServerSocket serverSocket;
|
||||
private final Set<Socket> clients = ConcurrentHashMap.newKeySet();
|
||||
private final ExecutorService clientPool = Executors.newCachedThreadPool();
|
||||
@lombok.Setter
|
||||
private volatile java.util.function.Consumer<Socket> clientListener;
|
||||
|
||||
public TcpServer(String name, int port) {
|
||||
this.name = name;
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动服务器:在守护线程中运行 ServerSocket 接受客户端连接
|
||||
*/
|
||||
public void start() {
|
||||
if (running.compareAndSet(false, true)) {
|
||||
Thread t = new Thread(this, "TcpServer-" + name + "-" + port);
|
||||
t.setDaemon(true);
|
||||
t.start();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止服务器:关闭 ServerSocket 与所有客户端连接,终止客户端线程池
|
||||
*/
|
||||
public void stop() {
|
||||
running.set(false);
|
||||
try {
|
||||
if (serverSocket != null) serverSocket.close();
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
for (Socket s : clients) {
|
||||
try {
|
||||
s.close();
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
clients.clear();
|
||||
clientPool.shutdownNow();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前已连接的客户端数量
|
||||
*/
|
||||
public int clientCount() {
|
||||
return clients.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* 广播消息到所有已连接客户端;写入失败的客户端将被移除
|
||||
*/
|
||||
public void broadcast(String message) {
|
||||
byte[] bytes = (message + "\n").getBytes(StandardCharsets.UTF_8);
|
||||
for (Socket s : clients) {
|
||||
try {
|
||||
OutputStream os = s.getOutputStream();
|
||||
os.write(bytes);
|
||||
os.flush();
|
||||
} catch (IOException e) {
|
||||
try {
|
||||
s.close();
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
clients.remove(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
/**
|
||||
* 服务器主循环:绑定端口,阻塞等待新连接并交由客户端处理线程执行
|
||||
*/
|
||||
public void run() {
|
||||
try {
|
||||
serverSocket = new ServerSocket(port);
|
||||
log.info("TCP server {} started on {}", name, port);
|
||||
while (running.get()) {
|
||||
Socket socket = serverSocket.accept();
|
||||
clients.add(socket);
|
||||
clientPool.execute(() -> handleClient(socket));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
if (running.get()) {
|
||||
log.error("TCP server {} failed on {} {}", name, port, e.getMessage());
|
||||
}
|
||||
} finally {
|
||||
stop();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 单个客户端处理:
|
||||
* - 调用已注册的客户端监听器进行初次处理
|
||||
* - 读取客户端输入,支持 ping/pong 心跳应答
|
||||
* - 连接结束时关闭资源并移除客户端
|
||||
*/
|
||||
private void handleClient(Socket socket) {
|
||||
if (clientListener != null) {
|
||||
try {
|
||||
clientListener.accept(socket);
|
||||
} catch (Exception e) {
|
||||
log.error("Error in client listener for {} on port {}", name, port, e);
|
||||
}
|
||||
}
|
||||
try {
|
||||
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8));
|
||||
String line;
|
||||
while ((line = br.readLine()) != null && running.get()) {
|
||||
if ("ping".equalsIgnoreCase(line.trim())) {
|
||||
OutputStream os = socket.getOutputStream();
|
||||
os.write("pong\n".getBytes(StandardCharsets.UTF_8));
|
||||
os.flush();
|
||||
}
|
||||
}
|
||||
} catch (IOException ignored) {
|
||||
} finally {
|
||||
try {
|
||||
socket.close();
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
clients.remove(socket);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package com.ruoyi.tcp;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.annotation.PreDestroy;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class TcpServerManager {
|
||||
private final TcpServerProperties properties;
|
||||
private final Map<String, TcpServer> servers = new HashMap<>();
|
||||
|
||||
/**
|
||||
* 构造函数:注入 TCP 服务器配置(启用标志与端口映射)
|
||||
*/
|
||||
public TcpServerManager(TcpServerProperties properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化:按配置创建并启动各端口的 TCP 服务器
|
||||
*/
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
if (!properties.isEnabled()) return;
|
||||
for (Map.Entry<String, Integer> e : properties.getChannels().entrySet()) {
|
||||
TcpServer s = new TcpServer(e.getKey(), e.getValue());
|
||||
servers.put(e.getKey(), s);
|
||||
s.start();
|
||||
}
|
||||
log.info("TCP servers initialized {}", properties.getChannels());
|
||||
}
|
||||
|
||||
/**
|
||||
* 销毁:停止所有 TCP 服务器并清理缓存
|
||||
*/
|
||||
@PreDestroy
|
||||
public void destroy() {
|
||||
for (TcpServer s : servers.values()) {
|
||||
s.stop();
|
||||
}
|
||||
servers.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* 状态查询:返回每个通道当前已连接客户端数量
|
||||
*/
|
||||
public Map<String, Integer> status() {
|
||||
Map<String, Integer> map = new HashMap<>();
|
||||
for (Map.Entry<String, TcpServer> e : servers.entrySet()) {
|
||||
map.put(e.getKey(), e.getValue().clientCount());
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* 广播消息:向指定通道的所有客户端发送文本消息
|
||||
*/
|
||||
public boolean broadcast(String channel, String message) {
|
||||
TcpServer s = servers.get(channel);
|
||||
if (s == null) return false;
|
||||
s.broadcast(message);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置客户端监听器:为指定通道注册客户端连接回调
|
||||
*/
|
||||
public void setClientListener(String channel, java.util.function.Consumer<java.net.Socket> listener) {
|
||||
TcpServer s = servers.get(channel);
|
||||
if (s != null) {
|
||||
s.setClientListener(listener);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取服务器实例集合(只读视图)
|
||||
*/
|
||||
public Map<String, TcpServer> getServers() {
|
||||
return Collections.unmodifiableMap(servers);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.ruoyi.tcp;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Component
|
||||
@ConfigurationProperties(prefix = "tcpserver")
|
||||
public class TcpServerProperties {
|
||||
private boolean enabled = false;
|
||||
private Map<String, Integer> channels = new LinkedHashMap<>();
|
||||
|
||||
/**
|
||||
* 获取是否启用 TCP 服务器功能
|
||||
*/
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置是否启用 TCP 服务器功能
|
||||
*/
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取通道端口映射(通道名 -> 端口号)
|
||||
*/
|
||||
public Map<String, Integer> getChannels() {
|
||||
return channels;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置通道端口映射(通道名 -> 端口号)
|
||||
*/
|
||||
public void setChannels(Map<String, Integer> channels) {
|
||||
this.channels = channels;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
package com.ruoyi.tcp;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.ruoyi.common.Constant;
|
||||
import lombok.Data;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.io.OutputStream;
|
||||
import java.net.Socket;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class Wcs2wmsgetEmptyCargoSpace {
|
||||
private final TcpServerManager manager;
|
||||
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||
private final RestTemplate restTemplate = new RestTemplate();
|
||||
|
||||
/**
|
||||
* 构造函数:注入 TCP 管理器,用于在 1111 端口管理客户端与数据发送
|
||||
*/
|
||||
public Wcs2wmsgetEmptyCargoSpace(TcpServerManager manager) {
|
||||
this.manager = manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化:注册 1111 端口客户端监听,客户端首次连接时触发数据发送
|
||||
*/
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
manager.setClientListener("port1111", this::handleConnect);
|
||||
}
|
||||
|
||||
/**
|
||||
* 客户端连接处理:调用 WMS 接口获取空货位数据,转换为统一 JSON 并写入到 Socket
|
||||
*/
|
||||
private void handleConnect(Socket socket) {
|
||||
try {
|
||||
String url = Constant.WMS_BASE_URL + "twin/getEmptyCargoSpace";
|
||||
log.info("Fetching WMS data from {}", url);
|
||||
String wmsResponse = restTemplate.getForObject(url, String.class);
|
||||
|
||||
JsonNode root = objectMapper.readTree(wmsResponse);
|
||||
List<CargoDto> cargoList = new ArrayList<>();
|
||||
|
||||
// Handle if root is array or wrapped in "data" or "rows"
|
||||
JsonNode arrayNode = null;
|
||||
if (root.isArray()) {
|
||||
arrayNode = root;
|
||||
} else if (root.has("data") && root.get("data").isArray()) {
|
||||
arrayNode = root.get("data");
|
||||
} else if (root.has("rows") && root.get("rows").isArray()) {
|
||||
arrayNode = root.get("rows");
|
||||
}
|
||||
|
||||
if (arrayNode != null) {
|
||||
for (JsonNode node : arrayNode) {
|
||||
cargoList.add(mapToDto(node));
|
||||
}
|
||||
} else {
|
||||
// If it's a single object, maybe treat as one item?
|
||||
// Or maybe the format is different. For now, log warning if empty.
|
||||
log.warn("WMS response is not an array: {}", wmsResponse);
|
||||
}
|
||||
|
||||
CargoResponse response = new CargoResponse();
|
||||
response.setCargo(cargoList);
|
||||
String json = objectMapper.writeValueAsString(response);
|
||||
|
||||
OutputStream os = socket.getOutputStream();
|
||||
os.write((json + "\n").getBytes(StandardCharsets.UTF_8));
|
||||
os.flush();
|
||||
log.info("Sent WMS data to client on port 1111");
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to fetch WMS data or send to client", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 映射单条 WMS 返回记录为 DTO:优先取目标字段名,兼容 BasCargoSpace 字段名
|
||||
*/
|
||||
private CargoDto mapToDto(JsonNode node) {
|
||||
CargoDto dto = new CargoDto();
|
||||
// Mapping strategy: try user's target keys first, then BasCargoSpace keys
|
||||
dto.setRow(getText(node, "row", "thePlatoon"));
|
||||
dto.setColumn(getText(node, "column", "theColumn"));
|
||||
dto.setLayer(getText(node, "layer", "theFloor"));
|
||||
dto.setStatus(getText(node, "status"));
|
||||
dto.setTrayCode(getText(node, "trayCode"));
|
||||
dto.setProductCode(getText(node, "productCode"));
|
||||
dto.setProductName(getText(node, "productName"));
|
||||
return dto;
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取节点文本:按给定字段名顺序查找首个存在且非空的值
|
||||
*/
|
||||
private String getText(JsonNode node, String... keys) {
|
||||
for (String key : keys) {
|
||||
if (node.has(key) && !node.get(key).isNull()) {
|
||||
return node.get(key).asText();
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
@Data
|
||||
private static class CargoResponse {
|
||||
private List<CargoDto> cargo;
|
||||
}
|
||||
|
||||
@Data
|
||||
private static class CargoDto {
|
||||
private String row;
|
||||
private String column;
|
||||
private String layer;
|
||||
private String status;
|
||||
private String trayCode;
|
||||
private String productCode;
|
||||
private String productName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package com.ruoyi.tcp;
|
||||
|
||||
import com.ruoyi.common.Constant;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.io.OutputStream;
|
||||
import java.net.Socket;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
@Component
|
||||
public class Wcs2wmsgetStockList {
|
||||
private final TcpServerManager manager;
|
||||
private final RestTemplate restTemplate = new RestTemplate();
|
||||
|
||||
/**
|
||||
* 构造函数:注入 TCP 管理器,用于在 6666 端口管理客户端与数据发送
|
||||
*/
|
||||
public Wcs2wmsgetStockList(TcpServerManager manager) {
|
||||
this.manager = manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化:注册 6666 端口客户端监听,客户端首次连接时触发库存数据发送
|
||||
*/
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
manager.setClientListener("port6666", this::handleConnect);
|
||||
}
|
||||
|
||||
/**
|
||||
* 客户端连接处理:调用 WMS 接口获取库存列表并写入到 Socket 输出流
|
||||
*/
|
||||
private void handleConnect(Socket socket) {
|
||||
try {
|
||||
String url = Constant.WMS_BASE_URL + "twin/getStockList";
|
||||
String payload = restTemplate.getForObject(url, String.class);
|
||||
OutputStream os = socket.getOutputStream();
|
||||
os.write(((payload == null ? "" : payload) + "\n").getBytes(StandardCharsets.UTF_8));
|
||||
os.flush();
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 周期发送:每 10 秒检查 6666 端口是否有连接,有则广播库存数据,无连接不发送
|
||||
*/
|
||||
@Scheduled(fixedRate = 10000)
|
||||
public void send() {
|
||||
Integer count = manager.status().getOrDefault("port6666", 0);
|
||||
if (count != null && count > 0) {
|
||||
String url = Constant.WMS_BASE_URL + "twin/getStockList";
|
||||
String payload = restTemplate.getForObject(url, String.class);
|
||||
manager.broadcast("port6666", payload == null ? "" : payload);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -127,3 +127,25 @@ xss:
|
||||
excludes: /system/notice
|
||||
# 匹配链接
|
||||
urlPatterns: /system/*,/monitor/*,/tool/*
|
||||
|
||||
# TCP服务器配置
|
||||
tcpserver:
|
||||
# 是否开启TCP服务器
|
||||
enabled: true
|
||||
# 通道配置
|
||||
channels:
|
||||
status: 9000
|
||||
events: 9001
|
||||
alarms: 9002
|
||||
# 货位与库存查询端口
|
||||
port1111: 1111
|
||||
# 数据分析端口
|
||||
port6666: 6666
|
||||
# Srgv端口
|
||||
port2222: 2222
|
||||
# ssj端口
|
||||
port3333: 3333
|
||||
# tsj端口
|
||||
port4444: 4444
|
||||
# 报警端口
|
||||
port5555: 5555
|
||||
|
||||
@@ -94,7 +94,7 @@ import { selectDictLabel } from "@/utils/ruoyi"
|
||||
|
||||
export default {
|
||||
name: "deviceMonitor",
|
||||
dicts: ['srgv_work_phase','srgv_work_mode','srgv_status','srgv_err_msg','srgv_alarm','srgv_task_type','ssj_dw','ssj_kx','ssj_ex','tsj_zxjd'],
|
||||
dicts: ['srgv_work_phase','srgv_work_mode','srgv_status','srgv_err_msg','srgv_alarm','srgv_task_type','ssj_dw','ssj_kx','ssj_ex','tsj_zxjd','tsj_alarm'],
|
||||
data() {
|
||||
return {
|
||||
imageUrl1: ssjImg,
|
||||
@@ -178,15 +178,11 @@ export default {
|
||||
{ key: 'rwh', label: '任务号', value: d.rwh },
|
||||
{ key: 'yxxf', label: '允许下发', value: d.yxxf },
|
||||
{ key: 'dqcs', label: '当前层数', value: d.dqcs },
|
||||
{ key: 'yph', label: '原排', value: d.yph },
|
||||
{ key: 'ylh', label: '原列', value: d.ylh },
|
||||
{ key: 'ych', label: '原层', value: d.ych },
|
||||
{ key: 'mbph', label: '目标排', value: d.mbph },
|
||||
{ key: 'mblh', label: '目标列', value: d.mblh },
|
||||
{ key: 'mbch', label: '目标层', value: d.mbch },
|
||||
{ key: 'hczt', label: '载货状态', value: d.hczt },
|
||||
{ key: 'xtxh', label: '心跳信号', value: d.xtxh },
|
||||
{ key: 'sbzt', label: '设备状态', value: d.sbzt },
|
||||
{ key: 'sbzt', label: '设备状态', value: d.sbzt, dict: 'tsj_alarm' },
|
||||
{ key: 'jdbz', label: '执行阶段', value: d.jdbz, dict: 'tsj_zxjd' }
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user