diff --git a/servo/src/main/java/com/galaxis/rcs/RCS.java b/servo/src/main/java/com/galaxis/rcs/RCS.java index 2851b76..2768bc9 100644 --- a/servo/src/main/java/com/galaxis/rcs/RCS.java +++ b/servo/src/main/java/com/galaxis/rcs/RCS.java @@ -35,19 +35,11 @@ public class RCS { AddTaskResult result = new AddTaskResult(); LogisticsRuntime logisticsRuntime = logisticsRuntimeService.findByEnvCode(envCode); - String bizTaskId = logisticsRuntime.taskService.addBizTask(request); - - logisticsRuntime.taskDispatchFactory.checkAll(); - result.bizTaskId = bizTaskId; return result; } - /** - * 地图信息2 - * 1<->2, 2<->3, 3<->4, 4<->5, 5<->6, 6<->7, 7<->8, 8<->9,9<->10 - * 1 <-> 38, 1 <-> 36 - */ + } diff --git a/servo/src/main/java/com/galaxis/rcs/common/entity/AddTaskRequest.java b/servo/src/main/java/com/galaxis/rcs/common/entity/AddTaskRequest.java index ef71c92..1774498 100644 --- a/servo/src/main/java/com/galaxis/rcs/common/entity/AddTaskRequest.java +++ b/servo/src/main/java/com/galaxis/rcs/common/entity/AddTaskRequest.java @@ -51,4 +51,14 @@ public class AddTaskRequest { * 目标位置 */ public StoreLocation to; + + /** + * 任务描述 + */ + public String description; + + /** + * 创建者 + */ + public String createBy; } diff --git a/servo/src/main/java/com/galaxis/rcs/common/entity/LccEnvInfo.java b/servo/src/main/java/com/galaxis/rcs/common/entity/LccEnvInfo.java new file mode 100644 index 0000000..cf5a65d --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/common/entity/LccEnvInfo.java @@ -0,0 +1,30 @@ +package com.galaxis.rcs.common.entity; + +import lombok.Data; +import java.io.Serializable; +import java.util.Date; + +/** + * (lcc_env_info) + */ +@Data +public class LccEnvInfo implements Serializable { + /** 环境ID */ + private Long envId; + /** 世界地图ID */ + private String worldId; + /** 环境名称 */ + private String envName; + /** 是否虚拟环境 */ + private Boolean isVirtual; + /** 环境负载信息 */ + private String envPayload; + /** 创建时间 */ + private Date createAt; + /** 创建人 */ + private String createBy; + /** 更新时间 */ + private Date updateAt; + /** 更新人 */ + private String updateBy; +} diff --git a/servo/src/main/java/com/galaxis/rcs/common/entity/RcsTaskBiz.java b/servo/src/main/java/com/galaxis/rcs/common/entity/RcsTaskBiz.java index 6aee863..1e19de5 100644 --- a/servo/src/main/java/com/galaxis/rcs/common/entity/RcsTaskBiz.java +++ b/servo/src/main/java/com/galaxis/rcs/common/entity/RcsTaskBiz.java @@ -11,6 +11,8 @@ import java.util.Date; public class RcsTaskBiz implements Serializable { /** */ private Long bizTaskId; + /** 环境ID */ + private Long envId; /** 任务类型 */ private String bizType; /** 托盘ID */ diff --git a/servo/src/main/java/com/galaxis/rcs/common/entity/RcsTaskDevice.java b/servo/src/main/java/com/galaxis/rcs/common/entity/RcsTaskDevice.java index 3746ca5..bec43dd 100644 --- a/servo/src/main/java/com/galaxis/rcs/common/entity/RcsTaskDevice.java +++ b/servo/src/main/java/com/galaxis/rcs/common/entity/RcsTaskDevice.java @@ -15,6 +15,8 @@ public class RcsTaskDevice implements Serializable { private Long planTaskId; /** 业务任务ID */ private Long bizTaskId; + /** 环境ID */ + private Long envId; /** 设备类型 */ private String deviceType; /** 执行器ID */ diff --git a/servo/src/main/java/com/galaxis/rcs/common/entity/RcsTaskPlan.java b/servo/src/main/java/com/galaxis/rcs/common/entity/RcsTaskPlan.java index e4fd18a..7fa08c9 100644 --- a/servo/src/main/java/com/galaxis/rcs/common/entity/RcsTaskPlan.java +++ b/servo/src/main/java/com/galaxis/rcs/common/entity/RcsTaskPlan.java @@ -13,6 +13,8 @@ public class RcsTaskPlan implements Serializable { private Long planTaskId; /** 业务任务ID */ private Long bizTaskId; + /** 环境ID */ + private Long envId; /** 规划类型 */ private String planType; /** 执行器ID */ diff --git a/servo/src/main/java/com/galaxis/rcs/common/enums/BizTaskStatus.java b/servo/src/main/java/com/galaxis/rcs/common/enums/BizTaskStatus.java new file mode 100644 index 0000000..83c662b --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/common/enums/BizTaskStatus.java @@ -0,0 +1,46 @@ +package com.galaxis.rcs.common.enums; + +public enum BizTaskStatus { + /** + * 待调度 + */ + WAITING_FOR_DISPATCH, + + /** + * 设备执行中 + */ + DEVICE_EXECUTING, + + /** + * 暂停执行 + */ + PAUSED, + + /** + * 调度异常 + */ + DISPATCH_ERROR, + + /** + * 规划异常 + */ + PLANNING_ERROR, + + /** + * 设备执行异常 + */ + DEVICE_ERROR; + + public static BizTaskStatus fromString(String value) { + if (value == null) + throw new IllegalArgumentException("Value cannot be null"); + + for (BizTaskStatus type : BizTaskStatus.values()) { + if (type.toString().equalsIgnoreCase(value.trim())) { + return type; + } + } + + throw new IllegalArgumentException("No constant with name: " + value); + } +} diff --git a/servo/src/main/java/com/galaxis/rcs/common/enums/BizTaskType.java b/servo/src/main/java/com/galaxis/rcs/common/enums/BizTaskType.java index c03f390..d95355b 100644 --- a/servo/src/main/java/com/galaxis/rcs/common/enums/BizTaskType.java +++ b/servo/src/main/java/com/galaxis/rcs/common/enums/BizTaskType.java @@ -1,5 +1,18 @@ package com.galaxis.rcs.common.enums; public enum BizTaskType { - CARRY, // 搬运任务 + CARRY; // 搬运任务 + + public static BizTaskType fromString(String value) { + if (value == null) + throw new IllegalArgumentException("Value cannot be null"); + + for (BizTaskType type : BizTaskType.values()) { + if (type.toString().equalsIgnoreCase(value.trim())) { + return type; + } + } + + throw new IllegalArgumentException("No constant with name: " + value); + } } diff --git a/servo/src/main/java/com/galaxis/rcs/common/enums/OperationSide.java b/servo/src/main/java/com/galaxis/rcs/common/enums/OperationSide.java new file mode 100644 index 0000000..e864ae4 --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/common/enums/OperationSide.java @@ -0,0 +1,26 @@ +package com.galaxis.rcs.common.enums; + +/** + * 表示货位 与 路标点, 在世界坐标中的相对位置关系 + */ +public enum OperationSide { + /** + * 货位在路标点的上方 + */ + TOP, + + /** + * 货位在路标点的下方 + */ + BOTTOM, + + /** + * 货位在路标点的左侧 + */ + LEFT, + + /** + * 货位在路标点的右侧 + */ + RIGHT +} diff --git a/servo/src/main/java/com/galaxis/rcs/common/query/QLccEnvInfo.java b/servo/src/main/java/com/galaxis/rcs/common/query/QLccEnvInfo.java new file mode 100644 index 0000000..f90eaf6 --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/common/query/QLccEnvInfo.java @@ -0,0 +1,74 @@ +package com.galaxis.rcs.common.query; + +import static com.querydsl.core.types.PathMetadataFactory.*; +import com.querydsl.core.types.dsl.*; +import com.querydsl.core.types.*; +import com.querydsl.sql.*; +import java.sql.Types; +import com.galaxis.rcs.common.entity.LccEnvInfo; +import java.util.Date; + +/** + * (lcc_env_info) + */ +@SuppressWarnings("ALL") +public class QLccEnvInfo extends RelationalPathBase { + /** lcc_env_info表 */ + public static final QLccEnvInfo lccEnvInfo = new QLccEnvInfo("lcc_env_info"); + + /** 环境ID */ + public final NumberPath envId = createNumber("envId", Long.class); + /** 世界地图ID */ + public final StringPath worldId = createString("worldId"); + /** 环境名称 */ + public final StringPath envName = createString("envName"); + /** 是否虚拟环境 */ + public final BooleanPath isVirtual = createBoolean("isVirtual"); + /** 环境负载信息 */ + public final StringPath envPayload = createString("envPayload"); + /** 创建时间 */ + public final DateTimePath createAt = createDateTime("createAt", Date.class); + /** 创建人 */ + public final StringPath createBy = createString("createBy"); + /** 更新时间 */ + public final DateTimePath updateAt = createDateTime("updateAt", Date.class); + /** 更新人 */ + public final StringPath updateBy = createString("updateBy"); + + public QLccEnvInfo(String variable) { + super(LccEnvInfo.class, forVariable(variable), "rcs2_tw_zhanghui", "lcc_env_info"); + addMetadata(); + } + + public QLccEnvInfo(String variable, String schema, String table) { + super(LccEnvInfo.class, forVariable(variable), schema, table); + addMetadata(); + } + + public QLccEnvInfo(String variable, String schema) { + super(LccEnvInfo.class, forVariable(variable), schema, "lcc_env_info"); + addMetadata(); + } + + public QLccEnvInfo(Path path) { + super(path.getType(), path.getMetadata(), "rcs2_tw_zhanghui", "lcc_env_info"); + addMetadata(); + } + + public QLccEnvInfo(PathMetadata metadata) { + super(LccEnvInfo.class, metadata, "rcs2_tw_zhanghui", "lcc_env_info"); + addMetadata(); + } + + private void addMetadata() { + addMetadata(envId, ColumnMetadata.named("env_id").withIndex(1).ofType(Types.BIGINT).withSize(19)); + addMetadata(worldId, ColumnMetadata.named("world_id").withIndex(2).ofType(Types.VARCHAR).withSize(50)); + addMetadata(envName, ColumnMetadata.named("env_name").withIndex(3).ofType(Types.VARCHAR).withSize(50)); + addMetadata(isVirtual, ColumnMetadata.named("is_virtual").withIndex(4).ofType(Types.BIT).withSize(3)); + addMetadata(envPayload, ColumnMetadata.named("env_payload").withIndex(5).ofType(Types.VARCHAR).withSize(3000)); + addMetadata(createAt, ColumnMetadata.named("create_at").withIndex(6).ofType(Types.TIMESTAMP)); + addMetadata(createBy, ColumnMetadata.named("create_by").withIndex(7).ofType(Types.VARCHAR).withSize(50)); + addMetadata(updateAt, ColumnMetadata.named("update_at").withIndex(8).ofType(Types.TIMESTAMP)); + addMetadata(updateBy, ColumnMetadata.named("update_by").withIndex(9).ofType(Types.VARCHAR).withSize(50)); + } +} diff --git a/servo/src/main/java/com/galaxis/rcs/common/query/QRcsTaskBiz.java b/servo/src/main/java/com/galaxis/rcs/common/query/QRcsTaskBiz.java index 7665b9b..7cdc5b5 100644 --- a/servo/src/main/java/com/galaxis/rcs/common/query/QRcsTaskBiz.java +++ b/servo/src/main/java/com/galaxis/rcs/common/query/QRcsTaskBiz.java @@ -18,6 +18,8 @@ public class QRcsTaskBiz extends RelationalPathBase { /** */ public final NumberPath bizTaskId = createNumber("bizTaskId", Long.class); + /** 环境ID */ + public final NumberPath envId = createNumber("envId", Long.class); /** 任务类型 */ public final StringPath bizType = createString("bizType"); /** 托盘ID */ @@ -74,19 +76,20 @@ public class QRcsTaskBiz extends RelationalPathBase { private void addMetadata() { addMetadata(bizTaskId, ColumnMetadata.named("biz_task_id").withIndex(1).ofType(Types.BIGINT).withSize(19)); - addMetadata(bizType, ColumnMetadata.named("biz_type").withIndex(2).ofType(Types.VARCHAR).withSize(10)); - addMetadata(lpn, ColumnMetadata.named("lpn").withIndex(3).ofType(Types.VARCHAR).withSize(50)); - addMetadata(priority, ColumnMetadata.named("priority").withIndex(4).ofType(Types.INTEGER).withSize(10)); - addMetadata(taskFrom, ColumnMetadata.named("task_from").withIndex(5).ofType(Types.VARCHAR).withSize(50)); - addMetadata(taskTo, ColumnMetadata.named("task_to").withIndex(6).ofType(Types.VARCHAR).withSize(50)); - addMetadata(allocatedExecutorId, ColumnMetadata.named("allocated_executor_id").withIndex(7).ofType(Types.VARCHAR).withSize(50)); - addMetadata(bizTaskPayload, ColumnMetadata.named("biz_task_payload").withIndex(8).ofType(Types.VARCHAR).withSize(3000)); - addMetadata(bizTaskErrorInfo, ColumnMetadata.named("biz_task_error_info").withIndex(9).ofType(Types.VARCHAR).withSize(500)); - addMetadata(bizTaskDescription, ColumnMetadata.named("biz_task_description").withIndex(10).ofType(Types.VARCHAR).withSize(500)); - addMetadata(bizTaskStatus, ColumnMetadata.named("biz_task_status").withIndex(11).ofType(Types.VARCHAR).withSize(10)); - addMetadata(createAt, ColumnMetadata.named("create_at").withIndex(12).ofType(Types.TIMESTAMP)); - addMetadata(createBy, ColumnMetadata.named("create_by").withIndex(13).ofType(Types.VARCHAR).withSize(50)); - addMetadata(updateAt, ColumnMetadata.named("update_at").withIndex(14).ofType(Types.TIMESTAMP)); - addMetadata(updateBy, ColumnMetadata.named("update_by").withIndex(15).ofType(Types.VARCHAR).withSize(50)); + addMetadata(envId, ColumnMetadata.named("env_id").withIndex(2).ofType(Types.BIGINT).withSize(19)); + addMetadata(bizType, ColumnMetadata.named("biz_type").withIndex(3).ofType(Types.VARCHAR).withSize(10)); + addMetadata(lpn, ColumnMetadata.named("lpn").withIndex(4).ofType(Types.VARCHAR).withSize(50)); + addMetadata(priority, ColumnMetadata.named("priority").withIndex(5).ofType(Types.INTEGER).withSize(10)); + addMetadata(taskFrom, ColumnMetadata.named("task_from").withIndex(6).ofType(Types.VARCHAR).withSize(50)); + addMetadata(taskTo, ColumnMetadata.named("task_to").withIndex(7).ofType(Types.VARCHAR).withSize(50)); + addMetadata(allocatedExecutorId, ColumnMetadata.named("allocated_executor_id").withIndex(8).ofType(Types.VARCHAR).withSize(50)); + addMetadata(bizTaskPayload, ColumnMetadata.named("biz_task_payload").withIndex(9).ofType(Types.VARCHAR).withSize(3000)); + addMetadata(bizTaskErrorInfo, ColumnMetadata.named("biz_task_error_info").withIndex(10).ofType(Types.VARCHAR).withSize(500)); + addMetadata(bizTaskDescription, ColumnMetadata.named("biz_task_description").withIndex(11).ofType(Types.VARCHAR).withSize(500)); + addMetadata(bizTaskStatus, ColumnMetadata.named("biz_task_status").withIndex(12).ofType(Types.VARCHAR).withSize(10)); + addMetadata(createAt, ColumnMetadata.named("create_at").withIndex(13).ofType(Types.TIMESTAMP)); + addMetadata(createBy, ColumnMetadata.named("create_by").withIndex(14).ofType(Types.VARCHAR).withSize(50)); + addMetadata(updateAt, ColumnMetadata.named("update_at").withIndex(15).ofType(Types.TIMESTAMP)); + addMetadata(updateBy, ColumnMetadata.named("update_by").withIndex(16).ofType(Types.VARCHAR).withSize(50)); } } diff --git a/servo/src/main/java/com/galaxis/rcs/common/query/QRcsTaskDevice.java b/servo/src/main/java/com/galaxis/rcs/common/query/QRcsTaskDevice.java index 29360a0..6b1bbc3 100644 --- a/servo/src/main/java/com/galaxis/rcs/common/query/QRcsTaskDevice.java +++ b/servo/src/main/java/com/galaxis/rcs/common/query/QRcsTaskDevice.java @@ -22,6 +22,8 @@ public class QRcsTaskDevice extends RelationalPathBase { public final NumberPath planTaskId = createNumber("planTaskId", Long.class); /** 业务任务ID */ public final NumberPath bizTaskId = createNumber("bizTaskId", Long.class); + /** 环境ID */ + public final NumberPath envId = createNumber("envId", Long.class); /** 设备类型 */ public final StringPath deviceType = createString("deviceType"); /** 执行器ID */ @@ -80,19 +82,20 @@ public class QRcsTaskDevice extends RelationalPathBase { addMetadata(deviceTaskId, ColumnMetadata.named("device_task_id").withIndex(1).ofType(Types.BIGINT).withSize(19)); addMetadata(planTaskId, ColumnMetadata.named("plan_task_id").withIndex(2).ofType(Types.BIGINT).withSize(19)); addMetadata(bizTaskId, ColumnMetadata.named("biz_task_id").withIndex(3).ofType(Types.BIGINT).withSize(19)); - addMetadata(deviceType, ColumnMetadata.named("device_type").withIndex(4).ofType(Types.VARCHAR).withSize(50)); - addMetadata(deviceItemId, ColumnMetadata.named("device_item_id").withIndex(5).ofType(Types.VARCHAR).withSize(50)); - addMetadata(seq, ColumnMetadata.named("seq").withIndex(6).ofType(Types.INTEGER).withSize(10)); - addMetadata(packetType, ColumnMetadata.named("packet_type").withIndex(7).ofType(Types.VARCHAR).withSize(10)); - addMetadata(packetEndPoint, ColumnMetadata.named("packet_end_point").withIndex(8).ofType(Types.VARCHAR).withSize(50)); - addMetadata(packetPayload, ColumnMetadata.named("packet_payload").withIndex(9).ofType(Types.VARCHAR).withSize(50)); - addMetadata(deviceTaskPayload, ColumnMetadata.named("device_task_payload").withIndex(10).ofType(Types.VARCHAR).withSize(3000)); - addMetadata(deviceTaskStatus, ColumnMetadata.named("device_task_status").withIndex(11).ofType(Types.VARCHAR).withSize(10)); - addMetadata(deviceTaskErrorInfo, ColumnMetadata.named("device_task_error_info").withIndex(12).ofType(Types.VARCHAR).withSize(500)); - addMetadata(deviceTaskDescription, ColumnMetadata.named("device_task_description").withIndex(13).ofType(Types.VARCHAR).withSize(500)); - addMetadata(createAt, ColumnMetadata.named("create_at").withIndex(14).ofType(Types.TIMESTAMP)); - addMetadata(createBy, ColumnMetadata.named("create_by").withIndex(15).ofType(Types.VARCHAR).withSize(50)); - addMetadata(updateAt, ColumnMetadata.named("update_at").withIndex(16).ofType(Types.TIMESTAMP)); - addMetadata(updateBy, ColumnMetadata.named("update_by").withIndex(17).ofType(Types.VARCHAR).withSize(50)); + addMetadata(envId, ColumnMetadata.named("env_id").withIndex(4).ofType(Types.BIGINT).withSize(19)); + addMetadata(deviceType, ColumnMetadata.named("device_type").withIndex(5).ofType(Types.VARCHAR).withSize(50)); + addMetadata(deviceItemId, ColumnMetadata.named("device_item_id").withIndex(6).ofType(Types.VARCHAR).withSize(50)); + addMetadata(seq, ColumnMetadata.named("seq").withIndex(7).ofType(Types.INTEGER).withSize(10)); + addMetadata(packetType, ColumnMetadata.named("packet_type").withIndex(8).ofType(Types.VARCHAR).withSize(10)); + addMetadata(packetEndPoint, ColumnMetadata.named("packet_end_point").withIndex(9).ofType(Types.VARCHAR).withSize(50)); + addMetadata(packetPayload, ColumnMetadata.named("packet_payload").withIndex(10).ofType(Types.VARCHAR).withSize(50)); + addMetadata(deviceTaskPayload, ColumnMetadata.named("device_task_payload").withIndex(11).ofType(Types.VARCHAR).withSize(3000)); + addMetadata(deviceTaskStatus, ColumnMetadata.named("device_task_status").withIndex(12).ofType(Types.VARCHAR).withSize(10)); + addMetadata(deviceTaskErrorInfo, ColumnMetadata.named("device_task_error_info").withIndex(13).ofType(Types.VARCHAR).withSize(500)); + addMetadata(deviceTaskDescription, ColumnMetadata.named("device_task_description").withIndex(14).ofType(Types.VARCHAR).withSize(500)); + addMetadata(createAt, ColumnMetadata.named("create_at").withIndex(15).ofType(Types.TIMESTAMP)); + addMetadata(createBy, ColumnMetadata.named("create_by").withIndex(16).ofType(Types.VARCHAR).withSize(50)); + addMetadata(updateAt, ColumnMetadata.named("update_at").withIndex(17).ofType(Types.TIMESTAMP)); + addMetadata(updateBy, ColumnMetadata.named("update_by").withIndex(18).ofType(Types.VARCHAR).withSize(50)); } } diff --git a/servo/src/main/java/com/galaxis/rcs/common/query/QRcsTaskPlan.java b/servo/src/main/java/com/galaxis/rcs/common/query/QRcsTaskPlan.java index 19167b1..581ed4c 100644 --- a/servo/src/main/java/com/galaxis/rcs/common/query/QRcsTaskPlan.java +++ b/servo/src/main/java/com/galaxis/rcs/common/query/QRcsTaskPlan.java @@ -20,6 +20,8 @@ public class QRcsTaskPlan extends RelationalPathBase { public final NumberPath planTaskId = createNumber("planTaskId", Long.class); /** 业务任务ID */ public final NumberPath bizTaskId = createNumber("bizTaskId", Long.class); + /** 环境ID */ + public final NumberPath envId = createNumber("envId", Long.class); /** 规划类型 */ public final StringPath planType = createString("planType"); /** 执行器ID */ @@ -71,16 +73,17 @@ public class QRcsTaskPlan extends RelationalPathBase { private void addMetadata() { addMetadata(planTaskId, ColumnMetadata.named("plan_task_id").withIndex(1).ofType(Types.BIGINT).withSize(19)); addMetadata(bizTaskId, ColumnMetadata.named("biz_task_id").withIndex(2).ofType(Types.BIGINT).withSize(19)); - addMetadata(planType, ColumnMetadata.named("plan_type").withIndex(3).ofType(Types.VARCHAR).withSize(10)); - addMetadata(executorId, ColumnMetadata.named("executor_id").withIndex(4).ofType(Types.VARCHAR).withSize(50)); - addMetadata(seq, ColumnMetadata.named("seq").withIndex(5).ofType(Types.INTEGER).withSize(10)); - addMetadata(planTaskPayload, ColumnMetadata.named("plan_task_payload").withIndex(6).ofType(Types.VARCHAR).withSize(3000)); - addMetadata(planTaskStatus, ColumnMetadata.named("plan_task_status").withIndex(7).ofType(Types.VARCHAR).withSize(10)); - addMetadata(planTaskErrorInfo, ColumnMetadata.named("plan_task_error_info").withIndex(8).ofType(Types.VARCHAR).withSize(500)); - addMetadata(planTaskDescription, ColumnMetadata.named("plan_task_description").withIndex(9).ofType(Types.VARCHAR).withSize(500)); - addMetadata(createAt, ColumnMetadata.named("create_at").withIndex(10).ofType(Types.TIMESTAMP)); - addMetadata(createBy, ColumnMetadata.named("create_by").withIndex(11).ofType(Types.VARCHAR).withSize(50)); - addMetadata(updateAt, ColumnMetadata.named("update_at").withIndex(12).ofType(Types.TIMESTAMP)); - addMetadata(updateBy, ColumnMetadata.named("update_by").withIndex(13).ofType(Types.VARCHAR).withSize(50)); + addMetadata(envId, ColumnMetadata.named("env_id").withIndex(3).ofType(Types.BIGINT).withSize(19)); + addMetadata(planType, ColumnMetadata.named("plan_type").withIndex(4).ofType(Types.VARCHAR).withSize(10)); + addMetadata(executorId, ColumnMetadata.named("executor_id").withIndex(5).ofType(Types.VARCHAR).withSize(50)); + addMetadata(seq, ColumnMetadata.named("seq").withIndex(6).ofType(Types.INTEGER).withSize(10)); + addMetadata(planTaskPayload, ColumnMetadata.named("plan_task_payload").withIndex(7).ofType(Types.VARCHAR).withSize(3000)); + addMetadata(planTaskStatus, ColumnMetadata.named("plan_task_status").withIndex(8).ofType(Types.VARCHAR).withSize(10)); + addMetadata(planTaskErrorInfo, ColumnMetadata.named("plan_task_error_info").withIndex(9).ofType(Types.VARCHAR).withSize(500)); + addMetadata(planTaskDescription, ColumnMetadata.named("plan_task_description").withIndex(10).ofType(Types.VARCHAR).withSize(500)); + addMetadata(createAt, ColumnMetadata.named("create_at").withIndex(11).ofType(Types.TIMESTAMP)); + addMetadata(createBy, ColumnMetadata.named("create_by").withIndex(12).ofType(Types.VARCHAR).withSize(50)); + addMetadata(updateAt, ColumnMetadata.named("update_at").withIndex(13).ofType(Types.TIMESTAMP)); + addMetadata(updateBy, ColumnMetadata.named("update_by").withIndex(14).ofType(Types.VARCHAR).withSize(50)); } } diff --git a/servo/src/main/java/com/galaxis/rcs/plan/PTRTaskPlanner.java b/servo/src/main/java/com/galaxis/rcs/plan/PTRTaskPlanner.java index 8413aff..6bb7195 100644 --- a/servo/src/main/java/com/galaxis/rcs/plan/PTRTaskPlanner.java +++ b/servo/src/main/java/com/galaxis/rcs/plan/PTRTaskPlanner.java @@ -2,64 +2,152 @@ package com.galaxis.rcs.plan; import com.galaxis.rcs.common.entity.RcsTaskBiz; import com.galaxis.rcs.common.entity.RcsTaskPlan; +import com.galaxis.rcs.common.enums.BizTaskStatus; +import com.google.common.collect.Lists; +import com.yvan.logisticsModel.ExecutorItem; import com.yvan.logisticsModel.LogisticsRuntime; +import org.clever.data.jdbc.DaoFactory; +import org.clever.data.jdbc.QueryDSL; + +import java.util.Date; +import java.util.List; + +import static com.galaxis.rcs.common.query.QRcsTaskBiz.rcsTaskBiz; /** * PTR 任务规划器。 * 用于处理 CL2 / CLX 等车型的任务规划 */ public class PTRTaskPlanner implements Planner { + + static final QueryDSL queryDSL = DaoFactory.getQueryDSL(); + /** * 执行任务规划 * - * @param runtime 物流运行时环境 - * @param task 任务对象,包含任务的详细信息 - * @param executorId 执行器ID + * @param runtime 物流运行时环境 + * @param task 任务对象,包含任务的详细信息 + * @param agv AGV */ @Override - public void executePlan(LogisticsRuntime runtime, RcsTaskBiz task, String executorId) { - /** - * 示例数据 - * { - * type: 'carry', // 任务类型 - * agv: 'cl2', // 指定车辆 - * lpn: 'pallet1124', // 托盘ID, 用于校验 - * priority: 1, // 优先级 - * // 起始点位的详细信息 - * from: { - * item: '27', // 货架编号 - * bay: 0, // 货架列 - * level: 1, // 货架层 - * cell: 0 // 货架格 - * }, - * // 目标点位的详细信息 - * to: { - * item: '20' // 地堆货位号 - * } - * } - */ + public void executePlan(LogisticsRuntime runtime, RcsTaskBiz task, ExecutorItem agv) { - /** - * 地图路由示例1 - * 17<->20, 20<->21, 21<->22, 22<->23, 23<->24, 24<->25, 25<->26, 26<->27, 27<->charger2, - * - * 地图货位信息 - * 21 左侧 rack1 / 3 - * 22 右侧 56 - * 23 左侧 rack1 / 2 - * 24 旋转位 - * 25 左侧 rack1 / 1 - * 26 右侧 58 - * 27 左侧 rack1 / 0 - */ // 绑定任务执行器 - task.setAllocatedExecutorId(executorId); + task.setAllocatedExecutorId(agv.getId()); + task.setBizTaskStatus(BizTaskStatus.DEVICE_EXECUTING.toString()); + queryDSL.update(rcsTaskBiz) + .populate(task) + .set(rcsTaskBiz.updateAt, new Date()) + .set(rcsTaskBiz.updateBy, PTRTaskPlanner.class.getName()) + .where(rcsTaskBiz.bizTaskId.eq(task.getBizTaskId())) + .execute(); + runtime.taskService.removeFromWaitingTaskList(task.getBizTaskId()); + + List planList = Lists.newArrayList(); + + + /* +用 Java 编写任务规划逻辑. + +例如, 需求给出的是 +示例数据 +需求报文: +```json5 +{ + type: 'carry', // 任务类型 + agv: 'cl2', // 指定车辆 + lpn: 'pallet1124', // 托盘ID, 用于校验 + priority: 1, // 优先级 + // 起始点位的详细信息 + from: { + item: 'rack1',// 货架编号 + bay: 0, // 货架列 + level: 1, // 货架层 + cell: 0 // 货架格 + }, + // 目标点位的详细信息 + to: { + item: '54' // 地堆货位号 + } +} +``` +from 是一个组合数据, 他需要取出 "rack1"货架的"3"列, 取出 "pallet1124" 托盘 +to 是一个对象数据,他需要搬运到 "54" 号储位 + - // TODO: 写入 rcs_task_biz 表, 写入 rcs_task_plan 表, 并安排规划方案的顺序执行, 并将全部规划通知给 MQTT - RcsTaskPlan[] planList = new RcsTaskPlan[0]; +地图路由 +```text +路标点位信息 +17<->20, 20<->21, 21<->22, 22<->23, 23<->24, 24<->25, 25<->26, 26<->27, 27<->charger2, +1<->2, 2<->3, 3<->4, 4<->5, 5<->6, 6<->7, 7<->8 +36<->1, 38<->1, 8<->charger1 + +地图货位信息 +```text +20 右侧 54 +21 左侧 rack1 / 3 +22 右侧 56 +23 左侧 rack1 / 2 +24 可旋转位 +25 左侧 rack1 / 1 +26 右侧 58 +27 左侧 rack1 / 0 +38 上方 49 +36 上方 47 +1 可旋转位 +3 右侧 rack1 / 3 +5 右侧 rack1 / 2 +7 右侧 rack1 / 1 +8 右侧 rack1 / 0 +``` + +从"地图货位信息"中看到,"rack1"货架的"3"列,在 "27" 号路标点的左侧 +他需要查询目前执行器所在的位置,和执行器当前的姿态(货叉朝向) +如果方向不对,他需要运行到最近的"可旋转位",进行方位姿态的调整 +然后引导到取货点,进行取货 + +取货完毕之后,再查看目标位置 +从"地图货位信息"中看到,目的地 "54" 号储位 位于 "20" 号路标点的右侧 +他要查询取货之后的车的姿态(货叉朝向) +如果方向不对,他需要运行到最近的"可旋转位",进行方位姿态的调整 +然后引导到目的点,进行放货 + +算法输出小车的行动规划序列, 行动的类型有: +移动: RcsTaskPlan move = new RcsTaskPlan() +move.type = "robotMove"; .executorId=当前机器人编号; .startWayPoint=""; .endWayPoint=""; .armRotiation=90; + +转动 RcsTaskPlan rotation = new RcsTaskPlan() +rotation.type = "robotRotation"; .executorId=当前机器人编号; .worldRotation=90; + +取货 RcsTaskPlan load = new RcsTaskPlan() +load.type = "robotLoad"; .executorId=当前机器人编号; .rackItem="货架ID"; .bay="列"; .level="层"; .cell="格" + +放货 RcsTaskPlan unload = new RcsTaskPlan() +unload.type = "robotUnload"; .executorId=当前机器人编号; .rackItem="货架ID"; .bay="列"; .level="层"; .cell="格" + +完成 RcsTaskPlan finish = new RcsTaskPlan() +finish.type = "robotFinish"; .executorId=当前机器人编号; + +按照这个示例,他输出结果为 + +const cl2 = Model.getCl2('ptr1') +const palletId = 'pallet1124' +const yy = Model.getPositionByEntityId(palletId).y + +move('23') +rotation(90) +move('27') +load(level=1, cell=0) +move('23') +rotation(-90) +move('20') +unload(level=0) +finish() +``` + */ - runtime.executorItemMap.get(executorId).executeTaskPlanList(runtime, task, planList); + agv.executeTaskPlanList(runtime, task, planList); } } diff --git a/servo/src/main/java/com/galaxis/rcs/plan/Planner.java b/servo/src/main/java/com/galaxis/rcs/plan/Planner.java index 73683d3..3707c94 100644 --- a/servo/src/main/java/com/galaxis/rcs/plan/Planner.java +++ b/servo/src/main/java/com/galaxis/rcs/plan/Planner.java @@ -1,6 +1,7 @@ package com.galaxis.rcs.plan; import com.galaxis.rcs.common.entity.RcsTaskBiz; +import com.yvan.logisticsModel.ExecutorItem; import com.yvan.logisticsModel.LogisticsRuntime; /** @@ -15,5 +16,5 @@ public interface Planner { * @param tasks 任务对象,包含任务的详细信息 * @param executorId 执行器ID */ - void executePlan(LogisticsRuntime runtime, RcsTaskBiz tasks, String executorId); + void executePlan(LogisticsRuntime runtime, RcsTaskBiz tasks, ExecutorItem executorId); } diff --git a/servo/src/main/java/com/galaxis/rcs/plan/path/AStarNodeState.java b/servo/src/main/java/com/galaxis/rcs/plan/path/AStarNodeState.java new file mode 100644 index 0000000..e7f5f10 --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/plan/path/AStarNodeState.java @@ -0,0 +1,29 @@ +package com.galaxis.rcs.plan.path; + +/** + * A*路径节点状态 + */ +public record AStarNodeState( + String nodeId, // 当前节点ID + int direction, // 当前方向 (0,90,180,270) + float gCost, // 实际代价 + float hCost, // 启发式代价 + AStarNodeState parent // 父节点 +) implements Comparable { + + // 状态唯一标识 + public String stateKey() { + return nodeId + ":" + direction; + } + + // 总代价 + public float fCost() { + return gCost + hCost; + } + + @Override + public int compareTo(AStarNodeState other) { + return Float.compare(this.fCost(), other.fCost()); + } +} + diff --git a/servo/src/main/java/com/galaxis/rcs/plan/path/AStarPathPlanner.java b/servo/src/main/java/com/galaxis/rcs/plan/path/AStarPathPlanner.java new file mode 100644 index 0000000..0c1a830 --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/plan/path/AStarPathPlanner.java @@ -0,0 +1,122 @@ +package com.galaxis.rcs.plan.path; + +import java.util.*; + +/** + * A*路径规划器 + */ +public class AStarPathPlanner { + private final NavigationGraph graph; + + public AStarPathPlanner(NavigationGraph graph) { + this.graph = graph; + } + + /** + * 规划路径 + * + * @param startNodeId 起始节点ID + * @param startDirection 起始方向 + * @param endNodeId 目标节点ID + * @param endDirection 目标方向 + * @return 路径节点序列 (包含方向信息) + */ + public List planPath(String startNodeId, int startDirection, String endNodeId, int endDirection) { + // 开放集 (优先队列) + PriorityQueue openSet = new PriorityQueue<>(); + + // 状态管理 + Map gScoreMap = new HashMap<>(); + Map cameFrom = new HashMap<>(); + + // 初始化起点 + AStarNodeState start = new AStarNodeState( + startNodeId, + startDirection, + 0, + graph.heuristicCost(startNodeId, endNodeId), + null + ); + + openSet.add(start); + gScoreMap.put(start.stateKey(), 0.0f); + + while (!openSet.isEmpty()) { + AStarNodeState current = openSet.poll(); + + // 到达目标状态 + if (current.nodeId().equals(endNodeId) && + current.direction() == endDirection) { + return reconstructPath(cameFrom, current); + } + + // 处理移动操作 (到相邻节点) + for (NavigationNode neighbor : graph.getAdjacentNodes(current.nodeId())) { + PathSegment segment = graph.getPathSegment(current.nodeId(), neighbor.id()); + if (segment == null) continue; + + float moveCost = segment.distance(); + float tentativeGCost = current.gCost() + moveCost; + String neighborKey = neighbor.id() + ":" + current.direction(); + + // 发现更好路径 + if (tentativeGCost < gScoreMap.getOrDefault(neighborKey, Float.MAX_VALUE)) { + AStarNodeState neighborState = new AStarNodeState( + neighbor.id(), + current.direction(), + tentativeGCost, + graph.heuristicCost(neighbor.id(), endNodeId), + current + ); + + cameFrom.put(neighborKey, current); + gScoreMap.put(neighborKey, tentativeGCost); + openSet.add(neighborState); + } + } + + // 处理旋转操作 (当前节点可旋转时) + NavigationNode currentNode = graph.nodes.get(current.nodeId()); + if (currentNode != null && currentNode.rotatable()) { + for (int rotation : new int[]{90, -90}) { + int newDirection = (current.direction() + rotation + 360) % 360; + float rotateCost = 1.0f; // 旋转代价 + float tentativeGCost = current.gCost() + rotateCost; + String rotatedKey = current.nodeId() + ":" + newDirection; + + // 发现更好路径 + if (tentativeGCost < gScoreMap.getOrDefault(rotatedKey, Float.MAX_VALUE)) { + AStarNodeState rotatedState = new AStarNodeState( + current.nodeId(), + newDirection, + tentativeGCost, + current.hCost(), // 旋转不改变位置,启发值不变 + current + ); + + cameFrom.put(rotatedKey, current); + gScoreMap.put(rotatedKey, tentativeGCost); + openSet.add(rotatedState); + } + } + } + } + + return Collections.emptyList(); // 未找到路径 + } + + private List reconstructPath( + Map cameFrom, + AStarNodeState endState + ) { + LinkedList path = new LinkedList<>(); + AStarNodeState current = endState; + + while (current != null) { + path.addFirst(current); + current = cameFrom.get(current.stateKey()); + } + + return path; + } +} diff --git a/servo/src/main/java/com/galaxis/rcs/plan/path/ChargerPoint.java b/servo/src/main/java/com/galaxis/rcs/plan/path/ChargerPoint.java deleted file mode 100644 index 5b36db4..0000000 --- a/servo/src/main/java/com/galaxis/rcs/plan/path/ChargerPoint.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.galaxis.rcs.plan.path; - -public class ChargerPoint { -} diff --git a/servo/src/main/java/com/galaxis/rcs/plan/path/GraphInitializer.java b/servo/src/main/java/com/galaxis/rcs/plan/path/GraphInitializer.java new file mode 100644 index 0000000..698c7a5 --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/plan/path/GraphInitializer.java @@ -0,0 +1,95 @@ +package com.galaxis.rcs.plan.path; + +import com.galaxis.rcs.common.enums.OperationSide; +import com.yvan.logisticsModel.LogisticsRuntime; +import org.clever.core.Conv; + +import java.util.List; +import java.util.Map; + +public class GraphInitializer { + + public NavigationGraph initializeGraph(LogisticsRuntime runtime, String agvType, List> jsonData) { + if (runtime.executorGraphMap.containsKey(agvType)) { + return runtime.executorGraphMap.get(agvType); + } + NavigationGraph graph = new NavigationGraph(); + runtime.executorGraphMap.put(agvType, graph); + + // 第一步:创建所有节点 + for (Map nodeData : jsonData) { + String id = (String) nodeData.get("id"); + + // 判断是否是 way 类型才创建 NavigationNode + if (!"way".equals(nodeData.get("t"))) { + continue; + } + + List> tf = (List>) nodeData.get("tf"); + float x = tf.get(0).get(0); + float z = tf.get(0).get(2); + + // 检查是否为可旋转点 + Map dt = (Map) nodeData.get("dt"); + boolean rotatable = false; + if (dt.containsKey("agvRotation")) { + rotatable = true; + } + + // 添加节点 + graph.addNode(new NavigationNode(id, x, z, rotatable)); + } + + // 第二步:添加路径连接 + for (Map nodeData : jsonData) { + if (!"way".equals(nodeData.get("t"))) continue; + + String id = (String) nodeData.get("id"); + Map dt = (Map) nodeData.get("dt"); + + List outEdges = (List) dt.get("out"); + if (outEdges != null) { + for (String neighborId : outEdges) { + if (graph.nodes.containsKey(id) && graph.nodes.containsKey(neighborId)) { + NavigationNode from = graph.nodes.get(id); + NavigationNode to = graph.nodes.get(neighborId); + graph.addBidirectionalPath(from, to); + } + } + } + } + + // 第三步:添加操作点 OperationPoint + for (Map nodeData : jsonData) { + if (!"way".equals(nodeData.get("t"))) continue; + + String nodeId = (String) nodeData.get("id"); + Map dt = (Map) nodeData.get("dt"); + + if (dt.containsKey("linkStore")) { + List> linkStores = (List>) dt.get("linkStore"); + for (Map store : linkStores) { + String targetId = (String) store.get("item"); + Integer bay = Conv.asInteger(store.get("bay")); + Integer level = Conv.asInteger(store.get("level")); + Integer cell = Conv.asInteger(store.get("cell")); + + // 根据位置确定方位(这里假设固定为 TOP,可根据 tf 中的方向判断更精确) + OperationSide side = OperationSide.TOP; + + OperationPoint point = new OperationPoint( + graph.nodes.get(nodeId), + targetId, + side, + bay, + level, + cell + ); + graph.addOperationPoint(point); + } + } + } + + return graph; + } +} diff --git a/servo/src/main/java/com/galaxis/rcs/plan/path/NavigationGraph.java b/servo/src/main/java/com/galaxis/rcs/plan/path/NavigationGraph.java new file mode 100644 index 0000000..08a4db7 --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/plan/path/NavigationGraph.java @@ -0,0 +1,69 @@ +package com.galaxis.rcs.plan.path; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +/** + * 导航图管理器 + */ +public class NavigationGraph { + final Map nodes = new ConcurrentHashMap<>(); + final Map operationPoints = new ConcurrentHashMap<>(); + final Map pathSegments = new ConcurrentHashMap<>(); + final Map> adjacencyList = new ConcurrentHashMap<>(); + + // 添加节点 + public void addNode(NavigationNode node) { + nodes.put(node.id(), node); + adjacencyList.put(node.id(), new ArrayList<>()); + } + + // 添加双向路径 + public void addBidirectionalPath(NavigationNode a, NavigationNode b) { + float distance = a.distanceTo(b); + pathSegments.put(a.id() + "->" + b.id(), new PathSegment(a, b, distance)); + pathSegments.put(b.id() + "->" + a.id(), new PathSegment(b, a, distance)); + + adjacencyList.get(a.id()).add(b); + adjacencyList.get(b.id()).add(a); + } + + // 添加操作点 + public void addOperationPoint(OperationPoint point) { + operationPoints.put(point.locationKey(), point); + } + + // 查找操作点 + public OperationPoint findOperationPoint(String locationKey) { + return operationPoints.get(locationKey); + } + + // 获取路径段 + public PathSegment getPathSegment(String startId, String endId) { + return pathSegments.get(startId + "->" + endId); + } + + // 获取相邻节点 + public List getAdjacentNodes(String nodeId) { + return adjacencyList.getOrDefault(nodeId, Collections.emptyList()); + } + + // 获取最近的旋转点 + public NavigationNode findNearestRotationPoint(String startId) { + NavigationNode start = nodes.get(startId); + if (start == null) return null; + + return nodes.values().parallelStream() + .filter(NavigationNode::rotatable) + .min(Comparator.comparing(start::distanceTo)) + .orElse(null); + } + + // 计算启发式代价 (使用欧几里得距离) + public float heuristicCost(String fromId, String toId) { + NavigationNode from = nodes.get(fromId); + NavigationNode to = nodes.get(toId); + if (from == null || to == null) return Float.MAX_VALUE; + return from.distanceTo(to); + } +} diff --git a/servo/src/main/java/com/galaxis/rcs/plan/path/NavigationNode.java b/servo/src/main/java/com/galaxis/rcs/plan/path/NavigationNode.java new file mode 100644 index 0000000..2cac8a6 --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/plan/path/NavigationNode.java @@ -0,0 +1,25 @@ +package com.galaxis.rcs.plan.path; + +import org.clever.core.Conv; + +/** + * 路标节点(地图中的顶点) + */ +public record NavigationNode( + String id, // 节点ID (如 "20", "charger1") + float x, // 向右增长 + float z, // 向下增长 (y无效) + boolean rotatable // 是否为可旋转位 +) implements Comparable { + // 计算到另一个节点的欧几里得距离 + public float distanceTo(NavigationNode other) { + float dx = this.x - other.x; + float dz = this.z - other.z; + return Conv.asFloat(Math.sqrt(dx * dx + dz * dz)); + } + + @Override + public int compareTo(NavigationNode other) { + return this.id.compareTo(other.id); + } +} diff --git a/servo/src/main/java/com/galaxis/rcs/plan/path/OperationPoint.java b/servo/src/main/java/com/galaxis/rcs/plan/path/OperationPoint.java new file mode 100644 index 0000000..3d5926d --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/plan/path/OperationPoint.java @@ -0,0 +1,33 @@ +package com.galaxis.rcs.plan.path; + +import com.galaxis.rcs.common.enums.OperationSide; + +/** + * 操作位置(取货/放货/充电点) + */ +public record OperationPoint( + NavigationNode node, // 关联的路标节点 + String targetId, // 货位ID (如 "54") 或货架ID (如 "rack1") + OperationSide side, // 方位 + Integer bay, // 列 (货架时非空) + Integer level, // 层 (货架时非空) + Integer cell // 格 (货架时非空) +) { + // 计算操作所需方向 + public int requiredDirection() { + return switch (side) { + case LEFT -> 90; + case RIGHT -> 270; + case TOP -> 0; + case BOTTOM -> 180; + }; + } + + // 位置唯一标识 + public String locationKey() { + if (bay == null || level == null || cell == null) { + return targetId; // 地堆货位 + } + return targetId + "-" + bay + "-" + level + "-" + cell; + } +} diff --git a/servo/src/main/java/com/galaxis/rcs/plan/path/PathInfoManager.java b/servo/src/main/java/com/galaxis/rcs/plan/path/PathInfoManager.java deleted file mode 100644 index 6c23db8..0000000 --- a/servo/src/main/java/com/galaxis/rcs/plan/path/PathInfoManager.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.galaxis.rcs.plan.path; - -/** - * 物流任务路径信息管理类 - */ -public class PathInfoManager { -} diff --git a/servo/src/main/java/com/galaxis/rcs/plan/path/PathSegment.java b/servo/src/main/java/com/galaxis/rcs/plan/path/PathSegment.java new file mode 100644 index 0000000..68c7b0e --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/plan/path/PathSegment.java @@ -0,0 +1,15 @@ +package com.galaxis.rcs.plan.path; + +/** + * 路径段(节点之间的连接) + */ +public record PathSegment( + NavigationNode start, // 起点节点 + NavigationNode end, // 终点节点 + float distance // 路径距离 +) { + // 路径唯一标识 + public String key() { + return start.id() + "->" + end.id(); + } +} diff --git a/servo/src/main/java/com/galaxis/rcs/plan/path/Point.java b/servo/src/main/java/com/galaxis/rcs/plan/path/Point.java deleted file mode 100644 index 3d00f7d..0000000 --- a/servo/src/main/java/com/galaxis/rcs/plan/path/Point.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.galaxis.rcs.plan.path; - -public class Point { -} diff --git a/servo/src/main/java/com/galaxis/rcs/plan/path/StorePoint.java b/servo/src/main/java/com/galaxis/rcs/plan/path/StorePoint.java deleted file mode 100644 index 3cc74a0..0000000 --- a/servo/src/main/java/com/galaxis/rcs/plan/path/StorePoint.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.galaxis.rcs.plan.path; - -public class StorePoint { -} diff --git a/servo/src/main/java/com/galaxis/rcs/plan/path/WayPoint.java b/servo/src/main/java/com/galaxis/rcs/plan/path/WayPoint.java deleted file mode 100644 index c171919..0000000 --- a/servo/src/main/java/com/galaxis/rcs/plan/path/WayPoint.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.galaxis.rcs.plan.path; - -public class WayPoint { -} diff --git a/servo/src/main/java/com/galaxis/rcs/task/TaskDispatchFactory.java b/servo/src/main/java/com/galaxis/rcs/task/TaskDispatchFactory.java index 261e40d..fcbbede 100644 --- a/servo/src/main/java/com/galaxis/rcs/task/TaskDispatchFactory.java +++ b/servo/src/main/java/com/galaxis/rcs/task/TaskDispatchFactory.java @@ -2,11 +2,15 @@ package com.galaxis.rcs.task; import com.galaxis.rcs.common.entity.RcsTaskBiz; import com.galaxis.rcs.task.dispatcher.TaiWanDispatcher; +import com.yvan.logisticsModel.ExecutorItem; import com.yvan.logisticsModel.LogisticsRuntime; +import java.util.List; + public class TaskDispatchFactory { public final LogisticsRuntime logisticsRuntime; private TaiWanDispatcher dispatcher = new TaiWanDispatcher(); + private WorkThread workThread; public TaskDispatchFactory(LogisticsRuntime logisticsRuntime) { this.logisticsRuntime = logisticsRuntime; @@ -16,16 +20,60 @@ public class TaskDispatchFactory { * 开启轮询线程,定时检查有没有空执行器,可以用于执行选定任务 */ public void startPolling() { - // TODO: 启动一个线程,定时检查是否有空闲的执行器 - RcsTaskBiz taskBiz = new RcsTaskBiz(); - dispatcher.dispatchTask(this, taskBiz); + if (workThread != null && workThread.isAlive()) { + return; // 如果线程已经在运行,则不再启动 + } + workThread = new WorkThread(this); + workThread.setName("RCS-TaskDispatchFactory-WorkThread"); + workThread.setDaemon(true); // 设置为守护线程 + workThread.start(); } /** * 停止轮询线程 */ public void stopPolling() { - // TODO: 停止轮询线程 + if (workThread != null) { + workThread.running = false; // 设置线程停止标志 + try { + workThread.join(); // 等待线程结束 + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); // 恢复中断状态 + } + workThread = null; // 清理引用 + } + } + + static class WorkThread extends Thread { + private final TaskDispatchFactory factory; + private boolean running = true; + + public WorkThread(TaskDispatchFactory factory) { + this.factory = factory; + } + + @Override + public void run() { + while (this.running) { + List executorList = this.factory.logisticsRuntime.getFreeExecutorList(); + // 获取空车 + if (!executorList.isEmpty()) { + // 获取任务 + List tasks = this.factory.logisticsRuntime.taskService.getWaitingTaskList(executorList); + if (!tasks.isEmpty()) { + // 分配任务 + this.factory.dispatcher.dispatchTask(this.factory, executorList, tasks); + } + } + + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + break; + } + } + } } /** diff --git a/servo/src/main/java/com/galaxis/rcs/task/TaskService.java b/servo/src/main/java/com/galaxis/rcs/task/TaskService.java index f686198..9590345 100644 --- a/servo/src/main/java/com/galaxis/rcs/task/TaskService.java +++ b/servo/src/main/java/com/galaxis/rcs/task/TaskService.java @@ -1,9 +1,22 @@ package com.galaxis.rcs.task; import com.galaxis.rcs.common.entity.AddTaskRequest; +import com.galaxis.rcs.common.entity.RcsTaskBiz; +import com.galaxis.rcs.common.enums.BizTaskStatus; +import com.galaxis.rcs.common.query.QRcsTaskBiz; import com.google.common.base.Strings; +import com.yvan.logisticsModel.ExecutorItem; import com.yvan.logisticsModel.LogisticsRuntime; +import org.clever.core.Conv; +import org.clever.core.json.JsonWrapper; import org.clever.data.jdbc.DaoFactory; +import org.clever.data.jdbc.QueryDSL; +import org.joda.time.DateTime; + +import java.util.Date; +import java.util.List; + +import static com.galaxis.rcs.common.query.QRcsTaskBiz.rcsTaskBiz; /** * 任务服务 @@ -11,13 +24,48 @@ import org.clever.data.jdbc.DaoFactory; */ public class TaskService { + static final QueryDSL queryDSL = DaoFactory.getQueryDSL(); public final LogisticsRuntime logisticsRuntime; + public List waitingTaskList; public TaskService(LogisticsRuntime logisticsRuntime) { this.logisticsRuntime = logisticsRuntime; } /** + * 从数据库中加载当前等待执行的任务列表 + */ + public void reload() { + this.waitingTaskList = queryDSL.select(rcsTaskBiz) + .from(rcsTaskBiz) + .where(rcsTaskBiz.bizTaskStatus.eq(BizTaskStatus.WAITING_FOR_DISPATCH.toString())) + .where(rcsTaskBiz.envId.eq(logisticsRuntime.logisticsEnv.getEnvId())) + .orderBy(rcsTaskBiz.priority.desc()) + .orderBy(rcsTaskBiz.bizTaskId.asc()) + .fetch(); + } + + /** + * 获取当前等待执行的任务列表 + */ + public List getWaitingTaskList(List executorList) { + return waitingTaskList; + } + + /** + * 从等待任务列表中移除指定的业务任务 + */ + public boolean removeFromWaitingTaskList(Long bizTaskId) { + for (RcsTaskBiz task : waitingTaskList) { + if (task.getBizTaskId().equals(bizTaskId)) { + waitingTaskList.remove(task); + return true; + } + } + return false; + } + + /** * 添加业务任务 * * @param request 任务请求 @@ -28,40 +76,27 @@ public class TaskService { throw new RuntimeException("TaskExecutorId cannot be null or empty"); } + String payload = JsonWrapper.toJson(request); + Long taskId = DaoFactory.getJdbc().nextId("rcs_task_biz"); + queryDSL.insert(rcsTaskBiz) + .set(rcsTaskBiz.bizTaskId, taskId) + .set(rcsTaskBiz.envId, logisticsRuntime.logisticsEnv.getEnvId()) + .set(rcsTaskBiz.bizType, request.type.toString()) + .set(rcsTaskBiz.lpn, request.lpn) + .set(rcsTaskBiz.priority, request.priority) + .set(rcsTaskBiz.taskFrom, request.from.toString()) + .set(rcsTaskBiz.taskTo, request.to.toString()) + .set(rcsTaskBiz.allocatedExecutorId, request.taskExecutorId) + .set(rcsTaskBiz.bizTaskPayload, payload) + .set(rcsTaskBiz.bizTaskErrorInfo, "N/A") + .set(rcsTaskBiz.bizTaskDescription, request.description) + .set(rcsTaskBiz.bizTaskStatus, BizTaskStatus.WAITING_FOR_DISPATCH.toString()) + .set(rcsTaskBiz.createAt, new Date()) + .set(rcsTaskBiz.createBy, request.createBy) + .execute(); - /** - * TODO: 插入 rcs_task_biz 表, 结构为 - * biz_task_id bigint not null, - * task_executor_id varchar(50) not null, - * task_type varchar(10) - * lpn varchar(50) - * priority integer - * task_from varchar(100) - * task_to varchar(100) - * biz_task_status varchar(10) default 'pending' - * create_at timestamp - * create_by varchar(50) - * update_at timestamp - * update_by varchar(50) - * - * create table rcs_task_biz ( - * biz_task_id bigint not null, - * task_executor_id varchar(50) not null comment '任务执行器ID' default 'N/A', - * task_type varchar(10) not null comment '任务类型' default 'carry', - * lpn varchar(50) not null comment '托盘ID', - * priority integer not null comment '任务优先级', - * task_from varchar(50) not null comment '任务起始点', - * task_to varchar(50) not null comment '任务目标点', - * biz_task_status varchar(10) default 'pending' comment '任务状态', - * create_at datetime not null comment '创建时间', - * create_by varchar(50) not null comment '创建人', - * update_at datetime not null comment '更新时间', - * update_by varchar(50) not null comment '更新人', - * - * primary key (biz_task_id) - * } - */ + logisticsRuntime.taskDispatchFactory.checkAll(); return taskId.toString(); } diff --git a/servo/src/main/java/com/galaxis/rcs/task/dispatcher/TaiWanDispatcher.java b/servo/src/main/java/com/galaxis/rcs/task/dispatcher/TaiWanDispatcher.java index eb0535c..1cb9e9d 100644 --- a/servo/src/main/java/com/galaxis/rcs/task/dispatcher/TaiWanDispatcher.java +++ b/servo/src/main/java/com/galaxis/rcs/task/dispatcher/TaiWanDispatcher.java @@ -4,24 +4,35 @@ import com.galaxis.rcs.common.entity.RcsTaskBiz; import com.galaxis.rcs.plan.Planner; import com.galaxis.rcs.plan.TaskPlannerFactory; import com.galaxis.rcs.task.TaskDispatchFactory; +import com.yvan.logisticsModel.ExecutorItem; + +import java.util.List; +import java.util.Objects; public class TaiWanDispatcher { - public void dispatchTask(TaskDispatchFactory factory, RcsTaskBiz tasks) { - // TODO: 台湾展会的任务分配逻辑 + public void dispatchTask(TaskDispatchFactory factory, List executorList, List tasks) { + // 台湾展会的任务分配逻辑 + for (ExecutorItem agv : executorList) { + String agvType = agv.getT(); + + for (RcsTaskBiz task : tasks) { + if (Objects.equals(agv.getId(), task.getAllocatedExecutorId())) { + // 按车 ID 分配任务 + this.allocateExecutorBizTask(factory, task, agv); + } + } + } } /** * TODO: 分配任务给指定的执行器 * - * @param tasks 任务对象,包含任务的详细信息 - * @param executorId 执行器ID + * @param task 任务对象,包含任务的详细信息 + * @param agv 执行器 */ - public void allocateExecutorBizTask(TaskDispatchFactory factory, RcsTaskBiz tasks, String executorId) { - // 选定了一个执行器,分配任务给它 - String executorType = executorId.substring(0, 3); // 假设执行器ID的前3位是车型标识 - - Planner planner = TaskPlannerFactory.getPlanner(executorType); - planner.executePlan(factory.logisticsRuntime, tasks, executorId); + public void allocateExecutorBizTask(TaskDispatchFactory factory, RcsTaskBiz task, ExecutorItem agv) { + Planner planner = TaskPlannerFactory.getPlanner(agv.getT()); + planner.executePlan(factory.logisticsRuntime, task, agv); } } diff --git a/servo/src/main/java/com/yvan/logisticsEnv/LogisticsEnv.java b/servo/src/main/java/com/yvan/logisticsEnv/LogisticsEnv.java index 9771c23..373262f 100644 --- a/servo/src/main/java/com/yvan/logisticsEnv/LogisticsEnv.java +++ b/servo/src/main/java/com/yvan/logisticsEnv/LogisticsEnv.java @@ -14,7 +14,7 @@ public class LogisticsEnv { private EnvStartParam startParam; // 环境ID - private String envId; + private Long envId; // 环境状态 private EnvStatus state; diff --git a/servo/src/main/java/com/yvan/logisticsModel/ExecutorItem.java b/servo/src/main/java/com/yvan/logisticsModel/ExecutorItem.java index ec36e40..deb67a0 100644 --- a/servo/src/main/java/com/yvan/logisticsModel/ExecutorItem.java +++ b/servo/src/main/java/com/yvan/logisticsModel/ExecutorItem.java @@ -16,7 +16,7 @@ public class ExecutorItem extends BaseItem { /** * 执行规划任务 */ - public void executeTaskPlanList(LogisticsRuntime runtime, RcsTaskBiz task, RcsTaskPlan[] planList) { + public void executeTaskPlanList(LogisticsRuntime runtime, RcsTaskBiz task, List planList) { if (this.currentPlanList.size() > 0) { throw new RuntimeException("has plans, please wait for the current plans to finish"); } @@ -24,4 +24,8 @@ public class ExecutorItem extends BaseItem { // TODO: 开启轮询线程,等待下一个待执行任务 // 找到对应类型的 connector,进行报文的发送 } + + public boolean isFree() { + throw new RuntimeException("not implemented yet, please implement isFree method in ExecutorItem"); + } } diff --git a/servo/src/main/java/com/yvan/logisticsModel/LogisticsRuntime.java b/servo/src/main/java/com/yvan/logisticsModel/LogisticsRuntime.java index d2f81b1..89d927a 100644 --- a/servo/src/main/java/com/yvan/logisticsModel/LogisticsRuntime.java +++ b/servo/src/main/java/com/yvan/logisticsModel/LogisticsRuntime.java @@ -1,10 +1,14 @@ package com.yvan.logisticsModel; +import com.galaxis.rcs.common.entity.RcsTaskBiz; +import com.galaxis.rcs.plan.path.NavigationGraph; import com.galaxis.rcs.task.TaskDispatchFactory; import com.galaxis.rcs.task.TaskService; +import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.yvan.logisticsEnv.LogisticsEnv; +import java.util.List; import java.util.Map; /** @@ -38,6 +42,11 @@ public class LogisticsRuntime { public final Map executorItemMap = Maps.newConcurrentMap(); /** + * AGV导航地图 车类型 t -> NavigationGraph + */ + public final Map executorGraphMap = Maps.newConcurrentMap(); + + /** * 楼层目录 catalogCode -> Floor */ public final Map floorMap = Maps.newHashMap(); @@ -45,4 +54,19 @@ public class LogisticsRuntime { public LogisticsRuntime(LogisticsEnv logisticsEnv) { this.logisticsEnv = logisticsEnv; } + + /** + * 获取当前空闲的执行器列表 + */ + public List getFreeExecutorList() { + List freeExecutorList = Lists.newArrayList(); + for (ExecutorItem executorItem : executorItemMap.values()) { + if (executorItem.isFree()) { + freeExecutorList.add(executorItem); + } + } + return freeExecutorList; + } + + } diff --git a/servo/src/main/java/com/yvan/workbench/controller/EnvController.java b/servo/src/main/java/com/yvan/workbench/controller/EnvController.java new file mode 100644 index 0000000..4aafc31 --- /dev/null +++ b/servo/src/main/java/com/yvan/workbench/controller/EnvController.java @@ -0,0 +1,31 @@ +package com.yvan.workbench.controller; + +import com.yvan.workbench.model.entity.Model; +import org.clever.core.Conv; +import org.clever.core.json.JsonWrapper; +import org.clever.data.jdbc.DaoFactory; +import org.clever.data.jdbc.QueryDSL; +import org.clever.data.jdbc.querydsl.utils.QueryDslUtils; +import org.clever.web.mvc.annotation.RequestBody; +import org.springframework.data.redis.core.query.QueryUtils; +import org.springframework.web.bind.annotation.ResponseBody; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import static com.galaxis.rcs.common.query.QLccEnvInfo.lccEnvInfo; + +public class EnvController { + static final QueryDSL queryDSL = DaoFactory.getQueryDSL(); + + @ResponseBody + public static Model>> getAllEnv(@RequestBody Map params) { + var list = queryDSL.select(QueryDslUtils.linkedMap(lccEnvInfo)) + .from(lccEnvInfo) + .where(lccEnvInfo.worldId.eq(Conv.asString(params.get("worldId")))) + .fetch(); + + return Model.newSuccess(list); + } +} diff --git a/servo/src/main/java/com/yvan/workbench/model/entity/Model.java b/servo/src/main/java/com/yvan/workbench/model/entity/Model.java new file mode 100644 index 0000000..0238e43 --- /dev/null +++ b/servo/src/main/java/com/yvan/workbench/model/entity/Model.java @@ -0,0 +1,38 @@ +package com.yvan.workbench.model.entity; + +public class Model implements java.io.Serializable { + private boolean success = false; + private T data; + private String msg = ""; + + public static Model newSuccess(T data) { + return new Model().setData(data).setSuccess(true).setMsg("操作成功"); + } + + public T getData() { + return data; + } + + public Model setData(T data) { + this.data = data; + return this; + } + + public String getMsg() { + return msg; + } + + public Model setMsg(String msg) { + this.msg = msg; + return this; + } + + public boolean isSuccess() { + return success; + } + + public Model setSuccess(boolean success) { + this.success = success; + return this; + } +} diff --git a/servo/src/main/resources/application.yml b/servo/src/main/resources/application.yml index ad026f2..90fd01e 100644 --- a/servo/src/main/resources/application.yml +++ b/servo/src/main/resources/application.yml @@ -141,6 +141,7 @@ web: read-only: false security: ignore-paths: + - '/api/**' - '/ok' - '/favicon.ico' - '/dist/**' diff --git a/servo/src/test/java/com/yvan/workbench/CodegenTest.java b/servo/src/test/java/com/yvan/workbench/CodegenTest.java index e02593b..519e9ae 100644 --- a/servo/src/test/java/com/yvan/workbench/CodegenTest.java +++ b/servo/src/test/java/com/yvan/workbench/CodegenTest.java @@ -26,9 +26,10 @@ public class CodegenTest { // .addCodegenType(CodegenType.KOTLIN_QUERYDSL) // .addCodegenType(CodegenType.DB_DOC_MARKDOWN) // .addTable("lcc_model_world"); - .addTable("rcs_task_biz") - .addTable("rcs_task_device") - .addTable("rcs_task_plan"); +// .addTable("rcs_task_biz") +// .addTable("rcs_task_device") +// .addTable("rcs_task_plan"); + .addTable("lcc_env_info"); CodegenUtils.genCode(jdbc, config); log.info("-->"); jdbc.close(); diff --git a/yvan-rcs-dev/.lck b/yvan-rcs-dev/.lck new file mode 100644 index 0000000..e69de29