opt:一期内容优化;
This commit is contained in:
@@ -131,6 +131,20 @@
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- PowerMock for static method mocking -->
|
||||
<dependency>
|
||||
<groupId>org.powermock</groupId>
|
||||
<artifactId>powermock-module-junit4</artifactId>
|
||||
<version>2.0.9</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.powermock</groupId>
|
||||
<artifactId>powermock-api-mockito2</artifactId>
|
||||
<version>2.0.9</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.reflections</groupId>
|
||||
<artifactId>reflections</artifactId>
|
||||
|
||||
@@ -8,6 +8,12 @@ public interface AcsConfig {
|
||||
String ONEFORKAGV = "oneforkagv";
|
||||
//同一站点运行最大任务数
|
||||
String ONEPOINTMAXTASK = "onePointMaxTask";
|
||||
//工作时长
|
||||
String WORKINGTIME = "workingTime";
|
||||
//飞书发送时间8:00-22:00
|
||||
String FEISHUSENDTIME = "feiShuSendTime";
|
||||
//飞书发送频次(分钟)
|
||||
String FEISHUSENDFRE = "feiShuSendFre";
|
||||
//同一任务创建最大指令数
|
||||
String MAXINSTNUMBER = "maxInstNumber";
|
||||
//同一任务创建最大RT车指令数
|
||||
@@ -65,4 +71,14 @@ public interface AcsConfig {
|
||||
String LOGLEVEL = "log_level";
|
||||
|
||||
String ELECTRIC ="electric";
|
||||
|
||||
|
||||
|
||||
String ELECTRIC2 ="electric2";
|
||||
|
||||
String ELECTRIC_BEGIN ="electric_begin";
|
||||
|
||||
String ELECTRIC_END ="electric_end";
|
||||
|
||||
String IS_ATUO_ELECTRIC ="is_atuo_electric";
|
||||
}
|
||||
|
||||
@@ -119,7 +119,7 @@ public class OneNDCSocketConnectionAutoRun extends AbstractAutoRunnable {
|
||||
StringBuffer bs1 = new StringBuffer("0");
|
||||
bs.append(temp < 16 ? bs1.append(Integer.toHexString(temp)) : Integer.toHexString(temp));
|
||||
}
|
||||
|
||||
//87cd000800140001007300100001020300730001000000000000004a
|
||||
boolean flag = false;
|
||||
if (arr[8] * 256 + arr[9] == 0x73) {
|
||||
byte[] data = null;
|
||||
@@ -288,11 +288,11 @@ public class OneNDCSocketConnectionAutoRun extends AbstractAutoRunnable {
|
||||
data = NDCAgvService.sendAgvOneModeInst(phase, index, 0);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
}else {
|
||||
//上报异常信息
|
||||
//(不需要WCS反馈)
|
||||
if (phase == 0x67) {
|
||||
device = deviceAppService.findDeviceByCode(Integer.toString(arr[27]));
|
||||
device = deviceAppService.findDeviceByCode(Integer.toString(agvaddr));
|
||||
} else {
|
||||
device = deviceAppService.findDeviceByCode(Integer.toString(arr[20]));
|
||||
}
|
||||
|
||||
@@ -1,22 +1,26 @@
|
||||
package org.nl.acs.device_driver.basedriver.agv.ndcone;
|
||||
|
||||
import cn.hutool.core.date.DateTime;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.http.HttpRequest;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import lombok.Data;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.nl.acs.AcsConfig;
|
||||
import org.nl.acs.agv.server.NDCAgvService;
|
||||
import org.nl.acs.auto.run.OneNDCSocketConnectionAutoRun;
|
||||
import org.nl.acs.device.domain.Device;
|
||||
import org.nl.acs.device.service.DeviceService;
|
||||
import org.nl.acs.device_driver.DeviceDriver;
|
||||
import org.nl.acs.device_driver.driver.AbstractDeviceDriver;
|
||||
import org.nl.acs.ext.wms.data.one.feedBackTaskStatus.FeedBackTaskStatusRequest;
|
||||
import org.nl.acs.ext.wms.service.AcsToWmsService;
|
||||
import org.nl.acs.ext.wms.service.impl.AcsToWmsServiceImpl;
|
||||
import org.nl.acs.history.ErrorUtil;
|
||||
import org.nl.acs.instruction.domain.Instruction;
|
||||
import org.nl.acs.instruction.service.InstructionService;
|
||||
import org.nl.acs.instruction.service.impl.InstructionServiceImpl;
|
||||
@@ -34,8 +38,11 @@ import org.nl.system.service.lucene.LuceneExecuteLogService;
|
||||
import org.nl.system.service.param.ISysParamService;
|
||||
import org.nl.system.service.param.impl.SysParamServiceImpl;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
|
||||
/**
|
||||
@@ -74,6 +81,16 @@ public class AgvNdcOneDeviceDriver extends AbstractDeviceDriver implements Devic
|
||||
int is_have = 0; //是否有货
|
||||
int error = 0; //车辆故障
|
||||
|
||||
// 飞书消息去重缓存:key为设备代码+错误类型,value为最后发送时间戳
|
||||
private final ConcurrentHashMap<String, Long> feiShuErrorCache = new ConcurrentHashMap<>();
|
||||
/**
|
||||
* 缓存的参数值,避免频繁查询数据库
|
||||
*/
|
||||
private volatile String feiShuSendTime = "8:00-22:00";
|
||||
private volatile String feiShuSendFre = "2";
|
||||
private volatile long lastParamLoadTime = 0;
|
||||
private static final long PARAM_CACHE_TIMEOUT = 600000; // 参数缓存超时时间:120秒
|
||||
|
||||
String transportOrder = "";
|
||||
boolean isCharge = false;
|
||||
String message = null;
|
||||
@@ -83,6 +100,7 @@ public class AgvNdcOneDeviceDriver extends AbstractDeviceDriver implements Devic
|
||||
public synchronized void processSocket(int[] arr) throws Exception {
|
||||
device_code = this.getDeviceCode();
|
||||
byte[] data = null;
|
||||
//阶段值
|
||||
phase = arr[16] * 256 + arr[17];
|
||||
// agv任务号
|
||||
int index = arr[12] * 256 + arr[13];
|
||||
@@ -116,20 +134,29 @@ public class AgvNdcOneDeviceDriver extends AbstractDeviceDriver implements Devic
|
||||
String old_device_code = null;
|
||||
String emptyNum = null;
|
||||
String device_code = null;
|
||||
|
||||
//设备故障
|
||||
if (phase == 0x67) {
|
||||
//todo 故障信息
|
||||
if (arr[18] * 256 + arr[19] == 0) {
|
||||
|
||||
try {
|
||||
if (ikey != 0) {
|
||||
data = ndcAgvService.sendAgvOneModeInst(phase, index, 0, 0, 0, 0, 0);
|
||||
Map<String, String> error = ErrorUtil.getAgvErrorMsg(ikey);
|
||||
String code = error.get("code");
|
||||
String info = error.get("info");
|
||||
log.error("车辆" + agvaddr + "故障:故障码:" + error + ",ikey为:" + ikey + ",已解析报警信息:code:" + code + ",info" + info);
|
||||
//通过ikey
|
||||
if (StringUtils.isNotBlank(info)) {
|
||||
sendFeiShuAlert(info);
|
||||
}
|
||||
// FeedBackTaskStatusRequest request = new FeedBackTaskStatusRequest();
|
||||
// request.setDevice_code(this.device_code);
|
||||
// request.setState("故障");
|
||||
// acsToWmsService.notify(request);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("发送飞书报警消息失败", e);
|
||||
}
|
||||
FeedBackTaskStatusRequest request = new FeedBackTaskStatusRequest();
|
||||
request.setDevice_code(this.device_code);
|
||||
request.setState("故障");
|
||||
acsToWmsService.notify(request);
|
||||
data = ndcAgvService.sendAgvOneModeInst(phase, index, 0, 0, 0, 0, 0);
|
||||
}
|
||||
TaskDto task = new TaskDto();
|
||||
|
||||
if (ObjectUtil.isNotEmpty(inst)) {
|
||||
task = taskService.findById(inst.getTask_id());
|
||||
}
|
||||
@@ -141,12 +168,8 @@ public class AgvNdcOneDeviceDriver extends AbstractDeviceDriver implements Devic
|
||||
transportOrder = inst.getTask_code();
|
||||
//车辆分配任务时 状态为1 执行中
|
||||
task.setTask_status("1");
|
||||
//车辆执行任务开始计时字段
|
||||
if (StrUtil.isEmpty(task.getTo_x())) {
|
||||
task.setTo_x(DateUtil.now());
|
||||
}
|
||||
//添加车号
|
||||
if (StrUtil.isEmpty(task.getCar_no())) {
|
||||
if (StringUtils.isBlank(task.getCar_no())) {
|
||||
task.setCar_no(String.valueOf(carno));
|
||||
}
|
||||
taskserver.update(task);
|
||||
@@ -156,22 +179,23 @@ public class AgvNdcOneDeviceDriver extends AbstractDeviceDriver implements Devic
|
||||
//到达取货点
|
||||
//(需要WCS反馈)
|
||||
} else if (phase == 0x03) {
|
||||
|
||||
inst.setExecute_status("1");
|
||||
instructionService.update(inst);
|
||||
data = ndcAgvService.sendAgvOneModeInst(phase, index, 0);
|
||||
flag = true;
|
||||
|
||||
} else if (phase == 0x04) {
|
||||
data = getData(data, index, inst, task);
|
||||
//取货完毕
|
||||
//(需要WCS反馈)
|
||||
} else if (phase == 0x05) {
|
||||
task.setTask_status("8");
|
||||
taskserver.update(task);
|
||||
data = ndcAgvService.sendAgvOneModeInst(phase, index, 0);
|
||||
log.info("agv进入" + device_code + "取货完成");
|
||||
flag = true;
|
||||
data = ndcAgvService.sendAgvOneModeInst(phase, index, 0);
|
||||
task.setTask_status("8");
|
||||
//车辆执行任务开始计时字段
|
||||
if (StringUtils.isBlank(task.getTo_x())) {
|
||||
task.setTo_x(DateUtil.now());
|
||||
}
|
||||
taskserver.updateEntity(task);
|
||||
flag = true;
|
||||
} else if (phase == 0x06) {
|
||||
JSONObject feed_jo = new JSONObject();
|
||||
feed_jo.put("task_id", task.getExt_task_id());
|
||||
@@ -183,7 +207,7 @@ public class AgvNdcOneDeviceDriver extends AbstractDeviceDriver implements Devic
|
||||
acsToWmsService.feedTaskStatus(ja);
|
||||
Instruction inst1 = instructionService.findBytaskCode(inst.getTask_id());
|
||||
log.info("二次分配指令终点是{}",inst1.getNext_point_code());
|
||||
if(inst1.getNext_point_code().equals("CKFPW")){
|
||||
if ("CKFPW".equals(inst1.getNext_point_code())) {
|
||||
throw new BadRequestException("没有出库点位了请释放");
|
||||
}
|
||||
data=ndcAgvService.sendAgvTwoModeInst(phase,index,0,inst1);
|
||||
@@ -194,9 +218,9 @@ public class AgvNdcOneDeviceDriver extends AbstractDeviceDriver implements Devic
|
||||
data = ndcAgvService.sendAgvOneModeInst(phase, index, 0);
|
||||
flag = true;
|
||||
} else if (phase == 0x09) {
|
||||
log.info("agv进入" + this.device_code + "放货完成" + task.getTo_x());
|
||||
data = ndcAgvService.sendAgvOneModeInst(phase, index, 0);
|
||||
flag = true;
|
||||
|
||||
}
|
||||
//到达位置点
|
||||
//(需要WCS反馈)
|
||||
@@ -254,4 +278,143 @@ public class AgvNdcOneDeviceDriver extends AbstractDeviceDriver implements Devic
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送飞书报警消息
|
||||
*
|
||||
* @param errorMessage 错误消息
|
||||
*/
|
||||
private void sendFeiShuAlert(String errorMessage) {
|
||||
try {
|
||||
loadTaskCountParamsIfNeeded();
|
||||
// 1. 检查是否在允许的工作时间范围内
|
||||
if (StrUtil.isNotBlank(feiShuSendTime) && feiShuSendTime.contains("-")) {
|
||||
// 解析时间格式:"8:00-22:00"
|
||||
String[] timeRange = feiShuSendTime.split("-");
|
||||
if (timeRange.length == 2) {
|
||||
DateTime now = DateUtil.date();
|
||||
// 将当前时间转换为分钟数进行比较
|
||||
int nowMinutes = DateUtil.hour(now, true) * 60 + DateUtil.minute(now);
|
||||
// 解析开始时间
|
||||
String[] startTime = timeRange[0].trim().split(":");
|
||||
int startHour = Integer.parseInt(startTime[0]);
|
||||
int startMinute = startTime.length > 1 ? Integer.parseInt(startTime[1]) : 0;
|
||||
int startMinutes = startHour * 60 + startMinute;
|
||||
// 解析结束时间
|
||||
String[] endTime = timeRange[1].trim().split(":");
|
||||
int endHour = Integer.parseInt(endTime[0]);
|
||||
int endMinute = endTime.length > 1 ? Integer.parseInt(endTime[1]) : 0;
|
||||
int endMinutes = endHour * 60 + endMinute;
|
||||
// 判断当前时间是否在工作时间内
|
||||
if (nowMinutes < startMinutes || nowMinutes >= endMinutes) {
|
||||
// log.info("当前时间{}不在工作时间范围内({}),跳过发送飞书消息",
|
||||
// DateUtil.formatTime(now), feiShuSendTime);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 2. 重复消息筛选:5分钟内相同设备的相同错误不重复发送
|
||||
String cacheKey = this.getDeviceCode() + errorMessage;
|
||||
long currentTime = System.currentTimeMillis();
|
||||
Long lastSendTime = feiShuErrorCache.get(cacheKey);
|
||||
if (lastSendTime != null) {
|
||||
long diffTime = currentTime - lastSendTime;
|
||||
// 距离上次发送不足2分钟,过滤掉该消息
|
||||
int feiShuSendFreMin = Integer.parseInt(feiShuSendFre);
|
||||
if (diffTime < feiShuSendFreMin * 60000L) {
|
||||
log.debug("设备{}的{}在5分钟内已有过提醒,过滤掉本次重复提醒(距今{}ms)",
|
||||
this.getDeviceCode(), errorMessage, diffTime);
|
||||
return;
|
||||
}
|
||||
}
|
||||
//构建飞书 webhook 请求参数(使用 Post 富文本格式)
|
||||
JSONObject requestBody = new JSONObject();
|
||||
requestBody.put("msg_type", "post");
|
||||
// 构建 Post 内容
|
||||
JSONObject content = new JSONObject();
|
||||
JSONObject post = new JSONObject();
|
||||
JSONObject zh_cn = new JSONObject();
|
||||
// 设置标题
|
||||
zh_cn.put("title", "AMR报警");
|
||||
// 设置内容
|
||||
JSONArray contentArray = new JSONArray();
|
||||
JSONArray contentRow1 = new JSONArray();
|
||||
// 第一行:报警信息: 【AMR故障报警】
|
||||
JSONObject tagText1 = new JSONObject();
|
||||
tagText1.put("tag", "text");
|
||||
tagText1.put("text", "报警信息: 【AMR故障报警】");
|
||||
// 第二行:设备编码
|
||||
JSONObject tagText2 = new JSONObject();
|
||||
tagText2.put("tag", "text");
|
||||
tagText2.put("text", "\n设备编码:" + this.getDeviceCode() + "号车");
|
||||
// 第三行:故障信息
|
||||
JSONObject tagText3 = new JSONObject();
|
||||
tagText3.put("tag", "text");
|
||||
tagText3.put("text", "\n故障信息:" + errorMessage);
|
||||
// 第四行:报警时间
|
||||
JSONObject tagText4 = new JSONObject();
|
||||
tagText4.put("tag", "text");
|
||||
tagText4.put("text", "\n报警时间:" + DateUtil.now());
|
||||
// 第五行:请及时处理!
|
||||
JSONObject tagText5 = new JSONObject();
|
||||
tagText5.put("tag", "text");
|
||||
tagText5.put("text", "\n请及时处理!");
|
||||
// 将所有内容行添加到内容数组
|
||||
contentArray.add(contentRow1);
|
||||
contentRow1.add(tagText1);
|
||||
contentRow1.add(tagText2);
|
||||
contentRow1.add(tagText3);
|
||||
contentRow1.add(tagText4);
|
||||
contentRow1.add(tagText5);
|
||||
zh_cn.put("content", contentArray);
|
||||
post.put("zh_cn", zh_cn);
|
||||
content.put("post", post);
|
||||
requestBody.put("content", content);
|
||||
String feiShuUrl = "https://open.feishu.cn/open-apis/bot/v2/hook/c3fcb100-72e0-48e6-bdf6-e266e67858a1";
|
||||
// 5. 发送 HTTP 请求到飞书机器人
|
||||
String response = HttpRequest.post(feiShuUrl)
|
||||
.header("Content-Type", "application/json")
|
||||
.body(requestBody.toJSONString())
|
||||
.timeout(15000) // 5秒超时
|
||||
.execute()
|
||||
.body();
|
||||
// 6. 检查响应结果并记录日志
|
||||
JSONObject jsonResponse = JSONObject.parseObject(response);
|
||||
if (jsonResponse != null && jsonResponse.getIntValue("code") == 0) {
|
||||
//log.info("设备{}的故障消息发送成功:{}", this.getDeviceCode(), errorMessage);
|
||||
// 更新缓存:记录最后发送时间
|
||||
feiShuErrorCache.put(cacheKey, currentTime);
|
||||
} else {
|
||||
log.error("设备{}的故障消息发送失败:{}", this.getDeviceCode(), response);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("发送飞书报警消息时发生异常,设备编码:{},错误信息:{}", this.getDeviceCode(), errorMessage, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果缓存未过期则直接使用缓存值,否则从数据库重新加载
|
||||
*/
|
||||
private void loadTaskCountParamsIfNeeded() {
|
||||
long currentTime = System.currentTimeMillis();
|
||||
try {
|
||||
if (currentTime - lastParamLoadTime < PARAM_CACHE_TIMEOUT) {
|
||||
return;
|
||||
}
|
||||
String feiShuSendTimeResult = paramService.findByCode(AcsConfig.FEISHUSENDTIME).getValue();
|
||||
String feiShuSendFreResult = paramService.findByCode(AcsConfig.FEISHUSENDFRE).getValue();
|
||||
// 更新缓存值
|
||||
if (StringUtils.isNotBlank(feiShuSendTimeResult)) {
|
||||
this.feiShuSendTime = feiShuSendTimeResult;
|
||||
}
|
||||
if (StringUtils.isNotBlank(feiShuSendFreResult)) {
|
||||
this.feiShuSendFre = feiShuSendFreResult;
|
||||
}
|
||||
this.lastParamLoadTime = System.currentTimeMillis();
|
||||
} catch (Exception e) {
|
||||
log.error("加载任务数量参数失败,使用缓存值", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -7,10 +7,7 @@ import org.nl.system.service.dict.ISysDictService;
|
||||
import org.nl.system.service.dict.dao.Dict;
|
||||
import org.nl.system.service.dict.impl.SysDictServiceImpl;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -64,7 +61,7 @@ public class ErrorUtil {
|
||||
List<Dict> dictDtos = dictDetailService.queryAll();
|
||||
for (int i = 0; i < dictDtos.size(); i++) {
|
||||
Dict dictDto = dictDtos.get(i);
|
||||
dictMap.put(dictDto.getName(), getDict(dictDto.getName(), dictDetailService::getDictByName));
|
||||
dictMap.put(dictDto.getCode(), getDict(dictDto.getDict_id(), dictDetailService::getDictDetail));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -76,7 +73,6 @@ public class ErrorUtil {
|
||||
public static Map<String, String> getAgvErrorMsg(Integer agvErrorNum) {
|
||||
String code;
|
||||
String message;
|
||||
|
||||
if (agvErrorNum == 0) {
|
||||
code = "0";
|
||||
message = "正常";
|
||||
@@ -90,7 +86,6 @@ public class ErrorUtil {
|
||||
message = "字典表未配置 [agv_error_type]";
|
||||
} else {
|
||||
List<Map.Entry<Integer, String>> errors = agvMap.entrySet().stream().filter(e -> e.getKey() > 0).sorted(Comparator.comparingInt(Map.Entry::getKey)).collect(Collectors.toList());
|
||||
|
||||
if (errors.isEmpty()) {
|
||||
code = "-1";
|
||||
message = "字典表 [agv_error_type] 配置有误";
|
||||
@@ -98,27 +93,37 @@ public class ErrorUtil {
|
||||
code = "-1";
|
||||
message = "AGV上报报警代码有误";
|
||||
} else {
|
||||
int index = 0;
|
||||
StringBuilder errorCode = new StringBuilder();
|
||||
StringBuilder errorMessage = new StringBuilder();
|
||||
for (int i = agvErrorNum; i != 0; i = i >> 1) {
|
||||
if (index == errors.size()) {
|
||||
errorCode.setLength(0);
|
||||
errorCode.append("-1");
|
||||
errorMessage.setLength(0);
|
||||
errorMessage.append("字典表 [agv_error_type] 配置有误");
|
||||
break;
|
||||
// 尝试直接匹配错误码
|
||||
Optional<Map.Entry<Integer, String>> matchedEntry = agvMap.entrySet().stream()
|
||||
.filter(e -> e.getKey().equals(agvErrorNum))
|
||||
.findFirst();
|
||||
if (matchedEntry.isPresent()) {
|
||||
code = matchedEntry.get().getKey().toString();
|
||||
message = matchedEntry.get().getValue();
|
||||
} else {
|
||||
// 如果没有直接匹配,使用位运算解析多个错误
|
||||
int index = 0;
|
||||
StringBuilder errorCode = new StringBuilder();
|
||||
StringBuilder errorMessage = new StringBuilder();
|
||||
for (int i = agvErrorNum; i != 0; i = i >> 1) {
|
||||
if (index == errors.size()) {
|
||||
errorCode.setLength(0);
|
||||
errorCode.append("-1");
|
||||
errorMessage.setLength(0);
|
||||
errorMessage.append("字典表 [agv_error_type] 配置有误");
|
||||
break;
|
||||
}
|
||||
if (i % 2 == 1) {
|
||||
errorCode.append(errors.get(index).getKey()).append(",");
|
||||
errorMessage.append(errors.get(index).getValue()).append(",");
|
||||
}
|
||||
index++;
|
||||
}
|
||||
if (i % 2 == 1) {
|
||||
errorCode.append(errors.get(index).getKey()).append(",");
|
||||
errorMessage.append(errors.get(index).getValue()).append(",");
|
||||
}
|
||||
index++;
|
||||
code = errorCode.toString();
|
||||
message = errorMessage.toString();
|
||||
}
|
||||
code = errorCode.toString();
|
||||
message = errorMessage.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, String> map = new HashMap<>(2);
|
||||
|
||||
@@ -346,7 +346,10 @@ public class InstructionServiceImpl extends CommonServiceImpl<InstructionMapper,
|
||||
dto = foramte(dto);
|
||||
String task_code = dto.getTask_code();
|
||||
TaskDto task = taskService.findByCodeFromCache(task_code);
|
||||
|
||||
if (task == null) {
|
||||
log.error("指令创建失败,该任务在缓存中已失效,任务号为:{}", task_code);
|
||||
throw new RuntimeException("指令创建失败,该任务在缓存中已失效,任务号为:"+task_code);
|
||||
}
|
||||
String currentUsername = SecurityUtils.getCurrentUsername();
|
||||
String now = DateUtil.now();
|
||||
if (StrUtil.isEmpty(dto.getRoute_plan_code())) {
|
||||
@@ -444,7 +447,7 @@ public class InstructionServiceImpl extends CommonServiceImpl<InstructionMapper,
|
||||
} catch (Exception e) {
|
||||
dto.setSend_status("2");
|
||||
e.printStackTrace();
|
||||
log.error("指令下发失败,异常信息:" + e.getMessage());
|
||||
log.error("指令号为:{},任务号为:{},下发失败,异常信息:" + e.getMessage(), dto.getInstruction_code(), task_code);
|
||||
}
|
||||
InstructionMybatis entity = ConvertUtil.convert(dto, InstructionMybatis.class);
|
||||
instructionMapper.insert(entity);
|
||||
@@ -718,7 +721,7 @@ public class InstructionServiceImpl extends CommonServiceImpl<InstructionMapper,
|
||||
DeviceAppService appService = SpringContextHolder.getBean(DeviceAppServiceImpl.class);
|
||||
Device startdevice = appService.findDeviceByCode(entity.getStart_point_code());
|
||||
if (ObjectUtils.isEmpty(startdevice)) {
|
||||
log.debug("地址对应设备未找到");
|
||||
log.error("指令号:{},任务号{},地址对应设备未找到", entity.getInstruction_code(), entity.getTask_code());
|
||||
throw new BadRequestException(LangProcess.msg("error_isNull", entity.getStart_device_code()));
|
||||
}
|
||||
CommonFinalParam commonFinalParam = new CommonFinalParam();
|
||||
@@ -727,8 +730,13 @@ public class InstructionServiceImpl extends CommonServiceImpl<InstructionMapper,
|
||||
}
|
||||
Device device = appService.findDeviceByCode(instnextdevice);
|
||||
if (device == null) {
|
||||
log.debug("地址对应设备未找到");
|
||||
throw new BadRequestException(LangProcess.msg("error_isNull", instnextdevice));
|
||||
device = appService.findDeviceByCode(entity.getNext_point_code());
|
||||
if (device == null) {
|
||||
log.error("地址对应设备未找到");
|
||||
throw new BadRequestException(LangProcess.msg("error_isNull", instnextdevice));
|
||||
} else {
|
||||
instnextdevice = entity.getNext_point_code();
|
||||
}
|
||||
}
|
||||
DeviceService deviceService = SpringContextHolder.getBean(DeviceServiceImpl.class);
|
||||
|
||||
@@ -785,11 +793,17 @@ public class InstructionServiceImpl extends CommonServiceImpl<InstructionMapper,
|
||||
finishAndCreateNextInst((Instruction) entity);
|
||||
}
|
||||
}
|
||||
updateTaskPriority(task);
|
||||
removeByCodeFromCache(entity.getInstruction_code());
|
||||
// this.reload();
|
||||
}
|
||||
|
||||
private void updateTaskPriority (Task task) {
|
||||
TaskDto acsTask = null;
|
||||
//查询是否存在出库任务,如果存在,按优先级和创建时间,创建1条出库任务的指令
|
||||
List<Task> taskList = new LambdaQueryChainWrapper<>(taskMapper)
|
||||
.eq(Task::getTask_status, "0")
|
||||
.eq(Task::getIs_delete, "0")
|
||||
.eq(Task::getCar_type, task.getCar_type())
|
||||
.eq(Task::getTask_type, "1".equals(task.getTask_type()) ? "2" : "1")
|
||||
.orderByDesc(Task::getPriority)
|
||||
.orderByAsc(Task::getTask_code)
|
||||
@@ -797,13 +811,14 @@ public class InstructionServiceImpl extends CommonServiceImpl<InstructionMapper,
|
||||
//指令列表
|
||||
List<InstructionMybatis> instructionList = new LambdaQueryChainWrapper<>(instructionMapper)
|
||||
.lt(InstructionMybatis::getInstruction_status, InstructionStatusEnum.FINISHED.getIndex())
|
||||
.eq(InstructionMybatis::getIs_delete, "0")
|
||||
.list();
|
||||
if (ObjectUtil.isNotEmpty(taskList)) {
|
||||
TaskDto acsTask = null;
|
||||
List<TaskDto> priorityTaskList = ConvertUtil.convertList(taskList, TaskDto.class);
|
||||
if (task.getTask_type().equals("2")) {
|
||||
if ("2".equals(task.getTask_type())) {
|
||||
//包含"BCPRK"或"CPRK"的任务
|
||||
List<TaskDto> collection1 = new ArrayList<>();
|
||||
//不需要二次分配的任务
|
||||
List<TaskDto> collection2 = new ArrayList<>();
|
||||
// 分组任务
|
||||
for (TaskDto taskDto : priorityTaskList) {
|
||||
@@ -839,8 +854,45 @@ public class InstructionServiceImpl extends CommonServiceImpl<InstructionMapper,
|
||||
&& collection3Prefixes.contains(startDeviceCode.split("-")[0]);
|
||||
});
|
||||
}
|
||||
//不存在执行中指令的入库任务
|
||||
if (ObjectUtil.isNotEmpty(collection1)) {
|
||||
acsTask = collection1.get(0);
|
||||
// 按前缀分组(CPRK5、CPRK3等)
|
||||
Map<String, List<TaskDto>> group = collection1.stream()
|
||||
.filter(r -> r.getStart_device_code() != null && r.getStart_device_code().contains("-"))
|
||||
.collect(Collectors.groupingBy(
|
||||
r -> r.getStart_device_code().split("-")[0]
|
||||
));
|
||||
|
||||
// 对每个组内的元素按task_code升序排序
|
||||
for (String key : group.keySet()) {
|
||||
List<TaskDto> sortedList = group.get(key).stream()
|
||||
.sorted(Comparator.comparing(TaskDto::getTask_code))
|
||||
.collect(Collectors.toList());
|
||||
group.put(key, sortedList);
|
||||
}
|
||||
// 将分组按组内第1个元素的task_code升序排序
|
||||
Map<String, List<TaskDto>> sortedGroup = group.entrySet().stream()
|
||||
.sorted((entry1, entry2) -> {
|
||||
List<TaskDto> list1 = entry1.getValue();
|
||||
List<TaskDto> list2 = entry2.getValue();
|
||||
if (!list1.isEmpty() && !list2.isEmpty()) {
|
||||
return list1.get(0).getTask_code().compareTo(list2.get(0).getTask_code());
|
||||
}
|
||||
return 0;
|
||||
}).collect(Collectors.toMap(
|
||||
Map.Entry::getKey,
|
||||
Map.Entry::getValue,
|
||||
(e1, e2) -> e1,
|
||||
LinkedHashMap::new
|
||||
));
|
||||
// 按car_type查找任务(从排序后的第1个组开始找)
|
||||
for (Map.Entry<String, List<TaskDto>> entry : sortedGroup.entrySet()) {
|
||||
List<TaskDto> groupList = entry.getValue();
|
||||
if (!groupList.isEmpty() && task.getCar_type().equals(groupList.get(0).getCar_type())) {
|
||||
acsTask = groupList.get(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (ObjectUtil.isNotEmpty(collection2)) {
|
||||
acsTask = collection2.get(0);
|
||||
@@ -852,12 +904,11 @@ public class InstructionServiceImpl extends CommonServiceImpl<InstructionMapper,
|
||||
if (acsTask != null) {
|
||||
//优先级最高
|
||||
acsTask.setPriority("98");
|
||||
acsTask.setRemark("前置任务:" + task.getTask_code());
|
||||
acsTask.setUpdate_time(DateUtil.now());
|
||||
taskService.update(acsTask);
|
||||
}
|
||||
}
|
||||
removeByCodeFromCache(entity.getInstruction_code());
|
||||
// this.reload();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -150,7 +150,7 @@ public interface TaskService extends CommonService<Task> {
|
||||
* @param task_status task_status
|
||||
* @return AcsTask
|
||||
*/
|
||||
List<TaskDto> queryAllByInStatus(Set<String> task_status);
|
||||
List<TaskDto> queryAllByInStatus(List<String> task_status);
|
||||
|
||||
|
||||
|
||||
@@ -281,6 +281,11 @@ public interface TaskService extends CommonService<Task> {
|
||||
*/
|
||||
void update(TaskDto dto);
|
||||
|
||||
|
||||
|
||||
void updateEntity(TaskDto dto);
|
||||
|
||||
|
||||
/**
|
||||
* 多选删除
|
||||
*
|
||||
|
||||
@@ -7,6 +7,7 @@ import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.http.HttpRequest;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
@@ -14,8 +15,9 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.nl.acs.AcsConfig;
|
||||
import org.nl.acs.agv.server.XianGongAgvService;
|
||||
@@ -31,6 +33,7 @@ import org.nl.acs.device.service.DeviceService;
|
||||
import org.nl.acs.device.service.dto.DeviceAssignedDto;
|
||||
import org.nl.acs.device.service.impl.DeviceServiceImpl;
|
||||
import org.nl.acs.ext.wms.service.AcsToWmsService;
|
||||
import org.nl.acs.history.ErrorUtil;
|
||||
import org.nl.acs.instruction.domain.Instruction;
|
||||
import org.nl.acs.instruction.domain.InstructionMybatis;
|
||||
import org.nl.acs.instruction.enums.InstructionStatusEnum;
|
||||
@@ -60,7 +63,9 @@ import org.nl.config.SpringContextHolder;
|
||||
import org.nl.config.language.LangProcess;
|
||||
import org.nl.system.service.param.ISysParamService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Propagation;
|
||||
@@ -70,6 +75,7 @@ import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
@@ -84,7 +90,6 @@ import java.util.stream.Collectors;
|
||||
@Lazy
|
||||
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
|
||||
public class TaskServiceImpl extends CommonServiceImpl<TaskMapper, Task> implements TaskService, ApplicationAutoInitial {
|
||||
|
||||
@Autowired
|
||||
private TaskMapper taskMapper;
|
||||
@Autowired
|
||||
@@ -200,7 +205,7 @@ public class TaskServiceImpl extends CommonServiceImpl<TaskMapper, Task> impleme
|
||||
return ConvertUtil.convertList(taskList, TaskDto.class);
|
||||
}
|
||||
|
||||
public List<TaskDto> queryAllByInStatus(Set<String> task_status) {
|
||||
public List<TaskDto> queryAllByInStatus(List<String> task_status) {
|
||||
List<Task> taskList = new LambdaQueryChainWrapper<>(taskMapper)
|
||||
.in(Task::getTask_status, task_status)
|
||||
.eq(Task::getIs_delete, "0")
|
||||
@@ -212,7 +217,6 @@ public class TaskServiceImpl extends CommonServiceImpl<TaskMapper, Task> impleme
|
||||
|
||||
@Override
|
||||
public Map<String, Object> queryAll(Map whereJson, Pageable page) {
|
||||
|
||||
String task_code = (String) whereJson.get("task_code");
|
||||
String vehicle_code = (String) whereJson.get("vehicle_code");
|
||||
String material_type = (String) whereJson.get("material_type");
|
||||
@@ -220,12 +224,15 @@ public class TaskServiceImpl extends CommonServiceImpl<TaskMapper, Task> impleme
|
||||
String point_code = (String) whereJson.get("point_code");
|
||||
String is_over = (String) whereJson.get("is_over");
|
||||
String priority = (String) whereJson.get("priority");
|
||||
|
||||
String task_type = (String) whereJson.get("task_type");
|
||||
IPage<Task> queryPage = PageUtil.toMybatisPage(page);
|
||||
LambdaQueryWrapper<Task> wrapper = new LambdaQueryWrapper<>();
|
||||
if (!StrUtil.isEmpty(task_code)) {
|
||||
wrapper.eq(Task::getTask_code, task_code);
|
||||
}
|
||||
if (!StrUtil.isEmpty(task_type)) {
|
||||
wrapper.eq(Task::getTask_type, task_type);
|
||||
}
|
||||
if (!StrUtil.isEmpty(vehicle_code)) {
|
||||
wrapper.eq(Task::getVehicle_code, vehicle_code);
|
||||
}
|
||||
@@ -328,7 +335,10 @@ public class TaskServiceImpl extends CommonServiceImpl<TaskMapper, Task> impleme
|
||||
String point_code = (String) whereJson.get("point_code");
|
||||
String create_time = (String) whereJson.get("createTime");
|
||||
String end_time = (String) whereJson.get("end_time");
|
||||
|
||||
String task_type = (String) whereJson.get("task_type");
|
||||
String start_point_code = (String) whereJson.get("start_point_code");
|
||||
String next_point_code = (String) whereJson.get("next_point_code");
|
||||
String timeIndex = (String) whereJson.get("timeIndex");
|
||||
IPage<Task> queryPage = PageUtil.toMybatisPage(page);
|
||||
LambdaQueryWrapper<Task> wrapper = new LambdaQueryWrapper<>();
|
||||
if (!StrUtil.isEmpty(car_no)) {
|
||||
@@ -337,6 +347,9 @@ public class TaskServiceImpl extends CommonServiceImpl<TaskMapper, Task> impleme
|
||||
if (!StrUtil.isEmpty(task_code)) {
|
||||
wrapper.eq(Task::getTask_code, task_code);
|
||||
}
|
||||
if (!StrUtil.isEmpty(task_type)) {
|
||||
wrapper.eq(Task::getTask_type, task_type);
|
||||
}
|
||||
if (!StrUtil.isEmpty(vehicle_code)) {
|
||||
wrapper.like(Task::getVehicle_code, vehicle_code);
|
||||
}
|
||||
@@ -348,11 +361,62 @@ public class TaskServiceImpl extends CommonServiceImpl<TaskMapper, Task> impleme
|
||||
}
|
||||
if (!StrUtil.isEmpty(point_code)) {
|
||||
wrapper.and(task -> task.like(Task::getStart_point_code, point_code).or().like(Task::getNext_point_code, point_code));
|
||||
}else{
|
||||
if ("AA".equals(start_point_code)) {
|
||||
wrapper.like(Task::getNext_point_code, next_point_code);
|
||||
}else if ("AA".equals(next_point_code)) {
|
||||
wrapper.like(Task::getStart_point_code, start_point_code);
|
||||
}
|
||||
}
|
||||
if (!StrUtil.isEmpty(create_time) && !StrUtil.isEmpty(end_time)) {
|
||||
wrapper.between(Task::getCreate_time, create_time, end_time);
|
||||
}
|
||||
wrapper.orderByDesc(Task::getCreate_time);
|
||||
if (StrUtil.isNotEmpty(timeIndex)) {
|
||||
// 先查询出所有符合条件的任务,然后在内存中根据时间间隔过滤
|
||||
List<Task> allTasks = taskMapper.selectList(wrapper);
|
||||
// 计算每个任务的时间间隔(分钟)
|
||||
List<Task> filteredTasks = allTasks.stream()
|
||||
.filter(task -> {
|
||||
Double duration = calculateDuration(task.getTo_x(), task.getTo_y());
|
||||
if (duration == null) {
|
||||
return false;
|
||||
}
|
||||
switch (timeIndex) {
|
||||
case "1": // 1-3分钟(包含1和3)
|
||||
return duration >= 1 && duration <= 3;
|
||||
case "2": // 3-5分钟(大于3,小于等于5)
|
||||
return duration > 3 && duration <= 5;
|
||||
case "3": // 5-8分钟(大于5,小于等于8)
|
||||
return duration > 5 && duration <= 8;
|
||||
case "4": // 大于8分钟
|
||||
return duration > 8;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}).collect(Collectors.toList());
|
||||
// 手动分页
|
||||
int total = filteredTasks.size();
|
||||
int start = (int) page.getOffset();
|
||||
int end = Math.min(start + page.getPageSize(), total);
|
||||
List<Task> pageData = start < total ? filteredTasks.subList(start, end) : new ArrayList<>();
|
||||
// 构建分页结果
|
||||
Page<Task> resultPage = new Page<>(page.getPageNumber() + 1, page.getPageSize(), total);
|
||||
resultPage.setRecords(pageData);
|
||||
final JSONObject json = (JSONObject) JSON.toJSON(ConvertUtil.convertPage(resultPage, TaskDto.class));
|
||||
JSONArray array = json.getJSONArray("content");
|
||||
int totalElements = (int) json.getLongValue("totalElements");
|
||||
JSONArray arr = new JSONArray();
|
||||
for (int i = 0; i < array.size(); i++) {
|
||||
JSONObject jsonObject = (JSONObject) array.get(i);
|
||||
jsonObject.put("hasChildren", true);
|
||||
arr.add(jsonObject);
|
||||
}
|
||||
JSONObject jo = new JSONObject();
|
||||
jo.put("content", arr);
|
||||
jo.put("totalElements", totalElements);
|
||||
return jo;
|
||||
}
|
||||
IPage<Task> taskPage = taskMapper.selectPage(queryPage, wrapper);
|
||||
final JSONObject json = (JSONObject) JSON.toJSON(ConvertUtil.convertPage(taskPage, TaskDto.class));
|
||||
JSONArray array = json.getJSONArray("content");
|
||||
@@ -768,6 +832,22 @@ public class TaskServiceImpl extends CommonServiceImpl<TaskMapper, Task> impleme
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//仅更新数据库
|
||||
@Override
|
||||
public void updateEntity(TaskDto dto) {
|
||||
TaskDto entity = this.findById(dto.getTask_id());
|
||||
if (entity == null) {
|
||||
throw new BadRequestException(LangProcess.msg("error_sysAuth"));
|
||||
}
|
||||
String currentUsername = SecurityUtils.getCurrentUsername();
|
||||
String now = DateUtil.now();
|
||||
dto.setUpdate_time(now);
|
||||
dto.setUpdate_by(currentUsername);
|
||||
Task task = ConvertUtil.convert(dto, Task.class);
|
||||
taskMapper.updateById(task);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void deleteAll(String[] ids) throws Exception {
|
||||
@@ -797,7 +877,7 @@ public class TaskServiceImpl extends CommonServiceImpl<TaskMapper, Task> impleme
|
||||
//车辆执行任务完成计时字段
|
||||
entity.setTo_y(now);
|
||||
Task task = ConvertUtil.convert(entity, Task.class);
|
||||
if (StrUtil.isNotBlank(entity.getTo_x())) {
|
||||
if (StringUtils.isNotBlank(entity.getTo_x())) {
|
||||
DateTime toXTime = DateUtil.parse(entity.getTo_x());
|
||||
DateTime nowTime = DateUtil.parse(now);
|
||||
long diffMs = nowTime.getTime() - toXTime.getTime();
|
||||
@@ -818,7 +898,10 @@ public class TaskServiceImpl extends CommonServiceImpl<TaskMapper, Task> impleme
|
||||
if (!StrUtil.startWith(entity.getTask_code(), "-") && StrUtil.equals(hasWms, "1")) {
|
||||
this.feedWmsTaskStatus(entity);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void finishmove(String id) {
|
||||
@@ -867,23 +950,52 @@ public class TaskServiceImpl extends CommonServiceImpl<TaskMapper, Task> impleme
|
||||
if (acsTask == null) {
|
||||
throw new BadRequestException(LangProcess.msg("error_sysAuth"));
|
||||
}
|
||||
DeviceAppService appService = SpringContextHolder.getBean(DeviceAppServiceImpl.class);
|
||||
InstructionService instructionservice = SpringContextHolder.getBean("instructionServiceImpl");
|
||||
InstructionDto inst = instructionservice.findByTaskid(ids, "instruction_status < 2 ");
|
||||
if (inst != null) {
|
||||
throw new BadRequestException(LangProcess.msg("task_insRun"));
|
||||
}
|
||||
int unfinishedInstructionCount = new LambdaQueryChainWrapper<>(instructionMapper)
|
||||
String maxInstNumber = "0";
|
||||
long unfinishedInstructionCount = 0L;
|
||||
List<InstructionMybatis> unfinishedList = new LambdaQueryChainWrapper<>(instructionMapper)
|
||||
.lt(InstructionMybatis::getInstruction_status, InstructionStatusEnum.FINISHED.getIndex())
|
||||
.count();
|
||||
String maxInstNumber = paramService.findByCode(AcsConfig.MAXINSTNUMBER).getValue();
|
||||
int maxInst = Integer.parseInt(maxInstNumber);
|
||||
.eq(InstructionMybatis::getIs_delete, "0").list();
|
||||
if ("2".equals(acsTask.getCar_type())) {
|
||||
maxInstNumber = paramService.findByCode(AcsConfig.MAXRTINSTNUMBER).getValue();
|
||||
unfinishedInstructionCount = unfinishedList.stream().filter(r -> "2".equals(r.getCar_type())).count();
|
||||
} else {
|
||||
maxInstNumber = paramService.findByCode(AcsConfig.MAXINSTNUMBER).getValue();
|
||||
unfinishedInstructionCount = unfinishedList.stream().filter(r -> !"2".equals(r.getCar_type())).count();
|
||||
}
|
||||
long maxInst = Long.parseLong(maxInstNumber);
|
||||
if (unfinishedInstructionCount >= maxInst) {
|
||||
throw new BadRequestException("超过最大指令数:"+maxInstNumber+"个,请等待指令列表完成后再创建!");
|
||||
throw new BadRequestException("超过最大指令数:" + maxInstNumber + "个,请等待指令列表完成后再创建!");
|
||||
}
|
||||
String startDeviceCode = acsTask.getStart_device_code();
|
||||
if ("1".equals(acsTask.getTask_type()) && (startDeviceCode.contains("BCPRK") || startDeviceCode.contains("CPRK"))) {
|
||||
// 包含"BCPRK"或"CPRK"的指令
|
||||
List<InstructionMybatis> collection = new ArrayList<>();
|
||||
// 分组指令
|
||||
for (InstructionMybatis instruction : unfinishedList) {
|
||||
String deviceCode = instruction.getStart_device_code();
|
||||
if (deviceCode != null && (deviceCode.contains("BCPRK") || deviceCode.contains("CPRK"))) {
|
||||
collection.add(instruction);
|
||||
}
|
||||
}
|
||||
boolean flag = collection.stream().anyMatch(ins -> {
|
||||
String code = ins.getStart_device_code();
|
||||
if (code == null) return false;
|
||||
String[] parts = code.split("-", 2);
|
||||
String[] parts1 = startDeviceCode.split("-", 2);
|
||||
return parts1[0].equals(parts[0]);
|
||||
});
|
||||
if (flag) {
|
||||
throw new BadRequestException("当前任务的起点:" + startDeviceCode + "存在相同入库口的指令,请等待执行完成再创建!");
|
||||
}
|
||||
}
|
||||
String taskid = acsTask.getTask_id();
|
||||
String taskcode = acsTask.getTask_code();
|
||||
String car_type=acsTask.getCar_type();
|
||||
String car_type = acsTask.getCar_type();
|
||||
String vehiclecode = acsTask.getVehicle_code();
|
||||
String priority = acsTask.getPriority();
|
||||
String start_point_code = acsTask.getStart_point_code();
|
||||
@@ -931,7 +1043,7 @@ public class TaskServiceImpl extends CommonServiceImpl<TaskMapper, Task> impleme
|
||||
instdto.setInstruction_type(task_type);
|
||||
instdto.setInstruction_id(IdUtil.simpleUUID());
|
||||
instdto.setRoute_plan_code(route_plan_code);
|
||||
instdto.setRemark(acsTask.getRemark());
|
||||
instdto.setRemark(acsTask.getRemark() != null ? acsTask.getRemark() + "该指令由人工创建" : "该指令由人工创建");
|
||||
instdto.setMaterial(acsTask.getMaterial());
|
||||
instdto.setQuantity(acsTask.getQuantity());
|
||||
instdto.setCar_type(car_type);
|
||||
@@ -959,7 +1071,6 @@ public class TaskServiceImpl extends CommonServiceImpl<TaskMapper, Task> impleme
|
||||
instdto.setAgv_system_type(agv_system_type);
|
||||
instdto.setAgv_inst_type(CommonFinalParam.ONE);
|
||||
instructionservice.create(instdto);
|
||||
|
||||
acsTask.setTask_status(CommonFinalParam.ONE);
|
||||
this.update(acsTask);
|
||||
return instdto;
|
||||
@@ -1354,32 +1465,35 @@ public class TaskServiceImpl extends CommonServiceImpl<TaskMapper, Task> impleme
|
||||
|
||||
@Override
|
||||
public List<JSONObject> getTaskList(Map whereJson) {
|
||||
whereJson.put("status", "2");
|
||||
LambdaQueryWrapper<Task> wrapper = getTaskLambdaQueryWrapper(whereJson);
|
||||
List<Task> taskList = taskMapper.selectList(wrapper);
|
||||
return Optional
|
||||
.ofNullable(taskList)
|
||||
.orElse(new ArrayList<>())
|
||||
.stream().sorted(Comparator.comparing(Task::getTo_x, Comparator.nullsLast(Comparator.naturalOrder())))
|
||||
Pageable page = PageRequest.of(0, 999999);
|
||||
JSONObject result = (JSONObject) getAll(whereJson, page);
|
||||
// 从结果中获取content数组
|
||||
JSONArray contentArray = result.getJSONArray("content");
|
||||
if (contentArray == null || contentArray.isEmpty()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
return contentArray.stream()
|
||||
.map(obj -> (JSONObject) obj)
|
||||
.sorted(Comparator.comparing(task -> task.getString("to_x"), Comparator.nullsLast(Comparator.naturalOrder())))
|
||||
.map(task -> {
|
||||
JSONObject ins = new JSONObject();
|
||||
ins.put("task_code", task.getTask_code());
|
||||
ins.put("task_type", "1".equals(task.getTask_type()) ? "入库" : "出库");
|
||||
ins.put("vehicle_code", task.getVehicle_code());
|
||||
ins.put("task_code", task.getString("task_code"));
|
||||
ins.put("task_type", "1".equals(task.getString("task_type")) ? "入库" : "出库");
|
||||
ins.put("vehicle_code", task.getString("vehicle_code"));
|
||||
ins.put("task_status", "完成");
|
||||
ins.put("priority", task.getPriority());
|
||||
ins.put("start_point_code", task.getStart_point_code());
|
||||
ins.put("next_point_code", task.getNext_point_code());
|
||||
ins.put("matarial", task.getMaterial());
|
||||
ins.put("quantity", task.getQuantity());
|
||||
ins.put("remark", task.getRemark());
|
||||
ins.put("create_by", task.getCreate_by());
|
||||
ins.put("create_time", task.getCreate_time());
|
||||
ins.put("car_no", task.getCar_no());
|
||||
ins.put("to_x", task.getTo_x());
|
||||
ins.put("to_y", task.getTo_y());
|
||||
ins.put("to_z", task.getTo_z());
|
||||
ins.put("update_time", task.getUpdate_time());
|
||||
ins.put("priority", task.getString("priority"));
|
||||
ins.put("start_point_code", task.getString("start_point_code"));
|
||||
ins.put("next_point_code", task.getString("next_point_code"));
|
||||
ins.put("matarial", task.getString("material"));
|
||||
ins.put("quantity", task.getString("quantity"));
|
||||
ins.put("remark", task.getString("remark"));
|
||||
ins.put("create_by", task.getString("create_by"));
|
||||
ins.put("create_time", task.getString("create_time"));
|
||||
ins.put("car_no", task.getString("car_no"));
|
||||
ins.put("to_x", task.getString("to_x"));
|
||||
ins.put("to_y", task.getString("to_y"));
|
||||
ins.put("to_z", task.getString("to_z"));
|
||||
ins.put("update_time", task.getString("update_time"));
|
||||
return ins;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
@@ -1589,7 +1703,6 @@ public class TaskServiceImpl extends CommonServiceImpl<TaskMapper, Task> impleme
|
||||
Collectors.mapping(durationCalculator, Collectors.toList())
|
||||
));
|
||||
long inTotal = inTaskMap.values().stream().mapToLong(List::size).sum();
|
||||
|
||||
// 出库任务 (type 2), 按start_point_code分组
|
||||
Map<String, List<Integer>> outTaskMap = taskList.stream()
|
||||
.filter(t -> "2".equals(t.getTask_type()))
|
||||
@@ -1618,10 +1731,10 @@ public class TaskServiceImpl extends CommonServiceImpl<TaskMapper, Task> impleme
|
||||
long c2 = durations.stream().filter(d -> d >= 3 && d < 5).count();
|
||||
long c3 = durations.stream().filter(d -> d >= 5 && d < 8).count();
|
||||
long c4 = durations.stream().filter(d -> d >= 8).count();
|
||||
result.put("item" + itemIndex, String.valueOf(c1 * 100 / total));
|
||||
result.put("item" + (itemIndex + 1), String.valueOf(c2 * 100 / total));
|
||||
result.put("item" + (itemIndex + 2), String.valueOf(c3 * 100 / total));
|
||||
result.put("item" + (itemIndex + 3), String.valueOf(c4 * 100 / total));
|
||||
result.put("AA-"+group+"-1-"+ (itemIndex), String.valueOf(c1 * 100 / total));
|
||||
result.put("AA-"+group+"-2-"+ (itemIndex + 1), String.valueOf(c2 * 100 / total));
|
||||
result.put("AA-"+group+"-3-"+ (itemIndex + 2), String.valueOf(c3 * 100 / total));
|
||||
result.put("AA-"+group+"-4-"+ (itemIndex + 3), String.valueOf(c4 * 100 / total));
|
||||
itemIndex += 4;
|
||||
}
|
||||
for (String group : groups) {
|
||||
@@ -1631,13 +1744,159 @@ public class TaskServiceImpl extends CommonServiceImpl<TaskMapper, Task> impleme
|
||||
long c2 = durations.stream().filter(d -> d >= 3 && d < 5).count();
|
||||
long c3 = durations.stream().filter(d -> d >= 5 && d < 8).count();
|
||||
long c4 = durations.stream().filter(d -> d >= 8).count();
|
||||
result.put("item" + itemIndex, String.valueOf(c1 * 100 / total));
|
||||
result.put("item" + (itemIndex + 1), String.valueOf(c2 * 100 / total));
|
||||
result.put("item" + (itemIndex + 2), String.valueOf(c3 * 100 / total));
|
||||
result.put("item" + (itemIndex + 3), String.valueOf(c4 * 100 / total));
|
||||
result.put(group+"-AA"+"-1-"+ (itemIndex), String.valueOf(c1 * 100 / total));
|
||||
result.put(group+"-AA"+"-2-"+ (itemIndex + 1), String.valueOf(c2 * 100 / total));
|
||||
result.put(group+"-AA"+"-3-"+ (itemIndex + 2), String.valueOf(c3 * 100 / total));
|
||||
result.put(group+"-AA"+"-4-"+ (itemIndex + 3), String.valueOf(c4 * 100 / total));
|
||||
itemIndex += 4;
|
||||
}
|
||||
// 稼动率统计
|
||||
// 1. getCar_no
|
||||
Map<String, List<Task>> carTaskMap = taskList.stream()
|
||||
.filter(t -> StrUtil.isNotEmpty(t.getCar_no()))
|
||||
.collect(Collectors.groupingBy(Task::getCar_no));
|
||||
// 2. 获取标准工作时间(分钟)
|
||||
long standardWorkingMinutes = getStandardWorkingMinutes(whereJson);
|
||||
// 3. 计算每辆车的统计数据
|
||||
int carIndex = 1;
|
||||
for (Map.Entry<String, List<Task>> entry : carTaskMap.entrySet()) {
|
||||
String carType = entry.getKey();
|
||||
List<Task> carTasks = entry.getValue();
|
||||
// 计算实际运行总时长(to_z累加,单位:分钟)
|
||||
// to_z格式为 "5.19" 表示 5分钟19秒,需要正确解析
|
||||
long totalRunningSeconds = carTasks.stream()
|
||||
.filter(t -> StrUtil.isNotEmpty(t.getTo_z()))
|
||||
.mapToLong(t -> {
|
||||
try {
|
||||
String[] parts = t.getTo_z().split("\\.");
|
||||
int minutes = Integer.parseInt(parts[0]);
|
||||
int seconds = parts.length > 1 ? Integer.parseInt(parts[1]) : 0;
|
||||
return minutes * 60 + seconds; // 转换为秒
|
||||
} catch (Exception e) {
|
||||
return 0L;
|
||||
}
|
||||
})
|
||||
.sum();
|
||||
long totalRunningMinutes = totalRunningSeconds / 60; // 转换为分钟
|
||||
// 任务数
|
||||
int taskCount = carTasks.size();
|
||||
// 计算稼动率(总时长/工作时间)
|
||||
int utilizationRate = standardWorkingMinutes > 0
|
||||
? (int) (totalRunningMinutes * 100 / standardWorkingMinutes)
|
||||
: 0;
|
||||
// 计算平均耗时(总秒数/任务数,单位:分钟)
|
||||
long avgSeconds = taskCount > 0 ? totalRunningSeconds / taskCount : 0;
|
||||
String avgTime = formatMinutes(avgSeconds / 60);
|
||||
// 格式化实际运行总时长
|
||||
String actualTimeStr = formatMinutes(totalRunningMinutes);
|
||||
String standardTimeStr = formatMinutes(standardWorkingMinutes);
|
||||
// 放入result
|
||||
result.put("car-" + carType + "-1", carType); // 车辆编号
|
||||
result.put("car-" + carType + "-2", actualTimeStr); // 实际运行总时长
|
||||
result.put("car-" + carType + "-3", standardTimeStr); // 标准工作时间
|
||||
result.put("car-" + carType + "-4", taskCount); // 总任务数
|
||||
result.put("car-" + carType + "-5", String.valueOf(utilizationRate)); // 稼动率
|
||||
result.put("car-" + carType + "-6", avgTime); // 平均耗时
|
||||
//carIndex += 5;
|
||||
}
|
||||
return Collections.singletonList(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取标准工作时间(分钟)
|
||||
* @param whereJson 查询参数,包含startDate和endDate
|
||||
* @return 标准工作总分钟数 = 每日标准工作时间 × 天数
|
||||
*/
|
||||
private long getStandardWorkingMinutes(Map whereJson) {
|
||||
try {
|
||||
// 获取每日标准工作时间(分钟)
|
||||
String workingTime = paramService.findByCode(AcsConfig.WORKINGTIME).getValue();
|
||||
if (StrUtil.isEmpty(workingTime)) {
|
||||
return 8 * 60; // 默认8小时
|
||||
}
|
||||
// 计算每日标准工作分钟数
|
||||
long dailyWorkingMinutes;
|
||||
if (workingTime.contains(".")) {
|
||||
// 格式如 8.30 表示 8小时30分钟
|
||||
String[] parts = workingTime.split("\\.");
|
||||
int hours = Integer.parseInt(parts[0]);
|
||||
int minutes = Integer.parseInt(parts[1]);
|
||||
dailyWorkingMinutes = hours * 60 + minutes;
|
||||
} else {
|
||||
// 纯小时数
|
||||
dailyWorkingMinutes = Long.parseLong(workingTime) * 60;
|
||||
}
|
||||
|
||||
// 计算时间范围的天数
|
||||
String create_time = (String) whereJson.get("startDate");
|
||||
String end_time = (String) whereJson.get("endDate");
|
||||
if (StrUtil.isEmpty(create_time) || StrUtil.isEmpty(end_time)) {
|
||||
// 默认当天,天数为1
|
||||
return dailyWorkingMinutes * 1;
|
||||
}
|
||||
|
||||
// 处理日期格式
|
||||
if (create_time.length() == 10) {
|
||||
create_time += " 00:00:00";
|
||||
}
|
||||
if (end_time.length() == 10) {
|
||||
end_time += " 23:59:59";
|
||||
}
|
||||
|
||||
// 计算天数差
|
||||
try {
|
||||
Date start = DateUtil.parse(create_time);
|
||||
Date end = DateUtil.parse(end_time);
|
||||
long days = (end.getTime() - start.getTime()) / (1000L * 60 * 60 * 24) + 1; // +1 包含当天
|
||||
if (days <= 0) {
|
||||
days = 1;
|
||||
}
|
||||
return dailyWorkingMinutes * days;
|
||||
} catch (Exception e) {
|
||||
return dailyWorkingMinutes * 1;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return 8 * 60; // 默认8小时
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将分钟格式化为 小时h分钟m 的字符串
|
||||
*/
|
||||
private String formatMinutes(long minutes) {
|
||||
if (minutes <= 0) {
|
||||
return "0m";
|
||||
}
|
||||
long hours = minutes / 60;
|
||||
long mins = minutes % 60;
|
||||
if (hours > 0 && mins > 0) {
|
||||
return hours + "h" + mins + "m";
|
||||
} else if (hours > 0) {
|
||||
return hours + "h";
|
||||
} else {
|
||||
return mins + "m";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 计算任务持续时间(分钟)
|
||||
* @param startTime 开始时间字符串
|
||||
* @param endTime 结束时间字符串
|
||||
* @return 分钟数,计算失败返回null
|
||||
*/
|
||||
private Double calculateDuration(String startTime, String endTime) {
|
||||
if (StrUtil.isEmpty(startTime) || StrUtil.isEmpty(endTime)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
Date start = DateUtil.parse(startTime);
|
||||
Date end = DateUtil.parse(endTime);
|
||||
long diffMillis = end.getTime() - start.getTime();
|
||||
return diffMillis / (1000.0 * 60);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -106,5 +106,19 @@ public class SysDictController {
|
||||
return new ResponseEntity<>(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@GetMapping("/showDetail2")
|
||||
@Log("查询字典明细")
|
||||
public ResponseEntity<Object> showDetail2(@RequestParam String name){
|
||||
return new ResponseEntity<>(dictService.getDictByName(name), HttpStatus.OK);
|
||||
}
|
||||
|
||||
@PostMapping("/initDict")
|
||||
@Log("初始化字典")
|
||||
public ResponseEntity<Object> initDict(@Validated @RequestBody Dict dto){
|
||||
dictService.initDict(dto);
|
||||
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -69,6 +69,14 @@ class SysParamController {
|
||||
return new ResponseEntity<>(paramService.findByCode(code), HttpStatus.CREATED);
|
||||
}
|
||||
|
||||
@PostMapping("/setParam")
|
||||
@Log("保存参数")
|
||||
@SaIgnore
|
||||
public ResponseEntity<Object> setParam(@RequestBody Map whereJson) {
|
||||
paramService.setParam(whereJson);
|
||||
return new ResponseEntity<>(HttpStatus.OK);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -62,6 +62,15 @@ public interface ISysDictService extends IService<Dict> {
|
||||
*/
|
||||
List<Dict> getDictByName(String name);
|
||||
|
||||
void initDict(Dict dto);
|
||||
|
||||
/**
|
||||
* 获取字典明细
|
||||
* @param code
|
||||
* @return
|
||||
*/
|
||||
List<Dict> getDictDetail(String code);
|
||||
|
||||
/**
|
||||
* 添加字典明细
|
||||
* @param resources
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
package org.nl.system.service.dict.dao.mapper;
|
||||
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
import org.nl.system.service.dict.dao.Dict;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 字典表 Mapper 接口
|
||||
@@ -13,4 +16,7 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
*/
|
||||
public interface SysDictMapper extends BaseMapper<Dict> {
|
||||
|
||||
@Select("select dict_id,label,value from sys_dict_detail where dict_id = #{code}")
|
||||
List<Dict> getDictDetail(String code);
|
||||
|
||||
}
|
||||
|
||||
@@ -124,6 +124,10 @@ public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, Dict> impleme
|
||||
.ne(Dict::getLabel, ""));
|
||||
return dictList;
|
||||
}
|
||||
@Override
|
||||
public List<Dict> getDictDetail(String code){
|
||||
return sysDictMapper.getDictDetail(code);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@@ -189,9 +193,28 @@ public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, Dict> impleme
|
||||
@Override
|
||||
public List<Dict> queryAll() {
|
||||
return sysDictMapper.selectList(new QueryWrapper<Dict>()
|
||||
.select("MAX(dict_id) AS dictId, code, name")
|
||||
.select("MAX(dict_id) AS dict_id, code, name")
|
||||
.lambda()
|
||||
.groupBy(Dict::getCode, Dict::getName));
|
||||
}
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void initDict(Dict dto) {
|
||||
Dict dict = sysDictMapper.selectById(dto.getDict_id());
|
||||
if (ObjectUtil.isEmpty(dict)) {
|
||||
throw new BadRequestException("字典不存在");
|
||||
}
|
||||
String currentUserId = SecurityUtils.getCurrentUserId();
|
||||
String currentNickName = SecurityUtils.getCurrentNickName();
|
||||
dict.setValue("0");
|
||||
dict.setPara2("");
|
||||
dict.setPara3("充电桩空闲");
|
||||
dict.setUpdate_id(currentUserId);
|
||||
dict.setUpdate_name(currentNickName);
|
||||
dict.setUpdate_time(DateUtil.now());
|
||||
sysDictMapper.updateById(dict);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -60,4 +60,6 @@ public interface ISysParamService extends IService<Param> {
|
||||
*/
|
||||
/*@Cached(name = "paramDataCode.", key = "#code", expire = 3600, cacheType = CacheType.REMOTE)*/
|
||||
Param findByCode(String code);
|
||||
|
||||
void setParam(Map whereJson);
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.nl.acs.AcsConfig;
|
||||
import org.nl.common.domain.query.PageQuery;
|
||||
import org.nl.common.exception.BadRequestException;
|
||||
import org.nl.common.utils.SecurityUtils;
|
||||
@@ -98,4 +99,47 @@ public class SysParamServiceImpl extends ServiceImpl<SysParamMapper, Param> impl
|
||||
Param param = paramMapper.selectOne(queryWrapper);
|
||||
return param;
|
||||
}
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void setParam(Map whereJson){
|
||||
Integer electric = (Integer) whereJson.get("electric");
|
||||
Integer electric2 = (Integer) whereJson.get("electric2");
|
||||
String electric_begin = (String) whereJson.get("electric_begin");
|
||||
String electric_end = (String) whereJson.get("electric_end");
|
||||
|
||||
String now_time = DateUtil.now();
|
||||
//白班充电阈值
|
||||
Param param_electric = this.findByCode(AcsConfig.ELECTRIC);
|
||||
if (ObjectUtil.isEmpty(param_electric)) throw new BadRequestException("白班充电阈值参数异常");
|
||||
param_electric.setValue(electric.toString());
|
||||
param_electric.setUpdate_id(SecurityUtils.getCurrentUserId());
|
||||
param_electric.setUpdate_name(SecurityUtils.getCurrentNickName());
|
||||
param_electric.setUpdate_time(now_time);
|
||||
paramMapper.updateById(param_electric);
|
||||
//晚班充电阈值
|
||||
Param param_electric2 = this.findByCode(AcsConfig.ELECTRIC2);
|
||||
if (ObjectUtil.isEmpty(param_electric2)) throw new BadRequestException("晚班充电阈值参数异常");
|
||||
param_electric2.setValue(electric2.toString());
|
||||
param_electric2.setUpdate_id(SecurityUtils.getCurrentUserId());
|
||||
param_electric2.setUpdate_name(SecurityUtils.getCurrentNickName());
|
||||
param_electric2.setUpdate_time(now_time);
|
||||
paramMapper.updateById(param_electric2);
|
||||
//白班开始时间
|
||||
Param param_electric_begin = this.findByCode(AcsConfig.ELECTRIC_BEGIN);
|
||||
if (ObjectUtil.isEmpty(param_electric_begin)) throw new BadRequestException("白班开始时间参数异常");
|
||||
param_electric_begin.setValue(electric_begin);
|
||||
param_electric_begin.setUpdate_id(SecurityUtils.getCurrentUserId());
|
||||
param_electric_begin.setUpdate_name(SecurityUtils.getCurrentNickName());
|
||||
param_electric_begin.setUpdate_time(now_time);
|
||||
paramMapper.updateById(param_electric_begin);
|
||||
//白班结束时间
|
||||
Param param_electric_end = this.findByCode(AcsConfig.ELECTRIC_END);
|
||||
if (ObjectUtil.isEmpty(param_electric_end)) throw new BadRequestException("白班开始时间参数异常");
|
||||
param_electric_end.setValue(electric_end);
|
||||
param_electric_end.setUpdate_id(SecurityUtils.getCurrentUserId());
|
||||
param_electric_end.setUpdate_name(SecurityUtils.getCurrentNickName());
|
||||
param_electric_end.setUpdate_time(now_time);
|
||||
paramMapper.updateById(param_electric_end);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,24 +15,18 @@ import org.nl.acs.instruction.enums.InstructionStatusEnum;
|
||||
import org.nl.acs.instruction.service.InstructionService;
|
||||
import org.nl.acs.instruction.service.mapper.InstructionMapper;
|
||||
import org.nl.acs.opc.DeviceAppService;
|
||||
import org.nl.acs.opc.DeviceAppServiceImpl;
|
||||
import org.nl.acs.task.enums.TaskStatusEnum;
|
||||
import org.nl.acs.task.enums.TaskTypeEnum;
|
||||
import org.nl.acs.task.service.TaskService;
|
||||
import org.nl.acs.task.service.dto.TaskDto;
|
||||
import org.nl.common.utils.SecurityUtils;
|
||||
import org.nl.config.SpringContextHolder;
|
||||
import org.nl.system.service.lucene.LuceneExecuteLogService;
|
||||
import org.nl.system.service.lucene.dto.LuceneLogDto;
|
||||
import org.nl.system.service.lucene.impl.LuceneExecuteLogServiceImpl;
|
||||
import org.nl.system.service.param.ISysParamService;
|
||||
import org.redisson.api.RLock;
|
||||
import org.redisson.api.RedissonClient;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@@ -60,14 +54,7 @@ public class AutoCreateInst {
|
||||
RLock lock = redissonClient.getLock("autoGenInstructionLock");
|
||||
boolean locked = false;
|
||||
try {
|
||||
String maxPsnumber = paramService.findByCode(AcsConfig.MAXINSTNUMBER).getValue();
|
||||
String maxRtNumber = paramService.findByCode(AcsConfig.MAXRTINSTNUMBER).getValue();
|
||||
int maxPsInst = Integer.parseInt(maxPsnumber);
|
||||
int maxRtnst = Integer.parseInt(maxRtNumber);
|
||||
int rtInstNum = 0;
|
||||
int psInstNum = 0;
|
||||
long estimatedTime = (maxPsInst + maxRtnst) * 5L + 10;
|
||||
locked = lock.tryLock(0, estimatedTime, TimeUnit.SECONDS);
|
||||
locked = lock.tryLock(0, TimeUnit.SECONDS);
|
||||
if (!locked) {
|
||||
//log.debug("未获取到分布式锁,跳过本次执行");
|
||||
return;
|
||||
@@ -77,24 +64,24 @@ public class AutoCreateInst {
|
||||
if (CollectionUtils.isEmpty(list)) {
|
||||
return;
|
||||
}
|
||||
List<TaskDto> pslist = list.stream().filter(r -> !"2".equals(r.getCar_type())).collect(Collectors.toList());
|
||||
List<TaskDto> rtlist = list.stream().filter(r -> "2".equals(r.getCar_type())).collect(Collectors.toList());
|
||||
String maxPsnumber = paramService.findByCode(AcsConfig.MAXINSTNUMBER).getValue();
|
||||
String maxRtNumber = paramService.findByCode(AcsConfig.MAXRTINSTNUMBER).getValue();
|
||||
int maxPsInst = Integer.parseInt(maxPsnumber);
|
||||
int maxRtnst = Integer.parseInt(maxRtNumber);
|
||||
int rtInstNum = 0;
|
||||
int psInstNum = 0;
|
||||
//已创建
|
||||
List<InstructionMybatis> instructionList = new LambdaQueryChainWrapper<>(instructionMapper)
|
||||
.lt(InstructionMybatis::getInstruction_status, InstructionStatusEnum.FINISHED.getIndex())
|
||||
.list();
|
||||
//2个车型各创建的任务数
|
||||
if (ObjectUtil.isNotEmpty(instructionList)) {
|
||||
rtInstNum = Math.toIntExact(instructionList.stream().filter(r -> "2".equals(r.getCar_type())).count());
|
||||
psInstNum = instructionList.size() - rtInstNum;
|
||||
}
|
||||
if (ObjectUtil.isNotEmpty(pslist)) {
|
||||
maxPsInst = Math.max(0, maxPsInst - psInstNum);
|
||||
createInstruction(pslist, maxPsInst);
|
||||
}
|
||||
if (ObjectUtil.isNotEmpty(rtlist)) {
|
||||
maxRtnst = Math.max(0, maxRtnst - rtInstNum);
|
||||
createInstruction(rtlist, maxRtnst);
|
||||
}
|
||||
maxRtnst = Math.max(0, maxRtnst - rtInstNum);
|
||||
maxPsInst = Math.max(0, maxPsInst - psInstNum);
|
||||
createInstruction(list, maxPsInst, maxRtnst);
|
||||
} catch (Exception e) {
|
||||
log.error("自动生成指令异常", e);
|
||||
} finally {
|
||||
@@ -109,136 +96,64 @@ public class AutoCreateInst {
|
||||
}
|
||||
|
||||
|
||||
private void createInstruction(List<TaskDto> list, int maxNum) throws InterruptedException {
|
||||
int createdCount = 0;
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
//每次循环前检查本次已创建指令数是否达到上限
|
||||
if (createdCount >= maxNum) {
|
||||
break;
|
||||
}
|
||||
TaskDto acsTask = list.get(i);
|
||||
Boolean flag = false;
|
||||
String taskid = acsTask.getTask_id();
|
||||
String taskcode = acsTask.getTask_code();
|
||||
String task_type = acsTask.getTask_type();
|
||||
String vehiclecode = acsTask.getVehicle_code();
|
||||
String priority = acsTask.getPriority();
|
||||
String is_send = acsTask.getIs_send();
|
||||
private void createInstruction(List<TaskDto> list, int maxPsNum, int maxRtNum) throws InterruptedException {
|
||||
int psCreatedCount = 0;
|
||||
int rtCreatedCount = 0;
|
||||
// 记录被阻断的起点,该起点上的后续任务一律不创建防止插
|
||||
Set<String> blockedPoints = new HashSet<>();
|
||||
Iterator<TaskDto> iterator = list.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
TaskDto acsTask = iterator.next();
|
||||
String car_type = acsTask.getCar_type();
|
||||
// 判断是否为起点任务,NPE
|
||||
String start_device_code = acsTask.getStart_device_code();
|
||||
boolean isStartTask = start_device_code != null &&
|
||||
(start_device_code.contains("BCPRK") || start_device_code.contains("CPRK"));
|
||||
String start_point = null;
|
||||
if (start_device_code.contains("BCPRK")) {
|
||||
String[] parts = start_device_code.split("-", 2);
|
||||
start_point = parts[0];
|
||||
} else if (start_device_code.contains("CPRK")) {
|
||||
String[] parts = start_device_code.split("-", 2);
|
||||
start_point = parts[0];
|
||||
if (isStartTask) {
|
||||
start_point = start_device_code.split("-", 2)[0];
|
||||
}
|
||||
if (start_point != null) {
|
||||
if (start_point.equals("CPRK1")) {
|
||||
List<TaskDto> list1 = taskserver.queryAllByStatus("1");
|
||||
for (int j = 0; j < list1.size(); j++) {
|
||||
String start_device_code1 = list1.get(j).getStart_device_code();
|
||||
String[] parts = start_device_code1.split("-", 2);
|
||||
start_point = parts[0];
|
||||
if (start_point.equals("CPRK1")) {
|
||||
flag = true;
|
||||
}
|
||||
}
|
||||
} else if (start_point.equals("CPRK2")) {
|
||||
List<TaskDto> list1 = taskserver.queryAllByStatus("1");
|
||||
for (int j = 0; j < list1.size(); j++) {
|
||||
String start_device_code1 = list1.get(j).getStart_device_code();
|
||||
String[] parts = start_device_code1.split("-", 2);
|
||||
start_point = parts[0];
|
||||
if (start_point.equals("CPRK2")) {
|
||||
flag = true;
|
||||
}
|
||||
}
|
||||
} else if (start_point.equals("CPRK3")) {
|
||||
List<TaskDto> list1 = taskserver.queryAllByStatus("1");
|
||||
for (int j = 0; j < list1.size(); j++) {
|
||||
String start_device_code1 = list1.get(j).getStart_device_code();
|
||||
String[] parts = start_device_code1.split("-", 2);
|
||||
start_point = parts[0];
|
||||
if (start_point.equals("CPRK3")) {
|
||||
flag = true;
|
||||
}
|
||||
}
|
||||
} else if (start_point.equals("CPRK4")) {
|
||||
List<TaskDto> list1 = taskserver.queryAllByStatus("1");
|
||||
for (int j = 0; j < list1.size(); j++) {
|
||||
String start_device_code1 = list1.get(j).getStart_device_code();
|
||||
String[] parts = start_device_code1.split("-", 2);
|
||||
start_point = parts[0];
|
||||
if (start_point.equals("CPRK4")) {
|
||||
flag = true;
|
||||
}
|
||||
}
|
||||
} else if (start_point.equals("CPRK5")) {
|
||||
List<TaskDto> list1 = taskserver.queryAllByStatus("1");
|
||||
for (int j = 0; j < list1.size(); j++) {
|
||||
String start_device_code1 = list1.get(j).getStart_device_code();
|
||||
String[] parts = start_device_code1.split("-", 2);
|
||||
start_point = parts[0];
|
||||
if (start_point.equals("CPRK5")) {
|
||||
flag = true;
|
||||
}
|
||||
}
|
||||
} else if (start_point.equals("BCPRK1")) {
|
||||
List<TaskDto> list1 = taskserver.queryAllByStatus("1");
|
||||
for (int j = 0; j < list1.size(); j++) {
|
||||
String start_device_code1 = list1.get(j).getStart_device_code();
|
||||
String[] parts = start_device_code1.split("-", 2);
|
||||
start_point = parts[0];
|
||||
if (start_point.equals("BCPRK1")) {
|
||||
flag = true;
|
||||
}
|
||||
}
|
||||
} else if (start_point.equals("BCPRK2")) {
|
||||
List<TaskDto> list1 = taskserver.queryAllByStatus("1");
|
||||
for (int j = 0; j < list1.size(); j++) {
|
||||
String start_device_code1 = list1.get(j).getStart_device_code();
|
||||
String[] parts = start_device_code1.split("-", 2);
|
||||
start_point = parts[0];
|
||||
if (start_point.equals("BCPRK2")) {
|
||||
flag = true;
|
||||
}
|
||||
}
|
||||
} else if (start_point.equals("BCPRK3")) {
|
||||
List<TaskDto> list1 = taskserver.queryAllByStatus("1");
|
||||
for (int j = 0; j < list1.size(); j++) {
|
||||
String start_device_code1 = list1.get(j).getStart_device_code();
|
||||
String[] parts = start_device_code1.split("-", 2);
|
||||
start_point = parts[0];
|
||||
if (start_point.equals("BCPRK3")) {
|
||||
flag = true;
|
||||
}
|
||||
}
|
||||
} else if (start_point.equals("BCPRK4")) {
|
||||
List<TaskDto> list1 = taskserver.queryAllByStatus("1");
|
||||
for (int j = 0; j < list1.size(); j++) {
|
||||
String start_device_code1 = list1.get(j).getStart_device_code();
|
||||
String[] parts = start_device_code1.split("-", 2);
|
||||
start_point = parts[0];
|
||||
if (start_point.equals("BCPRK4")) {
|
||||
flag = true;
|
||||
}
|
||||
}
|
||||
} else if (start_point.equals("BCPRK5")) {
|
||||
List<TaskDto> list1 = taskserver.queryAllByStatus("1");
|
||||
for (int j = 0; j < list1.size(); j++) {
|
||||
String start_device_code1 = list1.get(j).getStart_device_code();
|
||||
String[] parts = start_device_code1.split("-", 2);
|
||||
start_point = parts[0];
|
||||
if (start_point.equals("BCPRK5")) {
|
||||
flag = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (flag) {
|
||||
//如果当前起点已被阻断,直接移除任务并跳过
|
||||
if (isStartTask && blockedPoints.contains(start_point)) {
|
||||
iterator.remove();
|
||||
continue;
|
||||
}
|
||||
//型上限检查
|
||||
boolean reachLimit = false;
|
||||
if ("2".equals(car_type) && rtCreatedCount >= maxRtNum) {
|
||||
reachLimit = true;
|
||||
} else if (!"2".equals(car_type) && psCreatedCount >= maxPsNum) {
|
||||
reachLimit = true;
|
||||
}
|
||||
if (reachLimit) {
|
||||
iterator.remove();
|
||||
if (isStartTask) {
|
||||
blockedPoints.add(start_point);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (StrUtil.equals(acsTask.getIs_send(), "0")) {
|
||||
iterator.remove();
|
||||
if (isStartTask) {
|
||||
blockedPoints.add(start_point);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
List<InstructionMybatis> activeInstructions = new LambdaQueryChainWrapper<>(instructionMapper)
|
||||
.lt(InstructionMybatis::getInstruction_status, InstructionStatusEnum.FINISHED.getIndex())
|
||||
.eq(InstructionMybatis::getIs_delete, "0")
|
||||
.list();
|
||||
//起点重复检查
|
||||
if (isStartTask && checkinsList(activeInstructions, start_point)) {
|
||||
blockedPoints.add(start_point);
|
||||
iterator.remove();
|
||||
continue;
|
||||
}
|
||||
String taskid = acsTask.getTask_id();
|
||||
String taskcode = acsTask.getTask_code();
|
||||
String vehiclecode = acsTask.getVehicle_code();
|
||||
String priority = acsTask.getPriority();
|
||||
String task_type = acsTask.getTask_type();
|
||||
String start_point_code = acsTask.getStart_point_code();
|
||||
String put_device_code = acsTask.getPut_device_code();
|
||||
String put_point_code = acsTask.getPut_point_code();
|
||||
@@ -249,11 +164,7 @@ public class AutoCreateInst {
|
||||
String agv_system_type = acsTask.getAgv_system_type();
|
||||
String start_height = acsTask.getStart_height();
|
||||
String next_height = acsTask.getNext_height();
|
||||
String car_type = acsTask.getCar_type();
|
||||
String car_width = acsTask.getCar_width();
|
||||
if (StrUtil.equals(is_send, "0")) {
|
||||
continue;
|
||||
}
|
||||
if (StrUtil.equals(appService.findDeviceTypeByCode(next_device_code), "storage")) {
|
||||
next_point_code = next_device_code + "-" + acsTask.getTo_y() + "-" + acsTask.getTo_z();
|
||||
} else {
|
||||
@@ -287,6 +198,7 @@ public class AutoCreateInst {
|
||||
instdto.setAgv_system_type(agv_system_type);
|
||||
instdto.setStart_height(start_height);
|
||||
instdto.setNext_height(next_height);
|
||||
instdto.setRemark(acsTask.getRemark());
|
||||
try {
|
||||
instructionService.create(instdto);
|
||||
} catch (Exception e) {
|
||||
@@ -300,152 +212,31 @@ public class AutoCreateInst {
|
||||
luceneExecuteLogService.deviceExecuteLog(logDto);
|
||||
continue;
|
||||
}
|
||||
TimeUnit.SECONDS.sleep(5);
|
||||
//创建指令后修改任务状态
|
||||
acsTask.setTask_status(TaskStatusEnum.BUSY.getIndex());
|
||||
acsTask.setUpdate_time(DateUtil.now());
|
||||
taskserver.update(acsTask);
|
||||
log.info("自动生成指令成功: {},{}", DateUtil.now(), acsTask.getTask_code());
|
||||
createdCount++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 根据任务状态创建指令、生成下一条指令
|
||||
*/
|
||||
public void run1() throws Exception {
|
||||
//log.info("自动生成指令开始: {}", DateUtil.now());
|
||||
RLock lock = redissonClient.getLock("autoGenInstructionLock");
|
||||
boolean locked = false;
|
||||
try {
|
||||
locked = lock.tryLock(0, 5, TimeUnit.SECONDS); // 不等待,锁持有5秒自动释放
|
||||
if (!locked) {
|
||||
//log.debug("未获取到分布式锁,跳过本次执行");
|
||||
return;
|
||||
}
|
||||
TaskService taskserver = SpringContextHolder.getBean(TaskService.class);
|
||||
InstructionService instructionService = SpringContextHolder.getBean(InstructionService.class);
|
||||
DeviceAppService appService = SpringContextHolder.getBean(DeviceAppServiceImpl.class);
|
||||
LuceneExecuteLogService luceneExecuteLogService = SpringContextHolder.getBean(LuceneExecuteLogServiceImpl.class);
|
||||
//按优先级降序task_code升序
|
||||
List<TaskDto> list = taskserver.queryAllByStatus("0");
|
||||
if (CollectionUtils.isEmpty(list)) {
|
||||
return;
|
||||
}
|
||||
Set<String> busyStartPoints = taskserver.queryAllByStatus("1").stream()
|
||||
.map(t -> extractStartPoint(t.getStart_device_code()))
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toSet());
|
||||
for (TaskDto acsTask : list) {
|
||||
if (isNonBlockingTaskType(acsTask)) {
|
||||
continue; // AGV/Truss且不以"-"开头,跳过,继续看下一个
|
||||
}
|
||||
if (StrUtil.equals(acsTask.getIs_send(), "0")) {
|
||||
break;
|
||||
}
|
||||
//起始点冲突(同一起点已有执行中任务)
|
||||
String startPoint = extractStartPoint(acsTask.getStart_device_code());
|
||||
if (startPoint != null && busyStartPoints.contains(startPoint)) {
|
||||
break;
|
||||
}
|
||||
try {
|
||||
createInstruction(acsTask, appService, instructionService, taskserver);
|
||||
} catch (Exception e) {
|
||||
acsTask.setRemark(e.getMessage());
|
||||
taskserver.updateByCodeFromCache(acsTask);
|
||||
LuceneLogDto logDto = LuceneLogDto.builder()
|
||||
.device_code("定时创建指令失败")
|
||||
.content(e.getMessage())
|
||||
.build();
|
||||
logDto.setLog_level(2);
|
||||
luceneExecuteLogService.deviceExecuteLog(logDto);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("自动生成指令异常", e);
|
||||
} finally {
|
||||
if (locked && lock.isHeldByCurrentThread()) {
|
||||
try {
|
||||
lock.unlock();
|
||||
} catch (Exception e) {
|
||||
log.error("释放分布式锁异常", e);
|
||||
}
|
||||
if ("2".equals(car_type)) {
|
||||
rtCreatedCount++;
|
||||
} else {
|
||||
psCreatedCount++;
|
||||
}
|
||||
TimeUnit.SECONDS.sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否属于无需生成指令的任务类型
|
||||
*/
|
||||
private boolean isNonBlockingTaskType(TaskDto acsTask) {
|
||||
String taskType = acsTask.getTask_type();
|
||||
String taskCode = acsTask.getTask_code();
|
||||
boolean isAgv = StrUtil.equals(taskType, TaskTypeEnum.AGV_Task.getIndex())
|
||||
&& !StrUtil.startWith(taskCode, "-");
|
||||
boolean isTruss = StrUtil.equals(taskType, TaskTypeEnum.Truss_Task.getIndex())
|
||||
&& !StrUtil.startWith(taskCode, "-");
|
||||
return isAgv || isTruss;
|
||||
private boolean checkinsList(List<InstructionMybatis> instructList, String targetPoint) {
|
||||
if (instructList == null || targetPoint == null) {
|
||||
return false;
|
||||
}
|
||||
return instructList.stream().anyMatch(r -> {
|
||||
String code = r.getStart_device_code();
|
||||
if (code == null) return false;
|
||||
String[] parts = code.split("-", 2);
|
||||
return targetPoint.equals(parts[0]);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 从设备编码中提取起点区域CPRK1, BCPRK2
|
||||
*/
|
||||
private String extractStartPoint(String startDeviceCode) {
|
||||
if (startDeviceCode == null) {
|
||||
return null;
|
||||
}
|
||||
if (startDeviceCode.contains("BCPRK") || startDeviceCode.contains("CPRK")) {
|
||||
return startDeviceCode.split("-")[0];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 封装指令创建与任务状态更新
|
||||
*/
|
||||
private void createInstruction(TaskDto acsTask, DeviceAppService appService,
|
||||
InstructionService instructionService, TaskService taskserver) throws Exception {
|
||||
String next_device_code = acsTask.getNext_device_code();
|
||||
String next_point_code;
|
||||
if (StrUtil.equals(appService.findDeviceTypeByCode(next_device_code), "storage")) {
|
||||
next_point_code = next_device_code + "-" + acsTask.getTo_y() + "-" + acsTask.getTo_z();
|
||||
} else {
|
||||
next_point_code = next_device_code;
|
||||
}
|
||||
Instruction instdto = new Instruction();
|
||||
instdto.setInstruction_type(acsTask.getTask_type());
|
||||
instdto.setInstruction_id(IdUtil.simpleUUID());
|
||||
instdto.setRoute_plan_code(acsTask.getRoute_plan_code());
|
||||
instdto.setRemark(acsTask.getRemark());
|
||||
instdto.setMaterial(acsTask.getMaterial());
|
||||
instdto.setQuantity(acsTask.getQuantity());
|
||||
instdto.setTask_id(acsTask.getTask_id());
|
||||
instdto.setTask_code(acsTask.getTask_code());
|
||||
instdto.setVehicle_code(acsTask.getVehicle_code());
|
||||
instdto.setCreate_time(DateUtil.now());
|
||||
instdto.setCreate_by(SecurityUtils.getCurrentNickName());
|
||||
instdto.setStart_device_code(acsTask.getStart_point_code());
|
||||
instdto.setStart_point_code(acsTask.getStart_point_code());
|
||||
instdto.setPut_device_code(acsTask.getPut_device_code());
|
||||
instdto.setPut_point_code(acsTask.getPut_point_code());
|
||||
instdto.setNext_device_code(next_device_code);
|
||||
instdto.setNext_point_code(next_point_code);
|
||||
instdto.setCar_type(acsTask.getCar_type());
|
||||
instdto.setCar_width(acsTask.getCar_width());
|
||||
instdto.setPriority(acsTask.getPriority());
|
||||
instdto.setInstruction_status(InstructionStatusEnum.READY.getIndex());
|
||||
instdto.setExecute_device_code(acsTask.getStart_point_code());
|
||||
instdto.setVehicle_type(acsTask.getVehicle_type());
|
||||
instdto.setAgv_system_type(acsTask.getAgv_system_type());
|
||||
instdto.setStart_height(acsTask.getStart_height());
|
||||
instdto.setNext_height(acsTask.getNext_height());
|
||||
instructionService.create(instdto);
|
||||
// 更新任务状态为执行中
|
||||
acsTask.setTask_status(TaskStatusEnum.BUSY.getIndex());
|
||||
acsTask.setUpdate_time(DateUtil.now());
|
||||
taskserver.update(acsTask);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user