From 4155a2b685b02531bb6fe663f6840bf927c598a5 Mon Sep 17 00:00:00 2001 From: gengby <858962040@qq.com> Date: Wed, 25 Sep 2024 14:01:47 +0800 Subject: [PATCH] =?UTF-8?q?rev:=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../device/device_driver/DriverTypeEnum.java | 3 +- .../service/impl/DeviceServiceImpl.java | 4 +- .../java/org/nl/acs/device/wql/task_inst.xls | Bin 157696 -> 159232 bytes .../agv/xg_agv/XianGongAgvDeviceDriver.java | 24 +- .../elevator/ElevatorDefinition.java | 49 +++ .../elevator/ElevatorDeviceDriver.java | 21 ++ .../acs/device_driver/rgv/ItemProtocol.java | 21 +- .../device_driver/rgv/RGVDeviceDriver.java | 73 +---- .../device_driver/rgv/enums/PositionEnum.java | 38 +++ .../wms/service/impl/WmsToAcsServiceImpl.java | 57 +++- .../nl/acs/ext/xg/rest/XgToAcsController.java | 51 +++ .../nl/acs/ext/xg/service/XgToAcsService.java | 37 +++ .../xg/service/impl/XgToAcsServiceImpl.java | 295 ++++++++++++++++++ .../service/dto/InstructionDto.java | 31 ++ .../service/impl/InstructionServiceImpl.java | 59 ++++ .../main/java/org/nl/acs/opc/DeviceType.java | 3 +- .../socket/elevator/ElevatorSocketUtil.java | 162 ++++++++++ .../org/nl/acs/task/service/dto/TaskDto.java | 30 ++ .../task/service/impl/TaskServiceImpl.java | 118 +++++++ .../modules/quartz/task/AutoCreateInst.java | 8 + .../quartz/task/ElevatorAutoReconnection.java | 30 ++ .../quartz/task/QueryXZAgvDeviceStatus.java | 3 +- .../run/ElevatorSocketConnectionAutoRun.java | 156 +++++++++ .../src/main/resources/config/application.yml | 2 +- .../src/main/resources/log/Elevator.xml | 33 ++ .../main/resources/log/ElevatorSocketUtil.xml | 33 ++ .../src/main/resources/logback-spring.xml | 8 +- .../src/views/acs/device/config.vue | 4 +- .../acs/device/driver/standard_elevator.vue | 111 +++++++ lms/nladmin-system/nlsso-server/pom.xml | 6 +- .../controller/BigScreenController.java | 6 + .../bigScreen/service/BigScreenService.java | 3 + .../service/impl/BigScreenServiceImpl.java | 15 + .../impl/MdBaseMaterialServiceImpl.java | 55 ++++ .../nl/wms/pda/controller/PdaController.java | 12 + .../org/nl/wms/pda/service/PdaService.java | 4 + .../wms/pda/service/impl/PdaServiceImpl.java | 70 +++++ .../task/tasks/lmzb/LMZBQKTask.java | 8 +- .../task/tasks/xkbs/XKBSSKTask.java | 212 +++++++++++++ .../task_manage/task/tasks/ycl/ZPRKTask.java | 138 ++++++-- 40 files changed, 1853 insertions(+), 140 deletions(-) create mode 100644 acs/nladmin-system/src/main/java/org/nl/acs/device_driver/basedriver/elevator/ElevatorDefinition.java create mode 100644 acs/nladmin-system/src/main/java/org/nl/acs/device_driver/basedriver/elevator/ElevatorDeviceDriver.java create mode 100644 acs/nladmin-system/src/main/java/org/nl/acs/device_driver/rgv/enums/PositionEnum.java create mode 100644 acs/nladmin-system/src/main/java/org/nl/acs/ext/xg/rest/XgToAcsController.java create mode 100644 acs/nladmin-system/src/main/java/org/nl/acs/ext/xg/service/XgToAcsService.java create mode 100644 acs/nladmin-system/src/main/java/org/nl/acs/ext/xg/service/impl/XgToAcsServiceImpl.java create mode 100644 acs/nladmin-system/src/main/java/org/nl/acs/socket/elevator/ElevatorSocketUtil.java create mode 100644 acs/nladmin-system/src/main/java/org/nl/modules/quartz/task/ElevatorAutoReconnection.java create mode 100644 acs/nladmin-system/src/main/java/org/nl/start/auto/run/ElevatorSocketConnectionAutoRun.java create mode 100644 acs/nladmin-system/src/main/resources/log/Elevator.xml create mode 100644 acs/nladmin-system/src/main/resources/log/ElevatorSocketUtil.xml create mode 100644 acs/nladmin-ui/src/views/acs/device/driver/standard_elevator.vue create mode 100644 lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/sch/task_manage/task/tasks/xkbs/XKBSSKTask.java diff --git a/acs/nladmin-system/src/main/java/org/nl/acs/device/device_driver/DriverTypeEnum.java b/acs/nladmin-system/src/main/java/org/nl/acs/device/device_driver/DriverTypeEnum.java index b827afc..5818344 100644 --- a/acs/nladmin-system/src/main/java/org/nl/acs/device/device_driver/DriverTypeEnum.java +++ b/acs/nladmin-system/src/main/java/org/nl/acs/device/device_driver/DriverTypeEnum.java @@ -13,7 +13,8 @@ public enum DriverTypeEnum { STANDARD_STORAGE(2, "standard_storage", "标准版-货架", "storage"), PHOTOELECTRIC_DETECTION_DEVICE_DRIVER(3, "photoelectric_detection_station", "光电检测站点", "station"), XIANGONG_AGV_DEVICE_DRIVER(4, "xg_agv", "仙工AGV", "agv"), - RGV_DEVICE_DRIVER(5, "rgv_station", "RGV", "rgv"); + RGV_DEVICE_DRIVER(5, "rgv_station", "RGV", "rgv"), + ELEVATOR_DRIVER(6, "standard_elevator", "电梯", "elevator"); //驱动索引 private int index; //驱动编码 diff --git a/acs/nladmin-system/src/main/java/org/nl/acs/device/service/impl/DeviceServiceImpl.java b/acs/nladmin-system/src/main/java/org/nl/acs/device/service/impl/DeviceServiceImpl.java index fa9be1f..d1bae09 100644 --- a/acs/nladmin-system/src/main/java/org/nl/acs/device/service/impl/DeviceServiceImpl.java +++ b/acs/nladmin-system/src/main/java/org/nl/acs/device/service/impl/DeviceServiceImpl.java @@ -693,8 +693,8 @@ public class DeviceServiceImpl implements DeviceService, ApplicationAutoInitial // String device_code = jo.getString("device_code"); // String device_name = jo.getString("device_name"); // Device device = appService.findDeviceByCode(device_code); -// if (device.getDeviceDriver() instanceof StandardOrdinarySiteDeviceDriver) { -// standardOrdinarySiteDeviceDriver = (StandardOrdinarySiteDeviceDriver) device.getDeviceDriver(); +// if (device.getDeviceDriver() instanceof ElevatorDeviceDriver) { +// standardOrdinarySiteDeviceDriver = (ElevatorDeviceDriver) device.getDeviceDriver(); // int branchProtocol = standardOrdinarySiteDeviceDriver.getBranchProtocol(); // devicejo.put("device_code",device_code); // devicejo.put("branchProtocol",branchProtocol); diff --git a/acs/nladmin-system/src/main/java/org/nl/acs/device/wql/task_inst.xls b/acs/nladmin-system/src/main/java/org/nl/acs/device/wql/task_inst.xls index 44ac6a1351d02d7eb5bbc6aba1d82cdb3ca52c62..b3861669451b55cd5e0c21dfa3f21ec6a1208f82 100644 GIT binary patch delta 48414 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 delta 48675 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 diff --git a/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/basedriver/agv/xg_agv/XianGongAgvDeviceDriver.java b/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/basedriver/agv/xg_agv/XianGongAgvDeviceDriver.java index 7066f4c..458bba9 100644 --- a/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/basedriver/agv/xg_agv/XianGongAgvDeviceDriver.java +++ b/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/basedriver/agv/xg_agv/XianGongAgvDeviceDriver.java @@ -1,5 +1,6 @@ package org.nl.acs.device_driver.basedriver.agv.xg_agv; +import cn.hutool.core.util.ObjectUtil; import com.alibaba.fastjson.JSONObject; import lombok.Data; import lombok.RequiredArgsConstructor; @@ -11,8 +12,14 @@ import org.nl.acs.device_driver.driver.ExecutableDeviceDriver; import org.nl.acs.instruction.service.InstructionService; import org.nl.acs.monitor.DeviceStageMonitor; import org.nl.acs.opc.Device; +import org.nl.acs.task.service.TaskService; +import org.nl.acs.task.service.dto.TaskDto; import org.nl.modules.wql.util.SpringContextHolder; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.text.DecimalFormat; + /** * 仙工AGV */ @@ -26,6 +33,7 @@ public class XianGongAgvDeviceDriver extends AbstractOpcDeviceDriver implements DeviceStageMonitor { private final InstructionService instructionService = SpringContextHolder.getBean(InstructionService.class); + private final TaskService taskService = SpringContextHolder.getBean(TaskService.class); /** * 当前设备号 @@ -115,22 +123,30 @@ public class XianGongAgvDeviceDriver extends AbstractOpcDeviceDriver implements @Override public JSONObject getDeviceStatusName() { + DecimalFormat hisFormat = new DecimalFormat("########.###"); + hisFormat.setRoundingMode(RoundingMode.DOWN); JSONObject jo = new JSONObject(); jo.put("device_code", this.currentDeviceCode); jo.put("device_name", this.currentDeviceCode); jo.put("task_code", this.taskCode); - jo.put("battery_level", (this.battery_level * 100) + "%"); + BigDecimal decimal = new BigDecimal(Double.toString(this.battery_level)); + BigDecimal scale = decimal.setScale(2, RoundingMode.HALF_UP); + BigDecimal multiply = scale.multiply(BigDecimal.valueOf(100)); + jo.put("battery_level", multiply + "%"); jo.put("angle", this.angle); - jo.put("time", this.time / 1000 / 1.0 / 3600); - jo.put("total_time", this.total_time / 1000 / 1.0 / 3600); + //jo.put("time", this.time / 1000 / 1.0 / 3600); + //jo.put("total_time", this.total_time / 1000 / 1.0 / 3600); jo.put("today_odo", this.today_odo); jo.put("odo", this.odo); jo.put("x", this.x); jo.put("y", this.y); - jo.put("status", this.statusName); + jo.put("status", this.status == 1 ? "工作中" : this.status == 2 ? "充电中" : this.status == 3 ? "故障" : this.status == 4 ? "休息中" : this.status == 5 ? "关机" : "未知状态"); //jo.put("status_name", this.statusName); jo.put("todayTaskNum", this.todayTaskNum); jo.put("monthTaskNum", this.monthTaskNum); + TaskDto taskDto = taskService.findByCodeFromCache(this.taskCode); + jo.put("start_loc", ObjectUtil.isEmpty(taskDto) ? "暂无" : taskDto.getStart_point_code()); + jo.put("target_loc", ObjectUtil.isEmpty(taskDto) ? "暂无" : taskDto.getNext_point_code()); jo.put("message", this.message == null ? "运行正常" : "运行异常"); return jo; } diff --git a/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/basedriver/elevator/ElevatorDefinition.java b/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/basedriver/elevator/ElevatorDefinition.java new file mode 100644 index 0000000..8178003 --- /dev/null +++ b/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/basedriver/elevator/ElevatorDefinition.java @@ -0,0 +1,49 @@ +package org.nl.acs.device_driver.basedriver.elevator; + +import org.nl.acs.device_driver.DeviceDriver; +import org.nl.acs.device_driver.DeviceDriverDefinition; +import org.nl.acs.opc.Device; +import org.nl.acs.opc.DeviceType; +import org.springframework.stereotype.Service; + +import java.util.LinkedList; +import java.util.List; + +/** + * 电梯 + */ +@Service +public class ElevatorDefinition implements DeviceDriverDefinition { + @Override + public String getDriverCode() { + return "standard_elevator"; + } + + @Override + public String getDriverName() { + return "电梯"; + } + + @Override + public String getDriverDescription() { + return "电梯"; + } + + @Override + public DeviceDriver getDriverInstance(Device device) { + return (new ElevatorDeviceDriver()).setDevice(device).setDriverDefinition(this); + + } + + @Override + public Class getDeviceDriverType() { + return ElevatorDeviceDriver.class; + } + + @Override + public List getFitDeviceTypes() { + List types = new LinkedList(); + types.add(DeviceType.elevator); + return types; + } +} diff --git a/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/basedriver/elevator/ElevatorDeviceDriver.java b/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/basedriver/elevator/ElevatorDeviceDriver.java new file mode 100644 index 0000000..a343102 --- /dev/null +++ b/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/basedriver/elevator/ElevatorDeviceDriver.java @@ -0,0 +1,21 @@ +package org.nl.acs.device_driver.basedriver.elevator; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import org.nl.acs.device_driver.DeviceDriver; +import org.nl.acs.device_driver.RouteableDeviceDriver; +import org.nl.acs.device_driver.driver.AbstractDeviceDriver; + + +/** + * 电梯 + */ +@Slf4j +@Getter +@Setter +@RequiredArgsConstructor +public class ElevatorDeviceDriver extends AbstractDeviceDriver implements DeviceDriver, RouteableDeviceDriver { +} + diff --git a/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/rgv/ItemProtocol.java b/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/rgv/ItemProtocol.java index 5765435..f0a1277 100644 --- a/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/rgv/ItemProtocol.java +++ b/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/rgv/ItemProtocol.java @@ -8,20 +8,13 @@ import java.util.ArrayList; import java.util.List; public enum ItemProtocol implements DeviceDriverBaseReader.KeyProvider { - HEARTBEAT("heartbeat", "心跳", "DB1101.B1"), - MODE("mode", "工作模式", "DB1101.B2"), - STATUS("status", "工作状态", "DB1101.B3"), - ERROR("error", "报警信息", "DB1101.B4"), - ENERGY_LEVEL("energyLevel", "当前电量", "DB1101.D5"), - TASK_CODE("taskCode", "当前执行任务号", "DB1101.D6"), - START_DEVICE_CODE("startDeviceCode", "任务起点", "DB1101.S7"), - NEXT_DEVICE_CODE("nextDeviceCode", "任务终点", "DB1101.S8"), - VEHICLE_CODE("vehicleCode", "载具号", "DB1101.S9"), - X("x", "x坐标", "DB1101.D10"), - Y("y", "y坐标", "DB1101.D11"), - ACTION("action", "当前动作", "DB1101.B12"), - TODAY_TASK_NUM("todayTaskNum", "当天执行任务数", "DB1101.D13"), - ALL_TASK_NUM("allTaskNum", "历史执行任务数", "DB1101.D14"); + HEARTBEAT("heartbeat", "心跳", "VB71"), + MODE("mode", "工作模式", "VB64"), + STATUS("status", "工作状态", "VB68"), + ERROR("error", "报警信息", "VB70"), + ENERGY_LEVEL("energyLevel", "当前电量", "VW60"), + CURRENT_POSITION("currentPosition", "当前位置", "VB14"), + TARGET_POSITION("targetPosition", "目标位置", "VB15"); private final String key; private final String description; diff --git a/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/rgv/RGVDeviceDriver.java b/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/rgv/RGVDeviceDriver.java index f93ed95..02d5c7b 100644 --- a/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/rgv/RGVDeviceDriver.java +++ b/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/rgv/RGVDeviceDriver.java @@ -8,12 +8,11 @@ import lombok.extern.slf4j.Slf4j; import org.nl.acs.device_driver.*; import org.nl.acs.device_driver.driver.AbstractOpcDeviceDriver; import org.nl.acs.device_driver.driver.ExecutableDeviceDriver; -import org.nl.acs.device_driver.sdk.ItemProtocol; +import org.nl.acs.device_driver.rgv.enums.PositionEnum; import org.nl.acs.monitor.DeviceStageMonitor; import org.nl.modules.lucene.service.LuceneExecuteLogService; import org.nl.modules.lucene.service.dto.LuceneLogDto; import org.nl.modules.wql.util.SpringContextHolder; -import org.springframework.util.ObjectUtils; /** * @author zhangjiangwei @@ -59,62 +58,20 @@ public class RGVDeviceDriver extends AbstractOpcDeviceDriver implements /** * 当前电量 */ - private Double energyLevel = 0.0d; - private Double lastEnergyLevel = 0.0d; - - /** - * 任务号 - */ - private int taskCode = 0; - private int lastTaskCode = 0; + private int energyLevel = 0; + private int lastEnergyLevel = 0; /** * 起点 */ - private String startDeviceCode; - private String lastStartDeviceCode; + private int currentPosition; + private int lastCurrentPosition; /** * 终点 */ - private String nextDeviceCode; - private String lastNextDeviceCode; - - /** - * 载具号 - */ - private String vehicleCode; - private String lastVehicleCode; - - /** - * x坐标 - */ - private Double x; - private Double lastX; - - /** - * y坐标 - */ - private Double y; - private Double lastY; - - /** - * 当前动作 - */ - private int action = 0; - private int lastAction = 0; - - /** - * 当天执行任务数 - */ - private int todayTaskNum = 0; - private int lastTodayTaskNum = 0; - - /** - * 历史执行任务数 - */ - private int allTaskNum = 0; - private int lastAllTaskNum = 0; + private int targetPosition; + private int lastTargetPosition; /** * 当前设备号 @@ -175,17 +132,11 @@ public class RGVDeviceDriver extends AbstractOpcDeviceDriver implements jo.put("mode", this.mode == 1 ? "手动" : this.mode == 2 ? "自动" : "未知"); jo.put("status", this.error > 0 ? "故障" : this.status == 0 ? "休息中" : this.status == 1 ? "工作中" : this.status == 2 ? "充电中" : "未知状态"); jo.put("error", this.error); - jo.put("battery_level", (this.energyLevel * 100) + "%"); - jo.put("task_code", this.taskCode); - jo.put("current_loc", ObjectUtils.isEmpty(this.startDeviceCode) ? "0" : this.startDeviceCode); - jo.put("target_loc", ObjectUtils.isEmpty(this.nextDeviceCode) ? "0" : this.nextDeviceCode); - jo.put("vehicleCode", this.vehicleCode); - jo.put("x", this.x); - jo.put("y", this.y); - jo.put("action", this.action); - jo.put("todayTaskNum", this.todayTaskNum); - jo.put("allTaskNum", this.allTaskNum); - jo.put("message", this.message == null ? "运行正常" : "运行异常"); + //1急停 2避障 0无报警 + jo.put("battery_level", this.energyLevel + "%"); + jo.put("current_loc", PositionEnum.getLabel(this.currentPosition)); + jo.put("target_loc", PositionEnum.getLabel(this.targetPosition)); + jo.put("message", this.error == 0 ? "正常" : this.error == 1 ? "急停" : this.error == 2 ? "避障" : "未知报警信息"); return jo; } diff --git a/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/rgv/enums/PositionEnum.java b/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/rgv/enums/PositionEnum.java new file mode 100644 index 0000000..235d72a --- /dev/null +++ b/acs/nladmin-system/src/main/java/org/nl/acs/device_driver/rgv/enums/PositionEnum.java @@ -0,0 +1,38 @@ +package org.nl.acs.device_driver.rgv.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * @Description TODO + * @Author Gengby + * @Date 2024/4/25 + */ +@Getter +@AllArgsConstructor +public enum PositionEnum { + P_1(1, "充电位"), + P_11(11, "工位1"), + P_21(21, "工位2"), + P_31(31, "工位3"), + P_41(41, "工位4"), + P_51(51, "工位5"), + P_61(61, "工位6"), + P_71(71, "充电位"), + P_81(81, "工位7"), + P_91(91, "工位8"), + P_101(101, "工位9"), + P_111(111, "工位10"); + + private final Integer value; + private final String label; + + public static String getLabel(Integer value) { + for (PositionEnum strategy : PositionEnum.values()) { + if (strategy.getValue().equals(value)) { + return strategy.getLabel(); + } + } + return "工位"; + } +} \ No newline at end of file diff --git a/acs/nladmin-system/src/main/java/org/nl/acs/ext/wms/service/impl/WmsToAcsServiceImpl.java b/acs/nladmin-system/src/main/java/org/nl/acs/ext/wms/service/impl/WmsToAcsServiceImpl.java index f088e77..b5bd7ba 100644 --- a/acs/nladmin-system/src/main/java/org/nl/acs/ext/wms/service/impl/WmsToAcsServiceImpl.java +++ b/acs/nladmin-system/src/main/java/org/nl/acs/ext/wms/service/impl/WmsToAcsServiceImpl.java @@ -37,10 +37,7 @@ import org.slf4j.MDC; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Service; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; @Service @RequiredArgsConstructor @@ -83,8 +80,8 @@ public class WmsToAcsServiceImpl implements WmsToAcsService { // 双工RGV任务 后工位任务 String start_point_code2 = task.getStart_device_code2(); String next_point_code2 = task.getNext_device_code2(); - String start_device_code2 = task.getStart_device_code2(); - String next_device_code2 = task.getNext_device_code2(); + String start_device_code2 = ""; + String next_device_code2 = ""; String start_device_code = ""; String next_device_code = ""; String start_parent_code = ""; @@ -109,6 +106,17 @@ public class WmsToAcsServiceImpl implements WmsToAcsService { next_parent_code = next_device_json.get("parent_storage_code") == null ? next_point_code : (String) next_device_json.get("parent_storage_code"); } + + + JSONObject start_device_json2 = WQLObject.getWQLObject("acs_storage_cell").query("parent_storage_code ='" + start_point_code2 + "'").uniqueResult(0); + if (!ObjectUtil.isEmpty(start_device_json2)) { + start_point_code2 = (String) start_device_json2.get("parent_storage_code") == null ? start_device_code2 : (String) start_device_json2.get("storage_code"); + } + JSONObject next_device_json2 = WQLObject.getWQLObject("acs_storage_cell").query("parent_storage_code ='" + next_point_code2 + "'").uniqueResult(0); + if (!ObjectUtil.isEmpty(next_device_json2)) { + next_point_code2 = (String) next_device_json2.get("parent_storage_code") == null ? next_device_code2 : (String) next_device_json2.get("storage_code"); + } + if (start_point_code.indexOf("-") > 0) { String str[] = start_point_code.split("-"); start_device_code = str[0]; @@ -123,6 +131,20 @@ public class WmsToAcsServiceImpl implements WmsToAcsService { next_device_code = next_point_code; } + if (StrUtil.isNotEmpty(start_point_code2) && start_point_code2.indexOf("-") > 0) { + String str[] = start_point_code2.split("-"); + start_device_code2 = str[0]; + } else { + start_device_code2 = start_point_code2; + } + + if (StrUtil.isNotEmpty(next_point_code2) && next_point_code2.indexOf("-") > 0) { + String str[] = next_point_code2.split("-"); + next_device_code2 = str[0]; + } else { + next_device_code2 = next_point_code2; + } + if (StrUtil.isEmpty(route_plan_code)) { route_plan_code = "normal"; } @@ -193,8 +215,8 @@ public class WmsToAcsServiceImpl implements WmsToAcsService { jo.put("next_parent_code", next_parent_code); jo.put("start_device_code", start_device_code); jo.put("next_device_code", next_device_code); - jo.put("start_point_code2", start_device_code2); - jo.put("next_point_code2", next_device_code2); + jo.put("start_point_code2", start_point_code2); + jo.put("next_point_code2", next_point_code2); jo.put("start_device_code2", start_device_code2); jo.put("next_device_code2", next_device_code2); jo.put("priority", priority); @@ -312,7 +334,6 @@ public class WmsToAcsServiceImpl implements WmsToAcsService { } } - @SneakyThrows @Override public JSONObject agvInfo(JSONObject req) { JSONObject resp = new JSONObject(); @@ -320,10 +341,18 @@ public class WmsToAcsServiceImpl implements WmsToAcsService { List agvInfos = new ArrayList<>(); for (Device agv : agvs) { if (agv != null && agv.getDeviceDriver() instanceof DeviceStageMonitor) { - DeviceStageMonitor deviceStageMonitor = (DeviceStageMonitor) agv.getDeviceDriver(); - agvInfos.add(deviceStageMonitor.getDeviceStatusName()); + try { + log.info("查询出AGV信息不为空"); + DeviceStageMonitor deviceStageMonitor = (DeviceStageMonitor) agv.getDeviceDriver(); + agvInfos.add(deviceStageMonitor.getDeviceStatusName()); + log.info("添加{}", deviceStageMonitor.getDeviceStatusName()); + }catch (Exception e){ + log.error("异常:{}",e.getMessage()); + log.error("异常:{}", Arrays.toString(e.getStackTrace())); + } } } + log.info("响应结果:{}", agvInfos); resp.put("status", 0); resp.put("message", "查询成功"); resp.put("data", agvInfos); @@ -354,9 +383,9 @@ public class WmsToAcsServiceImpl implements WmsToAcsService { Map map = new HashMap<>(); map.put("flag", "1"); JSONArray data = WQL.getWO("EXT_QUERY001").addParamMap(map).process().getResultJSONArray(0); - resp.put("status",0); - resp.put("message","查询成功"); - resp.put("data",data); + resp.put("status", 0); + resp.put("message", "查询成功"); + resp.put("data", data); return resp; } } diff --git a/acs/nladmin-system/src/main/java/org/nl/acs/ext/xg/rest/XgToAcsController.java b/acs/nladmin-system/src/main/java/org/nl/acs/ext/xg/rest/XgToAcsController.java new file mode 100644 index 0000000..7c95901 --- /dev/null +++ b/acs/nladmin-system/src/main/java/org/nl/acs/ext/xg/rest/XgToAcsController.java @@ -0,0 +1,51 @@ +package org.nl.acs.ext.xg.rest; + +import cn.dev33.satoken.annotation.SaIgnore; +import com.alibaba.fastjson.JSONObject; +import io.swagger.annotations.Api; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.nl.acs.ext.log.OthersToInterfaceLog; +import org.nl.acs.ext.xg.service.XgToAcsService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * @Description TODO + * @Author Gengby + * @Date 2024/8/8 + */ +@RestController +@RequiredArgsConstructor +@Api(tags = "仙工调用接口") +@RequestMapping("/api/elevator") +@Slf4j +@SaIgnore +public class XgToAcsController { + + @Autowired + private XgToAcsService xgToAcsService; + + @PostMapping("/call") + @OthersToInterfaceLog("AGV->ACS") + public ResponseEntity call(@RequestBody JSONObject param) { + return new ResponseEntity<>(xgToAcsService.call(param), HttpStatus.OK); + } + + @PostMapping("/status") + @OthersToInterfaceLog("AGV->ACS") + public ResponseEntity status(@RequestBody JSONObject param) { + return new ResponseEntity<>(xgToAcsService.status(param), HttpStatus.OK); + } + + @PostMapping("/setDoor") + @OthersToInterfaceLog("AGV->ACS") + public ResponseEntity setDoor(@RequestBody JSONObject param) { + return new ResponseEntity<>(xgToAcsService.setDoor(param), HttpStatus.OK); + } +} \ No newline at end of file diff --git a/acs/nladmin-system/src/main/java/org/nl/acs/ext/xg/service/XgToAcsService.java b/acs/nladmin-system/src/main/java/org/nl/acs/ext/xg/service/XgToAcsService.java new file mode 100644 index 0000000..5ff807d --- /dev/null +++ b/acs/nladmin-system/src/main/java/org/nl/acs/ext/xg/service/XgToAcsService.java @@ -0,0 +1,37 @@ +package org.nl.acs.ext.xg.service; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; + +/** + * @Description TODO + * @Author Gengby + * @Date 2024/8/8 + */ +public interface XgToAcsService { + + /** + * 呼叫楼层 + * + * @param param + * @return + */ + JSONObject call(JSONObject param); + + /** + * 查看电梯状态 + * + * @param param + * @return + */ + JSONArray status(JSONObject param); + + + /** + * 开关门 + * + * @param param + * @return + */ + JSONObject setDoor(JSONObject param); +} \ No newline at end of file diff --git a/acs/nladmin-system/src/main/java/org/nl/acs/ext/xg/service/impl/XgToAcsServiceImpl.java b/acs/nladmin-system/src/main/java/org/nl/acs/ext/xg/service/impl/XgToAcsServiceImpl.java new file mode 100644 index 0000000..ada9ea5 --- /dev/null +++ b/acs/nladmin-system/src/main/java/org/nl/acs/ext/xg/service/impl/XgToAcsServiceImpl.java @@ -0,0 +1,295 @@ +package org.nl.acs.ext.xg.service.impl; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.nl.acs.ext.xg.service.XgToAcsService; +import org.nl.acs.opc.Device; +import org.nl.acs.opc.DeviceAppService; +import org.nl.acs.opc.DeviceType; +import org.nl.modules.common.exception.BadRequestException; +import org.nl.start.auto.run.ElevatorSocketConnectionAutoRun; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + + +/** + * @Description TODO + * @Author Gengby + * @Date 2024/8/8 + */ +@Service +@RequiredArgsConstructor +@Slf4j +public class XgToAcsServiceImpl implements XgToAcsService { + + @Autowired + private DeviceAppService deviceAppService; + + @Override + public JSONObject call(JSONObject param) { + //电梯编号 + String elevatorCode = param.getString("elevatorCode"); + if (StrUtil.isEmpty(elevatorCode)) { + JSONObject resp = new JSONObject(); + resp.put("code", 400); + resp.put("message", "电梯编号不能为空!"); + return resp; + } + //目标楼层 + Integer floor = param.getInteger("floor"); + if (floor == null) { + JSONObject resp = new JSONObject(); + resp.put("code", 400); + resp.put("message", "目标楼层不能为空!"); + return resp; + } + String doorStatusMsg = "00110000000601039CAC0001"; + int[] doorStatusRec = ElevatorSocketConnectionAutoRun.write("查询电梯门状态", doorStatusMsg); + boolean doorStatus = determineDoorStatus(doorStatusRec); + if (doorStatus) { + String currentFloorHexMsg = "00050000000601039C410001"; + int[] currentFloorRec = ElevatorSocketConnectionAutoRun.write("读取楼层信息", currentFloorHexMsg); + int currentFloor = determineFloor(currentFloorRec); + if (currentFloor == floor) { + String openDoorHexMsg = "002B0000000601069C7A0001"; + ElevatorSocketConnectionAutoRun.write("开门", openDoorHexMsg); + JSONObject resp = new JSONObject(); + resp.put("code", 400); + resp.put("message", "电梯已开门,已继续下发开门信号"); + return resp; + } else { + JSONObject resp = new JSONObject(); + resp.put("code", 400); + resp.put("message", "电梯门已打开,无法呼叫楼层!"); + return resp; + } + } + //下发目标楼层 + String callFloorHexMsg = ""; + if (floor == 1) { + callFloorHexMsg = "001A0000000601069C580001"; + } else if (floor == 2) { + callFloorHexMsg = "00170000000601069C580002"; + } else if (floor == 3) { + callFloorHexMsg = "00200000000601069C580004"; + } else { + JSONObject resp = new JSONObject(); + resp.put("code", 400); + resp.put("message", "呼叫楼层号错误!"); + return resp; + } + int[] callFloorRec = ElevatorSocketConnectionAutoRun.write("呼叫楼层", callFloorHexMsg); + int callFloorRecInt = determineCallFloorRec(callFloorRec); + if (callFloorRecInt != floor) { + JSONObject resp = new JSONObject(); + resp.put("code", 400); + resp.put("message", "呼叫楼层响应报文信息楼层与下发楼层信息不一致!"); + return resp; + } + String currentFloorHexMsg = "00050000000601039C410001"; + int[] currentFloorRec = ElevatorSocketConnectionAutoRun.write("读取楼层信息", currentFloorHexMsg); + int currentFloor = determineFloor(currentFloorRec); + if (currentFloor != floor) { + JSONObject resp = new JSONObject(); + resp.put("code", 400); + resp.put("message", "当前电梯所在楼层与呼叫楼层不一致!"); + return resp; + } + // String doorStatusMsg = "00110000000601039CAC0001"; + doorStatusRec = ElevatorSocketConnectionAutoRun.write("查询电梯门状态", doorStatusMsg); + doorStatus = determineDoorStatus(doorStatusRec); + if (!doorStatus) { + String openDoorHexMsg = "002B0000000601069C7A0001"; + ElevatorSocketConnectionAutoRun.write("开门", openDoorHexMsg); + JSONObject resp = new JSONObject(); + resp.put("code", 400); + resp.put("message", "当前电梯门状态为关门中状态!"); + return resp; + } + String openDoorHexMsg = "002B0000000601069C7A0001"; + ElevatorSocketConnectionAutoRun.write("开门", openDoorHexMsg); + JSONObject resp = new JSONObject(); + resp.put("code", 200); + resp.put("message", "ok"); + return resp; + } + + @Override + public JSONArray status(JSONObject param) { + JSONArray array = new JSONArray(); + String elevatorCode = param.getString("elevatorCode"); + if (StrUtil.isEmpty(elevatorCode)) { + JSONObject resp = new JSONObject(); + resp.put("code", 400); + resp.put("message", "电梯编号不能为空"); + array.add(resp); + return array; + } + if (!StrUtil.isEmpty(elevatorCode)) { + String doorStatusMsg = "00110000000601039CAC0001"; + int[] doorStatusRec = ElevatorSocketConnectionAutoRun.write("查询电梯门状态", doorStatusMsg); + boolean doorStatus = determineDoorStatus(doorStatusRec); + String currentFloorHexMsg = "00050000000601039C410001"; + int[] currentFloorRec = ElevatorSocketConnectionAutoRun.write("读取楼层信息", currentFloorHexMsg); + int currentFloor = determineFloor(currentFloorRec); + JSONObject resp = new JSONObject(); + resp.put("elevatorCode", elevatorCode); + resp.put("floor", currentFloor); + resp.put("status", doorStatus ? 1 : 0); + resp.put("move", doorStatus ? 1 : 0); + array.add(resp); + return array; + } + List devices = deviceAppService.findDeviceByType(DeviceType.elevator); + if (CollectionUtil.isEmpty(devices)) { + return array; + } + for (Device device : devices) { +// String doorStatusMsg = "00110000000601039CAC0001"; +// ElevatorSocketConnectionAutoRun.write(doorStatusMsg); +// boolean doorStatus = elevatorSocketConnectionAutoRun.isCurrentFloorStatus(); +// String currentFloorHexMsg = "00050000000601039C410001"; +// ElevatorSocketConnectionAutoRun.write(currentFloorHexMsg); +// int currentFloor = elevatorSocketConnectionAutoRun.getCurrentFloor(); +// JSONObject resp = new JSONObject(); +// resp.put("elevatorCode", elevatorCode); +// resp.put("floor", currentFloor); +// resp.put("status", doorStatus ? 1 : 0); +// resp.put("move", doorStatus ? 0 : 1); +// array.add(resp); + } + return array; + } + + @Override + public JSONObject setDoor(JSONObject param) { + //电梯编号 + String elevatorCode = param.getString("elevatorCode"); + if (StrUtil.isEmpty(elevatorCode)) { + JSONObject resp = new JSONObject(); + resp.put("code", 400); + resp.put("message", "电梯编号不能为空!"); + return resp; + } + Integer status = param.getInteger("status"); + if (status == null) { + JSONObject resp = new JSONObject(); + resp.put("code", 400); + resp.put("message", "开关门状态不能为空!"); + return resp; + } + if (status == 1) { + //开门 + String openDoorHexMsg = "002B0000000601069C7A0001"; + int[] openDoor = ElevatorSocketConnectionAutoRun.write("开门", openDoorHexMsg); + boolean flag = parseOpenResponse(openDoor); + if (!flag) { + JSONObject resp = new JSONObject(); + resp.put("code", 400); + resp.put("message", "下发开门状态响应报文有误!"); + return resp; + } + } else if (status == 0) { + //关门 + String closeDoorHexMsg = "002D0000000601069C7A0008"; + int[] closeDoor = ElevatorSocketConnectionAutoRun.write("关门", closeDoorHexMsg); + boolean flag = parseCloseResponse(closeDoor); + if (!flag) { + JSONObject resp = new JSONObject(); + resp.put("code", 400); + resp.put("message", "下发关门状态响应报文有误!"); + return resp; + } + } + JSONObject resp = new JSONObject(); + resp.put("code", 200); + resp.put("message", "ok"); + return resp; + } + + public static boolean parseOpenResponse(int[] binaryArray) { + int keyByte = binaryArray[1]; + if (keyByte == 0x2B) { + return true; + } + return false; + } + + public static boolean parseCloseResponse(int[] binaryArray) { + int keyByte = binaryArray[1]; + if (keyByte == 0x2D) { + return true; + } + return false; + } + + + /** + * 解析当前楼层 + * + * @param binaryArray + * @return + */ + public static int determineFloor(int[] binaryArray) { + if (binaryArray.length < 8) { + throw new BadRequestException("结果有误!"); + } + int floorByte = binaryArray[9]; + if (floorByte == 0x31) { + return 1; + } else if (floorByte == 0x32) { + return 2; + } else if (floorByte == 0x33) { + return 3; + } + return -1; + } + + /** + * 解析开门关门状态 + * + * @param binaryArray + * @return + */ + public static boolean determineDoorStatus(int[] binaryArray) { + if (binaryArray.length < 8) { + throw new IllegalArgumentException("结果有误!"); + } + int lastByte = binaryArray[binaryArray.length - 1]; + if (lastByte == 0x10) { + return true; + } else if (lastByte == 0x00) { + return false; + } + return false; + } + + + /** + * 解析呼叫楼层 + * + * @param binaryArray + * @return + */ + public static int determineCallFloorRec(int[] binaryArray) { + if (binaryArray.length < 8) { + throw new IllegalArgumentException("结果有误!"); + } + int floorByte = binaryArray[1]; + if (floorByte == 0x1A) { + return 1; + } else if (floorByte == 0x17) { + return 2; + } else if (floorByte == 0x20) { + return 3; + } + return -1; + } + +} \ No newline at end of file diff --git a/acs/nladmin-system/src/main/java/org/nl/acs/instruction/service/dto/InstructionDto.java b/acs/nladmin-system/src/main/java/org/nl/acs/instruction/service/dto/InstructionDto.java index 4405618..afc2424 100644 --- a/acs/nladmin-system/src/main/java/org/nl/acs/instruction/service/dto/InstructionDto.java +++ b/acs/nladmin-system/src/main/java/org/nl/acs/instruction/service/dto/InstructionDto.java @@ -154,6 +154,37 @@ public class InstructionDto implements Serializable { */ private String to_z; + + /** + * 排 + */ + private String from_x2; + + /** + * 列 + */ + private String from_y2; + + /** + * 层 + */ + private String from_z2; + + /** + * 排 + */ + private String to_x2; + + /** + * 列 + */ + private String to_y2; + + /** + * 层 + */ + private String to_z2; + /** * 最后一条指令标识 */ diff --git a/acs/nladmin-system/src/main/java/org/nl/acs/instruction/service/impl/InstructionServiceImpl.java b/acs/nladmin-system/src/main/java/org/nl/acs/instruction/service/impl/InstructionServiceImpl.java index dee2cea..27c72b8 100644 --- a/acs/nladmin-system/src/main/java/org/nl/acs/instruction/service/impl/InstructionServiceImpl.java +++ b/acs/nladmin-system/src/main/java/org/nl/acs/instruction/service/impl/InstructionServiceImpl.java @@ -618,18 +618,24 @@ public class InstructionServiceImpl implements InstructionService, ApplicationAu String next_point_code = inst.getNext_point_code(); String start_device_code = ""; String next_device_code = ""; + String start_point_code2 = inst.getStart_point_code2(); + String next_point_code2 = inst.getNext_point_code2(); + String start_device_code2 = ""; + String next_device_code2 = ""; if (StrUtil.contains(start_point_code, ".")) { String[] point = start_point_code.split("\\."); start_device_code = point[0]; } else { start_device_code = start_point_code; } + if (StrUtil.contains(next_point_code, ".")) { String[] point = next_point_code.split("\\."); next_device_code = point[0]; } else { next_device_code = next_point_code; } + if (StrUtil.contains(start_point_code, "-") && StrUtil.count(start_point_code, "-") == 2) { String[] start_point = start_point_code.split("-"); inst.setFrom_x(start_point[0]); @@ -668,6 +674,59 @@ public class InstructionServiceImpl implements InstructionService, ApplicationAu inst.setNext_device_code(next_device_code); } } + + if (StrUtil.isNotEmpty(start_point_code2) && StrUtil.isNotEmpty(next_point_code2)){ + if (StrUtil.contains(start_point_code2, ".")) { + String[] point = start_point_code2.split("\\."); + start_device_code2 = point[0]; + } else { + start_device_code2 = start_point_code2; + } + if (StrUtil.contains(next_point_code2, ".")) { + String[] point = next_point_code2.split("\\."); + next_device_code2 = point[0]; + } else { + next_device_code2 = next_point_code2; + } + + if (StrUtil.contains(start_point_code2, "-") && StrUtil.count(start_point_code2, "-") == 2) { + String[] start_point2 = start_point_code2.split("-"); + inst.setFrom_x2(start_point2[0]); + inst.setStart_device_code2(start_point2[0]); + inst.setFrom_y2(start_point2[1]); + inst.setFrom_z2(start_point2[2]); + } else { + String start_device2 = deviceAppService.findDeviceByCode(start_device_code2).getDeviceDriverDefinition().getFitDeviceTypes().get(0).name(); + if (StrUtil.equals("storage", start_device2)) { + String[] start_point2 = start_point_code2.split("-"); + inst.setFrom_x2(start_point2[0]); + inst.setStart_device_code2(start_point2[0]); + inst.setFrom_y2(start_point2[1]); + inst.setFrom_z2(start_point2[2]); + } else { + inst.setStart_device_code2(start_device_code2); + } + } + + if (StrUtil.contains(next_point_code2, "-") && StrUtil.count(next_point_code2, "-") == 2) { + String[] next_point2 = next_point_code2.split("-"); + inst.setTo_x2(next_point2[0]); + inst.setNext_device_code2(next_point2[0]); + inst.setTo_y2(next_point2[1]); + inst.setTo_z2(next_point2[2]); + } else { + String next_device2 = deviceAppService.findDeviceByCode(next_device_code2).getDeviceDriverDefinition().getFitDeviceTypes().get(0).name(); + if (StrUtil.equals("storage", next_device2)) { + String[] next_point2 = start_point_code2.split("-"); + inst.setTo_x2(next_point2[0]); + inst.setNext_device_code2(next_point2[0]); + inst.setTo_y2(next_point2[1]); + inst.setTo_z2(next_point2[2]); + } else { + inst.setNext_device_code2(next_device_code2); + } + } + } return inst; } diff --git a/acs/nladmin-system/src/main/java/org/nl/acs/opc/DeviceType.java b/acs/nladmin-system/src/main/java/org/nl/acs/opc/DeviceType.java index d5dabfe..bc9bcbe 100644 --- a/acs/nladmin-system/src/main/java/org/nl/acs/opc/DeviceType.java +++ b/acs/nladmin-system/src/main/java/org/nl/acs/opc/DeviceType.java @@ -17,7 +17,8 @@ public enum DeviceType { autodoor("自动门", 14), shadow("影子设备", 20), other("其他设备", 14), - safetydoor("安全门",17); + safetydoor("安全门", 17), + elevator("电梯", 21); private String description; private int order; diff --git a/acs/nladmin-system/src/main/java/org/nl/acs/socket/elevator/ElevatorSocketUtil.java b/acs/nladmin-system/src/main/java/org/nl/acs/socket/elevator/ElevatorSocketUtil.java new file mode 100644 index 0000000..c5e5806 --- /dev/null +++ b/acs/nladmin-system/src/main/java/org/nl/acs/socket/elevator/ElevatorSocketUtil.java @@ -0,0 +1,162 @@ +package org.nl.acs.socket.elevator; + +import cn.hutool.core.util.ObjectUtil; +import lombok.extern.slf4j.Slf4j; +import org.nl.modules.common.exception.BadRequestException; + +import java.io.*; +import java.net.Socket; +import java.net.SocketTimeoutException; +import java.util.Arrays; + +/** + * @Description TODO + * @Author Gengby + * @Date 2024/8/8 + */ +@Slf4j +public class ElevatorSocketUtil { + //private static Socket socket; + //private static DataOutputStream outToServer; + //private static BufferedReader inFromServer; + //private static String ipAddress = "192.168.8.236"; + //private static int portNumber = 502; + + public static synchronized boolean startConnection(String ip, int port) { + // try { +// ipAddress = ip; +// portNumber = port; +// Socket socket = new Socket(ip, port); +// DataOutputStream outToServer = new DataOutputStream(socket.getOutputStream()); +// BufferedReader inFromServer = new BufferedReader(new InputStreamReader(socket.getInputStream())); +// socket.setSoTimeout(10000); +// return true; +// } catch (IOException e) { +// e.printStackTrace(); +// return false; +// } + return false; + } + + private static synchronized boolean ensureConnection(String ip, int port) { +// if (socket == null || socket.isClosed() || !socket.isConnected()) { +// return startConnection(ip, port); +// } +// return true; + return false; + } + + public static synchronized int[] sendMessageAndGetResponse(String ip, int port, String hexMessage) { + Socket socket = null; + DataOutputStream outToServer = null; + BufferedReader inFromServer = null; + String message = null; + try { + log.info("{}:{},开始连接; 下发报文:{}", ip, port, hexMessage); + socket = new Socket(ip, port); + outToServer = new DataOutputStream(socket.getOutputStream()); + inFromServer = new BufferedReader(new InputStreamReader(socket.getInputStream())); + socket.setSoTimeout(5000); + //sendMessage(outToServer, hexMessage); + byte[] messageBytes = hexStringToByteArray(hexMessage); + outToServer.write(messageBytes); + //String message = receiveMessage(socket); + try (InputStream inputStream = socket.getInputStream(); + ByteArrayOutputStream buffer = new ByteArrayOutputStream()) { + byte[] data = new byte[1024]; + int nRead; + while ((nRead = inputStream.read(data, 0, data.length)) != -1) { + buffer.write(data, 0, nRead); + if (nRead < 1024) { + break; + } + } + buffer.flush(); + message = byteArrayToHexString(buffer.toByteArray()); + log.info("{}:{},开始连接; 读取报文:{}", ip, port, message); + } + if (ObjectUtil.isEmpty(message)) { + return new int[]{-1}; + } + return binary(message); + } catch (IOException e) { + log.error("{}:{},连接失败; 失败原因:{}", ip, port, e.getMessage()); + log.error("{}:{},连接失败; 堆栈信息:{}", ip, port, Arrays.toString(e.getStackTrace())); + e.printStackTrace(); + throw new BadRequestException(e.getMessage()); + } finally { + if (socket != null) { + try { + socket.close(); + } catch (IOException ex) { + log.error("{}:{},连接失败; 失败原因:{}", ip, port, ex.getMessage()); + log.error("{}:{},连接失败; 堆栈信息:{}", ip, port, Arrays.toString(ex.getStackTrace())); + ex.printStackTrace(); + } + } + } + } + + private static void sendMessage(DataOutputStream out, String hexMessage) throws IOException { + byte[] messageBytes = hexStringToByteArray(hexMessage); + out.write(messageBytes); + } + + private static String receiveMessage(Socket socket) throws IOException { + try (InputStream inputStream = socket.getInputStream(); + ByteArrayOutputStream buffer = new ByteArrayOutputStream()) { + byte[] data = new byte[1024]; + int nRead; + while ((nRead = inputStream.read(data, 0, data.length)) != -1) { + buffer.write(data, 0, nRead); + if (nRead < 1024) { + break; + } + } + buffer.flush(); + return byteArrayToHexString(buffer.toByteArray()); + } catch (SocketTimeoutException e) { + e.printStackTrace(); + return null; + } + } + + private static byte[] hexStringToByteArray(String s) { + int length = s.length(); + byte[] data = new byte[length / 2]; + for (int i = 0; i < length; i += 2) { + data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + + Character.digit(s.charAt(i + 1), 16)); + } + return data; + } + + private static String byteArrayToHexString(byte[] bytes) { + StringBuilder sb = new StringBuilder(); + for (byte b : bytes) { + sb.append(String.format("%02X", b)); + } + return sb.toString(); + } + + public static int[] binary(String hexString) { + hexString = hexString.replaceAll(" ", ""); + int[] intArray = new int[hexString.length() / 2]; + for (int i = 0; i < hexString.length(); i += 2) { + String byteString = hexString.substring(i, i + 2); + intArray[i / 2] = Integer.parseInt(byteString, 16); + } + return intArray; + } + + + public static void reverseArray(int[] array) { + int temp; + int n = array.length; + for (int i = 0; i < n / 2; i++) { + temp = array[i]; + array[i] = array[n - i - 1]; + array[n - i - 1] = temp; + } + } +} \ No newline at end of file diff --git a/acs/nladmin-system/src/main/java/org/nl/acs/task/service/dto/TaskDto.java b/acs/nladmin-system/src/main/java/org/nl/acs/task/service/dto/TaskDto.java index 63b3c5b..db9c3dd 100644 --- a/acs/nladmin-system/src/main/java/org/nl/acs/task/service/dto/TaskDto.java +++ b/acs/nladmin-system/src/main/java/org/nl/acs/task/service/dto/TaskDto.java @@ -139,6 +139,36 @@ public class TaskDto implements Serializable { */ private String to_z; + /** + * 排 + */ + private String from_x2; + + /** + * 列 + */ + private String from_y2; + + /** + * 层 + */ + private String from_z2; + + /** + * 排 + */ + private String to_x2; + + /** + * 列 + */ + private String to_y2; + + /** + * 层 + */ + private String to_z2; + /** * 路由方案名称 */ diff --git a/acs/nladmin-system/src/main/java/org/nl/acs/task/service/impl/TaskServiceImpl.java b/acs/nladmin-system/src/main/java/org/nl/acs/task/service/impl/TaskServiceImpl.java index 34969a2..437f88b 100644 --- a/acs/nladmin-system/src/main/java/org/nl/acs/task/service/impl/TaskServiceImpl.java +++ b/acs/nladmin-system/src/main/java/org/nl/acs/task/service/impl/TaskServiceImpl.java @@ -526,6 +526,14 @@ public class TaskServiceImpl implements TaskService, ApplicationAutoInitial { String from_z = null; String to_y = null; String to_z = null; + + String start_point_code2 = task.getStart_point_code2(); + String next_point_code2 = task.getNext_point_code2(); + String from_y2 = null; + String from_z2 = null; + String to_y2 = null; + String to_z2 = null; + if (StrUtil.contains(start_point_code, "-") && StrUtil.count(start_point_code, "-") == 2) { String[] start_point = start_point_code.split("-"); task.setFrom_x(start_point[0]); @@ -577,6 +585,60 @@ public class TaskServiceImpl implements TaskService, ApplicationAutoInitial { } } + if (StrUtil.isNotEmpty(start_point_code2)){ + if (StrUtil.contains(start_point_code2, "-") && StrUtil.count(start_point_code2, "-") == 2) { + String[] start_point2 = start_point_code2.split("-"); + task.setFrom_x2(start_point2[0]); + task.setStart_device_code2(start_point2[0]); + if (Integer.parseInt(start_point2[1]) < 10 && start_point2[1].length() == 1) { + from_y2 = "0" + start_point2[1]; + task.setFrom_y2(from_y2); + } else { + from_y2 = start_point2[1]; + task.setFrom_y2(from_y2); + } + if (Integer.parseInt(start_point2[2]) < 10 && start_point2[2].length() == 1) { + from_z2 = "0" + start_point2[2]; + task.setFrom_z2(from_z2); + } else { + from_z2 = start_point2[2]; + } + task.setStart_point_code2(task.getStart_device_code2() + "-" + from_y2 + "-" + from_z2); + task.setStart_device_code2(task.getStart_device_code2()); + + } else { + String start_device2 = deviceAppService.findDeviceByCode(start_point_code2).getDeviceDriverDefinition().getFitDeviceTypes().get(0).name(); + //如果point_device为货架,则不包含列层信息,需要重新拼接 + if (StrUtil.equals("storage", start_device2)) { + if (StrUtil.isEmpty(task.getFrom_x2())) { + throw new BadRequestException("货位信息起点需要包含列信息"); + } + if (StrUtil.isEmpty(task.getFrom_y2())) { + throw new BadRequestException("货位信息起点需要包含层信息"); + } + if (Integer.parseInt(task.getFrom_y2()) < 10 && task.getFrom_y2().length() == 1) { + from_y2 = "0" + task.getFrom_y2(); + task.setFrom_y2(from_y2); + } else { + from_y2 = task.getFrom_y2(); + } + if (Integer.parseInt(task.getFrom_z2()) < 10 && task.getFrom_z2().length() == 1) { + from_z2 = "0" + task.getFrom_z2(); + task.setFrom_z2(from_z2); + } else { + from_z2 = task.getFrom_z2(); + } + task.setFrom_x2(start_point_code); + task.setStart_point_code2(start_point_code2 + "-" + from_y2 + "-" + from_z2); + task.setStart_device_code2(start_point_code2); + } else { + task.setStart_point_code2(start_point_code2); + task.setStart_device_code2(start_point_code2); + } + } + } + + if (StrUtil.contains(next_point_code, "-") && StrUtil.count(next_point_code, "-") == 2) { String[] next_point = next_point_code.split("-"); task.setNext_device_code(next_point[0]); @@ -629,6 +691,62 @@ public class TaskServiceImpl implements TaskService, ApplicationAutoInitial { } } + + + if (StrUtil.isNotEmpty(task.getNext_point_code2())){ + if (StrUtil.contains(next_point_code2, "-") && StrUtil.count(next_point_code2, "-") == 2) { + String[] next_point2 = next_point_code2.split("-"); + task.setNext_device_code2(next_point2[0]); + task.setTo_x2(next_point2[0]); + if (Integer.parseInt(next_point2[1]) < 10 && next_point2[1].length() == 1) { + to_y2 = "0" + next_point2[1]; + task.setTo_y2(to_y2); + } else { + to_y2 = next_point2[1]; + task.setTo_y2(to_y2); + } + if (Integer.parseInt(next_point2[2]) < 10 && next_point2[2].length() == 1) { + to_z2 = "0" + next_point2[2]; + task.setTo_z2(to_z2); + } else { + to_z2 = next_point2[2]; + task.setTo_z2(to_z2); + } + task.setNext_point_code2(task.getNext_device_code2() + "-" + to_y2 + "-" + to_z2); + task.setNext_device_code2(task.getNext_device_code2()); + + } else { + String next_device2 = deviceAppService.findDeviceByCode(next_point_code2).getDeviceDriverDefinition().getFitDeviceTypes().get(0).name(); + if (StrUtil.equals("storage", next_device2)) { + if (StrUtil.isEmpty(task.getTo_x2())) { + throw new BadRequestException("货位信息终点需要包含列信息"); + } + if (StrUtil.isEmpty(task.getTo_y2())) { + throw new BadRequestException("货位信息终点需要包含层信息"); + } + if (Integer.parseInt(task.getTo_y2()) < 10 && task.getTo_y2().length() == 1) { + to_y2 = "0" + task.getTo_y2(); + task.setTo_y2(to_y2); + } else { + to_y2 = task.getTo_y2(); + } + if (Integer.parseInt(task.getTo_z2()) < 10 && task.getTo_z2().length() == 1) { + to_z2 = "0" + task.getTo_z2(); + task.setTo_z2(to_z2); + } else { + to_z2 = task.getTo_z2(); + } + task.setTo_x2(next_point_code2); + task.setNext_point_code2(next_point_code2 + "-" + to_y2 + "-" + to_z2); + task.setNext_device_code2(next_point_code2); + + } else { + task.setNext_point_code2(next_point_code2); + task.setNext_device_code2(next_point_code2); + + } + } + } return task; } diff --git a/acs/nladmin-system/src/main/java/org/nl/modules/quartz/task/AutoCreateInst.java b/acs/nladmin-system/src/main/java/org/nl/modules/quartz/task/AutoCreateInst.java index d76acde..3d5d294 100644 --- a/acs/nladmin-system/src/main/java/org/nl/modules/quartz/task/AutoCreateInst.java +++ b/acs/nladmin-system/src/main/java/org/nl/modules/quartz/task/AutoCreateInst.java @@ -46,6 +46,8 @@ public class AutoCreateInst { String priority = acsTask.getPriority(); String start_point_code = acsTask.getStart_point_code(); String start_device_code = acsTask.getStart_device_code(); + String start_point_code2 = acsTask.getStart_point_code2(); + String start_device_code2 = acsTask.getStart_device_code2(); String route_plan_code = acsTask.getRoute_plan_code(); String vehicleType = acsTask.getVehicle_type(); //是否复合任务 =0非复合任务 @@ -53,6 +55,8 @@ public class AutoCreateInst { String compound_task_data = null; String next_point_code = acsTask.getNext_point_code(); String next_device_code = acsTask.getNext_device_code(); + String next_point_code2 = acsTask.getNext_point_code2(); + String next_device_code2 = acsTask.getNext_device_code2(); if (StrUtil.isEmpty(start_device_code)) { log.info("任务 [" + taskcode + "] 起点设备为空,无法生成指令。"); acsTask.setRemark("任务 [" + taskcode + "] 起点设备为空,无法生成指令。"); @@ -151,6 +155,10 @@ public class AutoCreateInst { instdto.setNext_device_code(next_device_code); instdto.setStart_point_code(start_point_code); instdto.setNext_point_code(next_point_code); + instdto.setStart_device_code2(start_device_code2); + instdto.setStart_point_code2(start_point_code2); + instdto.setNext_device_code2(next_device_code2); + instdto.setNext_point_code2(next_point_code2); instdto.setCompound_inst_data(compound_task_data); instdto.setPriority(priority); instdto.setInstruction_status("0"); diff --git a/acs/nladmin-system/src/main/java/org/nl/modules/quartz/task/ElevatorAutoReconnection.java b/acs/nladmin-system/src/main/java/org/nl/modules/quartz/task/ElevatorAutoReconnection.java new file mode 100644 index 0000000..8530494 --- /dev/null +++ b/acs/nladmin-system/src/main/java/org/nl/modules/quartz/task/ElevatorAutoReconnection.java @@ -0,0 +1,30 @@ +package org.nl.modules.quartz.task; + +import lombok.extern.slf4j.Slf4j; +import org.nl.acs.auto.run.AutoRunService; +import org.nl.modules.system.service.ParamService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * 电梯自动重连 + */ +@Slf4j +@Component +public class ElevatorAutoReconnection { + + @Autowired + ParamService paramService; + + @Autowired + AutoRunService autoRunService; + + public void run(String threadCode) throws Exception { + String[] threadCodes = threadCode.split(","); + for (String code : threadCodes) { + if (!autoRunService.getThreadByCode(code).isAlive()) { + autoRunService.startThread(code); + } + } + } +} diff --git a/acs/nladmin-system/src/main/java/org/nl/modules/quartz/task/QueryXZAgvDeviceStatus.java b/acs/nladmin-system/src/main/java/org/nl/modules/quartz/task/QueryXZAgvDeviceStatus.java index 6471659..0cfb9be 100644 --- a/acs/nladmin-system/src/main/java/org/nl/modules/quartz/task/QueryXZAgvDeviceStatus.java +++ b/acs/nladmin-system/src/main/java/org/nl/modules/quartz/task/QueryXZAgvDeviceStatus.java @@ -72,6 +72,7 @@ public class QueryXZAgvDeviceStatus { } DecimalFormat hisFormat = new DecimalFormat("########.###"); hisFormat.setRoundingMode(RoundingMode.DOWN); + //x坐标 Double x = rbk_report.getDouble("x"); //y坐标 @@ -102,7 +103,7 @@ public class QueryXZAgvDeviceStatus { if (device != null && device.getDeviceDriver() instanceof XianGongAgvDeviceDriver) { XianGongAgvDeviceDriver xgAGV = (XianGongAgvDeviceDriver) device.getDeviceDriver(); xgAGV.setTaskCode(taskCode); - xgAGV.setBattery_level(battery_level); + xgAGV.setBattery_level(Double.valueOf(hisFormat.format(battery_level))); xgAGV.setAngle(angle); xgAGV.setTime(time); xgAGV.setTotal_time(total_time); diff --git a/acs/nladmin-system/src/main/java/org/nl/start/auto/run/ElevatorSocketConnectionAutoRun.java b/acs/nladmin-system/src/main/java/org/nl/start/auto/run/ElevatorSocketConnectionAutoRun.java new file mode 100644 index 0000000..a0c022f --- /dev/null +++ b/acs/nladmin-system/src/main/java/org/nl/start/auto/run/ElevatorSocketConnectionAutoRun.java @@ -0,0 +1,156 @@ +package org.nl.start.auto.run; + +import cn.hutool.core.util.ObjectUtil; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.nl.acs.auto.run.AbstractAutoRunnable; +import org.nl.modules.system.service.ParamService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.io.*; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.util.Arrays; +import java.util.Date; + +@Slf4j +@Component +@Data +public class ElevatorSocketConnectionAutoRun extends AbstractAutoRunnable { + + + private int recordTimeOut = 10000; + private Date recordTime; + private static Socket socket; + private static DataOutputStream dos; + private static BufferedReader dis; + private boolean bConnected = true; + + + @Autowired + private ParamService paramService; + + + public ElevatorSocketConnectionAutoRun() { + this.recordTime = new Date((new Date()).getTime() - (long) this.recordTimeOut); + } + + @Override + public String getCode() { + return ElevatorSocketConnectionAutoRun.class.getSimpleName(); + } + + @Override + public String getName() { + return "电梯在线Socket连接"; + } + + @Override + public void autoRun() throws IOException, InterruptedException { + System.out.println("电梯链接开始"); + String ip = "192.168.8.236"; + int port = 502; + InetSocketAddress socketAddress = new InetSocketAddress(ip, port); + socket = new Socket(); + socket.connect(socketAddress, 2 * 1000); + socket.setKeepAlive(true); + dos = new DataOutputStream(socket.getOutputStream()); + dis = new BufferedReader(new InputStreamReader(socket.getInputStream())); + while (bConnected) { + String heartbeat = "00060000000601039C430001"; + int[] heartRec = write("心跳", heartbeat); + if (heartRec.length < 8) { + log.error("PLC端开连接......"); + throw new IllegalArgumentException("PLC端开连接!"); + } + Thread.sleep(5000); + } + } + + + @Override + public void stop() { + super.after(); + try { + socket.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + + public static synchronized int[] write(String name, String hexMessage) { + String message = null; + try { + log.info("下发{}报文:{}", name, hexMessage); + dos = new DataOutputStream(socket.getOutputStream()); + dis = new BufferedReader(new InputStreamReader(socket.getInputStream())); + socket.setSoTimeout(5000); + byte[] messageBytes = hexStringToByteArray(hexMessage); + dos.write(messageBytes); + dos.flush(); + InputStream inputStream = socket.getInputStream(); + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + byte[] data = new byte[1024]; + int nRead; + while ((nRead = inputStream.read(data, 0, data.length)) != -1) { + buffer.write(data, 0, nRead); + if (nRead < 1024) { + break; + } + } + buffer.flush(); + message = byteArrayToHexString(buffer.toByteArray()); + log.info("读取{}报文:{}", name, message); + if (ObjectUtil.isEmpty(message)) { + return new int[]{-1}; + } + return binary(message); + } catch (IOException e) { + log.error("失败原因:{}", e.getMessage()); + log.error("堆栈信息:{}", Arrays.toString(e.getStackTrace())); + e.printStackTrace(); + if (ObjectUtil.isNotEmpty(socket)) { + try { + dis.close(); + dos.close(); + socket.close(); + log.error("连接出现异常,已关闭连接"); + } catch (IOException ex) { + ex.printStackTrace(); + } + } + } + return new int[]{-1}; + } + + private static byte[] hexStringToByteArray(String s) { + int length = s.length(); + byte[] data = new byte[length / 2]; + for (int i = 0; i < length; i += 2) { + data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + + Character.digit(s.charAt(i + 1), 16)); + } + return data; + } + + private static String byteArrayToHexString(byte[] bytes) { + StringBuilder sb = new StringBuilder(); + for (byte b : bytes) { + sb.append(String.format("%02X", b)); + } + return sb.toString(); + } + + + public static int[] binary(String hexString) { + hexString = hexString.replaceAll(" ", ""); + int[] intArray = new int[hexString.length() / 2]; + for (int i = 0; i < hexString.length(); i += 2) { + String byteString = hexString.substring(i, i + 2); + intArray[i / 2] = Integer.parseInt(byteString, 16); + } + return intArray; + } +} diff --git a/acs/nladmin-system/src/main/resources/config/application.yml b/acs/nladmin-system/src/main/resources/config/application.yml index 0602e94..9e96fc9 100644 --- a/acs/nladmin-system/src/main/resources/config/application.yml +++ b/acs/nladmin-system/src/main/resources/config/application.yml @@ -2,7 +2,7 @@ spring: freemarker: check-template-location: false profiles: - active: dev2 + active: prod jackson: time-zone: GMT+8 data: diff --git a/acs/nladmin-system/src/main/resources/log/Elevator.xml b/acs/nladmin-system/src/main/resources/log/Elevator.xml new file mode 100644 index 0000000..d21098d --- /dev/null +++ b/acs/nladmin-system/src/main/resources/log/Elevator.xml @@ -0,0 +1,33 @@ + + + + + + + + + ${LOG_HOME}/电梯/%d{yyyy-MM-dd}.%i.log + + 15 + + 200MB + + 2GB + + + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n + ${log.charset} + + + + + + + + 512 + + + + + diff --git a/acs/nladmin-system/src/main/resources/log/ElevatorSocketUtil.xml b/acs/nladmin-system/src/main/resources/log/ElevatorSocketUtil.xml new file mode 100644 index 0000000..d00e533 --- /dev/null +++ b/acs/nladmin-system/src/main/resources/log/ElevatorSocketUtil.xml @@ -0,0 +1,33 @@ + + + + + + + + + ${LOG_HOME}/电梯请求报文信息/%d{yyyy-MM-dd}.%i.log + + 15 + + 200MB + + 2GB + + + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n + ${log.charset} + + + + + + + + 512 + + + + + diff --git a/acs/nladmin-system/src/main/resources/logback-spring.xml b/acs/nladmin-system/src/main/resources/logback-spring.xml index f00e416..4e378ad 100644 --- a/acs/nladmin-system/src/main/resources/logback-spring.xml +++ b/acs/nladmin-system/src/main/resources/logback-spring.xml @@ -21,9 +21,11 @@ https://juejin.cn/post/6844903775631572999 - - - + + + + + ${log.pattern} diff --git a/acs/nladmin-ui/src/views/acs/device/config.vue b/acs/nladmin-ui/src/views/acs/device/config.vue index 6e6e0c4..ad9a771 100644 --- a/acs/nladmin-ui/src/views/acs/device/config.vue +++ b/acs/nladmin-ui/src/views/acs/device/config.vue @@ -103,6 +103,7 @@ import conveyor_ssx_barcode from '@/views/acs/device/driver/lnsh/conveyor_ssx_ba import conveyor_press_station from '@/views/acs/device/driver/lnsh/conveyor_press_station' import xg_agv from '@/views/acs/device/driver/xg/xg_agv' import rgv_station from '@/views/acs/device/driver/rgv_station' +import standard_elevator from '@/views/acs/device/driver/standard_elevator' import agv_ndc_one from '@/views/acs/device/driver/agv/agv_ndc_one' import agv_ndc_two from '@/views/acs/device/driver/agv/agv_ndc_two' import package_site from './driver/lnsh/package_site.vue' @@ -146,7 +147,8 @@ export default { nl4_station, photoelectric_detection_station, xg_agv, - rgv_station + rgv_station, + standard_elevator }, dicts: ['device_type'], mixins: [crud], diff --git a/acs/nladmin-ui/src/views/acs/device/driver/standard_elevator.vue b/acs/nladmin-ui/src/views/acs/device/driver/standard_elevator.vue new file mode 100644 index 0000000..c8c914e --- /dev/null +++ b/acs/nladmin-ui/src/views/acs/device/driver/standard_elevator.vue @@ -0,0 +1,111 @@ + + + + + diff --git a/lms/nladmin-system/nlsso-server/pom.xml b/lms/nladmin-system/nlsso-server/pom.xml index bf6ef6d..c923352 100644 --- a/lms/nladmin-system/nlsso-server/pom.xml +++ b/lms/nladmin-system/nlsso-server/pom.xml @@ -232,17 +232,17 @@ org.apache.poi poi-ooxml-schemas - 3.17 + 4.1.2 org.apache.poi poi - 3.17 + 4.1.2 org.apache.poi poi-ooxml - 3.17 + 4.1.2 xerces diff --git a/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/bigScreen/controller/BigScreenController.java b/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/bigScreen/controller/BigScreenController.java index cc3acc3..71b5ed7 100644 --- a/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/bigScreen/controller/BigScreenController.java +++ b/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/bigScreen/controller/BigScreenController.java @@ -73,4 +73,10 @@ public class BigScreenController { return new ResponseEntity<>(bigScreenService.todayLoadingAndUnloadingStatistics(), HttpStatus.OK); } + @PostMapping("/getAllBigScreen") + @Log("获取所有大屏信息") + public ResponseEntity getAllBigScreen() { + return new ResponseEntity<>(bigScreenService.getAllBigScreen(), HttpStatus.OK); + } + } \ No newline at end of file diff --git a/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/bigScreen/service/BigScreenService.java b/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/bigScreen/service/BigScreenService.java index 293640b..03f76f8 100644 --- a/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/bigScreen/service/BigScreenService.java +++ b/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/bigScreen/service/BigScreenService.java @@ -1,6 +1,7 @@ package org.nl.wms.bigScreen.service; import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; import java.util.List; import java.util.Map; @@ -66,4 +67,6 @@ public interface BigScreenService { * @return */ List> inventoryIOAnalysis(); + + JSONObject getAllBigScreen(); } \ No newline at end of file diff --git a/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/bigScreen/service/impl/BigScreenServiceImpl.java b/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/bigScreen/service/impl/BigScreenServiceImpl.java index ee07c61..2da9d70 100644 --- a/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/bigScreen/service/impl/BigScreenServiceImpl.java +++ b/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/bigScreen/service/impl/BigScreenServiceImpl.java @@ -1,6 +1,7 @@ package org.nl.wms.bigScreen.service.impl; import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; import org.nl.wms.bigScreen.service.BigScreenService; import org.nl.wms.bigScreen.service.mapper.BigScreenMapper; import org.nl.wms.ext.acs.service.WmsToAcsService; @@ -74,4 +75,18 @@ public class BigScreenServiceImpl implements BigScreenService { List> res = bigScreenMapper.inventoryIOAnalysis(); return res; } + + @Override + public JSONObject getAllBigScreen() { + JSONObject resp = new JSONObject(); + resp.put("inventoryAnalysis", this.inventoryAnalysis()); + resp.put("agvInfo", this.agvInfo()); + resp.put("rgvInfo", this.rgvInfo()); + resp.put("todayProduceStatistic", this.todayProduceStatistic()); + resp.put("todayLoadingAndUnloadingStatistics", this.todayLoadingAndUnloadingStatistics()); + resp.put("todayTask", this.todayTask()); + resp.put("historyInventoryIOAnalysis", this.historyInventoryIOAnalysis()); + resp.put("inventoryIOAnalysis", this.inventoryIOAnalysis()); + return resp; + } } \ No newline at end of file diff --git a/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/database/material/service/impl/MdBaseMaterialServiceImpl.java b/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/database/material/service/impl/MdBaseMaterialServiceImpl.java index b389694..6cca3ef 100644 --- a/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/database/material/service/impl/MdBaseMaterialServiceImpl.java +++ b/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/database/material/service/impl/MdBaseMaterialServiceImpl.java @@ -1,6 +1,7 @@ package org.nl.wms.database.material.service.impl; import cn.hutool.core.date.DateUtil; +import cn.hutool.core.lang.Assert; import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.poi.excel.ExcelReader; @@ -26,6 +27,7 @@ import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletRequest; import java.io.InputStream; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; @@ -138,11 +140,64 @@ public class MdBaseMaterialServiceImpl extends ServiceImpl> read = excelReader.read(1, excelReader.getRowCount()); // 循环获取的数据 + MdBaseMaterial mdBaseMaterial = null; + List list = new ArrayList<>(); + for (int i = 0; i < read.size(); i++) { + mdBaseMaterial = new MdBaseMaterial(); + + List material = read.get(i); + Object materialCode = material.get(0); + Assert.notNull(materialCode); + Object materialName = material.get(1); + Assert.notNull(materialName); + Object specification = material.get(2); + Assert.notNull(specification); + Object model = material.get(3); + mdBaseMaterial.setMaterial_id(IdUtil.getSnowflake(1, 1).nextIdStr()); + mdBaseMaterial.setMaterial_code(materialCode.toString()); + mdBaseMaterial.setMaterial_name(materialName.toString()); + mdBaseMaterial.setMaterial_spec(specification.toString()); + mdBaseMaterial.setMaterial_model(model + ""); + mdBaseMaterial.setCreate_id(SecurityUtils.getCurrentUserId()); + mdBaseMaterial.setCreate_name(SecurityUtils.getCurrentNickName()); + mdBaseMaterial.setCreate_time(DateUtil.now()); + // mdBaseMaterialMapper.insert(mdBaseMaterial); + list.add(mdBaseMaterial); } +// ExcelReader excelReader = ExcelUtil.getReader(inputStream); +// List> readAll = excelReader.readAll(); +// List list = new ArrayList<>(); +// // 3.处理读取到的数据 +// MdBaseMaterial mdBaseMaterial = null; +// for (Map row : readAll) { +// mdBaseMaterial = new MdBaseMaterial(); +// // 这里可以对每一行数据进行处理 +// String materialCode = (String) row.get("物料编码"); +// String materialName = (String) row.get("物料名称"); +// String specification = (String) row.get("规格"); +// String model = (String) row.get("型号"); +// String materialCategory = (String) row.get("物料分类"); +// String productSeries = (String) row.get("产品系列"); +// String unit = (String) row.get("单位"); +// Double weight = row.get("单重") != null ? Double.parseDouble(row.get("单重").toString()) : null; +// String originalMaterialInfo = (String) row.get("原始物料信息"); +// mdBaseMaterial.setMaterial_id(IdUtil.getSnowflake(1, 1).nextIdStr()); +// mdBaseMaterial.setMaterial_code(materialCode); +// mdBaseMaterial.setCreate_name(materialName); +// mdBaseMaterial.setMaterial_spec(specification); +// mdBaseMaterial.setMaterial_model(model); +// list.add(mdBaseMaterial); +// } + this.saveBatch(list); + // 4.关闭资源 + excelReader.close(); + } } diff --git a/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/pda/controller/PdaController.java b/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/pda/controller/PdaController.java index 248be03..9d30219 100644 --- a/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/pda/controller/PdaController.java +++ b/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/pda/controller/PdaController.java @@ -102,6 +102,18 @@ public class PdaController { return new ResponseEntity<>(pdaService.callEmptyVehicle(requestParam), HttpStatus.OK); } + @PostMapping("/lmzbCallEmptyVehicle") + @Log("蜡模制备区呼叫空托盘") + public ResponseEntity lmzbCallEmptyVehicle(@Validated @RequestBody CommonPointQueryDto requestParam) { + return new ResponseEntity<>(pdaService.lmzbCallEmptyVehicle(requestParam), HttpStatus.OK); + } + + @PostMapping("/sendEmptyVehicle") + @Log("型壳焙烧区空托位送空托盘") + public ResponseEntity sendEmptyVehicle(@Validated @RequestBody CommonPointQueryDto requestParam) { + return new ResponseEntity<>(pdaService.sendEmptyVehicle(requestParam), HttpStatus.OK); + } + @PostMapping("/emptyInStore") @Log("空托盘入库") public ResponseEntity emptyInStore(@Validated @RequestBody VehicleInStoreDto requestParam) { diff --git a/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/pda/service/PdaService.java b/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/pda/service/PdaService.java index 4cf93fd..56da9f8 100644 --- a/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/pda/service/PdaService.java +++ b/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/pda/service/PdaService.java @@ -386,4 +386,8 @@ public interface PdaService { * @return */ List queryExistGroup(); + + PdaResponseVo lmzbCallEmptyVehicle(CommonPointQueryDto requestParam); + + PdaResponseVo sendEmptyVehicle(CommonPointQueryDto requestParam); } diff --git a/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/pda/service/impl/PdaServiceImpl.java b/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/pda/service/impl/PdaServiceImpl.java index e2c5708..449c21b 100644 --- a/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/pda/service/impl/PdaServiceImpl.java +++ b/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/pda/service/impl/PdaServiceImpl.java @@ -1,6 +1,7 @@ package org.nl.wms.pda.service.impl; import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.date.DateUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.IdUtil; @@ -222,6 +223,12 @@ public class PdaServiceImpl implements PdaService { if (!PointStatusEnum.FULL_POINT.getCode().equals(point.getPoint_status())) { throw new BadRequestException("点位:" + point_code + ",状态不是有料状态!"); } + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + lqw.eq(SchBasePoint::getPoint_status, PointStatusEnum.EMPTY_VEHICLE.getCode()); + List list = pointService.list(lqw); + if (CollectionUtil.isEmpty(list)) { + throw new BadRequestException("原材料库中没有空载具!"); + } JSONObject param = new JSONObject(); param.put("device_code", point_code); param.put("config_code", "ZPRKTask"); @@ -276,6 +283,52 @@ public class PdaServiceImpl implements PdaService { return PdaResponseVo.pdaResultOk("空托盘出库请求成功"); } + @Override + public PdaResponseVo lmzbCallEmptyVehicle(CommonPointQueryDto requestParam) { + Assert.notNull(requestParam, "参数不能为空!"); + String point_code = requestParam.getPoint_code(); + SchBasePoint point = pointService.getById(point_code); + if (ObjectUtil.isEmpty(point)) { + throw new BadRequestException("点位:" + point_code + ",对应的点位信息不存在!"); + } + if (!point.getPoint_status().equals(PointStatusEnum.EMPTY_POINT.getCode())) { + throw new BadRequestException("点位:" + point_code + ",点位状态不为空位!"); + } + if (!RegionEnum.LMZB.getRegion_code().equals(point.getRegion_code()) || !PointTypeEnum.FULL_POINT.getCode().equals(point.getPoint_type())) { + throw new BadRequestException("点位:" + point_code + ",不属于蜡模制备区域满托位,无法呼叫空托盘!"); + } + JSONObject param = new JSONObject(); + param.put("device_code", requestParam.getPoint_code()); + param.put("config_code", "LMZBQKTask"); + param.put("requestNo", IdUtil.simpleUUID()); + param.put("user_id", "1"); + taskService.apply(param); + return PdaResponseVo.pdaResultOk("蜡模制备区呼叫空托盘请求成功"); + } + + @Override + public PdaResponseVo sendEmptyVehicle(CommonPointQueryDto requestParam) { + Assert.notNull(requestParam, "参数不能为空!"); + String point_code = requestParam.getPoint_code(); + SchBasePoint point = pointService.getById(point_code); + if (ObjectUtil.isEmpty(point)) { + throw new BadRequestException("点位:" + point_code + ",对应的点位信息不存在!"); + } + if (!point.getPoint_status().equals(PointStatusEnum.EMPTY_VEHICLE.getCode())) { + throw new BadRequestException("点位:" + point_code + ",点位状态不为空载具!"); + } + if (!RegionEnum.XKBS.getRegion_code().equals(point.getRegion_code()) || !PointTypeEnum.FULL_POINT.getCode().equals(point.getPoint_type())) { + throw new BadRequestException("点位:" + point_code + ",不属于型壳焙烧区满托位,无法送空托盘!"); + } + JSONObject param = new JSONObject(); + param.put("device_code", requestParam.getPoint_code()); + param.put("config_code", "XKBSSKTask"); + param.put("requestNo", IdUtil.simpleUUID()); + param.put("user_id", "1"); + taskService.apply(param); + return PdaResponseVo.pdaResultOk("型壳焙烧区空托位送空托请求成功"); + } + @Override public PdaResponseVo emptyInStore(VehicleInStoreDto requestParam) { Assert.notNull(requestParam, "参数不能为空!"); @@ -328,6 +381,9 @@ public class PdaServiceImpl implements PdaService { List vehicleLinkVoList = new ArrayList<>(); for (SchBaseVehiclematerialgroup group : list) { SchBasePoint point = pointService.getById(group.getPoint_code()); + if (point == null) { + continue; + } if (!RegionEnum.YCL.getRegion_code().equals(point.getRegion_code())) { continue; } @@ -527,6 +583,20 @@ public class PdaServiceImpl implements PdaService { public PdaResponseVo createP2pTask(FullVehicleOutDto requestParam) { Assert.notNull(requestParam, "参数不能为空!"); this.checkNextPoint(requestParam.getPoint_code1(), requestParam.getPoint_code2()); + SchBasePoint point1 = pointService.getById(requestParam.getPoint_code1()); + if (point1 == null) { + throw new BadRequestException("起点不存在!"); + } + if (PointStatusEnum.EMPTY_POINT.getCode().equals(point1.getPoint_status())) { + throw new BadRequestException("起点无货!"); + } + SchBasePoint point2 = pointService.getById(requestParam.getPoint_code2()); + if (point2 == null) { + throw new BadRequestException("终点不存在!"); + } + if (!PointStatusEnum.EMPTY_POINT.getCode().equals(point2.getPoint_status())) { + throw new BadRequestException("终点有货!"); + } JSONObject param = new JSONObject(); param.put("device_code", requestParam.getPoint_code1()); param.put("device_code2", requestParam.getPoint_code2()); diff --git a/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/sch/task_manage/task/tasks/lmzb/LMZBQKTask.java b/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/sch/task_manage/task/tasks/lmzb/LMZBQKTask.java index ffa5c79..64d534d 100644 --- a/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/sch/task_manage/task/tasks/lmzb/LMZBQKTask.java +++ b/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/sch/task_manage/task/tasks/lmzb/LMZBQKTask.java @@ -64,9 +64,9 @@ public class LMZBQKTask extends AbstractTask { SchBasePoint point = findStartPoint(startRegionStr); if (ObjectUtil.isEmpty(point)) { // 消息通知 - noticeService.createNotice("空托缓存2区暂无空托盘!", TASK_CONFIG_CODE + task.getPoint_code2(), + noticeService.createNotice("暂无空托盘!", TASK_CONFIG_CODE + task.getPoint_code2(), NoticeTypeEnum.WARN.getCode()); - throw new BadRequestException("空托缓存2区暂无空托盘!"); + throw new BadRequestException("暂无空托盘!"); } // 设置终点并修改创建成功状态 task.setPoint_code1(point.getPoint_code()); @@ -101,12 +101,12 @@ public class LMZBQKTask extends AbstractTask { .eq(SchBasePoint::getIs_used, true); List schBasePoints = pointService.list(lam); SchBasePoint start_point = schBasePoints.stream() - .filter(point -> RegionEnum.BCXKZB.getRegion_code().equals(point.getRegion_code())) + .filter(point -> RegionEnum.LMZB.getRegion_code().equals(point.getRegion_code())) .filter(point -> PointTypeEnum.EMPTY_POINT.getCode().equals(point.getPoint_type())) .findFirst() .orElse(null); if (ObjectUtil.isEmpty(start_point)) { - start_point = schBasePoints.stream().filter(point -> RegionEnum.KTPHC2.getRegion_code().equals(point.getRegion_code())) + start_point = schBasePoints.stream().filter(point -> RegionEnum.KTPHC1.getRegion_code().equals(point.getRegion_code())) .findFirst().orElse(null); } return ObjectUtil.isNotEmpty(start_point) ? start_point : null; diff --git a/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/sch/task_manage/task/tasks/xkbs/XKBSSKTask.java b/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/sch/task_manage/task/tasks/xkbs/XKBSSKTask.java new file mode 100644 index 0000000..a4c4209 --- /dev/null +++ b/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/sch/task_manage/task/tasks/xkbs/XKBSSKTask.java @@ -0,0 +1,212 @@ +package org.nl.wms.sch.task_manage.task.tasks.xkbs; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import org.nl.common.exception.BadRequestException; +import org.nl.system.service.notice.ISysNoticeService; +import org.nl.wms.sch.point.service.ISchBasePointService; +import org.nl.wms.sch.point.service.dao.SchBasePoint; +import org.nl.wms.sch.region.service.RegionEnum; +import org.nl.wms.sch.task.service.ISchBaseTaskService; +import org.nl.wms.sch.task.service.ISchBaseTaskconfigService; +import org.nl.wms.sch.task.service.dao.SchBaseTask; +import org.nl.wms.sch.task.service.dao.SchBaseTaskconfig; +import org.nl.wms.sch.task_manage.AbstractTask; +import org.nl.wms.sch.task_manage.GeneralDefinition; +import org.nl.wms.sch.task_manage.enums.NoticeTypeEnum; +import org.nl.wms.sch.task_manage.enums.PointStatusEnum; +import org.nl.wms.sch.task_manage.enums.PointTypeEnum; +import org.nl.wms.sch.task_manage.enums.TaskFinishedTypeEnum; +import org.nl.wms.sch.task_manage.task.TaskType; +import org.nl.wms.sch.task_manage.task.core.TaskStatus; +import org.nl.wms.util.PointUtils; +import org.nl.wms.util.TaskUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 型壳焙烧区空托位送空托盘到空托盘缓存1区或者蜡模制备空托位 + * + * @author onepiece + */ +@Component(value = "XKBSSKTask") +@TaskType("XKBSSKTask") +public class XKBSSKTask extends AbstractTask { + private static final String TASK_CONFIG_CODE = "XKBSSKTask"; + @Autowired + private ISchBasePointService pointService; + @Autowired + private ISchBaseTaskService taskService; + @Autowired + private ISchBaseTaskconfigService taskConfigService; + @Autowired + private ISysNoticeService noticeService; + + @Override + public void create() throws BadRequestException { + + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void createCompletion(SchBaseTask task) { + // 配置信息 + SchBaseTaskconfig taskConfig = taskConfigService.getOne(new LambdaQueryWrapper() + .eq(SchBaseTaskconfig::getConfig_code, TASK_CONFIG_CODE)); + TaskUtils.setUpdateByAcs(task); + List nextRegionStr = Arrays.stream(taskConfig.getNext_region_str().split(",")) + .collect(Collectors.toList()); + // 找终点 + SchBasePoint point = findEndPoint(nextRegionStr); + if (ObjectUtil.isEmpty(point)) { + // 消息通知 + noticeService.createNotice("空托盘缓存1区或者蜡模制备区空托位未找到终点空位!", TASK_CONFIG_CODE + task.getPoint_code2(), + NoticeTypeEnum.WARN.getCode()); + throw new BadRequestException("空托盘缓存1区或者蜡模制备区空托位未找到终点空位!"); + } + + // 设置终点并修改创建成功状态 + task.setPoint_code2(point.getPoint_code()); + String point_code1 = task.getPoint_code1(); + SchBasePoint point1 = pointService.getById(point_code1); + if (point1 != null) { + task.setVehicle_code(point1.getVehicle_code()); + task.setVehicle_type(point1.getVehicle_type()); + } + task.setRemark(""); + task.setVehicle_qty(1); + task.setTask_status(TaskStatus.CREATED.getCode()); + task.setCreate_mode(GeneralDefinition.HAND_CREATION); + taskService.save(task); + // 点位更新 + point.setIng_task_code(task.getTask_code()); + PointUtils.setUpdateByAcs(point); + pointService.updateById(point); + } + + /** + * 找空位 + * + * @param nextRegionStr + * @return + */ + private SchBasePoint findEndPoint(List nextRegionStr) { + LambdaQueryWrapper lam = new LambdaQueryWrapper<>(); + // 默认一直都有载具 + lam.in(SchBasePoint::getRegion_code, nextRegionStr) + // 点位状态是空位 + .eq(SchBasePoint::getPoint_status, PointStatusEnum.EMPTY_POINT.getCode()) + // 当前执行的任务为空或者NULL,有数据表示锁住 + .and(la -> la.isNull(SchBasePoint::getIng_task_code) + .or() + .eq(SchBasePoint::getIng_task_code, "")) + .eq(SchBasePoint::getIs_used, true); + List schBasePoints = pointService.list(lam); + SchBasePoint next_point = schBasePoints.stream() + .filter(point -> RegionEnum.LMZB.getRegion_code().equals(point.getRegion_code())) + .filter(point -> PointTypeEnum.EMPTY_POINT.getCode().equals(point.getPoint_type())) + .findFirst() + .orElse(null); + if (ObjectUtil.isEmpty(next_point)) { + next_point = schBasePoints.stream().filter(point -> RegionEnum.KTPHC1.getRegion_code().equals(point.getRegion_code())) + .findFirst().orElse(null); + } + return ObjectUtil.isNotEmpty(schBasePoints) ? next_point : null; + } + + @Override + protected void updateStatus(String task_code, TaskStatus status) { + // 校验任务 + SchBaseTask taskObj = taskService.getByCode(task_code); + if (taskObj.getTask_status().equals(TaskStatus.FINISHED.getCode())) { + throw new BadRequestException("该任务已完成!"); + } + if (taskObj.getTask_status().equals(TaskStatus.CANCELED.getCode())) { + throw new BadRequestException("该任务已取消!"); + } + // 根据传来的类型去对任务进行操作 + if (status.equals(TaskStatus.EXECUTING)) { + taskObj.setTask_status(TaskStatus.EXECUTING.getCode()); + taskObj.setRemark("执行中"); + TaskUtils.setUpdateByAcs(taskObj); + taskService.updateById(taskObj); + } + if (status.equals(TaskStatus.FINISHED)) { + this.finishTask(taskObj, TaskFinishedTypeEnum.AUTO_ACS); + } + if (status.equals(TaskStatus.CANCELED)) { + this.cancelTask(taskObj, TaskFinishedTypeEnum.AUTO_ACS); + } + } + + @Override + public void forceFinish(String task_code) { + SchBaseTask taskObj = taskService.getByCode(task_code); + if (ObjectUtil.isEmpty(taskObj)) { + throw new BadRequestException("该任务不存在"); + } + this.finishTask(taskObj, TaskFinishedTypeEnum.MANUAL_PC); + } + + @Override + public void cancel(String task_code) { + SchBaseTask taskObj = taskService.getByCode(task_code); + if (ObjectUtil.isEmpty(taskObj)) { + throw new BadRequestException("该任务不存在"); + } + this.cancelTask(taskObj, TaskFinishedTypeEnum.MANUAL_PC); + } + + @Transactional(rollbackFor = Exception.class) + public void finishTask(SchBaseTask taskObj, TaskFinishedTypeEnum taskFinishedType) { + // 获取参数 + SchBasePoint startPointObj = pointService.getById(taskObj.getPoint_code1()); + // 起点清空 + if (ObjectUtil.isNotEmpty(startPointObj)) { + PointUtils.setUpdateByType(startPointObj, taskFinishedType); + PointUtils.clearPoint(startPointObj); + pointService.updateById(startPointObj); + } + //更新终点的点位信息 + SchBasePoint endPointObj = pointService.getById(taskObj.getPoint_code2()); + if (ObjectUtil.isNotEmpty(endPointObj)) { + endPointObj.setIng_task_code(""); + endPointObj.setPoint_status(PointStatusEnum.EMPTY_VEHICLE.getCode()); + endPointObj.setVehicle_code(taskObj.getVehicle_code()); + endPointObj.setVehicle_type(taskObj.getVehicle_type()); + endPointObj.setVehicle_qty(taskObj.getVehicle_qty()); + endPointObj.setUpdate_time(DateUtil.now()); + PointUtils.setUpdateByType(endPointObj, taskFinishedType); + pointService.updateById(endPointObj); + } + // 任务完成 + taskObj.setTask_status(TaskStatus.FINISHED.getCode()); + taskObj.setRemark(GeneralDefinition.TASK_FINISH); + taskObj.setFinished_type(taskFinishedType.getCode()); + TaskUtils.setUpdateByType(taskObj, taskFinishedType); + taskService.updateById(taskObj); + } + + @Transactional(rollbackFor = Exception.class) + public void cancelTask(SchBaseTask taskObj, TaskFinishedTypeEnum taskFinishedType) { + // 获取参数 + SchBasePoint endPointObj = pointService.getById(taskObj.getPoint_code2()); + // 终点解锁 + if (ObjectUtil.isNotEmpty(endPointObj)) { + endPointObj.setIng_task_code(""); + PointUtils.setUpdateByType(endPointObj, taskFinishedType); + pointService.updateById(endPointObj); + } + taskObj.setTask_status(TaskStatus.CANCELED.getCode()); + taskObj.setRemark(GeneralDefinition.TASK_CANCEL); + taskObj.setFinished_type(taskFinishedType.getCode()); + TaskUtils.setUpdateByType(taskObj, taskFinishedType); + taskService.updateById(taskObj); + } +} diff --git a/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/sch/task_manage/task/tasks/ycl/ZPRKTask.java b/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/sch/task_manage/task/tasks/ycl/ZPRKTask.java index d62f59b..788d49d 100644 --- a/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/sch/task_manage/task/tasks/ycl/ZPRKTask.java +++ b/lms/nladmin-system/nlsso-server/src/main/java/org/nl/wms/sch/task_manage/task/tasks/ycl/ZPRKTask.java @@ -8,7 +8,6 @@ import org.nl.common.utils.SecurityUtils; import org.nl.system.service.notice.ISysNoticeService; import org.nl.wms.sch.group.service.ISchBaseVehiclematerialgroupService; import org.nl.wms.sch.group.service.dao.SchBaseVehiclematerialgroup; -import org.nl.wms.sch.group.service.impl.SchBaseVehiclematerialgroupServiceImpl; import org.nl.wms.sch.point.service.ISchBasePointService; import org.nl.wms.sch.point.service.dao.SchBasePoint; import org.nl.wms.sch.task.service.ISchBaseTaskService; @@ -26,8 +25,10 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Optional; import java.util.stream.Collectors; /** @@ -58,34 +59,53 @@ public class ZPRKTask extends AbstractTask { @Override @Transactional(rollbackFor = Exception.class) public void createCompletion(SchBaseTask task) { - // 配置信息 - SchBaseTaskconfig taskConfig = taskConfigService.getOne(new LambdaQueryWrapper() - .eq(SchBaseTaskconfig::getConfig_code, TASK_CONFIG_CODE)); - TaskUtils.setUpdateByAcs(task); - List nextRegionStr = Arrays.stream(taskConfig.getNext_region_str().split(",")) - .collect(Collectors.toList()); - // 找终点 - SchBasePoint point = findEndPoint(nextRegionStr); - if (ObjectUtil.isEmpty(point)) { - // 消息通知 - noticeService.createNotice("原材料库未找到终点空位!", TASK_CONFIG_CODE + task.getPoint_code2(), - NoticeTypeEnum.WARN.getCode()); - throw new BadRequestException("原材料库未找到终点空位!"); + synchronized (ZPRKTask.class) { + // 配置信息 + SchBaseTaskconfig taskConfig = taskConfigService.getOne(new LambdaQueryWrapper() + .eq(SchBaseTaskconfig::getConfig_code, TASK_CONFIG_CODE)); + TaskUtils.setUpdateByAcs(task); + List nextRegionStr = Arrays.stream(taskConfig.getNext_region_str().split(",")) + .collect(Collectors.toList()); + + List startRegionStr = Arrays.stream(taskConfig.getStart_region_str().split(",")) + .collect(Collectors.toList()); + // 找终点 + SchBasePoint point = findEndPoint(nextRegionStr); + if (ObjectUtil.isEmpty(point)) { + // 消息通知 + noticeService.createNotice("原材料库未找到终点空位!", TASK_CONFIG_CODE + task.getPoint_code1(), + NoticeTypeEnum.WARN.getCode()); + throw new BadRequestException("原材料库未找到终点空位!"); + } + SchBasePoint point3 = findStartPoint(startRegionStr); + if (ObjectUtil.isEmpty(point3)) { + // 消息通知 + noticeService.createNotice("原材料库未找到起点空载具!", TASK_CONFIG_CODE + task.getPoint_code1(), + NoticeTypeEnum.WARN.getCode()); + throw new BadRequestException("原材料库未找到起点空载具!"); + } + // 设置终点并修改创建成功状态 + task.setPoint_code2(point.getPoint_code()); + task.setPoint_code3(point3.getPoint_code()); + task.setPoint_code4(task.getPoint_code1()); + task.setRemark(""); + SchBasePoint startPointObj = pointService.getById(task.getPoint_code1()); + task.setVehicle_qty(startPointObj.getVehicle_qty()); + task.setVehicle_type(startPointObj.getVehicle_type()); + task.setVehicle_code(startPointObj.getVehicle_code()); + task.setVehicle_code2(point3.getVehicle_code()); + task.setTask_status(TaskStatus.CREATED.getCode()); + task.setCreate_mode(GeneralDefinition.HAND_CREATION); + taskService.save(task); + // 点位更新 + point.setIng_task_code(task.getTask_code()); + PointUtils.setUpdateByAcs(point); + pointService.updateById(point); + + point3.setIng_task_code(task.getTask_code()); + PointUtils.setUpdateByAcs(point3); + pointService.updateById(point3); } - // 设置终点并修改创建成功状态 - task.setPoint_code2(point.getPoint_code()); - task.setRemark(""); - SchBasePoint startPointObj = pointService.getById(task.getPoint_code1()); - task.setVehicle_qty(startPointObj.getVehicle_qty()); - task.setVehicle_type(startPointObj.getVehicle_type()); - task.setVehicle_code(startPointObj.getVehicle_code()); - task.setTask_status(TaskStatus.CREATED.getCode()); - task.setCreate_mode(GeneralDefinition.HAND_CREATION); - taskService.save(task); - // 点位更新 - point.setIng_task_code(task.getTask_code()); - PointUtils.setUpdateByAcs(point); - pointService.updateById(point); } /** @@ -106,6 +126,32 @@ public class ZPRKTask extends AbstractTask { .eq(SchBasePoint::getIng_task_code, "")) .eq(SchBasePoint::getIs_used, true); List schBasePoints = pointService.list(lam); + List list = Optional.ofNullable(schBasePoints) + .orElse(new ArrayList<>()) + .stream() + .filter(point -> !point.getPoint_code().endsWith("03")) + .collect(Collectors.toList()); + return ObjectUtil.isNotEmpty(list) ? list.get(0) : null; + } + + /** + * 从原材料库找空载具 + * + * @param startRegionStr + * @return + */ + private SchBasePoint findStartPoint(List startRegionStr) { + LambdaQueryWrapper lam = new LambdaQueryWrapper<>(); + // 默认一直都有载具 + lam.in(SchBasePoint::getRegion_code, startRegionStr) + // 点位状态是空位 + .eq(SchBasePoint::getPoint_status, PointStatusEnum.EMPTY_VEHICLE.getCode()) + // 当前执行的任务为空或者NULL,有数据表示锁住 + .and(la -> la.isNull(SchBasePoint::getIng_task_code) + .or() + .eq(SchBasePoint::getIng_task_code, "")) + .eq(SchBasePoint::getIs_used, true); + List schBasePoints = pointService.list(lam); return ObjectUtil.isNotEmpty(schBasePoints) ? schBasePoints.get(0) : null; } @@ -175,8 +221,8 @@ public class ZPRKTask extends AbstractTask { pointService.updateById(endPointObj); LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); - lqw.eq(SchBaseVehiclematerialgroup::getVehicle_code,taskObj.getVehicle_code()) - .eq(SchBaseVehiclematerialgroup::getGroup_bind_material_status,GroupBindMaterialStatusEnum.BOUND.getValue()); + lqw.eq(SchBaseVehiclematerialgroup::getVehicle_code, taskObj.getVehicle_code()) + .eq(SchBaseVehiclematerialgroup::getGroup_bind_material_status, GroupBindMaterialStatusEnum.BOUND.getValue()); SchBaseVehiclematerialgroup vehiclematerialgroup = vehiclematerialgroupService.getOne(lqw); vehiclematerialgroup.setPoint_code(endPointObj.getPoint_code()); vehiclematerialgroup.setPoint_name(endPointObj.getPoint_name()); @@ -186,6 +232,29 @@ public class ZPRKTask extends AbstractTask { vehiclematerialgroup.setUpdate_time(DateUtil.now()); vehiclematerialgroupService.update(vehiclematerialgroup); } + + // 获取参数 + SchBasePoint startPointObj2 = pointService.getById(taskObj.getPoint_code3()); + String vehicle_code2 = startPointObj2.getVehicle_code(); + // 起点2清空 + if (ObjectUtil.isNotEmpty(startPointObj2)) { + startPointObj2.setIng_task_code(""); + PointUtils.setUpdateByType(startPointObj2, taskFinishedType); + PointUtils.clearPoint(startPointObj2); + pointService.updateById(startPointObj2); + } + + //更新终点的点位信息 + SchBasePoint endPointObj2 = pointService.getById(taskObj.getPoint_code4()); + if (ObjectUtil.isNotEmpty(endPointObj2)) { + endPointObj2.setPoint_status(PointStatusEnum.EMPTY_VEHICLE.getCode()); + endPointObj2.setVehicle_code(vehicle_code2); + endPointObj2.setVehicle_type(taskObj.getVehicle_type()); + endPointObj2.setVehicle_qty(taskObj.getVehicle_qty()); + endPointObj2.setUpdate_time(DateUtil.now()); + PointUtils.setUpdateByType(endPointObj2, taskFinishedType); + pointService.updateById(endPointObj2); + } // 任务完成 taskObj.setTask_status(TaskStatus.FINISHED.getCode()); taskObj.setRemark(GeneralDefinition.TASK_FINISH); @@ -204,6 +273,15 @@ public class ZPRKTask extends AbstractTask { PointUtils.setUpdateByType(endPointObj, taskFinishedType); pointService.updateById(endPointObj); } + + // 获取参数 + SchBasePoint startPointObj2 = pointService.getById(taskObj.getPoint_code3()); + // 解锁 + if (ObjectUtil.isNotEmpty(startPointObj2)) { + startPointObj2.setIng_task_code(""); + PointUtils.setUpdateByType(startPointObj2, taskFinishedType); + pointService.updateById(startPointObj2); + } taskObj.setTask_status(TaskStatus.CANCELED.getCode()); taskObj.setRemark(GeneralDefinition.TASK_CANCEL); taskObj.setFinished_type(taskFinishedType.getCode());