From 0b44fe4743ffa6ba7961e6ee9f361d9c1f580869 Mon Sep 17 00:00:00 2001 From: liyongde <1419499670@qq.com> Date: Tue, 21 Apr 2026 15:32:45 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=8B=86=E5=8D=95AGV=E4=BB=BB=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tasks/slitter/SendDisassemblyAgvTask.java | 208 ++++++++++++++++++ .../tasks/slitter/TrussSendAirShaftTask.java | 5 + .../slitter/auto/AutoSendAirShaftAgvTask.java | 67 +++++- .../tasks/slitter/constant/SlitterEnum.java | 2 +- .../tasks/slitter/mapper/SlitterMapper.java | 2 + .../tasks/slitter/mapper/SlitterMapper.xml | 16 ++ .../tasks/slitter/util/SlitterTaskUtil.java | 29 +++ 7 files changed, 327 insertions(+), 2 deletions(-) create mode 100644 lms/nladmin-system/src/main/java/org/nl/b_lms/sch/tasks/slitter/SendDisassemblyAgvTask.java diff --git a/lms/nladmin-system/src/main/java/org/nl/b_lms/sch/tasks/slitter/SendDisassemblyAgvTask.java b/lms/nladmin-system/src/main/java/org/nl/b_lms/sch/tasks/slitter/SendDisassemblyAgvTask.java new file mode 100644 index 000000000..e24c9cd78 --- /dev/null +++ b/lms/nladmin-system/src/main/java/org/nl/b_lms/sch/tasks/slitter/SendDisassemblyAgvTask.java @@ -0,0 +1,208 @@ +package org.nl.b_lms.sch.tasks.slitter; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import lombok.extern.slf4j.Slf4j; +import org.nl.b_lms.bst.ivt.cutpointivt.service.IBstIvtCutpointivtService; +import org.nl.b_lms.bst.ivt.cutpointivt.service.dao.BstIvtCutpointivt; +import org.nl.b_lms.pdm.bi.slittingproductionplan.service.IPdmBiSlittingproductionplanService; +import org.nl.b_lms.pdm.bi.slittingproductionplan.service.dao.PdmBiSlittingproductionplan; +import org.nl.b_lms.sch.task.dao.SchBaseTask; +import org.nl.b_lms.sch.task.service.IschBaseTaskService; +import org.nl.b_lms.sch.tasks.slitter.constant.SlitterConstant; +import org.nl.b_lms.storage_manage.ios.enums.IOSEnum; +import org.nl.common.utils.IdUtil; +import org.nl.common.utils.SecurityUtils; +import org.nl.common.utils.TaskUtils; +import org.nl.modules.wql.WQL; +import org.nl.modules.wql.core.bean.WQLObject; +import org.nl.wms.sch.AcsTaskDto; +import org.nl.wms.sch.manage.AbstractAcsTask; +import org.nl.wms.sch.manage.TaskStatusEnum; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * 送气胀轴拆单AGV任务 + * @Author: liyongde + * @Date: 2026/4/21 14:47 + */ +@Slf4j +@Service +public class SendDisassemblyAgvTask extends AbstractAcsTask { + private final String THIS_CLASS = SendAirShaftAgvTask.class.getName(); + @Autowired + private IschBaseTaskService taskService; + @Autowired + private IPdmBiSlittingproductionplanService slittingproductionplanService; + @Autowired + private IBstIvtCutpointivtService bcutpointivtService; + + @Override + public List addTask() { + /* + * 下发给ACS时需要特殊处理 + */ + ArrayList resultList = new ArrayList<>(); + String agv_system_type = "2"; + List taskList = taskService.getIssueTasks(THIS_CLASS); + for (SchBaseTask task : taskList) { + AcsTaskDto dto = AcsTaskDto.builder() + .ext_task_id(task.getTask_id()) + .task_code(task.getTask_code()) + .task_type(task.getAcs_task_type()) + .start_device_code(task.getPoint_code1()) + .next_device_code(task.getPoint_code2()) + .start_device_code2(task.getPoint_code3()) + .next_device_code2(task.getPoint_code4()) + .vehicle_code(task.getVehicle_code()) + .agv_system_type(agv_system_type) + .priority(task.getPriority()) + .remark(task.getRemark()) + .product_area(task.getProduct_area()) + .build(); + resultList.add(dto); + } + return resultList; + } + + /** + * 单任务下发,业务逻辑与无参 addTask 保持一致 + */ + @Override + public List addTask(SchBaseTask task) { + ArrayList resultList = new ArrayList<>(); + String agv_system_type = "2"; + if (task != null) { + AcsTaskDto dto = AcsTaskDto.builder() + .ext_task_id(task.getTask_id()) + .task_code(task.getTask_code()) + .task_type(task.getAcs_task_type()) + .start_device_code(task.getPoint_code1()) + .next_device_code(task.getPoint_code2()) + .start_device_code2(task.getPoint_code3()) + .next_device_code2(task.getPoint_code4()) + .vehicle_code(task.getVehicle_code()) + .agv_system_type(agv_system_type) + .priority(task.getPriority()) + .remark(task.getRemark()) + .product_area(task.getProduct_area()) + .build(); + resultList.add(dto); + } + return resultList; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateTaskStatus(JSONObject taskObj, String status) { + SchBaseTask task = taskService.getById(taskObj.getString("task_id")); + if (TaskStatusEnum.EXECUTING.getCode().equals(status)) { + // 更新任务状态为执行中 + task.setTask_status(TaskStatusEnum.EXECUTING.getCode()); + } + + if (StrUtil.equals(status, TaskStatusEnum.FINISHED.getCode())) { + task.setTask_status(TaskStatusEnum.FINISHED.getCode()); + // 互换资源 + // update: 在acs请求取货完成就已经清空点位信息 + String endPoint = task.getPoint_code2(); + BstIvtCutpointivt endPointObj = bcutpointivtService.getPintByAgvCode(endPoint, false); + TaskUtils.pointMaintenanceInventory(task, endPointObj, "2"); + bcutpointivtService.updateById(endPointObj); + // 创建桁架任务 + if (ObjectUtil.isNotEmpty(task.getVehicle_code()) && ObjectUtil.isNotEmpty(task.getVehicle_code2())) { + + } +// // 分切计划状态修改02->03 +// List collect = Stream.of(task.getVehicle_code(), task.getVehicle_code2()) +// .filter(value -> value != null && !value.isEmpty()).collect(Collectors.toList()); +// PdmBiSlittingproductionplan p = new PdmBiSlittingproductionplan(); +// p.setStatus("03"); +// TaskUtils.updateOptMessageBySlitterPlan(p); +// slittingproductionplanService.update(p, new LambdaQueryWrapper() +// .in(PdmBiSlittingproductionplan::getQzzno, collect)); + } + + // 取消 + if (status.equals(IOSEnum.IS_NOTANDYES.code("否"))) { + task.setTask_status(TaskStatusEnum.FINISHED.getCode()); + // 分切计划是否需要回退 状态 02->01 + List collect = Stream.of(task.getVehicle_code(), task.getVehicle_code2()) + .filter(value -> value != null && !value.isEmpty()).collect(Collectors.toList()); + PdmBiSlittingproductionplan p = new PdmBiSlittingproductionplan(); + p.setStatus("01"); + TaskUtils.updateOptMessageBySlitterPlan(p); + slittingproductionplanService.update(p, new LambdaQueryWrapper() + .in(PdmBiSlittingproductionplan::getQzzno, collect)); + } + task.setUpdate_time(DateUtil.now()); + taskService.updateById(task); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public String createTask(JSONObject form) { + String currentUserId = SecurityUtils.getCurrentUserId(); + String currentUsername = SecurityUtils.getCurrentUsername(); + + SchBaseTask task = new SchBaseTask(); + task.setTask_id(IdUtil.getStringId()); + task.setTask_code(IdUtil.getStringId()); + task.setTask_status(TaskStatusEnum.START_AND_POINT.getCode()); + task.setPoint_code1(form.getString("point_code1")); + task.setPoint_code2(form.getString("point_code2")); + task.setVehicle_code(form.getString("vehicle_code1")); + task.setVehicle_code2(form.getString("vehicle_code2")); + task.setAcs_task_type("3"); + task.setIs_delete(SlitterConstant.SLITTER_NO); + task.setRequest_param(form.toJSONString()); + task.setTask_type(form.getString("task_type")); + task.setProduct_area(form.getString("product_area")); + task.setCreate_id(currentUserId); + task.setCreate_name(currentUsername); + task.setCreate_time(DateUtil.now()); + task.setHandle_class(THIS_CLASS); + //根据类型获取对应的任务优先级 + JSONObject priority_jo = WQL.getWO("PDA_COOLIN").addParam("flag", "3").addParam("task_type", task.getTask_type()).process().uniqueResult(0); + if (ObjectUtil.isEmpty(priority_jo)) { + task.setPriority("1"); + } else { + task.setPriority(priority_jo.getString("value")); + } + taskService.save(task); + // 分切计划(最多四个)修改状态 01->02 + List collect = Stream.of(task.getVehicle_code(), task.getVehicle_code2()) + .filter(value -> value != null && !value.isEmpty()).collect(Collectors.toList()); + PdmBiSlittingproductionplan p = new PdmBiSlittingproductionplan(); + p.setStatus("02"); + TaskUtils.updateOptMessageBySlitterPlan(p); + slittingproductionplanService.update(p, new LambdaQueryWrapper() + .in(PdmBiSlittingproductionplan::getQzzno, collect)); + this.immediateTaskNotifyAcs(task); + return task.getTask_id(); + } + + @Override + public void forceFinish(String task_id) { + JSONObject taskObj = WQLObject.getWQLObject("SCH_BASE_Task").query("task_id = '" + task_id + "'").uniqueResult(0); + this.updateTaskStatus(taskObj, TaskStatusEnum.FINISHED.getCode()); + } + + + @Override + public void cancel(String task_id) { + JSONObject taskObj = WQLObject.getWQLObject("SCH_BASE_Task").query("task_id = '" + task_id + "'").uniqueResult(0); + this.updateTaskStatus(taskObj, "0"); + } +} diff --git a/lms/nladmin-system/src/main/java/org/nl/b_lms/sch/tasks/slitter/TrussSendAirShaftTask.java b/lms/nladmin-system/src/main/java/org/nl/b_lms/sch/tasks/slitter/TrussSendAirShaftTask.java index 9c8345e2e..53c120b72 100644 --- a/lms/nladmin-system/src/main/java/org/nl/b_lms/sch/tasks/slitter/TrussSendAirShaftTask.java +++ b/lms/nladmin-system/src/main/java/org/nl/b_lms/sch/tasks/slitter/TrussSendAirShaftTask.java @@ -124,6 +124,7 @@ public class TrussSendAirShaftTask extends AbstractAcsTask { task.setTask_status(TaskStatusEnum.FINISHED.getCode()); String startPoint = task.getPoint_code1(); String endPoint = task.getPoint_code2(); + JSONObject parseObject = JSONObject.parseObject(task.getRequest_param()); BstIvtShafttubeivt startPointObj = shafttubeivtService.getByPointCode(startPoint, false); BstIvtCutpointivt endPointObj = bcutpointivtService.getPintByTrussCode(endPoint, false); // 设置点位信息 @@ -134,6 +135,10 @@ public class TrussSendAirShaftTask extends AbstractAcsTask { // 下轴 endPointObj.setQzz_no2(task.getVehicle_code2()); } + // 如果parseObject为空或flag为空,设置为"0" + String flag = (parseObject != null && StrUtil.isNotBlank(parseObject.getString("flag"))) + ? parseObject.getString("flag") : "0"; + endPointObj.setPlan(flag); endPointObj.setPoint_status("2"); TaskUtils.updateOptMessageByBCutPoint(endPointObj); bcutpointivtService.updateById(endPointObj); diff --git a/lms/nladmin-system/src/main/java/org/nl/b_lms/sch/tasks/slitter/auto/AutoSendAirShaftAgvTask.java b/lms/nladmin-system/src/main/java/org/nl/b_lms/sch/tasks/slitter/auto/AutoSendAirShaftAgvTask.java index 0193945bc..f0ff8d3c8 100644 --- a/lms/nladmin-system/src/main/java/org/nl/b_lms/sch/tasks/slitter/auto/AutoSendAirShaftAgvTask.java +++ b/lms/nladmin-system/src/main/java/org/nl/b_lms/sch/tasks/slitter/auto/AutoSendAirShaftAgvTask.java @@ -14,12 +14,15 @@ import org.nl.b_lms.pdm.bi.slittingproductionplan.service.dao.PdmBiSlittingprodu import org.nl.b_lms.sch.point.dao.StIvtCutpointivt; import org.nl.b_lms.sch.point.service.IstIvtCutpointivtService; import org.nl.b_lms.sch.tasks.slitter.SendAirShaftAgvTask; +import org.nl.b_lms.sch.tasks.slitter.SendDisassemblyAgvTask; import org.nl.b_lms.sch.tasks.slitter.SendNBJExceptionPointTask; import org.nl.b_lms.sch.tasks.slitter.constant.SlitterConstant; import org.nl.b_lms.sch.tasks.slitter.constant.SlitterEnum; import org.nl.b_lms.sch.tasks.slitter.mapper.SlitterMapper; import org.nl.b_lms.sch.tasks.slitter.util.SlitterTaskUtil; import org.nl.modules.common.exception.BadRequestException; +import org.nl.system.service.param.ISysParamService; +import org.nl.system.service.param.dao.Param; import org.redisson.api.RLock; import org.redisson.api.RedissonClient; import org.springframework.beans.factory.annotation.Autowired; @@ -38,6 +41,10 @@ import java.util.stream.Stream; @Slf4j @Component public class AutoSendAirShaftAgvTask { + /** 合单配送 */ + public final static String IS_COMBINED_ORDER = "IS_COMBINED_ORDER"; + /** 合单超时时间 */ + public final static String IS_COMBINED_ORDER_TIME = "IS_COMBINED_ORDER_TIME"; @Autowired private IBstIvtCutpointivtService bcutpointivtService; @Autowired @@ -52,6 +59,10 @@ public class AutoSendAirShaftAgvTask { private RedissonClient redissonClient; @Autowired private SendNBJExceptionPointTask sendNBJExceptionPointTask; + @Autowired + private SendDisassemblyAgvTask sendDisassemblyAgvTask; + @Autowired + private ISysParamService paramService; @SneakyThrows public void run() { @@ -131,6 +142,16 @@ public class AutoSendAirShaftAgvTask { continue; } } + // 检测是否存在气胀轴缓存架子上 + Param codParam = paramService.findByCode(IS_COMBINED_ORDER); + // plan=0/1,1代表拼单,需要拆单,不能走原来的逻辑 + if (ObjectUtil.isNotEmpty(codParam) + && "1".equals(codParam.getValue()) + && "1".equals(cutPoint.getPlan())) { + // 拼单输送 + toCreateDisassemblyAgvTask(cutPoint, plans, deviceCut); + continue; + } // 如果两个气涨轴编码则表示一组满了 // 查找分切对接没任务的空位 // hint: B1、B2、B3、B4分切区分两个桁架位置 (B1,B3: 1-6为上。B2,B4是1-5为上区域) @@ -139,7 +160,7 @@ public class AutoSendAirShaftAgvTask { SlitterTaskUtil.getPointLocationInCutDevice( SlitterTaskUtil.getNumberByResourceCode(demoPlan.getResource_name()), area)); - if (emptyPoint.size() == 0) { + if (emptyPoint.isEmpty()) { log.warn("当前分切机找不到空闲的对接位置!"); cutPoint.setRemark("找不到当前分切机空闲的对接位置,暂时不送轴!"); cutPoint.setUpdate_time(DateUtil.now()); @@ -174,4 +195,48 @@ public class AutoSendAirShaftAgvTask { } + /** + * 创建拆单AGV任务 + * @param cutPoint + */ + public void toCreateDisassemblyAgvTask(BstIvtCutpointivt cutPoint, List plans, StIvtCutpointivt deviceCut) { + Param codParam = paramService.findByCode(IS_COMBINED_ORDER_TIME); + // 单位:分钟 + String time = ObjectUtil.isNotEmpty(codParam) ? codParam.getValue() : "5"; + time = ObjectUtil.defaultIfBlank(time, "5"); + int limitMinutes = Integer.parseInt(time); + // 核心判断:两个编号为空 + 更新时间在规定分钟内 + if ((ObjectUtil.isEmpty(cutPoint.getQzz_no1()) || ObjectUtil.isEmpty(cutPoint.getQzz_no2())) + && ObjectUtil.isNotEmpty(cutPoint.getUpdate_time()) + && SlitterTaskUtil.isTimeWithinLimit(cutPoint.getUpdate_time(), limitMinutes)) { + log.info("等待拼单,等待时间未超过{}分钟...", time); + return; + } + PdmBiSlittingproductionplan demoPlan = plans.get(0); + // 找到对应的位置 + String area = deviceCut.getProduct_area(); + List emptyPoint = slitterMapper.getEmptyAirShaftAgvPointNotTask( + area, + SlitterTaskUtil.getPointLocationInCutDevice( + SlitterTaskUtil.getNumberByResourceCode(demoPlan.getResource_name()), + area), + deviceCut.getPlan()); + if (emptyPoint.isEmpty()) { + log.warn("当前分切机找不到空闲的对接位置!"); + cutPoint.setRemark("找不到当前分切机空闲的对接位置,暂时不送轴!"); + cutPoint.setUpdate_time(DateUtil.now()); + bcutpointivtService.updateById(cutPoint); + } + BstIvtCutpointivt endPoint = emptyPoint.get(0); + JSONObject param = new JSONObject(); + param.put("point_code1", cutPoint.getPoint_code()); + param.put("point_code2", endPoint.getPoint_code()); + param.put("vehicle_code1", cutPoint.getQzz_no1()); + param.put("vehicle_code2", cutPoint.getQzz_no2()); + param.put("task_type", SlitterEnum.TASK_TYPE.code("送轴拆单任务")); + param.put("product_area", SlitterConstant.SLITTER_TASK_AREA); + param.put("containers", plans.stream().map(PdmBiSlittingproductionplan::getContainer_name).collect(Collectors.toList())); + sendDisassemblyAgvTask.createTask(param); + } + } diff --git a/lms/nladmin-system/src/main/java/org/nl/b_lms/sch/tasks/slitter/constant/SlitterEnum.java b/lms/nladmin-system/src/main/java/org/nl/b_lms/sch/tasks/slitter/constant/SlitterEnum.java index f998dae51..d9b12f293 100644 --- a/lms/nladmin-system/src/main/java/org/nl/b_lms/sch/tasks/slitter/constant/SlitterEnum.java +++ b/lms/nladmin-system/src/main/java/org/nl/b_lms/sch/tasks/slitter/constant/SlitterEnum.java @@ -27,7 +27,7 @@ public enum SlitterEnum { , "拔轴完毕出轴", "010814", "穿拔轴缓存<>气胀轴缓存位", "010815", "备货区单独送空载具", "010816" , "拼单送轴", "010817", "拆单两点移动任务", "010818", "拆单四点移动任务", "010819" , "满轴拼单桁架任务", "010820", "送空轴AGV任务", "010821", "人工叫空轴桁架任务", "010822" - , "备货区托盘入库", "010823", "备货区托盘出库", "010824") + , "备货区托盘入库", "010823", "备货区托盘出库", "010824", "送轴拆单任务", "010825") ), /** * 二次请求 diff --git a/lms/nladmin-system/src/main/java/org/nl/b_lms/sch/tasks/slitter/mapper/SlitterMapper.java b/lms/nladmin-system/src/main/java/org/nl/b_lms/sch/tasks/slitter/mapper/SlitterMapper.java index 24120c898..58494d98d 100644 --- a/lms/nladmin-system/src/main/java/org/nl/b_lms/sch/tasks/slitter/mapper/SlitterMapper.java +++ b/lms/nladmin-system/src/main/java/org/nl/b_lms/sch/tasks/slitter/mapper/SlitterMapper.java @@ -75,4 +75,6 @@ public interface SlitterMapper { List getMoveTzdjwExceptionPoint(); List getCombinedOrders(CombinedOrderDto cod); + + List getEmptyAirShaftAgvPointNotTask(String area, String location, String plan); } diff --git a/lms/nladmin-system/src/main/java/org/nl/b_lms/sch/tasks/slitter/mapper/SlitterMapper.xml b/lms/nladmin-system/src/main/java/org/nl/b_lms/sch/tasks/slitter/mapper/SlitterMapper.xml index 375e0e67d..05c521330 100644 --- a/lms/nladmin-system/src/main/java/org/nl/b_lms/sch/tasks/slitter/mapper/SlitterMapper.xml +++ b/lms/nladmin-system/src/main/java/org/nl/b_lms/sch/tasks/slitter/mapper/SlitterMapper.xml @@ -362,4 +362,20 @@ OR t.point_code2 = cp.truss_point_code2 )) + diff --git a/lms/nladmin-system/src/main/java/org/nl/b_lms/sch/tasks/slitter/util/SlitterTaskUtil.java b/lms/nladmin-system/src/main/java/org/nl/b_lms/sch/tasks/slitter/util/SlitterTaskUtil.java index b637c30a4..9188d942d 100644 --- a/lms/nladmin-system/src/main/java/org/nl/b_lms/sch/tasks/slitter/util/SlitterTaskUtil.java +++ b/lms/nladmin-system/src/main/java/org/nl/b_lms/sch/tasks/slitter/util/SlitterTaskUtil.java @@ -1,6 +1,7 @@ package org.nl.b_lms.sch.tasks.slitter.util; import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.NumberUtil; import cn.hutool.core.util.ObjectUtil; import com.alibaba.fastjson.JSONArray; @@ -14,6 +15,7 @@ import org.nl.modules.common.exception.BadRequestException; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.*; +import java.util.concurrent.TimeUnit; import java.util.function.Function; import java.util.stream.Collectors; @@ -704,4 +706,31 @@ public class SlitterTaskUtil { } return true; } + + // ===================== 工具方法:判断字符串时间是否在 N 分钟内 ===================== + /** + * 判断字符串格式的时间 是否在指定分钟内(未超时) + * @param timeStr 格式:2024-03-03 14:00:00.000 + * @param minutes 限制分钟数 + * @return true=未超过规定时间 | false=已超过 + */ + public static boolean isTimeWithinLimit(String timeStr, int minutes) { + try { + // 把字符串时间转成 Date(自动适配你这种格式) + Date updateTime = DateUtil.parse(timeStr); + + // 计算时间差(毫秒) + long diffMs = System.currentTimeMillis() - updateTime.getTime(); + + // 转成分钟 + long diffMinutes = TimeUnit.MILLISECONDS.toMinutes(diffMs); + + // 未超过规定分钟 → 返回true + return diffMinutes <= minutes; + + } catch (Exception e) { + // 时间格式异常 → 不进入if + return false; + } + } }