From 79186364b829617f3219a1e952220f7ac2667124 Mon Sep 17 00:00:00 2001 From: jw Date: Sat, 12 Sep 2026 09:15:46 +0800 Subject: [PATCH] =?UTF-8?q?docs(order-v3):=20#7537=20=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E7=AB=AF=E5=B1=95=E7=A4=BA=E8=AE=A2=E5=8D=95=E5=8F=B7=E7=9A=84?= =?UTF-8?q?=E5=93=8D=E5=BA=94=E4=BD=93=E7=BB=9F=E4=B8=80=E8=A1=A5=E5=9B=A2?= =?UTF-8?q?=E5=8F=B7=EF=BC=88teamNo=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 11 个 /v3/admin/** 端点响应体纯增 teamNo:退款详情/列表、支付分页/详情/按订单、 工单分页/详情三块新增字段,订单待办 4 个写端点补上此前恒 null 的填充。 面向 hl-ui 写清四件事:teamNo 是订单团号 order_main.team_no(26-0001),不是运营 团期号 batchNo(GB-26-0001);为空一律 null 不返空串不回退订单号;生成条件是订金 支付成功、与是不是团期单无关(已付订金散客单有、未付订金团期单没有);同团每张 子订单团号各不相同,别按团号归并。 另记 4 个 /v3/internal/ 端点连带多出该字段(服务间调用,前端不对接)。 Co-Authored-By: Claude Opus 5 (1M context) --- ...¤º订单号的响应体统一补团号-修改接口-管理后台.md | 1049 +++++++++++++++++ 1 file changed, 1049 insertions(+) create mode 100644 changelogs-v2/2026-09/12_7537_管理端展示订单号的响应体统一补团号-修改接口-管理后台.md diff --git a/changelogs-v2/2026-09/12_7537_管理端展示订单号的响应体统一补团号-修改接口-管理后台.md b/changelogs-v2/2026-09/12_7537_管理端展示订单号的响应体统一补团号-修改接口-管理后台.md new file mode 100644 index 00000000..5701dd55 --- /dev/null +++ b/changelogs-v2/2026-09/12_7537_管理端展示订单号的响应体统一补团号-修改接口-管理后台.md @@ -0,0 +1,1049 @@ +--- +schema: "hl-changelog/v2" +ticket: "7537" +title: "管理端展示订单号的响应体统一补团号(teamNo)" +consumer: "admin" +author: "jw(GIT)" +change_type: "修改接口" +backend_status: "deployed" +gateway_status: "verified" +frontend_status: "pending" +frontend_owner: "mmg" +frontend_ref: "" +target_release: "" +verified_at: "2026-09-12" +status_note: "响应体纯增字段,向后兼容:未消费 teamNo 的页面行为完全不变。前端可按需在退款记录、支付流水、协同工单三块列表/详情补一列「团号」。" +updated_at: "2026-09-12" +base: "dev-v3" +--- + +# order-v3: 管理端展示订单号的响应体统一补团号(teamNo) + +**服务**: hl-order-service-v3 +**PR**: #7564 +**Issue**: #7537 + +--- + +## ⚠️ 关键变化 + +🔴 **`teamNo` 是订单团号,不是运营团期号。** 系统里有两个都被叫作「团号」的字段: + +| 字段 | 来源 | 格式 | 生成时点 | 本单 | +|---|---|---|---|---| +| **`teamNo`** | `order_main.team_no` | `26-0001`(4 位) | **订金支付成功** | ✅ 本单返的是这个 | +| `batchNo` | `order_group_batch.batch_no` | `GB-26-0001` | 建团期时 | ❌ 本单不返 | + +🔴 **`teamNo` 为 `null` 不代表「不是团期单」。** 生成条件是**订金支付成功**,与订单是不是团期单**完全无关**: + +- 已付订金的**散客单** → **有**团号 +- 未付订金的**团期单** → **没有**团号 + +前端**不要**用 `teamNo != null` 去判断团期单,那会判错两个方向。 + +🔴 **团号为空时一律是 `null`**,不是空串、更不会回退成订单号。前端按 `null` 判空即可,不必再区分 `""`。 + +🔴 **同一团期下的每张子订单团号各不相同**(团号是订单级的,不是团期级的)。别按「同团共用一个号」做归并。 + +--- + +## 一、背景 + +hl-ui 管理后台的**退款记录、支付流水、协同工单**三块列表/详情只显示订单号, +客服要知道团号得另开一个页面按订单号反查;**订单待办**的 `teamNo` 字段虽然早就在契约里, +但分页路径有值、单对象路径(新建/修改/完成/重开的回包)从来没赋过值,**恒为 `null`**, +前端拿到的数据前后不一致。 + +本单把这四处补齐:三个 VO 新增 `teamNo` 字段,一个 VO 补上从未执行的填充。 +**路径、方法、请求参数一律不变**,只在响应体追加(或补填)一个字段,向后兼容纯增。 + +--- + +## 二、变更接口清单 + +| # | 接口 | 方法 | 路径 | 变更类型 | 说明 | +|---|------|------|------|----------|------| +| 1 | 退款详情 | GET | `/v3/admin/refund/{refundId}` | 修改 | 响应体新增 `teamNo` | +| 2 | 按订单查退款 | GET | `/v3/admin/refund/order/{orderId}/list` | 修改 | 响应体新增 `teamNo` | +| 3 | 支付交易分页 | GET | `/v3/admin/payment/list` | 修改 | 响应体新增 `teamNo` | +| 4 | 交易详情 | GET | `/v3/admin/payment/{transactionId}` | 修改 | 响应体新增 `teamNo` | +| 5 | 按订单查交易 | GET | `/v3/admin/payment/order/{orderId}` | 修改 | 响应体新增 `teamNo` | +| 6 | 工单分页 | GET | `/v3/admin/order/work-order/list` | 修改 | 响应体新增 `teamNo` | +| 7 | 工单详情 | GET | `/v3/admin/order/work-order/{workOrderId}` | 修改 | 响应体新增 `teamNo` | +| 8 | 手动新建待办 | POST | `/v3/admin/order-todos/manual` | 修改 | `teamNo` 字段已存在,本单补上从未赋值的填充 | +| 9 | 修改手动待办 | PUT | `/v3/admin/order-todos/{todoId}` | 修改 | `teamNo` 字段已存在,本单补上从未赋值的填充 | +| 10 | 完成待办 | PUT | `/v3/admin/order-todos/{todoId}/complete` | 修改 | `teamNo` 字段已存在,本单补上从未赋值的填充 | +| 11 | 重开待办 | PUT | `/v3/admin/order-todos/{todoId}/reopen` | 修改 | `teamNo` 字段已存在,本单补上从未赋值的填充 | + +--- + +## 三、接口详情 + +### 1. 退款详情 `GET /v3/admin/refund/{refundId}` + +**VO**: `RefundRecordVO` + +#### 使用场景 + +hl-ui 管理后台查看单笔退款记录的完整信息。**本单起响应体多出 `teamNo`**,退款详情页可直接显示团号,不必再按订单号反查。 + +#### 入参字段表 + +| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | +|------|------|------|------|------|------| +| refundId | Path | Long | ✅ | 退款记录 ID | 退款 ID | + +#### 出参字段表 + +| 字段 | 类型 | 说明 | +|------|------|------| +| teamNo | String | **本单新增**。团号,4 位,形如 `26-0001`。订金支付成功后生成;未生成、订单不存在或 `orderId` 为空时为 `null`(**不返空串、不回退订单号**) | +| (其余字段) | — | **全部不变**,本单不改动任何既有字段的名称、类型与语义 | + +#### 请求示例 + +```http +GET /v3/admin/refund/{refundId} +Authorization: Bearer +``` + +#### 响应示例 + +```json +{ + "code": 200, + "message": "成功", + "data": { + "refundId": "2098380606701256706", + "orderId": "2098372746097348609", + "orderNo": "HL20260911192703129", + "teamNo": "26-4823", + "status": "SUCCESS" + }, + "success": true +} +``` + +#### 空数据 / 降级响应 + +订单已被删除、或订金尚未支付成功时,`teamNo` 为 `null`,其余字段照常返回,**不降级、不报错**。 + +#### 错误响应 + +| 码 | 符号 | 触发 | +|----|------|------| +| 不变 | `PAYMENT_REFUND_RECORD_NOT_FOUND` | `refundId` 查不到记录 | + +```json +{ + "code": 520009, + "message": "退款记录不存在: 999999", + "data": null, + "traceId": null, + "success": false +} +``` + +#### 业务边界 + +- `teamNo` 是**订单团号**(`order_main.team_no`),不是运营团期号 `batchNo`(`GB-26-0001`),本单不返后者。 +- 同一张订单的多条退款记录 `teamNo` 必然相同。 + +### 2. 按订单查退款 `GET /v3/admin/refund/order/{orderId}/list` + +**VO**: `List` + +#### 使用场景 + +hl-ui 订单详情页的退款记录列表。**本单起每行多出 `teamNo`**。 + +#### 入参字段表 + +| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | +|------|------|------|------|------|------| +| orderId | Path | Long | ✅ | 订单 ID | 订单 ID | + +#### 出参字段表 + +| 字段 | 类型 | 说明 | +|------|------|------| +| teamNo | String | **本单新增**。团号,4 位,形如 `26-0001`。订金支付成功后生成;未生成、订单不存在或 `orderId` 为空时为 `null`(**不返空串、不回退订单号**) | +| (其余字段) | — | **全部不变**,本单不改动任何既有字段的名称、类型与语义 | + +#### 请求示例 + +```http +GET /v3/admin/refund/order/{orderId}/list +Authorization: Bearer +``` + +#### 响应示例 + +```json +{ + "code": 200, + "message": "成功", + "data": [ + { + "refundId": "2098380606701256706", + "orderId": "2098372746097348609", + "orderNo": "HL20260911192703129", + "teamNo": "26-4823", + "status": "SUCCESS" + } + ], + "success": true +} +``` + +#### 空数据 / 降级响应 + +该订单无退款记录时返回空数组 `[]`(HTTP 200),**不抛错**。空数组时后端不发订单查询。 + +#### 错误响应 + +| 码 | 符号 | 触发 | +|----|------|------| +| 不变 | 无 | 本端点无新增错误码;无记录返空数组 | + +```json +{ + "code": 401, + "message": "缺少有效的 Authorization 头", + "data": null, + "traceId": "b8ffe9e9e9f84abe", + "success": false +} +``` + +#### 业务边界 + +- 本列表所有行同属一张订单,团号必然相同;后端仍走批量富化,**整页只发 1 次订单查询**,前端无需担心行数带来的耗时增长。 + +### 3. 支付交易分页 `GET /v3/admin/payment/list` + +**VO**: `PageResult` + +#### 使用场景 + +hl-ui 支付管理的交易流水分页列表。**本单起 `records[]` 每行多出 `teamNo`**,可直接做「按团号归并」的展示。 + +#### 入参字段表 + +| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | +|------|------|------|------|------|------| +| orderNo | Query | String | ❌ | 模糊匹配 | 订单号 | +| mchId | Query | String | ❌ | — | 商户号 | +| status | Query | String | ❌ | PENDING/SUCCESS/CLOSED/REFUNDED | 交易状态 | +| tradeType | Query | String | ❌ | JSAPI/H5 | 交易类型 | +| payType | Query | String | ❌ | FULL/DEPOSIT/BALANCE | 支付类型 | +| startDate | Query | String | ❌ | `yyyy-MM-dd` | 起始日期(含) | +| endDate | Query | String | ❌ | `yyyy-MM-dd` | 结束日期(含) | +| page | Query | Integer | ❌ | 默认 1 | 页码 | +| pageSize | Query | Integer | ❌ | 默认 20 | 每页条数 | + +#### 出参字段表 + +| 字段 | 类型 | 说明 | +|------|------|------| +| teamNo | String | **本单新增**。团号,4 位,形如 `26-0001`。订金支付成功后生成;未生成、订单不存在或 `orderId` 为空时为 `null`(**不返空串、不回退订单号**) | +| (其余字段) | — | **全部不变**,本单不改动任何既有字段的名称、类型与语义 | + +#### 请求示例 + +```http +GET /v3/admin/payment/list +Authorization: Bearer +``` + +#### 响应示例 + +```json +{ + "code": 200, + "message": "成功", + "data": { + "records": [ + { "orderId": "2098381549387882497", "orderNo": "HL20260911200202015", "teamNo": "26-4684" }, + { "orderId": "2098381524394024962", "orderNo": "HL20260911200156046", "teamNo": "26-7561" } + ], + "total": 128, + "page": 1, + "pageSize": 20 + }, + "success": true +} +``` + +#### 空数据 / 降级响应 + +空页(`records: []`)时后端不发订单查询;单行订单已删或订金未付时该行 `teamNo` 为 `null`,**整页照常返回,不会因一条脏数据整页 500**。 + +#### 错误响应 + +| 码 | 符号 | 触发 | +|----|------|------| +| 不变 | `PAYMENT_START_DATE_FORMAT_INVALID` / `PAYMENT_END_DATE_FORMAT_INVALID` | 日期格式非 `yyyy-MM-dd` | + +```json +{ + "code": 520007, + "message": "开始日期格式错误,应为 yyyy-MM-dd", + "data": null, + "traceId": null, + "success": false +} +``` + +```json +{ + "code": 520008, + "message": "结束日期格式错误,应为 yyyy-MM-dd", + "data": null, + "traceId": null, + "success": false +} +``` + +#### 业务边界 + +- 同一页里 `teamNo` 有值与为 `null` 的行会并存,属正常:团号只在订金支付成功后生成。 +- **整页只发 1 次**订单批量查询(按 distinct `orderId`),不随行数线性增长。 + +### 4. 交易详情 `GET /v3/admin/payment/{transactionId}` + +**VO**: `PaymentTransactionVO` + +#### 使用场景 + +hl-ui 查看单笔支付交易详情。**本单起响应体多出 `teamNo`**。 + +#### 入参字段表 + +| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | +|------|------|------|------|------|------| +| transactionId | Path | Long | ✅ | 交易 ID | 交易 ID | + +#### 出参字段表 + +| 字段 | 类型 | 说明 | +|------|------|------| +| teamNo | String | **本单新增**。团号,4 位,形如 `26-0001`。订金支付成功后生成;未生成、订单不存在或 `orderId` 为空时为 `null`(**不返空串、不回退订单号**) | +| (其余字段) | — | **全部不变**,本单不改动任何既有字段的名称、类型与语义 | + +#### 请求示例 + +```http +GET /v3/admin/payment/{transactionId} +Authorization: Bearer +``` + +#### 响应示例 + +```json +{ + "code": 200, + "message": "成功", + "data": { + "transactionId": "2098382090226581506", + "orderId": "2098381549387882497", + "orderNo": "HL20260911200202015", + "teamNo": "26-4684", + "status": "SUCCESS" + }, + "success": true +} +``` + +#### 空数据 / 降级响应 + +订金未支付成功 / 订单已删时 `teamNo` 为 `null`,其余字段照常返回。 + +#### 错误响应 + +| 码 | 符号 | 触发 | +|----|------|------| +| 不变 | `PAYMENT_TRANSACTION_NOT_FOUND` | `transactionId` 查不到交易 | + +```json +{ + "code": 520005, + "message": "交易记录不存在", + "data": null, + "traceId": null, + "success": false +} +``` + +#### 业务边界 + +- 同 VO 的 `POST /v3/admin/payment/{transactionId}/sync`(同步支付状态)**两个返回分支都已补富化**,响应体同样多出 `teamNo`。 + +### 5. 按订单查交易 `GET /v3/admin/payment/order/{orderId}` + +**VO**: `List` + +#### 使用场景 + +hl-ui 订单详情页的支付流水列表。**本单起每行多出 `teamNo`**。 + +#### 入参字段表 + +| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | +|------|------|------|------|------|------| +| orderId | Path | Long | ✅ | 订单 ID | 订单 ID | + +#### 出参字段表 + +| 字段 | 类型 | 说明 | +|------|------|------| +| teamNo | String | **本单新增**。团号,4 位,形如 `26-0001`。订金支付成功后生成;未生成、订单不存在或 `orderId` 为空时为 `null`(**不返空串、不回退订单号**) | +| (其余字段) | — | **全部不变**,本单不改动任何既有字段的名称、类型与语义 | + +#### 请求示例 + +```http +GET /v3/admin/payment/order/{orderId} +Authorization: Bearer +``` + +#### 响应示例 + +```json +{ + "code": 200, + "message": "成功", + "data": [ + { "orderId": "2098381549387882497", "orderNo": "HL20260911200202015", "teamNo": "26-4684", "payType": "BALANCE" }, + { "orderId": "2098381549387882497", "orderNo": "HL20260911200202015", "teamNo": "26-4684", "payType": "DEPOSIT" } + ], + "success": true +} +``` + +#### 空数据 / 降级响应 + +该订单无交易记录时返回空数组 `[]`(HTTP 200)。 + +#### 错误响应 + +| 码 | 符号 | 触发 | +|----|------|------| +| 不变 | 无 | 本端点无新增错误码 | + +```json +{ + "code": 401, + "message": "缺少有效的 Authorization 头", + "data": null, + "traceId": "b8ffe9e9e9f84abe", + "success": false +} +``` + +#### 业务边界 + +- 本列表所有行同属一张订单,团号必然相同。 + +### 6. 工单分页 `GET /v3/admin/order/work-order/list` + +**VO**: `PageResult` + +#### 使用场景 + +hl-ui 协同工单分页列表。**本单起 `records[]` 每行多出 `teamNo`**。 + +#### 入参字段表 + +| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | +|------|------|------|------|------|------| +| status | Query | String | ❌ | PENDING/PROCESSING/RESOLVED/REJECTED | 工单状态 | +| type | Query | String | ❌ | CHANGE/COMPLAINT/SUPPLEMENT/OTHER,取值以字典 `work_order_type` 为准 | 工单类型 | +| priority | Query | String | ❌ | — | 优先级 | +| orderNo | Query | String | ❌ | — | 关联订单号 | +| assigneeAdminId | Query | Long | ❌ | — | 指派人 ID | +| page | Query | Integer | ❌ | 默认 1 | 页码 | +| pageSize | Query | Integer | ❌ | 默认 20 | 每页条数 | + +#### 出参字段表 + +| 字段 | 类型 | 说明 | +|------|------|------| +| teamNo | String | **本单新增**。团号,4 位,形如 `26-0001`。订金支付成功后生成;未生成、订单不存在或 `orderId` 为空时为 `null`(**不返空串、不回退订单号**) | +| (其余字段) | — | **全部不变**,本单不改动任何既有字段的名称、类型与语义 | + +#### 请求示例 + +```http +GET /v3/admin/order/work-order/list +Authorization: Bearer +``` + +#### 响应示例 + +```json +{ + "code": 200, + "message": "成功", + "data": { + "records": [ + { "id": "2098579038820786177", "orderId": "2097500233448448002", "orderNo": "HL20260909093959906", "teamNo": "26-9208" }, + { "id": "2098579038493728770", "orderId": "2095549346731757569", "orderNo": "HL20260904002752146", "teamNo": null } + ], + "total": 12, + "page": 1, + "pageSize": 20 + }, + "success": true +} +``` + +#### 空数据 / 降级响应 + +空页时后端不发订单查询;单行订单已删或 `orderId` 为空时该行 `teamNo` 为 `null`,整页照常返回。 + +#### 错误响应 + +| 码 | 符号 | 触发 | +|----|------|------| +| 不变 | 无 | 本端点无新增错误码 | + +```json +{ + "code": 401, + "message": "缺少有效的 Authorization 头", + "data": null, + "traceId": "b8ffe9e9e9f84abe", + "success": false +} +``` + +#### 业务边界 + +- **整页只发 1 次**订单批量查询。 +- `teamNo` 与 `typeName`/`statusName`/`priorityName` 三个字典展示名是两条独立填充链路,团号不走字典。 + +### 7. 工单详情 `GET /v3/admin/order/work-order/{workOrderId}` + +**VO**: `WorkOrderRespVO` + +#### 使用场景 + +hl-ui 工单详情(含处理记录)。**本单起响应体多出 `teamNo`**。 + +#### 入参字段表 + +| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | +|------|------|------|------|------|------| +| workOrderId | Path | Long | ✅ | 工单 ID | 工单 ID | + +#### 出参字段表 + +| 字段 | 类型 | 说明 | +|------|------|------| +| teamNo | String | **本单新增**。团号,4 位,形如 `26-0001`。订金支付成功后生成;未生成、订单不存在或 `orderId` 为空时为 `null`(**不返空串、不回退订单号**) | +| (其余字段) | — | **全部不变**,本单不改动任何既有字段的名称、类型与语义 | + +#### 请求示例 + +```http +GET /v3/admin/order/work-order/{workOrderId} +Authorization: Bearer +``` + +#### 响应示例 + +```json +{ + "code": 200, + "message": "成功", + "data": { + "id": "2098579038820786177", + "workOrderNo": "WO202609120918017898", + "orderId": "2097500233448448002", + "orderNo": "HL20260909093959906", + "teamNo": "26-9208", + "status": "PENDING", + "logs": [] + }, + "success": true +} +``` + +#### 空数据 / 降级响应 + +订金未支付成功 / 订单已删时 `teamNo` 为 `null`。 + +#### 错误响应 + +| 码 | 符号 | 触发 | +|----|------|------| +| 不变 | `WORK_ORDER_NOT_FOUND` | `workOrderId` 查不到工单 | + +```json +{ + "code": 581440, + "message": "工单不存在", + "data": null, + "traceId": null, + "success": false +} +``` + +#### 业务边界 + +- 同 VO 的 4 个写端点**同步补了富化**,响应体同样多出 `teamNo`:`POST /v3/admin/order/work-order`(创建)、`PUT …/{workOrderId}/process`(处理)、`PUT …/{workOrderId}/assign`(指派)、`POST …/{workOrderId}/comment`(备注)。 + +### 8. 手动新建待办 `POST /v3/admin/order-todos/manual` + +**VO**: `OrderTodoRespVO` + +#### 使用场景 + +hl-ui 定制师手动给订单加一条待办。`teamNo` 字段**早就在契约里**,但此前单对象返回路径从未赋值、**恒为 `null`**;本单补上填充。 + +#### 入参字段表 + +| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | +|------|------|------|------|------|------| +| orderId | Body | Long | ✅ | 必须是调用人自己的订单 | 订单 ID | +| todoLabel | Body | String | ✅ | 非空白 | 待办标题 | +| todoDate | Body | String | ✅ | `yyyy-MM-dd` | 待办日期 | + +#### 出参字段表 + +| 字段 | 类型 | 说明 | +|------|------|------| +| teamNo | String | **本单新增**。团号,4 位,形如 `26-0001`。订金支付成功后生成;未生成、订单不存在或 `orderId` 为空时为 `null`(**不返空串、不回退订单号**) | +| (其余字段) | — | **全部不变**,本单不改动任何既有字段的名称、类型与语义 | + +#### 请求示例 + +```http +POST /v3/admin/order-todos/manual +Authorization: Bearer +``` + +#### 响应示例 + +```json +{ + "code": 200, + "message": "成功", + "data": { + "todoId": "2098579085771923457", + "orderId": "2097500233448448002", + "orderNo": "HL20260909093959906", + "teamNo": "26-9208", + "todoSource": "MANUAL", + "status": "PENDING" + }, + "success": true +} +``` + +#### 空数据 / 降级响应 + +订金未支付成功 / 订单已删时 `teamNo` 为 `null`(**此前是恒 `null`,现在是真实值或 `null`**)。 + +#### 错误响应 + +| 码 | 符号 | 触发 | +|----|------|------| +| 不变 | `TODO_ORDER_REQUIRED` | `orderId` 为空或订单不存在 | +| 不变 | `TODO_TITLE_REQUIRED` | `todoLabel` 为空白 | +| 不变 | `TODO_DATE_REQUIRED` | `todoDate` 为空 | +| 不变 | `TODO_ORDER_CONSULTANT_MISMATCH` | 订单不属于调用人 | + +```json +{ + "code": 581702, + "message": "待办必须关联订单", + "data": null, + "traceId": null, + "success": false +} +``` + +```json +{ + "code": 581704, + "message": "待办标题不能为空", + "data": null, + "traceId": null, + "success": false +} +``` + +#### 业务边界 + +- **分页列表 `GET /v3/admin/order-todos` 的 `teamNo` 本来就有值**(走 join 直接带出),本单只补齐单对象路径,两条路径自此一致。 + +### 9. 修改手动待办 `PUT /v3/admin/order-todos/{todoId}` + +**VO**: `OrderTodoRespVO` + +#### 使用场景 + +hl-ui 修改手动待办的标题 / 日期。`data.teamNo` 由**恒 `null`**改为真实值。 + +#### 入参字段表 + +| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | +|------|------|------|------|------|------| +| todoId | Path | Long | ✅ | 必须是调用人自己的手动待办 | 待办 ID | +| todoLabel | Body | String | ❌ | 两者都不传则原样返回 | 新标题 | +| todoDate | Body | String | ❌ | `yyyy-MM-dd` | 新日期 | + +#### 出参字段表 + +| 字段 | 类型 | 说明 | +|------|------|------| +| teamNo | String | **本单新增**。团号,4 位,形如 `26-0001`。订金支付成功后生成;未生成、订单不存在或 `orderId` 为空时为 `null`(**不返空串、不回退订单号**) | +| (其余字段) | — | **全部不变**,本单不改动任何既有字段的名称、类型与语义 | + +#### 请求示例 + +```http +PUT /v3/admin/order-todos/{todoId} +Authorization: Bearer +``` + +#### 响应示例 + +```json +{ + "code": 200, + "message": "成功", + "data": { + "todoId": "2098579085771923457", + "orderId": "2097500233448448002", + "orderNo": "HL20260909093959906", + "teamNo": "26-9208", + "status": "PENDING" + }, + "success": true +} +``` + +#### 空数据 / 降级响应 + +订金未支付成功 / 订单已删时 `teamNo` 为 `null`。 + +#### 错误响应 + +| 码 | 符号 | 触发 | +|----|------|------| +| 不变 | `TODO_NOT_FOUND` | `todoId` 查不到 | +| 不变 | `SYSTEM_TODO_MANUAL_OPERATION_FORBIDDEN` | 系统生成的待办不允许手动改 | +| 不变 | `TODO_FORBIDDEN` | 待办不属于调用人 | + +```json +{ + "code": 581700, + "message": "待办不存在", + "data": null, + "traceId": null, + "success": false +} +``` + +```json +{ + "code": 581701, + "message": "无权操作该待办", + "data": null, + "traceId": null, + "success": false +} +``` + +#### 业务边界 + +- 两个 body 字段都不传时,后端原样返回当前待办——此路径同样会填 `teamNo`。 + +### 10. 完成待办 `PUT /v3/admin/order-todos/{todoId}/complete` + +**VO**: `OrderTodoRespVO` + +#### 使用场景 + +hl-ui 把手动待办标记为已完成。`data.teamNo` 由**恒 `null`**改为真实值。 + +#### 入参字段表 + +| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | +|------|------|------|------|------|------| +| todoId | Path | Long | ✅ | 必须是调用人自己的手动待办 | 待办 ID | + +#### 出参字段表 + +| 字段 | 类型 | 说明 | +|------|------|------| +| teamNo | String | **本单新增**。团号,4 位,形如 `26-0001`。订金支付成功后生成;未生成、订单不存在或 `orderId` 为空时为 `null`(**不返空串、不回退订单号**) | +| (其余字段) | — | **全部不变**,本单不改动任何既有字段的名称、类型与语义 | + +#### 请求示例 + +```http +PUT /v3/admin/order-todos/{todoId}/complete +Authorization: Bearer +``` + +#### 响应示例 + +```json +{ + "code": 200, + "message": "成功", + "data": { + "todoId": "2098579085461446657", + "orderId": "2095549346731757569", + "orderNo": "HL20260904002752146", + "teamNo": null, + "status": "COMPLETED" + }, + "success": true +} +``` + +#### 空数据 / 降级响应 + +上面的响应示例就是订金未支付成功的真实回包:`teamNo` 为 `null`,**不是空串、不是订单号**。 + +#### 错误响应 + +| 码 | 符号 | 触发 | +|----|------|------| +| 不变 | `TODO_NOT_FOUND` | `todoId` 查不到 | +| 不变 | `SYSTEM_TODO_MANUAL_OPERATION_FORBIDDEN` | 系统生成的待办不允许手动操作 | +| 不变 | `TODO_FORBIDDEN` | 待办不属于调用人 | + +```json +{ + "code": 581700, + "message": "待办不存在", + "data": null, + "traceId": null, + "success": false +} +``` + +```json +{ + "code": 581703, + "message": "系统待办不允许手动完成或重开", + "data": null, + "traceId": null, + "success": false +} +``` + +#### 业务边界 + +- 待办已是非 `PENDING` 态时后端不重复写库、原样返回,该短路分支**同样**会填 `teamNo`。 + +### 11. 重开待办 `PUT /v3/admin/order-todos/{todoId}/reopen` + +**VO**: `OrderTodoRespVO` + +#### 使用场景 + +hl-ui 把已完成的手动待办重新打开。`data.teamNo` 由**恒 `null`**改为真实值。 + +#### 入参字段表 + +| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | +|------|------|------|------|------|------| +| todoId | Path | Long | ✅ | 必须是调用人自己的手动待办 | 待办 ID | + +#### 出参字段表 + +| 字段 | 类型 | 说明 | +|------|------|------| +| teamNo | String | **本单新增**。团号,4 位,形如 `26-0001`。订金支付成功后生成;未生成、订单不存在或 `orderId` 为空时为 `null`(**不返空串、不回退订单号**) | +| (其余字段) | — | **全部不变**,本单不改动任何既有字段的名称、类型与语义 | + +#### 请求示例 + +```http +PUT /v3/admin/order-todos/{todoId}/reopen +Authorization: Bearer +``` + +#### 响应示例 + +```json +{ + "code": 200, + "message": "成功", + "data": { + "todoId": "2098579085771923457", + "orderId": "2097500233448448002", + "orderNo": "HL20260909093959906", + "teamNo": "26-9208", + "status": "PENDING" + }, + "success": true +} +``` + +#### 空数据 / 降级响应 + +订金未支付成功 / 订单已删时 `teamNo` 为 `null`。 + +#### 错误响应 + +| 码 | 符号 | 触发 | +|----|------|------| +| 不变 | `TODO_NOT_FOUND` | `todoId` 查不到 | +| 不变 | `SYSTEM_TODO_MANUAL_OPERATION_FORBIDDEN` | 系统生成的待办不允许手动操作 | +| 不变 | `TODO_FORBIDDEN` | 待办不属于调用人 | + +```json +{ + "code": 581700, + "message": "待办不存在", + "data": null, + "traceId": null, + "success": false +} +``` + +```json +{ + "code": 581703, + "message": "系统待办不允许手动完成或重开", + "data": null, + "traceId": null, + "success": false +} +``` + +#### 业务边界 + +- 待办已是 `PENDING` 态时后端不重复写库、原样返回,该短路分支**同样**会填 `teamNo`。 + + +--- + +## 四、契约约束与正确调用方式 + +- **判空只判 `null`**:`teamNo` 为空时后端返 `null`,**不返空串**。前端 `if (row.teamNo)` 即可,不必再写 `!== ''`。 +- **不要拿 `teamNo` 判团期单**:判团期请用团期相关字段(`groupBatchId` 等),不是团号。 + 已付订金的散客单有团号、未付订金的团期单没有团号,用团号判会两个方向都判错。 +- **不要按团号归并同团订单**:同一团期下每张子订单的团号各不相同。要归团请用 `groupBatchId`。 +- **不要期待本单返运营团期号**:`batchNo`(`GB-26-0001`)与从订单跳团期所需的 `groupBatchId` **不在本单范围**,另有工单跟进。 +- **格式**:`26-0001` —— 年份后两位 + `-` + 4 位序号,`VARCHAR(10)` 字符串,**不是数字**, + 不要做数值解析、也不要按 `T` 开头做前缀判断(旧 Swagger `example` 写的 `T2026…` 是错的,本单已一并订正)。 +- **分页接口不会因为新增该字段变慢**:整页只发 1 次订单批量查询,不随行数增长。 + +--- + +## 五、数据库行为 + +**本单零数据库变更**:无新增/修改表、无新增列、无新增索引、无 Flyway 迁移脚本、无 Mapper 改动。 + +`teamNo` 取的是**既有列** `order_main.team_no`(DDL 注释:「团号(订金支付成功后生成,4位)」), +经既有服务契约 `OrderService.selectBatchByIds(Collection)` 批量读出,**只读、不写**。 + +清单里的写端点(8/9/10/11 待办写接口,以及工单的创建/处理/指派/备注)**写库行为一行未改**, +本单只是在它们返回前多填了一个展示字段。 + +--- + +## 六、边界行为 + +| 场景 | 行为 | +|---|---| +| 订金已支付成功 | `teamNo` 有值,形如 `26-0001` | +| 订金未支付成功 | `teamNo` 为 `null` | +| 行的 `orderId` 为 `null`(历史脏数据) | 该行 `teamNo` 为 `null`,**接口正常返回,不抛异常** | +| 订单已被删除 | 该行 `teamNo` 为 `null`,**接口正常返回,不抛异常** | +| 分页里一条脏数据 | **只影响那一行**,整页照常返回,不会整页 500 | +| 空列表 / 空页 | 后端不发订单查询 | +| 团期子订单 | 与散客单一视同仁,按订金是否付成功决定有无团号 | + +## 六.6、修改前后对比 + +| 维度 | 改前 | 改后 | +|---|---|---| +| 接口 1~7(退款/支付/工单) | 响应体**没有** `teamNo` 字段 | 响应体**有** `teamNo`,位置紧随 `orderNo` | +| 接口 8~11(订单待办) | `teamNo` 字段存在但**恒为 `null`** | `teamNo` 填真实值(无团号时才是 `null`) | +| 订单待办分页 `GET /v3/admin/order-todos` | 已有值 | **不变**(本单未动该路径) | +| 路径 / 方法 / 请求参数 | — | **完全不变** | +| 既有字段的名称/类型/语义 | — | **完全不变** | +| 错误码 | — | **无新增、无调整** | + +## 六.7、影响评估 + +- **兼容性**:响应体**纯增**字段,未消费 `teamNo` 的前端页面行为完全不变,**无需任何改动即可继续工作**。 +- **需要前端动的**:想显示团号的页面按上表加一列即可;接口 8~11 的调用方若此前把 `teamNo` 恒为 `null` + 当成「该字段没用」硬编码隐藏,现在可以打开。 +- **性能**:3 个列表/分页端点每页多一次主键 `IN` 批量查询(**整页 1 次,不是每行 1 次**)。 + `POST /v3/admin/payment/{transactionId}/sync` 的写事务内多一次同数据源本地读,该端点是管理员手动触发的低频操作。 +- **连带生效(无需单独对接,响应体同样多出该字段)**: + `POST /v3/admin/refund/orders/{orderId}`、`POST /v3/admin/payment/{transactionId}/sync`、 + 工单的 `POST /v3/admin/order/work-order`、`PUT …/process`、`PUT …/assign`、`POST …/comment`。 +- **`/v3/internal/` 侧连带多出该字段的 4 个端点**(服务间调用,公网网关不放行,前端不对接): + `POST /v3/internal/payment/refund`、`GET /v3/internal/payment/status/{orderId}`、 + `GET /v3/internal/payment/transactions/{orderId}`、`GET /v3/internal/order/{orderId}/transactions`。 + 它们复用同一批 VO,属向后兼容纯增。 + +--- + +## 七、不影响范围 + +- **`GET /v3/internal/payment/pay-info/{orderId}`(`PayInfoVO`)不追加任何字段** —— 非前端可见,本单明确不改。 +- **小程序端(mp 域)全部 VO 不动**。 +- **团期详情页的 5 个逐行 VO 不动**(`GroupBatchOrderItemRespVO` / `GroupBatchChipItemRespVO` / + `GroupBatchContractItemVO` / `GroupBatchFinanceItemVO` / `GroupBatchAdvanceItemVO`),另有工单跟进。 +- **`RefundApplicationDetailRespVO.RecordItemVO` 刻意不加**:同一响应体里的 record 行全属同一张订单, + 团号与 `orderInfo.teamNo` 必然相同,逐行重复只会让前端猜哪个是权威值。 +- **8 个已有 `teamNo` 的 VO 字段声明未被改动**;只订正了 3 处 Swagger `example` 字面量 + (`T2026…` → `26-0001`),字段名与文案不动。 +- **零改动**:Controller 方法体、Mapper、Entity、Flyway、错误码、hl-gateway 配置、其他微服务。 + +--- + +## 八、测试环境已验证 + +**部署**:`hl-order-service-v3` @ `feature/7537-team-no-backfill` / `6dcee7d4d`(已合并 dev-v3 = `c798fd5a6`), +双实例滚动重启完成。**全部实测经真实网关 `api.test.1814.love:9443` + Bearer 鉴权**。 + +| # | 端点 | 已付订金 | 未付订金 | +|---|---|---|---| +| 1 | `GET /v3/admin/refund/{refundId}` | 200,`teamNo="26-4823"` | 200,`teamNo=null` | +| 2 | `GET /v3/admin/refund/order/{orderId}/list` | 200,`teamNo="26-4823"` | 200,`teamNo=null` | +| 3 | `GET /v3/admin/payment/list` | 200,`26-4684` / `26-7561` / `26-0438` 三行各自正确 | 同页混合行含 `null` | +| 4 | `GET /v3/admin/payment/{transactionId}` | 200,`teamNo="26-4684"` | 200,`teamNo=null` | +| 5 | `GET /v3/admin/payment/order/{orderId}` | 200,两行均 `26-4684` | 200,`teamNo=null` | +| 6 | `GET /v3/admin/order/work-order/list` | 200,`26-6331`/`26-9208`/`26-1849` | 同页含 `teamNo=null` 行 | +| 7 | `GET /v3/admin/order/work-order/{workOrderId}` | 200,`teamNo="26-9208"` | 200,`teamNo=null` | +| 10 | `PUT /v3/admin/order-todos/{todoId}/complete` | 200,`teamNo="26-9208"` | 200,`teamNo=null` | + +**团期子订单也有团号**(挡住「以为只有团期单才有团号」的反向误解): +`GET /v3/admin/payment/order/2098372769329598466` → `teamNo="26-9069"`,该单 `group_batch_id` 非空。 + +**同团多户团号各不相同**:同一 `group_batch_id=2097500233511362561` 下的两张子订单, +经 `GET /v3/admin/order/work-order/{workOrderId}` 分别返 `26-9208` 与 `26-6331`。 + +**本地全量**:`mvn -o -pl hl-order-service-v3 -am test` → **9925 例 / Failures 0**; +其中新增 4 个测试类 35 例全绿,`RedLineArchTest` / `LayerEnforcementTest` / `MapperBoundaryArchTest` 均通过(非 Skipped)。 + +--- + +## 十、相关文档 + +- Issue:https://git.1814.love:8443/wx/HL/issues/7537 +- PR:https://git.1814.love:8443/wx/HL/pulls/7564 +- 字段来源 DDL:`hl-order-service-v3/src/main/resources/db/migration/V20260511_001__init_core_tables.sql:32` +- 团号生成器:`hl-order-service-v3/src/main/java/com/hulalv/order/core/service/GroupCodeService.java:11-17,30-37` + +--- + +## 关联 / 联系人 + +- 后端:jw +- 前端(hl-ui 管理后台):mmg +- 需求定案:wx(2026-09-11 选项卡)