Merge remote-tracking branch 'origin/feature/20260713/task-module'
# Conflicts: # nl-module-system/nl-module-system-server/src/main/resources/application-dev.yaml # pom.xml
This commit is contained in:
308
docs/superpowers/specs/2026-07-14-task-core-design.md
Normal file
308
docs/superpowers/specs/2026-07-14-task-core-design.md
Normal file
@@ -0,0 +1,308 @@
|
||||
# Task 服务核心业务设计文档
|
||||
|
||||
> 日期: 2026-07-14
|
||||
> 分支: feature/20260713/task-module
|
||||
> 参考: doc/task-service-technical-development.md
|
||||
|
||||
## 1. 概述
|
||||
|
||||
Task 服务是搬运任务生命周期中台,负责接收 LMS/WMS 创建的任务、接收 ACS 状态反馈、维护任务状态机、以及通过 HTTP/MQ 将状态变更通知回 LMS/WMS。
|
||||
|
||||
### 1.1 本期范围
|
||||
|
||||
| 本期做 | 本期不做 |
|
||||
|--------|----------|
|
||||
| LMS/WMS 创建任务 (RPC) | 定时器自动下发 ACS |
|
||||
| ACS 反馈:执行中、取货完成、完成、取消 | ACS 下发接口调用 |
|
||||
| 取货完成同步 HTTP 回调 LMS/WMS | 下发中超时补偿 |
|
||||
| 完成/取消 MQ 异步通知 LMS/WMS | 回调超时重试补偿 |
|
||||
| 业务回调结果接收 + 状态更新 | AcsTaskDto 转换器 |
|
||||
| 幂等控制(创建、反馈、回调) | 人工完成/取消 |
|
||||
| 管理后台 CRUD(已有) | 任务过程日志表 |
|
||||
|
||||
## 2. 整体交互流程
|
||||
|
||||
```
|
||||
LMS/WMS Task 服务 ACS
|
||||
│ │ │
|
||||
│── POST /rpc-api/task/transport/create ──→│ │
|
||||
│ │ 保存任务(status=040) │
|
||||
│←── 返回 taskId ───────────────│ │
|
||||
│ │ │
|
||||
│ │ (后续: 定时器下发ACS) │
|
||||
│ │ │
|
||||
│ │←── ACS 反馈 执行中(60) ───────│
|
||||
│ │ 更新状态, 直接返回成功 │
|
||||
│ │ │
|
||||
│ │←── ACS 反馈 取货完成(61) ─────│
|
||||
│ │ 更新状态 │
|
||||
│←── POST /rpc-api/{service}/transport-task/status-callback ──│ │
|
||||
│── 同步执行业务处理 ──────────→│ │
|
||||
│←── 返回业务结果 ─────────────│ │
|
||||
│ │──── 返回成功给 ACS ───────────→│
|
||||
│ │ (AGV 可继续) │
|
||||
│ │ │
|
||||
│ │←── ACS 反馈 完成 ─────────────│
|
||||
│ │ status=067, callback=PENDING │
|
||||
│←── MQ: TASK_EVENT:LMS ───────│ (异步) │
|
||||
│ 业务处理 → 回调 Task ───────→│ status=070, callback=SUCCESS │
|
||||
│ │ │
|
||||
│ │←── ACS 反馈 取消 ─────────────│
|
||||
│ │ status=069, callback=PENDING │
|
||||
│←── MQ: TASK_EVENT:LMS ───────│ (异步) │
|
||||
│ 业务处理 → 回调 Task ───────→│ status=080, callback=SUCCESS │
|
||||
```
|
||||
|
||||
### 2.1 回调策略总结
|
||||
|
||||
| ACS 状态 | Task 动作 | 通知方式 | 说明 |
|
||||
|----------|----------|----------|------|
|
||||
| 执行中(60) | 更新 status=060 | 无 | 直接改状态 |
|
||||
| 取货完成(61) | 更新 status=061 | HTTP 同步 | 调 LMS/WMS,等业务完成再回 ACS |
|
||||
| 完成 | status=067, callback=PENDING | MQ 异步 | 通知后不等待,LMS/WMS 处理完回调 |
|
||||
| 取消 | status=069, callback=PENDING | MQ 异步 | 同上 |
|
||||
|
||||
## 3. 状态机
|
||||
|
||||
### 3.1 状态枚举
|
||||
|
||||
```java
|
||||
CREATED(10, "生成")
|
||||
READY(40, "待下发")
|
||||
ISSUING(45, "下发中")
|
||||
ISSUED(50, "已下发")
|
||||
EXECUTING(60, "执行中")
|
||||
PICKED(61, "已取货搬运中")
|
||||
FINISHED_CALLBACK_PENDING(67, "外部完成待业务处理")
|
||||
CANCEL_EXTERNAL_PENDING(68, "外部取消中")
|
||||
CANCEL_CALLBACK_PENDING(69, "外部取消待业务处理")
|
||||
FINISHED(70, "完成")
|
||||
CANCELLED(80, "取消")
|
||||
FAILED(90, "失败")
|
||||
```
|
||||
|
||||
### 3.2 本期状态流转
|
||||
|
||||
```
|
||||
010(生成) → 040(待下发)
|
||||
040(待下发) → 060(执行中) → 061(取货完成) → 067(外部完成待业务处理) → 070(完成)
|
||||
→ 069(外部取消待业务处理) → 080(取消)
|
||||
```
|
||||
|
||||
### 3.3 状态前置校验
|
||||
|
||||
| 目标状态 | 允许的前置状态 |
|
||||
|----------|---------------|
|
||||
| EXECUTING(60) | 040, 050, 060 |
|
||||
| PICKED(61) | 060, 061 |
|
||||
| FINISHED_CALLBACK_PENDING(67) | 050, 060, 061, 067 |
|
||||
| CANCEL_CALLBACK_PENDING(69) | 040, 050, 060, 061, 069 |
|
||||
|
||||
## 4. 接口设计
|
||||
|
||||
### 4.1 LMS/WMS → Task:创建任务
|
||||
|
||||
```
|
||||
POST /rpc-api/task/transport/create
|
||||
```
|
||||
|
||||
请求 DTO(位于 `nl-module-task-api` 模块):
|
||||
|
||||
```java
|
||||
public class TransportTaskCreateReqDTO {
|
||||
@NotEmpty String taskName;
|
||||
@NotEmpty String ownerService; // LMS / WMS,路由键
|
||||
@NotEmpty String bizType; // 业务类型
|
||||
@NotEmpty String bizId; // 业务侧单据ID(幂等)
|
||||
@NotEmpty String handleCode; // LMS/WMS内部handler编码
|
||||
@NotEmpty String acsTaskType; // ACS任务类型
|
||||
@NotEmpty String agvSystemType;
|
||||
String pointCode1, pointCode2, pointCode3, pointCode4;
|
||||
String vehicleCode, vehicleCode2;
|
||||
String priority;
|
||||
String productArea;
|
||||
String isAutoIssue; // 是否自动下发
|
||||
Map<String, Object> requestParam; // 扩展参数
|
||||
}
|
||||
```
|
||||
|
||||
创建逻辑:
|
||||
1. 参数校验
|
||||
2. 幂等检查:同 bizType + bizId 下是否有未完结任务 (status < 067),有则返回已有 taskId
|
||||
3. 生成 taskId / taskCode
|
||||
4. 参数完整 → status=040,否则 status=010
|
||||
5. 保存并返回 taskId
|
||||
|
||||
### 4.2 ACS → Task:状态反馈
|
||||
|
||||
```
|
||||
POST /api/task/transport/acs-feedback
|
||||
```
|
||||
|
||||
```java
|
||||
public class AcsFeedbackReqDTO {
|
||||
@NotNull Long taskId;
|
||||
@NotEmpty String status; // EXECUTING / PICKED / FINISHED / CANCELLED
|
||||
String eventId; // 幂等键
|
||||
Map<String, Object> payload; // 保存到 resultParam
|
||||
}
|
||||
```
|
||||
|
||||
### 4.3 Task → LMS/WMS:同步回调(取货完成)
|
||||
|
||||
```
|
||||
POST /rpc-api/transport-task/status-callback
|
||||
```
|
||||
|
||||
LMS/WMS 需实现此端点。路由方式:根据 `ownerService` 通过 Nacos 服务发现 + HTTP 调用对应服务。
|
||||
|
||||
```java
|
||||
// 请求
|
||||
public class TaskStatusCallbackReqDTO {
|
||||
Long taskId;
|
||||
String taskCode;
|
||||
String status; // PICKED(61)
|
||||
String ownerService;
|
||||
String bizType;
|
||||
String bizId;
|
||||
String handleCode; // LMS/WMS内部通过此字段路由到具体handler
|
||||
Map<String, Object> payload;
|
||||
}
|
||||
|
||||
// 响应
|
||||
public class TaskStatusCallbackRespDTO {
|
||||
Boolean success;
|
||||
String message;
|
||||
}
|
||||
```
|
||||
|
||||
### 4.4 Task → LMS/WMS:MQ 异步通知(完成/取消)
|
||||
|
||||
```
|
||||
Topic: TASK_EVENT_TOPIC
|
||||
Tag: LMS 或 WMS (即 ownerService)
|
||||
```
|
||||
|
||||
```java
|
||||
public class TaskEventMessage {
|
||||
String eventId;
|
||||
String eventType; // TASK_FINISHED / TASK_CANCELLED
|
||||
Long taskId;
|
||||
String taskCode;
|
||||
String ownerService;
|
||||
String bizType;
|
||||
String bizId;
|
||||
String handleCode;
|
||||
Map<String, Object> payload;
|
||||
}
|
||||
```
|
||||
|
||||
### 4.5 LMS/WMS → Task:业务处理结果回调
|
||||
|
||||
```
|
||||
POST /rpc-api/task/transport/callback-result
|
||||
```
|
||||
|
||||
```java
|
||||
public class TaskCallbackResultReqDTO {
|
||||
@NotNull Long taskId;
|
||||
@NotEmpty String eventId;
|
||||
@NotEmpty String result; // SUCCESS / FAILED
|
||||
String message;
|
||||
}
|
||||
```
|
||||
|
||||
回调后状态更新:
|
||||
|
||||
| 场景 | taskStatus | callbackStatus |
|
||||
|------|-----------|----------------|
|
||||
| 完成业务成功 | 070 | SUCCESS |
|
||||
| 完成业务失败 | 067 | FAILED |
|
||||
| 取消业务成功 | 080 | SUCCESS |
|
||||
| 取消业务失败 | 069 | FAILED |
|
||||
|
||||
## 5. 服务层设计
|
||||
|
||||
### 5.1 模块结构
|
||||
|
||||
```
|
||||
nl-module-task-server/
|
||||
controller/
|
||||
TransportTaskController ← 已有,管理后台 CRUD
|
||||
AcsFeedbackController ← 新增:接收 ACS 状态反馈
|
||||
api/
|
||||
TransportTaskApiImpl ← 新增:实现 rpc-api 创建任务接口
|
||||
service/
|
||||
TransportTaskService ← 已有,扩展创建方法
|
||||
TransportTaskFeedbackService ← 新增:处理 ACS 状态反馈
|
||||
TransportTaskCallbackService ← 新增:处理 LMS/WMS 业务回调结果
|
||||
mq/
|
||||
TaskEventProducer ← 新增:发送完成/取消 MQ
|
||||
client/
|
||||
TransportTaskStatusClient ← 新增:同步 HTTP 调 LMS/WMS
|
||||
|
||||
nl-module-task-api/
|
||||
dto/
|
||||
TransportTaskCreateReqDTO ← 新增
|
||||
AcsFeedbackReqDTO ← 新增
|
||||
TaskStatusCallbackReqDTO ← 新增(LMS/WMS 依赖此 DTO 实现端点)
|
||||
TaskStatusCallbackRespDTO ← 新增
|
||||
TaskCallbackResultReqDTO ← 新增
|
||||
TaskEventMessage ← 新增
|
||||
enums/
|
||||
TransportTaskStatusEnum ← 已有(需对齐状态码)
|
||||
CallbackStatusEnum ← 新增
|
||||
TaskEventTypeEnum ← 新增
|
||||
```
|
||||
|
||||
### 5.2 TransportTaskFeedbackService(核心)
|
||||
|
||||
```
|
||||
receiveAcsFeedback(AcsFeedbackReqDTO req):
|
||||
1. 查询任务,校验存在
|
||||
2. eventId 幂等判断
|
||||
3. 前置状态校验(不合法则记日志并返回成功)
|
||||
4. 保存 resultParam
|
||||
5. 按 status 路由:
|
||||
EXECUTING:
|
||||
→ 更新 taskStatus=060
|
||||
PICKED:
|
||||
→ 更新 taskStatus=061
|
||||
→ 同步 HTTP 调 LMS/WMS status-callback
|
||||
→ 回调失败:记 callbackStatus=FAILED,仍返回成功给 ACS
|
||||
FINISHED:
|
||||
→ 更新 taskStatus=067, callbackStatus=PENDING
|
||||
→ 发送 MQ (TASK_FINISHED)
|
||||
→ MQ 失败:记 callbackStatus=FAILED, callbackErrorMsg
|
||||
CANCELLED:
|
||||
→ 更新 taskStatus=069, callbackStatus=PENDING
|
||||
→ 发送 MQ (TASK_CANCELLED)
|
||||
→ MQ 失败:记 callbackStatus=FAILED, callbackErrorMsg
|
||||
```
|
||||
|
||||
### 5.3 TransportTaskStatusClient(HTTP 同步路由)
|
||||
|
||||
```java
|
||||
// 根据 ownerService → Nacos 服务名 → 构造 URL 调用
|
||||
// LMS/WMS 通过 handleCode 路由到内部 handler
|
||||
```
|
||||
|
||||
## 6. 错误处理与幂等
|
||||
|
||||
| 场景 | 处理 |
|
||||
|------|------|
|
||||
| 创建时参数校验失败 | 返回参数错误码 |
|
||||
| 创建时同名未完结任务已存在 | 返回已有 taskId |
|
||||
| ACS 反馈 taskId 不存在 | 记录日志,返回成功(防 ACS 重试报错) |
|
||||
| 反馈状态前置校验不通过 | 记录日志,返回成功 |
|
||||
| 取货完成同步回调 LMS/WMS 失败 | 记 callbackStatus=FAILED,仍返回 ACS 成功(不阻塞 AGV) |
|
||||
| MQ 发送失败 | 记 callbackStatus=FAILED + callbackErrorMsg |
|
||||
| 业务回调结果已终态(070/080) | 直接返回成功 |
|
||||
| 重复 eventId 反馈 | 直接返回成功 |
|
||||
| 重复创建(同 bizType+bizId) | 返回已有 taskId |
|
||||
|
||||
## 7. 测试策略
|
||||
|
||||
- **单元测试**:TransportTaskFeedbackService 各状态分支、状态机约束
|
||||
- **集成测试**:创建 → 执行中 → 取货完成 → 完成 → 业务回调 → 终态 完整链路
|
||||
- **幂等测试**:重复创建、重复 ACS 反馈、重复业务回调
|
||||
@@ -0,0 +1,139 @@
|
||||
# 搬运任务操作重构 + PC 端操作功能设计
|
||||
|
||||
- 日期:2026-07-15
|
||||
- 分支:feature/20260713/task-module
|
||||
- 状态:已评审通过(方案 A:单类路由表)
|
||||
|
||||
## 1. 背景与目标
|
||||
|
||||
任务状态操作目前存在两个入口:
|
||||
|
||||
- **ACS 入口**:`AcsFeedbackController` → `TransportTaskFeedbackServiceImpl.receiveAcsFeedback()`,用字符串 if-else 按 `status` 分发到 `handleExecuting/handlePicked/handleFinished/handleCancelled`,代码凌乱。
|
||||
- **PC 入口**:尚不存在。前端 `views/task/transporttask/index.vue` 已有"完成任务/取消任务/强制完成任务"三个按钮,但都错绑在 `handleEdit` 上,未传操作类型。
|
||||
|
||||
目标:
|
||||
|
||||
1. 消灭 if-else 分发,改为表驱动策略(路由表)。
|
||||
2. 操作业务代码统一集中到 `TransportTaskServiceImpl`;`handleExecuting/handlePicked/handleFinished/handleCancelled/publishEvent` 方法体**原样迁移**,不改业务逻辑。
|
||||
3. 新增 PC 端统一操作接口 `POST /task/transport-task/operate`(taskId + operationType),支持 FINISHED / CANCELLED / FORCE-FINISH。
|
||||
4. `APPLY-AGAIN`(二次请求)、`FORCE-FINISH`(强制完成)业务未开发,路由表中注册 todo 占位(仅打日志)。
|
||||
5. 前端按钮补齐操作类型标识与调用逻辑。
|
||||
|
||||
## 2. 操作类型与入口矩阵
|
||||
|
||||
| 操作类型 | code | ACS 触发 | PC 触发 | 业务 |
|
||||
|---|---|---|---|---|
|
||||
| EXECUTING | EXECUTING | ✅ | ❌ | handleExecuting(已有) |
|
||||
| PICKED | PICKED | ✅ | ❌ | handlePicked(已有) |
|
||||
| FINISHED | FINISHED | ✅ | ✅ | handleFinished(已有) |
|
||||
| CANCELLED | CANCELLED | ✅ | ✅ | handleCancelled(已有) |
|
||||
| APPLY_AGAIN | APPLY-AGAIN | ✅ | ❌ | todo,未开发 |
|
||||
| FORCE_FINISH | FORCE-FINISH | ❌ | ✅ | todo,未开发 |
|
||||
|
||||
## 3. 后端设计
|
||||
|
||||
### 3.1 枚举增强 `TaskOperationTypeEnum`(task-api 模块)
|
||||
|
||||
- 增加两个布尔属性:`acsAllowed`(允许 ACS 触发)、`pcAllowed`(允许 PC 触发),取值见上表。
|
||||
- 增加静态解析方法 `getByCode(String code)`:忽略大小写匹配 `code`,找不到返回 `null`。
|
||||
|
||||
### 3.2 `TransportTaskServiceImpl`:路由表 + PC 入口
|
||||
|
||||
- 从 `TransportTaskFeedbackServiceImpl` **原样迁入**:`handleExecuting`、`handlePicked`、`handleFinished`、`handleCancelled`、`publishEvent`、`buildCallbackReq`(当前无调用方,随迁保留);依赖 `TaskEventProducer`、`TaskCommonApiFactory`、`OBJECT_MAPPER` 相关部分随迁。
|
||||
- 路由表:`EnumMap<TaskOperationTypeEnum, BiConsumer<TransportTaskDO, AcsFeedbackReqDTO>>`,在 `@PostConstruct` 中注册六种类型;`APPLY_AGAIN`、`FORCE_FINISH` 注册为 todo 占位(打 log.info,不做业务)。
|
||||
- 新增接口方法 `dispatchOperation(TransportTaskDO task, TaskOperationTypeEnum type, AcsFeedbackReqDTO reqDTO)`:查路由表分发,查不到打 warn 日志。
|
||||
- 新增 PC 入口 `operateTransportTask(TransportTaskOperateReqVO reqVO)`,`@Transactional(rollbackFor = Exception.class)`:
|
||||
1. 查任务,不存在 → 抛 `TRANSPORT_TASK_NOT_EXISTS`。
|
||||
2. `getByCode` 解析 operationType,为 `null` 或 `pcAllowed=false` → 抛新错误码 `TRANSPORT_TASK_OPERATION_NOT_SUPPORTED`。
|
||||
3. 任务已终态(79 完成 / 89 取消)→ 抛新错误码 `TRANSPORT_TASK_ALREADY_FINAL`(PC 端需给用户明确反馈,区别于 ACS 入口的静默幂等返回)。
|
||||
4. **PC 与 ACS 的差异点——记录完成类型/来源**:`FINISHED` → `task.setFinishedType("MANUAL")`(人工完成);`FORCE_FINISH` → `task.setFinishedType("FORCE")`(强制完成);`CANCELLED` 不设置。注意:`FORCE_FINISH` 的业务 handler 当前为 todo 占位、不执行 `updateById`,因此该 finishedType 设置在业务开发完成前不会实际落库,属预期行为。
|
||||
5. 构造仅含 `taskId`、`status` 的 `AcsFeedbackReqDTO`,调用 `dispatchOperation` 走同一路由表(保持 handler 签名不变)。
|
||||
- 新错误码追加到 `ErrorCodeConstants`,编号顺延现有 task 模块段。
|
||||
|
||||
### 3.3 `TransportTaskFeedbackServiceImpl` 瘦身
|
||||
|
||||
只保留 ACS 前置处理,注入 `TransportTaskService` 后委托分发:
|
||||
|
||||
1. 查任务(不存在打 warn 返回,保持现状)。
|
||||
2. 终态幂等判断(保持现状)。
|
||||
3. 保存 `resultParam`(保持现状)。
|
||||
4. 分发段替换为:
|
||||
|
||||
```java
|
||||
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` 从此类删除。依赖方向为 Feedback → TransportTaskService 单向,无循环依赖;`receiveAcsFeedback` 的 `@Transactional` 保持,跨 Bean 调用按 REQUIRED 传播沿用同一事务。
|
||||
|
||||
### 3.4 Controller / VO
|
||||
|
||||
- `TransportTaskController` 新增:
|
||||
|
||||
```java
|
||||
@PostMapping("/operate")
|
||||
@Operation(summary = "PC 端操作搬运任务(完成/取消/强制完成)")
|
||||
@PreAuthorize("@ss.hasPermission('task:transport-task:operate')")
|
||||
public CommonResult<Boolean> operateTransportTask(@Valid @RequestBody TransportTaskOperateReqVO reqVO)
|
||||
```
|
||||
|
||||
- 新 VO `TransportTaskOperateReqVO`(controller vo 包):`@NotNull Long taskId`;`@NotEmpty String operationType`(取值 FINISHED/CANCELLED/FORCE-FINISH)。
|
||||
|
||||
## 4. 前端设计(web-antdv-next)
|
||||
|
||||
### 4.1 API(`api/task/transporttask/index.ts`)
|
||||
|
||||
```ts
|
||||
/** PC 端操作搬运任务(完成/取消/强制完成) */
|
||||
export function operateTransportTask(data: {
|
||||
operationType: string;
|
||||
taskId: number;
|
||||
}) {
|
||||
return requestClient.post('/task/transport-task/operate', data);
|
||||
}
|
||||
```
|
||||
|
||||
### 4.2 页面(`views/task/transporttask/index.vue`)
|
||||
|
||||
- 新增操作函数:
|
||||
|
||||
```ts
|
||||
async function handleOperate(
|
||||
row: TaskTransportTaskApi.TransportTask,
|
||||
operationType: string,
|
||||
label: string,
|
||||
) {
|
||||
await confirm(`确认要${label}【${row.taskCode}】吗?`);
|
||||
await operateTransportTask({ taskId: row.taskId!, operationType });
|
||||
message.success(`${label}成功`);
|
||||
handleRefresh();
|
||||
}
|
||||
```
|
||||
|
||||
- 三个按钮 `onClick` 替换错绑的 `handleEdit`:
|
||||
- 完成任务 → `handleOperate(row, 'FINISHED', '完成任务')`
|
||||
- 取消任务 → `handleOperate(row, 'CANCELLED', '取消任务')`
|
||||
- 强制完成任务 → `handleOperate(row, 'FORCE-FINISH', '强制完成任务')`
|
||||
- 备注:强制完成按钮当前 `auth` 复用 `task:transport-task:cancel`、icon 用 `CANCEL`,本次不调整权限(需菜单配套),仅修正绑定。
|
||||
|
||||
## 5. 错误处理
|
||||
|
||||
- PC 入口:任务不存在 / 操作类型不支持 / 任务已终态,均抛 ServiceException,由全局异常处理返回给前端提示。
|
||||
- ACS 入口:保持现状(不存在/终态/未知状态均打日志静默返回成功,避免 ACS 重试)。
|
||||
- MQ 发布失败:沿用 `publishEvent` 现有逻辑(callbackStatus=FAILED + 记录错误信息)。
|
||||
|
||||
## 6. 测试与验证
|
||||
|
||||
- 按项目约定本次不编写测试(CLAUDE.md:除非用户允许测试)。
|
||||
- 验证方式:后端 `mvn compile`(task 模块)通过;前端 lint/类型检查通过。
|
||||
|
||||
## 7. 范围外(明确不做)
|
||||
|
||||
- APPLY-AGAIN、FORCE-FINISH 的具体业务实现(todo 占位)。
|
||||
- 强制完成按钮的独立权限与菜单配置。
|
||||
- PC 操作联动 ACS(如向 ACS 下发取消指令)。
|
||||
- `finishedType` 的字典配置与前端字典展示。
|
||||
@@ -0,0 +1,73 @@
|
||||
# Jenkinsfile 单体部署 nl-server 设计
|
||||
|
||||
- 日期:2026-07-16
|
||||
- 分支:feature/20260713/task-module
|
||||
- 状态:已评审通过(Docker 容器 + 构建机=运行机 + 参数化多环境)
|
||||
|
||||
## 1. 背景与目标
|
||||
|
||||
项目当前无任何 CI/CD 流水线。目标:在仓库根目录新增 `Jenkinsfile`,把 `nl-server`(单体聚合模块,内含 system/infra/lms/task 四个 server 模块)以 Docker 容器形式部署到 Jenkins 构建机本机,先跑通单服务单机部署。
|
||||
|
||||
## 2. 已确认的环境事实与决策
|
||||
|
||||
| 项 | 结论 |
|
||||
|---|---|
|
||||
| 部署形态 | Docker 容器(复用现有 `nl-server/Dockerfile`:temurin 21-jre、EXPOSE 48080、支持 `JAVA_OPTS`/`ARGS` 环境变量) |
|
||||
| 构建机与运行机 | 同一台机器(Jenkins agent 本机 docker run) |
|
||||
| Spring profile | 参数化(test/dev/prod,默认 test) |
|
||||
| 构建产物 | `mvn package` 后 `nl-server/target/nl-server.jar`(pom finalName=nl-server,spring-boot repackage) |
|
||||
| 前提 | 构建机已装 JDK 17+、Maven、Docker,Jenkins 任务类型为 Pipeline from SCM |
|
||||
| 测试 | 构建跳过测试(`-DskipTests`,项目约定) |
|
||||
|
||||
## 3. Jenkinsfile 设计(声明式 Pipeline)
|
||||
|
||||
### 3.1 参数(parameters)
|
||||
|
||||
| 参数 | 类型 | 默认值 | 用途 |
|
||||
|---|---|---|---|
|
||||
| `PROFILE` | choice(test/dev/prod) | test | 注入 `SPRING_PROFILES_ACTIVE` |
|
||||
| `NACOS_ADDR` | string | `127.0.0.1:8848` | 注入 `SPRING_CLOUD_NACOS_CONFIG_SERVER_ADDR` 与 `SPRING_CLOUD_NACOS_SERVER_ADDR`(沿用现有 docker-compose 变量名风格) |
|
||||
| `NACOS_NAMESPACE` | string | 空 | 注入 `SPRING_CLOUD_NACOS_CONFIG_NAMESPACE` 与 `SPRING_CLOUD_NACOS_DISCOVERY_NAMESPACE` |
|
||||
| `JAVA_OPTS` | string | `-Xms512m -Xmx512m -Djava.security.egd=file:/dev/./urandom` | 覆盖 Dockerfile 内默认 JVM 参数(默认值与 Dockerfile 保持一致,避免参数化后丢失 egd 配置) |
|
||||
|
||||
### 3.2 环境变量(environment)
|
||||
|
||||
- `IMAGE_NAME = 'nl-server'`
|
||||
- `CONTAINER_NAME = 'nl-server'`
|
||||
- `APP_PORT = '48080'`
|
||||
|
||||
### 3.3 Stages
|
||||
|
||||
1. **Checkout**:`checkout scm`。
|
||||
2. **Maven Build**:`mvn clean package -pl nl-server -am -DskipTests`(只构建 nl-server 及依赖模块)。
|
||||
3. **Docker Build**:`docker build -t nl-server:${BUILD_NUMBER} -t nl-server:latest nl-server/`(构建上下文为 nl-server 目录,Dockerfile `COPY ./target/nl-server.jar`)。
|
||||
4. **Deploy**:`docker stop`/`docker rm` 旧容器(`|| true` 容错首次部署);`docker run -d --name nl-server --restart always --network host`,挂载日志卷 `-v /docker/nl-cloud/logs:/root/logs/`(与现有 compose 一致),注入 `TZ=Asia/Shanghai`、`SPRING_PROFILES_ACTIVE`、Nacos 四个变量、`JAVA_OPTS`,镜像用 `nl-server:${BUILD_NUMBER}`。
|
||||
5. **Health Check**:shell 循环最多 24 次、每次间隔 5s(约 120s)探测 `http://127.0.0.1:48080`,收到任意 HTTP 响应即通过;超时则 `docker logs --tail 200` 输出容器日志并使构建失败。
|
||||
|
||||
### 3.4 post 处理
|
||||
|
||||
- `success`:输出部署成功信息(镜像 tag、访问地址)。
|
||||
- `failure`:输出失败提示。
|
||||
- `always`:`docker image prune -f` 仅清理悬空镜像(历史 `nl-server:<BUILD_NUMBER>` tag 保留,用于手动回滚)。
|
||||
|
||||
### 3.5 网络模式说明
|
||||
|
||||
使用 `--network host`:与项目现有 `script/docker/docker-compose.yml` 一致;Nacos 在同机部署时容器内可直接访问 `127.0.0.1:8848`,无需端口映射(端口由应用自身监听 48080)。
|
||||
|
||||
## 4. 错误处理
|
||||
|
||||
- 任一 stage 命令非零退出即中止流水线(声明式默认行为)。
|
||||
- 停删旧容器 `|| true`,首次部署无旧容器不报错。
|
||||
- 健康检查失败:输出容器日志后 `exit 1`,构建标红;旧镜像 tag 仍在本机,可手动回滚。
|
||||
|
||||
## 5. 验证
|
||||
|
||||
- 本地无 Jenkins 环境,静态验证为主:Jenkinsfile 为 Groovy 声明式语法,检查括号/引号配对与 stage 结构;shell 片段用 `bash -n` 无法直接验证(内嵌),人工核对。
|
||||
- 真实验证需在 Jenkins 上建 Pipeline 任务指向仓库运行(由用户执行)。
|
||||
|
||||
## 6. 范围外(明确不做)
|
||||
|
||||
- 微服务逐个部署(gateway/system/infra/task 独立容器)。
|
||||
- 推送镜像仓库、SSH 远程部署、多机部署。
|
||||
- 前端 nl-ui 的构建部署。
|
||||
- 自动回滚、通知(钉钉等)。
|
||||
@@ -0,0 +1,112 @@
|
||||
# TransportTaskApi RPC 查询接口设计(补全 todo)
|
||||
|
||||
- 日期:2026-07-16
|
||||
- 分支:feature/20260713/task-module
|
||||
- 状态:已评审通过(方案 1:Api → Service → Mapper 标准分层)
|
||||
|
||||
## 1. 背景与目标
|
||||
|
||||
`TransportTaskApi`(Task 服务 RPC 接口,LMS/WMS 经 Feign 调用)中有两个 todo 待实现:
|
||||
|
||||
```java
|
||||
// todo 根据taskId查找任务(返回TaskInfoDTO、过滤删除)
|
||||
// todo 根据taskCode获取任务(返回TaskInfoDTO、过滤删除)
|
||||
```
|
||||
|
||||
目标:补全这两个 RPC 查询接口,返回已存在的 `TaskInfoDTO`(35 字段全量数据),自动过滤逻辑删除的数据。
|
||||
|
||||
## 2. 关键事实(探索确认)
|
||||
|
||||
- `TaskInfoDTO` 已存在于 `nl-module-task-api/.../dto/TaskInfoDTO.java`,字段与 `TransportTaskDO` 同名同义(vehicleQty=Long、callbackRetryCount=Integer 均一致),可零配置映射。
|
||||
- `BaseDO.deleted` 带 `@TableLogic`,MyBatis-Plus 的 `selectById`/`selectOne` 自动追加 `deleted=0`,"过滤删除"无需手写条件。
|
||||
- MapStruct 1.6.3 经 `nl-common` 传递依赖对 task-server 可用(infra 模块 `ConfigConvert` 即此模式),无需改 pom。
|
||||
- task 模块尚无 `convert` 包,需新建。
|
||||
- Mapper 已有 `selectOne` 简单查询先例(`selectUnfinishedByBiz`),团队规范允许简单查询用 MyBatis-Plus 自带方法。
|
||||
|
||||
## 3. 设计
|
||||
|
||||
### 3.1 `TransportTaskApi`(api 模块)
|
||||
|
||||
删除两行 todo,新增两个 GET 方法(遵循"feign 方法名驼峰、url 与方法名一致"规则;注解风格与本文件现有方法保持一致):
|
||||
|
||||
```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);
|
||||
```
|
||||
|
||||
需补充 import:`GetMapping`、`RequestParam`、`TaskInfoDTO`。
|
||||
|
||||
### 3.2 `TransportTaskApiImpl`(server 模块)
|
||||
|
||||
只做委托(与现有模式一致):
|
||||
|
||||
```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));
|
||||
}
|
||||
```
|
||||
|
||||
### 3.3 `TransportTaskService(Impl)`
|
||||
|
||||
新增两个方法(中文 javadoc):
|
||||
|
||||
- `TaskInfoDTO getTaskInfoById(Long taskId)`:`transportTaskMapper.selectById(taskId)`,为 null 返回 null,否则 `TransportTaskConvert.INSTANCE.convert(task)`。
|
||||
- `TaskInfoDTO getTaskInfoByCode(String taskCode)`:`transportTaskMapper.selectByTaskCode(taskCode)`,同上。
|
||||
|
||||
查不到(含已逻辑删除)统一返回 null,由调用方判断——不抛业务异常(已确认)。
|
||||
|
||||
### 3.4 新建 `TransportTaskConvert`(server 模块,仿 infra `ConfigConvert`)
|
||||
|
||||
路径:`nl-module-task-server/src/main/java/cn/code/nl/module/task/convert/transporttask/TransportTaskConvert.java`
|
||||
|
||||
```java
|
||||
@Mapper
|
||||
public interface TransportTaskConvert {
|
||||
|
||||
TransportTaskConvert INSTANCE = Mappers.getMapper(TransportTaskConvert.class);
|
||||
|
||||
TaskInfoDTO convert(TransportTaskDO bean);
|
||||
}
|
||||
```
|
||||
|
||||
字段全部同名,无需 `@Mapping` 配置。
|
||||
|
||||
### 3.5 `TransportTaskMapper`
|
||||
|
||||
新增(taskCode 业务唯一,返回单对象;`selectOne` 自动滤删):
|
||||
|
||||
```java
|
||||
/**
|
||||
* 根据任务编码查询任务
|
||||
*/
|
||||
default TransportTaskDO selectByTaskCode(String taskCode) {
|
||||
return selectOne(TransportTaskDO::getTaskCode, taskCode);
|
||||
}
|
||||
```
|
||||
|
||||
## 4. 错误处理
|
||||
|
||||
- 查不到 / 已逻辑删除:`success(null)`,调用方自行判断。
|
||||
- 参数校验:Long/String 由 Spring MVC `@RequestParam` 必填约束兜底(缺参即 400),不额外写判空。
|
||||
|
||||
## 5. 测试与验证
|
||||
|
||||
- 按项目约定不编写测试。
|
||||
- 验证:`mvn -pl nl-module-task/nl-module-task-server -am compile` BUILD SUCCESS(同时验证 MapStruct 注解处理器生成实现类无报错)。
|
||||
|
||||
## 6. 范围外(明确不做)
|
||||
|
||||
- taskCode 数据库唯一索引调整。
|
||||
- LMS/WMS 调用方接入代码。
|
||||
- 其他 Api 方法的改动。
|
||||
Reference in New Issue
Block a user