Commit cf69dc85 authored by wanghao's avatar wanghao

1 老化过程中 获取卡号,获取IOT状态调整中

parent 2a1ab005
......@@ -124,6 +124,17 @@ public class PalletDeviceBindingController extends BaseController
return toAjax(palletDeviceBindingService.batchUpdateDeviceCodeAndUnbindingTime(palletDeviceBindings));
}
/**
* 实时获取iot状态
* @param trayCode f
* @return r
*/
@GetMapping("/realTimeObtainIotStatusByTrayCode/{trayCode}")
public AjaxResult realTimeObtainIotStatusByTrayCode(@PathVariable("trayCode") String trayCode){
return palletDeviceBindingService.realTimeObtainIotStatusByTrayCode(trayCode);
}
/**
* 修改托盘绑定的设备列
*/
......
......@@ -36,6 +36,7 @@ public class Modbus4jUtils {
private static final int START_ADDRESS = 0; // 对应40001
private static final int REGISTER_COUNT = 16; // 读取15个寄存器
private static final int REGISTER_COUNT_36 = 36; // 读取36个寄存器
private static final int TARGET_VALUE = 1; // 目标值(第二个寄存器的期望值)
private static final int MAX_RETRIES = 3; // 最大重试次数
private static final int RETRY_DELAY = 500; // 重试延迟(ms)// 监控参数
......@@ -1103,7 +1104,7 @@ public class Modbus4jUtils {
throws ModbusTransportException {
// 创建读取请求
ReadHoldingRegistersRequest request = Modbus4jUtils.getReadHoldingRegistersRequest(deviceId,START_ADDRESS, REGISTER_COUNT);
ReadHoldingRegistersRequest request = Modbus4jUtils.getReadHoldingRegistersRequest(deviceId,START_ADDRESS, REGISTER_COUNT_36);
// 发送请求并获取响应
ModbusResponse response = master.send(request);
......
......@@ -148,7 +148,8 @@ public class CalibrationResultEventHandler {
&& palletDeviceBinding.getWriteSelfCheckStatus() != null && palletDeviceBinding.getWriteSelfCheckStatus() == 1
&& palletDeviceBinding.getModuleStatus() != null && palletDeviceBinding.getModuleStatus() == 1
&& palletDeviceBinding.getSimCardStatus() != null && palletDeviceBinding.getSimCardStatus() == 1
&& palletDeviceBinding.getNetworkStatus() != null && palletDeviceBinding.getNetworkStatus() == 1) {
&& palletDeviceBinding.getNetworkStatus() != null && palletDeviceBinding.getNetworkStatus() == 1
&& palletDeviceBinding.getIotStatus() != null && palletDeviceBinding.getIotStatus() == 1) {
palletDeviceBinding.setStandardInspectResult("1");
}
......
......@@ -59,6 +59,8 @@ public interface IPalletDeviceBindingService
public int batchUpdateDeviceCodeAndUnbindingTime(List<PalletDeviceBinding> palletDeviceBindingList);
public AjaxResult realTimeObtainIotStatusByTrayCode(String trayCode);
/**
* 修改托盘绑定的设备列
*
......
......@@ -3,6 +3,8 @@ package com.zehong.system.service.impl;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.util.concurrent.RateLimiter;
import com.zehong.common.constant.Constants;
import com.zehong.common.constant.RoboticArmConstans;
import com.zehong.common.core.domain.AjaxResult;
import com.zehong.common.utils.DateUtils;
......@@ -13,14 +15,14 @@ import com.zehong.system.mapper.*;
import com.zehong.system.service.*;
import com.zehong.system.task.DeviceTaskScheduler;
import com.zehong.system.task.event.ReceivedNbCodeEvent;
import com.zehong.system.task.util.IotDataAndTokenUtil;
import org.quartz.SchedulerException;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.List;
import java.util.Set;
import java.util.*;
import java.util.stream.Collectors;
/**
......@@ -63,6 +65,11 @@ public class PalletDeviceBindingServiceImpl implements IPalletDeviceBindingServi
@Resource
private ApplicationEventPublisher eventPublisher; // 新增事件发布器
@Resource
private IotDataAndTokenUtil iotDataAndTokenUtil;
// 根据 IOT 接口文档的 QPS 限制调整,如果接口说限制 50 QPS,就设 45 留余量
private static final RateLimiter RATE_LIMITER = RateLimiter.create(2);
/**
* 查询托盘绑定的设备列
*
......@@ -264,6 +271,103 @@ public class PalletDeviceBindingServiceImpl implements IPalletDeviceBindingServi
return palletDeviceBindingMapper.batchUpdateDeviceCodeAndUnbindingTime(palletDeviceBindingList);
}
/**
* 实时获取物联网状态
*
* @param trayCode 托盘编号
* @return 结果
*/
@Override
public AjaxResult realTimeObtainIotStatusByTrayCode(String trayCode) {
if(StringUtils.isBlank(trayCode)){
return AjaxResult.error("托盘编号不能为空");
}
PalletDeviceBinding palletDeviceBinding = new PalletDeviceBinding();
palletDeviceBinding.setfTrayCode(trayCode);
List<PalletDeviceBinding> palletDeviceBindings = palletDeviceBindingMapper.selectPalletDeviceBindingList(palletDeviceBinding);
if(palletDeviceBindings == null || palletDeviceBindings.size() == 0){
return AjaxResult.error("无此托盘");
}
// 2. 按主板码分组,并过滤掉无效数据(同时提前处理无需调接口的)
// // 只留 nbCode 有效的 // 网络状态为 1
Map<String, List<PalletDeviceBinding>> groupByMotherboard = palletDeviceBindings.stream()
.filter(b -> org.apache.commons.lang3.StringUtils.isNotBlank(b.getNbCode()) && b.getNetworkStatus() != null && b.getNetworkStatus() == 1)
.collect(Collectors.groupingBy(PalletDeviceBinding::getMotherboardCode));
// 处理 nbCode 为空的(直接设状态为 2,加入待更新列表)
for (PalletDeviceBinding binding : palletDeviceBindings) {
if (org.apache.commons.lang3.StringUtils.isBlank(binding.getNbCode())) {
binding.setIotStatus(2);
}
// 顺便处理网络状态异常(但不要覆盖后续 IOT 查询结果,网络异常只是前置标记)
// 注意:如果网络状态 !=1,但 IOT 查询成功,应该以 IOT 为准,这里先不 set,留给后面判断
}
// 3. 获取 IOT Token(只获取一次)
String iotToken = iotDataAndTokenUtil.getIOTToken();
if (org.apache.commons.lang3.StringUtils.isBlank(iotToken)) {
throw new RuntimeException("IOT token未获取");
}
// 4. 构造通用请求头
Map<String, String> headers = new HashMap<>();
headers.put("Authorization", iotToken);
headers.put("Content-Type", "application/json");
String iotApiUrl = sysConfigService.directSelectConfigByKey(Constants.IOT_DEVICES_SCAN);
// 5. 循环处理每个主板码(带限流)
for (Map.Entry<String, List<PalletDeviceBinding>> entry : groupByMotherboard.entrySet()) {
String motherboardCode = entry.getKey();
List<PalletDeviceBinding> sameBoardDevices = entry.getValue();
// 取任意一个设备的 nbCode(因为同一主板下的 nbCode 理论上一致,但为了严谨取第一个非空的)
String nbCode = sameBoardDevices.stream()
.map(PalletDeviceBinding::getNbCode)
.filter(org.apache.commons.lang3.StringUtils::isNotBlank)
.findFirst()
.orElse(null);
if (nbCode == null) {
continue;
}
// ★★★ Guava 限流(阻塞等待令牌) ★★★
RATE_LIMITER.acquire();
// 调用 IOT 接口
Map<String, Object> params = new HashMap<>();
params.put("number", nbCode);
String result = null;
try {
result = HttpUtils.get(iotApiUrl, headers, params);
} catch (Exception e) {
log.error("调用IOT接口异常, motherboardCode: {}, nbCode: {}", motherboardCode, nbCode, e);
}
// 6. 根据结果设置状态(应用到该主板下的所有设备)
Integer statusToSet;
if (org.apache.commons.lang3.StringUtils.isNotBlank(result)) {
Map<String, String> dataMap = iotDataAndTokenUtil.processIotData(result);
if (dataMap != null && !dataMap.isEmpty()) {
statusToSet = 1; // IOT数据正常
} else {
statusToSet = 0; // IOT数据为空
}
} else {
statusToSet = 0; // 请求失败
}
// 将状态设置给该组所有设备,并加入待更新列表
for (PalletDeviceBinding device : sameBoardDevices) {
device.setIotStatus(statusToSet);
}
}
return AjaxResult.success(palletDeviceBindings);
}
/**
* 修改托盘绑定的设备列
*
......
......@@ -22,6 +22,7 @@ import com.zehong.system.netty.handler.NettyUdpServerHandler;
import com.zehong.system.service.IConveyorBeltIpMaintainService;
import com.zehong.system.service.websocket.RobotArmWebSocketHandler;
import com.zehong.system.task.event.CheckPowerOnCommandEvent;
import com.zehong.system.task.event.IotStatusEvent;
import com.zehong.system.task.event.PowerOffCommandEvent;
import com.zehong.system.udp.UdpCommandSender;
import org.slf4j.Logger;
......@@ -190,7 +191,7 @@ public class RobotArmCommandServiceImpl implements IRobotArmCommandService
Modbus4jUtils.writeCoil(master, 1, registerOffsetInt, false);
log.info("已发送断电指令 - 设备:{} 层:{}", tEquipmentInfo.getfEquipmentCode(), layer);
master.destroy();
eventPublisher.publishEvent(new IotStatusEvent(this, storeyCode));
// 如果正常 则发送 IOT请求
} catch (ModbusTransportException | ModbusInitException e) {
log.info("下料发送断电指令失败 - 设备:{} 层:{}", tEquipmentInfo.getfEquipmentCode(), layer);
......
......@@ -182,6 +182,15 @@ public class AgingStageOneProcessJob implements Job {
int i = Modbus4jUtils.writeSelfCheckStatus(master, deviceId);
binding.setWriteSelfCheckStatus(i);
}
// 设置卡号
StringBuilder simCardNoBuilder = new StringBuilder();
for (int i = 17; i <= 36; i++) {
simCardNoBuilder.append(result[i]);
}
String simCardNo = simCardNoBuilder.toString();
binding.setSimCardNo(simCardNo);
// 6. 更新数据库
palletDeviceBindingMapper.updatePalletDeviceBinding(binding);
......
......@@ -222,6 +222,14 @@ public class AgingStageThreeProcessJob implements Job {
if("5".equals(binding.getDeviceStatus())) {
binding.setWriteTimeStatus("0");
}
// 设置卡号
StringBuilder simCardNoBuilder = new StringBuilder();
for (int i = 17; i <= 36; i++) {
simCardNoBuilder.append(result[i]);
}
String simCardNo = simCardNoBuilder.toString();
binding.setSimCardNo(simCardNo);
// 5. 更新数据库
palletDeviceBindingMapper.updatePalletDeviceBinding(binding);
......
......@@ -250,6 +250,13 @@ public class AgingStageTwoProcessJob implements Job {
binding.setWriteSelfCheckStatus(i);
}
// 设置卡号
StringBuilder simCardNoBuilder = new StringBuilder();
for (int i = 17; i <= 36; i++) {
simCardNoBuilder.append(result[i]);
}
String simCardNo = simCardNoBuilder.toString();
binding.setSimCardNo(simCardNo);
// 5. 更新数据库
palletDeviceBindingMapper.updatePalletDeviceBinding(binding);
......
......@@ -9,8 +9,6 @@ import com.serotonin.modbus4j.exception.ModbusInitException;
import com.serotonin.modbus4j.exception.ModbusTransportException;
import com.zehong.common.constant.Constants;
import com.zehong.common.constant.RoboticArmConstans;
import com.zehong.common.core.domain.AjaxResult;
import com.zehong.common.core.redis.RedisCache;
import com.zehong.common.utils.DateUtils;
import com.zehong.common.utils.http.HttpUtils;
import com.zehong.system.domain.*;
......@@ -25,6 +23,7 @@ import com.zehong.system.task.event.CheckPowerOnCommandEvent;
import com.zehong.system.task.event.IotStatusEvent;
import com.zehong.system.task.event.PowerOffCommandEvent;
import com.zehong.system.task.event.ReceivedNbCodeEvent;
import com.zehong.system.task.util.IotDataAndTokenUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.event.EventListener;
......@@ -34,7 +33,6 @@ import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
/**
......@@ -76,8 +74,7 @@ public class AllCommandHandler {
private IReceivedNbFailureHistoryService receivedNbFailureHistoryService;
@Resource
private RedisCache redisCache;
private IotDataAndTokenUtil iotDataAndTokenUtil;
@Resource
private ISysConfigService sysConfigService;
......@@ -239,8 +236,9 @@ public class AllCommandHandler {
}
// 2. 按主板码分组,并过滤掉无效数据(同时提前处理无需调接口的)
// // 只留 nbCode 有效的 // 网络状态为 1
Map<String, List<PalletDeviceBinding>> groupByMotherboard = bindings.stream()
.filter(b -> StringUtils.isNotBlank(b.getNbCode())) // 只留 nbCode 有效的
.filter(b -> StringUtils.isNotBlank(b.getNbCode()) && b.getNetworkStatus() == 1)
.collect(Collectors.groupingBy(PalletDeviceBinding::getMotherboardCode));
// 处理 nbCode 为空的(直接设状态为 2,加入待更新列表)
......@@ -263,7 +261,7 @@ public class AllCommandHandler {
}
// 3. 获取 IOT Token(只获取一次)
String iotToken = getIOTToken();
String iotToken = iotDataAndTokenUtil.getIOTToken();
if (StringUtils.isBlank(iotToken)) {
throw new RuntimeException("IOT token未获取");
}
......@@ -305,7 +303,7 @@ public class AllCommandHandler {
// 6. 根据结果设置状态(应用到该主板下的所有设备)
Integer statusToSet;
if (StringUtils.isNotBlank(result)) {
Map<String, String> dataMap = processIotData(result);
Map<String, String> dataMap = iotDataAndTokenUtil.processIotData(result);
if (dataMap != null && !dataMap.isEmpty()) {
statusToSet = 1; // IOT数据正常
} else {
......@@ -328,161 +326,6 @@ public class AllCommandHandler {
}
}
/**
* 处理MES返回的数据
*/
private Map<String,String > processIotData(String data ) {
Map<String,String > deviceStatus = new HashMap<>();
// 根据实际业务需求处理数据
// 这里只是示例,具体实现根据您的业务逻辑
try {
JSONObject jsonObject = JSON.parseObject(data);
Object data1 = jsonObject.get("data");
if(data1 == null) {
return deviceStatus;
}
JSONObject jsonData = JSON.parseObject(data1.toString());
deviceStatus.put("number", jsonData.getString("number") == null ? "" : jsonData.getString("number"));
deviceStatus.put("title", jsonData.getString("title") == null ? "" : jsonData.getString("title"));
deviceStatus.put("deviceType", jsonData.getString("devices_type") == null ? "" : jsonData.getString("devices_type"));
deviceStatus.put("modelTitle", jsonData.getString("model_title") == null ? "" : jsonData.getString("model_title"));
deviceStatus.put("batchNum", jsonData.getString("batchNum") == null ? "" : jsonData.getString("batchNum"));
deviceStatus.put("gas", jsonData.getString("gas") == null ? "" : jsonData.getString("gas"));
deviceStatus.put("unit", jsonData.getString("unit") == null ? "" : jsonData.getString("unit"));
deviceStatus.put("status", jsonData.getString("report_status") == null ? "" : jsonData.getString("report_status"));
deviceStatus.put("concentration", jsonData.getString("report_nd") == null ? "" : jsonData.getString("report_nd"));
deviceStatus.put("reportTime", jsonData.getString("report_time") == null ? "" : jsonData.getString("report_time"));
// 处理数据逻辑...
return deviceStatus;
} catch (Exception e) {
return new HashMap<>();
}
}
/**
* 获取MES token
*/
private String getIOTToken() {
// 1. 先从Redis中获取token
Object tokenObj = redisCache.getCacheObject(Constants.IOT_LOGIN_TOKEN);
if (tokenObj != null) {
String token = tokenObj.toString();
// 检查token是否即将过期(提前5分钟刷新)
long expireTime = redisCache.getExpire(Constants.IOT_LOGIN_TOKEN, TimeUnit.MINUTES);
if (expireTime > 10) { // 大于10分钟,直接返回
return token;
}
}
// 2. 如果Redis中没有或即将过期,重新获取token
return refreshIOTToken();
}
/**
* 刷新MES token
*/
private String refreshIOTToken() {
try {
// 1. 获取登录配置信息
String loginUrl = sysConfigService.directSelectConfigByKey(Constants.IOT_LOGIN_ADDRESS);
String username = sysConfigService.directSelectConfigByKey(Constants.IOT_LOGIN_USERNAME);
String password = sysConfigService.directSelectConfigByKey(Constants.IOT_LOGIN_PASSWORD);
if (org.apache.commons.lang3.StringUtils.isAnyBlank(loginUrl, username, password)) {
throw new RuntimeException("MES登录配置信息不完整");
}
// 2. 构造登录参数
Map<String, String> loginParams = new HashMap<>();
loginParams.put("username", username);
loginParams.put("password", password);
// 3. 添加请求头
Map<String, String> headers = new HashMap<>();
// 3. 调用登录接口
String response = HttpUtils.postJson(loginUrl, headers ,loginParams);
// 5. 解析响应
if (org.apache.commons.lang3.StringUtils.isNotBlank(response)) {
// 尝试解析为JSON
try {
Map<String, Object> responseMap = JSON.parseObject(response, Map.class);
// 检查是否有错误
if (responseMap.containsKey("code") && !"200".equals(String.valueOf(responseMap.get("code")))) {
String errorMsg = responseMap.containsKey("msg") ?
String.valueOf(responseMap.get("msg")) : "登录失败";
System.err.println("登录失败: " + errorMsg);
return null;
}
// 根据实际响应结构提取token
String token = extractTokenFromResponse(responseMap);
if (org.apache.commons.lang3.StringUtils.isNotBlank(token)) {
// 存储token到Redis
redisCache.setCacheObject(Constants.IOT_LOGIN_TOKEN, token, 1, TimeUnit.HOURS);
System.out.println("登录成功,token: " + token);
return token;
}
} catch (Exception e) {
System.err.println("解析响应失败: " + e.getMessage());
e.printStackTrace();
}
}
return null;
} catch (Exception e) {
throw new RuntimeException("获取MES token失败");
}
}
/**
* 从响应中提取token(根据实际响应格式调整)
*/
private String extractTokenFromResponse(Map<String, Object> responseMap) {
// 根据实际响应结构提取token
// 例如:responseMap.get("data").get("token")
// 示例1:如果token在顶层
if (responseMap.containsKey("token")) {
return String.valueOf(responseMap.get("token"));
}
// 示例2:如果token在data对象中
if (responseMap.containsKey("data")) {
Object data = responseMap.get("data");
if (data instanceof Map) {
Map<?, ?> dataMap = (Map<?, ?>) data;
if (dataMap.containsKey("access_token")) {
return String.valueOf(dataMap.get("access_token"));
}
}
}
// 示例3:如果token在其他字段中
String[] possibleTokenKeys = {"access_token", "accessToken", "Authorization", "authToken"};
for (String key : possibleTokenKeys) {
if (responseMap.containsKey(key)) {
return String.valueOf(responseMap.get(key));
}
}
// 如果都找不到,打印整个响应用于调试
System.out.println("无法找到token,完整响应: " + JSON.toJSONString(responseMap));
return null;
}
/**
* 接收到NB码
* @param event event
......
package com.zehong.system.task.util;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.zehong.common.constant.Constants;
import com.zehong.common.core.redis.RedisCache;
import com.zehong.common.utils.http.HttpUtils;
import com.zehong.system.service.ISysConfigService;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* @author lenovo
* @date 2026/8/4
* @description tokenUtil
*/
@Component
public class IotDataAndTokenUtil {
@Resource
private RedisCache redisCache;
@Resource
private ISysConfigService sysConfigService;
/**
* 获取MES token
*/
public String getIOTToken() {
// 1. 先从Redis中获取token
Object tokenObj = redisCache.getCacheObject(Constants.IOT_LOGIN_TOKEN);
if (tokenObj != null) {
String token = tokenObj.toString();
// 检查token是否即将过期(提前5分钟刷新)
long expireTime = redisCache.getExpire(Constants.IOT_LOGIN_TOKEN, TimeUnit.MINUTES);
if (expireTime > 10) { // 大于10分钟,直接返回
return token;
}
}
// 2. 如果Redis中没有或即将过期,重新获取token
return refreshIOTToken();
}
/**
* 刷新MES token
*/
private String refreshIOTToken() {
try {
// 1. 获取登录配置信息
String loginUrl = sysConfigService.directSelectConfigByKey(Constants.IOT_LOGIN_ADDRESS);
String username = sysConfigService.directSelectConfigByKey(Constants.IOT_LOGIN_USERNAME);
String password = sysConfigService.directSelectConfigByKey(Constants.IOT_LOGIN_PASSWORD);
if (org.apache.commons.lang3.StringUtils.isAnyBlank(loginUrl, username, password)) {
throw new RuntimeException("MES登录配置信息不完整");
}
// 2. 构造登录参数
Map<String, String> loginParams = new HashMap<>();
loginParams.put("username", username);
loginParams.put("password", password);
// 3. 添加请求头
Map<String, String> headers = new HashMap<>();
// 3. 调用登录接口
String response = HttpUtils.postJson(loginUrl, headers ,loginParams);
// 5. 解析响应
if (org.apache.commons.lang3.StringUtils.isNotBlank(response)) {
// 尝试解析为JSON
try {
Map<String, Object> responseMap = JSON.parseObject(response, Map.class);
// 检查是否有错误
if (responseMap.containsKey("code") && !"200".equals(String.valueOf(responseMap.get("code")))) {
String errorMsg = responseMap.containsKey("msg") ?
String.valueOf(responseMap.get("msg")) : "登录失败";
System.err.println("登录失败: " + errorMsg);
return null;
}
// 根据实际响应结构提取token
String token = extractTokenFromResponse(responseMap);
if (org.apache.commons.lang3.StringUtils.isNotBlank(token)) {
// 存储token到Redis
redisCache.setCacheObject(Constants.IOT_LOGIN_TOKEN, token, 1, TimeUnit.HOURS);
System.out.println("登录成功,token: " + token);
return token;
}
} catch (Exception e) {
System.err.println("解析响应失败: " + e.getMessage());
e.printStackTrace();
}
}
return null;
} catch (Exception e) {
throw new RuntimeException("获取MES token失败");
}
}
/**
* 从响应中提取token(根据实际响应格式调整)
*/
private String extractTokenFromResponse(Map<String, Object> responseMap) {
// 根据实际响应结构提取token
// 例如:responseMap.get("data").get("token")
// 示例1:如果token在顶层
if (responseMap.containsKey("token")) {
return String.valueOf(responseMap.get("token"));
}
// 示例2:如果token在data对象中
if (responseMap.containsKey("data")) {
Object data = responseMap.get("data");
if (data instanceof Map) {
Map<?, ?> dataMap = (Map<?, ?>) data;
if (dataMap.containsKey("access_token")) {
return String.valueOf(dataMap.get("access_token"));
}
}
}
// 示例3:如果token在其他字段中
String[] possibleTokenKeys = {"access_token", "accessToken", "Authorization", "authToken"};
for (String key : possibleTokenKeys) {
if (responseMap.containsKey(key)) {
return String.valueOf(responseMap.get(key));
}
}
// 如果都找不到,打印整个响应用于调试
System.out.println("无法找到token,完整响应: " + JSON.toJSONString(responseMap));
return null;
}
/**
* 处理MES返回的数据
*/
public Map<String,String > processIotData(String data ) {
Map<String,String > deviceStatus = new HashMap<>();
// 根据实际业务需求处理数据
// 这里只是示例,具体实现根据您的业务逻辑
try {
JSONObject jsonObject = JSON.parseObject(data);
Object data1 = jsonObject.get("data");
if(data1 == null) {
return deviceStatus;
}
JSONObject jsonData = JSON.parseObject(data1.toString());
deviceStatus.put("number", jsonData.getString("number") == null ? "" : jsonData.getString("number"));
deviceStatus.put("title", jsonData.getString("title") == null ? "" : jsonData.getString("title"));
deviceStatus.put("deviceType", jsonData.getString("devices_type") == null ? "" : jsonData.getString("devices_type"));
deviceStatus.put("modelTitle", jsonData.getString("model_title") == null ? "" : jsonData.getString("model_title"));
deviceStatus.put("batchNum", jsonData.getString("batchNum") == null ? "" : jsonData.getString("batchNum"));
deviceStatus.put("gas", jsonData.getString("gas") == null ? "" : jsonData.getString("gas"));
deviceStatus.put("unit", jsonData.getString("unit") == null ? "" : jsonData.getString("unit"));
deviceStatus.put("status", jsonData.getString("report_status") == null ? "" : jsonData.getString("report_status"));
deviceStatus.put("concentration", jsonData.getString("report_nd") == null ? "" : jsonData.getString("report_nd"));
deviceStatus.put("reportTime", jsonData.getString("report_time") == null ? "" : jsonData.getString("report_time"));
// 处理数据逻辑...
return deviceStatus;
} catch (Exception e) {
return new HashMap<>();
}
}
}
......@@ -73,6 +73,13 @@ export function unbindAllDeviceNoUploadMes(trayId){
})
}
export function realTimeObtainIotStatusByTrayCode(trayCode){
return request({
url: '/palletDevice/binding/realTimeObtainIotStatusByTrayCode/' + trayCode,
method: 'get'
})
}
// 修改托盘绑定的设备列
export function updateBinding(data) {
return request({
......
......@@ -367,6 +367,7 @@ export default {
(device.runTimeStatus != null && device.runTimeStatus === '0') ||
(device.relayStatus != null && device.relayStatus === 0) ||
(device.pulseStatus != null && device.pulseStatus === 0) ||
(device.iotStatus != null && device.iotStatus === 0) ||
device.moduleStatus === 0 || device.simCardStatus === 0 || device.networkStatus === 0;
},
......
<template>
<div class="iot-status-container">
<!-- 搜索区域 -->
<el-form :inline="true" class="search-form">
<el-form-item>
<el-input
v-model="trayCode"
placeholder="请输入托盘号"
clearable
size="medium"
@keyup.enter.native="handleSearch"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="handleSearch">查询</el-button>
</el-form-item>
</el-form>
<!-- 加载状态 -->
<div v-loading="loading" class="result-area">
<!-- 无数据提示 -->
<el-empty v-if="!loading && matrixData.length === 0" description="暂无数据,请搜索托盘号" />
<!-- 矩阵网格 8行 x 9列 -->
<div v-else class="matrix-grid">
<div
v-for="(row, rowIndex) in matrixData"
:key="'row-' + rowIndex"
class="matrix-row"
>
<div
v-for="(cell, colIndex) in row"
:key="'col-' + colIndex"
class="matrix-cell"
>
<!-- 有设备数据显示圆点 -->
<el-tooltip
v-if="cell"
placement="top"
:content="tooltipContent(cell)"
effect="dark"
>
<div
class="dot"
:class="{
'dot-green': isNormal(cell),
'dot-red': !isNormal(cell)
}"
></div>
</el-tooltip>
<!-- 无设备数据展示空位(灰色小圆) -->
<div v-else class="dot dot-empty"></div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { realTimeObtainIotStatusByTrayCode } from '@/api/palletDeviceBinding/binding'
export default {
name: 'SearchIotStatus',
data() {
return {
trayCode: '',
loading: false,
deviceList: [], // 接口返回的原始数组
matrixData: [] // 8行 x 9列的二维数组
}
},
methods: {
/** 搜索 */
handleSearch() {
if (!this.trayCode.trim()) {
this.$message.warning('请输入托盘号')
return
}
this.loading = true
realTimeObtainIotStatusByTrayCode(this.trayCode.trim())
.then(res => {
this.deviceList = res.data || []
if (this.deviceList.length === 0) {
this.$message.info('未查询到设备信息')
}
this.buildMatrix()
})
.catch(err => {
this.$message.error('查询失败:' + (err.message || '未知错误'))
this.deviceList = []
this.matrixData = []
})
.finally(() => {
this.loading = false
})
},
/** 根据 deviceList 构建 8行 x 9列 的矩阵 */
buildMatrix() {
// 初始化 8行 x 9列,全部为 null
const rows = 8
const cols = 9
const matrix = Array.from({ length: rows }, () => Array(cols).fill(null))
// 填充数据:row 和 col 从 1 开始,映射到索引 0 开始
this.deviceList.forEach(item => {
const rowIdx = (item.row || 0) - 1
const colIdx = (item.col || 0) - 1
// 仅当行列在有效范围内才填充
if (rowIdx >= 0 && rowIdx < rows && colIdx >= 0 && colIdx < cols) {
matrix[rowIdx][colIdx] = item
}
})
this.matrixData = matrix
},
/** 判断该设备是否正常(网络和IOT均为正常) */
isNormal(cell) {
if (!cell) return false
const networkOk = cell.networkStatus === 1
const iotOk = cell.iotStatus === 1
return networkOk && iotOk
},
/** 生成悬停提示内容 */
tooltipContent(cell) {
if (!cell) return ''
const rows = [
`行:${cell.row ?? '-'}`,
`列:${cell.col ?? '-'}`,
`设备编号:${cell.motherboardCode || '-'}`,
`NB码:${cell.nbCode || '-'}`,
`网络状态:${this.formatNetworkStatus(cell.networkStatus)}`,
`IOT状态:${this.formatIotStatus(cell.iotStatus)}`
]
return rows.join('\n')
},
/** 格式化网络状态显示文本(用于tooltip) */
formatNetworkStatus(status) {
if (status === null || status === undefined) return '空'
return status === 1 ? '正常' : '异常'
},
/** 格式化IOT状态显示文本(用于tooltip) */
formatIotStatus(status) {
if (status === null || status === undefined) return '空'
const map = {
0: '异常',
1: '正常',
2: 'Nb码为空',
3: '网络状态异常'
}
return map[status] || '未知'
}
}
}
</script>
<style lang="scss" scoped>
.iot-status-container {
padding: 20px;
.search-form {
margin-bottom: 20px;
text-align: center;
}
.result-area {
min-height: 200px;
}
.matrix-grid {
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
margin-top: 10px;
}
.matrix-row {
display: flex;
gap: 8px;
}
.matrix-cell {
width: 40px;
height: 40px;
display: flex;
align-items: center;
justify-content: center;
}
.dot {
width: 28px;
height: 28px;
border-radius: 50%;
border: 2px solid #dcdfe6;
background-color: #f5f7fa;
transition: all 0.2s;
cursor: default;
&.dot-green {
background-color: #67c23a;
border-color: #67c23a;
box-shadow: 0 2px 6px rgba(103, 194, 58, 0.3);
}
&.dot-red {
background-color: #f56c6c;
border-color: #f56c6c;
box-shadow: 0 2px 6px rgba(245, 108, 108, 0.3);
}
&.dot-empty {
background-color: #e4e7ed;
border-color: #c0c4cc;
opacity: 0.4;
}
&:hover {
transform: scale(1.1);
}
}
}
</style>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment