From 8eff20fa407af53b50ae3da0bc864a314a75a25b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E6=B1=9F=E7=8E=AE?= <zhangjiangwei2000@outlook.com> Date: Sat, 8 Oct 2022 09:41:17 +0800 Subject: [PATCH] =?UTF-8?q?=E8=87=AA=E5=8A=A8=E9=97=A8=E5=8F=8A=E6=B7=B7?= =?UTF-8?q?=E6=96=99=E9=97=B4=E8=AE=BE=E5=A4=87=E9=A9=B1=E5=8A=A8=E6=9B=B4?= =?UTF-8?q?=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../device/device_driver/DriverTypeEnum.java | 6 +- .../device_driver/driver/OpcDeviceDriver.java | 4 + .../standard_autodoor_smart/ItemProtocol.java | 72 ++ .../StandardAutodoorSmartDefination.java | 71 ++ .../StandardAutodoorSmartDeviceDriver.java | 163 ++++ .../ItemProtocol.java | 108 +++ .../StandardInspectSiteSmartDefination.java | 62 ++ .../StandardInspectSiteSmartDeviceDriver.java | 725 ++++++++++++++++++ acs/qd/src/views/acs/device/config.vue | 4 +- .../device/driver/standard_autodoor_smart.vue | 352 +++++++++ .../driver/standard_inspect_site_smart.vue | 489 ++++++++++++ .../service/impl/SendMaterialServiceImpl.java | 7 +- .../java/org/nl/wms/sch/service/wql/sch.xls | Bin 174592 -> 174592 bytes 13 files changed, 2058 insertions(+), 5 deletions(-) create mode 100644 acs/hd/nladmin-system/src/main/java/org/nl/acs/device_driver/standard_autodoor_smart/ItemProtocol.java create mode 100644 acs/hd/nladmin-system/src/main/java/org/nl/acs/device_driver/standard_autodoor_smart/StandardAutodoorSmartDefination.java create mode 100644 acs/hd/nladmin-system/src/main/java/org/nl/acs/device_driver/standard_autodoor_smart/StandardAutodoorSmartDeviceDriver.java create mode 100644 acs/hd/nladmin-system/src/main/java/org/nl/acs/device_driver/standard_inspect_site_smart200/ItemProtocol.java create mode 100644 acs/hd/nladmin-system/src/main/java/org/nl/acs/device_driver/standard_inspect_site_smart200/StandardInspectSiteSmartDefination.java create mode 100644 acs/hd/nladmin-system/src/main/java/org/nl/acs/device_driver/standard_inspect_site_smart200/StandardInspectSiteSmartDeviceDriver.java create mode 100644 acs/qd/src/views/acs/device/driver/standard_autodoor_smart.vue create mode 100644 acs/qd/src/views/acs/device/driver/standard_inspect_site_smart.vue diff --git a/acs/hd/nladmin-system/src/main/java/org/nl/acs/device/device_driver/DriverTypeEnum.java b/acs/hd/nladmin-system/src/main/java/org/nl/acs/device/device_driver/DriverTypeEnum.java index 2c10437..c3b3109 100644 --- a/acs/hd/nladmin-system/src/main/java/org/nl/acs/device/device_driver/DriverTypeEnum.java +++ b/acs/hd/nladmin-system/src/main/java/org/nl/acs/device/device_driver/DriverTypeEnum.java @@ -41,7 +41,11 @@ public enum DriverTypeEnum { TRAFFIC_LIGHT(34, "traffic_light", "标准版-交通灯-欧姆龙plc", "alarmLamp"), - STANDARD_RGV(35, "standard_rgv", "标准版-RGV", "rgv"); + STANDARD_RGV(35, "standard_rgv", "标准版-RGV", "rgv"), + + INSPECT_SITE_SMART(41, "standard_inspect_site_smart", "检测站点_smaet200", "station"), + + AUTODOOR_SMART(9, "standard_autodoor_smart", "标准版-自动门(Smart)", "autodoor"); //驱动索引 private int index; diff --git a/acs/hd/nladmin-system/src/main/java/org/nl/acs/device_driver/driver/OpcDeviceDriver.java b/acs/hd/nladmin-system/src/main/java/org/nl/acs/device_driver/driver/OpcDeviceDriver.java index bd62201..8954ce5 100644 --- a/acs/hd/nladmin-system/src/main/java/org/nl/acs/device_driver/driver/OpcDeviceDriver.java +++ b/acs/hd/nladmin-system/src/main/java/org/nl/acs/device_driver/driver/OpcDeviceDriver.java @@ -73,6 +73,10 @@ public interface OpcDeviceDriver extends DeviceDriver { return (String) this.getOpcValueAccessor().getValue(this.getItem(protocol)); } + default Integer getIntegerValue(String protocol) { + return (Integer) this.getValue(protocol); + } + default Object getValue(String protocol) { return this.getOpcValueAccessor().getValue(this.getItem(protocol)); } diff --git a/acs/hd/nladmin-system/src/main/java/org/nl/acs/device_driver/standard_autodoor_smart/ItemProtocol.java b/acs/hd/nladmin-system/src/main/java/org/nl/acs/device_driver/standard_autodoor_smart/ItemProtocol.java new file mode 100644 index 0000000..39a278f --- /dev/null +++ b/acs/hd/nladmin-system/src/main/java/org/nl/acs/device_driver/standard_autodoor_smart/ItemProtocol.java @@ -0,0 +1,72 @@ +package org.nl.acs.device_driver.standard_autodoor_smart; + +import lombok.extern.slf4j.Slf4j; +import org.nl.acs.device.device_driver.standard_inspect.ItemDto; + +import java.util.ArrayList; +import java.util.List; + +@Slf4j +public class ItemProtocol { + public static String item_heartbeat = "heartbeat"; + public static String item_mode = "mode"; + public static String item_action = "action"; + public static String item_error = "error"; + public static String item_to_command = "to_command"; + + + private StandardAutodoorSmartDeviceDriver driver; + + public ItemProtocol(StandardAutodoorSmartDeviceDriver driver) { + this.driver = driver; + } + + public int getHeartbeat() { + return this.getOpcIntegerValue(item_heartbeat); + } + + public int getMode() { + return this.getOpcIntegerValue(item_mode); + } + + public int getAction() { + return this.getOpcIntegerValue(item_action); + } + + public int getError() { + return this.getOpcIntegerValue(item_error); + } + + public int getToCommand() { + return this.getOpcIntegerValue(item_to_command); + } + + + public int getOpcIntegerValue(String protocol) { + Integer value = this.driver.getIntegeregerValue(protocol); + if (value == null) { + log.error("读取错误!"); + } else { + return value; + } + return 0; + + } + + public static List<ItemDto> getReadableItemDtos() { + ArrayList list = new ArrayList(); + list.add(new ItemDto(item_heartbeat, "心跳", "VW0")); + list.add(new ItemDto(item_mode, "工作状态", "VW2", Boolean.valueOf(true))); + list.add(new ItemDto(item_action, "动作信号", "VW4")); + list.add(new ItemDto(item_error, "报警信号", "VW6")); + return list; + } + + public static List<ItemDto> getWriteableItemDtos() { + ArrayList list = new ArrayList(); + list.add(new ItemDto(item_to_command, "作业命令", "VW52", Boolean.valueOf(true))); + return list; + } + +} + diff --git a/acs/hd/nladmin-system/src/main/java/org/nl/acs/device_driver/standard_autodoor_smart/StandardAutodoorSmartDefination.java b/acs/hd/nladmin-system/src/main/java/org/nl/acs/device_driver/standard_autodoor_smart/StandardAutodoorSmartDefination.java new file mode 100644 index 0000000..734e3bc --- /dev/null +++ b/acs/hd/nladmin-system/src/main/java/org/nl/acs/device_driver/standard_autodoor_smart/StandardAutodoorSmartDefination.java @@ -0,0 +1,71 @@ +package org.nl.acs.device_driver.standard_autodoor_smart; + +import org.nl.acs.device.device_driver.standard_inspect.ItemDto; +import org.nl.acs.device_driver.DeviceDriver; +import org.nl.acs.device_driver.defination.OpcDeviceDriverDefination; +import org.nl.acs.opc.Device; +import org.nl.acs.opc.DeviceType; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +/** + * 自动门驱动定义 + */ +@Service +public class StandardAutodoorSmartDefination implements OpcDeviceDriverDefination { + @Override + public String getDriverCode() { + return "standard_autodoor_smart"; + } + + @Override + public String getDriverName() { + return "标准版-自动门(Smart)"; + } + + @Override + public String getDriverDescription() { + return "标准版-自动门(Smart)"; + } + + @Override + public DeviceDriver getDriverInstance(Device device) { + return (new StandardAutodoorSmartDeviceDriver()).setDevice(device).setDriverDefination(this); + + } + + @Override + public Class<? extends DeviceDriver> getDeviceDriverType() { + return StandardAutodoorSmartDeviceDriver.class; + } + + @Override + public List<DeviceType> getFitDeviceTypes() { + List<DeviceType> types = new LinkedList(); + types.add(DeviceType.conveyor); + return types; + } + + @Override + public List<ItemDto> getReadableItemDtos() { + return getReadableItemDtos2(); + } + + public static List<ItemDto> getReadableItemDtos2() { + List<ItemDto> list = new ArrayList(); + list.add(new ItemDto(ItemProtocol.item_heartbeat, "心跳", "VW0")); + list.add(new ItemDto(ItemProtocol.item_mode, "工作状态", "VW2", true)); + list.add(new ItemDto(ItemProtocol.item_action, "动作信号", "VW4")); + list.add(new ItemDto(ItemProtocol.item_error, "报警信号", "VW6")); + return list; + } + + @Override + public List<ItemDto> getWriteableItemDtos() { + return ItemProtocol.getWriteableItemDtos(); + } + +} diff --git a/acs/hd/nladmin-system/src/main/java/org/nl/acs/device_driver/standard_autodoor_smart/StandardAutodoorSmartDeviceDriver.java b/acs/hd/nladmin-system/src/main/java/org/nl/acs/device_driver/standard_autodoor_smart/StandardAutodoorSmartDeviceDriver.java new file mode 100644 index 0000000..34c4cc5 --- /dev/null +++ b/acs/hd/nladmin-system/src/main/java/org/nl/acs/device_driver/standard_autodoor_smart/StandardAutodoorSmartDeviceDriver.java @@ -0,0 +1,163 @@ +package org.nl.acs.device_driver.standard_autodoor_smart; + +import com.alibaba.fastjson.JSONObject; +import lombok.Data; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.nl.acs.device.device_driver.standard_inspect.ReadUtil; +import org.nl.acs.device.service.DeviceService; +import org.nl.acs.device_driver.DeviceDriver; +import org.nl.acs.device_driver.driver.AbstractOpcDeviceDriver; +import org.nl.acs.device_driver.driver.ExecutableDeviceDriver; +import org.nl.acs.instruction.service.InstructionService; +import org.nl.acs.opc.Device; +import org.nl.acs.route.service.RouteLineService; +import org.nl.acs.task.service.TaskService; +import org.nl.utils.SpringContextHolder; +import org.openscada.opc.lib.da.Server; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +/** + * 自动门驱动 + */ +@Slf4j +@Data +@RequiredArgsConstructor +public class StandardAutodoorSmartDeviceDriver extends AbstractOpcDeviceDriver implements DeviceDriver, ExecutableDeviceDriver { + protected ItemProtocol itemProtocol = new ItemProtocol(this); + @Autowired + InstructionService instructionService = SpringContextHolder.getBean("instructionServiceImpl"); + @Autowired + DeviceService deviceservice = SpringContextHolder.getBean("deviceServiceImpl"); + @Autowired + RouteLineService routelineserver = SpringContextHolder.getBean("routeLineServiceImpl"); + @Autowired + TaskService taskserver = SpringContextHolder.getBean("taskServiceImpl"); + String container; + String container_type_desc; + String last_container_type_desc; + String last_container; + //放货准备锁 + String putReadyLock = null; + //有货标记 + protected boolean has_goods_tag = false; + String devicecode; + int mode = 0; + int action = 0; + int error = 0; + Boolean iserror = false; + + int move = 0; + int task = 0; + int last_action = 0; + int last_mode = 0; + int last_error = 0; + int last_move = 0; + int last_task = 0; + + boolean hasVehicle = false; + boolean isReady = false; + protected int instruction_num = 0; + protected int instruction_num_truth = 0; + protected boolean hasGoods = false; + boolean isFold = false; + private String assemble_check_tag; + private Boolean sampleMode0; + private Boolean sampleMode3; + private Integer sampleError; + private Boolean sampleOnline; + protected String displayMessage = null; + public int display_message_time_out = 30000; + public Date display_message_time; + protected String current_stage_instruction_message; + protected String last_stage_instruction_message; + Integer heartbeat_tag; + private Date instruction_require_time = new Date(); + private Date instruction_finished_time = new Date(); + + private int instruction_require_time_out; + boolean requireSucess = false; + + private int instruction_finished_time_out; + + int branchProtocol = 0; + + @Override + public Device getDevice() { + return this.device; + } + + + @Override + public void execute() { + String message = null; + + String device_code = this.getDevice().getDevice_code(); + mode = this.itemProtocol.getMode(); + action = this.itemProtocol.getAction(); + error = this.itemProtocol.getError(); + if (mode != last_mode) { + } + if (action != last_action) { + } + if (error != last_error) { + //this.execute_log.setContainer(""); + } + last_action = action; + last_mode = mode; + last_error = error; + //message = StringFormatUtl.format("设备报警:{}", new Object[]{}); + +// String manual_create_task = this.getDevice().getExtraValue().get("manual_create_task").toString(); + + } + + public synchronized String getStatus() { + JSONObject jo = new JSONObject(); + + if (action == 1) { + jo.put("name", this.getDevice().getDevice_code()); + jo.put("status", "OPEN"); + + } else if (action == 2) { + jo.put("name", this.getDevice().getDevice_code()); + jo.put("status", "CLOSE"); + + } else { + jo.put("name", this.getDevice().getDevice_code()); + jo.put("status", "ERROR"); + } + return jo.toString(); + } + + + public void writeing(int command) { + String to_command = this.getDevice().getOpc_server_code() + "." + this.getDevice().getOpc_plc_code() + "." + this.getDevice().getDevice_code() + + "." + ItemProtocol.item_to_command; + + String opcservcerid = this.getDevice().getOpc_server_id(); + Server server = ReadUtil.getServer(opcservcerid); + Map<String, Object> itemMap = new HashMap<String, Object>(); + itemMap.put(to_command, command); + ReadUtil.write(itemMap, server); + log.info("下发PLC信号:{},{}", to_command, command); + System.out.println("设备:" + devicecode + ",下发PLC信号:" + to_command + ",value:" + command); + + } + + public synchronized void OpenOrClose(String type) { + + //开门 + if ("1".equals(type)) { + writeing(1); + } else { + writeing(2); + } + + } + +} diff --git a/acs/hd/nladmin-system/src/main/java/org/nl/acs/device_driver/standard_inspect_site_smart200/ItemProtocol.java b/acs/hd/nladmin-system/src/main/java/org/nl/acs/device_driver/standard_inspect_site_smart200/ItemProtocol.java new file mode 100644 index 0000000..782bb3c --- /dev/null +++ b/acs/hd/nladmin-system/src/main/java/org/nl/acs/device_driver/standard_inspect_site_smart200/ItemProtocol.java @@ -0,0 +1,108 @@ +package org.nl.acs.device_driver.standard_inspect_site_smart200; + +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.nl.acs.device.device_driver.standard_inspect.ItemDto; + +import java.util.ArrayList; +import java.util.List; + +@Slf4j +@Data +public class ItemProtocol { + + public static String item_heartbeat = "heartbeat"; + public static String item_mode = "mode"; + public static String item_move = "move"; + public static String item_action = "action"; + public static String item_ioaction = "ioaction"; + public static String item_error = "error"; + public static String item_task = "task"; + public static String item_to_command = "to_command"; + public static String item_to_target = "to_target"; + public static String item_to_task = "to_task"; + public static String item_weight = "weight"; + + private StandardInspectSiteSmartDeviceDriver driver; + + public ItemProtocol(StandardInspectSiteSmartDeviceDriver driver) { + this.driver = driver; + } + + public int getHeartbeat() { + return this.getOpcIntegerValue(item_heartbeat); + } + + public int getMode() { + return this.getOpcIntegerValue(item_mode); + } + + public int getMove() { + return this.getOpcIntegerValue(item_move); + } + + public int getIoaction() { + return this.getOpcIntegerValue(item_ioaction); + } + + public int getError() { + return this.getOpcIntegerValue(item_error); + } + + public int getTask() { + return this.getOpcIntegerValue(item_task); + } + + public int getToCommand() { + return this.getOpcIntegerValue(item_to_command); + } + + public int getToTarget() { + return this.getOpcIntegerValue(item_to_target); + } + + public int getToTask() { + return this.getOpcIntegerValue(item_to_task); + } + + //是否有货 + public int hasGoods(int move) { + return move; + } + + Boolean isonline; + + public int getOpcIntegerValue(String protocol) { + Integer value = this.driver.getIntegerValue(protocol); + if (value == null) { + log.error(this.getDriver().getDeviceCode() + ":protocol " + protocol + " 信号同步异常!"); + setIsonline(false); + } else { + setIsonline(true); + return value; + } + return 0; + + } + + public static List<ItemDto> getReadableItemDtos() { + ArrayList list = new ArrayList(); + list.add(new ItemDto(item_heartbeat, "心跳", "VW0")); + list.add(new ItemDto(item_mode, "工作状态", "VW2", Boolean.valueOf(true))); + list.add(new ItemDto(item_move, "光电开关信号", "VW4")); + list.add(new ItemDto(item_action, "动作信号", "VW8")); + list.add(new ItemDto(item_error, "报警信号", "VW12")); + list.add(new ItemDto(item_task, "任务号", "VD14")); + return list; + } + + public static List<ItemDto> getWriteableItemDtos() { + ArrayList list = new ArrayList(); + list.add(new ItemDto(item_to_command, "作业命令", "VW52", Boolean.valueOf(true))); + list.add(new ItemDto(item_to_target, "目标站", "VW54")); + list.add(new ItemDto(item_to_task, "任务号", "VD58")); + return list; + } + +} + diff --git a/acs/hd/nladmin-system/src/main/java/org/nl/acs/device_driver/standard_inspect_site_smart200/StandardInspectSiteSmartDefination.java b/acs/hd/nladmin-system/src/main/java/org/nl/acs/device_driver/standard_inspect_site_smart200/StandardInspectSiteSmartDefination.java new file mode 100644 index 0000000..e5b2db4 --- /dev/null +++ b/acs/hd/nladmin-system/src/main/java/org/nl/acs/device_driver/standard_inspect_site_smart200/StandardInspectSiteSmartDefination.java @@ -0,0 +1,62 @@ +package org.nl.acs.device_driver.standard_inspect_site_smart200; + +import org.nl.acs.device.device_driver.standard_inspect.ItemDto; +import org.nl.acs.device_driver.DeviceDriver; +import org.nl.acs.device_driver.defination.OpcDeviceDriverDefination; +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 StandardInspectSiteSmartDefination implements OpcDeviceDriverDefination { + @Override + public String getDriverCode() { + return "standard_inspect_site_smart"; + } + + @Override + public String getDriverName() { + return "标准版-检测站点_smart"; + } + + @Override + public String getDriverDescription() { + return "标准版-检测站点_smart"; + } + + @Override + public DeviceDriver getDriverInstance(Device device) { + return (new StandardInspectSiteSmartDeviceDriver()).setDevice(device).setDriverDefination(this); + + } + + @Override + public Class<? extends DeviceDriver> getDeviceDriverType() { + return StandardInspectSiteSmartDeviceDriver.class; + } + + @Override + public List<DeviceType> getFitDeviceTypes() { + List<DeviceType> types = new LinkedList(); + types.add(DeviceType.conveyor); + return types; + } + + @Override + public List<ItemDto> getReadableItemDtos() { + return ItemProtocol.getReadableItemDtos(); + } + + @Override + public List<ItemDto> getWriteableItemDtos() { + return ItemProtocol.getWriteableItemDtos(); + } + +} diff --git a/acs/hd/nladmin-system/src/main/java/org/nl/acs/device_driver/standard_inspect_site_smart200/StandardInspectSiteSmartDeviceDriver.java b/acs/hd/nladmin-system/src/main/java/org/nl/acs/device_driver/standard_inspect_site_smart200/StandardInspectSiteSmartDeviceDriver.java new file mode 100644 index 0000000..f659d2e --- /dev/null +++ b/acs/hd/nladmin-system/src/main/java/org/nl/acs/device_driver/standard_inspect_site_smart200/StandardInspectSiteSmartDeviceDriver.java @@ -0,0 +1,725 @@ +package org.nl.acs.device_driver.standard_inspect_site_smart200; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.StrUtil; +import lombok.Data; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import net.sf.json.JSONObject; +import org.nl.acs.device.device_driver.standard_inspect.ReadUtil; +import org.nl.acs.device.service.DeviceService; +import org.nl.acs.device_driver.DeviceDriver; +import org.nl.acs.device_driver.RouteableDeviceDriver; +import org.nl.acs.device_driver.driver.AbstractOpcDeviceDriver; +import org.nl.acs.device_driver.driver.ExecutableDeviceDriver; +import org.nl.acs.device_driver.standard_emptypallet_site.StandardEmptyPalletSiteDeviceDriver; +import org.nl.acs.instruction.service.InstructionService; +import org.nl.acs.instruction.service.dto.Instruction; +import org.nl.acs.opc.Device; +import org.nl.acs.opc.DeviceAppService; +import org.nl.acs.opc.DeviceAppServiceImpl; +import org.nl.acs.opc.WcsConfig; +import org.nl.acs.route.service.RouteLineService; +import org.nl.acs.route.service.dto.RouteLineDto; +import org.nl.acs.task.service.TaskService; +import org.nl.acs.task.service.dto.TaskDto; +import org.nl.modules.system.util.CodeUtil; +import org.nl.utils.SpringContextHolder; +import org.nl.wql.core.bean.WQLObject; +import org.openscada.opc.lib.da.Server; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 检测站点驱动 + */ +@Slf4j +@Data +@RequiredArgsConstructor +public class StandardInspectSiteSmartDeviceDriver extends AbstractOpcDeviceDriver implements DeviceDriver, ExecutableDeviceDriver, RouteableDeviceDriver { + protected ItemProtocol itemProtocol = new ItemProtocol(this); + @Autowired + InstructionService instructionService = SpringContextHolder.getBean("instructionServiceImpl"); + @Autowired + DeviceService deviceservice = SpringContextHolder.getBean("deviceServiceImpl"); + @Autowired + RouteLineService routelineserver = SpringContextHolder.getBean("routeLineServiceImpl"); + @Autowired + TaskService taskserver = SpringContextHolder.getBean("taskServiceImpl"); + @Autowired + DeviceAppService deviceAppservice = SpringContextHolder.getBean(DeviceAppService.class); + String container; + String container_type_desc; + String last_container_type_desc; + String last_container; + //放货准备锁 + String putReadyLock = null; + //有货标记 + protected boolean has_goods_tag = false; + + int mode = 0; + int error = 0; + int move = 0; + int task = 0; + int last_mode = 0; + int last_error = 0; + int last_move = 0; + int last_task = 0; + Boolean isonline = true; + int hasGoods = 0; + String message = null; + Boolean iserror = false; + + + boolean hasVehicle = false; + boolean isReady = false; + protected int instruction_num = 0; + protected int instruction_num_truth = 0; + boolean isFold = false; + private String assemble_check_tag; + + protected String current_stage_instruction_message; + protected String last_stage_instruction_message; + Integer heartbeat_tag; + private Date instruction_require_time = new Date(); + private Date instruction_finished_time = new Date(); + + private int instruction_require_time_out; + boolean requireSucess = false; + boolean inrequireSucess = false; + boolean emptyrequireSucess = false; + + private int instruction_finished_time_out; + + int branchProtocol = 0; + //备注 + String remark; + //数量 + String qty; + //物料 + String material; + //批次 + String batch; + //当前指令 + Instruction inst = null; + //上次指令 + Instruction last_inst = null; + + Object object = new Object(); + //触摸屏手动触发任务 + private Boolean is_has_task = false; + + //申请搬运任务 + private Boolean apply_handling = false; + //申请物料 + private Boolean apply_material = false; + + //暂定 0就绪 1请求取货 2取货完成 3请求放货 4放货完成 5取货完成离开 6放货完成离开 7请求进入区域 8请求离开区域 + int flag; + + String devicecode; + + // 手持设备信息 + private String model; + + // 工序 + private String process; + + // 重量 + private String weight; + + // 质量状态 + private String qc_status; + + // 日期 + private String date; + + // 操作员 + private String operation_by; + + String put_goods_time = ""; + + Boolean islock = false; + + @Override + public Device getDevice() { + return this.device; + } + + + @Override + public void execute() { + String message = null; + try { + String device_code = this.getDeviceCode(); + mode = this.itemProtocol.getMode(); + error = this.itemProtocol.getError(); + move = this.itemProtocol.getMove(); + task = this.itemProtocol.getTask(); + hasGoods = this.itemProtocol.getMove(); + + if (mode != last_mode) { + if (mode == 5) { + this.setEmptyrequireSucess(false); + } + if (mode == 6) { + this.setInrequireSucess(false); + } + } + + if (this.getApply_handling()) { + String link_device_code = this.getDevice().getExtraValue().get("link_device_code").toString(); + DeviceAppService appService = SpringContextHolder.getBean(DeviceAppServiceImpl.class); + Device link_device = appService.findDeviceByCode(link_device_code); + StandardInspectSiteSmartDeviceDriver standardInspectSiteDevicedriver; + if (link_device.getDeviceDriver() instanceof StandardInspectSiteSmartDeviceDriver) { + standardInspectSiteDevicedriver = (StandardInspectSiteSmartDeviceDriver) link_device.getDeviceDriver(); +// if(standardInspectSiteDevicedriver.getMode() != 2){ +// log.debug("设备未待机"); +// return; +// } +// if(standardInspectSiteDevicedriver.getMove() != 0){ +// log.debug("设备不满足放货条件"); +// return; +// } + + //如果目标设备申请叫料 则允许生成任务 + if (standardInspectSiteDevicedriver.getApply_material()) { + TaskDto dto = new TaskDto(); + String now = DateUtil.now(); + dto.setTask_id(IdUtil.simpleUUID()); + dto.setCreate_by(this.getDevice().getDevice_code()); + dto.setUpdate_by(this.getDevice().getDevice_code()); + dto.setStart_point_code(this.getDevice().getDevice_code()); + + String taskcode = CodeUtil.getNewCode("TASK_NO"); + dto.setTask_code("-" + taskcode); + dto.setTask_status("0"); + dto.setPriority("101"); +// RouteLineDto jo = routelineserver.findByCode(this.getDevice().getDevice_code()); +// String next_device_codecode = jo.getNext_device_code(); +// if(StrUtil.isEmpty(next_device_codecode)){ +// throw new RuntimeException("该设备未找到对应路由"); +// } + dto.setNext_point_code(standardInspectSiteDevicedriver.getDevicecode()); + dto.setUpdate_time(now); + dto.setCreate_time(now); + + WQLObject wo = WQLObject.getWQLObject("acs_task"); + JSONObject json = JSONObject.fromObject(dto); + wo.insert(json); + standardInspectSiteDevicedriver.setApply_material(false); + } + } + this.setApply_handling(false); + } + + } catch (Exception var17) { + return; + } + + if (!this.itemProtocol.getIsonline()) { + this.setIsonline(false); + this.setIserror(true); + message = "信号量同步异常"; + //未联机 + } else if (mode == 0) { + this.setIsonline(false); + this.setIserror(true); + message = "未联机"; + //有报警 + } else if (error != 0) { + this.setIsonline(false); + this.setIserror(true); + message = "有报警"; + //无报警 + } else { + this.setIsonline(true); + this.setIserror(false); + message = ""; + Instruction instruction = null; + List toInstructions; + + switch (mode) { + case 1: + log.debug("设备运转模式:等待工作"); + return; + case 2: + //申请任务 +// if (this.getApply_handling()) { +// String link_device_code = this.getDevice().getExtraValue().get("link_device_code").toString(); +// DeviceAppService appService = SpringContextHolder.getBean(DeviceAppServiceImpl.class); +// Device link_device = appService.findDeviceByCode(link_device_code); +// StandardInspectSiteDeviceDriver standardInspectSiteDevicedriver; +// if(link_device.getDeviceDriver() instanceof StandardInspectSiteDeviceDriver) { +// standardInspectSiteDevicedriver = (StandardInspectSiteDeviceDriver) link_device.getDeviceDriver(); +// if(standardInspectSiteDevicedriver.getMode() != 2){ +// log.debug("设备未待机"); +// return; +// } +// if(standardInspectSiteDevicedriver.getMove() != 0){ +// log.debug("设备不满足放货条件"); +// return; +// } +// +// //如果目标设备申请叫料 则允许生成任务 +// if(standardInspectSiteDevicedriver.getApply_material()){ +// TaskDto dto = new TaskDto(); +// String now = DateUtil.now(); +// dto.setTask_id(IdUtil.simpleUUID()); +// dto.setCreate_by(this.getDevice().getDevice_code()); +// dto.setUpdate_by(this.getDevice().getDevice_code()); +// dto.setStart_point_code(this.getDevice().getDevice_code()); +// +// String taskcode = CodeGenerateUtil.getNewCode("TASK_NO"); +// dto.setTask_code("-"+taskcode); +// dto.setTask_status("0"); +// dto.setPriority("101"); +// RouteLineDto jo = routelineserver.findByCode(this.getDevice().getDevice_code()); +// String next_device_codecode = jo.getNext_device_code(); +// if(StrUtil.isEmpty(next_device_codecode)){ +// throw new RuntimeException("该设备未找到对应路由"); +// } +// dto.setNext_point_code(next_device_codecode); +// dto.setUpdate_time(now); +// dto.setCreate_time(now); +// +// WQLObject wo = WQLObject.getWQLObject("acs_task"); +// JSONObject json = JSONObject.fromObject(dto); +// wo.insert(json); +// standardInspectSiteDevicedriver.setApply_material(false); +// } +// } +// this.setApply_handling(false); +// } + + if (material.length() > 0 && qty.length() > 0 && !requireSucess) { + + this.instruction_require(container); + + } + case 5: + if (!emptyrequireSucess) { + //mode = 5 并且工位上无货时申请空托盘 + if (move == 0) { + this.apply_empty_require(container); + } + } + break; + case 6: + if (!inrequireSucess) { + if (move == 1) { + this.apply_in_require(container); + } + } + break; + } + + switch (flag) { + //取货完成 + case 1: + writing(2); + return; + //放货完成 + case 2: + writing(3); + return; + + } + + } + last_mode = mode; + last_error = error; + last_move = move; + last_task = task; + + } + + + public boolean exe_error() { + if (this.error == 0) { + return true; + } else { + log.debug("设备报警"); + return false; + } + } + + protected void thingToNothing() { + log.debug("从有货到无货 清理数据"); + this.set_last_container(container, container_type_desc); + } + + public void set_last_container(String barcode, String type_desc) { + this.set_last_container(barcode); + this.set_last_container_type_desc(type_desc); + } + + public void set_last_container(String barcode) { + } + + public void set_last_container_type_desc(String type) { + } + + public boolean exe_business() { + return true; + } + + protected void executing(Instruction instruction) { + this.executing(1, instruction, ""); + } + + public void executing(int command, Instruction instruction, String appendMessage) { + String to_command = this.getDevice().getOpc_server_code() + "." + this.getDevice().getOpc_plc_code() + "." + this.getDevice().getDevice_code() + + "." + ItemProtocol.item_to_command; + String to_target = this.getDevice().getOpc_server_code() + "." + this.getDevice().getOpc_plc_code() + "." + this.getDevice().getDevice_code() + + "." + ItemProtocol.item_to_target; + String to_task = this.getDevice().getOpc_server_code() + "." + this.getDevice().getOpc_plc_code() + "." + this.getDevice().getDevice_code() + + "." + ItemProtocol.item_to_task; + if (appendMessage == null) { + appendMessage = ""; + } + if (instruction != null) { + instruction_num = Integer.parseInt(instruction.getInstruction_code()); + } + String opcservcerid = this.getDevice().getOpc_server_id(); + Server server = ReadUtil.getServer(opcservcerid); + Map<String, Object> itemMap = new HashMap<String, Object>(); + itemMap.put(to_command, 1); + itemMap.put(to_task, instruction_num); + ReadUtil.write(itemMap, server); + + } + + public void executing(Server server, Map<String, Object> itemMap) { + ReadUtil.write(itemMap, server); + } + + public void writing(int command) { + String to_command = this.getDevice().getOpc_server_code() + "." + this.getDevice().getOpc_plc_code() + "." + this.getDevice().getDevice_code() + + "." + ItemProtocol.item_to_command; + + String opcservcerid = this.getDevice().getOpc_server_id(); + Server server = ReadUtil.getServer(opcservcerid); + Map<String, Object> itemMap = new HashMap<String, Object>(); + itemMap.put(to_command, command); + ReadUtil.write(itemMap, server); + + } + + public void writing(int type, int command) { + String to_command = this.getDevice().getOpc_server_code() + "." + this.getDevice().getOpc_plc_code() + "." + this.getDevice().getDevice_code() + + "." + ItemProtocol.item_to_command; + String to_target = this.getDevice().getOpc_server_code() + "." + this.getDevice().getOpc_plc_code() + "." + this.getDevice().getDevice_code() + + "." + ItemProtocol.item_to_target; + String to_task = this.getDevice().getOpc_server_code() + "." + this.getDevice().getOpc_plc_code() + "." + this.getDevice().getDevice_code() + + "." + ItemProtocol.item_to_task; + String opcservcerid = this.getDevice().getOpc_server_id(); + Server server = ReadUtil.getServer(opcservcerid); + Map<String, Object> itemMap = new HashMap<String, Object>(); + if (type == 1) { + itemMap.put(to_command, command); + } else if (type == 2) { + itemMap.put(to_target, command); + + } else if (type == 3) { + itemMap.put(to_task, command); + } + ReadUtil.write(itemMap, server); + + } + + public boolean instruction_require(String container_code) { + return instruction_require(container_code, WcsConfig.task_container_type_default_desc); + } + + public synchronized boolean apply_empty_require(String container_code) { + return apply_empty_require(container_code, WcsConfig.task_container_type_default_desc); + } + + public synchronized boolean apply_in_require(String container_code) { + return apply_in_require(container_code, WcsConfig.task_container_type_default_desc); + } + + + /** + * 请求指令 + * + * @param container_code + * @param container_type + */ + public synchronized boolean apply_in_require(String container_code, String container_type) { + WQLObject runpointwo = WQLObject.getWQLObject("acs_device_runpoint"); + Date date = new Date(); + Boolean flag = false; + if (date.getTime() - this.instruction_require_time.getTime() < (long) this.instruction_require_time_out) { + log.trace("触发时间因为小于{}毫秒,而被无视", this.instruction_require_time_out); + return false; + } else { + this.instruction_require_time = date; + //查询该设备所有路由 + List<RouteLineDto> pathLinesByCode = routelineserver.getSuperiorShortPathLinesByCode(this.getDevice().getDevice_code(), "normal"); + StandardInspectSiteSmartDeviceDriver standardInspectSiteDeviceDriver; + for (int i = 0; i < pathLinesByCode.size(); i++) { + RouteLineDto routeLineDto = pathLinesByCode.get(i); + //获取该路由的起点设备编码 + String start_device_code = routeLineDto.getDevice_code(); + //获取该路由的终点设备编码 + String next_device_code = routeLineDto.getNext_device_code(); + //获取该路由终点设备信息 + Device route_link_device = deviceAppservice.findDeviceByCode(next_device_code); + //判断终点设备驱动是否为检测站点驱动 + if (route_link_device.getDeviceDriver() instanceof StandardInspectSiteSmartDeviceDriver) { + standardInspectSiteDeviceDriver = (StandardInspectSiteSmartDeviceDriver) route_link_device.getDeviceDriver(); + //判断该终点设备是否有货,有货就结束循环 + if (standardInspectSiteDeviceDriver.getMove() != 0 || standardInspectSiteDeviceDriver.getMode() != 2) { + continue; + } + + //判断是否已经有该起点设备的任务,如果有就结束循环 + int num1 = WQLObject + .getWQLObject("acs_task") + .query("start_device_code = '" + start_device_code + "'") + .getResultCount(); + if (num1 != 0) { + continue; + } + //判断是否有相同终点的任务,有就结束本次循环 + int num = WQLObject + .getWQLObject("acs_task") + .query("next_device_code = '" + next_device_code + "'") + .getResultCount(); + if (num != 0) { + continue; + } + /* //判断检测站点是否锁定,如果锁定就结束本次循环 + JSONObject jsonObject = runpointwo.query("device_code = '" + next_device_code + "' and islock = '1'").uniqueResult(0); + if (ObjectUtil.isNotEmpty(jsonObject)) { + this.execute_log.log("设备:" + devicecode+ "", "", "对应路由设备," + next_device_code + "已锁定"); + continue; + }*/ + //创建任务 + TaskDto dto = new TaskDto(); + String now = DateUtil.now(); + dto.setTask_id(IdUtil.simpleUUID()); + dto.setCreate_by(this.getDevice().getDevice_code()); + dto.setUpdate_by(this.getDevice().getDevice_code()); + dto.setVehicle_code(container_code); + dto.setVehicle_type(container_type); + String taskcode = CodeUtil.getNewCode("TASK_NO"); + dto.setTask_code("-" + taskcode); + dto.setTask_status("0"); + dto.setPriority("101"); + dto.setMaterial(this.getDevice().getMaterial_type()); + dto.setUpdate_time(now); + dto.setCreate_time(now); + dto.setStart_device_code(start_device_code); + dto.setStart_point_code(start_device_code); + dto.setNext_device_code(next_device_code); + dto.setNext_point_code(next_device_code); + try { + //判断是否已经有该起点设备的任务,如果有就结束循环 + int num2 = WQLObject + .getWQLObject("acs_task") + .query("start_device_code = '" + start_device_code + "'") + .getResultCount(); + if (num2 != 0) { + continue; + } + //判断是否有相同终点的任务,有就结束本次循环 + int num3 = WQLObject + .getWQLObject("acs_task") + .query("next_device_code = '" + next_device_code + "'") + .getResultCount(); + if (num3 != 0) { + continue; + } + taskserver.create(dto); +/* //任务创建成功 锁定终点设备 + JSONObject map = new JSONObject(); + map.put("islock", "true"); + map.put("update_by", "auto"); + map.put("update_time", DateUtil.now()); + runpointwo.update(map, "device_code = '" + next_device_code + "'");*/ + flag = true; + break; + } catch (Exception e) { + } + } + } + + //生成任务成功 + if (flag) { + + inrequireSucess = true; + } + return true; + } + } + + /** + * 请求指令 + * + * @param container_code + * @param container_type + */ + public synchronized boolean apply_empty_require(String container_code, String container_type) { + WQLObject runpointwo = WQLObject.getWQLObject("acs_device_runpoint"); + Date date = new Date(); + Boolean flag = false; + if (date.getTime() - this.instruction_require_time.getTime() < (long) this.instruction_require_time_out) { + log.trace("触发时间因为小于{}毫秒,而被无视", this.instruction_require_time_out); + return false; + } else { + this.instruction_require_time = date; + //查询所有到这台设备的路由,这台设备为路由的终点 + List<RouteLineDto> pathLinesByCode = routelineserver.getPathLinesByCode(this.getDevice().getDevice_code(), "normal"); + StandardEmptyPalletSiteDeviceDriver standardEmptyPalletSiteDeviceDriver; + for (int i = 0; i < pathLinesByCode.size(); i++) { + //获取每个路由 + RouteLineDto routeLineDto = pathLinesByCode.get(i); + //获取路由的起点 + String start_device_code = routeLineDto.getDevice_code(); + //获取路由的终点 + String next_device_code = routeLineDto.getNext_device_code(); + //获取起点设备的信息 + Device route_link_device = deviceAppservice.findDeviceByCode(start_device_code); + //判断起点设备驱动是否为堆叠位驱动 + if (route_link_device.getDeviceDriver() instanceof StandardEmptyPalletSiteDeviceDriver) { + standardEmptyPalletSiteDeviceDriver = (StandardEmptyPalletSiteDeviceDriver) route_link_device.getDeviceDriver(); + // TODO 判断堆叠位是否有货,没货就结束本次循环 + //判断堆叠位的数量是否大于0,如果=0就结束本次循环 + if (standardEmptyPalletSiteDeviceDriver.getMove() != 1 || standardEmptyPalletSiteDeviceDriver.getNumber() == 0) { + continue; + } + //判断是否已经有该起点设备的任务,如果有就结束循环 + int num = WQLObject + .getWQLObject("acs_task") + .query("start_device_code = '" + start_device_code + "'") + .getResultCount(); + if (num != 0) { + continue; + } + //判断是否已经有到该起点设备的任务,如果有就结束循环 + int num1 = WQLObject + .getWQLObject("acs_task") + .query("next_device_code = '" + next_device_code + "'") + .getResultCount(); + if (num1 != 0) { + continue; + } +/* //判断起点是否锁定,如果被锁定就结束循环 + JSONObject jsonObject = runpointwo.query("device_code = '" + next_device_code + "' and islock = 'true'").uniqueResult(0); + if (ObjectUtil.isNotEmpty(jsonObject)) { + this.execute_log.log("设备:" + devicecode+ "", "", "对应路由设备," + next_device_code + "已锁定"); + continue; + }*/ + //创建任务 + TaskDto dto = new TaskDto(); + String now = DateUtil.now(); + dto.setTask_id(IdUtil.simpleUUID()); + dto.setCreate_by(this.getDevice().getDevice_code()); + dto.setUpdate_by(this.getDevice().getDevice_code()); + dto.setVehicle_code(container_code); + dto.setVehicle_type(container_type); + String taskcode = CodeUtil.getNewCode("TASK_NO"); + dto.setTask_code("-" + taskcode); + dto.setTask_status("0"); + dto.setPriority("101"); + dto.setUpdate_time(now); + dto.setCreate_time(now); + dto.setStart_device_code(start_device_code); + dto.setStart_point_code(start_device_code); + dto.setNext_device_code(next_device_code); + dto.setNext_point_code(next_device_code); + dto.setMaterial(route_link_device.getMaterial_type()); + try { + //判断是否已经有该起点设备的任务,如果有就结束循环 + int num2 = WQLObject + .getWQLObject("acs_task") + .query("start_device_code = '" + start_device_code + "'") + .getResultCount(); + if (num2 != 0) { + continue; + } + //判断是否有相同终点的任务,有就结束本次循环 + int num3 = WQLObject + .getWQLObject("acs_task") + .query("next_device_code = '" + next_device_code + "'") + .getResultCount(); + if (num3 != 0) { + continue; + } + taskserver.create(dto); + //任务创建成功 锁定该终点设备 + JSONObject map = new JSONObject(); + map.put("islock", "true"); + map.put("update_by", "auto"); + map.put("update_time", DateUtil.now()); + runpointwo.update(map, "device_code = '" + start_device_code + "'"); + flag = true; + break; + } catch (Exception e) { + } + } + } + + //生成任务成功 + if (flag) { + emptyrequireSucess = true; + } + return true; + } + } + + + /** + * 请求指令 + * + * @param container_code + * @param container_type + */ + public synchronized boolean instruction_require(String container_code, String container_type) { + Date date = new Date(); + if (date.getTime() - this.instruction_require_time.getTime() < (long) this.instruction_require_time_out) { + log.trace("触发时间因为小于{}毫秒,而被无视", this.instruction_require_time_out); + return false; + } else { + this.instruction_require_time = date; + TaskDto dto = new TaskDto(); + String now = DateUtil.now(); + dto.setTask_id(IdUtil.simpleUUID()); + dto.setCreate_by(this.getDevice().getDevice_code()); + dto.setUpdate_by(this.getDevice().getDevice_code()); + dto.setStart_point_code(this.getDevice().getDevice_code()); + dto.setVehicle_code(container_code); + dto.setVehicle_type(container_type); + + String taskcode = CodeUtil.getNewCode("TASK_NO"); + dto.setTask_code("-" + taskcode); + dto.setTask_status("0"); + dto.setPriority("101"); + RouteLineDto jo = routelineserver.findByCode(this.getDevice().getDevice_code()); + String next_device_codecode = jo.getNext_device_code(); + if (StrUtil.isEmpty(next_device_codecode)) { + throw new RuntimeException("该设备未找到对应路由"); + } + dto.setNext_point_code(next_device_codecode); + dto.setUpdate_time(now); + dto.setCreate_time(now); + + WQLObject wo = WQLObject.getWQLObject("acs_task"); + JSONObject json = JSONObject.fromObject(dto); + wo.insert(json); + requireSucess = false; + return true; + } + } + + +} diff --git a/acs/qd/src/views/acs/device/config.vue b/acs/qd/src/views/acs/device/config.vue index 22358a9..c014df5 100644 --- a/acs/qd/src/views/acs/device/config.vue +++ b/acs/qd/src/views/acs/device/config.vue @@ -95,6 +95,8 @@ import manipulator_inspect_site_NDC from '@/views/acs/device/driver/manipulator_ import standard_manipulator_stacking_site from '@/views/acs/device/driver/standard_manipulator_stacking_site' import standard_photoelectric_inspect_site from '@/views/acs/device/driver/standard_photoelectric_inspect_site' import electric_fence from '@/views/acs/device/driver/electric_fence' +import standard_inspect_site_smart from '@/views/acs/device/driver/standard_inspect_site_smart' +import standard_autodoor_smart from '@/views/acs/device/driver/standard_autodoor_smart' export default { name: 'DeviceConfig', @@ -103,7 +105,7 @@ export default { lamp_three_color, standard_storage, special_ordinary_site, standard_scanner, standard_conveyor_control_with_scanner, standard_conveyor_control_with_plcscanner, standard_conveyor_control, standard_conveyor_monitor, weighing_site, machines_site, non_line_manipulator_inspect_site, non_line_inspect_site, manipulator_inspect_site_NDC, standard_manipulator_stacking_site, - standard_photoelectric_inspect_site, electric_fence }, + standard_photoelectric_inspect_site, electric_fence, standard_inspect_site_smart, standard_autodoor_smart }, dicts: ['device_type'], mixins: [crud], data() { diff --git a/acs/qd/src/views/acs/device/driver/standard_autodoor_smart.vue b/acs/qd/src/views/acs/device/driver/standard_autodoor_smart.vue new file mode 100644 index 0000000..41e2f46 --- /dev/null +++ b/acs/qd/src/views/acs/device/driver/standard_autodoor_smart.vue @@ -0,0 +1,352 @@ +<template> + <!--自动门--> + <div> + + <el-card class="box-card" shadow="never"> + <div slot="header" class="clearfix"> + <span class="role-span">设备协议:</span> + </div> + + <el-row> + <el-col :span="12"> + OpcServer: + <el-select + v-model="opc_id" + placeholder="无" + clearable + @change="changeOpc" + > + <el-option + v-for="item in dataOpcservers" + :key="item.opc_id" + :label="item.opc_name" + :value="item.opc_id" + /> + </el-select> + </el-col> + <el-col :span="12"> + PLC: + <el-select + v-model="plc_id" + placeholder="无" + clearable + @change="changePlc" + > + <el-option + v-for="item in dataOpcPlcs" + :key="item.plc_id" + :label="item.plc_name" + :value="item.plc_id" + /> + </el-select> + </el-col> + </el-row> + + </el-card> + + <el-card class="box-card" shadow="never"> + <div slot="header" class="clearfix"> + <span class="role-span">输送系统:</span> + </div> + <el-form ref="form" :inline="true" :model="form" :rules="rules" size="small" label-width="78px"> + <el-row> + <el-col :span="8"> + <el-form-item label="电气调度号" label-width="150px"> + <el-switch v-model="form.OPCServer" /> + </el-form-item> + </el-col> + </el-row> + </el-form> + </el-card> + + <el-card class="box-card" shadow="never"> + <div slot="header" class="clearfix"> + <span class="role-span">PLC读取字段:</span> + </div> + <el-form ref="form" :inline="true" :model="form" :rules="rules" size="small" label-width="78px"> + <el-table + v-loading="false" + :data="data1" + :max-height="550" + size="small" + style="width: 100%;margin-bottom: 15px" + > + + <el-table-column prop="name" label="用途" /> + <el-table-column prop="code" label="别名要求" /> + <el-table-column prop="db" label="DB块"> + <template slot-scope="scope"> + <el-input + v-model="data1[scope.$index].db" + size="mini" + class="edit-input" + @input="finishReadEdit(data1[scope.$index])" + /> + </template> + </el-table-column> + <el-table-column prop="dbr_value"> + <template slot="header"> + <el-link type="primary" :underline="false" @click.native="test_read1()">测试读</el-link> + </template> + <template slot-scope="scope"> + <el-input v-model="data1[scope.$index].dbr_value" size="mini" class="edit-input" /> + </template> + </el-table-column> + </el-table> + </el-form> + </el-card> + + <el-card class="box-card" shadow="never"> + <div slot="header" class="clearfix"> + <span class="role-span">PLC写入字段:</span> + </div> + <el-form ref="form" :inline="true" :model="form" :rules="rules" size="small" label-width="78px"> + <el-table + v-loading="false" + :data="data2" + :max-height="550" + size="small" + style="width: 100%;margin-bottom: 15px" + > + + <el-table-column prop="name" label="用途" /> + <el-table-column prop="code" label="别名要求" /> + <el-table-column prop="db" label="DB块"> + <template slot-scope="scope"> + <el-input + v-model="data2[scope.$index].db" + size="mini" + class="edit-input" + @input="finishWriteEdit(data2[scope.$index])" + /> + </template> + </el-table-column> + <el-table-column prop="dbw_value"> + <template slot="header"> + <el-link type="primary" :underline="false" @click.native="test_write1()">测试写</el-link> + </template> + <template slot-scope="scope"> + <el-input v-model="data2[scope.$index].dbw_value" size="mini" class="edit-input" /> + </template> + </el-table-column> + </el-table> + </el-form> + </el-card> + + <el-card class="box-card" shadow="never"> + <div slot="header" class="clearfix"> + <span class="role-span" /> + <el-button + :loading="false" + icon="el-icon-check" + size="mini" + style="float: right; padding: 6px 9px" + type="primary" + @click="doSubmit" + >保存 + </el-button> + </div> + </el-card> + + </div> +</template> + +<script> +import { + queryDriverConfig, + updateConfig, + testRead, + testwrite +} from '@/api/acs/device/driverConfig' +import { selectOpcList } from '@/api/acs/device/opc' +import { selectPlcList } from '@/api/acs/device/opcPlc' +import { selectListByOpcID } from '@/api/acs/device/opcPlc' + +import crud from '@/mixins/crud' + +export default { + name: 'StandardAutodoor', + mixins: [crud], + props: { + parentForm: { + type: Object, + require: true + } + }, + data() { + return { + device_code: '', + device_id: '', + plc_id: '', + plc_code: '', + opc_id: '', + opc_code: '', + configLoading: false, + dataOpcservers: [], + dataOpcPlcs: [], + data1: [], + data2: [], + form: { + inspect_in_stocck: true, + ignore_pickup_check: true, + ignore_release_check: true, + apply_task: true, + manual_create_task: true, + is_pickup: true, + is_release: true + }, + rules: {} + } + }, + created() { + this.$nextTick(() => { + // 从父表单获取设备编码 + this.device_id = this.$props.parentForm.device_id + this.device_code = this.$props.parentForm.device_code + queryDriverConfig(this.device_id, this.$props.parentForm.driver_code).then(data => { + // 给表单赋值,并且属性不能为空 + if (data.form) { + const arr = Object.keys(data.form) + // 不为空 + if (arr.length > 0) { + this.form = data.form + } + } + + // 给表单赋值,并且属性不能为空 + if (data.parentForm) { + const arr = Object.keys(data.parentForm) + // 不为空 + if (arr.length > 0) { + this.opc_code = data.parentForm.opc_code + this.plc_code = data.parentForm.plc_code + } + } + this.data1 = data.rs + this.data2 = data.ws + this.sliceItem() + }) + selectPlcList().then(data => { + this.dataOpcPlcs = data + this.plc_id = this.$props.parentForm.opc_plc_id + }) + selectOpcList().then(data => { + this.dataOpcservers = data + this.opc_id = this.$props.parentForm.opc_server_id + }) + }) + }, + methods: { + changeOpc(val) { + this.dataOpcservers.forEach(item => { + if (item.opc_id === val) { + this.opc_code = item.opc_code + } + }) + selectListByOpcID(val).then(data => { + this.dataOpcPlcs = data + this.plc_id = '' + this.plc_code = '' + if (this.dataOpcPlcs && this.dataOpcPlcs.length > 0) { + this.plc_id = this.dataOpcPlcs[0].plc_id + this.plc_code = this.dataOpcPlcs[0].plc_code + } + this.sliceItem() + }) + }, + finishReadEdit(data) { + // 编辑的是code列,并且值包含mode + if (data.code.indexOf('mode') !== -1) { + const dbValue = data.db + // .之前的字符串 + const beforeStr = dbValue.match(/(\S*)\./)[1] + // .之后的字符串 + const afterStr = dbValue.match(/\.(\S*)/)[1] + // 取最后数字 + const endNumber = afterStr.substring(1) + // 最后为非数字 + if (isNaN(parseInt(endNumber))) { + return + } + for (const val in this.data1) { + if (this.data1[val].code.indexOf('action') !== -1) { + this.data1[val].db = beforeStr + '.' + afterStr.substring(0, 1) + (parseInt(endNumber) + 1) + } + if (this.data1[val].code.indexOf('error') !== -1) { + this.data1[val].db = beforeStr + '.' + afterStr.substring(0, 1) + (parseInt(endNumber) + 2) + } + } + } + }, + changePlc(val) { + this.dataOpcPlcs.forEach(item => { + if (item.plc_id === val) { + this.plc_code = item.plc_code + this.sliceItem() + return + } + }) + }, + test_read1() { + testRead(this.data1, this.opc_id).then(data => { + this.data1 = data + this.notify('操作成功!', 'success') + }).catch(err => { + console.log(err.response.data.message) + }) + }, + test_write1() { + testwrite(this.data2, this.opc_id).then(data => { + this.notify('操作成功!', 'success') + }).catch(err => { + console.log(err.response.data.message) + }) + }, + doSubmit() { + this.$refs['form'].validate((valid) => { + if (valid) { + this.configLoading = true + // 根据驱动类型判断是否为路由设备 + const parentForm = this.parentForm + parentForm.is_route = true + parentForm.plc_id = this.plc_id + parentForm.opc_id = this.opc_id + updateConfig(parentForm, this.form, this.data1, this.data2).then(res => { + this.notify('保存成功', 'success') + this.configLoading = false + }).catch(err => { + this.configLoading = false + console.log(err.response.data.message) + }) + } + }) + }, + sliceItem() { // 拼接DB的Item值 + this.data1.forEach(item => { + const str = item.code + // 是否包含. + if (str.search('.') !== -1) { + // 截取最后一位 + item.code = this.opc_code + '.' + this.plc_code + '.' + this.device_code + '.' + str.slice(str.lastIndexOf('.') + 1) + } else { + item.code = this.opc_code + '.' + this.plc_code + '.' + this.device_code + '.' + item.code + } + }) + this.data2.forEach(item => { + const str = item.code + // 是否包含. + if (str.search('.') !== -1) { + // 截取最后一位 + item.code = this.opc_code + '.' + this.plc_code + '.' + this.device_code + '.' + str.slice(str.lastIndexOf('.') + 1) + } else { + item.code = this.opc_code + '.' + this.plc_code + '.' + this.device_code + '.' + item.code + } + }) + } + } +} +</script> + +<style scoped> + +</style> diff --git a/acs/qd/src/views/acs/device/driver/standard_inspect_site_smart.vue b/acs/qd/src/views/acs/device/driver/standard_inspect_site_smart.vue new file mode 100644 index 0000000..39f2c9a --- /dev/null +++ b/acs/qd/src/views/acs/device/driver/standard_inspect_site_smart.vue @@ -0,0 +1,489 @@ +<template> + <!--检测站点Smart200--> + <div> + <el-card class="box-card" shadow="never"> + <div slot="header" class="clearfix"> + <span class="role-span">设备协议:</span> + </div> + + <el-row> + <el-col :span="12"> + OpcServer: + <el-select + v-model="opc_id" + placeholder="无" + clearable + @change="changeOpc" + > + <el-option + v-for="item in dataOpcservers" + :key="item.opc_id" + :label="item.opc_name" + :value="item.opc_id" + /> + </el-select> + </el-col> + <el-col :span="12"> + PLC: + <el-select + v-model="plc_id" + placeholder="无" + clearable + @change="changePlc" + > + <el-option + v-for="item in dataOpcPlcs" + :key="item.plc_id" + :label="item.plc_name" + :value="item.plc_id" + /> + </el-select> + </el-col> + </el-row> + + </el-card> + + <el-card class="box-card" shadow="never"> + <div slot="header" class="clearfix"> + <span class="role-span">输送系统:</span> + </div> + <el-form ref="form" :inline="true" :model="form" :rules="rules" size="small" label-width="78px"> + <el-row> + <el-col :span="8"> + <el-form-item label="电气调度号" label-width="150px"> + <el-input v-model="form.OPCServer" /> + </el-form-item> + </el-col> + </el-row> + </el-form> + </el-card> + + <el-card class="box-card" shadow="never"> + <div slot="header" class="clearfix"> + <span class="role-span">指令相关:</span> + </div> + <el-form ref="form" :inline="true" :model="form" :rules="rules" size="small" label-width="78px"> + <el-row> + <el-col :span="8"> + <el-form-item label="检验有货"> + <el-switch v-model="form.inspect_in_stocck" /> + </el-form-item> + </el-col> + <el-col :span="8"> + <el-form-item label="忽视取货校验" label-width="150px"> + <el-switch v-model="form.ignore_pickup_check" /> + </el-form-item> + </el-col> + <el-col :span="8"> + <el-form-item label="忽视放货校验" label-width="150px"> + <el-switch v-model="form.ignore_release_check" /> + </el-form-item> + </el-col> + </el-row> + + <el-row> + <el-col :span="8"> + <el-form-item label="呼叫"> + <el-switch v-model="form.apply_task" /> + </el-form-item> + </el-col> + <el-col :span="8"> + <el-form-item label="响应" label-width="150px"> + <el-switch v-model="form.manual_create_task" /> + </el-form-item> + </el-col> + <el-col :span="8"> + <el-form-item label="是否输入物料" label-width="150px"> + <el-switch v-model="form.input_material" /> + </el-form-item> + </el-col> + </el-row> + + <el-row> + <el-col :span="8"> + <el-form-item label="关联设备" prop="device_code"> + <el-select + v-model="form.link_device_code" + filterable + multiple + placeholder="请选择" + > + <el-option + v-for="item in deviceList" + :key="item.device_code" + :label="item.device_name" + :value="item.device_code" + /> + </el-select> + </el-form-item> + </el-col> + <el-col :span="8"> + <el-form-item label="关联三色灯" prop="device_code" label-width="100px"> + <el-select + v-model="form.link_three_lamp" + filterable + clearable + placeholder="请选择" + > + <el-option + v-for="item in deviceList" + :key="item.device_code" + :label="item.device_name" + :value="item.device_code" + /> + </el-select> + </el-form-item> + </el-col> + <el-tooltip class="item" effect="dark" content="创建设备点位记录有无货信号" placement="bottom-end"> + <el-form-item label="站点管理" label-width="150px"> + <el-switch v-model="form.station_manager" /> + </el-form-item> + </el-tooltip> + </el-row> + </el-form> + </el-card> + + <el-card class="box-card" shadow="never"> + <div slot="header" class="clearfix"> + <span class="role-span">AGV相关:</span> + </div> + <el-form ref="form" :inline="true" :model="form" :rules="rules" size="small" label-width="78px"> + <el-row> + <el-col :span="8"> + <el-form-item label="取货"> + <el-switch v-model="form.is_pickup" /> + </el-form-item> + </el-col> + <el-col :span="8"> + <el-form-item label="放货"> + <el-switch v-model="form.is_release" /> + </el-form-item> + </el-col> + </el-row> + </el-form> + </el-card> + + <el-card class="box-card" shadow="never"> + <div slot="header" class="clearfix"> + <span class="role-span">PLC读取字段:</span> + </div> + <el-form ref="form" :inline="true" :model="form" :rules="rules" size="small" label-width="78px"> + <el-table + v-loading="false" + :data="data1" + :max-height="550" + size="small" + style="width: 100%;margin-bottom: 15px" + > + + <el-table-column prop="name" label="用途" /> + <el-table-column prop="code" label="别名要求" /> + <el-table-column prop="db" label="DB块"> + <template slot-scope="scope"> + <el-input + v-model="data1[scope.$index].db" + size="mini" + class="edit-input" + @input="finishReadEdit(data1[scope.$index])" + /> + </template> + </el-table-column> + <el-table-column prop="dbr_value"> + <template slot="header"> + <el-link type="primary" :underline="false" @click.native="test_read1()">测试读</el-link> + </template> + <template slot-scope="scope"> + <el-input v-model="data1[scope.$index].dbr_value" size="mini" class="edit-input" /> + </template> + </el-table-column> + </el-table> + </el-form> + </el-card> + + <el-card class="box-card" shadow="never"> + <div slot="header" class="clearfix"> + <span class="role-span">PLC写入字段:</span> + </div> + <el-form ref="form" :inline="true" :model="form" :rules="rules" size="small" label-width="78px"> + <el-table + v-loading="false" + :data="data2" + :max-height="550" + size="small" + style="width: 100%;margin-bottom: 15px" + > + + <el-table-column prop="name" label="用途" /> + <el-table-column prop="code" label="别名要求" /> + <el-table-column prop="db" label="DB块"> + <template slot-scope="scope"> + <el-input + v-model="data2[scope.$index].db" + size="mini" + class="edit-input" + @input="finishWriteEdit(data2[scope.$index])" + /> + </template> + </el-table-column> + <el-table-column prop="dbw_value"> + <template slot="header"> + <el-link type="primary" :underline="false" @click.native="test_write1()">测试写</el-link> + </template> + <template slot-scope="scope"> + <el-input v-model="data2[scope.$index].dbw_value" size="mini" class="edit-input" /> + </template> + </el-table-column> + </el-table> + </el-form> + </el-card> + + <el-card class="box-card" shadow="never"> + <div slot="header" class="clearfix"> + <span class="role-span" /> + <el-button + :loading="false" + icon="el-icon-check" + size="mini" + style="float: right; padding: 6px 9px" + type="primary" + @click="doSubmit" + >保存 + </el-button> + </div> + </el-card> + + </div> +</template> + +<script> +import { + queryDriverConfig, + updateConfig, + testRead, + testwrite +} from '@/api/acs/device/driverConfig' +import { selectOpcList } from '@/api/acs/device/opc' +import { selectPlcList } from '@/api/acs/device/opcPlc' +import { selectListByOpcID } from '@/api/acs/device/opcPlc' + +import crud from '@/mixins/crud' +import deviceCrud from '@/api/acs/device/device' + +export default { + name: 'StandardInspectSite', + mixins: [crud], + props: { + parentForm: { + type: Object, + require: true + } + }, + data() { + return { + device_code: '', + device_id: '', + plc_id: '', + plc_code: '', + opc_id: '', + opc_code: '', + configLoading: false, + dataOpcservers: [], + dataOpcPlcs: [], + deviceList: [], + data1: [], + data2: [], + form: { + inspect_in_stocck: true, + ignore_pickup_check: true, + ignore_release_check: true, + apply_task: true, + link_three_lamp: '', + manual_create_task: true, + is_pickup: true, + is_release: true, + link_device_code: [] + }, + rules: {} + } + }, + created() { + this.$nextTick(() => { + // 从父表单获取设备编码 + this.device_id = this.$props.parentForm.device_id + this.device_code = this.$props.parentForm.device_code + queryDriverConfig(this.device_id, this.$props.parentForm.driver_code).then(data => { + // 给表单赋值,并且属性不能为空 + if (data.form) { + const arr = Object.keys(data.form) + // 不为空 + if (arr.length > 0) { + this.form = data.form + } + } + + // 给表单赋值,并且属性不能为空 + if (data.parentForm) { + const arr = Object.keys(data.parentForm) + // 不为空 + if (arr.length > 0) { + this.opc_code = data.parentForm.opc_code + this.plc_code = data.parentForm.plc_code + } + } + this.data1 = data.rs + this.data2 = data.ws + this.sliceItem() + }) + selectPlcList().then(data => { + this.dataOpcPlcs = data + this.plc_id = this.$props.parentForm.opc_plc_id + }) + selectOpcList().then(data => { + this.dataOpcservers = data + this.opc_id = this.$props.parentForm.opc_server_id + }) + deviceCrud.selectDeviceList().then(data => { + this.deviceList = data + }) + }) + }, + methods: { + finishReadEdit(data) { + debugger + // 编辑的是code列,并且值包含mode + if (data.code.indexOf('mode') !== -1) { + const dbValue = data.db + // .之前的字符串 + const beforeStr = dbValue.substring(0, 2) + // .之后的字符串 + const afterStr = dbValue.substring(2) + for (const val in this.data1) { + if (this.data1[val].code.indexOf('move') !== -1) { + this.data1[val].db = beforeStr + (parseInt(afterStr) + 2) + } + if (this.data1[val].code.indexOf('action') !== -1) { + this.data1[val].db = beforeStr + (parseInt(afterStr) + 4) + } + if (this.data1[val].code.indexOf('error') !== -1) { + this.data1[val].db = beforeStr + (parseInt(afterStr) + 6) + } + if (this.data1[val].code.indexOf('number') !== -1) { + this.data1[val].db = beforeStr + (parseInt(afterStr) + 8) + } + if (this.data1[val].code.indexOf('container_type') !== -1) { + this.data1[val].db = beforeStr + (parseInt(afterStr) + 10) + } + if (this.data1[val].code.indexOf('task') !== -1) { + this.data1[val].db = beforeStr + (parseInt(afterStr) + 12) + } + } + } + }, + finishWriteEdit(data) { + // 编辑的是code列,并且值包含mode + if (data.code.indexOf('to_command') !== -1) { + const dbValue = data.db + // .之前的字符串 + const beforeStr = dbValue.substring(0, 2) + // .之后的字符串 + const afterStr = dbValue.substring(2) + for (const val in this.data2) { + if (this.data2[val].code.indexOf('to_target') !== -1) { + this.data2[val].db = beforeStr + (parseInt(afterStr) + 2) + } + if (this.data2[val].code.indexOf('to_task') !== -1) { + this.data2[val].db = beforeStr + (parseInt(afterStr) + 4) + } + } + } + }, + changeOpc(val) { + this.dataOpcservers.forEach(item => { + if (item.opc_id === val) { + this.opc_code = item.opc_code + } + }) + + selectListByOpcID(val).then(data => { + this.dataOpcPlcs = data + this.plc_id = '' + this.plc_code = '' + if (this.dataOpcPlcs && this.dataOpcPlcs.length > 0) { + this.plc_id = this.dataOpcPlcs[0].plc_id + this.plc_code = this.dataOpcPlcs[0].plc_code + } + this.sliceItem() + }) + }, + changePlc(val) { + this.dataOpcPlcs.forEach(item => { + if (item.plc_id === val) { + this.plc_code = item.plc_code + this.sliceItem() + return + } + }) + }, + test_read1() { + testRead(this.data1, this.opc_id).then(data => { + this.data1 = data + this.notify('操作成功!', 'success') + }).catch(err => { + console.log(err.response.data.message) + }) + }, + test_write1() { + testwrite(this.data2, this.opc_id).then(data => { + this.notify('操作成功!', 'success') + }).catch(err => { + console.log(err.response.data.message) + }) + }, + doSubmit() { + this.$refs['form'].validate((valid) => { + if (valid) { + this.configLoading = true + // 根据驱动类型判断是否为路由设备 + const parentForm = this.parentForm + parentForm.is_route = true + parentForm.plc_id = this.plc_id + parentForm.opc_id = this.opc_id + updateConfig(parentForm, this.form, this.data1, this.data2).then(res => { + this.notify('保存成功', 'success') + this.configLoading = false + }).catch(err => { + this.configLoading = false + console.log(err.response.data.message) + }) + } + }) + }, + sliceItem() { // 拼接DB的Item值 + this.data1.forEach(item => { + const str = item.code + // 是否包含. + if (str.search('.') !== -1) { + // 截取最后一位 + item.code = this.opc_code + '.' + this.plc_code + '.' + this.device_code + '.' + str.slice(str.lastIndexOf('.') + 1) + } else { + item.code = this.opc_code + '.' + this.plc_code + '.' + this.device_code + '.' + item.code + } + }) + this.data2.forEach(item => { + const str = item.code + // 是否包含. + if (str.search('.') !== -1) { + // 截取最后一位 + item.code = this.opc_code + '.' + this.plc_code + '.' + this.device_code + '.' + str.slice(str.lastIndexOf('.') + 1) + } else { + item.code = this.opc_code + '.' + this.plc_code + '.' + this.device_code + '.' + item.code + } + }) + } + } +} +</script> + +<style scoped> + +</style> diff --git a/lms/hd/nladmin-system/src/main/java/org/nl/wms/pda/sendmaterial/service/impl/SendMaterialServiceImpl.java b/lms/hd/nladmin-system/src/main/java/org/nl/wms/pda/sendmaterial/service/impl/SendMaterialServiceImpl.java index e29ae8b..e57c547 100644 --- a/lms/hd/nladmin-system/src/main/java/org/nl/wms/pda/sendmaterial/service/impl/SendMaterialServiceImpl.java +++ b/lms/hd/nladmin-system/src/main/java/org/nl/wms/pda/sendmaterial/service/impl/SendMaterialServiceImpl.java @@ -15,9 +15,9 @@ import org.nl.wms.sch.tasks.SendMaterialTask; import org.nl.wms.st.inbill.service.dto.RegionioDto; import org.nl.wql.WQL; import org.nl.wql.core.bean.WQLObject; -import org.nl.wql.core.engine.object.WO; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.transaction.interceptor.TransactionAspectSupport; @Service @RequiredArgsConstructor @@ -56,6 +56,7 @@ public class SendMaterialServiceImpl implements SendMaterialService { return resultJSON; } + @Transactional(rollbackFor = Exception.class) @Override public JSONObject confirm(JSONObject param) { // 返回值 @@ -121,8 +122,8 @@ public class SendMaterialServiceImpl implements SendMaterialService { json.put("bill_status", "20"); regionIOTable.update(json, "iostorinv_id = " + id); } catch (Exception e) { - // 报错删除搬运记录(任务已在createTask中删除) - regionIOTable.delete("iostorinv_id = " + id); + // 手动回滚事务 + TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); resultJSON.put("code", "0"); resultJSON.put("desc", e.getMessage()); diff --git a/lms/hd/nladmin-system/src/main/java/org/nl/wms/sch/service/wql/sch.xls b/lms/hd/nladmin-system/src/main/java/org/nl/wms/sch/service/wql/sch.xls index da3252b4cb4d80f241fa62fe7f4436edfb469908..8178a7ce42390aaad0bd5be708c739aaca414d50 100644 GIT binary patch delta 3697 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 YUVIa)CL|7AEi~y(rHS&C{WwMWzl^KOmjD0& delta 3655 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