Commit 04c19f2a authored by wanghao's avatar wanghao

1 上料 时 读状态 写时间,以及 托盘 和 层之间绑定关系的处理。

2 72 小时老化后 托盘 和 层之间 关系处理。
3 下料 时 断电 以及  托盘 和 层之间绑定关系的处理。
parent 9808fa2d
...@@ -209,25 +209,25 @@ public class TestTaskController { ...@@ -209,25 +209,25 @@ public class TestTaskController {
Integer registerOffset = entry.getKey(); Integer registerOffset = entry.getKey();
String registerValue = entry.getValue(); String registerValue = entry.getValue();
if ("true".equals(registerValue)) { if ("true".equals(registerValue)) {
eventPublisher.publishEvent(new CheckPowerOnCommandEvent( // eventPublisher.publishEvent(new CheckPowerOnCommandEvent(
this, // this,
modbusDeviceData.getDeviceCode(), // modbusDeviceData.getDeviceCode(),
modbusDeviceData.getfPowerOutageIp(), // modbusDeviceData.getfPowerOutageIp(),
modbusDeviceData.getfPowerOutagePort(), // modbusDeviceData.getfPowerOutagePort(),
registerOffset +1, // registerOffset +1,
registerOffset // registerOffset
)); // ));
isRun = true; isRun = true;
// 要给这个 层 发断电的 指令 // 要给这个 层 发断电的 指令
} else { } else {
// 发布断电指令事件(不再直接执行) // 发布断电指令事件(不再直接执行)
eventPublisher.publishEvent(new PowerOffCommandEvent( // eventPublisher.publishEvent(new PowerOffCommandEvent(
this, // this,
modbusDeviceData.getDeviceCode(), // modbusDeviceData.getDeviceCode(),
modbusDeviceData.getfPowerOutageIp(), // modbusDeviceData.getfPowerOutageIp(),
modbusDeviceData.getfPowerOutagePort(), // modbusDeviceData.getfPowerOutagePort(),
registerOffset // registerOffset
)); // ));
} }
} }
if (isRun) { if (isRun) {
......
...@@ -52,7 +52,7 @@ public class PalletDeviceBinding extends BaseEntity ...@@ -52,7 +52,7 @@ public class PalletDeviceBinding extends BaseEntity
private Date unbindingTime; private Date unbindingTime;
/** /**
* 状态 * 状态 0-预热;1-正常;3-传感器故障;4-报警;5-通讯故障;6-程序写时间失败
*/ */
private String status; private String status;
...@@ -81,6 +81,26 @@ public class PalletDeviceBinding extends BaseEntity ...@@ -81,6 +81,26 @@ public class PalletDeviceBinding extends BaseEntity
*/ */
private String recordMinute; private String recordMinute;
/**
* 写时间状态 0-失败;1-成功
*/
private String writeTimeStatus;
/**
* 零点校准AD
*/
private String adjustmentZeroAd;
/**
* 零点校准AD
*/
private String calibrationAd;
/**
* 浓度
*/
private String concentration;
public String getStatus() { public String getStatus() {
return status; return status;
} }
...@@ -201,6 +221,38 @@ public class PalletDeviceBinding extends BaseEntity ...@@ -201,6 +221,38 @@ public class PalletDeviceBinding extends BaseEntity
this.recordMinute = recordMinute; this.recordMinute = recordMinute;
} }
public String getWriteTimeStatus() {
return writeTimeStatus;
}
public void setWriteTimeStatus(String writeTimeStatus) {
this.writeTimeStatus = writeTimeStatus;
}
public String getAdjustmentZeroAd() {
return adjustmentZeroAd;
}
public void setAdjustmentZeroAd(String adjustmentZeroAd) {
this.adjustmentZeroAd = adjustmentZeroAd;
}
public String getCalibrationAd() {
return calibrationAd;
}
public void setCalibrationAd(String calibrationAd) {
this.calibrationAd = calibrationAd;
}
public String getConcentration() {
return concentration;
}
public void setConcentration(String concentration) {
this.concentration = concentration;
}
@Override @Override
public String toString() { public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
......
...@@ -67,9 +67,15 @@ public class TStoreyInfo extends BaseEntity ...@@ -67,9 +67,15 @@ public class TStoreyInfo extends BaseEntity
/** 老化开始时间 */ /** 老化开始时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Excel(name = "更新时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss") @Excel(name = "老化开始时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
private Date fAgingStartTime; private Date fAgingStartTime;
/** 老化结束时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Excel(name = "老化结束时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
private Date fAgingEndTime;
/** 更新时间 */ /** 更新时间 */
@JsonFormat(pattern = "yyyy-MM-dd") @JsonFormat(pattern = "yyyy-MM-dd")
@Excel(name = "更新时间", width = 30, dateFormat = "yyyy-MM-dd") @Excel(name = "更新时间", width = 30, dateFormat = "yyyy-MM-dd")
...@@ -224,6 +230,14 @@ public class TStoreyInfo extends BaseEntity ...@@ -224,6 +230,14 @@ public class TStoreyInfo extends BaseEntity
this.fEquipmentCode = fEquipmentCode; this.fEquipmentCode = fEquipmentCode;
} }
public Date getfAgingEndTime() {
return fAgingEndTime;
}
public void setfAgingEndTime(Date fAgingEndTime) {
this.fAgingEndTime = fAgingEndTime;
}
@Override @Override
public String toString() { public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
......
...@@ -29,7 +29,7 @@ public class TTrayInfo extends BaseEntity ...@@ -29,7 +29,7 @@ public class TTrayInfo extends BaseEntity
private String fStoreyCode; private String fStoreyCode;
/** 状态:0.空闲 1.运行 */ /** 状态:0.空闲 1.运行 */
@Excel(name = "状态:0.空闲 1.运行") @Excel(name = "状态:0.空闲 1.运行 2老化完成 3标定完成")
private String fStatus; private String fStatus;
/** 绑定设备数 */ /** 绑定设备数 */
......
...@@ -21,6 +21,10 @@ public interface TTrayInfoMapper ...@@ -21,6 +21,10 @@ public interface TTrayInfoMapper
public TTrayInfo selectTTrayInfoByCode(String code); public TTrayInfo selectTTrayInfoByCode(String code);
public TTrayInfo selectTTrayInfoByStoreyCode(String storeyCode);
public int clearStoreyCodeByStoreyCode(String storeyCode);
/** /**
* 查询托盘信息列表 * 查询托盘信息列表
* *
......
...@@ -88,6 +88,7 @@ public class PalletDeviceBindingServiceImpl implements IPalletDeviceBindingServi ...@@ -88,6 +88,7 @@ public class PalletDeviceBindingServiceImpl implements IPalletDeviceBindingServi
@Override @Override
public int batchUpdateDeviceCode(List<PalletDeviceBinding> palletDeviceBindingList) { public int batchUpdateDeviceCode(List<PalletDeviceBinding> palletDeviceBindingList) {
palletDeviceBindingList.forEach(palletDeviceBinding -> { palletDeviceBindingList.forEach(palletDeviceBinding -> {
palletDeviceBinding.setStatus("1");
palletDeviceBinding.setUpdateTime(DateUtils.getNowDate()); palletDeviceBinding.setUpdateTime(DateUtils.getNowDate());
}); });
return palletDeviceBindingMapper.batchUpdateDeviceCode(palletDeviceBindingList); return palletDeviceBindingMapper.batchUpdateDeviceCode(palletDeviceBindingList);
......
...@@ -23,6 +23,7 @@ import com.zehong.system.modbus.util.Modbus4jUtils; ...@@ -23,6 +23,7 @@ import com.zehong.system.modbus.util.Modbus4jUtils;
import com.zehong.system.netty.handler.NettyUdpServerHandler; import com.zehong.system.netty.handler.NettyUdpServerHandler;
import com.zehong.system.service.websocket.RobotArmWebSocketHandler; import com.zehong.system.service.websocket.RobotArmWebSocketHandler;
import com.zehong.system.task.CheckPowerOnCommandEvent; import com.zehong.system.task.CheckPowerOnCommandEvent;
import com.zehong.system.task.PowerOffCommandEvent;
import com.zehong.system.udp.UdpCommandSender; import com.zehong.system.udp.UdpCommandSender;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
...@@ -207,26 +208,23 @@ public class RobotArmCommandServiceImpl implements IRobotArmCommandService ...@@ -207,26 +208,23 @@ public class RobotArmCommandServiceImpl implements IRobotArmCommandService
log.info("command != null && \"2\".equals(command.getStatus()"); log.info("command != null && \"2\".equals(command.getStatus()");
// 发送上电指令 // 发送上电指令
try { try {
// 上料的指令 需要去上电
if("0".equals(command.getType())){
log.info("\"0\".equals(command.getType()");
// 发送上电指令给机械臂
String storeyCode = command.getStoreyCode();
String equitmentCode = "";
Integer registerOffset = null;
if(storeyCode.contains("-")) {
log.info("storeyCode.contains(\"-\")");
String[] parts = storeyCode.split("-");
equitmentCode = parts[0];
registerOffset = Integer.parseInt(parts[1]);
TEquipmentInfo tEquipmentInfo = equipmentInfoMapper.selectTEquipmentInfoByCode(equitmentCode);
if(tEquipmentInfo != null) {
log.info("tEquipmentInfo != null");
String powerOutageIp = tEquipmentInfo.getfPowerOutageIp();
Integer powerOutagePort = tEquipmentInfo.getfPowerOutagePort();
if(StringUtils.isNotBlank(powerOutageIp) && powerOutagePort != null) {
String storeyCode = command.getStoreyCode();
String equitmentCode = "";
Integer registerOffset = null;
if(storeyCode.contains("-")) {
log.info("storeyCode.contains(\"-\")");
String[] parts = storeyCode.split("-");
equitmentCode = parts[0];
registerOffset = Integer.parseInt(parts[1]);
TEquipmentInfo tEquipmentInfo = equipmentInfoMapper.selectTEquipmentInfoByCode(equitmentCode);
if(tEquipmentInfo != null) {
log.info("tEquipmentInfo != null");
String powerOutageIp = tEquipmentInfo.getfPowerOutageIp();
Integer powerOutagePort = tEquipmentInfo.getfPowerOutagePort();
if(StringUtils.isNotBlank(powerOutageIp) && powerOutagePort != null) {
if("0".equals(command.getType())) {
eventPublisher.publishEvent(new CheckPowerOnCommandEvent( eventPublisher.publishEvent(new CheckPowerOnCommandEvent(
this, this,
equitmentCode, equitmentCode,
...@@ -235,21 +233,17 @@ public class RobotArmCommandServiceImpl implements IRobotArmCommandService ...@@ -235,21 +233,17 @@ public class RobotArmCommandServiceImpl implements IRobotArmCommandService
registerOffset, registerOffset,
registerOffset - 1 registerOffset - 1
)); ));
} else {
eventPublisher.publishEvent(new PowerOffCommandEvent(
this,
equitmentCode,
powerOutageIp,
powerOutagePort,
registerOffset
));
} }
} }
} }
// 下料的话 得解除 托盘 和 层的绑定关系
} else {
TStoreyInfo tStoreyInfo = new TStoreyInfo();
tStoreyInfo.setfStoreyCode(command.getStoreyCode());
tStoreyInfo.setUpdateTime(new Date());
storeyInfoMapper.unbindByCode(tStoreyInfo);
TTrayInfo tTrayInfo = new TTrayInfo();
tTrayInfo.setfTrayCode(command.getTrayCode());
tTrayInfo.setUpdateTime(new Date());
tTrayInfo.setfUnbindingTime(new Date());
tTrayInfoMapper.unbindByCode(tTrayInfo);
} }
command.setStatus("4"); command.setStatus("4");
log.info("指令执行成功,状态设置为4"); log.info("指令执行成功,状态设置为4");
......
...@@ -173,25 +173,25 @@ public class AgingCabinetInspectionAndPowerCheckTask { ...@@ -173,25 +173,25 @@ public class AgingCabinetInspectionAndPowerCheckTask {
log.info("registerValue = " + registerValue); log.info("registerValue = " + registerValue);
log.info("true equals registerValue" + Boolean.TRUE.equals(registerValue)); log.info("true equals registerValue" + Boolean.TRUE.equals(registerValue));
if (Boolean.TRUE.equals(registerValue)) { if (Boolean.TRUE.equals(registerValue)) {
eventPublisher.publishEvent(new CheckPowerOnCommandEvent( // eventPublisher.publishEvent(new CheckPowerOnCommandEvent(
this, // this,
modbusDeviceData.getfEquipmentCode(), // modbusDeviceData.getfEquipmentCode(),
modbusDeviceData.getfPowerOutageIp(), // modbusDeviceData.getfPowerOutageIp(),
modbusDeviceData.getfPowerOutagePort(), // modbusDeviceData.getfPowerOutagePort(),
registerOffset + 1, // registerOffset + 1,
registerOffset // registerOffset
)); // ));
isRun = true; isRun = true;
// 要给这个 层 发断电的 指令 // 要给这个 层 发断电的 指令
} else { } else {
// 发布断电指令事件(不再直接执行) // 发布断电指令事件(不再直接执行)
eventPublisher.publishEvent(new PowerOffCommandEvent( // eventPublisher.publishEvent(new PowerOffCommandEvent(
this, // this,
modbusDeviceData.getfEquipmentCode(), // modbusDeviceData.getfEquipmentCode(),
modbusDeviceData.getfPowerOutageIp(), // modbusDeviceData.getfPowerOutageIp(),
modbusDeviceData.getfPowerOutagePort(), // modbusDeviceData.getfPowerOutagePort(),
registerOffset + 1 // registerOffset + 1
)); // ));
} }
} }
if (isRun) { if (isRun) {
......
...@@ -7,6 +7,8 @@ import com.serotonin.modbus4j.exception.ModbusTransportException; ...@@ -7,6 +7,8 @@ import com.serotonin.modbus4j.exception.ModbusTransportException;
import com.zehong.system.domain.TEquipmentAlarmData; import com.zehong.system.domain.TEquipmentAlarmData;
import com.zehong.system.domain.TStoreyInfo; import com.zehong.system.domain.TStoreyInfo;
import com.zehong.system.domain.TTrayInfo; import com.zehong.system.domain.TTrayInfo;
import com.zehong.system.mapper.TStoreyInfoMapper;
import com.zehong.system.mapper.TTrayInfoMapper;
import com.zehong.system.modbus.util.Modbus4jUtils; import com.zehong.system.modbus.util.Modbus4jUtils;
import com.zehong.system.service.ITEquipmentAlarmDataService; import com.zehong.system.service.ITEquipmentAlarmDataService;
import com.zehong.system.service.ITStoreyInfoService; import com.zehong.system.service.ITStoreyInfoService;
...@@ -29,8 +31,12 @@ public class AllCommandHandler { ...@@ -29,8 +31,12 @@ public class AllCommandHandler {
@Resource @Resource
private ITEquipmentAlarmDataService alarmDataService; private ITEquipmentAlarmDataService alarmDataService;
@Resource
private TStoreyInfoMapper tStoreyInfoMapper;
@Resource @Resource
private ITStoreyInfoService tStoreyInfoService; private TTrayInfoMapper tTrayInfoMapper;
@Resource @Resource
private ITTrayInfoService trayInfoService; private ITTrayInfoService trayInfoService;
...@@ -40,6 +46,7 @@ public class AllCommandHandler { ...@@ -40,6 +46,7 @@ public class AllCommandHandler {
/** /**
* check是否启动 ,没启动就启动下 开始老化 * check是否启动 ,没启动就启动下 开始老化
*
* @param event event * @param event event
*/ */
@Async @Async
...@@ -55,20 +62,20 @@ public class AllCommandHandler { ...@@ -55,20 +62,20 @@ public class AllCommandHandler {
String storeyCode = event.getDeviceCode() + "-" + event.getLayer(); String storeyCode = event.getDeviceCode() + "-" + event.getLayer();
log.info("需要发送上电指令 - 设备:{} 层:{} ip:{} 端口号:{}", event.getDeviceCode(),layer, fip, fport); log.info("需要发送上电指令 - 设备:{} 层:{} ip:{} 端口号:{}", event.getDeviceCode(), layer, fip, fport);
ModbusMaster master; ModbusMaster master;
try { try {
master = Modbus4jUtils.getMaster(fip, fport); master = Modbus4jUtils.getMaster(fip, fport);
Boolean aBoolean = Modbus4jUtils.readCoilStatus(master, 1, registerOffset); Boolean aBoolean = Modbus4jUtils.readCoilStatus(master, 1, registerOffset);
log.info("当前 - 设备:{} 层:{} -的 状态是:{}", event.getDeviceCode(), event.getLayer(),aBoolean); log.info("当前 - 设备:{} 层:{} -的 状态是:{}", event.getDeviceCode(), event.getLayer(), aBoolean);
if(!aBoolean) { if (!aBoolean) {
Modbus4jUtils.writeCoil(master, 1, registerOffset, true); Modbus4jUtils.writeCoil(master, 1, registerOffset, true);
TStoreyInfo tStoreyInfo = tStoreyInfoService.selectTStoreyInfoByCode(storeyCode); TStoreyInfo tStoreyInfo = tStoreyInfoMapper.selectTStoreyInfoByCode(storeyCode);
tStoreyInfo.setfStatus("1"); tStoreyInfo.setfStatus("1");
tStoreyInfo.setfAgingStartTime(new Date()); tStoreyInfo.setfAgingStartTime(new Date());
tStoreyInfoService.updateTStoreyInfo(tStoreyInfo); tStoreyInfoMapper.updateTStoreyInfo(tStoreyInfo);
// 同时 把 托盘的 状态更新 // 同时 把 托盘的 状态更新
TTrayInfo tTrayInfo = new TTrayInfo(); TTrayInfo tTrayInfo = new TTrayInfo();
...@@ -76,7 +83,7 @@ public class AllCommandHandler { ...@@ -76,7 +83,7 @@ public class AllCommandHandler {
tTrayInfo.setfStoreyCode(storeyCode); tTrayInfo.setfStoreyCode(storeyCode);
trayInfoService.updateStatusByTrayCode(tTrayInfo); trayInfoService.updateStatusByTrayCode(tTrayInfo);
deviceTaskScheduler.scheduleDeviceMonitoring(tStoreyInfo.getfStoreyId(),fip,fport); deviceTaskScheduler.scheduleDeviceMonitoring(tStoreyInfo.getfStoreyId(), fip, fport);
} }
} catch (ModbusInitException | ModbusTransportException | ErrorResponseException e) { } catch (ModbusInitException | ModbusTransportException | ErrorResponseException e) {
...@@ -98,7 +105,7 @@ public class AllCommandHandler { ...@@ -98,7 +105,7 @@ public class AllCommandHandler {
String ip = event.getIp(); String ip = event.getIp();
int port = event.getPort(); int port = event.getPort();
log.info("需要发送断电指令 - 设备:{} 层:{}", event.getDeviceCode(), event.getLayer()); log.info("需要发送断电指令 - 设备:{} 层:{}", event.getDeviceCode(), event.getLayer());
TStoreyInfo tStoreyInfo = tStoreyInfoService.selectTStoreyInfoByCode(storeyCode); TStoreyInfo tStoreyInfo = tStoreyInfoMapper.selectTStoreyInfoByCode(storeyCode);
if (tStoreyInfo == null) { if (tStoreyInfo == null) {
TEquipmentAlarmData alarmData = new TEquipmentAlarmData(); TEquipmentAlarmData alarmData = new TEquipmentAlarmData();
// 记录异常数据 // 记录异常数据
...@@ -107,11 +114,18 @@ public class AllCommandHandler { ...@@ -107,11 +114,18 @@ public class AllCommandHandler {
alarmData.setfAlarmData("下属" + storeyCode + "号老化层不存在"); alarmData.setfAlarmData("下属" + storeyCode + "号老化层不存在");
alarmDataService.insertTEquipmentAlarmData(alarmData); alarmDataService.insertTEquipmentAlarmData(alarmData);
} else { } else {
// // 下料后断电
ModbusMaster master = Modbus4jUtils.getMaster(ip, port); ModbusMaster master = Modbus4jUtils.getMaster(ip, port);
Modbus4jUtils.writeCoil(master, 1, event.getLayer(), false); Modbus4jUtils.writeCoil(master, 1, event.getLayer(), false);
log.info("已发送断电指令 - 设备:{} 层:{}", event.getDeviceCode(), event.getLayer()); log.info("已发送断电指令 - 设备:{} 层:{}", event.getDeviceCode(), event.getLayer());
master.destroy(); master.destroy();
tStoreyInfo.setfStoreyCode(tStoreyInfo.getfStoreyCode());
tStoreyInfo.setUpdateTime(new Date());
tStoreyInfoMapper.unbindByCode(tStoreyInfo);
// 清理 托盘 和 层的关联关系
tTrayInfoMapper.clearStoreyCodeByStoreyCode(storeyCode);
} }
} catch (ModbusInitException | ModbusTransportException e) { } catch (ModbusInitException | ModbusTransportException e) {
log.error("断电指令执行失败 - 设备:{} 层:{}", event.getDeviceCode(), event.getLayer(), e); log.error("断电指令执行失败 - 设备:{} 层:{}", event.getDeviceCode(), event.getLayer(), e);
......
...@@ -49,8 +49,7 @@ public class DeviceCommunicationJob implements Job { ...@@ -49,8 +49,7 @@ public class DeviceCommunicationJob implements Job {
private static final int SINGLE_DEVICE_TIMEOUT_SEC = 10; // 单个设备超时:10秒 private static final int SINGLE_DEVICE_TIMEOUT_SEC = 10; // 单个设备超时:10秒
// Modbus配置:取消内置重试,统一用自定义重试 // Modbus配置:取消内置重试,统一用自定义重试
private static final int MODBUS_CONN_TIMEOUT_MS = 3000; // 连接超时:3秒 private static final int MODBUS_CONN_TIMEOUT_MS = 3000; // 连接超时:3秒
private static final int CUSTOM_RETRY_TIMES = 1; // 自定义重试次数:1次 private static final int CUSTOM_RETRY_TIMES = 2; // 自定义重试次数:1次
private static final int RETRY_DELAY_MS = 200; // 重试间隔:200ms
// Modbus寄存器配置 // Modbus寄存器配置
private static final int REG_START_ADDR = 0; private static final int REG_START_ADDR = 0;
private static final int REG_READ_COUNT = 10; private static final int REG_READ_COUNT = 10;
...@@ -70,8 +69,6 @@ public class DeviceCommunicationJob implements Job { ...@@ -70,8 +69,6 @@ public class DeviceCommunicationJob implements Job {
private ITEquipmentAlarmDataService alarmDataService; private ITEquipmentAlarmDataService alarmDataService;
@Resource @Resource
private TStoreyInfoMapper tStoreyInfoMapper; private TStoreyInfoMapper tStoreyInfoMapper;
@Autowired
private ModbusResultHandler resultHandler;
@Resource @Resource
private PalletDeviceBindingMapper palletDeviceBindingMapper; private PalletDeviceBindingMapper palletDeviceBindingMapper;
...@@ -234,34 +231,58 @@ public class DeviceCommunicationJob implements Job { ...@@ -234,34 +231,58 @@ public class DeviceCommunicationJob implements Job {
*/ */
private int[] readDeviceWithRetry(String ip, int port, int deviceId) { private int[] readDeviceWithRetry(String ip, int port, int deviceId) {
ModbusMaster master = null; ModbusMaster master = null;
int[] lastResult = null; // 用于记录最后一次读取的结果(无论是否满足停止条件)
for (int retry = 0; retry <= CUSTOM_RETRY_TIMES; retry++) { try {
try { // 只创建一次ModbusMaster,循环内复用
master = createModbusMaster(ip, port); master = createModbusMaster(ip, port);
int[] result = readDeviceRegisters(master, deviceId);
for (int retry = 0; retry <= CUSTOM_RETRY_TIMES; retry++) {
// 检查停止条件 try {
if (resultHandler != null && ModbusResultHandler.createDefaultStopCondition().test(result)) { // 执行读取操作,获取本次结果
log.info("设备{}读取成功: ip={}, port={}", deviceId, ip, port); int[] currentResult = readDeviceRegisters(master, deviceId);
return result; // 更新最后一次结果(无论是否满足停止条件,都记录)
} lastResult = currentResult;
if (retry < CUSTOM_RETRY_TIMES) { // 检查停止条件,如果满足则提前返回(无需等到重试耗尽)
Thread.sleep(200); if (ModbusResultHandler.createDefaultStopCondition().test(currentResult)) {
} log.info("设备{}第{}次读取成功(满足条件): ip={}, port={}",
} catch (Exception e) { deviceId, retry + 1, ip, port);
if (retry < CUSTOM_RETRY_TIMES) { return currentResult;
log.info("设备{}读取失败,准备重试: ip={}, port={}", deviceId, ip, port); }
} else {
log.info("设备{}读取重试耗尽: ip={}, port={}", deviceId, ip, port, e); // 未满足条件且不是最后一次重试,休眠后继续
throw new RuntimeException("设备读取失败", e); if (retry < CUSTOM_RETRY_TIMES) {
log.info("设备{}第{}次读取未满足条件,准备重试: ip={}, port={}",
deviceId, retry + 1, ip, port);
Thread.sleep(200);
}
} catch (Exception e) {
// 本次读取发生异常,记录日志但不中断重试(继续下一次)
log.warn("设备{}第{}次读取发生异常: ip={}, port={}",
deviceId, retry + 1, ip, port, e);
// 如果是最后一次重试,异常时lastResult可能为null(需后续处理)
} }
} finally {
destroyModbusMaster(master, deviceId);
} }
// 循环结束(重试耗尽),此时lastResult为最后一次的结果(可能是正常读取但不满足条件,或null)
log.info("设备{}重试次数耗尽,返回最后一次结果: ip={}, port={}",
deviceId, ip, port);
} catch (Exception e) {
// 捕获创建ModbusMaster或休眠时的异常(非读取操作的异常)
log.error("设备{}连接创建或休眠失败: ip={}, port={}",
deviceId, ip, port, e);
throw new RuntimeException("设备连接或操作异常", e);
} finally {
// 无论结果如何,最终销毁连接
destroyModbusMaster(master, deviceId);
} }
throw new RuntimeException("设备读取未满足条件"); // 处理最后一次结果可能为null的情况(例如所有重试都异常)
if (lastResult == null) {
throw new RuntimeException("设备所有读取尝试均失败(无有效结果)");
}
return lastResult;
} }
/** /**
* 写入当前时间到设备 * 写入当前时间到设备
...@@ -292,9 +313,11 @@ public class DeviceCommunicationJob implements Job { ...@@ -292,9 +313,11 @@ public class DeviceCommunicationJob implements Job {
binding.setRecordMinute(String.valueOf(minute)); binding.setRecordMinute(String.valueOf(minute));
log.debug("设备{}时间写入成功", deviceId); log.debug("设备{}时间写入成功", deviceId);
} else { } else {
binding.setWriteTimeStatus("0");
recordAlarmByBinding(binding, "设备时间写入失败"); recordAlarmByBinding(binding, "设备时间写入失败");
} }
} catch (Exception e) { } catch (Exception e) {
binding.setWriteTimeStatus("0");
log.error("设备{}时间写入异常", deviceId, e); log.error("设备{}时间写入异常", deviceId, e);
recordAlarmByBinding(binding, "设备时间写入异常: " + e.getMessage()); recordAlarmByBinding(binding, "设备时间写入异常: " + e.getMessage());
} }
......
...@@ -236,14 +236,25 @@ public class DeviceTaskScheduler { ...@@ -236,14 +236,25 @@ public class DeviceTaskScheduler {
.storeDurably(false) .storeDurably(false)
.build(); .build();
Date executeTime = Date.from(Instant.now().plus(5, ChronoUnit.MINUTES));
// 关键修复:使用StartAt而不是StartNow // 关键修复:使用StartAt而不是StartNow
CronTrigger trigger = TriggerBuilder.newTrigger() SimpleTrigger trigger = TriggerBuilder.newTrigger()
.withIdentity(triggerKey) .withIdentity(triggerKey)
.forJob(jobKey) .forJob(jobKey)
.withSchedule(CronScheduleBuilder.cronSchedule("0 0/3 * * * ?") // 改为3分钟 .withDescription("设备" + fStoreyId + "最终任务触发器,触发时间是:" + executeTime)
.withMisfireHandlingInstructionDoNothing()) .startAt(executeTime)
.startAt(new Date()) // 显式设置开始时间:cite[1] .withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withMisfireHandlingInstructionFireNow() // 错过立即执行
.withRepeatCount(0)) // 仅一次
.build(); .build();
// CronTrigger trigger = TriggerBuilder.newTrigger()
// .withIdentity(triggerKey)
// .forJob(jobKey)
// .withDescription("设备" + fStoreyId + "写时间任务,触发时间是:" + executeTime)
// .withSchedule(CronScheduleBuilder.cronSchedule("0 0/3 * * * ?") // 改为3分钟
// .withMisfireHandlingInstructionDoNothing())
// .startAt(new Date()) // 显式设置开始时间:cite[1]
// .build();
Date nextFireTime = scheduler.scheduleJob(job, trigger); Date nextFireTime = scheduler.scheduleJob(job, trigger);
log.info("通信任务[{}]创建成功,下次执行:{}", jobId, nextFireTime); log.info("通信任务[{}]创建成功,下次执行:{}", jobId, nextFireTime);
......
...@@ -7,8 +7,10 @@ import com.zehong.common.utils.StringUtils; ...@@ -7,8 +7,10 @@ import com.zehong.common.utils.StringUtils;
import com.zehong.system.domain.RobotArmCommand; import com.zehong.system.domain.RobotArmCommand;
import com.zehong.system.domain.TEquipmentAlarmData; import com.zehong.system.domain.TEquipmentAlarmData;
import com.zehong.system.domain.TStoreyInfo; import com.zehong.system.domain.TStoreyInfo;
import com.zehong.system.domain.TTrayInfo;
import com.zehong.system.mapper.RobotArmCommandMapper; import com.zehong.system.mapper.RobotArmCommandMapper;
import com.zehong.system.mapper.TStoreyInfoMapper; import com.zehong.system.mapper.TStoreyInfoMapper;
import com.zehong.system.mapper.TTrayInfoMapper;
import com.zehong.system.modbus.util.Modbus4jUtils; import com.zehong.system.modbus.util.Modbus4jUtils;
import com.zehong.system.service.ITEquipmentAlarmDataService; import com.zehong.system.service.ITEquipmentAlarmDataService;
import com.zehong.system.service.ITStoreyInfoService; import com.zehong.system.service.ITStoreyInfoService;
...@@ -34,11 +36,12 @@ public class FinalExecutionJob implements Job { ...@@ -34,11 +36,12 @@ public class FinalExecutionJob implements Job {
private RobotArmWebSocketHandler robotArmWebSocketHandler; private RobotArmWebSocketHandler robotArmWebSocketHandler;
@Resource @Resource
private ITEquipmentAlarmDataService alarmDataService; private ITEquipmentAlarmDataService alarmDataService;
@Resource
private ITStoreyInfoService tStoreyInfoService;
@Resource @Resource
private TStoreyInfoMapper tStoreyInfoMapper; private TStoreyInfoMapper tStoreyInfoMapper;
@Resource
private TTrayInfoMapper tTrayInfoMapper;
@Resource @Resource
private Scheduler scheduler; private Scheduler scheduler;
...@@ -47,17 +50,18 @@ public class FinalExecutionJob implements Job { ...@@ -47,17 +50,18 @@ public class FinalExecutionJob implements Job {
@Override @Override
public void execute(JobExecutionContext context) { public void execute(JobExecutionContext context) {
// 1. 初始化变量,避免空指针 // 1. 初始化变量,避免空指针
JobDataMap data = null; JobDataMap data;
String fPowerOutageIp = null; String fPowerOutageIp;
Long fStoreyId = null; Long fStoreyId = null;
Integer fPowerOutagePort = null; Integer fPowerOutagePort;
TStoreyInfo tStoreyInfo = null; TStoreyInfo tStoreyInfo = null;
TTrayInfo tTrayInfo;
try { try {
// 2. 提取并校验所有参数 // 2. 提取并校验所有参数
data = context.getJobDetail().getJobDataMap(); data = context.getJobDetail().getJobDataMap();
if (data == null) { if (data == null) {
log.error("JobDataMap为空,终止执行"); log.info("JobDataMap为空,终止执行");
return; return;
} }
fStoreyId = data.getLong("fStoreyId"); fStoreyId = data.getLong("fStoreyId");
...@@ -65,45 +69,53 @@ public class FinalExecutionJob implements Job { ...@@ -65,45 +69,53 @@ public class FinalExecutionJob implements Job {
fPowerOutagePort = data.getInt("fPowerOutagePort"); fPowerOutagePort = data.getInt("fPowerOutagePort");
if(StringUtils.isBlank(fPowerOutageIp)) { if(StringUtils.isBlank(fPowerOutageIp)) {
log.error("参数缺失:fStoreyId={}, ip={}, port={},终止执行", fStoreyId, fPowerOutageIp, fPowerOutagePort); log.info("参数缺失:fStoreyId={}, ip={}, port={},终止执行", fStoreyId, fPowerOutageIp, fPowerOutagePort);
return; return;
} }
// 4. 查询设备信息 // 4. 查询设备信息
tStoreyInfo = tStoreyInfoMapper.selectTStoreyInfoById(fStoreyId); tStoreyInfo = tStoreyInfoMapper.selectTStoreyInfoById(fStoreyId);
if (tStoreyInfo == null) { if (tStoreyInfo == null) {
log.error("未查询到设备信息:fStoreyId={},终止执行", fStoreyId); log.info("未查询到设备信息:fStoreyId={},终止执行", fStoreyId);
return; return;
} }
// 5. 执行业务逻辑(Modbus写操作,单独捕获异常) // 5. 执行业务逻辑(Modbus写操作,单独捕获异常)
String storeyCode = tStoreyInfo.getfStoreyCode(); String storeyCode = tStoreyInfo.getfStoreyCode();
if (StringUtils.isBlank(storeyCode)) { if (StringUtils.isBlank(storeyCode)) {
log.error("设备编码为空:fStoreyId={},终止执行", fStoreyId); log.info("设备编码为空:fStoreyId={},终止执行", fStoreyId);
return;
}
int registerOffsets;
try {
registerOffsets = Integer.parseInt(storeyCode.split("-")[1]) - 1;
} catch (Exception e) {
log.error("设备编码解析失败:storeyCode={},终止执行", storeyCode);
return; return;
} }
tTrayInfo = tTrayInfoMapper.selectTTrayInfoByStoreyCode(storeyCode);
// Modbus写操作(容错:失败不影响后续清理任务) // Modbus写操作(容错:失败不影响后续清理任务)
try { // 科强说 老化完成先不断电,等下料后才断电
executeBusinessLogic(fPowerOutageIp, fPowerOutagePort, registerOffsets); // int registerOffsets;
log.info("Modbus写操作完成:fStoreyId={}", fStoreyId); // try {
} catch (Exception e) { // registerOffsets = Integer.parseInt(storeyCode.split("-")[1]) - 1;
log.error("Modbus写操作异常:fStoreyId={}", fStoreyId, e); // } catch (Exception e) {
// 记录告警,但不终止执行(后续清理任务必须执行) // log.error("设备编码解析失败:storeyCode={},终止执行", storeyCode);
recordAlarm(tStoreyInfo, "Modbus写操作失败:" + e.getMessage()); // return;
} // }
// try {
// executeBusinessLogic(fPowerOutageIp, fPowerOutagePort, registerOffsets);
// log.info("Modbus写操作完成:fStoreyId={}", fStoreyId);
// } catch (Exception e) {
// log.error("Modbus写操作异常:fStoreyId={}", fStoreyId, e);
// // 记录告警,但不终止执行(后续清理任务必须执行)
// recordAlarm(tStoreyInfo, "Modbus写操作失败:" + e.getMessage());
// }
// 6. 更新设备状态(DB操作单独捕获异常) // 6. 更新设备状态(DB操作单独捕获异常)
try { try {
tStoreyInfo.setfStatus("0"); tStoreyInfo.setfStatus("4");
tStoreyInfo.setfAgingStartTime(null); tStoreyInfo.setfAgingEndTime(new Date());
tStoreyInfoService.updateTStoreyInfo(tStoreyInfo); tStoreyInfoMapper.updateTStoreyInfo(tStoreyInfo);
tTrayInfo.setfStatus("2");
tTrayInfoMapper.updateTTrayInfo(tTrayInfo);
log.info("设备状态更新完成:fStoreyId={}", fStoreyId); log.info("设备状态更新完成:fStoreyId={}", fStoreyId);
} catch (Exception e) { } catch (Exception e) {
log.error("设备状态更新异常:fStoreyId={}", fStoreyId, e); log.error("设备状态更新异常:fStoreyId={}", fStoreyId, e);
...@@ -111,15 +123,16 @@ public class FinalExecutionJob implements Job { ...@@ -111,15 +123,16 @@ public class FinalExecutionJob implements Job {
} }
// 7.清理 job // 7.清理 job
cleanUpJobs(fStoreyId,context); // 为什么不用清理,是因为 写时间的任务 创建的时候是 一次性执行完的 job
// cleanUpJobs(fStoreyId,context);
// 8. 发送机械臂指令(单独捕获异常) // 8. 发送机械臂指令(单独捕获异常)
// try { try {
// createRoboticArm(tStoreyInfo.getfTrayCode(), storeyCode, tStoreyInfo.getBlankingCommand()); createRoboticArm(tStoreyInfo.getfTrayCode(), storeyCode, tStoreyInfo.getBlankingCommand());
// log.info("机械臂指令发送完成:fStoreyId={}", fStoreyId); log.info("机械臂指令发送完成:fStoreyId={}", fStoreyId);
// } catch (Exception e) { } catch (Exception e) {
// log.error("机械臂指令发送异常:fStoreyId={}", fStoreyId, e); log.error("机械臂指令发送异常:fStoreyId={}", fStoreyId, e);
// recordAlarm(tStoreyInfo, "机械臂指令发送失败:" + e.getMessage()); recordAlarm(tStoreyInfo, "机械臂指令发送失败:" + e.getMessage());
// } }
log.info("=== FinalExecutionJob 执行完成:fStoreyId={} ===", fStoreyId); log.info("=== FinalExecutionJob 执行完成:fStoreyId={} ===", fStoreyId);
......
...@@ -20,11 +20,17 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" ...@@ -20,11 +20,17 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="recordDate" column="f_record_date" /> <result property="recordDate" column="f_record_date" />
<result property="recordHour" column="f_record_hour" /> <result property="recordHour" column="f_record_hour" />
<result property="recordMinute" column="f_record_minute" /> <result property="recordMinute" column="f_record_minute" />
<result property="writeTimeStatus" column="f_write_time_status" />
<result property="adjustmentZeroAd" column="f_adjustment_zero_ad" />
<result property="calibrationAd" column="f_calibration_ad" />
<result property="concentration" column="f_concentration" />
</resultMap> </resultMap>
<sql id="selectPalletDeviceBindingVo"> <sql id="selectPalletDeviceBindingVo">
select f_pallet_device_binding_id, f_tray_id, f_device_code, f_row, f_col, f_index,f_binding_time, select f_pallet_device_binding_id, f_tray_id, f_device_code, f_row, f_col, f_index,f_binding_time,
f_unbinding_time, f_create_time,f_status,f_record_year,f_record_month,f_record_date,f_record_hour,f_record_minute from t_pallet_device_binding f_unbinding_time, f_create_time,f_status,f_record_year,f_record_month,f_record_date,f_record_hour,
f_record_minute, f_write_time_status, f_adjustment_zero_ad, f_calibration_ad, f_concentration from t_pallet_device_binding
</sql> </sql>
<select id="selectPalletDeviceBindingList" parameterType="PalletDeviceBinding" resultMap="PalletDeviceBindingResult"> <select id="selectPalletDeviceBindingList" parameterType="PalletDeviceBinding" resultMap="PalletDeviceBindingResult">
...@@ -61,7 +67,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" ...@@ -61,7 +67,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
f_record_month, f_record_month,
f_record_date, f_record_date,
f_record_hour, f_record_hour,
f_record_minute from t_pallet_device_binding palDeviceBinding where palDeviceBinding.f_tray_id = ( f_record_minute ,
f_write_time_status,
f_adjustment_zero_ad,
f_calibration_ad,
f_concentration
from t_pallet_device_binding palDeviceBinding where palDeviceBinding.f_tray_id = (
SELECT SELECT
trayInfo.f_tray_id trayInfo.f_tray_id
FROM FROM
...@@ -132,6 +143,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" ...@@ -132,6 +143,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="recordDate != null">f_record_date = #{recordDate},</if> <if test="recordDate != null">f_record_date = #{recordDate},</if>
<if test="recordHour != null">f_record_hour = #{recordHour},</if> <if test="recordHour != null">f_record_hour = #{recordHour},</if>
<if test="recordMinute != null">f_record_minute = #{recordMinute},</if> <if test="recordMinute != null">f_record_minute = #{recordMinute},</if>
<if test="writeTimeStatus != null">f_write_time_status = #{writeTimeStatus},</if>
<if test="adjustmentZeroAd != null">f_adjustment_zero_ad = #{adjustmentZeroAd},</if>
<if test="calibrationAd != null">f_calibration_ad = #{calibrationAd},</if>
<if test="concentration != null">f_concentration = #{concentration},</if>
</trim> </trim>
where f_pallet_device_binding_id = #{palletDeviceBindingId} where f_pallet_device_binding_id = #{palletDeviceBindingId}
</update> </update>
......
...@@ -14,6 +14,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" ...@@ -14,6 +14,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="fStatus" column="f_status" /> <result property="fStatus" column="f_status" />
<result property="fPort" column="f_port" /> <result property="fPort" column="f_port" />
<result property="fAgingStartTime" column="f_aging_start_time" /> <result property="fAgingStartTime" column="f_aging_start_time" />
<result property="fAgingEndTime" column="f_aging_end_time" />
<result property="fUpdateTime" column="f_update_time" /> <result property="fUpdateTime" column="f_update_time" />
<result property="fCreateTime" column="f_create_time" /> <result property="fCreateTime" column="f_create_time" />
<result property="fAlarmTime" column="f_alarm_time" /> <result property="fAlarmTime" column="f_alarm_time" />
...@@ -30,6 +31,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" ...@@ -30,6 +31,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
storeyInfo.f_status, storeyInfo.f_status,
storeyInfo.f_port, storeyInfo.f_port,
storeyInfo.f_aging_start_time, storeyInfo.f_aging_start_time,
storeyInfo.f_aging_end_time,
storeyInfo.f_update_time, storeyInfo.f_update_time,
storeyInfo.f_create_time, storeyInfo.f_create_time,
storeyInfo.f_alarm_time, storeyInfo.f_alarm_time,
...@@ -67,6 +69,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" ...@@ -67,6 +69,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<select id="queryByDepartmentId" parameterType="long" resultMap="TStoreyInfoResult"> <select id="queryByDepartmentId" parameterType="long" resultMap="TStoreyInfoResult">
<include refid="selectTStoreyInfoVo"/> <include refid="selectTStoreyInfoVo"/>
where storeyInfo.f_equipment_id = #{fEquipmentId} where storeyInfo.f_equipment_id = #{fEquipmentId}
order by storeyInfo.f_storey_id asc
</select> </select>
<select id="selectTStoreyInfoById" parameterType="Long" resultMap="TStoreyInfoResult"> <select id="selectTStoreyInfoById" parameterType="Long" resultMap="TStoreyInfoResult">
...@@ -88,6 +91,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" ...@@ -88,6 +91,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
f_status, f_status,
f_port, f_port,
f_aging_start_time, f_aging_start_time,
f_aging_end_time,
f_update_time, f_update_time,
f_create_time, f_create_time,
f_alarm_time, f_alarm_time,
...@@ -176,9 +180,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" ...@@ -176,9 +180,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="fPort != null">f_port = #{fPort},</if> <if test="fPort != null">f_port = #{fPort},</if>
<if test="fAgingStartTime != null">f_aging_start_time = #{fAgingStartTime},</if> <if test="fAgingStartTime != null">f_aging_start_time = #{fAgingStartTime},</if>
<if test="fAgingStartTime == null">f_aging_start_time = null,</if> <if test="fAgingStartTime == null">f_aging_start_time = null,</if>
<if test="fAgingEndTime != null">f_aging_end_time = #{fAgingEndTime},</if>
<if test="fAgingEndTime == null">f_aging_end_time = null,</if>
<if test="fUpdateTime != null">f_update_time = #{fUpdateTime},</if> <if test="fUpdateTime != null">f_update_time = #{fUpdateTime},</if>
<if test="fCreateTime != null">f_create_time = #{fCreateTime},</if> <if test="fCreateTime != null">f_create_time = #{fCreateTime},</if>
<if test="fAlarmTime != null">f_alarm_time = #{fAlarmTime},</if> <if test="fAlarmTime != null">f_alarm_time = #{fAlarmTime},</if>
<if test="fAlarmTime == null">f_alarm_time = null,</if>
<if test="blankingCommand != null">f_blanking_command = #{blankingCommand},</if> <if test="blankingCommand != null">f_blanking_command = #{blankingCommand},</if>
<if test="feedingCommand != null">f_feeding_command = #{feedingCommand},</if> <if test="feedingCommand != null">f_feeding_command = #{feedingCommand},</if>
...@@ -191,6 +198,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" ...@@ -191,6 +198,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="fStatus != null">f_status = #{fStatus},</if> <if test="fStatus != null">f_status = #{fStatus},</if>
<if test="fAgingStartTime != null">f_aging_start_time = #{fAgingStartTime},</if> <if test="fAgingStartTime != null">f_aging_start_time = #{fAgingStartTime},</if>
<if test="fAgingStartTime == null">f_aging_start_time = null,</if> <if test="fAgingStartTime == null">f_aging_start_time = null,</if>
<if test="fAgingEndTime != null">f_aging_end_time = #{fAgingEndTime},</if>
<if test="fAgingEndTime == null">f_aging_end_time = null,</if>
</trim> </trim>
</update> </update>
...@@ -199,6 +208,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" ...@@ -199,6 +208,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<trim prefix="SET" suffixOverrides=","> <trim prefix="SET" suffixOverrides=",">
<if test="fStatus != null">f_status = #{fStatus},</if> <if test="fStatus != null">f_status = #{fStatus},</if>
<if test="fAgingStartTime == null">f_aging_start_time = null,</if> <if test="fAgingStartTime == null">f_aging_start_time = null,</if>
<if test="fAgingEndTime == null">f_aging_end_time = null,</if>
<if test="fUpdateTime != null">f_update_time = #{fUpdateTime},</if> <if test="fUpdateTime != null">f_update_time = #{fUpdateTime},</if>
</trim> </trim>
where f_storey_code = #{fStoreyCode} where f_storey_code = #{fStoreyCode}
......
...@@ -57,6 +57,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" ...@@ -57,6 +57,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<include refid="selectTTrayInfoVo"/> <include refid="selectTTrayInfoVo"/>
where f_tray_code = #{fTrayCode} where f_tray_code = #{fTrayCode}
</select> </select>
<select id="selectTTrayInfoByStoreyCode" parameterType="string" resultMap="TTrayInfoResult">
<include refid="selectTTrayInfoVo"/>
where f_storey_code = #{fStoreyCode}
</select>
<insert id="insertTTrayInfo" parameterType="TTrayInfo" useGeneratedKeys="true" keyProperty="fTrayId"> <insert id="insertTTrayInfo" parameterType="TTrayInfo" useGeneratedKeys="true" keyProperty="fTrayId">
insert into t_tray_info insert into t_tray_info
...@@ -90,6 +94,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" ...@@ -90,6 +94,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
set f_status = #{fStatus} set f_status = #{fStatus}
where f_storey_code = #{fStoreyCode} where f_storey_code = #{fStoreyCode}
</update> </update>
<update id="clearStoreyCodeByStoreyCode" parameterType="string">
update t_tray_info
set f_storey_code = null
where f_storey_code = #{fStoreyCode}
</update>
<update id="updateTTrayInfo" parameterType="TTrayInfo"> <update id="updateTTrayInfo" parameterType="TTrayInfo">
update t_tray_info update t_tray_info
<trim prefix="SET" suffixOverrides=","> <trim prefix="SET" suffixOverrides=",">
......
...@@ -34,7 +34,8 @@ ...@@ -34,7 +34,8 @@
'status-running': layer.fStatus === '1', 'status-running': layer.fStatus === '1',
'status-fault': layer.fStatus === '2', 'status-fault': layer.fStatus === '2',
'status-idle': layer.fStatus === '0', 'status-idle': layer.fStatus === '0',
'status-power_outage': layer.fStatus === '3' 'status-power_outage': layer.fStatus === '3',
'status-completed': layer.fStatus === '4' // 新增完成状态的样式类绑定
} }
]" ]"
@click="selectLayer(index)" @click="selectLayer(index)"
...@@ -128,6 +129,14 @@ export default { ...@@ -128,6 +129,14 @@ export default {
trayInfo: { trayInfo: {
deep: true, deep: true,
handler(newVal) { handler(newVal) {
// 状态为4(完成)时,停止计时器,保留当前时长
if (newVal.fStatus === '4') {
this.stopAgingTimer();
// 计算并显示固定时长
this.agingTimeDisplay = this.calcFixedAgingTime(newVal.fAgingStartTime, newVal.fAgingEndTime);
return;
}
if (newVal.fAgingStartTime) { if (newVal.fAgingStartTime) {
this.startAgingTimer(newVal.fAgingStartTime); this.startAgingTimer(newVal.fAgingStartTime);
} else { } else {
...@@ -162,6 +171,12 @@ export default { ...@@ -162,6 +171,12 @@ export default {
// 启动老化计时器 // 启动老化计时器
startAgingTimer(startTime) { startAgingTimer(startTime) {
// 状态为4(完成)时,直接返回不启动计时
if (this.trayInfo.fStatus === '4') return;
this.stopAgingTimer(); this.stopAgingTimer();
this.agingStartTime = new Date(startTime); this.agingStartTime = new Date(startTime);
...@@ -173,7 +188,20 @@ export default { ...@@ -173,7 +188,20 @@ export default {
this.updateAgingTime(); this.updateAgingTime();
}, 1000); }, 1000);
}, },
// 计算固定老化时长(fAgingEndTime - fAgingStartTime)
calcFixedAgingTime(startTime, endTime) {
if (!startTime || !endTime) return "00:00:00";
const start = new Date(startTime);
const end = new Date(endTime);
const diff = Math.floor((end - start) / 1000); // 秒数(确保非负)
const hours = Math.floor(diff / 3600);
const minutes = Math.floor((diff % 3600) / 60);
const seconds = diff % 60;
return `${this.padZero(hours)}:${this.padZero(minutes)}:${this.padZero(seconds)}`;
},
// 更新老化时间显示 // 更新老化时间显示
updateAgingTime() { updateAgingTime() {
if (!this.agingStartTime) return; if (!this.agingStartTime) return;
...@@ -213,12 +241,18 @@ export default { ...@@ -213,12 +241,18 @@ export default {
productModel: `PQC-${1000 + i}`, productModel: `PQC-${1000 + i}`,
status: this.getStatusText(item.fStatus), status: this.getStatusText(item.fStatus),
statusClass: this.getStatusClass(item.fStatus), statusClass: this.getStatusClass(item.fStatus),
fAgingStartTime: item.fAgingStartTime fAgingStartTime: item.fAgingStartTime,
fAgingEndTime: item.fAgingEndTime
})); }));
// 默认选中第一层 // 默认选中第一层
if (this.layers.length > 0) { if (this.layers.length > 0) {
this.selectLayer(0); this.selectLayer(0);
// 默认选中层为完成状态时,初始化固定时长
const firstLayer = this.layers[0];
if (firstLayer.fStatus === '4') {
this.agingTimeDisplay = this.calcFixedAgingTime(firstLayer.fAgingStartTime, firstLayer.fAgingEndTime);
}
} }
} else { } else {
this.$message.error("加载层数据失败"); this.$message.error("加载层数据失败");
...@@ -238,6 +272,14 @@ export default { ...@@ -238,6 +272,14 @@ export default {
// 选择层 // 选择层
selectLayer(index) { selectLayer(index) {
this.trayInfo = { ...this.layers[index] }; this.trayInfo = { ...this.layers[index] };
const currentLayer = this.layers[index];
// 状态为4(完成)时,计算固定时长
if (currentLayer.fStatus === '4') {
this.agingTimeDisplay = this.calcFixedAgingTime(currentLayer.fAgingStartTime, currentLayer.fAgingEndTime);
this.stopAgingTimer(); // 确保停止计时
}
}, },
// 操作按钮方法 // 操作按钮方法
...@@ -275,6 +317,7 @@ export default { ...@@ -275,6 +317,7 @@ export default {
case '1': return 'status-running'; case '1': return 'status-running';
case '2': return 'status-fault'; case '2': return 'status-fault';
case '3': return 'status-power_outage'; case '3': return 'status-power_outage';
case '4': return 'status-completed'; // 新增完成状态类名
default: return 'status-idle'; default: return 'status-idle';
} }
}, },
...@@ -286,6 +329,7 @@ export default { ...@@ -286,6 +329,7 @@ export default {
case '1': return '运行中'; case '1': return '运行中';
case '2': return '故障'; case '2': return '故障';
case '3': return '断电'; case '3': return '断电';
case '4': return '完成';
default: return '未知状态'; default: return '未知状态';
} }
}, },
...@@ -738,4 +782,35 @@ export default { ...@@ -738,4 +782,35 @@ export default {
color: #66b1ff; color: #66b1ff;
transform: translateX(-5px); transform: translateX(-5px);
} }
/* 层状态样式 - 完成 */
.status-completed {
/* 完成状态 - 青色 #409EFF */
color: #409EFF;
border: 1px solid rgba(64, 158, 255, 0.8);
box-shadow:
0 4px 12px rgba(0, 0, 0, 0.6),
inset 0 0 8px rgba(64, 158, 255, 0.5);
}
.status-completed.layer-depth {
border-width: 1px 3px 3px 1px;
border-color:
rgba(64, 158, 255, 0.4)
rgba(64, 158, 255, 0.8)
rgba(64, 158, 255, 0.8)
rgba(64, 158, 255, 0.4);
}
.status-completed:hover {
background: linear-gradient(to bottom, rgba(64, 158, 255, 0.2), rgba(0,0,0,0.3));
box-shadow:
0 4px 15px rgba(64, 158, 255, 0.4),
inset 0 0 10px rgba(64, 158, 255, 0.4);
}
/* 右侧信息区 - 完成状态文本样式 */
.info-value.status-completed {
color: #409EFF;
font-weight: bold;
}
</style> </style>
...@@ -42,7 +42,7 @@ ...@@ -42,7 +42,7 @@
<div class="status-bar"> <div class="status-bar">
<i class="fas fa-info-circle"></i> <i class="fas fa-info-circle"></i>
<span v-if="trayStatus === '0'">已绑定设备: <span class="filled-count">{{ filledCount }}</span>/72</span> <span v-if="trayStatus === '0'">已绑定设备: <span class="filled-count">{{ filledCount }}</span>/72</span>
<span v-if="trayStatus === '2'">待处理异常设备: <span class="filled-count">{{ abnormalCount }}</span>/{{ initialAbnormalCount }}</span> <span v-if="trayStatus === '3'">待处理异常设备: <span class="filled-count">{{ abnormalCount }}</span>/{{ initialAbnormalCount }}</span>
</div> </div>
</div> </div>
</div> </div>
...@@ -57,7 +57,7 @@ ...@@ -57,7 +57,7 @@
:class="{ :class="{
'active': activeCell === index, 'active': activeCell === index,
'empty': !device.deviceCode, 'empty': !device.deviceCode,
'error': device.deviceCode && device.status === '0' 'error': device.deviceCode && (device.status === '0' || device.status === '5')
}" }"
@click="setActiveCell(index)" @click="setActiveCell(index)"
> >
...@@ -87,7 +87,7 @@ ...@@ -87,7 +87,7 @@
:disabled="bindButtonDisabled" :disabled="bindButtonDisabled"
> >
<i class="fas fa-paper-plane"></i> <i class="fas fa-paper-plane"></i>
{{ trayStatus === '2' ? '提交修复' : '提交绑定' }} {{ trayStatus === '3' ? '提交修复' : '提交绑定' }}
</button> </button>
</div> </div>
...@@ -95,12 +95,12 @@ ...@@ -95,12 +95,12 @@
<div class="instructions"> <div class="instructions">
<h3><i class="fas fa-lightbulb"></i> 使用说明</h3> <h3><i class="fas fa-lightbulb"></i> 使用说明</h3>
<ul> <ul>
<li v-if="trayStatus === '0'">1. 点击矩阵中的单元格或按顺序扫描<span class="highlight">设备条码</span>(扫描枪自动识别)</li> <li v-if="trayStatus === '0'"> 点击矩阵中的单元格或按顺序扫描<span class="highlight">设备条码</span>(扫描枪自动识别)</li>
<li v-if="trayStatus === '0'">2. 设备条码会自动填充到当前激活的单元格中</li> <li v-if="trayStatus === '0'"> 设备条码会自动填充到当前激活的单元格中</li>
<li v-if="trayStatus === '2'">1. 请扫描异常设备条码进行修复处理</li> <li v-if="trayStatus === '3'"> 请扫描异常设备条码进行修复处理</li>
<li v-if="trayStatus === '2'">2. 每修复一个异常设备,待处理数量将减少</li> <li v-if="trayStatus === '3'"> 每修复一个异常设备,待处理数量将减少</li>
<li>3. 可以手动点击任何单元格进行修改或重新扫描</li> <li> 可以手动点击任何单元格进行修改或重新扫描</li>
<li>4. 完成操作后,点击<span class="highlight">{{ trayStatus === '2' ? '提交修复' : '提交绑定' }}</span>按钮</li> <li> 完成操作后,点击<span class="highlight">{{ trayStatus === '3' ? '提交修复' : '提交绑定' }}</span>按钮</li>
<li><i class="fas fa-bolt scanner-icon"></i> 提示:使用扫描枪时,请确保输入框获得焦点</li> <li><i class="fas fa-bolt scanner-icon"></i> 提示:使用扫描枪时,请确保输入框获得焦点</li>
</ul> </ul>
</div> </div>
...@@ -158,7 +158,7 @@ export default { ...@@ -158,7 +158,7 @@ export default {
trayInput: '', trayInput: '',
// 托盘状态 // 托盘状态
trayStatus: '0', // 0:空闲, 1:运行中, 2:标检完成 trayStatus: '0', // 0:空闲, 1:运行中, 2:老化完成,3:标定完成
// 异常设备计数 // 异常设备计数
abnormalCount: 0, abnormalCount: 0,
...@@ -191,7 +191,7 @@ export default { ...@@ -191,7 +191,7 @@ export default {
bindButtonDisabled() { bindButtonDisabled() {
if (this.trayStatus === '0') { if (this.trayStatus === '0') {
return this.filledCount === 0 || !this.fTrayCode; return this.filledCount === 0 || !this.fTrayCode;
} else if (this.trayStatus === '2') { } else if (this.trayStatus === '3') {
return this.abnormalCount > 0; return this.abnormalCount > 0;
} }
return true; return true;
...@@ -202,7 +202,8 @@ export default { ...@@ -202,7 +202,8 @@ export default {
const map = { const map = {
'0': 'success', // 空闲 - 绿色 '0': 'success', // 空闲 - 绿色
'1': 'warning', // 运行中 - 黄色 '1': 'warning', // 运行中 - 黄色
'2': 'danger' // 标检完成 - 红色 '2': 'danger', // 老化完成 - 红色
'3': 'primary' // 标定完成
}; };
return map[this.trayStatus] || 'info'; return map[this.trayStatus] || 'info';
}, },
...@@ -212,14 +213,15 @@ export default { ...@@ -212,14 +213,15 @@ export default {
const map = { const map = {
'0': '空闲', '0': '空闲',
'1': '运行中', '1': '运行中',
'2': '标检完成' '2': '老化完成',
'3': '标定完成'
}; };
return map[this.trayStatus] || '未知状态'; return map[this.trayStatus] || '未知状态';
}, },
// 扫描输入框提示语 // 扫描输入框提示语
scanPlaceholder() { scanPlaceholder() {
return this.trayStatus === '2' return this.trayStatus === '3'
? '扫描异常设备条码...' ? '扫描异常设备条码...'
: '扫描设备条码...'; : '扫描设备条码...';
} }
...@@ -234,10 +236,10 @@ export default { ...@@ -234,10 +236,10 @@ export default {
if(res.code === 200 && res.data.length > 0) { if(res.code === 200 && res.data.length > 0) {
this.devices = res.data; this.devices = res.data;
// 计算初始异常设备数量(标完成状态) // 计算初始异常设备数量(标完成状态)
if (this.trayStatus === '2') { if (this.trayStatus === '3') {
this.abnormalCount = this.devices.filter( this.abnormalCount = this.devices.filter(
d => d.deviceCode && d.fstatus != '1' d => d.deviceCode && d.status !== '1'
).length; ).length;
this.initialAbnormalCount = this.abnormalCount; this.initialAbnormalCount = this.abnormalCount;
} }
...@@ -298,11 +300,11 @@ export default { ...@@ -298,11 +300,11 @@ export default {
if (this.deviceInput) { if (this.deviceInput) {
// 标完成状态下的特殊处理 // 标完成状态下的特殊处理
if (this.trayStatus === '2') { if (this.trayStatus === '3') {
// 检查扫描的设备是否是异常设备 // 检查扫描的设备是否是异常设备
const deviceIndex = this.devices.findIndex( const deviceIndex = this.devices.findIndex(
d => d.deviceCode === this.deviceInput && d.status === '0' d => d.deviceCode === this.deviceInput && (d.status === '0' || d.status === '5')
); );
if (deviceIndex !== -1) { if (deviceIndex !== -1) {
...@@ -370,8 +372,8 @@ export default { ...@@ -370,8 +372,8 @@ export default {
}) })
} }
} }
} else if (this.trayStatus === '2') { } else if (this.trayStatus === '3') {
// 标完成状态 - 提交修复 // 标完成状态 - 提交修复
batchUpdateDeviceCode(this.devices).then(res => { batchUpdateDeviceCode(this.devices).then(res => {
if (res.code === 200) { if (res.code === 200) {
this.msgSuccess("修复信息提交成功"); this.msgSuccess("修复信息提交成功");
......
...@@ -51,7 +51,8 @@ ...@@ -51,7 +51,8 @@
<el-table-column prop="status" label="状态" align="center"> <el-table-column prop="status" label="状态" align="center">
<template slot-scope="scope"> <template slot-scope="scope">
<el-tag :type="statusTagType(scope.row.fStatus)" v-if="scope.row.fStatus === '1'" class="status-tag">运行中</el-tag> <el-tag :type="statusTagType(scope.row.fStatus)" v-if="scope.row.fStatus === '1'" class="status-tag">运行中</el-tag>
<el-tag :type="statusTagType(scope.row.fStatus)" v-else-if="scope.row.fStatus === '2'" class="status-tag">质检完成</el-tag> <el-tag :type="statusTagType(scope.row.fStatus)" v-else-if="scope.row.fStatus === '2'" class="status-tag">老化完成</el-tag>
<el-tag :type="statusTagType(scope.row.fStatus)" v-else-if="scope.row.fStatus === '3'" class="status-tag">标定完成</el-tag>
<el-tag :type="statusTagType(scope.row.fStatus)" v-else class="status-tag">空闲</el-tag> <el-tag :type="statusTagType(scope.row.fStatus)" v-else class="status-tag">空闲</el-tag>
</template> </template>
</el-table-column> </el-table-column>
...@@ -177,6 +178,7 @@ export default { ...@@ -177,6 +178,7 @@ export default {
const statusMap = { const statusMap = {
'0': 'success', '0': 'success',
'2': 'warning', '2': 'warning',
'3': 'warning',
'1': 'primary', '1': 'primary',
}; };
return statusMap[status] || 'info'; return statusMap[status] || 'info';
......
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