fix: ACS、PC对任务状态的变化
This commit is contained in:
697
docs/superpowers/plans/2026-07-15-task-operation-refactor.md
Normal file
697
docs/superpowers/plans/2026-07-15-task-operation-refactor.md
Normal file
@@ -0,0 +1,697 @@
|
||||
# 搬运任务操作路由表重构 + PC 端操作接口 实现计划
|
||||
|
||||
> **面向 AI 代理的工作者:** 必需子技能:使用 superpowers:subagent-driven-development(推荐)或 superpowers:executing-plans 逐任务实现此计划。步骤使用复选框(`- [ ]`)语法来跟踪进度。
|
||||
|
||||
**目标:** 消灭 ACS 反馈的 if-else 分发,改为 `TransportTaskServiceImpl` 内的枚举路由表;新增 PC 端统一操作接口(完成/取消/强制完成)并打通前端按钮。
|
||||
|
||||
**架构:** `TaskOperationTypeEnum` 增加 acsAllowed/pcAllowed 属性与 `getByCode` 解析;`TransportTaskServiceImpl` 持有 `EnumMap<操作类型, BiConsumer>` 路由表,`handle*` 业务方法原样迁入;`TransportTaskFeedbackServiceImpl` 瘦身为 ACS 前置处理层后委托分发;PC 入口 `POST /task/transport-task/operate` 走同一路由表,差异仅在前置校验(抛异常)与记录 finishedType。
|
||||
|
||||
**技术栈:** Java 17 / Spring Boot / MyBatis-Plus(后端);Vue 3 + Vben + antdv-next(前端)
|
||||
|
||||
**规格:** `docs/superpowers/specs/2026-07-15-task-operation-refactor-design.md`
|
||||
|
||||
**约定(来自 CLAUDE.md 与 nl-java-style):** 注释/日志用中文;注入用 `@Resource`;不写测试;不频繁 commit(最后统一一次,需用户同意);枚举解析方法命名 `getByCode`。
|
||||
|
||||
---
|
||||
|
||||
## 文件结构
|
||||
|
||||
| 文件 | 操作 | 职责 |
|
||||
|---|---|---|
|
||||
| `nl-module-task/nl-module-task-api/src/main/java/cn/code/nl/module/task/enums/TaskOperationTypeEnum.java` | 修改 | 操作类型枚举:增加入口允许标记与 getByCode 解析 |
|
||||
| `nl-module-task/nl-module-task-api/src/main/java/cn/code/nl/module/task/enums/ErrorCodeConstants.java` | 修改 | 新增 PC 操作两个错误码 |
|
||||
| `nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/controller/admin/transporttask/vo/TransportTaskOperateReqVO.java` | 创建 | PC 操作请求 VO |
|
||||
| `nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/service/transporttask/TransportTaskService.java` | 修改 | 接口新增 operateTransportTask / dispatchOperation |
|
||||
| `nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/service/transporttask/TransportTaskServiceImpl.java` | 修改 | 路由表 + handle* 迁入 + PC 入口 |
|
||||
| `nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/service/transporttask/TransportTaskFeedbackServiceImpl.java` | 修改 | 瘦身为 ACS 前置处理层 |
|
||||
| `nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/controller/admin/transporttask/TransportTaskController.java` | 修改 | 新增 POST /operate |
|
||||
| `nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/api/task/transporttask/index.ts` | 修改 | 新增 operateTransportTask API |
|
||||
| `nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/views/task/transporttask/index.vue` | 修改 | 三个按钮绑定 handleOperate |
|
||||
|
||||
---
|
||||
|
||||
### 任务 1:枚举增强 `TaskOperationTypeEnum`
|
||||
|
||||
**文件:**
|
||||
- 修改:`nl-module-task/nl-module-task-api/src/main/java/cn/code/nl/module/task/enums/TaskOperationTypeEnum.java`
|
||||
|
||||
- [ ] **步骤 1:整体替换为以下内容**
|
||||
|
||||
```java
|
||||
package cn.code.nl.module.task.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 任务操作类型枚举
|
||||
* <p>
|
||||
* acsAllowed:是否允许 ACS 反馈触发;pcAllowed:是否允许 PC 端触发
|
||||
*
|
||||
* @Author: liyongde
|
||||
* @Date: 2026/7/15 19:11
|
||||
*/
|
||||
@Getter
|
||||
public enum TaskOperationTypeEnum {
|
||||
|
||||
EXECUTING("EXECUTING", "执行中", true, false),
|
||||
|
||||
PICKED("PICKED", "取货完成", true, false),
|
||||
|
||||
FINISHED("FINISHED", "完成任务", true, true),
|
||||
|
||||
CANCELLED("CANCELLED", "取消任务", true, true),
|
||||
|
||||
APPLY_AGAIN("APPLY-AGAIN", "二次请求", true, false),
|
||||
|
||||
FORCE_FINISH("FORCE-FINISH", "强制完成", false, true);
|
||||
|
||||
/** 操作编码 */
|
||||
private final String code;
|
||||
/** 操作名称 */
|
||||
private final String name;
|
||||
/** 是否允许 ACS 反馈触发 */
|
||||
private final boolean acsAllowed;
|
||||
/** 是否允许 PC 端触发 */
|
||||
private final boolean pcAllowed;
|
||||
|
||||
TaskOperationTypeEnum(String code, String name, boolean acsAllowed, boolean pcAllowed) {
|
||||
this.code = code;
|
||||
this.name = name;
|
||||
this.acsAllowed = acsAllowed;
|
||||
this.pcAllowed = pcAllowed;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据编码解析枚举(忽略大小写),找不到返回 null
|
||||
*/
|
||||
public static TaskOperationTypeEnum getByCode(String code) {
|
||||
for (TaskOperationTypeEnum type : values()) {
|
||||
if (type.getCode().equalsIgnoreCase(code)) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 任务 2:新增错误码
|
||||
|
||||
**文件:**
|
||||
- 修改:`nl-module-task/nl-module-task-api/src/main/java/cn/code/nl/module/task/enums/ErrorCodeConstants.java`
|
||||
|
||||
- [ ] **步骤 1:在 `TRANSPORT_TASK_RUNNING_ALREADY_EXIST` 之后追加两行**
|
||||
|
||||
```java
|
||||
ErrorCode TRANSPORT_TASK_OPERATION_NOT_SUPPORTED = new ErrorCode(5006, "不支持的任务操作类型");
|
||||
ErrorCode TRANSPORT_TASK_ALREADY_FINAL = new ErrorCode(5007, "任务已处于终态,不允许操作");
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 任务 3:新增 `TransportTaskOperateReqVO`
|
||||
|
||||
**文件:**
|
||||
- 创建:`nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/controller/admin/transporttask/vo/TransportTaskOperateReqVO.java`
|
||||
|
||||
- [ ] **步骤 1:创建文件**
|
||||
|
||||
```java
|
||||
package cn.code.nl.module.task.controller.admin.transporttask.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* PC 端搬运任务操作 Request VO
|
||||
*
|
||||
* @Author: liyongde
|
||||
* @Date: 2026/7/15
|
||||
*/
|
||||
@Schema(description = "管理后台 - PC 端搬运任务操作 Request VO")
|
||||
@Data
|
||||
public class TransportTaskOperateReqVO {
|
||||
|
||||
@Schema(description = "任务ID", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "任务ID不能为空")
|
||||
private Long taskId;
|
||||
|
||||
@Schema(description = "操作类型:FINISHED/CANCELLED/FORCE-FINISH", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotEmpty(message = "操作类型不能为空")
|
||||
private String operationType;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 任务 4:`TransportTaskService` 接口新增方法
|
||||
|
||||
**文件:**
|
||||
- 修改:`nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/service/transporttask/TransportTaskService.java`
|
||||
|
||||
- [ ] **步骤 1:新增 import**
|
||||
|
||||
在现有 import 区追加(`vo.*` 通配已覆盖新 VO,无需单独引入):
|
||||
|
||||
```java
|
||||
import cn.code.nl.module.task.dto.AcsFeedbackReqDTO;
|
||||
import cn.code.nl.module.task.enums.TaskOperationTypeEnum;
|
||||
```
|
||||
|
||||
- [ ] **步骤 2:在 `getTransportTaskPage` 方法之后新增两个方法声明**
|
||||
|
||||
```java
|
||||
/**
|
||||
* PC 端操作搬运任务(完成/取消/强制完成)
|
||||
*
|
||||
* @param reqVO 操作请求
|
||||
*/
|
||||
void operateTransportTask(@Valid TransportTaskOperateReqVO reqVO);
|
||||
|
||||
/**
|
||||
* 按操作类型分发处理任务(ACS 反馈与 PC 端操作共用路由表)
|
||||
*
|
||||
* @param task 任务
|
||||
* @param type 操作类型
|
||||
* @param reqDTO 反馈请求(PC 端为构造的精简对象)
|
||||
*/
|
||||
void dispatchOperation(TransportTaskDO task, TaskOperationTypeEnum type, AcsFeedbackReqDTO reqDTO);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 任务 5:`TransportTaskServiceImpl` 路由表 + handle* 迁入 + PC 入口
|
||||
|
||||
**文件:**
|
||||
- 修改:`nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/service/transporttask/TransportTaskServiceImpl.java`
|
||||
|
||||
**说明:** `handleExecuting/handlePicked/handleFinished/handleCancelled/publishEvent/buildCallbackReq` 六个方法从 `TransportTaskFeedbackServiceImpl` **原样迁入**(方法体一字不改),本任务只新增代码,删除动作在任务 6。
|
||||
|
||||
- [ ] **步骤 1:补充 import**
|
||||
|
||||
在现有 import 区追加:
|
||||
|
||||
```java
|
||||
import cn.code.nl.framework.execute.biz.api.TaskCommonApi;
|
||||
import cn.code.nl.framework.execute.core.TaskCommonApiFactory;
|
||||
import cn.code.nl.module.task.dto.AcsFeedbackReqDTO;
|
||||
import cn.code.nl.module.task.dto.TaskStatusCallbackReqDTO;
|
||||
import cn.code.nl.module.task.enums.TaskEventTypeEnum;
|
||||
import cn.code.nl.module.task.enums.TaskOperationTypeEnum;
|
||||
import cn.code.nl.module.task.mq.message.TaskEventMessage;
|
||||
import cn.code.nl.module.task.mq.producer.TaskEventProducer;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.EnumMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import static cn.code.nl.module.task.enums.ErrorCodeConstants.TRANSPORT_TASK_ALREADY_FINAL;
|
||||
import static cn.code.nl.module.task.enums.ErrorCodeConstants.TRANSPORT_TASK_OPERATION_NOT_SUPPORTED;
|
||||
import static cn.code.nl.module.task.framework.common.util.TaskUtil.isAllowedFrom;
|
||||
```
|
||||
|
||||
注意:`TRANSPORT_TASK_NOT_EXISTS` 的静态导入已存在,不要重复。
|
||||
|
||||
- [ ] **步骤 2:类上补充 `@Slf4j` 注解**
|
||||
|
||||
```java
|
||||
@Slf4j
|
||||
@Service
|
||||
@Validated
|
||||
public class TransportTaskServiceImpl implements TransportTaskService {
|
||||
```
|
||||
|
||||
- [ ] **步骤 3:新增依赖字段与路由表字段(放在 `transportTaskMapper` 字段之后)**
|
||||
|
||||
```java
|
||||
@Resource
|
||||
private TaskEventProducer taskEventProducer;
|
||||
|
||||
@Resource
|
||||
private TaskCommonApiFactory taskCommonApiFactory;
|
||||
|
||||
/**
|
||||
* 操作类型 -> 处理方法 路由表(ACS 反馈与 PC 端操作共用)
|
||||
*/
|
||||
private final Map<TaskOperationTypeEnum, BiConsumer<TransportTaskDO, AcsFeedbackReqDTO>> operationHandlers =
|
||||
new EnumMap<>(TaskOperationTypeEnum.class);
|
||||
|
||||
/**
|
||||
* 初始化操作类型路由表
|
||||
*/
|
||||
@PostConstruct
|
||||
public void initOperationHandlers() {
|
||||
operationHandlers.put(TaskOperationTypeEnum.EXECUTING, (task, reqDTO) -> handleExecuting(task));
|
||||
operationHandlers.put(TaskOperationTypeEnum.PICKED, this::handlePicked);
|
||||
operationHandlers.put(TaskOperationTypeEnum.FINISHED, this::handleFinished);
|
||||
operationHandlers.put(TaskOperationTypeEnum.CANCELLED, this::handleCancelled);
|
||||
// todo: 二次请求业务未开发
|
||||
operationHandlers.put(TaskOperationTypeEnum.APPLY_AGAIN,
|
||||
(task, reqDTO) -> log.info("二次请求业务未开发, taskId={}", task.getTaskId()));
|
||||
// todo: 强制完成业务未开发
|
||||
operationHandlers.put(TaskOperationTypeEnum.FORCE_FINISH,
|
||||
(task, reqDTO) -> log.info("强制完成业务未开发, taskId={}", task.getTaskId()));
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **步骤 4:新增 PC 入口与分发方法(放在 `getTransportTaskPage` 方法之后)**
|
||||
|
||||
```java
|
||||
/**
|
||||
* PC 端操作搬运任务(完成/取消/强制完成):先校验再走统一路由表分发
|
||||
*/
|
||||
@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("MANUAL");
|
||||
} else if (type == TaskOperationTypeEnum.FORCE_FINISH) {
|
||||
task.setFinishedType("FORCE");
|
||||
}
|
||||
// 5. 构造精简反馈对象,走统一路由表分发
|
||||
AcsFeedbackReqDTO reqDTO = new AcsFeedbackReqDTO();
|
||||
reqDTO.setTaskId(task.getTaskId());
|
||||
reqDTO.setStatus(type.getCode());
|
||||
dispatchOperation(task, type, reqDTO);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按操作类型查路由表分发(消灭 if-else)
|
||||
*/
|
||||
@Override
|
||||
public void dispatchOperation(TransportTaskDO task, TaskOperationTypeEnum type, AcsFeedbackReqDTO reqDTO) {
|
||||
BiConsumer<TransportTaskDO, AcsFeedbackReqDTO> handler = operationHandlers.get(type);
|
||||
if (handler == null) {
|
||||
log.warn("操作类型未注册处理器, taskId={}, type={}", task.getTaskId(), type.getCode());
|
||||
return;
|
||||
}
|
||||
handler.accept(task, reqDTO);
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **步骤 5:迁入六个业务方法(放在类末尾,方法体与原 `TransportTaskFeedbackServiceImpl` 完全一致)**
|
||||
|
||||
```java
|
||||
// ==================== 各状态处理方法(自 TransportTaskFeedbackServiceImpl 迁入,逻辑未改动) ====================
|
||||
|
||||
/**
|
||||
* 处理执行中(60):直接更新状态,不做业务回调
|
||||
*/
|
||||
private void handleExecuting(TransportTaskDO task) {
|
||||
if (!isAllowedFrom(task.getTaskStatus(), "40", "50")) {
|
||||
log.warn("执行中反馈状态校验不通过, taskId={}, currentStatus={}",
|
||||
task.getTaskId(), task.getTaskStatus());
|
||||
return;
|
||||
}
|
||||
task.setTaskStatus(TransportTaskStatusEnum.EXECUTING.getCode());
|
||||
transportTaskMapper.updateById(task);
|
||||
log.info("任务执行中, taskId={}", task.getTaskId());
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理取货完成(61):更新状态 + 同步 HTTP 回调 LMS/WMS
|
||||
* ownerService: 服务提供商
|
||||
*/
|
||||
private void handlePicked(TransportTaskDO task, AcsFeedbackReqDTO reqDTO) {
|
||||
if (!isAllowedFrom(task.getTaskStatus(), "60", "61")) {
|
||||
log.warn("取货完成反馈状态校验不通过, taskId={}, currentStatus={}",
|
||||
task.getTaskId(), task.getTaskStatus());
|
||||
return;
|
||||
}
|
||||
// 更新状态
|
||||
task.setTaskStatus(TransportTaskStatusEnum.PICKED.getCode());
|
||||
transportTaskMapper.updateById(task);
|
||||
log.info("任务已取货, taskId={}", task.getTaskId());
|
||||
|
||||
// 同步请求业务
|
||||
TaskCommonApi byServerName = taskCommonApiFactory.getByServerName("lms-server");
|
||||
byServerName.doHandlePicked();
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理完成(67):更新状态 + 异步 MQ 通知 LMS/WMS
|
||||
*/
|
||||
private void handleFinished(TransportTaskDO task, AcsFeedbackReqDTO reqDTO) {
|
||||
if (!isAllowedFrom(task.getTaskStatus(), "10", "40", "45", "50", "60", "61", "67")) {
|
||||
log.warn("完成反馈状态校验不通过, taskId={}, currentStatus={}",
|
||||
task.getTaskId(), task.getTaskStatus());
|
||||
return;
|
||||
}
|
||||
// 已是 67 则只发 MQ,不改状态
|
||||
if (!TransportTaskStatusEnum.FINISHED_CALLBACK_PENDING.getCode().equals(task.getTaskStatus())) {
|
||||
task.setTaskStatus(TransportTaskStatusEnum.FINISHED_CALLBACK_PENDING.getCode());
|
||||
}
|
||||
task.setCallbackStatus(CallbackStatusEnum.PENDING.getCode());
|
||||
transportTaskMapper.updateById(task);
|
||||
|
||||
publishEvent(task, TaskEventTypeEnum.TASK_FINISHED, reqDTO.getPayload());
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理取消(69):更新状态 + 异步 MQ 通知 LMS/WMS
|
||||
*/
|
||||
private void handleCancelled(TransportTaskDO task, AcsFeedbackReqDTO reqDTO) {
|
||||
if (!isAllowedFrom(task.getTaskStatus(), "10", "40", "45", "50", "60", "61", "67", "69")) {
|
||||
log.warn("取消反馈状态校验不通过, taskId={}, currentStatus={}",
|
||||
task.getTaskId(), task.getTaskStatus());
|
||||
return;
|
||||
}
|
||||
if (!TransportTaskStatusEnum.CANCEL_CALLBACK_PENDING.getCode().equals(task.getTaskStatus())) {
|
||||
task.setTaskStatus(TransportTaskStatusEnum.CANCEL_CALLBACK_PENDING.getCode());
|
||||
}
|
||||
task.setCallbackStatus(CallbackStatusEnum.PENDING.getCode());
|
||||
transportTaskMapper.updateById(task);
|
||||
|
||||
publishEvent(task, TaskEventTypeEnum.TASK_CANCELLED, reqDTO.getPayload());
|
||||
}
|
||||
|
||||
// ==================== 工具方法 ====================
|
||||
|
||||
/**
|
||||
* 发布 MQ 事件。发送失败时记录 callbackStatus=FAILED
|
||||
*/
|
||||
private void publishEvent(TransportTaskDO task, TaskEventTypeEnum eventType,
|
||||
Map<String, Object> payload) {
|
||||
TaskEventMessage msg = new TaskEventMessage();
|
||||
msg.setEventType(eventType.getCode());
|
||||
msg.setTaskId(task.getTaskId());
|
||||
msg.setTaskCode(task.getTaskCode());
|
||||
msg.setOwnerService(task.getOwnerService());
|
||||
msg.setBizType(task.getBizType());
|
||||
msg.setBizId(task.getBizId());
|
||||
msg.setHandleCode(task.getHandleCode());
|
||||
msg.setPayload(payload);
|
||||
|
||||
try {
|
||||
taskEventProducer.publishEvent(msg);
|
||||
} catch (Exception e) {
|
||||
log.error("MQ 发布失败, taskId={}, eventType={}",
|
||||
task.getTaskId(), eventType.getCode(), e);
|
||||
task.setCallbackStatus(CallbackStatusEnum.FAILED.getCode());
|
||||
task.setCallbackErrorMsg(StrUtil.maxLength(e.getMessage(), 500));
|
||||
transportTaskMapper.updateById(task);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建同步回调请求 DTO(当前无调用方,随迁保留)
|
||||
*/
|
||||
private TaskStatusCallbackReqDTO buildCallbackReq(TransportTaskDO task,
|
||||
AcsFeedbackReqDTO reqDTO) {
|
||||
TaskStatusCallbackReqDTO req = new TaskStatusCallbackReqDTO();
|
||||
req.setTaskId(task.getTaskId());
|
||||
req.setTaskCode(task.getTaskCode());
|
||||
req.setStatus(TransportTaskStatusEnum.PICKED.getCode());
|
||||
req.setOwnerService(task.getOwnerService());
|
||||
req.setBizType(task.getBizType());
|
||||
req.setBizId(task.getBizId());
|
||||
req.setHandleCode(task.getHandleCode());
|
||||
req.setPayload(reqDTO.getPayload());
|
||||
return req;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 任务 6:`TransportTaskFeedbackServiceImpl` 瘦身
|
||||
|
||||
**文件:**
|
||||
- 修改:`nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/service/transporttask/TransportTaskFeedbackServiceImpl.java`
|
||||
|
||||
- [ ] **步骤 1:整体替换为以下内容**
|
||||
|
||||
```java
|
||||
package cn.code.nl.module.task.service.transporttask;
|
||||
|
||||
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.dto.AcsFeedbackReqDTO;
|
||||
import cn.code.nl.module.task.enums.TaskOperationTypeEnum;
|
||||
import cn.code.nl.module.task.enums.TransportTaskStatusEnum;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
/**
|
||||
* ACS 反馈处理服务实现
|
||||
* <p>
|
||||
* 只做 ACS 前置处理(查任务/幂等/保存反馈参数),具体操作业务统一由 {@link TransportTaskService} 路由表分发
|
||||
*
|
||||
* @author 诺力管理员
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@Validated
|
||||
public class TransportTaskFeedbackServiceImpl implements TransportTaskFeedbackService {
|
||||
|
||||
@Resource
|
||||
private TransportTaskMapper transportTaskMapper;
|
||||
|
||||
@Resource
|
||||
private TransportTaskService transportTaskService;
|
||||
|
||||
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void receiveAcsFeedback(AcsFeedbackReqDTO reqDTO) {
|
||||
// 1. 查询任务
|
||||
TransportTaskDO task = transportTaskMapper.selectById(reqDTO.getTaskId());
|
||||
if (task == null) {
|
||||
log.warn("ACS 反馈 taskId 不存在, taskId={}, 直接返回成功", reqDTO.getTaskId());
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. 幂等判断:已经是终态(完成/取消)则不重复处理
|
||||
String currentStatus = task.getTaskStatus();
|
||||
if (TransportTaskStatusEnum.FINISHED.getCode().equals(currentStatus)
|
||||
|| TransportTaskStatusEnum.CANCELLED.getCode().equals(currentStatus)) {
|
||||
log.info("任务已处终态, taskId={}, currentStatus={}, 忽略反馈",
|
||||
reqDTO.getTaskId(), currentStatus);
|
||||
return;
|
||||
}
|
||||
|
||||
// 3. 保存 resultParam
|
||||
if (reqDTO.getPayload() != null) {
|
||||
try {
|
||||
task.setResultParam(OBJECT_MAPPER.writeValueAsString(reqDTO.getPayload()));
|
||||
} catch (Exception e) {
|
||||
log.warn("resultParam 序列化失败, taskId={}", reqDTO.getTaskId(), e);
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 解析操作类型并校验允许 ACS 触发,走统一路由表分发
|
||||
TaskOperationTypeEnum type = TaskOperationTypeEnum.getByCode(reqDTO.getStatus());
|
||||
if (type == null || !type.isAcsAllowed()) {
|
||||
log.warn("未知或不允许的 ACS 反馈状态, taskId={}, status={}",
|
||||
reqDTO.getTaskId(), reqDTO.getStatus());
|
||||
return;
|
||||
}
|
||||
transportTaskService.dispatchOperation(task, type, reqDTO);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
注意:原类中 `handle*`、`publishEvent`、`buildCallbackReq` 及其相关 import(TaskCommonApi、TaskCommonApiFactory、TaskEventMessage、TaskStatusCallbackReqDTO、CallbackStatusEnum、TaskEventTypeEnum、TaskEventProducer、StrUtil、isAllowedFrom、Map)随整体替换一并移除,已在任务 5 迁入 `TransportTaskServiceImpl`。
|
||||
|
||||
---
|
||||
|
||||
### 任务 7:`TransportTaskController` 新增 operate 接口
|
||||
|
||||
**文件:**
|
||||
- 修改:`nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/controller/admin/transporttask/TransportTaskController.java`
|
||||
|
||||
- [ ] **步骤 1:在 `updateTransportTask` 方法之后新增(`vo.*` 通配 import 已覆盖新 VO)**
|
||||
|
||||
```java
|
||||
@PostMapping("/operate")
|
||||
@Operation(summary = "PC 端操作搬运任务(完成/取消/强制完成)")
|
||||
@PreAuthorize("@ss.hasPermission('task:transport-task:operate')")
|
||||
public CommonResult<Boolean> operateTransportTask(@Valid @RequestBody TransportTaskOperateReqVO reqVO) {
|
||||
transportTaskService.operateTransportTask(reqVO);
|
||||
return success(true);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 任务 8:后端编译验证
|
||||
|
||||
- [ ] **步骤 1:编译 task 模块**
|
||||
|
||||
运行(仓库根目录):
|
||||
|
||||
```bash
|
||||
mvn -f nl-module-task/pom.xml compile -q
|
||||
```
|
||||
|
||||
预期:BUILD SUCCESS,无编译错误。若因兄弟模块依赖未安装到本地仓库而失败,改用:
|
||||
|
||||
```bash
|
||||
mvn -pl nl-module-task -am compile -q
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 任务 9:前端 API 新增 `operateTransportTask`
|
||||
|
||||
**文件:**
|
||||
- 修改:`nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/api/task/transporttask/index.ts`
|
||||
|
||||
- [ ] **步骤 1:在 `exportTransportTask` 之后新增**
|
||||
|
||||
```ts
|
||||
/** PC 端操作搬运任务(完成/取消/强制完成) */
|
||||
export function operateTransportTask(data: {
|
||||
operationType: string;
|
||||
taskId: number | string;
|
||||
}) {
|
||||
return requestClient.post('/task/transport-task/operate', data);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 任务 10:`index.vue` 三个按钮绑定操作类型
|
||||
|
||||
**文件:**
|
||||
- 修改:`nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/views/task/transporttask/index.vue`
|
||||
|
||||
- [ ] **步骤 1:import 块补充 `operateTransportTask`**
|
||||
|
||||
```ts
|
||||
import {
|
||||
deleteTransportTask,
|
||||
deleteTransportTaskList,
|
||||
exportTransportTask,
|
||||
getTransportTaskPage,
|
||||
operateTransportTask,
|
||||
} from '#/api/task/transporttask';
|
||||
```
|
||||
|
||||
- [ ] **步骤 2:在 `handleDelete` 之前新增操作函数**
|
||||
|
||||
```ts
|
||||
/** PC 端操作搬运任务(完成/取消/强制完成) */
|
||||
async function handleOperate(
|
||||
row: TaskTransportTaskApi.TransportTask,
|
||||
operationType: string,
|
||||
label: string,
|
||||
) {
|
||||
await confirm(`确认要${label}【${row.taskCode}】吗?`);
|
||||
const hideLoading = message.loading({
|
||||
content: `正在${label}...`,
|
||||
duration: 0,
|
||||
});
|
||||
try {
|
||||
await operateTransportTask({ taskId: row.taskId!, operationType });
|
||||
message.success(`${label}成功`);
|
||||
handleRefresh();
|
||||
} finally {
|
||||
hideLoading();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **步骤 3:替换三个按钮的 `onClick`(原来错绑 `handleEdit.bind(null, row)`)**
|
||||
|
||||
```ts
|
||||
{
|
||||
label: '完成任务',
|
||||
type: 'link',
|
||||
icon: ACTION_ICON.SEND,
|
||||
auth: ['task:transport-task:finish'],
|
||||
disabled: ['79', '89', '99'].includes(row.taskStatus),
|
||||
onClick: handleOperate.bind(null, row, 'FINISHED', '完成任务'),
|
||||
},
|
||||
{
|
||||
label: '取消任务',
|
||||
type: 'link',
|
||||
icon: ACTION_ICON.CANCEL,
|
||||
auth: ['task:transport-task:cancel'],
|
||||
disabled: ['79', '89', '99'].includes(row.taskStatus),
|
||||
onClick: handleOperate.bind(null, row, 'CANCELLED', '取消任务'),
|
||||
},
|
||||
{
|
||||
label: '强制完成任务',
|
||||
type: 'link',
|
||||
icon: ACTION_ICON.CANCEL,
|
||||
auth: ['task:transport-task:cancel'],
|
||||
disabled: ['79', '89', '99'].includes(row.taskStatus),
|
||||
onClick: handleOperate.bind(null, row, 'FORCE-FINISH', '强制完成任务'),
|
||||
},
|
||||
```
|
||||
|
||||
说明:`auth`/`icon` 维持现状(强制完成的独立权限属规格范围外)。
|
||||
|
||||
---
|
||||
|
||||
### 任务 11:前端验证
|
||||
|
||||
- [ ] **步骤 1:类型检查(可选,monorepo 全量较慢)**
|
||||
|
||||
运行(`nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next` 目录):
|
||||
|
||||
```bash
|
||||
pnpm typecheck
|
||||
```
|
||||
|
||||
预期:本次改动的两个文件无新增类型错误(仓库既有错误不属本次范围)。
|
||||
|
||||
---
|
||||
|
||||
### 任务 12:统一提交(可选,需用户同意)
|
||||
|
||||
- [ ] **步骤 1:确认用户同意后提交**
|
||||
|
||||
```bash
|
||||
git add docs/superpowers/specs/2026-07-15-task-operation-refactor-design.md \
|
||||
docs/superpowers/plans/2026-07-15-task-operation-refactor.md \
|
||||
nl-module-task/nl-module-task-api/src/main/java/cn/code/nl/module/task/enums/TaskOperationTypeEnum.java \
|
||||
nl-module-task/nl-module-task-api/src/main/java/cn/code/nl/module/task/enums/ErrorCodeConstants.java \
|
||||
nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/controller/admin/transporttask/vo/TransportTaskOperateReqVO.java \
|
||||
nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/controller/admin/transporttask/TransportTaskController.java \
|
||||
nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/service/transporttask/TransportTaskService.java \
|
||||
nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/service/transporttask/TransportTaskServiceImpl.java \
|
||||
nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/service/transporttask/TransportTaskFeedbackServiceImpl.java \
|
||||
nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/api/task/transporttask/index.ts \
|
||||
nl-ui/nl-ui-admin-vben/yudao-ui-admin-vben/apps/web-antdv-next/src/views/task/transporttask/index.vue
|
||||
git commit -m "feat:任务操作路由表重构 + PC 端完成/取消/强制完成操作"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 风险与注意事项
|
||||
|
||||
1. **循环依赖**:依赖方向为 `FeedbackServiceImpl → TransportTaskService` 单向,`TransportTaskServiceImpl` 不得反向注入 `TransportTaskFeedbackService`。
|
||||
2. **事务**:`receiveAcsFeedback` 的 `@Transactional` 经跨 Bean 调用按 REQUIRED 传播覆盖 `dispatchOperation`;PC 入口自带 `@Transactional`。
|
||||
3. **FORCE-FINISH 的 finishedType**:PC 入口会 set 但 handler 为 todo 不落库,属规格已确认的预期行为。
|
||||
4. **工作区有未提交改动**:本计划涉及的部分文件已有本地修改(见 git status),实现时在现有基础上叠加,不要回退已有改动。
|
||||
170
docs/superpowers/plans/2026-07-16-jenkinsfile-monolith-deploy.md
Normal file
170
docs/superpowers/plans/2026-07-16-jenkinsfile-monolith-deploy.md
Normal file
@@ -0,0 +1,170 @@
|
||||
# Jenkinsfile 单体部署 nl-server 实现计划
|
||||
|
||||
> **面向 AI 代理的工作者:** 必需子技能:使用 superpowers:subagent-driven-development(推荐)或 superpowers:executing-plans 逐任务实现此计划。步骤使用复选框(`- [ ]`)语法来跟踪进度。
|
||||
|
||||
**目标:** 在仓库根目录新增 `Jenkinsfile`,以 Docker 容器形式在 Jenkins 构建机本机部署 `nl-server` 单体。
|
||||
|
||||
**架构:** 声明式 Pipeline:参数化(PROFILE/NACOS_ADDR/NACOS_NAMESPACE/JAVA_OPTS)→ Checkout → `mvn package -pl nl-server -am -DskipTests` → 复用 `nl-server/Dockerfile` 构建镜像(BUILD_NUMBER + latest 双 tag)→ 停删旧容器后 host 网络 `docker run` → curl 循环健康检查;post 清理悬空镜像。
|
||||
|
||||
**技术栈:** Jenkins 声明式 Pipeline(Groovy)/ Maven / Docker(Linux 构建机)
|
||||
|
||||
**规格:** `docs/superpowers/specs/2026-07-16-jenkinsfile-monolith-deploy-design.md`
|
||||
|
||||
---
|
||||
|
||||
## 文件结构
|
||||
|
||||
| 文件 | 操作 | 职责 |
|
||||
|---|---|---|
|
||||
| `Jenkinsfile`(仓库根目录) | 创建 | 单体部署流水线全部逻辑 |
|
||||
|
||||
---
|
||||
|
||||
### 任务 1:创建根目录 `Jenkinsfile`
|
||||
|
||||
**文件:**
|
||||
- 创建:`Jenkinsfile`
|
||||
|
||||
- [ ] **步骤 1:创建文件,内容如下**
|
||||
|
||||
```groovy
|
||||
// nl-server 单体部署流水线(构建机 = 运行机,Linux + JDK17+ + Maven + Docker)
|
||||
pipeline {
|
||||
agent any
|
||||
|
||||
parameters {
|
||||
choice(name: 'PROFILE', choices: ['test', 'dev', 'prod'], description: '运行环境(注入 SPRING_PROFILES_ACTIVE)')
|
||||
string(name: 'NACOS_ADDR', defaultValue: '127.0.0.1:8848', description: 'Nacos 配置/注册中心地址')
|
||||
string(name: 'NACOS_NAMESPACE', defaultValue: '', description: 'Nacos 命名空间(public 留空)')
|
||||
string(name: 'JAVA_OPTS', defaultValue: '-Xms512m -Xmx512m -Djava.security.egd=file:/dev/./urandom', description: 'JVM 启动参数')
|
||||
}
|
||||
|
||||
environment {
|
||||
IMAGE_NAME = 'nl-server'
|
||||
CONTAINER_NAME = 'nl-server'
|
||||
APP_PORT = '48080'
|
||||
}
|
||||
|
||||
stages {
|
||||
stage('Checkout') {
|
||||
steps {
|
||||
checkout scm
|
||||
}
|
||||
}
|
||||
|
||||
stage('Maven Build') {
|
||||
steps {
|
||||
// 只构建 nl-server 及其依赖模块,跳过测试
|
||||
sh 'mvn clean package -pl nl-server -am -DskipTests'
|
||||
}
|
||||
}
|
||||
|
||||
stage('Docker Build') {
|
||||
steps {
|
||||
// 构建上下文为 nl-server 目录,复用其现有 Dockerfile
|
||||
sh "docker build -t ${IMAGE_NAME}:${BUILD_NUMBER} -t ${IMAGE_NAME}:latest nl-server/"
|
||||
}
|
||||
}
|
||||
|
||||
stage('Deploy') {
|
||||
steps {
|
||||
// 停删旧容器(首次部署无旧容器,容错处理),host 网络启动新容器
|
||||
sh """
|
||||
docker stop ${CONTAINER_NAME} || true
|
||||
docker rm ${CONTAINER_NAME} || true
|
||||
docker run -d --name ${CONTAINER_NAME} \\
|
||||
--restart always \\
|
||||
--network host \\
|
||||
-v /docker/nl-cloud/logs:/root/logs/ \\
|
||||
-e TZ=Asia/Shanghai \\
|
||||
-e SPRING_PROFILES_ACTIVE=${params.PROFILE} \\
|
||||
-e SPRING_CLOUD_NACOS_CONFIG_SERVER_ADDR=${params.NACOS_ADDR} \\
|
||||
-e SPRING_CLOUD_NACOS_SERVER_ADDR=${params.NACOS_ADDR} \\
|
||||
-e SPRING_CLOUD_NACOS_CONFIG_NAMESPACE=${params.NACOS_NAMESPACE} \\
|
||||
-e SPRING_CLOUD_NACOS_DISCOVERY_NAMESPACE=${params.NACOS_NAMESPACE} \\
|
||||
-e "JAVA_OPTS=${params.JAVA_OPTS}" \\
|
||||
${IMAGE_NAME}:${BUILD_NUMBER}
|
||||
"""
|
||||
}
|
||||
}
|
||||
|
||||
stage('Health Check') {
|
||||
steps {
|
||||
// 最多等待 24 次 x 5s ≈ 120s,收到任意 HTTP 响应(含 404)即视为启动成功
|
||||
sh """
|
||||
echo "等待 nl-server 启动..."
|
||||
for i in \$(seq 1 24); do
|
||||
if curl -s -o /dev/null http://127.0.0.1:${APP_PORT}; then
|
||||
echo "nl-server 启动成功"
|
||||
exit 0
|
||||
fi
|
||||
sleep 5
|
||||
done
|
||||
echo "健康检查超时,输出容器日志:"
|
||||
docker logs --tail 200 ${CONTAINER_NAME}
|
||||
exit 1
|
||||
"""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
post {
|
||||
success {
|
||||
echo "部署成功:${IMAGE_NAME}:${BUILD_NUMBER},服务端口 ${APP_PORT}(历史镜像 tag 保留,可用于手动回滚)"
|
||||
}
|
||||
failure {
|
||||
echo '部署失败,请检查上方日志'
|
||||
}
|
||||
always {
|
||||
// 仅清理悬空镜像,保留历史 BUILD_NUMBER tag
|
||||
sh 'docker image prune -f || true'
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 任务 2:静态验证
|
||||
|
||||
本地无 Jenkins/Groovy 环境,做结构性静态检查:
|
||||
|
||||
- [ ] **步骤 1:花括号配对计数**
|
||||
|
||||
运行(仓库根目录):
|
||||
|
||||
```bash
|
||||
grep -o '{' Jenkinsfile | wc -l && grep -o '}' Jenkinsfile | wc -l
|
||||
```
|
||||
|
||||
预期:两个数字相等(60 上下,以实际为准)。
|
||||
|
||||
- [ ] **步骤 2:结构核对清单(人工比对文件内容)**
|
||||
|
||||
- [ ] `pipeline { agent any; parameters; environment; stages; post }` 五段齐全
|
||||
- [ ] 4 个参数名与规格一致:PROFILE / NACOS_ADDR / NACOS_NAMESPACE / JAVA_OPTS
|
||||
- [ ] 5 个 stage:Checkout / Maven Build / Docker Build / Deploy / Health Check
|
||||
- [ ] Deploy 中 6 个 `-e` 环境变量 + TZ + 日志卷挂载 + `--network host` + `--restart always`
|
||||
- [ ] shell 中 `$(seq ...)` 已转义为 `\$(seq ...)`(避免被 Groovy 插值)
|
||||
- [ ] `JAVA_OPTS` 注入带引号(值含空格)
|
||||
|
||||
---
|
||||
|
||||
### 任务 3:统一提交(可选,需用户同意)
|
||||
|
||||
- [ ] **步骤 1:确认用户同意后提交**
|
||||
|
||||
```bash
|
||||
git add Jenkinsfile \
|
||||
docs/superpowers/specs/2026-07-16-jenkinsfile-monolith-deploy-design.md \
|
||||
docs/superpowers/plans/2026-07-16-jenkinsfile-monolith-deploy.md
|
||||
git commit -m "build:新增 Jenkinsfile 单体部署 nl-server"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 风险与注意事项
|
||||
|
||||
1. **构建机前提**:Linux、JDK 17+、Maven、Docker、curl 已装且 Jenkins 用户有 docker 权限(在 docker 用户组)。
|
||||
2. **真实验证需在 Jenkins 执行**:建 Pipeline 任务指向本仓库运行;首次运行参数页尚未生成,会用默认参数跑一次。
|
||||
3. **Nacos 前置**:nl-server 为 Spring Cloud 应用,启动依赖 Nacos 可达;若 Nacos 未就绪,健康检查会超时失败并打印容器日志。
|
||||
252
docs/superpowers/plans/2026-07-16-transport-task-api-query.md
Normal file
252
docs/superpowers/plans/2026-07-16-transport-task-api-query.md
Normal file
@@ -0,0 +1,252 @@
|
||||
# TransportTaskApi RPC 查询接口 实现计划
|
||||
|
||||
> **面向 AI 代理的工作者:** 必需子技能:使用 superpowers:subagent-driven-development(推荐)或 superpowers:executing-plans 逐任务实现此计划。步骤使用复选框(`- [ ]`)语法来跟踪进度。
|
||||
|
||||
**目标:** 补全 `TransportTaskApi` 两个 todo——根据 taskId / taskCode 查询任务,返回 `TaskInfoDTO`,自动过滤逻辑删除。
|
||||
|
||||
**架构:** Api(Feign GET)→ ApiImpl(委托)→ TransportTaskService(查询 + MapStruct 转换,查不到返回 null)→ TransportTaskMapper(selectById / selectByTaskCode,`@TableLogic` 自动滤删)。新建 `TransportTaskConvert`(MapStruct,字段同名零配置)。
|
||||
|
||||
**技术栈:** Java 17 / Spring Boot / MyBatis-Plus(BaseMapperX)/ MapStruct 1.6.3(经 nl-common 传递依赖,无需改 pom)
|
||||
|
||||
**规格:** `docs/superpowers/specs/2026-07-16-transport-task-api-query-design.md`
|
||||
|
||||
**约定:** 注释/日志中文;`@Resource` 注入;不写测试;不频繁 commit(最后统一一次,需用户同意)。
|
||||
|
||||
---
|
||||
|
||||
## 文件结构
|
||||
|
||||
| 文件 | 操作 | 职责 |
|
||||
|---|---|---|
|
||||
| `nl-module-task/nl-module-task-api/src/main/java/cn/code/nl/module/task/api/TransportTaskApi.java` | 修改 | 新增两个 Feign GET 查询方法,删除两行 todo |
|
||||
| `nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/convert/transporttask/TransportTaskConvert.java` | 创建 | DO→TaskInfoDTO MapStruct 转换 |
|
||||
| `nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/dal/mysql/transporttask/TransportTaskMapper.java` | 修改 | 新增 selectByTaskCode |
|
||||
| `nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/service/transporttask/TransportTaskService.java` | 修改 | 接口新增 getTaskInfoById / getTaskInfoByCode |
|
||||
| `nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/service/transporttask/TransportTaskServiceImpl.java` | 修改 | 实现两个查询方法 |
|
||||
| `nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/api/TransportTaskApiImpl.java` | 修改 | 实现两个 Api 方法(委托 service) |
|
||||
|
||||
---
|
||||
|
||||
### 任务 1:`TransportTaskApi` 新增两个查询方法
|
||||
|
||||
**文件:**
|
||||
- 修改:`nl-module-task/nl-module-task-api/src/main/java/cn/code/nl/module/task/api/TransportTaskApi.java`
|
||||
|
||||
- [ ] **步骤 1:补充 import**
|
||||
|
||||
在现有 import 区追加:
|
||||
|
||||
```java
|
||||
import cn.code.nl.module.task.dto.TaskInfoDTO;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
```
|
||||
|
||||
- [ ] **步骤 2:删除两行 todo,替换为两个方法声明**
|
||||
|
||||
将文件末尾的:
|
||||
|
||||
```java
|
||||
// todo 根据taskId查找任务(返回TaskInfoDTO、过滤删除)
|
||||
|
||||
// todo 根据taskCode获取任务(返回TaskInfoDTO、过滤删除)
|
||||
```
|
||||
|
||||
替换为:
|
||||
|
||||
```java
|
||||
@GetMapping(PREFIX + "/getTaskById")
|
||||
@Operation(summary = "根据 taskId 查询任务(LMS/WMS 调用)")
|
||||
CommonResult<TaskInfoDTO> getTaskById(@RequestParam("taskId") Long taskId);
|
||||
|
||||
@GetMapping(PREFIX + "/getTaskByCode")
|
||||
@Operation(summary = "根据 taskCode 查询任务(LMS/WMS 调用)")
|
||||
CommonResult<TaskInfoDTO> getTaskByCode(@RequestParam("taskCode") String taskCode);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 任务 2:新建 `TransportTaskConvert`
|
||||
|
||||
**文件:**
|
||||
- 创建:`nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/convert/transporttask/TransportTaskConvert.java`
|
||||
|
||||
- [ ] **步骤 1:创建文件**
|
||||
|
||||
```java
|
||||
package cn.code.nl.module.task.convert.transporttask;
|
||||
|
||||
import cn.code.nl.module.task.dal.dataobject.transporttask.TransportTaskDO;
|
||||
import cn.code.nl.module.task.dto.TaskInfoDTO;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
/**
|
||||
* 搬运任务 Convert
|
||||
*
|
||||
* @Author: liyongde
|
||||
* @Date: 2026/7/16
|
||||
*/
|
||||
@Mapper
|
||||
public interface TransportTaskConvert {
|
||||
|
||||
TransportTaskConvert INSTANCE = Mappers.getMapper(TransportTaskConvert.class);
|
||||
|
||||
/**
|
||||
* DO 转 RPC 全量信息 DTO(字段同名,零配置映射)
|
||||
*/
|
||||
TaskInfoDTO convert(TransportTaskDO bean);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 任务 3:`TransportTaskMapper` 新增 `selectByTaskCode`
|
||||
|
||||
**文件:**
|
||||
- 修改:`nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/dal/mysql/transporttask/TransportTaskMapper.java`
|
||||
|
||||
- [ ] **步骤 1:在 `selectUnfinishedByBiz` 方法之前新增**
|
||||
|
||||
```java
|
||||
/**
|
||||
* 根据任务编码查询任务(taskCode 业务唯一)
|
||||
*/
|
||||
default TransportTaskDO selectByTaskCode(String taskCode) {
|
||||
return selectOne(TransportTaskDO::getTaskCode, taskCode);
|
||||
}
|
||||
```
|
||||
|
||||
说明:`selectOne(SFunction, Object)` 为 `BaseMapperX` 现有重载(BaseMapperX.java:105),`@TableLogic` 自动过滤 `deleted=1`。
|
||||
|
||||
---
|
||||
|
||||
### 任务 4:`TransportTaskService` 接口与实现新增查询方法
|
||||
|
||||
**文件:**
|
||||
- 修改:`nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/service/transporttask/TransportTaskService.java`
|
||||
- 修改:`nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/service/transporttask/TransportTaskServiceImpl.java`
|
||||
|
||||
- [ ] **步骤 1:接口补充 import 并新增两个声明**
|
||||
|
||||
import 区追加(`AcsFeedbackReqDTO` 等已存在,勿重复):
|
||||
|
||||
```java
|
||||
import cn.code.nl.module.task.dto.TaskInfoDTO;
|
||||
```
|
||||
|
||||
在 `dispatchOperation` 声明之后新增:
|
||||
|
||||
```java
|
||||
/**
|
||||
* 根据 taskId 查询任务全量信息(RPC 用,自动过滤逻辑删除,查不到返回 null)
|
||||
*
|
||||
* @param taskId 任务ID
|
||||
* @return 任务全量信息
|
||||
*/
|
||||
TaskInfoDTO getTaskInfoById(Long taskId);
|
||||
|
||||
/**
|
||||
* 根据 taskCode 查询任务全量信息(RPC 用,自动过滤逻辑删除,查不到返回 null)
|
||||
*
|
||||
* @param taskCode 任务编码
|
||||
* @return 任务全量信息
|
||||
*/
|
||||
TaskInfoDTO getTaskInfoByCode(String taskCode);
|
||||
```
|
||||
|
||||
- [ ] **步骤 2:实现类补充 import 并新增两个实现(放在 `dispatchOperation` 方法之后)**
|
||||
|
||||
import 区追加:
|
||||
|
||||
```java
|
||||
import cn.code.nl.module.task.convert.transporttask.TransportTaskConvert;
|
||||
import cn.code.nl.module.task.dto.TaskInfoDTO;
|
||||
```
|
||||
|
||||
新增实现:
|
||||
|
||||
```java
|
||||
/**
|
||||
* 根据 taskId 查询任务全量信息:查不到返回 null,由调用方判断
|
||||
*/
|
||||
@Override
|
||||
public TaskInfoDTO getTaskInfoById(Long taskId) {
|
||||
TransportTaskDO task = transportTaskMapper.selectById(taskId);
|
||||
return task != null ? TransportTaskConvert.INSTANCE.convert(task) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 taskCode 查询任务全量信息:查不到返回 null,由调用方判断
|
||||
*/
|
||||
@Override
|
||||
public TaskInfoDTO getTaskInfoByCode(String taskCode) {
|
||||
TransportTaskDO task = transportTaskMapper.selectByTaskCode(taskCode);
|
||||
return task != null ? TransportTaskConvert.INSTANCE.convert(task) : null;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 任务 5:`TransportTaskApiImpl` 实现两个方法
|
||||
|
||||
**文件:**
|
||||
- 修改:`nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/api/TransportTaskApiImpl.java`
|
||||
|
||||
- [ ] **步骤 1:补充 import**
|
||||
|
||||
```java
|
||||
import cn.code.nl.module.task.dto.TaskInfoDTO;
|
||||
```
|
||||
|
||||
- [ ] **步骤 2:在 `receiveCallbackResult` 方法之后新增**
|
||||
|
||||
```java
|
||||
@Override
|
||||
public CommonResult<TaskInfoDTO> getTaskById(Long taskId) {
|
||||
return success(transportTaskService.getTaskInfoById(taskId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<TaskInfoDTO> getTaskByCode(String taskCode) {
|
||||
return success(transportTaskService.getTaskInfoByCode(taskCode));
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 任务 6:编译验证
|
||||
|
||||
- [ ] **步骤 1:编译(仓库根目录)**
|
||||
|
||||
```bash
|
||||
mvn -pl nl-module-task/nl-module-task-server -am compile
|
||||
```
|
||||
|
||||
预期:`BUILD SUCCESS`(同时验证 MapStruct 注解处理器生成 `TransportTaskConvertImpl` 无报错)。
|
||||
|
||||
---
|
||||
|
||||
### 任务 7:统一提交(可选,需用户同意)
|
||||
|
||||
- [ ] **步骤 1:确认用户同意后提交(仅本次相关文件)**
|
||||
|
||||
```bash
|
||||
git add docs/superpowers/specs/2026-07-16-transport-task-api-query-design.md \
|
||||
docs/superpowers/plans/2026-07-16-transport-task-api-query.md \
|
||||
nl-module-task/nl-module-task-api/src/main/java/cn/code/nl/module/task/api/TransportTaskApi.java \
|
||||
nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/api/TransportTaskApiImpl.java \
|
||||
nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/convert/transporttask/TransportTaskConvert.java \
|
||||
nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/dal/mysql/transporttask/TransportTaskMapper.java \
|
||||
nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/service/transporttask/TransportTaskService.java \
|
||||
nl-module-task/nl-module-task-server/src/main/java/cn/code/nl/module/task/service/transporttask/TransportTaskServiceImpl.java
|
||||
git commit -m "feat:TransportTaskApi 新增按 taskId/taskCode 查询任务 RPC 接口"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 风险与注意事项
|
||||
|
||||
1. **工作区有未提交改动**:`TransportTaskService(Impl)`、`TransportTaskMapper` 均已有本地改动(含上一需求的路由表代码),实现时在现有基础上叠加,不要回退。
|
||||
2. **MapStruct 与 Lombok 顺序**:模块继承的编译配置已被 infra 等模块的 Convert 验证可用,若编译报 MapStruct 处理器缺失,检查是否误改了 pom(本计划不改 pom)。
|
||||
3. **`TransportTaskServiceImplTest`**:test 目录引用了 `TransportTaskApi`,`compile` 阶段不编译测试代码,不受影响。
|
||||
Reference in New Issue
Block a user