diff --git a/cpte-boot-base-core/src/main/java/org/jeecg/common/aspect/DictAspect.java b/cpte-boot-base-core/src/main/java/org/jeecg/common/aspect/DictAspect.java index 20cebdd..6756d2c 100644 --- a/cpte-boot-base-core/src/main/java/org/jeecg/common/aspect/DictAspect.java +++ b/cpte-boot-base-core/src/main/java/org/jeecg/common/aspect/DictAspect.java @@ -62,9 +62,12 @@ public class DictAspect { * 定义切点Pointcut */ @Pointcut("(@within(org.springframework.web.bind.annotation.RestController) || " + - "@within(org.springframework.stereotype.Controller) || @annotation(org.jeecg.common.aspect.annotation.AutoDict)) " + + "@within(org.springframework.stereotype.Controller) || " + + "@annotation(org.jeecg.common.aspect.annotation.AutoDict)) " + "&& (execution(public org.jeecg.common.api.vo.Result org.jeecg..*.*(..)) || " + - "(execution(public * org.cpte..*.*Controller.*(..)) && !execution(public org.cpte.modules.hikAgv.response.* org.cpte.modules.hikAgv.controller.*.*(..))))") + "(execution(public * org.cpte..*.*Controller.*(..)) && " + + "!execution(public org.cpte.modules.hikAgv.response.* org.cpte.modules.hikAgv.controller.*.*(..)) && " + + "!execution(public org.cpte.modules.tesAgv.response.* org.cpte.modules.tesAgv.controller.*.*(..))))") public void excudeService() { } diff --git a/cpte-boot-base-core/src/main/java/org/jeecg/config/mybatis/MybatisPlusSaasConfig.java b/cpte-boot-base-core/src/main/java/org/jeecg/config/mybatis/MybatisPlusSaasConfig.java index fbadc97..a07a8f0 100644 --- a/cpte-boot-base-core/src/main/java/org/jeecg/config/mybatis/MybatisPlusSaasConfig.java +++ b/cpte-boot-base-core/src/main/java/org/jeecg/config/mybatis/MybatisPlusSaasConfig.java @@ -36,7 +36,7 @@ import java.util.List; */ @Slf4j @Configuration -@MapperScan(value={"org.jeecg.**.mapper*","org.cpte.**.mapper*"}) +@MapperScan(value={"org.jeecg.modules.**.mapper*", "org.jeecg.**.mapper*","org.cpte.modules.**.mapper*", "org.cpte.**.mapper*"}) public class MybatisPlusSaasConfig { @Autowired private DataSource dataSource; diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/agvTask/entity/AgvTask.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/agvTask/entity/AgvTask.java index 9c20e17..02a15c6 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/agvTask/entity/AgvTask.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/agvTask/entity/AgvTask.java @@ -32,19 +32,12 @@ public class AgvTask implements Serializable { private static final long serialVersionUID = 1L; /** - * id + * 任务ID */ @TableId(type = IdType.ASSIGN_ID) @Schema(description = "id") private java.lang.String id; - /** - * 任务编号 - */ - @Excel(name = "任务编号", width = 15) - @Schema(description = "任务编号") - private java.lang.String agvCode; - /** * 载具编号 */ @@ -76,7 +69,7 @@ public class AgvTask implements Serializable { @Excel(name = "任务状态", width = 15) @Schema(description = "任务状态") @Dict(dicCode = "agv_task_status") - private java.lang.String status; + private java.lang.Integer status; /** * 优先级 */ @@ -95,6 +88,15 @@ public class AgvTask implements Serializable { @Excel(name = "终点位置", width = 15) @Schema(description = "终点位置") private java.lang.String endCode; + + /** + * AGV供应商 + */ + @Excel(name = "AGV供应商", width = 15) + @Schema(description = "AGV供应商") + @Dict(dicCode = "agv_vendor") + private java.lang.String agvVendor; + /** * 返回报文 */ diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/agvTask/mapper/AgvTaskMapper.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/agvTask/mapper/AgvTaskMapper.java index 4d1112b..057c8f4 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/agvTask/mapper/AgvTaskMapper.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/agvTask/mapper/AgvTaskMapper.java @@ -1,12 +1,12 @@ package org.cpte.modules.agvTask.mapper; -import java.util.List; - import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Select; import org.cpte.modules.agvTask.entity.AgvTask; import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import java.util.List; + /** * @Description: AGV任务表 * @author: cpte @@ -14,6 +14,21 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper; * @Version: V1.0 */ public interface AgvTaskMapper extends BaseMapper { - @Select(value = "select count(agv.id) from data_agv_task where carrier_code = #{carrierCode} and start_code = #{startCode} and end_code= #{endCode} and status in ('CREATED','ARRIVED','EXECUTING') ") - Long isAGVTaskDuplicate(String carrierCode, String startCode, String endCode); + /** + * 验证AGV任务是否存在 + * + * @param carrierCode 容器 + * @param agvVendor 供应商;AGV/TES + */ + @Select(value = "select count(id) from data_agv_task where carrier_code = #{carrierCode} and agv_vendor = #{agvVendor} and status in (1,2,3) ") + Long existsAGVTask(@Param("carrierCode") String carrierCode, @Param("agvVendor") String agvVendor); + + /** + * 查询AGV任务列表 + * + * @param status 状态 + * @param agvVendor 供应商;AGV/TES + */ + @Select(value = "select * from data_agv_task where status = #{status} and agv_vendor = #{agvVendor}") + List queryAgvTaskList(@Param("status") Integer status, @Param("agvVendor") String agvVendor); } diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/agvTask/service/IAgvTaskService.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/agvTask/service/IAgvTaskService.java index 577af48..5099a4c 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/agvTask/service/IAgvTaskService.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/agvTask/service/IAgvTaskService.java @@ -21,13 +21,8 @@ public interface IAgvTaskService extends IService { * @param endCode 终点 * @param taskType 任务类型 * @param type 业务类型 + * @param agvVendor 供应商 */ - AgvTask createAgvTask(String status, String carrierCode, String startCode, String endCode, String taskType,String type); + AgvTask createAgvTask(Integer status, String carrierCode, String startCode, String endCode, String taskType, String type, String agvVendor); - /** - * 查询agvTask任务列表 - * - * @param status 状态 - */ - List queryAgvTaskList(String status); } diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/agvTask/service/impl/AgvTaskServiceImpl.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/agvTask/service/impl/AgvTaskServiceImpl.java index 6fe2be5..08516c8 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/agvTask/service/impl/AgvTaskServiceImpl.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/agvTask/service/impl/AgvTaskServiceImpl.java @@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import org.cpte.modules.agvTask.entity.AgvTask; import org.cpte.modules.agvTask.mapper.AgvTaskMapper; import org.cpte.modules.agvTask.service.IAgvTaskService; +import org.cpte.modules.constant.enums.AgvVendorEnum; import org.cpte.modules.constant.enums.StockTypeEnum; import org.springframework.stereotype.Service; @@ -23,7 +24,11 @@ public class AgvTaskServiceImpl extends ServiceImpl impl @Override @Transactional(rollbackFor = Exception.class) - public AgvTask createAgvTask(String status, String carrierCode, String startCode, String endCode, String taskType, String type) { + public AgvTask createAgvTask(Integer status, String carrierCode, String startCode, String endCode, String taskType, String type, String agvVendor) { + Integer priority = 99; + if (AgvVendorEnum.TES.getValue().equals(agvVendor)) { + priority = 3; + } AgvTask agvTask = AgvTask.builder() .carrierCode(carrierCode) .type(type) @@ -32,15 +37,9 @@ public class AgvTaskServiceImpl extends ServiceImpl impl .endCode(endCode) .carrierType(StockTypeEnum.TRAY.getValue()) .taskType(taskType) - .priority(99) + .priority(priority) + .agvVendor(agvVendor) .build(); return this.save(agvTask) ? agvTask : null; } - - @Override - public List queryAgvTaskList(String status) { - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.eq(AgvTask::getStatus, status); - return this.list(queryWrapper); - } } diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/service/IStockService.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/service/IStockService.java index 1578e43..0e546ab 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/service/IStockService.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/base/service/IStockService.java @@ -37,5 +37,4 @@ public interface IStockService extends IService { */ Map queryByStockCodesToMap(List stockCodes); - } diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/constant/enums/AgvStatusEnum.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/constant/enums/AgvStatusEnum.java index 5df6578..efe1191 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/constant/enums/AgvStatusEnum.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/constant/enums/AgvStatusEnum.java @@ -10,27 +10,27 @@ import lombok.Getter; @Getter public enum AgvStatusEnum { - CREATED("CREATED", "已创建"), + CREATED(1, "已创建"), - EXECUTING("EXECUTING", "执行中"), + EXECUTING(2, "执行中"), - ARRIVED("ARRIVED", "已到达"), + ARRIVED(3, "已到达"), - COMPLETED("COMPLETED", "已完成"), + COMPLETED(4, "已完成"), - CANCELLED("CANCELLED", "已取消"), + CANCELLED(5, "已取消"), ; /** * 值 */ - private final String value; + private final Integer value; /** * 描述 */ private final String desc; - AgvStatusEnum(String value, String desc) { + AgvStatusEnum(Integer value, String desc) { this.value = value; this.desc = desc; } diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/constant/enums/AgvVendorEnum.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/constant/enums/AgvVendorEnum.java new file mode 100644 index 0000000..d78ee5a --- /dev/null +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/constant/enums/AgvVendorEnum.java @@ -0,0 +1,32 @@ +package org.cpte.modules.constant.enums; + +import lombok.Getter; + +/** + * agv供应商 + * + * @author: cpte + */ +@Getter +public enum AgvVendorEnum { + + HIK("HIK", "海康AGV"), + + TES("TES", "旷视四向车"), + + ; + /** + * 值 + */ + private final String value; + /** + * 描述 + */ + private final String desc; + + AgvVendorEnum(String value, String desc) { + this.value = value; + this.desc = desc; + } + +} diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/constant/enums/AsnStatusEnum.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/constant/enums/AsnStatusEnum.java index eb27524..d504a0a 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/constant/enums/AsnStatusEnum.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/constant/enums/AsnStatusEnum.java @@ -10,21 +10,18 @@ import lombok.Getter; @Getter public enum AsnStatusEnum { - CREATED("CREATED", "已创建"), + CREATED(1, "已创建"), - ACTIVE("ACTIVE", "已审核"), + RECEIVING(2, "部分收货"), - RECEIVING("RECEIVING", "部分收货"), + RECEIVED(3, "收货完成"), - RECEIVED("RECEIVED", "收货完成"), + CANCELED(4, "已取消"), - CLOSE("CLOSE", "已关闭"), - - CANCEL("CANCEL", "已取消"), ; - AsnStatusEnum(String value, String desc) { + AsnStatusEnum(Integer value, String desc) { this.value = value; this.desc = desc; } @@ -32,7 +29,7 @@ public enum AsnStatusEnum { /** * 值 */ - final String value; + final Integer value; /** * 描述 diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/constant/enums/InventoryStatusEnum.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/constant/enums/InventoryStatusEnum.java new file mode 100644 index 0000000..4c8a23e --- /dev/null +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/constant/enums/InventoryStatusEnum.java @@ -0,0 +1,63 @@ +package org.cpte.modules.constant.enums; + +import lombok.Data; +import lombok.Getter; + +/** + * 库存状态 + * + * @author: cpte + */ +@Getter +public enum InventoryStatusEnum { + /** + * 可用 + */ + AVAILABLE(1, "可用"), + + /** + * 已分配 + */ + ALLOCATED(2, "已分配"), + + /** + * 出库中 + */ + OUTBOUND(3, "出库中"), + + /** + * 移位中 + */ + TRANSFER(4, "移位中"), + + /** + * 盘点中 + */ + COUNTING(5, "盘点中"), + + /** + * 冻结 + */ + FROZEN(6, "冻结"), + + /** + * 残次品 + */ + DEFECTIVE(7, "残次品"); + + InventoryStatusEnum(Integer value, String desc) { + this.value = value; + this.desc = desc; + } + + /** + * 值 + */ + final Integer value; + + /** + * 描述 + */ + final String desc; +} + diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/conveyorLine/controller/ConveyorLineController.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/conveyorLine/controller/ConveyorLineController.java index f9b4807..c0fd00e 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/conveyorLine/controller/ConveyorLineController.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/conveyorLine/controller/ConveyorLineController.java @@ -1,6 +1,5 @@ package org.cpte.modules.conveyorLine.controller; -import com.alibaba.fastjson.JSON; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/conveyorLine/service/impl/IConveyorLineServiceImpl.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/conveyorLine/service/impl/IConveyorLineServiceImpl.java index 55e9d12..3e27773 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/conveyorLine/service/impl/IConveyorLineServiceImpl.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/conveyorLine/service/impl/IConveyorLineServiceImpl.java @@ -1,6 +1,15 @@ package org.cpte.modules.conveyorLine.service.impl; import lombok.extern.slf4j.Slf4j; +import org.cpte.modules.agvTask.mapper.AgvTaskMapper; +import org.cpte.modules.agvTask.service.IAgvTaskService; +import org.cpte.modules.base.entity.Stock; +import org.cpte.modules.base.mapper.StockMapper; +import org.cpte.modules.base.service.IStockService; +import org.cpte.modules.constant.enums.AgvStatusEnum; +import org.cpte.modules.constant.enums.AgvVendorEnum; +import org.cpte.modules.constant.enums.AsnStatusEnum; +import org.cpte.modules.constant.enums.BusinessTypeEnum; import org.cpte.modules.conveyorLine.request.ScanTrayRequest; import org.cpte.modules.conveyorLine.service.IConveyorLineService; import org.cpte.modules.receive.entity.AsnDetail; @@ -12,15 +21,40 @@ import org.springframework.stereotype.Service; @Service @Slf4j public class IConveyorLineServiceImpl implements IConveyorLineService { + @Autowired private AsnDetailMapper asnDetailMapper; + @Autowired + private IStockService iStockService; + + @Autowired + private AgvTaskMapper agvTaskMapper; + @Autowired + private IAgvTaskService iAgvTaskService; + @Override public void scanTray(ScanTrayRequest scanTrayRequest) { - AsnDetail asnDetail=asnDetailMapper.queryByStockCode(scanTrayRequest.getStockCode()); - if(asnDetail==null){ - throw new RuntimeException("【"+scanTrayRequest.getStockCode()+"】托盘,无入库信息"); + + //验证托盘 + Stock stock = iStockService.validateStock(scanTrayRequest.getStockCode()); + + //验证入库信息 + AsnDetail asnDetail = asnDetailMapper.queryByStockCode(stock.getId(), AsnStatusEnum.CREATED.getValue()); + if (asnDetail == null) { + throw new RuntimeException("【" + scanTrayRequest.getStockCode() + "】托盘,无入库信息"); } + //验证当前托盘是否有库存 + + //通过算法获取目标点位 + String endCode = "CCQ01"; + + //验证当前托盘是否生成了TES任务 + if (agvTaskMapper.existsAGVTask(stock.getStockCode(), AgvVendorEnum.TES.getValue()) > 0) { + throw new RuntimeException("【" + scanTrayRequest.getStockCode() + "】托盘已扫描,请勿重复扫描"); + } + //验证通过,生成Tes任务 + iAgvTaskService.createAgvTask(AgvStatusEnum.CREATED.getValue(), stock.getStockCode(), null, endCode, null, BusinessTypeEnum.INBOUND.getValue(), AgvVendorEnum.TES.getValue()); } } diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/hikAgv/controller/HikAgvController.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/hikAgv/controller/HikAgvController.java index 2bee872..b64935b 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/hikAgv/controller/HikAgvController.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/hikAgv/controller/HikAgvController.java @@ -1,20 +1,17 @@ package org.cpte.modules.hikAgv.controller; import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONObject; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.extern.slf4j.Slf4j; -import org.cpte.modules.hikAgv.request.submit.SubmitRequest; -import org.cpte.modules.hikAgv.request.taskReporter.TaskReporterRequest; -import org.cpte.modules.hikAgv.response.ResponesData; +import org.cpte.modules.hikAgv.request.SubmitRequest; +import org.cpte.modules.hikAgv.request.TaskReporterRequest; import org.cpte.modules.hikAgv.service.IHikAgvService; import org.jeecg.common.api.vo.Result; import org.cpte.modules.hikAgv.response.HikResult; import org.jeecg.common.aspect.annotation.AutoLog; import org.jeecg.config.shiro.IgnoreAuth; import org.springframework.beans.factory.annotation.Autowired; -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; @@ -27,34 +24,38 @@ import org.springframework.web.bind.annotation.RestController; public class HikAgvController { @Autowired - private IHikAgvService hikAgvService; + private IHikAgvService iHikAgvService; /** * 任务下发 * * @param submitRequest 请求参数 */ - @AutoLog(value = "任务下发") + @AutoLog(value = "海康AGV-任务下发") @Operation(summary = "海康AGV-任务下发") @PostMapping(value = "/controller/task/submit") @IgnoreAuth public Result submit(@RequestBody SubmitRequest submitRequest) { - hikAgvService.sendAgvTask("http://localhost:8000/cpte-wms/rcs/rtas/api/robot/controller/task/submit", JSON.toJSONString(submitRequest), null); + iHikAgvService.sendHikAgvTask( + "http://localhost:8000/cpte-wms/rcs/rtas/api/robot/controller/task/submit", + JSON.toJSONString(submitRequest), + null + ); return Result.OK("下发成功!"); } - @AutoLog(value = "任务上报") + @AutoLog(value = "海康AGV-任务上报") @Operation(summary = "海康AGV-任务上报") @PostMapping(value = "/reporter/task") @IgnoreAuth public HikResult taskReporter(@RequestBody TaskReporterRequest taskReporterRequest) { try { - hikAgvService.taskReporter(taskReporterRequest); - ResponesData data = new ResponesData(); + iHikAgvService.taskReporter(taskReporterRequest); + HikResult.ResponesData data = new HikResult.ResponesData(); data.setRobotTaskCode(taskReporterRequest.getRobotTaskCode()); return HikResult.success(data); } catch (Exception e) { - return HikResult.error("上报失败: " + e.getMessage()); + return HikResult.error("系统异常: " + e.getMessage()); } } } diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/hikAgv/request/SubmitRequest.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/hikAgv/request/SubmitRequest.java new file mode 100644 index 0000000..a50b921 --- /dev/null +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/hikAgv/request/SubmitRequest.java @@ -0,0 +1,266 @@ +package org.cpte.modules.hikAgv.request; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import lombok.Data; + +import java.util.List; + +/** + * AGV任务提交请求类 + *

+ * 用于向AGV系统提交任务请求的DTO对象,包含任务执行所需的所有参数配置。 + * 支持配置任务类型、执行路径、优先级、截止时间、机器人资源等核心属性。 + */ + +@JsonPropertyOrder({ + "taskType", + "targetRoute", + "initPriority", + "deadline", + "robotType", + "robotCode", + "interrupt", + "robotTaskCode", + "groupCode", + "extra" +}) +@Data +public class SubmitRequest { + /** + * 任务类型 + * 指定AGV需要执行的任务类型 + */ + @JsonProperty("taskType") + private String taskType; + + /** + * 执行步骤集合 + * 任务执行的路径规划和步骤集合 + */ + @JsonProperty("targetRoute") + private List targetRoute; + + /** + * 优先级 + * 任务的初始优先级设置 + */ + @JsonProperty("initPriority") + private Integer initPriority; + + /** + * 截止时间 + * 任务的截止时间,采用ISO 8601格式(如:2021-04-04T12:23:55Z) + */ + @JsonProperty("deadline") + private String deadline; + + /** + * 机器人类型 + * 指定机器人的资源类型,固定枚举值 + * GROUPS: 机器人资源组编号 + * ROBOTS: 机器人编号 + */ + @JsonProperty("robotType") + private String robotType; + + /** + * 机器人编码 + * 与 robotType 匹配的资源类型唯一标识,支持单个和多个编号 + */ + @JsonProperty("robotCode") + private List robotCode; + + /** + * 能否打断 + * 任务执行过程中是否允许被打断 + * 1: 可打断 - 该货架中途有其他任务时,打断当前任务 + * 0: 不可打断 - 该货架中途有其他任务时,不能打断当前任务,默认不可打断 + */ + @JsonProperty("interrupt") + private Integer interrupt; + + /** + * 机器人任务编码 + * 外部任务唯一编号,如果为空则由系统生成并返回 + */ + @JsonProperty("robotTaskCode") + private String robotTaskCode; + + /** + * 任务组编码 + * 任务组编号,全局唯一标识 + */ + @JsonProperty("groupCode") + private String groupCode; + + /** + * 扩展字段 + * 自定义扩展字段,支持不同业务场景的扩展内容, + * 可用于业务流程执行或透传上报 + */ + @JsonProperty("extra") + private Extra extra; + + + @JsonPropertyOrder({ + "seq", + "type", + "code", + "operation", + "robotType", + "robotCode", + "extra" + }) + @Data + public static class TargetRoute { + + /** + * 目标路径序列 + * 路径执行顺序编号,从0开始计数 + */ + @JsonProperty("seq") + private Integer seq; + + /** + * 目标类型 + * 指定目标位置的类型 + */ + @JsonProperty("type") + private String type; + + /** + * 目标编号 + * 目标位置的唯一标识编码 + */ + @JsonProperty("code") + private String code; + + /** + * 到达目标位置后的操作 + * 国标要求,非必要字段,对AMR动作无影响,支持可扩展枚举值 + * 预制枚举值: + * COLLECT: 取货 + * DELIVERY: 送货 + * ROTATE: 旋转 + */ + @JsonProperty("operation") + private String operation; + + /** + * 机器人类型 + * 指定机器人的资源类型,固定枚举值: + * GROUPS: 机器人资源组编号 + * ROBOTS: 机器人编号 + */ + @JsonProperty("robotType") + private String robotType; + + /** + * 机器人编码 + * 与 [robotType] 匹配的资源类型唯一标识 + */ + @JsonProperty("robotCode") + private List robotCode; + + /** + * 扩展字段 + * 自定义扩展字段,可随业务的差异而传入不同的扩展内容,在业务流程的执行中使用 + */ + @JsonProperty("extra") + private Extra extra; + } + + + /** + * 扩展信息类 + *

+ * 用于承载AGV任务的扩展配置信息,包括角度信息和载具信息等可选配置。 + */ + @JsonPropertyOrder({ + "angleInfo", + "carrierInfo" + }) + @Data + public static class Extra { + + /** + * 角度信息 + * 包含角度类型与角度值,用于指定AGV在工作站的角度配置 + */ + @JsonProperty("angleInfo") + private AngleInfo angleInfo; + + /** + * 载具信息集合 + * 包含载具编号、层号等信息,用于描述运输过程中的载具配置 + * 支持多个载具信息的配置 + */ + @JsonProperty("carrierInfo") + private List carrierInfo; + } + + /** + * 角度信息类 + *

+ * 用于描述AGV在工作站的角度信息配置,包括角度类型和具体角度值。 + */ + @JsonPropertyOrder({ + "type", + "code" + }) + @Data + public static class AngleInfo { + /** + * 角度类型 + * 可扩展枚举值,预制枚举值: + * ABSOLUTE: 绝对角度(与工作站的方向有关) + */ + @JsonProperty("type") + private String type; + + /** + * 角度值 + * 与 type 对应的具体角度值 + * 支持的角度值:[0, 90, 180, -90, 360] + */ + @JsonProperty("code") + private String code; + } + + /** + * 载具信息类 + *

+ * 用于描述AGV运输过程中承载货物的载具信息,包括载具类型、编码和层号等属性。 + */ + @JsonPropertyOrder({ + "carrierType", + "carrierCode", + "layer" + }) + @Data + public static class CarrierInfo { + + /** + * 载具类型 + * 描述载具的类型信息 + */ + @JsonProperty("carrierType") + private String carrierType; + + /** + * 载具编码 + * 载具的唯一标识编码 + */ + @JsonProperty("carrierCode") + private String carrierCode; + + /** + * 层号 + * 货物所在的层数,从0开始计数,从下往上编号 + */ + @JsonProperty("layer") + private String layer; + } + +} diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/hikAgv/request/TaskReporterRequest.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/hikAgv/request/TaskReporterRequest.java new file mode 100644 index 0000000..0fff00f --- /dev/null +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/hikAgv/request/TaskReporterRequest.java @@ -0,0 +1,168 @@ +package org.cpte.modules.hikAgv.request; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import lombok.Data; + +/** + * AGV任务状态上报请求类 + *

+ * 用于AGV任务执行过程中向系统上报任务状态信息的DTO对象, + * 包含任务执行的关键节点信息和当前位置信息。 + */ +@Data +public class TaskReporterRequest { + + /** + * 机器人任务编码 + * 外部任务唯一编号,用于关联具体任务实例 + */ + @JsonProperty("robotTaskCode") + private String robotTaskCode; + + /** + * 当前执行任务的机器人唯一标识 + * 用于标识执行当前任务的具体AGV设备 + */ + @JsonProperty("singleRobotCode") + private String singleRobotCode; + + /** + * 自定义扩展字段 + * 包含任务执行过程中的详细状态信息和其他扩展数据 + */ + @JsonProperty("extra") + private Extra extra; + + @Data + public static class Extra { + + @JsonProperty("async") + private String async; + + //节点信息 + @JsonProperty("values") + private Values values; + } + + /** + * AGV任务状态上报值对象 + *

+ * 包含AGV任务执行过程中的详细状态信息,如位置坐标、载具信息、机器人信息等 + */ + @Data + public static class Values { + + /** + * 地图编号 + * 标识当前AGV所在地图的唯一编码 + */ + @JsonProperty("mapCode") + private String mapCode; + + /** + * 存储类型 + * 枚举值: + * BIN - 仓位 + * SITE - 站点 + */ + @JsonProperty("slotCategory") + private String slotCategory; + + /** + * 当前站点编号 + * AGV当前所在的站点位置编码 + */ + @JsonProperty("slotCode") + private String slotCode; + + /** + * 站点别名 + * 1.走出储位:起点 + * 2.任务完成:目标点 + */ + @JsonProperty("slotName") + private String slotName; + + /** + * 机器人当前位置 x 坐标 + * AGV在地图中的X轴坐标值 + */ + @JsonProperty("x") + private Integer x; + + /** + * 机器人当前位置 y 坐标 + * AGV在地图中的Y轴坐标值 + */ + @JsonProperty("y") + private Integer y; + + /** + * 任务执行过程中消息上报的方法名 + * 默认使用方式: + * start : 任务开始 + * outbin : 走出储位 + * end : 任务完成 + */ + @JsonProperty("method") + private String method; + + /** + * 载具种类 + * 标识载具的分类信息 + */ + @JsonProperty("carrierCategory") + private String carrierCategory; + + /** + * 载具类型 + * 标识载具的具体型号或类型 + */ + @JsonProperty("carrierType") + private String carrierType; + + /** + * 载具编号 + * 当前任务关联的载具唯一标识 + */ + @JsonProperty("carrierCode") + private String carrierCode; + + /** + * 机器人种类 + * 标识机器人的分类信息 + */ + @JsonProperty("amrCategory") + private String amrCategory; + + /** + * 机器人类型 + * 标识机器人的具体型号或类型 + */ + @JsonProperty("amrType") + private String amrType; + + /** + * 机器人编号 + * 机器人的唯一标识编码 + */ + @JsonProperty("amrCode") + private String amrCode; + + /** + * 载具名称 + * 载具的显示名称或描述信息 + */ + @JsonProperty("carrierName") + private String carrierName; + + /** + * 载具角度 + * 载具当前的方向角度值 + */ + @JsonProperty("carrierDir") + private String carrierDir; + } + +} diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/hikAgv/request/submit/AngleInfo.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/hikAgv/request/submit/AngleInfo.java deleted file mode 100644 index 4046270..0000000 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/hikAgv/request/submit/AngleInfo.java +++ /dev/null @@ -1,28 +0,0 @@ -package org.cpte.modules.hikAgv.request.submit; - -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Data; - -/** - * 角度信息类 - * - * 用于描述AGV在工作站的角度信息配置,包括角度类型和具体角度值。 - */ -@Data -public class AngleInfo { - /** - * 角度类型 - * 可扩展枚举值,预制枚举值: - * ABSOLUTE: 绝对角度(与工作站的方向有关) - */ - @JsonProperty("type") - private String type; - - /** - * 角度值 - * 与 type 对应的具体角度值 - * 支持的角度值:[0, 90, 180, -90, 360] - */ - @JsonProperty("code") - private String code; -} diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/hikAgv/request/submit/CarrierInfo.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/hikAgv/request/submit/CarrierInfo.java deleted file mode 100644 index 696870f..0000000 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/hikAgv/request/submit/CarrierInfo.java +++ /dev/null @@ -1,34 +0,0 @@ -package org.cpte.modules.hikAgv.request.submit; - -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Data; - -/** - * 载具信息类 - * - * 用于描述AGV运输过程中承载货物的载具信息,包括载具类型、编码和层号等属性。 - */ -@Data -public class CarrierInfo { - - /** - * 载具类型 - * 描述载具的类型信息 - */ - @JsonProperty("carrierType") - private String carrierType; - - /** - * 载具编码 - * 载具的唯一标识编码 - */ - @JsonProperty("carrierCode") - private String carrierCode; - - /** - * 层号 - * 货物所在的层数,从0开始计数,从下往上编号 - */ - @JsonProperty("layer") - private String layer; -} diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/hikAgv/request/submit/Extra.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/hikAgv/request/submit/Extra.java deleted file mode 100644 index 01af057..0000000 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/hikAgv/request/submit/Extra.java +++ /dev/null @@ -1,30 +0,0 @@ -package org.cpte.modules.hikAgv.request.submit; - -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Data; - -import java.util.List; - -/** - * 扩展信息类 - * - * 用于承载AGV任务的扩展配置信息,包括角度信息和载具信息等可选配置。 - */ -@Data -public class Extra { - - /** - * 角度信息 - * 包含角度类型与角度值,用于指定AGV在工作站的角度配置 - */ - @JsonProperty("angleInfo") - private AngleInfo angleInfo; - - /** - * 载具信息集合 - * 包含载具编号、层号等信息,用于描述运输过程中的载具配置 - * 支持多个载具信息的配置 - */ - @JsonProperty("carrierInfo") - private List carrierInfo; -} diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/hikAgv/request/submit/SubmitRequest.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/hikAgv/request/submit/SubmitRequest.java deleted file mode 100644 index 2dfe910..0000000 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/hikAgv/request/submit/SubmitRequest.java +++ /dev/null @@ -1,104 +0,0 @@ -package org.cpte.modules.hikAgv.request.submit; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonPropertyOrder; -import lombok.Data; - -import java.util.List; - -/** - * AGV任务提交请求类 - *

- * 用于向AGV系统提交任务请求的DTO对象,包含任务执行所需的所有参数配置。 - * 支持配置任务类型、执行路径、优先级、截止时间、机器人资源等核心属性。 - */ - -@JsonPropertyOrder({ - "taskType", - "targetRoute", - "initPriority", - "deadline", - "robotType", - "robotCode", - "interrupt", - "robotTaskCode", - "groupCode", - "extra" -}) -@Data -public class SubmitRequest { - /** - * 任务类型 - * 指定AGV需要执行的任务类型 - */ - @JsonProperty("taskType") - private String taskType; - - /** - * 执行步骤集合 - * 任务执行的路径规划和步骤集合 - */ - @JsonProperty("targetRoute") - private List targetRoute; - - /** - * 优先级 - * 任务的初始优先级设置 - */ - @JsonProperty("initPriority") - private Integer initPriority; - - /** - * 截止时间 - * 任务的截止时间,采用ISO 8601格式(如:2021-04-04T12:23:55Z) - */ - @JsonProperty("deadline") - private String deadline; - - /** - * 机器人类型 - * 指定机器人的资源类型,固定枚举值 - * GROUPS: 机器人资源组编号 - * ROBOTS: 机器人编号 - */ - @JsonProperty("robotType") - private String robotType; - - /** - * 机器人编码 - * 与 robotType 匹配的资源类型唯一标识,支持单个和多个编号 - */ - @JsonProperty("robotCode") - private List robotCode; - - /** - * 能否打断 - * 任务执行过程中是否允许被打断 - * 1: 可打断 - 该货架中途有其他任务时,打断当前任务 - * 0: 不可打断 - 该货架中途有其他任务时,不能打断当前任务,默认不可打断 - */ - @JsonProperty("interrupt") - private Integer interrupt; - - /** - * 机器人任务编码 - * 外部任务唯一编号,如果为空则由系统生成并返回 - */ - @JsonProperty("robotTaskCode") - private String robotTaskCode; - - /** - * 任务组编码 - * 任务组编号,全局唯一标识 - */ - @JsonProperty("groupCode") - private String groupCode; - - /** - * 扩展字段 - * 自定义扩展字段,支持不同业务场景的扩展内容, - * 可用于业务流程执行或透传上报 - */ - @JsonProperty("extra") - private Extra extra; -} diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/hikAgv/request/submit/TargetRoute.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/hikAgv/request/submit/TargetRoute.java deleted file mode 100644 index 3751db2..0000000 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/hikAgv/request/submit/TargetRoute.java +++ /dev/null @@ -1,70 +0,0 @@ -package org.cpte.modules.hikAgv.request.submit; - -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Data; - -import java.util.List; - -/** - * 目标路径类 - * - * 用于描述AGV任务执行过程中的目标路径信息,包含目标位置、操作类型、资源配置等详细信息。 - */ -@Data -public class TargetRoute { - - /** - * 目标路径序列 - * 路径执行顺序编号,从0开始计数 - */ - @JsonProperty("seq") - private Integer seq; - - /** - * 目标类型 - * 指定目标位置的类型 - */ - @JsonProperty("type") - private String type; - - /** - * 目标编号 - * 目标位置的唯一标识编码 - */ - @JsonProperty("code") - private String code; - - /** - * 到达目标位置后的操作 - * 国标要求,非必要字段,对AMR动作无影响,支持可扩展枚举值 - * 预制枚举值: - * COLLECT: 取货 - * DELIVERY: 送货 - * ROTATE: 旋转 - */ - @JsonProperty("operation") - private String operation; - - /** - * 机器人类型 - * 指定机器人的资源类型,固定枚举值: - * GROUPS: 机器人资源组编号 - * ROBOTS: 机器人编号 - */ - @JsonProperty("robotType") - private String robotType; - - /** - * 机器人编码 - * 与 [robotType] 匹配的资源类型唯一标识 - */ - @JsonProperty("robotCode") - private List robotCode; - - /** - * 扩展字段 - * 自定义扩展字段,可随业务的差异而传入不同的扩展内容,在业务流程的执行中使用 - */ - @JsonProperty("extra") - private Extra extra; -} diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/hikAgv/request/taskReporter/Extra.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/hikAgv/request/taskReporter/Extra.java deleted file mode 100644 index d1685d0..0000000 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/hikAgv/request/taskReporter/Extra.java +++ /dev/null @@ -1,15 +0,0 @@ -package org.cpte.modules.hikAgv.request.taskReporter; - -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Data; - -@Data -public class Extra { - - @JsonProperty("async") - private String async; - - //节点信息 - @JsonProperty("values") - private Values values; -} diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/hikAgv/request/taskReporter/TaskReporterRequest.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/hikAgv/request/taskReporter/TaskReporterRequest.java deleted file mode 100644 index 33a7f3e..0000000 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/hikAgv/request/taskReporter/TaskReporterRequest.java +++ /dev/null @@ -1,36 +0,0 @@ -package org.cpte.modules.hikAgv.request.taskReporter; - -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Data; - -/** - * AGV任务状态上报请求类 - *

- * 用于AGV任务执行过程中向系统上报任务状态信息的DTO对象, - * 包含任务执行的关键节点信息和当前位置信息。 - */ -@Data -public class TaskReporterRequest { - - /** - * 机器人任务编码 - * 外部任务唯一编号,用于关联具体任务实例 - */ - @JsonProperty("robotTaskCode") - private String robotTaskCode; - - /** - * 当前执行任务的机器人唯一标识 - * 用于标识执行当前任务的具体AGV设备 - */ - @JsonProperty("singleRobotCode") - private String singleRobotCode; - - /** - * 自定义扩展字段 - * 包含任务执行过程中的详细状态信息和其他扩展数据 - */ - @JsonProperty("extra") - private Extra extra; - -} diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/hikAgv/request/taskReporter/Values.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/hikAgv/request/taskReporter/Values.java deleted file mode 100644 index d46841a..0000000 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/hikAgv/request/taskReporter/Values.java +++ /dev/null @@ -1,124 +0,0 @@ -package org.cpte.modules.hikAgv.request.taskReporter; - -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Data; - -/** - * AGV任务状态上报值对象 - *

- * 包含AGV任务执行过程中的详细状态信息,如位置坐标、载具信息、机器人信息等 - */ -@Data -public class Values { - - /** - * 地图编号 - * 标识当前AGV所在地图的唯一编码 - */ - @JsonProperty("mapCode") - private String mapCode; - - /** - * 存储类型 - * 枚举值: - * BIN - 仓位 - * SITE - 站点 - */ - @JsonProperty("slotCategory") - private String slotCategory; - - /** - * 当前站点编号 - * AGV当前所在的站点位置编码 - */ - @JsonProperty("slotCode") - private String slotCode; - - /** - * 站点别名 - * 1.走出储位:起点 - * 2.任务完成:目标点 - */ - @JsonProperty("slotName") - private String slotName; - - /** - * 机器人当前位置 x 坐标 - * AGV在地图中的X轴坐标值 - */ - @JsonProperty("x") - private Integer x; - - /** - * 机器人当前位置 y 坐标 - * AGV在地图中的Y轴坐标值 - */ - @JsonProperty("y") - private Integer y; - - /** - * 任务执行过程中消息上报的方法名 - * 默认使用方式: - * start : 任务开始 - * outbin : 走出储位 - * end : 任务完成 - */ - @JsonProperty("method") - private String method; - - /** - * 载具种类 - * 标识载具的分类信息 - */ - @JsonProperty("carrierCategory") - private String carrierCategory; - - /** - * 载具类型 - * 标识载具的具体型号或类型 - */ - @JsonProperty("carrierType") - private String carrierType; - - /** - * 载具编号 - * 当前任务关联的载具唯一标识 - */ - @JsonProperty("carrierCode") - private String carrierCode; - - /** - * 机器人种类 - * 标识机器人的分类信息 - */ - @JsonProperty("amrCategory") - private String amrCategory; - - /** - * 机器人类型 - * 标识机器人的具体型号或类型 - */ - @JsonProperty("amrType") - private String amrType; - - /** - * 机器人编号 - * 机器人的唯一标识编码 - */ - @JsonProperty("amrCode") - private String amrCode; - - /** - * 载具名称 - * 载具的显示名称或描述信息 - */ - @JsonProperty("carrierName") - private String carrierName; - - /** - * 载具角度 - * 载具当前的方向角度值 - */ - @JsonProperty("carrierDir") - private String carrierDir; -} diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/hikAgv/response/HikResult.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/hikAgv/response/HikResult.java index 57b81fc..19defa0 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/hikAgv/response/HikResult.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/hikAgv/response/HikResult.java @@ -1,7 +1,10 @@ package org.cpte.modules.hikAgv.response; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; + import java.io.Serializable; /** @@ -11,24 +14,38 @@ import java.io.Serializable; * @email cpteos@163.com * @date 2019年1月19日 */ +@JsonPropertyOrder({ + "code", + "message", + "data" +}) @Data public class HikResult implements Serializable { /** * 返回代码 */ + @JsonProperty("code") private String code = ""; /** * 返回处理消息 */ + @JsonProperty("message") private String message = ""; /** * 返回数据对象 data */ + @JsonProperty("data") private ResponesData data; + @Data + public static class ResponesData { + @JsonProperty("robotTaskCode") + private String robotTaskCode; + } + public static HikResult success(ResponesData data) { HikResult response = new HikResult(); response.code = "SUCCESS"; diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/hikAgv/response/ResponesData.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/hikAgv/response/ResponesData.java deleted file mode 100644 index 5b86466..0000000 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/hikAgv/response/ResponesData.java +++ /dev/null @@ -1,10 +0,0 @@ -package org.cpte.modules.hikAgv.response; - -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Data; - -@Data -public class ResponesData { - @JsonProperty("robotTaskCode") - private String robotTaskCode; -} diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/hikAgv/service/IHikAgvService.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/hikAgv/service/IHikAgvService.java index 725868d..f0234e8 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/hikAgv/service/IHikAgvService.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/hikAgv/service/IHikAgvService.java @@ -1,8 +1,8 @@ package org.cpte.modules.hikAgv.service; import org.cpte.modules.agvTask.entity.AgvTask; -import org.cpte.modules.hikAgv.request.submit.SubmitRequest; -import org.cpte.modules.hikAgv.request.taskReporter.TaskReporterRequest; +import org.cpte.modules.hikAgv.request.SubmitRequest; +import org.cpte.modules.hikAgv.request.TaskReporterRequest; public interface IHikAgvService { /** @@ -10,7 +10,7 @@ public interface IHikAgvService { * * @param agvTask 任务 */ - SubmitRequest generateAgvTaskJson(AgvTask agvTask); + String generateHikAgvTaskJson(AgvTask agvTask); /** * 下发任务 @@ -19,7 +19,7 @@ public interface IHikAgvService { * @param json 接口json * @param agvTask 任务 */ - void sendAgvTask(String url, String json, AgvTask agvTask); + void sendHikAgvTask(String url, String json, AgvTask agvTask); /** * 任务上报 diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/hikAgv/service/impl/IHikAgvServiceImpl.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/hikAgv/service/impl/IHikAgvServiceImpl.java index 722d66d..3ac8883 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/hikAgv/service/impl/IHikAgvServiceImpl.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/hikAgv/service/impl/IHikAgvServiceImpl.java @@ -8,8 +8,8 @@ import org.cpte.modules.agvTask.entity.AgvTask; import org.cpte.modules.agvTask.mapper.AgvTaskMapper; import org.cpte.modules.agvTask.service.IAgvTaskService; import org.cpte.modules.constant.enums.*; -import org.cpte.modules.hikAgv.request.submit.*; -import org.cpte.modules.hikAgv.request.taskReporter.TaskReporterRequest; +import org.cpte.modules.hikAgv.request.SubmitRequest; +import org.cpte.modules.hikAgv.request.TaskReporterRequest; import org.cpte.modules.hikAgv.service.IHikAgvService; import org.jeecg.modules.system.mapper.SysDictMapper; import org.springframework.beans.factory.annotation.Autowired; @@ -25,12 +25,21 @@ import java.util.*; @Slf4j public class IHikAgvServiceImpl implements IHikAgvService { - // 接口开关 + /** + * 接口开关 + */ final String open_flag = "OPEN"; - // 成功码 + /** + * 成功码 + */ final String success_code = "SUCCESS"; + /** + * 失败码 + */ + final String fail_code = "FAILED"; + @Autowired private SysDictMapper sysDictMapper; @@ -41,18 +50,18 @@ public class IHikAgvServiceImpl implements IHikAgvService { private IAgvTaskService iAgvTaskService; @Override - public SubmitRequest generateAgvTaskJson(AgvTask agvTask) { + public String generateHikAgvTaskJson(AgvTask agvTask) { SubmitRequest submitRequest = new SubmitRequest(); submitRequest.setTaskType("PF-LMR-COMMON"); // 设置起点路径 - TargetRoute srcTargetRoute = createSrcTargetRoute(agvTask); + SubmitRequest.TargetRoute srcTargetRoute = createSrcTargetRoute(agvTask); // 设置终点路径 - TargetRoute dstTargetRoute = createDstTargetRoute(agvTask); + SubmitRequest.TargetRoute dstTargetRoute = createDstTargetRoute(agvTask); submitRequest.setTargetRoute(Arrays.asList(srcTargetRoute, dstTargetRoute)); - submitRequest.setInitPriority(agvTask == null ? 99 : agvTask.getPriority()); + submitRequest.setInitPriority( agvTask.getPriority()); LocalDateTime now = LocalDateTime.now(ZoneOffset.UTC); String deadline = now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'")); @@ -61,23 +70,23 @@ public class IHikAgvServiceImpl implements IHikAgvService { submitRequest.setRobotType("GROUPS"); submitRequest.setRobotCode(Collections.singletonList("c3a1e7bb")); - Extra extra1 = new Extra(); - extra1.setCarrierInfo(createCarrierInfoList(agvTask == null ? "" : agvTask.getCarrierCode())); + SubmitRequest.Extra extra1 = new SubmitRequest.Extra(); + extra1.setCarrierInfo(createCarrierInfoList(agvTask.getCarrierCode())); submitRequest.setExtra(extra1); submitRequest.setInterrupt(0); - submitRequest.setRobotTaskCode(agvTask == null ? "" : agvTask.getId()); - submitRequest.setGroupCode(agvTask == null ? "" : agvTask.getId()); + submitRequest.setRobotTaskCode(agvTask.getId().toString()); + submitRequest.setGroupCode(agvTask.getId().toString()); - return submitRequest; + return JSON.toJSONString(submitRequest); } @Override - public void sendAgvTask(String url, String json, AgvTask agvTask) { + public void sendHikAgvTask(String url, String json, AgvTask agvTask) { log.info("请求报文:{}", json); // 检查接口开关, 未开启则返回 if (sysDictMapper.queryByDictCode(open_flag) == null) { - updateAgvTaskResponse(agvTask, "接口未开启", "FAILED"); + updateAgvTaskResponse(agvTask, "接口未开启", fail_code); return; } @@ -111,7 +120,7 @@ public class IHikAgvServiceImpl implements IHikAgvService { updateAgvTaskResponse(agvTask, message, code); } catch (Exception e) { // 记录异常到 AgvTask - updateAgvTaskResponse(agvTask, e.getMessage(), "FAILED"); + updateAgvTaskResponse(agvTask, e.getMessage(), fail_code); throw e; // 继续向上抛出异常供 Controller 层处理 } } @@ -120,6 +129,9 @@ public class IHikAgvServiceImpl implements IHikAgvService { @Transactional(rollbackFor = Exception.class) public void taskReporter(TaskReporterRequest taskReporterRequest) { AgvTask agvTask = agvTaskMapper.selectById(taskReporterRequest.getRobotTaskCode()); + if (agvTask == null) { + throw new RuntimeException("【" + taskReporterRequest.getRobotTaskCode() + "】任务不存在"); + } String status = taskReporterRequest.getExtra().getValues().getMethod(); switch (status) { case "outbin": @@ -161,19 +173,19 @@ public class IHikAgvServiceImpl implements IHikAgvService { /** * 重新发送 * - * @param agvTask + * @param agvTask 任务 */ private void handleResend(AgvTask agvTask) { - Long count = agvTaskMapper.isAGVTaskDuplicate(agvTask.getCarrierCode(), agvTask.getStartCode(), agvTask.getEndCode()); + Long count = agvTaskMapper.existsAGVTask(agvTask.getCarrierCode(),AgvVendorEnum.HIK.getValue()); if (count > 0) { throw new RuntimeException("任务已重新生成,请勿重复操作! "); } - AgvTask newAgvTask = iAgvTaskService.createAgvTask(AgvStatusEnum.CREATED.getValue(), agvTask.getCarrierCode(), agvTask.getStartCode(), agvTask.getEndCode(), agvTask.getTaskType(), agvTask.getType()); + AgvTask newAgvTask = iAgvTaskService.createAgvTask(AgvStatusEnum.CREATED.getValue(), agvTask.getCarrierCode(), agvTask.getStartCode(), agvTask.getEndCode(), null, agvTask.getType(),AgvVendorEnum.HIK.getValue()); switch (agvTask.getType()) { case "INBOUND": case "OUTBOUND": - //下发任务 - sendAgvTask("", "", newAgvTask); + //下发海康AGV任务 + sendHikAgvTask("", "", newAgvTask); break; default: throw new RuntimeException("任务类型不支持: " + agvTask.getType()); @@ -198,11 +210,11 @@ public class IHikAgvServiceImpl implements IHikAgvService { * @param agvTask 任务 * @return TargetRoute */ - private TargetRoute createSrcTargetRoute(AgvTask agvTask) { - TargetRoute srcTargetRoute = new TargetRoute(); + private SubmitRequest.TargetRoute createSrcTargetRoute(AgvTask agvTask) { + SubmitRequest.TargetRoute srcTargetRoute = new SubmitRequest.TargetRoute(); srcTargetRoute.setSeq(0); srcTargetRoute.setType("ZONE"); - srcTargetRoute.setCode(agvTask == null ? "" : agvTask.getStartCode()); + srcTargetRoute.setCode(agvTask.getStartCode()); srcTargetRoute.setOperation("COLLECT"); srcTargetRoute.setExtra(null); srcTargetRoute.setRobotType("GROUPS"); @@ -216,29 +228,29 @@ public class IHikAgvServiceImpl implements IHikAgvService { * @param agvTask 任务 * @return TargetRoute */ - private TargetRoute createDstTargetRoute(AgvTask agvTask) { - TargetRoute dstTargetRoute = new TargetRoute(); + private SubmitRequest.TargetRoute createDstTargetRoute(AgvTask agvTask) { + SubmitRequest.TargetRoute dstTargetRoute = new SubmitRequest.TargetRoute(); dstTargetRoute.setSeq(1); dstTargetRoute.setType("SITE"); - dstTargetRoute.setCode(agvTask == null ? "" : agvTask.getEndCode()); + dstTargetRoute.setCode(agvTask.getEndCode()); dstTargetRoute.setOperation("DELIVERY"); - Extra extra = new Extra(); + SubmitRequest.Extra extra = new SubmitRequest.Extra(); - AngleInfo angleInfo = new AngleInfo(); + SubmitRequest.AngleInfo angleInfo = new SubmitRequest.AngleInfo(); angleInfo.setType("RELATIVE"); angleInfo.setCode("90"); extra.setAngleInfo(angleInfo); - extra.setCarrierInfo(createCarrierInfoList(agvTask == null ? "" : agvTask.getCarrierCode())); + extra.setCarrierInfo(createCarrierInfoList(agvTask.getCarrierCode())); dstTargetRoute.setExtra(extra); return dstTargetRoute; } - private List createCarrierInfoList(String carrierCode) { - List carrierInfoList = new ArrayList<>(); - CarrierInfo cif = new CarrierInfo(); + private List createCarrierInfoList(String carrierCode) { + List carrierInfoList = new ArrayList<>(); + SubmitRequest.CarrierInfo cif = new SubmitRequest.CarrierInfo(); cif.setCarrierType("1"); // 建议替换为常量 cif.setCarrierCode(carrierCode); cif.setLayer("0"); diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventory/controller/InventoryController.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventory/controller/InventoryController.java new file mode 100644 index 0000000..32ab0bb --- /dev/null +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventory/controller/InventoryController.java @@ -0,0 +1,182 @@ +package org.cpte.modules.inventory.controller; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.jeecg.common.api.vo.Result; +import org.jeecg.common.system.query.QueryGenerator; +import org.jeecg.common.system.query.QueryRuleEnum; +import org.jeecg.common.util.oConvertUtils; +import org.cpte.modules.inventory.entity.Inventory; +import org.cpte.modules.inventory.service.IInventoryService; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.extern.slf4j.Slf4j; + +import org.jeecgframework.poi.excel.ExcelImportUtil; +import org.jeecgframework.poi.excel.def.NormalExcelConstants; +import org.jeecgframework.poi.excel.entity.ExportParams; +import org.jeecgframework.poi.excel.entity.ImportParams; +import org.jeecgframework.poi.excel.view.JeecgEntityExcelView; +import org.jeecg.common.system.base.controller.JeecgController; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; +import org.springframework.web.multipart.MultipartHttpServletRequest; +import org.springframework.web.servlet.ModelAndView; +import com.alibaba.fastjson.JSON; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.jeecg.common.aspect.annotation.AutoLog; +import org.apache.shiro.authz.annotation.RequiresPermissions; + /** + * @Description: 库存表 + * @author: cpte + * @Date: 2025-11-08 + * @Version: V1.0 + */ +@Tag(name="库存表") +@RestController +@RequestMapping("/inventory") +@Slf4j +public class InventoryController extends JeecgController { + @Autowired + private IInventoryService inventoryService; + + /** + * 分页列表查询 + * + * @param inventory + * @param pageNo + * @param pageSize + * @param req + * @return + */ + //@AutoLog(value = "库存表-分页列表查询") + @Operation(summary="库存表-分页列表查询") + @GetMapping(value = "/list") + public Result> queryPageList(Inventory inventory, + @RequestParam(name="pageNo", defaultValue="1") Integer pageNo, + @RequestParam(name="pageSize", defaultValue="10") Integer pageSize, + HttpServletRequest req) { + + + QueryWrapper queryWrapper = QueryGenerator.initQueryWrapper(inventory, req.getParameterMap()); + Page page = new Page(pageNo, pageSize); + IPage pageList = inventoryService.page(page, queryWrapper); + return Result.OK(pageList); + } + + /** + * 添加 + * + * @param inventory + * @return + */ + @AutoLog(value = "库存表-添加") + @Operation(summary="库存表-添加") + @RequiresPermissions("inventory:data_inventory:add") + @PostMapping(value = "/add") + public Result add(@RequestBody Inventory inventory) { + inventoryService.save(inventory); + + return Result.OK("添加成功!"); + } + + /** + * 编辑 + * + * @param inventory + * @return + */ + @AutoLog(value = "库存表-编辑") + @Operation(summary="库存表-编辑") + @RequiresPermissions("inventory:data_inventory:edit") + @RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST}) + public Result edit(@RequestBody Inventory inventory) { + inventoryService.updateById(inventory); + return Result.OK("编辑成功!"); + } + + /** + * 通过id删除 + * + * @param id + * @return + */ + @AutoLog(value = "库存表-通过id删除") + @Operation(summary="库存表-通过id删除") + @RequiresPermissions("inventory:data_inventory:delete") + @DeleteMapping(value = "/delete") + public Result delete(@RequestParam(name="id",required=true) String id) { + inventoryService.removeById(id); + return Result.OK("删除成功!"); + } + + /** + * 批量删除 + * + * @param ids + * @return + */ + @AutoLog(value = "库存表-批量删除") + @Operation(summary="库存表-批量删除") + @RequiresPermissions("inventory:data_inventory:deleteBatch") + @DeleteMapping(value = "/deleteBatch") + public Result deleteBatch(@RequestParam(name="ids",required=true) String ids) { + this.inventoryService.removeByIds(Arrays.asList(ids.split(","))); + return Result.OK("批量删除成功!"); + } + + /** + * 通过id查询 + * + * @param id + * @return + */ + //@AutoLog(value = "库存表-通过id查询") + @Operation(summary="库存表-通过id查询") + @GetMapping(value = "/queryById") + public Result queryById(@RequestParam(name="id",required=true) String id) { + Inventory inventory = inventoryService.getById(id); + if(inventory==null) { + return Result.error("未找到对应数据"); + } + return Result.OK(inventory); + } + + /** + * 导出excel + * + * @param request + * @param inventory + */ + @RequiresPermissions("inventory:data_inventory:exportXls") + @RequestMapping(value = "/exportXls") + public ModelAndView exportXls(HttpServletRequest request, Inventory inventory) { + return super.exportXls(request, inventory, Inventory.class, "库存表"); + } + + /** + * 通过excel导入数据 + * + * @param request + * @param response + * @return + */ + @RequiresPermissions("inventory:data_inventory:importExcel") + @RequestMapping(value = "/importExcel", method = RequestMethod.POST) + public Result importExcel(HttpServletRequest request, HttpServletResponse response) { + return super.importExcel(request, response, Inventory.class); + } + +} diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventory/entity/Inventory.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventory/entity/Inventory.java new file mode 100644 index 0000000..2af61a3 --- /dev/null +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventory/entity/Inventory.java @@ -0,0 +1,156 @@ +package org.cpte.modules.inventory.entity; + +import java.io.Serializable; +import java.io.UnsupportedEncodingException; +import java.util.Date; +import java.math.BigDecimal; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.annotation.TableLogic; +import lombok.*; +import org.jeecg.common.constant.ProvinceCityArea; +import org.jeecg.common.util.SpringContextUtils; +import com.fasterxml.jackson.annotation.JsonFormat; +import org.springframework.format.annotation.DateTimeFormat; +import org.jeecgframework.poi.excel.annotation.Excel; +import org.jeecg.common.aspect.annotation.Dict; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.experimental.Accessors; + +/** + * @Description: 库存表 + * @author: cpte + * @Date: 2025-11-08 + * @Version: V1.0 + */ +@Schema(description = "库存表") +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +@TableName("data_inventory") +public class Inventory implements Serializable { + private static final long serialVersionUID = 1L; + + /** + * ID + */ + @TableId(type = IdType.AUTO) + @Schema(description = "ID") + private java.lang.Integer id; + /** + * 物料ID + */ + @Excel(name = "物料ID", width = 15) + @Schema(description = "物料ID") + @Dict(dictTable = "base_item", dicCode = "id", dicText = "item_code") + private java.lang.String itemId; + /** + * 库位ID + */ + @Excel(name = "库位ID", width = 15) + @Schema(description = "库位ID") + @Dict(dictTable = "base_point", dicCode = "id", dicText = "point_code") + private java.lang.String pointId; + /** + * 容器ID + */ + @Excel(name = "容器ID", width = 15) + @Schema(description = "容器ID") + @Dict(dictTable = "base_stock", dicCode = "id", dicText = "stock_code") + private java.lang.String stockId; + /** + * 数量 + */ + @Excel(name = "数量", width = 15) + @Schema(description = "数量") + private java.math.BigDecimal quantity; + /** + * 分配数 + */ + @Excel(name = "分配数", width = 15) + @Schema(description = "分配数") + private java.math.BigDecimal queuedQty; + /** + * 外部仓库 + */ + @Excel(name = "外部仓库", width = 15) + @Schema(description = "外部仓库") + private java.lang.String whCode; + /** + * 批次号 + */ + @Excel(name = "批次号", width = 15) + @Schema(description = "批次号") + private java.lang.String propC1; + /** + * 序列号 + */ + @Excel(name = "序列号", width = 15) + @Schema(description = "序列号") + private java.lang.String propC2; + /** + * 外部库存状态 + */ + @Excel(name = "外部库存状态", width = 15) + @Schema(description = "外部库存状态") + private java.lang.String propC3; + /** + * 库存状态 + */ + @Excel(name = "库存状态", width = 15) + @Schema(description = "库存状态") + @Dict(dicCode = "inventory_status") + private java.lang.Integer status; + /** + * 生产日期 + */ + @Excel(name = "生产日期", width = 15, format = "yyyy-MM-dd") + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd") + @DateTimeFormat(pattern = "yyyy-MM-dd") + @Schema(description = "生产日期") + private java.util.Date propD1; + /** + * 描述 + */ + @Excel(name = "描述", width = 15) + @Schema(description = "描述") + private java.lang.String description; + /** + * 所属部门 + */ + @Schema(description = "所属部门") + private java.lang.String sysOrgCode; + /** + * 租户ID + */ + @Excel(name = "租户ID", width = 15) + @Schema(description = "租户ID") + private java.lang.Integer tenantId; + /** + * 创建人 + */ + @Schema(description = "创建人") + private java.lang.String createBy; + /** + * 创建日期 + */ + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Schema(description = "创建日期") + private java.util.Date createTime; + /** + * 更新人 + */ + @Schema(description = "更新人") + private java.lang.String updateBy; + /** + * 更新日期 + */ + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Schema(description = "更新日期") + private java.util.Date updateTime; +} diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventory/mapper/InventoryMapper.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventory/mapper/InventoryMapper.java new file mode 100644 index 0000000..9954987 --- /dev/null +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventory/mapper/InventoryMapper.java @@ -0,0 +1,26 @@ +package org.cpte.modules.inventory.mapper; + + +import org.apache.ibatis.annotations.Delete; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; +import org.cpte.modules.inventory.entity.Inventory; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + * @Description: 库存表 + * @author: cpte + * @Date: 2025-11-08 + * @Version: V1.0 + */ +public interface InventoryMapper extends BaseMapper { + + /** + * 根据容器查询库存数据 + * + * @param stockId 容器 + * @return 库存数据 + */ + @Select("select * from data_inventory where stock_id = #{stockId} ") + Inventory selectByStockId(@Param("stockId") String stockId); +} diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventory/mapper/xml/InventoryMapper.xml b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventory/mapper/xml/InventoryMapper.xml new file mode 100644 index 0000000..36265d3 --- /dev/null +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventory/mapper/xml/InventoryMapper.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventory/service/IInventoryService.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventory/service/IInventoryService.java new file mode 100644 index 0000000..db49287 --- /dev/null +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventory/service/IInventoryService.java @@ -0,0 +1,14 @@ +package org.cpte.modules.inventory.service; + +import org.cpte.modules.inventory.entity.Inventory; +import com.baomidou.mybatisplus.extension.service.IService; + +/** + * @Description: 库存表 + * @author: cpte + * @Date: 2025-11-08 + * @Version: V1.0 + */ +public interface IInventoryService extends IService { + +} diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventory/service/impl/InventoryServiceImpl.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventory/service/impl/InventoryServiceImpl.java new file mode 100644 index 0000000..9568e50 --- /dev/null +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/inventory/service/impl/InventoryServiceImpl.java @@ -0,0 +1,19 @@ +package org.cpte.modules.inventory.service.impl; + +import org.cpte.modules.inventory.entity.Inventory; +import org.cpte.modules.inventory.mapper.InventoryMapper; +import org.cpte.modules.inventory.service.IInventoryService; +import org.springframework.stereotype.Service; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; + +/** + * @Description: 库存表 + * @author: cpte + * @Date: 2025-11-08 + * @Version: V1.0 + */ +@Service +public class InventoryServiceImpl extends ServiceImpl implements IInventoryService { + +} diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/quartz/job/AgvTaskJob.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/quartz/job/HikAgvJob.java similarity index 64% rename from cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/quartz/job/AgvTaskJob.java rename to cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/quartz/job/HikAgvJob.java index ec58100..ec96925 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/quartz/job/AgvTaskJob.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/quartz/job/HikAgvJob.java @@ -1,12 +1,11 @@ package org.cpte.modules.quartz.job; -import com.alibaba.fastjson.JSON; import lombok.extern.slf4j.Slf4j; import org.cpte.modules.agvTask.entity.AgvTask; -import org.cpte.modules.agvTask.service.IAgvTaskService; +import org.cpte.modules.agvTask.mapper.AgvTaskMapper; import org.cpte.modules.constant.enums.AgvStatusEnum; +import org.cpte.modules.constant.enums.AgvVendorEnum; import org.cpte.modules.hikAgv.service.IHikAgvService; -import org.jeecg.common.util.DateUtils; import org.quartz.Job; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; @@ -15,9 +14,9 @@ import org.springframework.beans.factory.annotation.Autowired; import java.util.List; @Slf4j -public class AgvTaskJob implements Job { +public class HikAgvJob implements Job { @Autowired - private IAgvTaskService agvTaskService; + private AgvTaskMapper agvTaskMapper; @Autowired private IHikAgvService hikAgvService; @@ -25,11 +24,15 @@ public class AgvTaskJob implements Job { @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { // 查询待执行任务 - List agvTaskList = agvTaskService.queryAgvTaskList(AgvStatusEnum.CREATED.getValue()); + List agvTaskList = agvTaskMapper.queryAgvTaskList(AgvStatusEnum.CREATED.getValue(), AgvVendorEnum.HIK.getValue()); String taskSubmitUrl = "http://localhost:8000/cpte-wms/rcs/rtas/api/robot/controller/task/submit"; for (AgvTask agvTask : agvTaskList) { try { - hikAgvService.sendAgvTask(taskSubmitUrl, JSON.toJSONString(hikAgvService.generateAgvTaskJson(agvTask)), agvTask); + hikAgvService.sendHikAgvTask( + taskSubmitUrl, + hikAgvService.generateHikAgvTaskJson(agvTask), + agvTask + ); } catch (Exception e) { log.error("发送AGV任务失败,任务ID: {}", agvTask.getId(), e); } diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/quartz/job/TesAgvJob.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/quartz/job/TesAgvJob.java new file mode 100644 index 0000000..fcdb8d4 --- /dev/null +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/quartz/job/TesAgvJob.java @@ -0,0 +1,42 @@ +package org.cpte.modules.quartz.job; + +import lombok.extern.slf4j.Slf4j; +import org.cpte.modules.agvTask.entity.AgvTask; +import org.cpte.modules.agvTask.mapper.AgvTaskMapper; +import org.cpte.modules.constant.enums.AgvStatusEnum; +import org.cpte.modules.constant.enums.AgvVendorEnum; +import org.cpte.modules.hikAgv.service.IHikAgvService; +import org.cpte.modules.tesAgv.service.ITesAgvService; +import org.quartz.Job; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.List; + +@Slf4j +public class TesAgvJob implements Job { + @Autowired + private AgvTaskMapper agvTaskMapper; + + @Autowired + private ITesAgvService tesAgvService; + + @Override + public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { + // 查询待执行任务 + List agvTaskList = agvTaskMapper.queryAgvTaskList(AgvStatusEnum.CREATED.getValue(), AgvVendorEnum.TES.getValue()); + String taskSubmitUrl = "http://localhost:8000/cpte-wms/tes/apiv2/newMovePodTask"; + for (AgvTask agvTask : agvTaskList) { + try { + tesAgvService.sendTesAgvTask( + taskSubmitUrl, + tesAgvService.generateTesAgvTaskJson(agvTask), + agvTask + ); + } catch (Exception e) { + log.error("发送AGV任务失败,任务ID: {}", agvTask.getId(), e); + } + } + } +} diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/entity/Asn.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/entity/Asn.java index 3329db9..0f483ac 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/entity/Asn.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/entity/Asn.java @@ -82,11 +82,12 @@ public class Asn implements Serializable { private java.lang.Integer orderType; /** * 订单状态 + * 1.已创建;2.部分收货;3.收货完成;4.已取消 */ @Excel(name = "订单状态", width = 15) @Schema(description = "订单状态") @Dict(dicCode = "asn_status") - private java.lang.String status; + private java.lang.Integer status; /** * 需求数量 */ diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/entity/AsnDetail.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/entity/AsnDetail.java index 90c51d7..4b57409 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/entity/AsnDetail.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/entity/AsnDetail.java @@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.annotation.*; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.NoArgsConstructor; +import org.jeecg.common.aspect.annotation.Dict; import org.jeecg.common.constant.ProvinceCityArea; import org.jeecg.common.util.SpringContextUtils; import lombok.Data; @@ -100,6 +101,14 @@ public class AsnDetail implements Serializable { @Excel(name = "收货数量", width = 15) @Schema(description = "收货数量") private java.math.BigDecimal receivedQty; + /** + * 状态 + * 1.已创建;2.部分收货;3.收货完成;4.已取消 + */ + @Excel(name = "状态", width = 15) + @Schema(description = "状态") + @Dict(dicCode = "asn_status") + private java.lang.Integer status; /** * 批次号 */ @@ -185,4 +194,7 @@ public class AsnDetail implements Serializable { @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") @Schema(description = "更新日期") private java.util.Date updateTime; + + @Version + private Integer updateCount; } diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/entity/ReceiveRecord.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/entity/ReceiveRecord.java new file mode 100644 index 0000000..733026a --- /dev/null +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/entity/ReceiveRecord.java @@ -0,0 +1,118 @@ +package org.cpte.modules.receive.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.format.annotation.DateTimeFormat; + +import java.io.Serializable; + +@Schema(description = "入库记录") +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +@TableName("data_receive_record") +public class ReceiveRecord implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId(type = IdType.ASSIGN_ID) + @Schema(description = "主键") + private java.lang.String id; + /** + * 入库明细 + */ + @Schema(description = "入库明细") + private java.lang.String asnDetailId; + /** + * 容器 + */ + @Schema(description = "容器") + private java.lang.String stockId; + /** + * 库位 + */ + @Schema(description = "库位") + private java.lang.String pointId; + /** + * 物料 + */ + @Schema(description = "物料") + private java.lang.String itemId; + /** + * 收货数量 + */ + @Schema(description = "收货数量") + private java.math.BigDecimal receivedQty; + /** + * 批次号 + */ + @Schema(description = "批次号") + private java.lang.String propC1; + /** + * 序列号 + */ + @Schema(description = "序列号") + private java.lang.String propC2; + /** + * 库存状态 + */ + @Schema(description = "库存状态") + private java.lang.String propC3; + /** + * 生产日期 + */ + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd") + @DateTimeFormat(pattern = "yyyy-MM-dd") + @Schema(description = "生产日期") + private java.util.Date propD1; + /** + * 备注 + */ + @Schema(description = "备注") + private java.lang.String description; + /** + * 仓库ID + */ + @Schema(description = "仓库ID") + private java.lang.Integer tenantId; + /** + * 所属部门 + */ + @Schema(description = "所属部门") + private java.lang.String sysOrgCode; + /** + * 创建人 + */ + @Schema(description = "创建人") + private java.lang.String createBy; + /** + * 创建日期 + */ + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Schema(description = "创建日期") + private java.util.Date createTime; + /** + * 更新人 + */ + @Schema(description = "更新人") + private java.lang.String updateBy; + /** + * 更新日期 + */ + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Schema(description = "更新日期") + private java.util.Date updateTime; +} diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/mapper/AsnDetailMapper.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/mapper/AsnDetailMapper.java index ed94818..be98659 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/mapper/AsnDetailMapper.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/mapper/AsnDetailMapper.java @@ -34,15 +34,12 @@ public interface AsnDetailMapper extends BaseMapper { /** - * 根据容器查询入库信息 + * 通过容器ID和明细状态查询入库明细 * - * @param stockCode 容器编号 + * @param stockId 库存id + * @param status 状态 * @return AsnDetail */ - @Select("select * from data_asn_detail " + - "join data_asn on data_asn.id=data_asn_detail.asn_id " + - "join base_stock on data_asn_detail.stock_id=base_stock.id " + - "where base_stock.stock_code = #{stockCode} " + - "and data_asn.status='CREATED' ") - AsnDetail queryByStockCode(@Param("stockCode") String stockCode); + @Select("select * from data_asn_detail where stock_id = #{stockId} and status = #{status} ") + AsnDetail queryByStockCode(@Param("stockId") String stockId, @Param("status") Integer status); } diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/mapper/ReceiveRecordMapper.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/mapper/ReceiveRecordMapper.java new file mode 100644 index 0000000..843b63c --- /dev/null +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/mapper/ReceiveRecordMapper.java @@ -0,0 +1,7 @@ +package org.cpte.modules.receive.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.cpte.modules.receive.entity.ReceiveRecord; + +public interface ReceiveRecordMapper extends BaseMapper { +} diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/mapper/xml/ReceiveRecordMapper.xml b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/mapper/xml/ReceiveRecordMapper.xml new file mode 100644 index 0000000..c062957 --- /dev/null +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/mapper/xml/ReceiveRecordMapper.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/service/IAsnService.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/service/IAsnService.java index 71d6bc9..04466b2 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/service/IAsnService.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/service/IAsnService.java @@ -4,6 +4,7 @@ import org.cpte.modules.receive.entity.AsnDetail; import org.cpte.modules.receive.entity.Asn; import com.baomidou.mybatisplus.extension.service.IService; import java.io.Serializable; +import java.math.BigDecimal; import java.util.Collection; import java.util.List; @@ -45,5 +46,11 @@ public interface IAsnService extends IService { */ public void delBatchMain (Collection idList); + /** + * 收货操作 + * + * @param stockCode 容器 + */ + void receiveGoods(String stockCode); } diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/service/impl/AsnServiceImpl.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/service/impl/AsnServiceImpl.java index d8304fe..b8b99fb 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/service/impl/AsnServiceImpl.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/receive/service/impl/AsnServiceImpl.java @@ -1,12 +1,25 @@ package org.cpte.modules.receive.service.impl; +import lombok.extern.slf4j.Slf4j; +import org.cpte.modules.base.entity.Point; +import org.cpte.modules.base.entity.Stock; +import org.cpte.modules.base.mapper.PointMapper; +import org.cpte.modules.base.mapper.StockMapper; +import org.cpte.modules.base.service.IStockService; import org.cpte.modules.constant.enums.AsnStatusEnum; +import org.cpte.modules.constant.enums.CommonStatusEnum; +import org.cpte.modules.constant.enums.InventoryStatusEnum; +import org.cpte.modules.inventory.entity.Inventory; +import org.cpte.modules.inventory.mapper.InventoryMapper; import org.cpte.modules.receive.entity.Asn; import org.cpte.modules.receive.entity.AsnDetail; +import org.cpte.modules.receive.entity.ReceiveRecord; import org.cpte.modules.receive.mapper.AsnDetailMapper; import org.cpte.modules.receive.mapper.AsnMapper; +import org.cpte.modules.receive.mapper.ReceiveRecordMapper; import org.cpte.modules.receive.service.IAsnService; import org.cpte.modules.utils.BigDecimalUtil; +import org.jeecg.common.constant.CommonSendStatus; import org.springframework.stereotype.Service; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import org.springframework.beans.factory.annotation.Autowired; @@ -15,6 +28,7 @@ import org.springframework.transaction.annotation.Transactional; import java.io.Serializable; import java.math.BigDecimal; import java.util.ArrayList; +import java.util.Date; import java.util.List; import java.util.Collection; import java.util.concurrent.atomic.AtomicInteger; @@ -26,12 +40,23 @@ import java.util.concurrent.atomic.AtomicInteger; * @Version: V1.0 */ @Service +@Slf4j public class AsnServiceImpl extends ServiceImpl implements IAsnService { + @Autowired + private StockMapper stockMapper; + @Autowired + private PointMapper pointMapper; @Autowired private AsnMapper asnMapper; @Autowired private AsnDetailMapper asnDetailMapper; + @Autowired + private ReceiveRecordMapper receiveRecordMapper; + @Autowired + private InventoryMapper inventoryMapper; + @Autowired + private IStockService iStockService; @Override @Transactional(rollbackFor = Exception.class) @@ -46,7 +71,6 @@ public class AsnServiceImpl extends ServiceImpl implements IAsnS entity.setAsnId(asn.getId()); asnDetailMapper.insert(entity); } - } //刷新入库单 refreshAsn(asn, asnDetailList); @@ -65,7 +89,7 @@ public class AsnServiceImpl extends ServiceImpl implements IAsnS BigDecimal receivedQty = asnDetails.stream().map(AsnDetail::getReceivedQty).reduce(BigDecimal.ZERO, BigDecimal::add); //当前状态 - String status = asn.getStatus(); + Integer status = asn.getStatus(); if (orderQty.compareTo(BigDecimal.ZERO) >= 0 && receivedQty.compareTo(BigDecimal.ZERO) == 0) { status = AsnStatusEnum.CREATED.getValue(); @@ -84,22 +108,21 @@ public class AsnServiceImpl extends ServiceImpl implements IAsnS @Override @Transactional(rollbackFor = Exception.class) public void updateMain(Asn asn, List asnDetailList) { + // 直接更新主表 asnMapper.updateById(asn); - //1.先删除子表数据 - asnDetailMapper.deleteByMainId(asn.getId()); - - //2.子表数据重新插入 + // 更新明细表 - 只更新传入的明细数据 if (asnDetailList != null && !asnDetailList.isEmpty()) { - AtomicInteger lineNoCounter = new AtomicInteger(1); for (AsnDetail entity : asnDetailList) { - if (entity.getLineNo() == null || entity.getLineNo() == 0) { - entity.setLineNo(lineNoCounter.getAndIncrement()); - } entity.setAsnId(asn.getId()); - asnDetailMapper.insert(entity); + // 直接更新,而不是删除后重新插入 + if (entity.getId() != null) { + asnDetailMapper.updateById(entity); + } } } + + // 刷新入库单状态 refreshAsn(asn, asnDetailList); } @@ -107,6 +130,10 @@ public class AsnServiceImpl extends ServiceImpl implements IAsnS @Override @Transactional(rollbackFor = Exception.class) public void delMain(String id) { + Asn asn = this.getById(id); + if(!AsnStatusEnum.CREATED.getValue().equals(asn.getStatus())){ + throw new RuntimeException("操作失败:【" + asn.getOrderNo() + "】入库单,非创建状态不允许删除"); + } asnDetailMapper.deleteByMainId(id); asnMapper.deleteById(id); } @@ -114,10 +141,119 @@ public class AsnServiceImpl extends ServiceImpl implements IAsnS @Override @Transactional(rollbackFor = Exception.class) public void delBatchMain(Collection idList) { + List orderNoList = new ArrayList<>(); for (Serializable id : idList) { + Asn asn = this.getById(id); + if(!AsnStatusEnum.CREATED.getValue().equals(asn.getStatus())){ + orderNoList.add(asn.getOrderNo()); + continue; + } asnDetailMapper.deleteByMainId(id.toString()); asnMapper.deleteById(id); } + if(!orderNoList.isEmpty()){ + throw new RuntimeException("操作失败:【" + orderNoList + "】入库单,非创建状态不允许删除"); + } } + @Override + @Transactional(rollbackFor = Exception.class) + public void receiveGoods(String stockCode) { + //验证容器 + Stock stock = iStockService.validateStock(stockCode); + AsnDetail asnDetail = asnDetailMapper.queryByStockCode(stock.getId(), AsnStatusEnum.CREATED.getValue()); + if (asnDetail == null) { + throw new RuntimeException("【" + stockCode + "】托盘,无入库信息"); + } + + Asn asn = this.getById(asnDetail.getAsnId()); + + //更新收货数量 + BigDecimal receivedQty = BigDecimalUtil.add(asnDetail.getReceivedQty(), asnDetail.getOrderQty(), 0); + asnDetail.setReceivedQty(receivedQty); + + //更新明细状态 + if (receivedQty.compareTo(asnDetail.getOrderQty()) >= 0) { + asnDetail.setStatus(AsnStatusEnum.RECEIVED.getValue()); + } else { + asnDetail.setStatus(AsnStatusEnum.RECEIVING.getValue()); + } + asnDetailMapper.updateById(asnDetail); + + // 根据容器ID查询库存 + Inventory existingInventory = inventoryMapper.selectByStockId(asnDetail.getStockId()); + if (existingInventory != null) { + // 更新库存 + existingInventory.setQuantity(receivedQty); + existingInventory.setQueuedQty(BigDecimal.ZERO); + existingInventory.setStatus(InventoryStatusEnum.AVAILABLE.getValue()); + inventoryMapper.updateById(existingInventory); + } else { + //生成新库存 + Inventory inventory = Inventory.builder() + .itemId(asnDetail.getItemId()) + .pointId(asnDetail.getPointId()) + .stockId(asnDetail.getStockId()) + .quantity(receivedQty) + .queuedQty(BigDecimal.ZERO) + .whCode(asn.getWhCode()) + .propC1(asnDetail.getPropC1()) + .propC2(asnDetail.getPropC2()) + .propC3(asnDetail.getPropC3()) + .status(InventoryStatusEnum.AVAILABLE.getValue()) + .propD1(asnDetail.getPropD1()) + .description(asnDetail.getDescription()) + .tenantId(asnDetail.getTenantId()) + .sysOrgCode(asnDetail.getSysOrgCode()) + .createBy(asnDetail.getCreateBy()) + .createTime(new Date()) + .build(); + inventoryMapper.insert(inventory); + } + + //更新容器状态和位置 + updateStockPoint(asnDetail.getStockId(), asnDetail.getPointId()); + + //更新入库单 + refreshAsn(asn, asnDetailMapper.selectByMainId(asn.getId())); + + //创建入库记录 + ReceiveRecord receiveRecord = ReceiveRecord.builder() + .asnDetailId(asnDetail.getId()) + .stockId(asnDetail.getStockId()) + .pointId(asnDetail.getPointId()) + .itemId(asnDetail.getItemId()) + .receivedQty(receivedQty) + .propC1(asnDetail.getPropC1()) + .propC2(asnDetail.getPropC2()) + .propC3(asnDetail.getPropC3()) + .propD1(asnDetail.getPropD1()) + .description(asnDetail.getDescription()) + .tenantId(asnDetail.getTenantId()) + .sysOrgCode(asnDetail.getSysOrgCode()) + .createBy(asnDetail.getCreateBy()) + .createTime(new Date()) + .build(); + receiveRecordMapper.insert(receiveRecord); + + //TODO: 在此处添加库存操作日志 + } + + + /** + * 更新容器位置和状态 + */ + private void updateStockPoint(String stockId, String pointId) { + Stock stock = stockMapper.selectById(stockId); + stock.setPointId(pointId); + stock.setStatus(CommonStatusEnum.USED.getValue()); + stockMapper.updateById(stock); + + // 更新库位状态为占用 + Point point = pointMapper.selectById(pointId); + point.setStatus(CommonStatusEnum.USED.getValue()); // 占用状态 + pointMapper.updateById(point); + } + + } diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/saiWms/controller/InBoundController.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/saiWms/controller/SaiWmsController.java similarity index 73% rename from cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/saiWms/controller/InBoundController.java rename to cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/saiWms/controller/SaiWmsController.java index ae8fbbf..1b50f18 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/saiWms/controller/InBoundController.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/saiWms/controller/SaiWmsController.java @@ -3,13 +3,9 @@ package org.cpte.modules.saiWms.controller; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; -import kotlin.jvm.Volatile; import lombok.extern.slf4j.Slf4j; -import org.apache.shiro.authz.annotation.RequiresPermissions; -import org.cpte.modules.base.entity.Area; -import org.cpte.modules.base.service.IAreaService; -import org.cpte.modules.saiWms.request.inbound.InboundRequest; -import org.cpte.modules.saiWms.service.IInBoundService; +import org.cpte.modules.saiWms.request.InboundRequest; +import org.cpte.modules.saiWms.service.ISaiWmsService; import org.jeecg.common.api.vo.Result; import org.jeecg.common.aspect.annotation.AutoLog; import org.jeecg.config.shiro.IgnoreAuth; @@ -23,10 +19,10 @@ import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/saiWms/inBound") @Slf4j -public class InBoundController { +public class SaiWmsController { @Autowired - private IInBoundService iInBoundService; + private ISaiWmsService iInBoundService; /** * 入库任务下发 @@ -39,6 +35,6 @@ public class InBoundController { @IgnoreAuth public Result inBoundTask(@RequestBody @Valid InboundRequest inboundRequest) { iInBoundService.inBoundTask(inboundRequest); - return Result.OK("添加成功!"); + return Result.OK("下发成功!"); } } diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/saiWms/request/inbound/InboundRequest.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/saiWms/request/InboundRequest.java similarity index 53% rename from cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/saiWms/request/inbound/InboundRequest.java rename to cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/saiWms/request/InboundRequest.java index b512741..716cd37 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/saiWms/request/inbound/InboundRequest.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/saiWms/request/InboundRequest.java @@ -1,4 +1,4 @@ -package org.cpte.modules.saiWms.request.inbound; +package org.cpte.modules.saiWms.request; import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.Valid; @@ -6,6 +6,7 @@ import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import lombok.Data; +import java.math.BigDecimal; import java.util.List; /** @@ -47,4 +48,49 @@ public class InboundRequest { @JsonProperty("details") @Valid private List details; + + @Data + public static class InboundDetail { + // 行号 + @NotBlank(message = "行号不能为空") + @JsonProperty("LineNo") + private String lineNo; + + // 物料 + @NotBlank(message = "物料不能为空") + @JsonProperty("Item") + private String item; + + // 单位 + @NotBlank(message = "单位不能为空") + @JsonProperty("Unit") + private String unit; + + // 数量 + @NotNull(message = "数量不能为空") + @JsonProperty("Qty") + private BigDecimal qty; + + // 托盘号 + @NotNull(message = "托盘号不能为空") + @JsonProperty("Lpn") + private String lpn; + + // 项目号 + @JsonProperty("Project") + private String project; + + // 任务号 + @JsonProperty("TaskNo") + private String taskNo; + + // 批次号 + @JsonProperty("LotAtt04") + private String lotAtt04; + + // 库存状态 + @JsonProperty("LotAtt010") + private String lotAtt010; + } + } diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/saiWms/request/inbound/InboundDetail.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/saiWms/request/inbound/InboundDetail.java deleted file mode 100644 index 78f41ab..0000000 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/saiWms/request/inbound/InboundDetail.java +++ /dev/null @@ -1,52 +0,0 @@ -package org.cpte.modules.saiWms.request.inbound; - -import com.fasterxml.jackson.annotation.JsonProperty; -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotNull; -import lombok.Data; - -import java.math.BigDecimal; - -@Data -public class InboundDetail { - // 行号 - @NotBlank(message = "行号不能为空") - @JsonProperty("LineNo") - private String lineNo; - - // 物料 - @NotBlank(message = "物料不能为空") - @JsonProperty("Item") - private String item; - - // 单位 - @NotBlank(message = "单位不能为空") - @JsonProperty("Unit") - private String unit; - - // 数量 - @NotNull(message = "数量不能为空") - @JsonProperty("Qty") - private BigDecimal qty; - - // 托盘号 - @NotNull(message = "托盘号不能为空") - @JsonProperty("Lpn") - private String lpn; - - // 项目号 - @JsonProperty("Project") - private String project; - - // 任务号 - @JsonProperty("TaskNo") - private String taskNo; - - // 批次号 - @JsonProperty("LotAtt04") - private String lotAtt04; - - // 库存状态 - @JsonProperty("LotAtt010") - private String lotAtt010; -} diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/saiWms/service/IInBoundService.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/saiWms/service/ISaiWmsService.java similarity index 65% rename from cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/saiWms/service/IInBoundService.java rename to cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/saiWms/service/ISaiWmsService.java index bd0627c..c9074f8 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/saiWms/service/IInBoundService.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/saiWms/service/ISaiWmsService.java @@ -1,8 +1,8 @@ package org.cpte.modules.saiWms.service; -import org.cpte.modules.saiWms.request.inbound.InboundRequest; +import org.cpte.modules.saiWms.request.InboundRequest; -public interface IInBoundService { +public interface ISaiWmsService { /** * 入库任务下发 * diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/saiWms/service/impl/IInBoundServiceImpl.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/saiWms/service/impl/ISaiWmsServiceImpl.java similarity index 85% rename from cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/saiWms/service/impl/IInBoundServiceImpl.java rename to cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/saiWms/service/impl/ISaiWmsServiceImpl.java index 46994bf..9ae8364 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/saiWms/service/impl/IInBoundServiceImpl.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/saiWms/service/impl/ISaiWmsServiceImpl.java @@ -1,13 +1,10 @@ package org.cpte.modules.saiWms.service.impl; import lombok.extern.slf4j.Slf4j; -import org.cpte.modules.agvTask.entity.AgvTask; import org.cpte.modules.agvTask.service.IAgvTaskService; import org.cpte.modules.base.entity.Item; import org.cpte.modules.base.entity.Point; import org.cpte.modules.base.entity.Stock; -import org.cpte.modules.base.mapper.ItemMapper; -import org.cpte.modules.base.mapper.StockMapper; import org.cpte.modules.base.service.IItemService; import org.cpte.modules.base.service.IPointService; import org.cpte.modules.base.service.IStockService; @@ -16,23 +13,20 @@ import org.cpte.modules.receive.entity.Asn; import org.cpte.modules.receive.entity.AsnDetail; import org.cpte.modules.receive.mapper.AsnMapper; import org.cpte.modules.receive.service.IAsnService; -import org.cpte.modules.saiWms.request.inbound.InboundDetail; -import org.cpte.modules.saiWms.request.inbound.InboundRequest; -import org.cpte.modules.saiWms.service.IInBoundService; +import org.cpte.modules.saiWms.request.InboundRequest; +import org.cpte.modules.saiWms.service.ISaiWmsService; import org.cpte.modules.utils.CodeGeneratorUtil; import org.jeecg.common.config.TenantContext; import org.jeecg.common.util.oConvertUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; import java.math.BigDecimal; import java.util.*; -import java.util.stream.Collectors; @Service @Slf4j -public class IInBoundServiceImpl implements IInBoundService { +public class ISaiWmsServiceImpl implements ISaiWmsService { @Autowired private AsnMapper asnMapper; @@ -66,7 +60,7 @@ public class IInBoundServiceImpl implements IInBoundService { } // 获取唯一的明细 - InboundDetail detail = inboundRequest.getDetails().get(0); + InboundRequest.InboundDetail detail = inboundRequest.getDetails().get(0); // 验证基础数据 String srcPointCode = inboundRequest.getLocationFrom(); @@ -92,7 +86,7 @@ public class IInBoundServiceImpl implements IInBoundService { asnService.saveMain(createAsn, Collections.singletonList(asnDetail)); //创建AGV任务 - iAgvTaskService.createAgvTask(AgvStatusEnum.CREATED.getValue(), stock.getStockCode(), srcPoint.getPointCode(), dstPoint.getPointCode(), "PF-LMR-COMMON", BusinessTypeEnum.INBOUND.getValue()); + iAgvTaskService.createAgvTask(AgvStatusEnum.CREATED.getValue(), stock.getStockCode(), srcPoint.getPointCode(), dstPoint.getPointCode(), null, BusinessTypeEnum.INBOUND.getValue(),AgvVendorEnum.HIK.getValue()); } /** @@ -118,7 +112,7 @@ public class IInBoundServiceImpl implements IInBoundService { /** * 构建入库明细 */ - private AsnDetail buildAsnDetail(InboundDetail detail, Point srcPoint, Item item, Stock stock) { + private AsnDetail buildAsnDetail(InboundRequest.InboundDetail detail, Point srcPoint, Item item, Stock stock) { // 由于明细只有一条,直接构建单个明细对象 return AsnDetail.builder() .lineNo(Integer.parseInt(detail.getLineNo())) @@ -127,6 +121,7 @@ public class IInBoundServiceImpl implements IInBoundService { .orderQty(detail.getQty()) .stockId(stock.getId()) .pointId(srcPoint.getId()) + .status(AsnStatusEnum.CREATED.getValue()) .project(detail.getProject()) .taskNo(detail.getTaskNo()) .propC1(detail.getLotAtt04()) diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/tesAgv/controller/TesAgvController.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/tesAgv/controller/TesAgvController.java new file mode 100644 index 0000000..e7aa3d3 --- /dev/null +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/tesAgv/controller/TesAgvController.java @@ -0,0 +1,64 @@ +package org.cpte.modules.tesAgv.controller; + +import com.alibaba.fastjson.JSON; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.cpte.modules.tesAgv.request.NewMovePodTaskRequest; +import org.cpte.modules.tesAgv.request.TesCallbackRequest; +import org.cpte.modules.tesAgv.response.TesResult; +import org.cpte.modules.tesAgv.service.ITesAgvService; +import org.jeecg.common.api.vo.Result; +import org.jeecg.common.aspect.annotation.AutoLog; +import org.jeecg.config.shiro.IgnoreAuth; +import org.springframework.beans.factory.annotation.Autowired; +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; + +@Tag(name = "TesAGV") +@RestController +@RequestMapping("/tes/apiv2") +@Slf4j +public class TesAgvController { + + @Autowired + private ITesAgvService iTesAgvService; + + /** + * 创建容器搬运任务 + * + * @param newMovePodTaskRequest 请求参数 + */ + @AutoLog(value = "TesAGV-任务下发") + @Operation(summary = "TesAGV-任务下发") + @PostMapping(value = "/newMovePodTask") + @IgnoreAuth + public Result newMovePodTask(@RequestBody NewMovePodTaskRequest newMovePodTaskRequest) { + iTesAgvService.sendTesAgvTask( + "http://localhost:8000/cpte-wms/tes/apiv2/newMovePodTask", + JSON.toJSONString(newMovePodTaskRequest), + null + ); + return Result.OK("下发成功!"); + } + + /** + * 任务状态更新消息通知 + * + * @param tesCallbackRequest 请求参数 + */ + @AutoLog(value = "TesAGV-任务上报") + @Operation(summary = "TesAGV-任务上报") + @PostMapping(value = "/callBackTask") + @IgnoreAuth + public TesResult callBackTask(@RequestBody TesCallbackRequest tesCallbackRequest) { + try { + iTesAgvService.callBackTask(tesCallbackRequest); + return TesResult.success(); + } catch (Exception e) { + return TesResult.error("系统异常: " + e.getMessage()); + } + } +} diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/tesAgv/request/NewMovePodTaskRequest.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/tesAgv/request/NewMovePodTaskRequest.java new file mode 100644 index 0000000..e1f5fe6 --- /dev/null +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/tesAgv/request/NewMovePodTaskRequest.java @@ -0,0 +1,383 @@ +package org.cpte.modules.tesAgv.request; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import lombok.Data; + +import java.util.List; + +/** + * 容器搬运任务请求参数 + * 功能描述:系统核心接口,需要发送出库、入库、移库等搬运容器任务时使用 + * 应用场景:外检场景、入库场景、移库场景、出库场景 + */ +@JsonPropertyOrder({ + "warehouseID", + "requestID", + "clientCode", + "priority", + "srcType", + "podID", + "bizID", + "replacePodTask", + "destination", + "desType", + "desNodeID", + "desStorageID", + "desZoneCode", + "desStationCodes", + "storagePreference", + "taskExt", + "desExt", + "bizExt" +}) +@Data +public class NewMovePodTaskRequest { + + /** + * 仓库ID + */ + @JsonProperty("warehouseID") + private String warehouseID; + + /** + * 请求ID + */ + @JsonProperty("requestID") + private String requestID; + + /** + * 客户端代码 + */ + @JsonProperty("clientCode") + private String clientCode; + + /** + * 优先级,范围(1-9),9是最高 + */ + @JsonProperty("priority") + private Integer priority = 3; + + /** + * 搬运类型,固定传1 + */ + @JsonProperty("srcType") + private Integer srcType = 1; + + /** + * 容器号 + */ + @JsonProperty("podID") + private String podID; + + /** + * 业务ID,任务完成的时候回调会把此ID回传,上位系统可以通过此参数反查业务订单号等信息 + */ + @JsonProperty("bizID") + private String bizID; + + /** + * 是否替换该容器的其他任务 + * - 0不替换,有多个任务按顺序执行 + * - 1:替换 + */ + @JsonProperty("replacePodTask") + private Integer replacePodTask = 0; + + /** + * 目标位置:可以是储位号,站点编号或巷道编号 + * 注:destination 参数与 desType参数可以选一个,都传的时候以desType为准 + * 如果目标位置是站点,支持传多个站点,用逗号(,)分割 + */ + @JsonProperty("destination") + private String destination; + + /** + * 目标类型: + * - 1:导航点; + * - 2:储位; + * - 3:存储区; + * - 5:工作站 + * - 6: 叠盘 + * - 7:巷道 + */ + @JsonProperty("desType") + private Integer desType; + + /** + * 目标导航点ID,desType=1时必传 + */ + @JsonProperty("desNodeID") + private String desNodeID; + + /** + * 目标储位号,desType=2时必传 + */ + @JsonProperty("desStorageID") + private String desStorageID; + + /** + * 目标区域编号,desType=3,7时必传 + */ + @JsonProperty("desZoneCode") + private String desZoneCode; + + /** + * 目标站点列表,逗号分割,desType=5,6时必传 + */ + @JsonProperty("desStationCodes") + private String desStationCodes; + + /** + * 储位选择偏好 + */ + @JsonProperty("storagePreference") + private StoragePreference storagePreference; + + /** + * 任务扩展参数 + */ + @JsonProperty("taskExt") + private TaskExt taskExt; + + /** + * 终点扩展参数 + */ + @JsonProperty("desExt") + private DesExt desExt; + + /** + * 业务扩展参数 + */ + @JsonProperty("bizExt") + private BizExt bizExt; + + /** + * 储位选择偏好 + * desType=7时有效 + */ + @JsonPropertyOrder({ + "candidateStorageIDs", + "materialClass" + }) + @Data + public static class StoragePreference { + /** + * 托盘可以放置的候选位置,要求是需要偏向于巷道一侧,且包括巷道口储位 + * 如果是双开口巷道,候选储位列表不能同时包含两个入口点位 + * desType=7时有效 + */ + @JsonProperty("candidateStorageIDs") + private List candidateStorageIDs; + + /** + * 物料类型,desType=7时有效,托盘选储位的时候,会按同种类的聚合 + * 注:用此参数时,不能设置candidateStorageIDs参数 + */ + @JsonProperty("materialClass") + private String materialClass; + } + + /** + * 任务扩展参数 + */ + @JsonPropertyOrder({ + "robotGroupID", + "turnMode", + "maxSpeed", + "timeoutFailed", + "autoToRest", + "keepRobot", + "keepRobotTimeout", + "foldType", + "foldNum", + "check", + "cover", + "wrap", + "cargoType", + "whenTargetDisabled", + "delayDispatch" + }) + @Data + public static class TaskExt { + /** + * 指定运力组中的小车搬运 + */ + @JsonProperty("robotGroupID") + private String robotGroupID; + + /** + * 指定小车搬运的顶盘旋转模式 + * - 0 异步旋转 + * - 1 同步旋转 + */ + @JsonProperty("turnMode") + private Integer turnMode; + + /** + * 指定小车搬运的最大车速(mm/s) + */ + @JsonProperty("maxSpeed") + private Integer maxSpeed; + + /** + * 指定任务超时失败的时间(秒) + */ + @JsonProperty("timeoutFailed") + private Integer timeoutFailed = 86400; + + /** + * 指定小车搬运完成后的行为 + * - 0 不限制 + * - 1 立刻离开 + */ + @JsonProperty("autoToRest") + private Integer autoToRest; + + /** + * 指定小车搬运完成后的行为 + * - 0 不限制 + * - 1 保持原地 + */ + @JsonProperty("keepRobot") + private Integer keepRobot; + + /** + * 保持原地的最长时长(分钟) + */ + @JsonProperty("keepRobotTimeout") + private Integer keepRobotTimeout; + + /** + * 叠盘类型 + * - 0 无意义 + * - 2 叠盘或整垛补给 + */ + @JsonProperty("foldType") + private Integer foldType; + + /** + * 叠盘数量 + * - 1 叠一个 + * - >1 整垛补给 + */ + @JsonProperty("foldNum") + private Integer foldNum; + + /** + * 是否进行外形检测,目标为检测站有效 + * - 0 无需 + * - 1 检测 + */ + @JsonProperty("check") + private Integer check; + + /** + * 是否去覆膜任务,目标位置是缠膜站点有效 + * - 0 无需 + * - 1 覆膜 + */ + @JsonProperty("cover") + private Integer cover; + + /** + * 是否去缠膜任务,目标位置是缠膜站点有效 + * - 0 无需 + * - 1 缠膜 + */ + @JsonProperty("wrap") + private Integer wrap; + + /** + * 外检给plc下发货型信息 + * - "000001" 小货型 + * - "000002" 大货型 + */ + @JsonProperty("cargoType") + private String cargoType; + + /** + * 如果目标站点禁用,如何处理任务 + * - taskFail 任务失败 + * - taskWait 任务等待 + */ + @JsonProperty("whenTargetDisabled") + private String whenTargetDisabled; + + /** + * 保留参数 + */ + @JsonProperty("delayDispatch") + private Integer delayDispatch; + } + + /** + * 终点扩展参数 + */ + @JsonPropertyOrder({ + "unload", + "robotFace", + "podFace" + }) + @Data + public static class DesExt { + /** + * 是否放下容器 + * - 0 不放下 + * - 1 放下 + */ + @JsonProperty("unload") + private Integer unload = 0; + + /** + * 指定小车放下容器后,调整姿态朝向 + * 单位弧度,枚举值: + * - 0(x轴正方向) + * - 1.57(y轴正方向) + * - 3.14(x轴负方向) + * - 4.71(y轴负方向) + */ + @JsonProperty("robotFace") + private Double robotFace; + + /** + * 指定容器搬运到位的姿态朝向 + * 单位弧度,枚举值: + * - 0(x轴正方向) + * - 1.57(y轴正方向) + * - 3.14(x轴负方向) + * - 4.71(y轴负方向) + */ + @JsonProperty("podFace") + private Double podFace; + } + + /** + * 业务扩展参数 + */ + @JsonPropertyOrder({ + "bizType", + "waveID" + }) + @Data + public static class BizExt { + /** + * 业务类型,用于做一些数据统计 + */ + @JsonProperty("bizType") + private String bizType; + + /** + * 出库波次 + * 波次说明: + * 1. 一个站点同时只出一个波次,只针对站点出库有效,两个波次去不同的站点则不干涉 + * 2. 进行中的任务无视波次,只有待执行拆第一个step要考虑波次 + * 3. 按波次最早下发那个任务时间排序,做为波次的出库顺序 + * 4. 无波次的任务,如果优先级高于波次任务的最大优先级,可以出库(紧急出库) + * 5. 波次内任务,按照优先级/创建时间/小车距离等综合排序,与无波次时相同 + * 6. 死锁:如果巷道内部为波次A,巷道外部为波次B,先出波次A,可能造成死锁 + */ + @JsonProperty("waveID") + private String waveID; + } +} \ No newline at end of file diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/tesAgv/request/TesCallbackRequest.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/tesAgv/request/TesCallbackRequest.java new file mode 100644 index 0000000..6f3895a --- /dev/null +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/tesAgv/request/TesCallbackRequest.java @@ -0,0 +1,179 @@ +package org.cpte.modules.tesAgv.request; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +@Data +public class TesCallbackRequest { + /** + * 消息号,唯一幂等校验 + */ + @JsonProperty("messageID") + private String messageID; + + /** + * 消息类型 + */ + @JsonProperty("messageType") + private Integer messageType; + + /** + * 仓库ID + */ + @JsonProperty("warehouseID") + private String warehouseID; + + /** + * 消息产生时间 + */ + @JsonProperty("createTime") + private String createTime; + + @JsonProperty("content") + private Content content; + + /** + * 消息具体内容 + */ + @Data + public static class Content { + /** + * 任务发送方,SUPER表示运维后台发送 + */ + @JsonProperty("clientCode") + private String clientCode; + + /** + * 任务ID + */ + @JsonProperty("taskID") + private Integer taskID; + + /** + * 业务ID + */ + @JsonProperty("bizID") + private String bizID; + + /** + * 任务优先级(1-99) + */ + @JsonProperty("priority") + private Integer priority; + + /** + * 任务类型(见附录) + * 2.机器人移动 + * 3.容器搬运 + * 4.充电 + */ + @JsonProperty("taskType") + private Integer taskType; + + /** + * 任务状态(见附录) + * 0.无效 + * 1.就绪 + * 2.进行中 + * 3.取消中 + * 4.成功 + * 5.失败 + * 6.已取消 + * 8.暂停中 + * 10.已替换 + */ + @JsonProperty("status") + private Integer status; + + /** + * 任务失败错误码(见附录) + */ + @JsonProperty("errorCode") + private Integer errorCode; + + /** + * 任务失败信息(见附录) + */ + @JsonProperty("errorReason") + private String errorReason; + + /** + * 最后一个执行设备 + */ + @JsonProperty("robotID") + private String robotID; + + /** + * 容器号 + */ + @JsonProperty("podID") + private String podID; + + /** + * 目的地类型,同任务下发参数 + */ + @JsonProperty("desType") + private Integer desType; + + /** + * 目标点ID + */ + @JsonProperty("desNodeID") + private String desNodeID; + + /** + * 目标储位ID + */ + @JsonProperty("desStorageID") + private String desStorageID; + + /** + * 目标区域ID + */ + @JsonProperty("desZoneCode") + private String desZoneCode; + + /** + * 目标站点编号 + */ + @JsonProperty("desStationCodes") + private String desStationCodes; + + /** + * 任务创建时间 + */ + @JsonProperty("createTime") + private String createTime; + + /** + * 任务完成时间 + */ + @JsonProperty("finishTime") + private String finishTime; + + /** + * 容器位置信息 + */ + @JsonProperty("podInfo") + private PodInfo podInfo; + } + + + /** + * 容器位置信息 + */ + @Data + public static class PodInfo { + /** + * 容器位置类型 + */ + @JsonProperty("positionType") + private Integer positionType; + + /** + * 容器位置编号 + */ + @JsonProperty("nodeID") + private String nodeID; + } +} diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/tesAgv/response/TesResult.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/tesAgv/response/TesResult.java new file mode 100644 index 0000000..669ba1e --- /dev/null +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/tesAgv/response/TesResult.java @@ -0,0 +1,45 @@ +package org.cpte.modules.tesAgv.response; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.io.Serializable; + +/** + * 接口返回数据格式 + * + * @author scott + * @email cpteos@163.com + * @date 2019年1月19日 + */ +@Data +public class TesResult implements Serializable { + + /** + * 返回码 + * 0表示成功,其他表示失败 + */ + @JsonProperty("returnCode") + private Integer returnCode; + + /** + * 返回消息(技术消息) + */ + @JsonProperty("returnMsg") + private String returnMsg; + + public static TesResult success() { + TesResult response = new TesResult(); + response.returnCode = 0; + response.returnMsg = "succ"; + return response; + } + + public static TesResult error(String returnMsg) { + TesResult response = new TesResult(); + response.returnCode = 500; + response.returnMsg = returnMsg; + return response; + } + +} diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/tesAgv/service/ITesAgvService.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/tesAgv/service/ITesAgvService.java new file mode 100644 index 0000000..7ed1330 --- /dev/null +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/tesAgv/service/ITesAgvService.java @@ -0,0 +1,29 @@ +package org.cpte.modules.tesAgv.service; + +import org.cpte.modules.agvTask.entity.AgvTask; +import org.cpte.modules.tesAgv.request.TesCallbackRequest; + +public interface ITesAgvService { + /** + * 生成任务下发JSON + * + * @param agvTask 任务 + */ + String generateTesAgvTaskJson(AgvTask agvTask); + + /** + * 下发任务 + * + * @param url 接口地址 + * @param json 接口json + * @param agvTask 任务 + */ + void sendTesAgvTask(String url, String json, AgvTask agvTask); + + /** + * 任务上报 + * + * @param tesCallbackRequest 上报参数 + */ + void callBackTask(TesCallbackRequest tesCallbackRequest); +} diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/tesAgv/service/impl/ITesAgvServiceImpl.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/tesAgv/service/impl/ITesAgvServiceImpl.java new file mode 100644 index 0000000..95680f1 --- /dev/null +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/tesAgv/service/impl/ITesAgvServiceImpl.java @@ -0,0 +1,222 @@ +package org.cpte.modules.tesAgv.service.impl; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.cpte.modules.agvTask.entity.AgvTask; +import org.cpte.modules.agvTask.mapper.AgvTaskMapper; +import org.cpte.modules.agvTask.service.IAgvTaskService; +import org.cpte.modules.constant.enums.AgvStatusEnum; +import org.cpte.modules.constant.enums.AgvVendorEnum; +import org.cpte.modules.receive.service.IAsnService; +import org.cpte.modules.tesAgv.request.NewMovePodTaskRequest; +import org.cpte.modules.tesAgv.request.TesCallbackRequest; +import org.cpte.modules.tesAgv.service.ITesAgvService; +import org.jeecg.modules.system.mapper.SysDictMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; + +@Service +@Slf4j +public class ITesAgvServiceImpl implements ITesAgvService { + + /** + * 接口开关 + */ + final String open_flag = "OPEN"; + + /** + * 成功码 + */ + final Integer success_code = 0; + + /** + * 失败码 + */ + final Integer fail_code = 500; + + @Autowired + private SysDictMapper sysDictMapper; + + @Autowired + private AgvTaskMapper agvTaskMapper; + + @Autowired + private IAsnService iAsnService; + + @Autowired + private IAgvTaskService iAgvTaskService; + + @Override + public String generateTesAgvTaskJson(AgvTask agvTask) { + NewMovePodTaskRequest newMovePodTaskRequest = new NewMovePodTaskRequest(); + newMovePodTaskRequest.setWarehouseID("HETU"); + newMovePodTaskRequest.setRequestID(String.valueOf(System.currentTimeMillis())); + newMovePodTaskRequest.setClientCode("WCS"); + + newMovePodTaskRequest.setPriority(agvTask.getPriority()); + newMovePodTaskRequest.setSrcType(1); + newMovePodTaskRequest.setPodID(agvTask.getCarrierCode()); + newMovePodTaskRequest.setBizID(agvTask.getId().toString()); + newMovePodTaskRequest.setReplacePodTask(0); + newMovePodTaskRequest.setDesType(1); + newMovePodTaskRequest.setDesNodeID(agvTask.getEndCode()); + + NewMovePodTaskRequest.DesExt desExt = new NewMovePodTaskRequest.DesExt(); + desExt.setUnload(1); + desExt.setRobotFace(3.14); + newMovePodTaskRequest.setDesExt(desExt); + + NewMovePodTaskRequest.TaskExt taskExt = new NewMovePodTaskRequest.TaskExt(); + taskExt.setAutoToRest(1); + taskExt.setTimeoutFailed(86400); + newMovePodTaskRequest.setTaskExt(taskExt); + + return JSON.toJSONString(newMovePodTaskRequest); + } + + @Override + public void sendTesAgvTask(String url, String json, AgvTask agvTask) { + log.info("请求报文:{}", json); + // 检查接口开关, 未开启则返回 + if (sysDictMapper.queryByDictCode(open_flag) == null) { + updateAgvTaskResponse(agvTask, "接口未开启", fail_code); + return; + } + + Integer returnCode = null; + String returnMsg = null; + try { + //String result = HttpPostUtil.sendPostReq(url, json); + String result = "{" + + " \"returnCode\":0," + + " \"returnMsg\":\"succ\"," + + " \"returnUserMsg\":\"成功\"," + + " \"data\":{" + + " \"taskID\":74602" + + " }\n" + + "}"; + if (StringUtils.isEmpty(result)) { + returnMsg = "Tes返回信息:下发任务接口调用失败"; + throw new RuntimeException(returnMsg); + } + + JSONObject resulObject = JSON.parseObject(result); + if (resulObject == null) { + returnMsg = "Tes返回信息:下发任务接口返回为空"; + throw new RuntimeException(returnMsg); + } + + returnCode = resulObject.getInteger("returnCode"); + returnMsg = resulObject.getString("returnUserMsg"); + + if (!success_code.equals(returnCode)) { + throw new RuntimeException("Tes返回消息:" + returnMsg); + } + + // 更新任务状态 + updateAgvTaskResponse(agvTask, returnMsg, returnCode); + } catch (Exception e) { + // 记录异常到 AgvTask + updateAgvTaskResponse(agvTask, e.getMessage(), fail_code); + throw e; // 继续向上抛出异常供 Controller 层处理 + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void callBackTask(TesCallbackRequest tesCallbackRequest) { + //根据任务ID查询任务 + AgvTask agvTask = agvTaskMapper.selectById(tesCallbackRequest.getContent().getBizID()); + String stockCode=tesCallbackRequest.getContent().getPodID(); + if (agvTask == null) { + throw new RuntimeException("【" + tesCallbackRequest.getContent().getBizID() + "】任务不存在"); + } + int status = tesCallbackRequest.getContent().getStatus(); + switch (status) { + case 4: + //4.成功-任务完成 + handleEnd(stockCode,agvTask); + break; + case 6: + //6.已取消-任务取消 + handleCelled(agvTask); + break; + case 7: + //7.自定义-重新发送任务 + handleResend(agvTask); + break; + } + } + + /** + * 任务完成 + * + * @param agvTask 任务 + */ + private void handleEnd(String stockCode,AgvTask agvTask) { + iAsnService.receiveGoods(stockCode); + agvTask.setStatus(AgvStatusEnum.COMPLETED.getValue()); + agvTask.setEndTime(new Date()); + agvTaskMapper.updateById(agvTask); + } + + /** + * 任务取消 + * + * @param agvTask 任务 + */ + private void handleCelled(AgvTask agvTask) { + agvTask.setStatus(AgvStatusEnum.CANCELLED.getValue()); + agvTask.setEndTime(new Date()); + agvTaskMapper.updateById(agvTask); + } + + /** + * 重新发送 + * + * @param agvTask 任务 + */ + private void handleResend(AgvTask agvTask) { + Long count = agvTaskMapper.existsAGVTask(agvTask.getCarrierCode(),AgvVendorEnum.TES.getValue()); + if (count > 0) { + throw new RuntimeException("任务已重新生成,请勿重复操作! "); + } + AgvTask newAgvTask = iAgvTaskService.createAgvTask(AgvStatusEnum.CREATED.getValue(), agvTask.getCarrierCode(), agvTask.getStartCode(), agvTask.getEndCode(), null, agvTask.getType(), AgvVendorEnum.TES.getValue()); + switch (agvTask.getType()) { + case "INBOUND": + case "OUTBOUND": + //下发四向车任务 + sendTesAgvTask("", "", newAgvTask); + break; + default: + throw new RuntimeException("任务类型不支持: " + agvTask.getType()); + } + } + + + /** + * 更新任务状态 + * + * @param agvTask 任务 + * @param message 信息 + * @param code 状态码 + */ + private void updateAgvTaskResponse(AgvTask agvTask, String message, Integer code) { + if (agvTask != null) { + if (success_code.equals(code)) { + agvTask.setStatus(AgvStatusEnum.EXECUTING.getValue()); + } + agvTask.setResMessage(message); + agvTask.setStartTime(new Date()); + agvTaskMapper.updateById(agvTask); + } + } + +} + +