opt:一期内容优化;

This commit is contained in:
2026-06-10 17:56:14 +08:00
parent eca0edad64
commit 02432faa17
27 changed files with 1500 additions and 480 deletions

View File

@@ -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>

View File

@@ -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";
}

View File

@@ -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]));
}

View File

@@ -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);
}
}
}

View File

@@ -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);

View File

@@ -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

View File

@@ -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);
/**
* 多选删除
*

View File

@@ -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;
}
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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);
}
}

View File

@@ -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);
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}