文件
hl-api-changelog/changelogs-v2/2026-09/12_7537_管理端展示订单号的响应体统一补团号-修改接口-管理后台.md
T
2026-09-13 09:14:00 +08:00

1050 行
34 KiB
Markdown
原始文件 Blame 文件历史

此文件含有模棱两可的 Unicode 字符
此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。
---
schema: "hl-changelog/v2"
ticket: "7537"
title: "管理端展示订单号的响应体统一补团号(teamNo)"
consumer: "admin"
author: "jw(GIT)"
change_type: "修改接口"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "verified"
frontend_owner: "mmg"
frontend_ref: "f7699455"
target_release: ""
verified_at: "2026-09-13"
status_note: "响应体纯增字段,向后兼容:未消费 teamNo 的页面行为完全不变。前端可按需在退款记录、支付流水、协同工单三块列表/详情补一列「团号」。 前端 2026-09-13 已交付(hl-admin f7699455):逐块 grep 实证退款走申请 VO 且列表/详情已显示团号、订单待办已读 teamNo、支付流水无前端页面,三块 no-op;仅协同工单列表 work-order/index.vue 与详情抽屉 WorkOrderDetailDrawer 原本无团号,按可选增强各补一列 teamNo(列表 null 显 -,详情 v-if 有值才显)。checkpoint 7 项全绿(含生产构建)。"
updated_at: "2026-09-13"
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 <admin token>
```
#### 响应示例
```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<RefundRecordVO>`
#### 使用场景
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 <admin token>
```
#### 响应示例
```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<PaymentTransactionVO>`
#### 使用场景
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 <admin token>
```
#### 响应示例
```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 <admin token>
```
#### 响应示例
```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<PaymentTransactionVO>`
#### 使用场景
hl-ui 订单详情页的支付流水列表。**本单起每行多出 `teamNo`**。
#### 入参字段表
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|------|------|------|------|------|------|
| orderId | Path | Long | ✅ | 订单 ID | 订单 ID |
#### 出参字段表
| 字段 | 类型 | 说明 |
|------|------|------|
| teamNo | String | **本单新增**。团号,4 位,形如 `26-0001`。订金支付成功后生成;未生成、订单不存在或 `orderId` 为空时为 `null`(**不返空串、不回退订单号**) |
| (其余字段) | — | **全部不变**,本单不改动任何既有字段的名称、类型与语义 |
#### 请求示例
```http
GET /v3/admin/payment/order/{orderId}
Authorization: Bearer <admin token>
```
#### 响应示例
```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<WorkOrderRespVO>`
#### 使用场景
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 <admin token>
```
#### 响应示例
```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 <admin token>
```
#### 响应示例
```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 <admin token>
```
#### 响应示例
```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 <admin token>
```
#### 响应示例
```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 <admin token>
```
#### 响应示例
```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 <admin token>
```
#### 响应示例
```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<Long>)` 批量读出,**只读、不写**。
清单里的写端点(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 选项卡)