Commit ec6ffe29 authored by wanghao's avatar wanghao

1 上料必须是 绑定状态。

2 解绑时 必须解绑 异常的后才能 一键解绑 托盘状态。
3 上传MES 后 先不删除历史数据。
4  历史界面 导出功能。 根据  托盘号,设备号
5 增加一个任务 去执行 继电器状态,脉冲状态,模组状态,SIM卡状态,网络状态 这几个状态的 单独读 以及 写,科强说网络需要监控两次。
6 继电器状态,脉冲状态,模组状态,SIM卡状态,网络状态 涉及到的 校验 以及记录都放开了,待联调。
parent 3d775b4d
...@@ -23,4 +23,9 @@ public class RoboticArmConstans { ...@@ -23,4 +23,9 @@ public class RoboticArmConstans {
* 老化流程第三阶段执行时间(单位:分钟) * 老化流程第三阶段执行时间(单位:分钟)
*/ */
public static final String AGING_STAGE3_TIME = "agingStage3Time"; public static final String AGING_STAGE3_TIME = "agingStage3Time";
/**
* 老化流程第四阶段执行时间(单位:分钟)
*/
public static final String AGING_STAGE4_TIME = "agingStage4Time";
} }
...@@ -22,14 +22,14 @@ public class PalletDeviceUploadHistory extends BaseEntity ...@@ -22,14 +22,14 @@ public class PalletDeviceUploadHistory extends BaseEntity
private Long id; private Long id;
/** 托盘id */ /** 托盘id */
@Excel(name = "托盘id")
private Long trayId; private Long trayId;
/** 托盘编号 */ /** 托盘编号 */
@Excel(name = "托盘编号")
private String trayCode; private String trayCode;
/** 绑定的设备编号 */ /** 绑定的设备编号 */
@Excel(name = "绑定的设备编号") @Excel(name = "设备编号")
private String deviceCode; private String deviceCode;
/** 行 */ /** 行 */
...@@ -59,7 +59,7 @@ public class PalletDeviceUploadHistory extends BaseEntity ...@@ -59,7 +59,7 @@ public class PalletDeviceUploadHistory extends BaseEntity
private Date unbindingTime; private Date unbindingTime;
/** 0-预热;1-正常;3-传感器故障;4-报警;5-通讯故障 */ /** 0-预热;1-正常;3-传感器故障;4-报警;5-通讯故障 */
@Excel(name = "0-预热;1-正常;3-传感器故障;4-报警;5-通讯故障") @Excel(name = "状态")
private String status; private String status;
/** 设置-年 */ /** 设置-年 */
...@@ -91,7 +91,7 @@ public class PalletDeviceUploadHistory extends BaseEntity ...@@ -91,7 +91,7 @@ public class PalletDeviceUploadHistory extends BaseEntity
private String adjustmentZeroAd; private String adjustmentZeroAd;
/** 合格;不合格 */ /** 合格;不合格 */
@Excel(name = "合格;不合格") @Excel(name = "调零状态")
private String zeroStatus; private String zeroStatus;
/** 标定AD */ /** 标定AD */
...@@ -99,7 +99,7 @@ public class PalletDeviceUploadHistory extends BaseEntity ...@@ -99,7 +99,7 @@ public class PalletDeviceUploadHistory extends BaseEntity
private String calibrationAd; private String calibrationAd;
/** 合格;不合格 */ /** 合格;不合格 */
@Excel(name = "合格;不合格") @Excel(name = "标定状态0-不合格;1-合格")
private String calibrationStatus; private String calibrationStatus;
/** 浓度值 */ /** 浓度值 */
...@@ -115,48 +115,56 @@ public class PalletDeviceUploadHistory extends BaseEntity ...@@ -115,48 +115,56 @@ public class PalletDeviceUploadHistory extends BaseEntity
private Integer realTimeAd; private Integer realTimeAd;
/** 实时AD状态;0-异常;1-正常 */ /** 实时AD状态;0-异常;1-正常 */
@Excel(name = "实时AD状态;0-异常;1-正常") @Excel(name = "实时AD状态;0-异常;1-正常 ")
private String realTimeAdStatus; private String realTimeAdStatus;
/** /**
* 传感器校准浓度 * 传感器校准浓度
*/ */
@Excel(name = "校准浓度")
private BigDecimal calibrationConcentration; private BigDecimal calibrationConcentration;
/** /**
* 传感器校准状态 4-正常,其他都是异常 * 传感器校准状态 4-正常,其他都是异常
* 0-预热;1-正常;3-传感器故障;4-报警;5-通讯故障; 只有是4的时候显示正常,其他的都是异常 * 0-预热;1-正常;3-传感器故障;4-报警;5-通讯故障; 只有是4的时候显示正常,其他的都是异常
*/ */
@Excel(name = "校准浓度状态;0-预热;1-正常;3-传感器故障;4-报警;5-通讯故障; 只有是4的时候显示正常")
private String calibrationConcentrationStatus; private String calibrationConcentrationStatus;
/** /**
* 写自检状态 空 是没写 0-失败;1-成功 * 写自检状态 空 是没写 0-失败;1-成功
*/ */
@Excel(name = "写自检状态;0-失败;1-成功")
private Integer writeSelfCheckStatus; private Integer writeSelfCheckStatus;
/** /**
* 继电器状态 0:初始 1:动作 * 继电器状态 0:初始 1:动作
*/ */
@Excel(name = "继电器状态;0:初始 1:动作")
private Integer relayStatus; private Integer relayStatus;
/** /**
* 脉冲状态 0:初始 1:动作 * 脉冲状态 0:初始 1:动作
*/ */
@Excel(name = "脉冲状态;0:初始 1:动作")
private Integer pulseStatus; private Integer pulseStatus;
/** /**
* 模块状态 0:异常 1:正常 * 模块状态 0:异常 1:正常
*/ */
@Excel(name = "模块状态;0:异常 1:正常")
private Integer moduleStatus; private Integer moduleStatus;
/** /**
* SIM卡状态 0:异常 1:正常 * SIM卡状态 0:异常 1:正常
*/ */
@Excel(name = "SIM卡状态;0:异常 1:正常")
private Integer simCardStatus; private Integer simCardStatus;
/** /**
* 网络状态 0:异常 1:正常 * 网络状态 0:异常 1:正常
*/ */
@Excel(name = "网络状态;0:异常 1:正常")
private Integer networkStatus; private Integer networkStatus;
public void setId(Long id) public void setId(Long id)
{ {
......
...@@ -137,14 +137,16 @@ public class CalibrationResultEventHandler { ...@@ -137,14 +137,16 @@ public class CalibrationResultEventHandler {
uploadMesResultHistoryService.insertUploadMesResultHistory(uploadMesResultHistory); uploadMesResultHistoryService.insertUploadMesResultHistory(uploadMesResultHistory);
if(StringUtils.isNotBlank(result)) { if(StringUtils.isNotBlank(result)) {
JSONObject jsonObject = JSON.parseObject(result); JSONObject jsonObject = JSON.parseObject(result);
if(jsonObject.getInteger("code") != 200) { // if(jsonObject.getInteger("code") != 200) {
String data = jsonObject.getString("data"); // String data = jsonObject.getString("data");
if(StringUtils.isNotBlank(data)) { // if(StringUtils.isNotBlank(data)) {
processPalletDeviceUploadHistory(palletDeviceBindings,data); // processPalletDeviceUploadHistory(palletDeviceBindings,data);
} else { // } else {
directProcessPaalletDeviceUploadHistory(palletDeviceBindings); // directProcessPaalletDeviceUploadHistory(palletDeviceBindings);
} // }
} // }
// 20251210 领导说 先 保存所有历史数据
directProcessPaalletDeviceUploadHistory(palletDeviceBindings);
} else { } else {
directProcessPaalletDeviceUploadHistory(palletDeviceBindings); directProcessPaalletDeviceUploadHistory(palletDeviceBindings);
} }
......
...@@ -501,9 +501,10 @@ public class RobotArmCommandServiceImpl implements IRobotArmCommandService ...@@ -501,9 +501,10 @@ public class RobotArmCommandServiceImpl implements IRobotArmCommandService
} }
// 20251104 上料 不需要看托盘状态了 // 20251104 上料 不需要看托盘状态了
// if(!"0".equals(tTrayInfo.getfStatus())) { // 20251210 上料 又需要看托盘状态了
// throw new RuntimeException("托盘未解绑,请联系管理员"); if(!"4".equals(tTrayInfo.getfStatus())) {
// } throw new RuntimeException("托盘状态异常,请联系管理员");
}
TStoreyInfo tStoreyInfo = storeyInfoMapper.selectNearestFreeStorey(); TStoreyInfo tStoreyInfo = storeyInfoMapper.selectNearestFreeStorey();
if(tStoreyInfo != null) { if(tStoreyInfo != null) {
......
package com.zehong.system.task; package com.zehong.system.task;
import com.serotonin.modbus4j.ModbusFactory;
import com.serotonin.modbus4j.ModbusMaster; import com.serotonin.modbus4j.ModbusMaster;
import com.serotonin.modbus4j.exception.ModbusInitException; import com.serotonin.modbus4j.exception.ModbusInitException;
import com.serotonin.modbus4j.exception.ModbusTransportException; import com.serotonin.modbus4j.exception.ModbusTransportException;
...@@ -22,7 +21,6 @@ import org.slf4j.LoggerFactory; ...@@ -22,7 +21,6 @@ import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.Arrays;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.concurrent.*; import java.util.concurrent.*;
...@@ -35,8 +33,8 @@ import java.util.stream.Collectors; ...@@ -35,8 +33,8 @@ import java.util.stream.Collectors;
* @description 老化最终执行任务 * @description 老化最终执行任务
*/ */
@Component @Component
public class FinalExecutionJob implements Job { public class AgingStageFourProcessJob implements Job {
private static final Logger log = LoggerFactory.getLogger(FinalExecutionJob.class); private static final Logger log = LoggerFactory.getLogger(AgingStageFourProcessJob.class);
// -------------------------- 常量配置(统一管理,避免魔法值)-------------------------- // -------------------------- 常量配置(统一管理,避免魔法值)--------------------------
// 超时控制:必须小于Cron周期(假设Cron为5分钟,这里留1分钟缓冲) // 超时控制:必须小于Cron周期(假设Cron为5分钟,这里留1分钟缓冲)
......
...@@ -31,8 +31,8 @@ import java.util.stream.Collectors; ...@@ -31,8 +31,8 @@ import java.util.stream.Collectors;
*/ */
@Component @Component
@DisallowConcurrentExecution // 禁止同一任务并行执行(必须保留) @DisallowConcurrentExecution // 禁止同一任务并行执行(必须保留)
public class DeviceCommunicationJob implements Job { public class AgingStageOneProcessJob implements Job {
private static final Logger log = LoggerFactory.getLogger(DeviceCommunicationJob.class); private static final Logger log = LoggerFactory.getLogger(AgingStageOneProcessJob.class);
// -------------------------- 常量配置(统一管理,避免魔法值)-------------------------- // -------------------------- 常量配置(统一管理,避免魔法值)--------------------------
// 超时控制:必须小于Cron周期(假设Cron为5分钟,这里留1分钟缓冲) // 超时控制:必须小于Cron周期(假设Cron为5分钟,这里留1分钟缓冲)
...@@ -157,16 +157,18 @@ public class DeviceCommunicationJob implements Job { ...@@ -157,16 +157,18 @@ public class DeviceCommunicationJob implements Job {
// 3. 更新浓度值 // 3. 更新浓度值
binding.setConcentration(String.valueOf(result[0])); binding.setConcentration(String.valueOf(result[0]));
// 重用之前的master连接进行写操作
master = Modbus4jUtils.createModbusMaster(ip, port);
// 4. 条件写入时间 // 4. 条件写入时间
if (result[1] == 1 || result[1] == 3 || result[1] == 4) { if (result[1] == 1 || result[1] == 3 || result[1] == 4) {
// 重用之前的master连接进行写操作
master = Modbus4jUtils.createModbusMaster(ip, port);
writeCurrentTimeToDevice(master, deviceId, binding); writeCurrentTimeToDevice(master, deviceId, binding);
} }
// 5. 写入自检让设备开始自检,跟 上面的状态没关系
writeSelfCheckStatus(master, deviceId, binding);
binding.setWriteTimeStatus("1"); binding.setWriteTimeStatus("1");
// 5. 更新数据库 // 6. 更新数据库
palletDeviceBindingMapper.updatePalletDeviceBinding(binding); palletDeviceBindingMapper.updatePalletDeviceBinding(binding);
log.debug("设备{}处理完成: ip={}, port={}, status={}", deviceId, ip, port, result[1]); log.debug("设备{}处理完成: ip={}, port={}, status={}", deviceId, ip, port, result[1]);
...@@ -214,6 +216,20 @@ public class DeviceCommunicationJob implements Job { ...@@ -214,6 +216,20 @@ public class DeviceCommunicationJob implements Job {
} }
} }
/**
* 写入自检状态 让设备开始自检
*/
private void writeSelfCheckStatus(ModbusMaster master, int deviceId,
PalletDeviceBinding binding){
// 20251206 写完时间写自检,写自检就在时间后边写就行,不管时间写不写成功
try {
Modbus4jUtils.writeRegister(master, deviceId, 15, (short) 1);
binding.setWriteSelfCheckStatus(1);
} catch (Exception e) {
binding.setWriteSelfCheckStatus(0);
}
}
/** /**
* 写入当前时间到设备 * 写入当前时间到设备
*/ */
...@@ -251,15 +267,6 @@ public class DeviceCommunicationJob implements Job { ...@@ -251,15 +267,6 @@ public class DeviceCommunicationJob implements Job {
log.error("设备{}时间写入异常", deviceId, e); log.error("设备{}时间写入异常", deviceId, e);
recordAlarmByBinding(binding, "设备时间写入异常: " + e.getMessage()); recordAlarmByBinding(binding, "设备时间写入异常: " + e.getMessage());
} }
// 20251206 写完时间写自检,写自检就在时间后边写就行,不管时间写不写成功
try {
Modbus4jUtils.writeRegister(master, deviceId, 15, (short) 1);
binding.setWriteSelfCheckStatus(1);
} catch (Exception e) {
binding.setWriteSelfCheckStatus(0);
}
} }
// -------------------------- 辅助方法(日志/告警)-------------------------- // -------------------------- 辅助方法(日志/告警)--------------------------
......
...@@ -36,8 +36,8 @@ import java.util.stream.Collectors; ...@@ -36,8 +36,8 @@ import java.util.stream.Collectors;
*/ */
@Component @Component
@DisallowConcurrentExecution // 禁止同一任务并行执行(必须保留) @DisallowConcurrentExecution // 禁止同一任务并行执行(必须保留)
public class PrepareFinalExecutionJob implements Job { public class AgingStageThreeProcessJob implements Job {
private static final Logger log = LoggerFactory.getLogger(DeviceCommunicationJob.class); private static final Logger log = LoggerFactory.getLogger(AgingStageThreeProcessJob.class);
// -------------------------- 常量配置(统一管理,避免魔法值)-------------------------- // -------------------------- 常量配置(统一管理,避免魔法值)--------------------------
// 超时控制:必须小于Cron周期(假设Cron为5分钟,这里留1分钟缓冲) // 超时控制:必须小于Cron周期(假设Cron为5分钟,这里留1分钟缓冲)
...@@ -190,6 +190,23 @@ public class PrepareFinalExecutionJob implements Job { ...@@ -190,6 +190,23 @@ public class PrepareFinalExecutionJob implements Job {
binding.setStatus(result[1] +""); binding.setStatus(result[1] +"");
} }
// 处理 继电器状态,脉冲状态,模组状态,SIM卡状态,网络状态
if(result[10] == 1){
binding.setRelayStatus(1);
}
if(result[11] == 1){
binding.setPulseStatus(1);
}
if(result[12] == 1){
binding.setModuleStatus(1);
}
if(result[13] == 1){
binding.setSimCardStatus(1);
}
if(result[14] == 1){
binding.setNetworkStatus(1);
}
// 5. 更新数据库 // 5. 更新数据库
palletDeviceBindingMapper.updatePalletDeviceBinding(binding); palletDeviceBindingMapper.updatePalletDeviceBinding(binding);
......
...@@ -9,7 +9,6 @@ import com.zehong.system.task.DeviceCommJob.DeviceComm501Device2Job; ...@@ -9,7 +9,6 @@ import com.zehong.system.task.DeviceCommJob.DeviceComm501Device2Job;
import com.zehong.system.task.DeviceCommJob.DeviceComm501Device3Job; import com.zehong.system.task.DeviceCommJob.DeviceComm501Device3Job;
import org.quartz.*; import org.quartz.*;
import org.quartz.impl.matchers.GroupMatcher; import org.quartz.impl.matchers.GroupMatcher;
import org.quartz.utils.Key;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
...@@ -19,9 +18,7 @@ import javax.annotation.Resource; ...@@ -19,9 +18,7 @@ import javax.annotation.Resource;
import java.time.Instant; import java.time.Instant;
import java.time.temporal.ChronoUnit; import java.time.temporal.ChronoUnit;
import java.util.Date; import java.util.Date;
import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors;
/** /**
* @author lenovo * @author lenovo
...@@ -74,6 +71,9 @@ public class DeviceTaskScheduler { ...@@ -74,6 +71,9 @@ public class DeviceTaskScheduler {
// 3. 创建5分钟开始读写时间的job // 3. 创建5分钟开始读写时间的job
createHourlyCommunicationJob(fStoreyId); createHourlyCommunicationJob(fStoreyId);
// 4. 增加一个阶段 去处理 脉冲状态,模组状态,SIM卡状态,网络状态
createTworPortCommJobs(fStoreyId);
// 4. 创建71小时 执行的任务 // 4. 创建71小时 执行的任务
prepareFinalExecutionJob(fStoreyId); prepareFinalExecutionJob(fStoreyId);
// 5. 创建72小时 最终任务 // 5. 创建72小时 最终任务
...@@ -223,6 +223,54 @@ public class DeviceTaskScheduler { ...@@ -223,6 +223,54 @@ public class DeviceTaskScheduler {
port, jobId, delayMin, nextFireTime); port, jobId, delayMin, nextFireTime);
} }
/**
* 创建第二阶段任务
* @param fStoreyId 设备ID
*/
private void createTworPortCommJobs(Long fStoreyId) throws SchedulerException {
String jobId = "TWO_" + fStoreyId;
JobKey jobKey = new JobKey(jobId, JOB_GROUP);
TriggerKey triggerKey = new TriggerKey(jobId + "_TRIGGER", TRIGGER_GROUP);
// 先删除旧的触发器和任务(彻底清理)
if (scheduler.checkExists(triggerKey)) {
scheduler.unscheduleJob(triggerKey);
}
if (scheduler.checkExists(jobKey)) {
scheduler.deleteJob(jobKey);
}
JobDetail job = JobBuilder.newJob(AgingStageOneProcessJob.class)
.withIdentity(jobKey)
.usingJobData("fStoreyId", fStoreyId.toString())
.storeDurably(false)
.build();
String s = sysConfigService.directSelectConfigByKey(RoboticArmConstans.AGING_STAGE2_TIME);
int delayMin = 0;
if(StringUtils.isNotBlank(s)) {
delayMin = Integer.parseInt(s);
}
if(delayMin == 0) {
delayMin = 10;
}
Date executeTime = Date.from(Instant.now().plus(delayMin, ChronoUnit.MINUTES));
// 关键修复:使用StartAt而不是StartNow
SimpleTrigger trigger = TriggerBuilder.newTrigger()
.withIdentity(triggerKey)
.forJob(jobKey)
.withDescription("设备" + fStoreyId + "第二阶段触发器,触发时间是:" + executeTime)
.startAt(executeTime)
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withMisfireHandlingInstructionFireNow() // 错过立即执行
.withRepeatCount(0)) // 仅一次
.build();
Date nextFireTime = scheduler.scheduleJob(job, trigger);
log.info("通信任务[{}]创建成功,下次执行:{}", jobId, nextFireTime);
}
/** /**
* 1. 创建每5分钟执行的通信任务(核心优化:简化调度逻辑、调整Misfire策略) * 1. 创建每5分钟执行的通信任务(核心优化:简化调度逻辑、调整Misfire策略)
*/ */
...@@ -239,7 +287,7 @@ public class DeviceTaskScheduler { ...@@ -239,7 +287,7 @@ public class DeviceTaskScheduler {
scheduler.deleteJob(jobKey); scheduler.deleteJob(jobKey);
} }
JobDetail job = JobBuilder.newJob(DeviceCommunicationJob.class) JobDetail job = JobBuilder.newJob(AgingStageOneProcessJob.class)
.withIdentity(jobKey) .withIdentity(jobKey)
.usingJobData("fStoreyId", fStoreyId.toString()) .usingJobData("fStoreyId", fStoreyId.toString())
.storeDurably(false) .storeDurably(false)
...@@ -259,20 +307,12 @@ public class DeviceTaskScheduler { ...@@ -259,20 +307,12 @@ public class DeviceTaskScheduler {
SimpleTrigger trigger = TriggerBuilder.newTrigger() SimpleTrigger trigger = TriggerBuilder.newTrigger()
.withIdentity(triggerKey) .withIdentity(triggerKey)
.forJob(jobKey) .forJob(jobKey)
.withDescription("设备" + fStoreyId + "最终任务触发器,触发时间是:" + executeTime) .withDescription("设备" + fStoreyId + "第一阶段触发器,触发时间是:" + executeTime)
.startAt(executeTime) .startAt(executeTime)
.withSchedule(SimpleScheduleBuilder.simpleSchedule() .withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withMisfireHandlingInstructionFireNow() // 错过立即执行 .withMisfireHandlingInstructionFireNow() // 错过立即执行
.withRepeatCount(0)) // 仅一次 .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);
...@@ -295,19 +335,19 @@ public class DeviceTaskScheduler { ...@@ -295,19 +335,19 @@ public class DeviceTaskScheduler {
scheduler.deleteJob(jobKey); scheduler.deleteJob(jobKey);
} }
JobDetail job = JobBuilder.newJob(PrepareFinalExecutionJob.class) JobDetail job = JobBuilder.newJob(AgingStageThreeProcessJob.class)
.withIdentity(jobKey) .withIdentity(jobKey)
.usingJobData("fStoreyId", fStoreyId.toString()) .usingJobData("fStoreyId", fStoreyId.toString())
.storeDurably(false) .storeDurably(false)
.build(); .build();
String s = sysConfigService.directSelectConfigByKey(RoboticArmConstans.AGING_STAGE2_TIME); String s = sysConfigService.directSelectConfigByKey(RoboticArmConstans.AGING_STAGE3_TIME);
int delayMin = 0; int delayMin = 0;
if(StringUtils.isNotBlank(s)) { if(StringUtils.isNotBlank(s)) {
delayMin = Integer.parseInt(s); delayMin = Integer.parseInt(s);
} }
if(delayMin == 0) { if(delayMin == 0) {
delayMin = 10; delayMin = 15;
} }
Date executeTime = Date.from(Instant.now().plus(delayMin, ChronoUnit.MINUTES)); Date executeTime = Date.from(Instant.now().plus(delayMin, ChronoUnit.MINUTES));
...@@ -315,7 +355,7 @@ public class DeviceTaskScheduler { ...@@ -315,7 +355,7 @@ public class DeviceTaskScheduler {
SimpleTrigger trigger = TriggerBuilder.newTrigger() SimpleTrigger trigger = TriggerBuilder.newTrigger()
.withIdentity(triggerKey) .withIdentity(triggerKey)
.forJob(jobKey) .forJob(jobKey)
.withDescription("设备" + fStoreyId + "最终任务触发器,触发时间是:" + executeTime) .withDescription("设备" + fStoreyId + "第三阶段触发器,触发时间是:" + executeTime)
.startAt(executeTime) .startAt(executeTime)
.withSchedule(SimpleScheduleBuilder.simpleSchedule() .withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withMisfireHandlingInstructionFireNow() // 错过立即执行 .withMisfireHandlingInstructionFireNow() // 错过立即执行
...@@ -327,14 +367,14 @@ public class DeviceTaskScheduler { ...@@ -327,14 +367,14 @@ public class DeviceTaskScheduler {
} }
/** /**
* 2. 创建15分钟后执行的最终任务(保持原逻辑,优化超时) * 2. 创建20分钟后执行的最终任务(保持原逻辑,优化超时)
*/ */
private void createFinalExecutionJob(Long fStoreyId, String fPowerOutageIp, Integer fPowerOutagePort) throws SchedulerException { private void createFinalExecutionJob(Long fStoreyId, String fPowerOutageIp, Integer fPowerOutagePort) throws SchedulerException {
String jobId = "FINAL_" + fStoreyId; String jobId = "FINAL_" + fStoreyId;
JobKey jobKey = new JobKey(jobId, JOB_GROUP); JobKey jobKey = new JobKey(jobId, JOB_GROUP);
TriggerKey triggerKey = new TriggerKey(jobId + "_TRIGGER", TRIGGER_GROUP); TriggerKey triggerKey = new TriggerKey(jobId + "_TRIGGER", TRIGGER_GROUP);
JobDetail job = JobBuilder.newJob(FinalExecutionJob.class) JobDetail job = JobBuilder.newJob(AgingStageFourProcessJob.class)
.withIdentity(jobKey) .withIdentity(jobKey)
.withDescription("设备" + fStoreyId + "最终执行任务(仅一次)") .withDescription("设备" + fStoreyId + "最终执行任务(仅一次)")
.usingJobData("fStoreyId", fStoreyId.toString()) .usingJobData("fStoreyId", fStoreyId.toString())
...@@ -344,13 +384,13 @@ public class DeviceTaskScheduler { ...@@ -344,13 +384,13 @@ public class DeviceTaskScheduler {
.requestRecovery(true) .requestRecovery(true)
.build(); .build();
String s = sysConfigService.directSelectConfigByKey(RoboticArmConstans.AGING_STAGE3_TIME); String s = sysConfigService.directSelectConfigByKey(RoboticArmConstans.AGING_STAGE4_TIME);
int delayMin = 0; int delayMin = 0;
if(StringUtils.isNotBlank(s)) { if(StringUtils.isNotBlank(s)) {
delayMin = Integer.parseInt(s); delayMin = Integer.parseInt(s);
} }
if(delayMin == 0) { if(delayMin == 0) {
delayMin = 15; delayMin = 20;
} }
Date executeTime = Date.from(Instant.now().plus(delayMin, ChronoUnit.MINUTES)); Date executeTime = Date.from(Instant.now().plus(delayMin, ChronoUnit.MINUTES));
SimpleTrigger trigger = TriggerBuilder.newTrigger() SimpleTrigger trigger = TriggerBuilder.newTrigger()
......
...@@ -84,7 +84,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" ...@@ -84,7 +84,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<select id="selectPalletDeviceUploadHistoryList" parameterType="PalletDeviceUploadHistory" resultMap="PalletDeviceUploadHistoryResult"> <select id="selectPalletDeviceUploadHistoryList" parameterType="PalletDeviceUploadHistory" resultMap="PalletDeviceUploadHistoryResult">
<include refid="selectPalletDeviceUploadHistoryVo"/> <include refid="selectPalletDeviceUploadHistoryVo"/>
<where> <where>
<if test="deviceCode != null and deviceCode != ''"> and palDeviceBinding.f_device_code = #{deviceCode}</if> <if test="deviceCode != null and deviceCode != ''"> and palDeviceBinding.f_device_code like concat('%',#{deviceCode},'%') </if>
<if test="trayCode != null and trayCode != ''"> and trayInfo.f_tray_code like concat('%',#{trayCode},'%') </if>
</where> </where>
</select> </select>
......
...@@ -39,7 +39,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" ...@@ -39,7 +39,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</select> </select>
<select id="selectAgingStageTime" resultMap="SysConfigResult"> <select id="selectAgingStageTime" resultMap="SysConfigResult">
<include refid="selectConfigVo"/> <include refid="selectConfigVo"/>
where config_key in ('agingStage1Time','agingStage2Time','agingStage3Time') where config_key in ('agingStage1Time','agingStage2Time','agingStage3Time','agingStage4Time')
</select> </select>
<select id="selectConfigList" parameterType="SysConfig" resultMap="SysConfigResult"> <select id="selectConfigList" parameterType="SysConfig" resultMap="SysConfigResult">
<include refid="selectConfigVo"/> <include refid="selectConfigVo"/>
......
...@@ -10,6 +10,15 @@ ...@@ -10,6 +10,15 @@
@keyup.enter.native="handleQuery" @keyup.enter.native="handleQuery"
/> />
</el-form-item> </el-form-item>
<el-form-item label="托盘编号" prop="trayCode">
<el-input
v-model="queryParams.trayCode"
placeholder="请输入托盘编号"
clearable
size="small"
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item> <el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button> <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button> <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
...@@ -322,6 +331,7 @@ export default { ...@@ -322,6 +331,7 @@ export default {
pageSize: 10, pageSize: 10,
trayId: null, trayId: null,
deviceCode: null, deviceCode: null,
trayCode: null,
row: null, row: null,
col: null, col: null,
index: null, index: null,
...@@ -435,10 +445,6 @@ export default { ...@@ -435,10 +445,6 @@ export default {
this.ids = selection.map(item => item.id) this.ids = selection.map(item => item.id)
this.single = selection.length!==1 this.single = selection.length!==1
this.multiple = !selection.length this.multiple = !selection.length
},
//单个设备重新上传
handleSingleUpload(row) {
}, },
/** 新增按钮操作 */ /** 新增按钮操作 */
handleAdd() { handleAdd() {
......
...@@ -34,10 +34,11 @@ ...@@ -34,10 +34,11 @@
</div> </div>
<!-- 设备扫描区域 --> <!-- 设备扫描区域 -->
<!-- 调整点1: 修改扫描区域的显示条件 -->
<div <div
class="scan-section" class="scan-section"
style="align-items: center;" style="align-items: center;"
v-show="trayStatus !== '1' && trayStatus !== '2'" v-show="trayStatus !== '1' && trayStatus !== '2' && !(trayStatus === '3' && abnormalCount === 0)"
> >
<input <input
type="text" type="text"
...@@ -46,12 +47,18 @@ ...@@ -46,12 +47,18 @@
v-model="deviceInput" v-model="deviceInput"
@keyup.enter="addDevice" @keyup.enter="addDevice"
ref="deviceInput" ref="deviceInput"
:disabled="trayStatus === '1'" :disabled="trayStatus === '1' || (trayStatus === '3' && abnormalCount === 0)"
> >
<div class="status-bar"> <div class="status-bar">
<i class="fas fa-info-circle"></i> <i class="fas fa-info-circle"></i>
<!-- 调整点2: 修改状态栏显示逻辑 -->
<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 === '3'">待处理异常设备: <span class="filled-count">{{ abnormalCount }}</span>/{{ initialAbnormalCount }}</span> <span v-if="trayStatus === '3' && abnormalCount > 0">
待处理异常设备: <span class="filled-count">{{ abnormalCount }}</span>/{{ initialAbnormalCount }}
</span>
<span v-if="trayStatus === '3' && abnormalCount === 0">
所有设备正常,可进行一键解绑
</span>
</div> </div>
</div> </div>
</div> </div>
...@@ -111,9 +118,9 @@ ...@@ -111,9 +118,9 @@
<i class="fas fa-paper-plane"></i> <i class="fas fa-paper-plane"></i>
{{ '提交绑定' }} {{ '提交绑定' }}
</button> </button>
<!-- 一键解绑按钮 - 仅status=3时显示 --> <!-- 调整点3: 修改一键解绑按钮显示条件 -->
<button <button
v-if="trayStatus === '3'" v-if="trayStatus === '3' && abnormalCount === 0"
class="unbind-btn" class="unbind-btn"
@click="unbindAll" @click="unbindAll"
> >
...@@ -256,6 +263,10 @@ export default { ...@@ -256,6 +263,10 @@ export default {
// 计算是否需要显示操作按钮 // 计算是否需要显示操作按钮
showControlButtons() { showControlButtons() {
// 当托盘状态为"老化中"(1)或"老化完成"(2)时,不显示操作按钮 // 当托盘状态为"老化中"(1)或"老化完成"(2)时,不显示操作按钮
// 调整点4: 在状态3时,只有当异常设备数量为0时才显示操作按钮(一键解绑)
if (this.trayStatus === '3') {
return this.abnormalCount === 0;
}
return this.trayStatus !== '1' && this.trayStatus !== '2'; return this.trayStatus !== '1' && this.trayStatus !== '2';
}, },
// 计算已填充的设备数量 // 计算已填充的设备数量
...@@ -300,7 +311,7 @@ export default { ...@@ -300,7 +311,7 @@ export default {
// 扫描输入框提示语 // 扫描输入框提示语
scanPlaceholder() { scanPlaceholder() {
return this.trayStatus === '3' return this.trayStatus === '3'
? '解绑设备条码...' ? '扫描异常设备条码进行解绑...'
: '扫描设备条码...'; : '扫描设备条码...';
} }
}, },
...@@ -353,7 +364,9 @@ export default { ...@@ -353,7 +364,9 @@ export default {
(device.realTimeStatus != null && device.realTimeStatus === '0') || (device.realTimeStatus != null && device.realTimeStatus === '0') ||
(device.calibrationConcentrationStatus != null && device.calibrationConcentrationStatus !== '4') || (device.calibrationConcentrationStatus != null && device.calibrationConcentrationStatus !== '4') ||
(device.writeTimeStatus != null && device.writeTimeStatus === '0') || (device.writeTimeStatus != null && device.writeTimeStatus === '0') ||
(device.runTimeStatus != null && device.runTimeStatus === '0'); (device.runTimeStatus != null && device.runTimeStatus === '0') ||
device.relayStatus === 0 || device.pulseStatus === 0 ||
device.moduleStatus === 0 || device.simCardStatus === 0 || device.networkStatus === 0;
} else { } else {
// 非标定完成状态(0,4,1,2等),只检查设备状态是否为 0 或 5 // 非标定完成状态(0,4,1,2等),只检查设备状态是否为 0 或 5
// 其他状态字段在绑定阶段可能为 null,不应该视为错误 // 其他状态字段在绑定阶段可能为 null,不应该视为错误
...@@ -467,6 +480,15 @@ export default { ...@@ -467,6 +480,15 @@ export default {
); );
if (deviceIndex !== -1) { if (deviceIndex !== -1) {
// 调整点5: 在标定完成状态下,只有异常设备才允许解绑
const device = this.devices[deviceIndex];
if (!this.isDeviceError(device)) {
// 正常设备不允许解绑
this.$message.warning(`设备 ${this.deviceInput} 状态正常,不能解绑`);
this.deviceInput = '';
return;
}
// 找到设备,直接解绑(不弹确认对话框) // 找到设备,直接解绑(不弹确认对话框)
this.executeUnbind(deviceIndex); this.executeUnbind(deviceIndex);
} else { } else {
...@@ -586,6 +608,11 @@ export default { ...@@ -586,6 +608,11 @@ export default {
// 如果是异常设备,减少异常计数(使用完整的异常判断逻辑) // 如果是异常设备,减少异常计数(使用完整的异常判断逻辑)
if (wasErrorDevice) { if (wasErrorDevice) {
this.abnormalCount--; this.abnormalCount--;
// 调整点6: 当异常设备全部解绑完成后,输入框会自动变为readonly(通过disabled属性控制)
if (this.abnormalCount === 0) {
this.$message.success('所有异常设备已解绑完成,可进行一键解绑');
}
} }
this.$message.success(`设备 ${device.deviceCode} 解绑成功`); this.$message.success(`设备 ${device.deviceCode} 解绑成功`);
......
...@@ -68,6 +68,23 @@ ...@@ -68,6 +68,23 @@
<div class="form-tips">必须大于等于第二阶段时间5分钟及以上,最大4320分钟</div> <div class="form-tips">必须大于等于第二阶段时间5分钟及以上,最大4320分钟</div>
</el-form-item> </el-form-item>
<!-- 第四阶段 - 新增字段 -->
<el-form-item
label="老化流程第四阶段执行时间(单位:分钟)"
prop="agingStage4Time"
>
<el-input-number
v-model="form.agingStage4Time"
:min="Math.max(20, form.agingStage3Time + 5)"
:max="4325"
placeholder="请输入第四阶段执行时间"
controls-position="right"
style="width: 300px;"
@change="validateStage4"
/>
<div class="form-tips">必须大于等于第三阶段时间5分钟及以上,最大4325分钟</div>
</el-form-item>
<!-- 操作按钮 --> <!-- 操作按钮 -->
<el-form-item> <el-form-item>
<el-button <el-button
...@@ -130,14 +147,28 @@ export default { ...@@ -130,14 +147,28 @@ export default {
} }
}; };
// 第四阶段验证规则 - 新增验证规则
const validateStage4 = (rule, value, callback) => {
if (value === null || value === undefined || value === '') {
callback(new Error("第四阶段时间不能为空"));
} else if (value < this.form.agingStage3Time + 5) {
callback(new Error("第四阶段时间必须大于等于第三阶段时间5分钟及以上"));
} else if (value > 4325) {
callback(new Error("第四阶段时间不能超过4325分钟"));
} else {
callback();
}
};
return { return {
// 表单数据 // 表单数据 - 添加第四阶段字段
form: { form: {
agingStage1Time: null, agingStage1Time: null,
agingStage2Time: null, agingStage2Time: null,
agingStage3Time: null, agingStage3Time: null,
agingStage4Time: null, // 新增第四阶段字段
}, },
// 验证规则 // 验证规则 - 添加第四阶段验证规则
rules: { rules: {
agingStage1Time: [ agingStage1Time: [
{ required: true, validator: validateStage1, trigger: ["blur", "change"] } { required: true, validator: validateStage1, trigger: ["blur", "change"] }
...@@ -148,14 +179,18 @@ export default { ...@@ -148,14 +179,18 @@ export default {
agingStage3Time: [ agingStage3Time: [
{ required: true, validator: validateStage3, trigger: ["blur", "change"] } { required: true, validator: validateStage3, trigger: ["blur", "change"] }
], ],
agingStage4Time: [ // 新增第四阶段验证规则
{ required: true, validator: validateStage4, trigger: ["blur", "change"] }
],
}, },
// 加载状态 // 加载状态
loading: false, loading: false,
// 配置键名 // 配置键名 - 添加第四阶段键名
configKeys: { configKeys: {
stage1: "agingStage1Time", stage1: "agingStage1Time",
stage2: "agingStage2Time", stage2: "agingStage2Time",
stage3: "agingStage3Time", stage3: "agingStage3Time",
stage4: "agingStage4Time", // 新增第四阶段键名
}, },
}; };
}, },
...@@ -170,7 +205,7 @@ export default { ...@@ -170,7 +205,7 @@ export default {
const response = await getAgingStageTime(); const response = await getAgingStageTime();
if (response.code === 200 && response.data) { if (response.code === 200 && response.data) {
// 假设返回的数据格式为数组,包含个配置项 // 假设返回的数据格式为数组,包含个配置项
const configs = response.data; const configs = response.data;
configs.forEach(item => { configs.forEach(item => {
switch (item.configKey) { switch (item.configKey) {
...@@ -183,6 +218,9 @@ export default { ...@@ -183,6 +218,9 @@ export default {
case this.configKeys.stage3: case this.configKeys.stage3:
this.form.agingStage3Time = parseInt(item.configValue) || 15; this.form.agingStage3Time = parseInt(item.configValue) || 15;
break; break;
case this.configKeys.stage4: // 新增第四阶段数据处理
this.form.agingStage4Time = parseInt(item.configValue) || 20;
break;
} }
}); });
} }
...@@ -201,7 +239,7 @@ export default { ...@@ -201,7 +239,7 @@ export default {
try { try {
this.loading = true; this.loading = true;
// 构建请求数据 // 构建请求数据 - 添加第四阶段数据
const requestData = [ const requestData = [
{ {
configKey: this.configKeys.stage1, configKey: this.configKeys.stage1,
...@@ -215,6 +253,10 @@ export default { ...@@ -215,6 +253,10 @@ export default {
configKey: this.configKeys.stage3, configKey: this.configKeys.stage3,
configValue: this.form.agingStage3Time.toString(), configValue: this.form.agingStage3Time.toString(),
}, },
{
configKey: this.configKeys.stage4, // 新增第四阶段数据
configValue: this.form.agingStage4Time.toString(),
},
]; ];
const response = await updateAgingStageTime(requestData); const response = await updateAgingStageTime(requestData);
...@@ -246,19 +288,27 @@ export default { ...@@ -246,19 +288,27 @@ export default {
// 第一阶段变化时触发验证 // 第一阶段变化时触发验证
validateStage1() { validateStage1() {
// 重新验证第二阶段和第三阶段 // 重新验证第二、三、四阶段
this.$refs.formRef.validateField("agingStage2Time"); this.$refs.formRef.validateField("agingStage2Time");
this.$refs.formRef.validateField("agingStage3Time"); this.$refs.formRef.validateField("agingStage3Time");
this.$refs.formRef.validateField("agingStage4Time");
}, },
// 第二阶段变化时触发验证 // 第二阶段变化时触发验证
validateStage2() { validateStage2() {
// 重新验证第三阶段 // 重新验证第三、四阶段
this.$refs.formRef.validateField("agingStage3Time"); this.$refs.formRef.validateField("agingStage3Time");
this.$refs.formRef.validateField("agingStage4Time");
}, },
// 第三阶段变化时触发验证 // 第三阶段变化时触发验证
validateStage3() { validateStage3() {
// 重新验证第四阶段
this.$refs.formRef.validateField("agingStage4Time");
},
// 第四阶段变化时触发验证 - 新增方法
validateStage4() {
// 不需要重新验证其他阶段 // 不需要重新验证其他阶段
}, },
...@@ -270,6 +320,11 @@ export default { ...@@ -270,6 +320,11 @@ export default {
// 计算第三阶段的最小值 // 计算第三阶段的最小值
getStage3Min() { getStage3Min() {
return Math.max(15, (this.form.agingStage2Time || 10) + 5); return Math.max(15, (this.form.agingStage2Time || 10) + 5);
},
// 计算第四阶段的最小值 - 新增方法
getStage4Min() {
return Math.max(20, (this.form.agingStage3Time || 15) + 5);
} }
}, },
watch: { watch: {
...@@ -296,6 +351,18 @@ export default { ...@@ -296,6 +351,18 @@ export default {
} }
}, },
immediate: true immediate: true
},
'form.agingStage3Time': {
handler(newVal) {
// 当第三阶段变化时,确保第四阶段不小于第三阶段+5 - 新增监听
if (newVal !== null && this.form.agingStage4Time !== null) {
const minStage4 = newVal + 5;
if (this.form.agingStage4Time < minStage4) {
this.form.agingStage4Time = minStage4;
}
}
},
immediate: true
} }
} }
}; };
......
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