From 89c21e900e3d661989c97cfb8de667745480e6a6 Mon Sep 17 00:00:00 2001 From: liyongde <1419499670@qq.com> Date: Fri, 24 Jul 2026 10:06:35 +0800 Subject: [PATCH] =?UTF-8?q?feat=EF=BC=9A=E4=BB=BB=E5=8A=A1=E5=AE=9A?= =?UTF-8?q?=E6=97=B6=E4=BB=BB=E5=8A=A1=E4=B8=8B=E5=8F=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../framework/common/util/http/AcsUtil.java | 45 +++ .../module/lms/api/LmsTaskExecuteApiImpl.java | 3 + .../transporttask/TransportTaskDO.java | 340 +++++++++--------- .../transporttask/TransportTaskMapper.java | 25 +- .../nl/module/task/job/TaskScheduleJob.java | 14 +- .../nl/module/task/job/dto/AcsBaseReqDTO.java | 22 ++ .../task/job/dto/AcsIssueResultDTO.java | 51 +++ .../nl/module/task/job/dto/AcsTaskDTO.java | 71 ++++ .../manage/TransportTaskIssueManager.java | 138 +++++++ .../transporttask/TransportTaskService.java | 5 + .../TransportTaskServiceImpl.java | 58 +-- .../nl/module/task/utils/AcsTaskUtil.java | 41 +++ .../nl/module/task/utils/package-info.java | 6 + .../module/wms/api/WmsTaskExecuteApiImpl.java | 3 + 14 files changed, 623 insertions(+), 199 deletions(-) create mode 100644 nl-framework/nl-common/src/main/java/cn/code/nl/framework/common/util/http/AcsUtil.java create mode 100644 nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/job/dto/AcsBaseReqDTO.java create mode 100644 nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/job/dto/AcsIssueResultDTO.java create mode 100644 nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/job/dto/AcsTaskDTO.java create mode 100644 nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/manage/TransportTaskIssueManager.java create mode 100644 nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/utils/AcsTaskUtil.java create mode 100644 nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/utils/package-info.java diff --git a/nl-framework/nl-common/src/main/java/cn/code/nl/framework/common/util/http/AcsUtil.java b/nl-framework/nl-common/src/main/java/cn/code/nl/framework/common/util/http/AcsUtil.java new file mode 100644 index 00000000..9bf9806c --- /dev/null +++ b/nl-framework/nl-common/src/main/java/cn/code/nl/framework/common/util/http/AcsUtil.java @@ -0,0 +1,45 @@ +package cn.code.nl.framework.common.util.http; + +import cn.code.nl.framework.common.util.json.JsonUtils; +import cn.hutool.core.util.StrUtil; + +import java.util.Collections; +import java.util.Map; + +/** + * ACS 调用工具 + */ +public class AcsUtil { + + /** + * 发送 POST 请求并解析响应 + * + * @param serverAddress ACS 服务地址 + * @param api API 路径 + * @param request 请求参数 + * @param responseType 响应类型 + * @return 响应对象 + */ + public static T post(String serverAddress, String api, Object request, Class responseType) { + String url = buildUrl(serverAddress, api); + String response = HttpUtils.post(url, headers(), JsonUtils.toJsonString(request)); + return JsonUtils.parseObject(response, responseType); + } + + /** + * 拼接服务地址和 API + */ + private static String buildUrl(String serverAddress, String api) { + String baseUrl = StrUtil.removeSuffix(serverAddress, StrUtil.SLASH); + String apiPath = StrUtil.addPrefixIfNot(api, StrUtil.SLASH); + return baseUrl + apiPath; + } + + /** + * 构建 JSON 请求头 + */ + private static Map headers() { + return Collections.singletonMap("Content-Type", "application/json;charset=UTF-8"); + } + +} diff --git a/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/api/LmsTaskExecuteApiImpl.java b/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/api/LmsTaskExecuteApiImpl.java index fb0e9fe4..994681d3 100644 --- a/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/api/LmsTaskExecuteApiImpl.java +++ b/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/api/LmsTaskExecuteApiImpl.java @@ -1,9 +1,11 @@ package cn.code.nl.module.lms.api; +import cn.code.nl.framework.common.enums.RpcConstants; import cn.code.nl.framework.execute.biz.api.AbstractTaskCommonApiImpl; import cn.code.nl.framework.execute.biz.api.lms.LmsTaskCommonApi; import org.springframework.context.annotation.Primary; import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** @@ -14,5 +16,6 @@ import org.springframework.web.bind.annotation.RestController; @RestController @Validated @Primary +@RequestMapping(RpcConstants.LMS_PREFIX) public class LmsTaskExecuteApiImpl extends AbstractTaskCommonApiImpl implements LmsTaskCommonApi { } diff --git a/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/dal/dataobject/transporttask/TransportTaskDO.java b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/dal/dataobject/transporttask/TransportTaskDO.java index 687fbc6c..1c4c393d 100644 --- a/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/dal/dataobject/transporttask/TransportTaskDO.java +++ b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/dal/dataobject/transporttask/TransportTaskDO.java @@ -1,170 +1,170 @@ -package cn.code.nl.module.task.dal.dataobject.transporttask; - -import lombok.*; -import java.util.*; -import java.time.LocalDateTime; -import java.time.LocalDateTime; -import com.baomidou.mybatisplus.annotation.*; -import cn.code.nl.framework.mybatis.core.dataobject.BaseDO; - -/** - * 搬运任务 DO - * - * @author 诺力管理员 - */ -@TableName("task_transport_job") -@KeySequence("task_transport_job_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 -@Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class TransportTaskDO extends BaseDO { - - /** - * 任务标识 - */ - @TableId - private Long taskId; - /** - * 任务编码 - */ - private String taskCode; - /** - * 任务名称 - */ - private String taskName; - /** - * 业务归属服务:LMS/WMS,用于完成取消事件一级路由 - */ - private String ownerService; - /** - * 业务类型 - */ - private String bizType; - /** - * 业务侧标识 - */ - private String bizId; - /** - * 业务回调处理器编码 - */ - private String handleCode; - /** - * 任务类型 - */ - private String taskType; - /** - * 任务状态 - */ - private String taskStatus; - /** - * ACS任务类型 - */ - private String acsTaskType; - /** - * AGV系统类型 - */ - private String agvSystemType; - /** - * ACS外部任务号 - */ - private String externalTaskNo; - /** - * 取货点1 - */ - private String pointCode1; - /** - * 放货点1 - */ - private String pointCode2; - /** - * 取货点2 - */ - private String pointCode3; - /** - * 放货点2 - */ - private String pointCode4; - /** - * 载具类型 - */ - private String vehicleType; - /** - * 载具数量 - */ - private Long vehicleQty; - /** - * 载具编码 - */ - private String vehicleCode; - /** - * 载具编码2 - */ - private String vehicleCode2; - /** - * 车号 - */ - private String carNo; - /** - * 优先级 - */ - private String priority; - /** - * 生产区域 - */ - private String productArea; - /** - * 是否自动下发 - */ - private String isAutoIssue; - /** - * 任务组标识 - */ - private Long taskGroupId; - /** - * 任务组顺序号 - */ - private Long sortSeq; - /** - * 任务完成类型 - */ - private String finishedType; - /** - * 业务回调状态:PENDING/SUCCESS/FAILED - */ - private String callbackStatus; - /** - * 业务回调重试次数 - */ - private Integer callbackRetryCount; - /** - * 业务回调失败原因 - */ - private String callbackErrorMsg; - /** - * 生成方式 - * - * 枚举 {@link TODO user_type 对应的类} - */ - private String createMode; - /** - * 创建任务请求参数 - */ - private String requestParam; - /** - * 下发ACS的AcsTaskDto扩展报文 - */ - private String dispatchParam; - /** - * ACS反馈参数 - */ - private String resultParam; - /** - * 备注 - */ - private String remark; - - -} \ No newline at end of file +package cn.code.nl.module.task.dal.dataobject.transporttask; + +import lombok.*; +import java.util.*; +import java.time.LocalDateTime; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.*; +import cn.code.nl.framework.mybatis.core.dataobject.BaseDO; + +/** + * 搬运任务 DO + * + * @author 诺力管理员 + */ +@TableName("task_transport_job") +@KeySequence("task_transport_job_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class TransportTaskDO extends BaseDO { + + /** + * 任务标识 + */ + @TableId + private Long taskId; + /** + * 任务编码 + */ + private String taskCode; + /** + * 任务名称 + */ + private String taskName; + /** + * 业务归属服务:LMS/WMS,用于完成取消事件一级路由 + */ + private String ownerService; + /** + * 业务类型 + */ + private String bizType; + /** + * 业务侧标识 + */ + private String bizId; + /** + * 业务回调处理器编码 + */ + private String handleCode; + /** + * 任务类型 + */ + private String taskType; + /** + * 任务状态 + */ + private String taskStatus; + /** + * ACS任务类型 + */ + private String acsTaskType; + /** + * AGV系统类型 + */ + private String agvSystemType; + /** + * ACS外部任务号 + */ + private String externalTaskNo; + /** + * 取货点1 + */ + private String pointCode1; + /** + * 放货点1 + */ + private String pointCode2; + /** + * 取货点2 + */ + private String pointCode3; + /** + * 放货点2 + */ + private String pointCode4; + /** + * 载具类型 + */ + private String vehicleType; + /** + * 载具数量 + */ + private Long vehicleQty; + /** + * 载具编码 + */ + private String vehicleCode; + /** + * 载具编码2 + */ + private String vehicleCode2; + /** + * 车号 + */ + private String carNo; + /** + * 优先级 + */ + private String priority; + /** + * 生产区域 + */ + private String productArea; + /** + * 是否自动下发 + */ + private String isAutoIssue; + /** + * 任务组标识 + */ + private Long taskGroupId; + /** + * 任务组顺序号 + */ + private Long sortSeq; + /** + * 任务完成类型 + */ + private String finishedType; + /** + * 业务回调状态:PENDING/SUCCESS/FAILED + */ + private String callbackStatus; + /** + * 业务回调重试次数 + */ + private Integer callbackRetryCount; + /** + * 业务回调失败原因 + */ + private String callbackErrorMsg; + /** + * 生成方式 + * + * 枚举 + */ + private String createMode; + /** + * 创建任务请求参数 + */ + private String requestParam; + /** + * 下发ACS的AcsTaskDto扩展报文 + */ + private String dispatchParam; + /** + * ACS反馈参数 + */ + private String resultParam; + /** + * 备注 + */ + private String remark; + + +} diff --git a/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/dal/mysql/transporttask/TransportTaskMapper.java b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/dal/mysql/transporttask/TransportTaskMapper.java index 8acdbfac..5e52125a 100644 --- a/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/dal/mysql/transporttask/TransportTaskMapper.java +++ b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/dal/mysql/transporttask/TransportTaskMapper.java @@ -66,6 +66,17 @@ public interface TransportTaskMapper extends BaseMapperX { return selectOne(TransportTaskDO::getTaskCode, taskCode); } + /** + * 查询自动下发的待下发任务 + */ + default List selectAutoIssueReadyList() { + return selectList(new LambdaQueryWrapperX() + .eq(TransportTaskDO::getIsAutoIssue, "1") + .eq(TransportTaskDO::getTaskStatus, TransportTaskStatusEnum.READY.getCode()) + .orderByDesc(TransportTaskDO::getPriority) + .orderByAsc(TransportTaskDO::getTaskId)); + } + /** * 按业务归属查询未完结任务(幂等校验用) */ @@ -87,4 +98,16 @@ public interface TransportTaskMapper extends BaseMapperX { return update(null, wrapper) > 0; } -} \ No newline at end of file + /** + * 更新下发结果 + */ + default void updateIssueResult(Long taskId, String taskStatus, String resultParam, String remark) { + TransportTaskDO updateObj = new TransportTaskDO(); + updateObj.setTaskId(taskId); + updateObj.setTaskStatus(taskStatus); + updateObj.setResultParam(resultParam); + updateObj.setRemark(remark); + updateById(updateObj); + } + +} diff --git a/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/job/TaskScheduleJob.java b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/job/TaskScheduleJob.java index 3fc005da..40540120 100644 --- a/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/job/TaskScheduleJob.java +++ b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/job/TaskScheduleJob.java @@ -1,28 +1,38 @@ package cn.code.nl.module.task.job; import cn.code.nl.framework.tenant.core.job.TenantJob; +import cn.code.nl.module.task.service.transporttask.TransportTaskService; import com.xxl.job.core.context.XxlJobHelper; import com.xxl.job.core.handler.annotation.XxlJob; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; /** * 任务相关的定时任务 + * * @Author: liyongde * @Date: 2026/7/13 14:01 */ +@Slf4j @Component public class TaskScheduleJob { + @Resource + private TransportTaskService transportTaskService; + @XxlJob("autoTaskAssignmentJob") @TenantJob public void autoTaskAssignmentJob() { + log.info("自动下发任务开始....."); XxlJobHelper.log("自动下发任务开始"); - // todo: 具体业务 + transportTaskService.autoIssueTransportTasks(); - String msg = "自动下发任务成功"; + String msg = "自动下发任务结束"; XxlJobHelper.log(msg); XxlJobHelper.handleSuccess(msg); + log.info(msg); } } diff --git a/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/job/dto/AcsBaseReqDTO.java b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/job/dto/AcsBaseReqDTO.java new file mode 100644 index 00000000..a920d0c8 --- /dev/null +++ b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/job/dto/AcsBaseReqDTO.java @@ -0,0 +1,22 @@ +package cn.code.nl.module.task.job.dto; + +import lombok.Data; + +/** + * 基础DTO对象 + * @Author: liyongde + * @Date: 2026/7/24 8:49 + */ +@Data +public class AcsBaseReqDTO { + /** + * 请求号: traceId + */ + private String traceId; + + /** + * + * 时间 + */ + private Long timestamp; +} diff --git a/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/job/dto/AcsIssueResultDTO.java b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/job/dto/AcsIssueResultDTO.java new file mode 100644 index 00000000..b8bd4422 --- /dev/null +++ b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/job/dto/AcsIssueResultDTO.java @@ -0,0 +1,51 @@ +package cn.code.nl.module.task.job.dto; + +import lombok.Data; + +import java.util.List; + +/** + * ACS 任务下发响应 + */ +@Data +public class AcsIssueResultDTO { + + /** + * 是否整体成功 + */ + private Boolean success; + + /** + * 响应编码 + */ + private String code; + + /** + * 响应消息 + */ + private String msg; + + /** + * 下发失败的任务 + */ + private List failedTasks; + + /** + * ACS 失败任务明细 + */ + @Data + public static class FailedTask { + + /** + * 任务标识 + */ + private Long taskId; + + /** + * 错误信息 + */ + private String errorMessage; + + } + +} diff --git a/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/job/dto/AcsTaskDTO.java b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/job/dto/AcsTaskDTO.java new file mode 100644 index 00000000..0c3a2153 --- /dev/null +++ b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/job/dto/AcsTaskDTO.java @@ -0,0 +1,71 @@ +package cn.code.nl.module.task.job.dto; + +import lombok.Data; + +import java.util.Map; + +/** + * 下发给ACS的实体 + * @Author: liyongde + * @Date: 2026/7/23 17:10 + */ +@Data +public class AcsTaskDTO extends AcsBaseReqDTO{ + /** + * 任务标识 + */ + private Long taskId; + /** + * 任务编码 + */ + private String taskCode; + /** + * 取货点1 + */ + private String startDeviceCode; + /** + * 放货点1 + */ + private String nextDeviceCode; + /** + * 取货点2 + */ + private String startDeviceCode2; + /** + * 放货点2 + */ + private String nextDeviceCode2; + /** + * 优先级 + */ + private String priority; + /** + * 载具号 + */ + private String vehicleCode; + /** + * 载具号2 + */ + private String vehicleCode2; + /** + * 任务类型 + */ + private String taskType; + /** + * Agv系统类型 + */ + private String agvSystemType; + + /** + * 备注 + */ + private String remark; + /** + * 扩展参数 + */ + private Map payload; + /** + * 生产区域 + */ + private String productArea; +} diff --git a/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/manage/TransportTaskIssueManager.java b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/manage/TransportTaskIssueManager.java new file mode 100644 index 00000000..4224dd45 --- /dev/null +++ b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/manage/TransportTaskIssueManager.java @@ -0,0 +1,138 @@ +package cn.code.nl.module.task.manage; + +import cn.code.nl.framework.common.exception.ServiceException; +import cn.code.nl.framework.common.pojo.CommonResult; +import cn.code.nl.framework.common.util.http.AcsUtil; +import cn.code.nl.framework.common.util.json.JsonUtils; +import cn.code.nl.module.infra.api.config.ConfigApi; +import cn.code.nl.module.task.dal.dataobject.transporttask.TransportTaskDO; +import cn.code.nl.module.task.dal.mysql.transporttask.TransportTaskMapper; +import cn.code.nl.module.task.enums.TransportTaskStatusEnum; +import cn.code.nl.module.task.job.dto.AcsIssueResultDTO; +import cn.code.nl.module.task.job.dto.AcsTaskDTO; +import cn.code.nl.module.task.utils.AcsTaskUtil; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * 搬运任务下发管理器 + */ +@Slf4j +@Component +public class TransportTaskIssueManager { + + private static final String ACS_TASK_API = "/acs-api/wms/task"; + private static final String ACS_SERVER_ADDRESS_CONFIG_SUFFIX = "-acs-server-address"; + + @Resource + private TransportTaskMapper transportTaskMapper; + + @Resource + private ConfigApi configApi; + + /** + * 按生产区域分组下发任务 + * + * @param tasks 待下发任务 + */ + public void issueTasks(List tasks) { + tasks.stream() + .filter(task -> StrUtil.isBlank(task.getProductArea())) + .forEach(task -> + updateIssueFailed(task.getTaskId(), "生产区域为空,无法获取 ACS 服务地址", null)); + Map> taskMap = tasks.stream() + .filter(task -> StrUtil.isNotBlank(task.getProductArea())) + .collect(Collectors.groupingBy(TransportTaskDO::getProductArea)); + taskMap.forEach(this::issueProductAreaTasks); + } + + /** + * 下发单个生产区域的任务 + * + * @param productArea 生产区域 + * @param tasks 待下发任务 + */ + private void issueProductAreaTasks(String productArea, List tasks) { + List acsTasks = tasks.stream().map(AcsTaskUtil::buildAcsTaskDTO).toList(); + String requestJson = JsonUtils.toJsonString(acsTasks); + try { + String serverAddress = getAcsServerAddress(productArea); + AcsIssueResultDTO result = AcsUtil.post(serverAddress, ACS_TASK_API, acsTasks, AcsIssueResultDTO.class); + handleIssueResult(tasks, result); + } catch (Exception ex) { + log.error("自动下发任务失败,productArea={},tasks={}", productArea, requestJson, ex); + tasks.forEach(task -> updateIssueFailed(task.getTaskId(), ex.getMessage(), null)); + } + } + + /** + * 获取 ACS 服务地址 + * + * @param productArea 生产区域 + * @return ACS 服务地址 + */ + private String getAcsServerAddress(String productArea) { + String configKey = productArea + ACS_SERVER_ADDRESS_CONFIG_SUFFIX; + CommonResult result = configApi.getConfigValueByKey(configKey); + String serverAddress = result.getCheckedData(); + if (StrUtil.isBlank(serverAddress)) { + throw new ServiceException(500, "未配置 ACS 服务地址:" + configKey); + } + return serverAddress; + } + + /** + * 处理 ACS 下发响应 + * + * @param tasks 本次下发任务 + * @param result ACS 响应 + */ + private void handleIssueResult(List tasks, AcsIssueResultDTO result) { + if (result == null) { + tasks.forEach(task -> updateIssueFailed(task.getTaskId(), "ACS 返回为空", null)); + return; + } + String resultJson = JsonUtils.toJsonString(result); + List failedTasks = result.getFailedTasks() == null + ? Collections.emptyList() + : result.getFailedTasks(); + if (Boolean.FALSE.equals(result.getSuccess()) && CollUtil.isEmpty(failedTasks)) { + String errorMessage = StrUtil.blankToDefault(result.getMsg(), "ACS 下发失败"); + tasks.forEach(task -> updateIssueFailed(task.getTaskId(), errorMessage, resultJson)); + return; + } + Map failedTaskMap = failedTasks.stream() + .filter(failedTask -> failedTask.getTaskId() != null) + .collect(Collectors.toMap(AcsIssueResultDTO.FailedTask::getTaskId, Function.identity(), (first, second) -> first)); + Set failedTaskIds = failedTaskMap.keySet(); + for (TransportTaskDO task : tasks) { + if (failedTaskIds.contains(task.getTaskId())) { + updateIssueFailed(task.getTaskId(), failedTaskMap.get(task.getTaskId()).getErrorMessage(), resultJson); + } else { + transportTaskMapper.updateIssueResult(task.getTaskId(), TransportTaskStatusEnum.ISSUED.getCode(), resultJson, null); + } + } + } + + /** + * 更新任务为下发失败 + * + * @param taskId 任务标识 + * @param errorMessage 错误信息 + * @param resultJson ACS 响应 JSON + */ + private void updateIssueFailed(Long taskId, String errorMessage, String resultJson) { + transportTaskMapper.updateIssueResult(taskId, TransportTaskStatusEnum.FAILED.getCode(), resultJson, errorMessage); + } + +} diff --git a/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/service/transporttask/TransportTaskService.java b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/service/transporttask/TransportTaskService.java index b7fdb0ef..5e46ec7d 100644 --- a/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/service/transporttask/TransportTaskService.java +++ b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/service/transporttask/TransportTaskService.java @@ -92,4 +92,9 @@ public interface TransportTaskService { */ TaskInfoDTO getTaskInfoByCode(String taskCode); + /** + * 自动下发待下发任务到 ACS + */ + void autoIssueTransportTasks(); + } diff --git a/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/service/transporttask/TransportTaskServiceImpl.java b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/service/transporttask/TransportTaskServiceImpl.java index f8e26b69..b923ee1a 100644 --- a/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/service/transporttask/TransportTaskServiceImpl.java +++ b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/service/transporttask/TransportTaskServiceImpl.java @@ -11,8 +11,13 @@ import cn.code.nl.module.task.dal.mysql.transporttask.TransportTaskMapper; import cn.code.nl.module.task.dto.AcsFeedbackReqDTO; import cn.code.nl.module.task.dto.TaskInfoDTO; import cn.code.nl.module.task.dto.TransportTaskCreateReqDTO; -import cn.code.nl.module.task.enums.*; +import cn.code.nl.module.task.enums.CallbackStatusEnum; +import cn.code.nl.module.task.enums.FinishedTypeEnum; +import cn.code.nl.module.task.enums.TaskOperationTypeEnum; +import cn.code.nl.module.task.enums.TransportTaskStatusEnum; +import cn.code.nl.module.task.manage.TransportTaskIssueManager; import cn.code.nl.module.task.manage.TransportTaskOperationManager; +import cn.hutool.core.collection.CollUtil; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -42,21 +47,19 @@ public class TransportTaskServiceImpl implements TransportTaskService { @Resource private TransportTaskOperationManager transportTaskOperationManager; + @Resource + private TransportTaskIssueManager transportTaskIssueManager; + @Override public Long createTransportTask(TransportTaskSaveReqVO createReqVO) { - // 插入 TransportTaskDO transportTask = BeanUtils.toBean(createReqVO, TransportTaskDO.class); transportTaskMapper.insert(transportTask); - - // 返回 return transportTask.getTaskId(); } @Override public Long createTransportTaskByRpc(TransportTaskCreateReqDTO reqDTO) { - // 1. 构建 DO 并保存 TransportTaskDO task = BeanUtils.toBean(reqDTO, TransportTaskDO.class); - // 参数完整 → 待下发(040),否则 → 生成(010) task.setTaskStatus(reqDTO.getIsCreateFinish() ? TransportTaskStatusEnum.READY.getCode() : TransportTaskStatusEnum.CREATED.getCode()); @@ -70,28 +73,27 @@ public class TransportTaskServiceImpl implements TransportTaskService { @Override public void updateTransportTask(TransportTaskSaveReqVO updateReqVO) { - // 校验存在 validateTransportTaskExists(updateReqVO.getTaskId()); - // 更新 TransportTaskDO updateObj = BeanUtils.toBean(updateReqVO, TransportTaskDO.class); transportTaskMapper.updateById(updateObj); } @Override public void deleteTransportTask(Long id) { - // 校验存在 validateTransportTaskExists(id); - // 删除 transportTaskMapper.deleteById(id); } @Override - public void deleteTransportTaskListByIds(List ids) { - // 删除 + public void deleteTransportTaskListByIds(List ids) { transportTaskMapper.deleteByIds(ids); - } - + } + /** + * 校验搬运任务是否存在 + * + * @param id 任务标识 + */ private void validateTransportTaskExists(Long id) { if (transportTaskMapper.selectById(id) == null) { throw exception(TRANSPORT_TASK_NOT_EXISTS); @@ -109,55 +111,59 @@ public class TransportTaskServiceImpl implements TransportTaskService { } /** - * PC 端操作搬运任务(完成/取消/强制完成):先校验再走统一路由表分发 + * PC 端操作搬运任务,统一走状态操作分发 + * + * @param reqVO 操作请求 */ @Override @Transactional(rollbackFor = Exception.class) public void operateTransportTask(TransportTaskOperateReqVO reqVO) { - // 1. 校验任务存在 TransportTaskDO task = transportTaskMapper.selectById(reqVO.getTaskId()); if (task == null) { throw exception(TRANSPORT_TASK_NOT_EXISTS); } - // 2. 校验操作类型允许 PC 端触发 TaskOperationTypeEnum type = TaskOperationTypeEnum.getByCode(reqVO.getOperationType()); if (type == null || !type.isPcAllowed()) { throw exception(TRANSPORT_TASK_OPERATION_NOT_SUPPORTED); } - // 3. 终态校验:已完成/已取消不允许再操作 if (TransportTaskStatusEnum.FINISHED.getCode().equals(task.getTaskStatus()) || TransportTaskStatusEnum.CANCELLED.getCode().equals(task.getTaskStatus())) { throw exception(TRANSPORT_TASK_ALREADY_FINAL); } - // 4. PC 端与 ACS 的差异点:记录完成类型 if (type == TaskOperationTypeEnum.FINISHED) { task.setFinishedType(FinishedTypeEnum.MANUAL.getCode()); } else if (type == TaskOperationTypeEnum.FORCE_FINISH) { task.setFinishedType(FinishedTypeEnum.MANUAL_FORCE.getCode()); } - // 5. 构造精简反馈对象,走统一路由表分发 AcsFeedbackReqDTO reqDTO = new AcsFeedbackReqDTO(); reqDTO.setTaskId(task.getTaskId()); reqDTO.setStatus(type.getCode()); transportTaskOperationManager.dispatchOperation(task, type, reqDTO); } - /** - * 根据 taskId 查询任务全量信息:查不到返回 null,由调用方判断 - */ @Override public TaskInfoDTO getTaskInfoById(Long taskId) { TransportTaskDO task = transportTaskMapper.selectById(taskId); return TransportTaskConvert.INSTANCE.convert(task); } - /** - * 根据 taskCode 查询任务全量信息:查不到返回 null,由调用方判断 - */ @Override public TaskInfoDTO getTaskInfoByCode(String taskCode) { TransportTaskDO task = transportTaskMapper.selectByTaskCode(taskCode); return TransportTaskConvert.INSTANCE.convert(task); } + /** + * 查询待下发任务,并委托下发管理器按生产区域下发到 ACS + */ + @Override + public void autoIssueTransportTasks() { + List tasks = transportTaskMapper.selectAutoIssueReadyList(); + if (CollUtil.isEmpty(tasks)) { + log.info("自动下发任务结束:没有待下发任务"); + return; + } + transportTaskIssueManager.issueTasks(tasks); + } + } diff --git a/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/utils/AcsTaskUtil.java b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/utils/AcsTaskUtil.java new file mode 100644 index 00000000..418f7956 --- /dev/null +++ b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/utils/AcsTaskUtil.java @@ -0,0 +1,41 @@ +package cn.code.nl.module.task.utils; + +import cn.code.nl.framework.common.util.json.JsonUtils; +import cn.code.nl.module.task.dal.dataobject.transporttask.TransportTaskDO; +import cn.code.nl.module.task.job.dto.AcsTaskDTO; + +import java.util.UUID; + +/** + * ACS 任务工具类 + */ +public class AcsTaskUtil { + + /** + * 构建 ACS 下发任务 + * + * @param task 搬运任务 + * @return ACS 下发任务 + */ + public static AcsTaskDTO buildAcsTaskDTO(TransportTaskDO task) { + AcsTaskDTO dto = new AcsTaskDTO(); + dto.setTraceId(UUID.randomUUID().toString()); + dto.setTimestamp(System.currentTimeMillis()); + dto.setTaskId(task.getTaskId()); + dto.setTaskCode(task.getTaskCode()); + dto.setStartDeviceCode(task.getPointCode1()); + dto.setNextDeviceCode(task.getPointCode2()); + dto.setStartDeviceCode2(task.getPointCode3()); + dto.setNextDeviceCode2(task.getPointCode4()); + dto.setPriority(task.getPriority()); + dto.setVehicleCode(task.getVehicleCode()); + dto.setVehicleCode2(task.getVehicleCode2()); + dto.setTaskType(task.getAcsTaskType()); + dto.setAgvSystemType(task.getAgvSystemType()); + dto.setRemark(task.getRemark()); + dto.setPayload(JsonUtils.parseMap(task.getDispatchParam())); + dto.setProductArea(task.getProductArea()); + return dto; + } + +} diff --git a/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/utils/package-info.java b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/utils/package-info.java new file mode 100644 index 00000000..136b5a0c --- /dev/null +++ b/nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/utils/package-info.java @@ -0,0 +1,6 @@ +/** + * 本模块业务员这中使用工具类 + * @Author: liyongde + * @Date: 2026/7/23 17:02 + */ +package cn.code.nl.module.task.utils; \ No newline at end of file diff --git a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/api/WmsTaskExecuteApiImpl.java b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/api/WmsTaskExecuteApiImpl.java index 33a7fc44..d1710fc2 100644 --- a/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/api/WmsTaskExecuteApiImpl.java +++ b/nl-module-wms/nl-module-wms-server/src/main/java/cn/code/nl/module/wms/api/WmsTaskExecuteApiImpl.java @@ -1,9 +1,11 @@ package cn.code.nl.module.wms.api; +import cn.code.nl.framework.common.enums.RpcConstants; import cn.code.nl.framework.execute.biz.api.AbstractTaskCommonApiImpl; import cn.code.nl.framework.execute.biz.api.wms.WmsTaskCommonApi; import org.springframework.context.annotation.Primary; import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** @@ -14,5 +16,6 @@ import org.springframework.web.bind.annotation.RestController; @RestController @Validated @Primary +@RequestMapping(RpcConstants.WMS_PREFIX) public class WmsTaskExecuteApiImpl extends AbstractTaskCommonApiImpl implements WmsTaskCommonApi { }