docs(changelog): 26_8375 房务配房列表合并抢单池(户级 / 团期两张列表)交接件
changelog-filename-gate / validate (push) Failing after 2s
changelog-filename-gate / validate (push) Failing after 2s
新增 GET /v3/admin/order/house-allocation/households 与 /group-batches, 五个旧抢单池读口标 @Deprecated(行为不变),菜单 101/102 下线、团期站内信链接改指订单列表。 第八节只列测试服 dev-v3 12707c57c 上的实测读数;808612/808613 与 productNo 降级标明未触发。 Refs wx/HL#8375 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
这个提交包含在:
@@ -0,0 +1,618 @@
|
||||
---
|
||||
schema: "hl-changelog/v2"
|
||||
ticket: "8375"
|
||||
title: "房务配房列表改版:并入订单列表,新增两个读端点(户级/团期),旧池端点标废弃,菜单与通知链接改向"
|
||||
consumer: "admin"
|
||||
author: "wx(GIT)"
|
||||
change_type: "新增接口"
|
||||
backend_status: "deployed"
|
||||
gateway_status: "verified"
|
||||
frontend_status: "pending"
|
||||
frontend_owner: ""
|
||||
frontend_ref: ""
|
||||
target_release: ""
|
||||
verified_at: "2026-09-26"
|
||||
status_note: "订单列表新增两个读端点替代房务抢单池;五个旧读端点标 @Deprecated;三个错误码文案改动(去「抢单池」);菜单 101/102 下线;团期通知链接改为订单列表。后端三个 PR(product-v2/#8381、order-v3/#8382、user-service/#8379)已合入 dev-v3 并部署测试服,逐条实测验证通过。"
|
||||
updated_at: "2026-09-26"
|
||||
base: "dev-v3"
|
||||
---
|
||||
|
||||
# 房务订单列表改版:新读端点替代抢单池、旧端点标废弃、菜单下线、通知改向(管理后台)
|
||||
|
||||
> **服务**: hl-order-service-v3(端口 8086/8186)/ hl-user-service(端口 8089/8189)
|
||||
> **PR**: #8381(product-v2)/ #8382(order-v3)/ #8379(user-service)
|
||||
> **Issue**: #8375
|
||||
> **日期**: 2026-09-26
|
||||
> **影响范围**: 房务管家 › 订单列表的页签切换、筛选项恢复、「开始配房」入口改向、所有房务角色的可见范围放开、旧页面与菜单下线
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ 关键变化
|
||||
|
||||
1. **新增两个读端点**,替代房务抢单池两个旧页面:
|
||||
- `GET /v3/admin/order/house-allocation/households`:户级(核心/定制订单)
|
||||
- `GET /v3/admin/order/house-allocation/group-batches`:团期订单
|
||||
|
||||
2. **五个旧读端点标 `@Deprecated`**,行为不变,但前端改调新端点:
|
||||
- `GET /v3/admin/order/grab-pool/hotel-requirements`
|
||||
- `GET /v3/admin/order/grab-pool/group-batches`
|
||||
- `GET /v3/admin/order/grab-pool/my-claims/hotel`
|
||||
- `GET /v3/admin/order/grab-pool/my-claims/group-batches`
|
||||
- `GET /v3/admin/order/grab-pool/all-claims/hotel`
|
||||
|
||||
3. **权限视图放开**:两个新端点都挂读门 `HouseReadPermission`,不限 `scope=all`;普通房务也能看全员认领情况(旧的 `all-claims/hotel` 仍返回 808092)。
|
||||
|
||||
4. **认领写口不变**:保持现有逻辑,只是入口从池页改到列表行:
|
||||
- 户级:`POST /v3/admin/order/hotel-requirements/{requirementId}/claim`
|
||||
- 团期:`POST /v3/admin/order/grab-pool/group-batches/{groupBatchId}/claim`
|
||||
|
||||
5. **三个错误码文案改动**,去掉"抢单池"页面名:
|
||||
- 808650:改为「团期订单须整团认领后配房,不支持逐户认领 / 转单」
|
||||
- 808612:改为「该团期尚未被房务整团认领」
|
||||
- 808001:改为「该需求已被其他房务认领或状态已变化,请刷新后重试」
|
||||
|
||||
6. **菜单下线**:房务抢单池菜单(菜单 101 与 102)已在 user-service 侧置为 INACTIVE,部署后生效。
|
||||
|
||||
7. **团期通知链接改向**:站内链接由 `/housekeeper/grab-pool-group?groupBatchId=` 改为 `/housekeeper/orders?groupBatchId=`(订单列表团期页签)。
|
||||
|
||||
---
|
||||
|
||||
## 一、背景
|
||||
|
||||
房务原来要在"订单列表"和"房务抢单池"两个页面之间来回切,体验割裂。本次改版将**待配房**的单并入**订单列表**,整合三类订单视图:
|
||||
- 待配房:所有房务都能点「开始配房」认领
|
||||
- 配房中:谁在做,全员可见
|
||||
- 已认领:可按「我的」或「全部」筛选
|
||||
|
||||
新端点按以下规则返回行:
|
||||
- **户级行**(order_main 表,group_batch_id 与 product_batch_id 都为空)
|
||||
- 待配房:`status=PENDING` 且 `claimer_id IS NULL`
|
||||
- 已认领:`status=PENDING` 且 `claimer_id IS NOT NULL`
|
||||
- **团期行**(order_group_batch 表,整团一行)
|
||||
- 待配房:`house_claimer_id IS NULL` 且 `requirement_confirmed=1` 且 `batch_status=RESOURCE_PREPARING`
|
||||
- 已认领:`house_claimer_id IS NOT NULL`(任意阶段)
|
||||
|
||||
---
|
||||
|
||||
## 二、变更接口清单
|
||||
|
||||
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|
||||
|---|------|------|------|----------|------|
|
||||
| 1 | 房务配房列表·户级 | GET | `/v3/admin/order/house-allocation/households` | **新增接口** | 户级页签(核心/定制订单),分页返回 |
|
||||
| 2 | 房务配房列表·团期 | GET | `/v3/admin/order/house-allocation/group-batches` | **新增接口** | 团期页签,整团一行 |
|
||||
|
||||
**旧端点标废弃(行为不变)**:`GET /v3/admin/order/grab-pool/hotel-requirements`、`/grab-pool/group-batches`、`/grab-pool/my-claims/hotel`、`/grab-pool/my-claims/group-batches`、`/grab-pool/all-claims/hotel` 加 `@Deprecated`,详见第五章节。
|
||||
|
||||
网关无改动(均在既有 `/v3/admin/order/` 前缀下);新路径已验证可达。
|
||||
|
||||
---
|
||||
|
||||
## 三、接口详情
|
||||
|
||||
### 1. 房务配房列表·户级 `GET /v3/admin/order/house-allocation/households`
|
||||
|
||||
**VO**: `HouseAllocationHouseholdPageReqVO` → `HouseAllocationHouseholdPageRespVO`
|
||||
|
||||
#### 使用场景
|
||||
|
||||
房务管家 › 订单列表的**核心**和**定制**页签,以及**全部**页签的户级数据部分。返回户级订单(order_main),按待配房/已认领分行展示,支持 `scope` 筛选当前用户或全员,按多种条件排序和分页。
|
||||
|
||||
#### 入参字段表
|
||||
|
||||
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|
||||
|------|------|------|------|------|------|
|
||||
| scope | Query | String | 否 | `all` \| `mine`,小写 | 默认 `all`;`mine` 则只返回当前用户认领的行,`pendingClaim` 桶恒为 0 |
|
||||
| status | Query | String | 否 | `pendingClaim` \| `unfinished` \| `claiming` \| `pendingConfirm` \| `confirmed` \| `exception`,或空 | 默认 `unfinished`;空串表示全部;返回对应 house_status 的行 |
|
||||
| productType | Query | String | 否 | `CORE` \| `CUSTOM`,或空 | 空或不传表示全部户级行;不接受 `productType=GROUP`(团期订单走团期端点) |
|
||||
| keyword | Query | String | 否 | `@Size(max=32)` | 模糊匹配:订单号 / 团号 / 客人姓名 / 产品名(OR) |
|
||||
| productName | Query | String | 否 | — | 模糊匹配产品名 |
|
||||
| consultantId | Query | Long | 否 | — | 定制师 ID,精确匹配 |
|
||||
| guestName | Query | String | 否 | — | 客人姓名,模糊匹配 |
|
||||
| departDateFrom | Query | LocalDate | 否 | `yyyy-MM-dd` | 出发日期起 |
|
||||
| departDateTo | Query | LocalDate | 否 | `yyyy-MM-dd` | 出发日期止(含) |
|
||||
| claimedAtFrom | Query | LocalDateTime | 否 | `yyyy-MM-dd'T'HH:mm:ss` | 认领时间起;传了就等于只看已认领的行 |
|
||||
| claimedAtTo | Query | LocalDateTime | 否 | `yyyy-MM-dd'T'HH:mm:ss` | 认领时间止 |
|
||||
| page | Query | Integer | 否 | `@Min(1)` | 默认 1 |
|
||||
| pageSize | Query | Integer | 否 | `@Min(1) @Max(100)` | 默认 20 |
|
||||
| sortBy | Query | String | 否 | `departDate,asc` \| `createTime,desc` \| `claimedAt,desc` | 默认 `departDate,asc`;**无论选哪个,都先按手动加急(manual_urgent DESC, manual_urgent_at DESC)排** |
|
||||
|
||||
#### 出参字段表
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| list | List\<HouseAllocationHouseholdRespVO\> | 分页结果行 |
|
||||
| total | Long | 满足条件的总行数 |
|
||||
| stats | HouseAllocationHouseholdStatsVO | 各页签的计数(与列表共用筛选条件,忽略 status) |
|
||||
|
||||
**行字段详情(HouseAllocationHouseholdRespVO)**:
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| id | String | requirementId,前端「开始配房」时用此值 |
|
||||
| orderId | String | 订单 ID,进户级详情时用 |
|
||||
| orderNo / teamNo | String | 订单号 / 团号 |
|
||||
| guestName | String | 客人姓名 |
|
||||
| personsDesc | String | 人数描述(如「2成人1儿童」) |
|
||||
| productType | String | 产品类型(CORE/CUSTOM/ROUTE/…) |
|
||||
| productName | String | 产品名称 |
|
||||
| productNo | String | 产品编号;来自 product-v2 批量查询,**取不到时为 null**(见降级响应) |
|
||||
| route | String | 行程描述 |
|
||||
| cities | List\<String\> | 城市列表 |
|
||||
| departDate | LocalDate | 出发日期 |
|
||||
| nights | Integer | 晚数 |
|
||||
| totalAmount | String | 订单金额(后端计算,已序列化为字符串) |
|
||||
| consultantId | String | 定制师 ID |
|
||||
| consultantName | String | 定制师姓名 |
|
||||
| consultantRemark | String | 定制师备注 |
|
||||
| requirementNote | String | 需求备注 |
|
||||
| dispatchRemark | String | 派车备注 |
|
||||
| special | String | 特殊需求 |
|
||||
| requirementVersion | Integer | 需求版本号 |
|
||||
| requirementStatus | String | 对外状态(PENDING/PROCESSING/DONE/…) |
|
||||
| houseStatus | String | **枚举码**:PENDING_CLAIM / CLAIMING / PENDING_FINALIZE / CONFIRMED / EXCEPTION;与旧 VO 的中文名不同 |
|
||||
| houseStatusLabel | String | 中文显示名(「待配房」/「配房中」/「待确认」/「已确认」/「异常」) |
|
||||
| claimerId | String | 当前认领人 ID;待配房行为 null |
|
||||
| claimerName | String | 当前认领人名字;待配房行为 null |
|
||||
| claimedAt | LocalDateTime | 认领时间;待配房行为 null |
|
||||
| isMine | Boolean | 认领人是否当前用户 |
|
||||
| canStartAllocation | Boolean | 前端「开始配房」按钮的**唯一依据**(true 时显示,false 时隐藏);条件:`status=PENDING` 且 `claimerId IS NULL` 且当前用户有写权限 |
|
||||
| manualUrgent | Boolean | 手动加急标记 |
|
||||
| manualUrgentAt | LocalDateTime | 加急时间 |
|
||||
| urgencyLevel | String | 紧急度标签(LOW/MEDIUM/HIGH) |
|
||||
| urgencyLabel | String | 紧急度中文名(「低」/「中」/「高」) |
|
||||
| daysToDepart | Integer | 距出发还有几天(负数表示已出发) |
|
||||
| isRework | Boolean | 是否返工 |
|
||||
| reworkPrevClaimerName | String | 上次认领人名字 |
|
||||
| exceptionCount | Integer | 已认领行:该户有几个未处理异常待办;待配房行为 0 |
|
||||
| todoCount | Integer | 已认领行:该户有几个待办;待配房行为 0 |
|
||||
| primaryAction | HousePrimaryActionVO | 只在 `isMine=true` 时返回;包含转单、释放等操作信息 |
|
||||
| createTime | LocalDateTime | 需求创建时间 |
|
||||
|
||||
**stats 分桶计数(HouseAllocationHouseholdStatsVO)**:
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| pendingClaim | Long | 待配房行数;`scope=mine` 时恒为 0 |
|
||||
| claiming | Long | house_status=CLAIMING 的行数 |
|
||||
| pendingConfirm | Long | house_status=PENDING_FINALIZE 的行数 |
|
||||
| confirmed | Long | house_status=CONFIRMED 的行数 |
|
||||
| exception | Long | house_status=EXCEPTION 或订单有未处理异常待办的行数 |
|
||||
| unfinished | Long | 待配房 + 配房中 + 待确认 + 异常 的行数;与 `status=unfinished` 的查询结果同源 |
|
||||
| all | Long | 待配房 + 已认领 的总行数;与不传 status 的查询结果同源 |
|
||||
|
||||
#### 请求示例
|
||||
|
||||
```http
|
||||
GET /v3/admin/order/house-allocation/households?scope=all&status=pendingClaim&productType=CORE&page=1&pageSize=20&sortBy=departDate,asc HTTP/1.1
|
||||
Host: api.test.1814.love:9443
|
||||
Authorization: Bearer ***
|
||||
```
|
||||
|
||||
无请求体。
|
||||
|
||||
#### 响应示例
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "成功",
|
||||
"success": true,
|
||||
"data": {
|
||||
"list": [
|
||||
{
|
||||
"id": "2097250563497385985",
|
||||
"orderId": "770145",
|
||||
"orderNo": "O20260926001",
|
||||
"teamNo": null,
|
||||
"guestName": "张三",
|
||||
"personsDesc": "2成人1儿童",
|
||||
"productType": "CORE",
|
||||
"productName": "日本东京 6 日游",
|
||||
"productNo": "P002301",
|
||||
"route": "东京→富士山→京都",
|
||||
"cities": ["东京", "富士山", "京都"],
|
||||
"departDate": "2026-10-01",
|
||||
"nights": 6,
|
||||
"totalAmount": "8500.00",
|
||||
"consultantId": "1001",
|
||||
"consultantName": "李四",
|
||||
"consultantRemark": "客户有特殊需求",
|
||||
"requirementNote": "希望升级酒店",
|
||||
"dispatchRemark": "已预留",
|
||||
"special": "客户晕车,安排靠窗座位",
|
||||
"requirementVersion": 1,
|
||||
"requirementStatus": "PROCESSING",
|
||||
"houseStatus": "PENDING_CLAIM",
|
||||
"houseStatusLabel": "待配房",
|
||||
"claimerId": null,
|
||||
"claimerName": null,
|
||||
"claimedAt": null,
|
||||
"isMine": false,
|
||||
"canStartAllocation": true,
|
||||
"manualUrgent": true,
|
||||
"manualUrgentAt": "2026-09-25T14:30:00",
|
||||
"urgencyLevel": "HIGH",
|
||||
"urgencyLabel": "高",
|
||||
"daysToDepart": 5,
|
||||
"isRework": false,
|
||||
"reworkPrevClaimerName": null,
|
||||
"exceptionCount": 0,
|
||||
"todoCount": 0,
|
||||
"primaryAction": null,
|
||||
"createTime": "2026-09-20T09:00:00"
|
||||
}
|
||||
],
|
||||
"total": 12,
|
||||
"stats": {
|
||||
"pendingClaim": 12,
|
||||
"claiming": 5,
|
||||
"pendingConfirm": 3,
|
||||
"confirmed": 8,
|
||||
"exception": 1,
|
||||
"unfinished": 21,
|
||||
"all": 28
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 空数据 / 降级响应
|
||||
|
||||
- 分页无结果时,`list=[]`,`total=0`,`stats` 各字段为 0,`code=200` 不报错:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "成功",
|
||||
"success": true,
|
||||
"data": {
|
||||
"list": [],
|
||||
"total": 0,
|
||||
"stats": { "pendingClaim": 0, "claiming": 0, "pendingConfirm": 0, "confirmed": 0, "exception": 0, "unfinished": 0, "all": 0 }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- **productNo 取不到时**(product-v2 服务降级或响应缺字段),该字段为 null,其余字段正常返回,不报错。
|
||||
|
||||
- **参数不合法时**(status、productType、sortBy 等与规则不符),HTTP 200,`code=400`(全局 BindException 处理),`message` 是具体字段的校验文案。下面是传 `productType=GROUP` 的实测原文:
|
||||
|
||||
```json
|
||||
{"code":400,"message":"productType 只能是 CORE 或 CUSTOM","data":null,"traceId":null,"success":false}
|
||||
```
|
||||
|
||||
#### 错误响应
|
||||
|
||||
- **未登录或无房务读权限**(808090):
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 808090,
|
||||
"message": "未登录或无该操作权限",
|
||||
"success": false,
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
#### 业务边界
|
||||
|
||||
- 查询条件 `claimedAtFrom/claimedAtTo` 同时传递时,等于隐含过滤 `claimerId IS NOT NULL`(只看已认领的行);与 `status=pendingClaim` 同传时查询结果为空、`code=200`、`stats.pendingClaim=0`,不报错。
|
||||
- 手动加急 `manual_urgent=true` 的行在任何 `status` 页签里都会被提前排列(加急 DESC,加急时间 DESC),无论选何种 sortBy。
|
||||
- **并发认领**:前端的「开始配房」按钮直接调 `POST /v3/admin/order/hotel-requirements/{id}/claim`,若二人同时点同一行,先到者返回 200,后到者返回 808001 并附加新文案「该需求已被其他房务认领或状态已变化,请刷新后重试」,前端刷新列表即可看到当前认领人。
|
||||
- **异常数据(存量)**:列表里个别行的 `orderNo` 或 `productName` 可能为 null(对应主订单已软删除),前端需容忍空值、不做特殊提示,只显示已有字段。
|
||||
- 转单、释放等操作只在 `isMine=true` 的行显示(`primaryAction` 非 null);他人认领的行为只读。
|
||||
- `requirementStatus` 是订单对外状态,`houseStatus` 是该户配房阶段(两个维度独立)。
|
||||
|
||||
---
|
||||
|
||||
### 2. 房务配房列表·团期 `GET /v3/admin/order/house-allocation/group-batches`
|
||||
|
||||
**VO**: `HouseAllocationGroupPageReqVO` → `HouseAllocationGroupPageRespVO`
|
||||
|
||||
#### 使用场景
|
||||
|
||||
订单列表的**团期**页签,整团一行。返回团期订单(order_group_batch),按待配房/已认领分行展示。前端的通知链接 `?groupBatchId=<团ID>` 也以此端点定位落地。
|
||||
|
||||
#### 入参字段表
|
||||
|
||||
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|
||||
|------|------|------|------|------|------|
|
||||
| scope | Query | String | 否 | `all` \| `mine` | 默认 `all`;`mine` 时只返回当前用户认领的团 |
|
||||
| status | Query | String | 否 | `pendingClaim` \| `claimed`,或空 | 空或不传表示两者都要 |
|
||||
| groupBatchId | Query | Long | 否 | — | 精确定位一个团(通知链接用);传了则 1 条或 0 条结果 |
|
||||
| keyword | Query | String | 否 | `@Size(max=32)` | 模糊匹配:团期号 / 产品名(OR) |
|
||||
| productId | Query | Long | 否 | — | 产品 ID,精确匹配 |
|
||||
| batchStatus | Query | String | 否 | `RECRUITING` \| `RESOURCE_PREPARING` \| `MATERIAL_PREPARING` \| `PENDING_DEPARTURE` \| `TRAVELLING` \| `TRIP_FINISHED` \| `REVIEWING` \| `SETTLED` \| `CANCELLED` | 团期阶段,精确匹配 |
|
||||
| departDateFrom | Query | LocalDate | 否 | `yyyy-MM-dd` | 出发日期起 |
|
||||
| departDateTo | Query | LocalDate | 否 | `yyyy-MM-dd` | 出发日期止 |
|
||||
| claimedAtFrom | Query | LocalDateTime | 否 | `yyyy-MM-dd'T'HH:mm:ss` | 认领时间起 |
|
||||
| claimedAtTo | Query | LocalDateTime | 否 | `yyyy-MM-dd'T'HH:mm:ss` | 认领时间止 |
|
||||
| page | Query | Integer | 否 | `@Min(1)` | 默认 1 |
|
||||
| pageSize | Query | Integer | 否 | `@Min(1) @Max(100)` | 默认 20 |
|
||||
| sortBy | Query | String | 否 | `departDate,asc` \| `claimedAt,desc` \| `createTime,desc` | 默认 `departDate,asc` |
|
||||
|
||||
#### 出参字段表
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| list | List\<HouseAllocationGroupRespVO\> | 分页结果行 |
|
||||
| total | Long | 满足条件的总行数 |
|
||||
| stats | HouseAllocationGroupStatsVO | 三个页签的计数:pendingClaim / claimed / all |
|
||||
|
||||
**行字段详情(HouseAllocationGroupRespVO)**:
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| groupBatchId | String | 团期 ID,前端「开始配房」时用此值 |
|
||||
| batchNo | String | 团期号 |
|
||||
| batchName | String | 团期名称 |
|
||||
| batchLabel | String | 团期标签 |
|
||||
| productId | String | 产品 ID |
|
||||
| productName | String | 产品名称 |
|
||||
| batchStatus | String | 团期阶段码(RECRUITING/RESOURCE_PREPARING/…) |
|
||||
| batchStatusLabel | String | 中文显示名(「招募中」/「资源准备中」/…) |
|
||||
| departDate | LocalDate | 出发日期 |
|
||||
| endDate | LocalDate | 结束日期 |
|
||||
| enrollDeadline | LocalDate | 报名截止日期 |
|
||||
| enrolledRooms | Integer | 已报名房间数 |
|
||||
| enrolledPeople | Integer | 已报名人数 |
|
||||
| activeOrderCount | Integer | 活跃订单数 |
|
||||
| hotelOrderCount | Integer | 需要配房的订单数 |
|
||||
| hotelReady | Integer | 已配房的订单数 |
|
||||
| daysToDepart | Integer | 距出发还有几天 |
|
||||
| urgencyLevel | String | 紧急度标签(LOW/MEDIUM/HIGH) |
|
||||
| urgencyLabel | String | 紧急度中文名 |
|
||||
| requirementConfirmed | Boolean | 团期需求是否已整体确认(仅信息展示,不影响认领) |
|
||||
| houseClaimerId | String | 团级认领人 ID;待配房时为 null |
|
||||
| houseClaimerName | String | 团级认领人名字;待配房时为 null |
|
||||
| houseClaimedAt | LocalDateTime | 认领时间;待配房时为 null |
|
||||
| isMine | Boolean | 认领人是否当前用户 |
|
||||
| canStartAllocation | Boolean | 前端「开始配房」按钮的**唯一依据**;条件:`houseClaimerId IS NULL` 且当前用户有写权限 |
|
||||
| createTime | LocalDateTime | 创建时间 |
|
||||
|
||||
**stats 分桶计数(HouseAllocationGroupStatsVO)**:
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| pendingClaim | Long | 待配房团数(`houseClaimerId IS NULL` 且 `requirementConfirmed=1` 且 `batchStatus=RESOURCE_PREPARING`) |
|
||||
| claimed | Long | 已认领团数(`houseClaimerId IS NOT NULL`,任意阶段) |
|
||||
| all | Long | pendingClaim + claimed 的总数 |
|
||||
|
||||
#### 请求示例
|
||||
|
||||
```http
|
||||
GET /v3/admin/order/house-allocation/group-batches?scope=all&status=pendingClaim&page=1&pageSize=20 HTTP/1.1
|
||||
Host: api.test.1814.love:9443
|
||||
Authorization: Bearer ***
|
||||
```
|
||||
|
||||
无请求体。
|
||||
|
||||
#### 响应示例
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "成功",
|
||||
"success": true,
|
||||
"data": {
|
||||
"list": [
|
||||
{
|
||||
"groupBatchId": "2097250563497385985",
|
||||
"batchNo": "G20260926001",
|
||||
"batchName": "日本 10 月团·东京-京都-大阪",
|
||||
"batchLabel": "标准",
|
||||
"productId": "5001",
|
||||
"productName": "日本东京-京都-大阪 8 日游",
|
||||
"batchStatus": "RESOURCE_PREPARING",
|
||||
"batchStatusLabel": "资源准备中",
|
||||
"departDate": "2026-10-05",
|
||||
"endDate": "2026-10-12",
|
||||
"enrollDeadline": "2026-09-28",
|
||||
"enrolledRooms": 8,
|
||||
"enrolledPeople": 16,
|
||||
"activeOrderCount": 8,
|
||||
"hotelOrderCount": 8,
|
||||
"hotelReady": 0,
|
||||
"daysToDepart": 9,
|
||||
"urgencyLevel": "HIGH",
|
||||
"urgencyLabel": "高",
|
||||
"requirementConfirmed": false,
|
||||
"houseClaimerId": null,
|
||||
"houseClaimerName": null,
|
||||
"houseClaimedAt": null,
|
||||
"isMine": false,
|
||||
"canStartAllocation": true,
|
||||
"createTime": "2026-09-15T10:00:00"
|
||||
}
|
||||
],
|
||||
"total": 5,
|
||||
"stats": {
|
||||
"pendingClaim": 5,
|
||||
"claimed": 12,
|
||||
"all": 17
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 空数据 / 降级响应
|
||||
|
||||
- 分页无结果:`list=[]`,`total=0`,`stats` 各字段为 0,`code=200`:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "成功",
|
||||
"success": true,
|
||||
"data": {
|
||||
"list": [],
|
||||
"total": 0,
|
||||
"stats": { "pendingClaim": 0, "claimed": 0, "all": 0 }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- 参数不合法时,HTTP 200,`code=400`,`message` 是具体字段的校验文案(结构同户级端点):
|
||||
|
||||
```json
|
||||
{"code":400,"message":"<该字段的校验文案>","data":null,"traceId":null,"success":false}
|
||||
```
|
||||
|
||||
#### 错误响应
|
||||
|
||||
- **未登录或无房务读权限**(808090):
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 808090,
|
||||
"message": "未登录或无该操作权限",
|
||||
"success": false,
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
#### 业务边界
|
||||
|
||||
- **整团一行**:团期阶段任意时刻只要被认领一次,就会在列表持续出现(`claimed` 页签或混合页签),不会因为进入后续阶段(待出发、出行中等)而消失。
|
||||
- **并发认领**:前端的「开始配房」按钮直接调 `POST /v3/admin/order/grab-pool/group-batches/{groupBatchId}/claim`。并发场景下:
|
||||
- 团期 claim 端点挂了 `@Idempotent`(5 秒窗口)与 `@Lock4j` 两重防护
|
||||
- 同时提交会被幂等或锁层拦下,返回 **100502**(「整团认领处理中,请勿重复提交」,幂等窗口内),前端提示并刷新列表
|
||||
- 窗口过后别人已抢到会返回 **808652**(「该团期已被其他房务认领」)
|
||||
- **他人认领的团不提供看板入口**:前端对 `isMine=false` 的行不显示「查看看板」入口(若用户直接访问详情页,会得到 808612 或 808613 拒绝);详情页权限不变。
|
||||
- 订单列表的通知参数 `?groupBatchId=<团ID>` 须在团期页签按此参数定位(可配合 filter 或直接查询定位)。
|
||||
|
||||
---
|
||||
|
||||
## 四、契约约束与正确调用方式
|
||||
|
||||
| 场景 | 调用方法 | 说明 |
|
||||
|------|---------|------|
|
||||
| ✅ 户级「开始配房」| `POST /v3/admin/order/hotel-requirements/{id}/claim` | 直接调现有写口,行为不变;`canStartAllocation=true` 时显示按钮 |
|
||||
| ✅ 团期「开始配房」| `POST /v3/admin/order/grab-pool/group-batches/{groupBatchId}/claim` | 同上;路径保留 grab-pool,因为是现有写口 |
|
||||
| ✅ 查看全员认领情况 | `GET /v3/admin/order/house-allocation/households?scope=all` 或 `/group-batches?scope=all` | **普通房务首次可见**;旧端点 `all-claims/` 仍返回 808092 |
|
||||
| ✅ 刷新列表信号 | 监听 SSE 事件 `grab-pool-changed` | 现有 SSE 通道保留,不新增事件 |
|
||||
| ❌ 调旧端点继续写代码 | `GET /v3/admin/order/grab-pool/hotel-requirements` | @Deprecated,禁用 |
|
||||
| ❌ 团期已被他人认领后再点「开始配房」 | — | 返回 808652「该团期已被其他房务认领」,刷新列表即可看到认领人,不要重试 |
|
||||
|
||||
---
|
||||
|
||||
### 配套变更说明
|
||||
|
||||
#### 错误码文案更新
|
||||
|
||||
随 PR-1 部署,三个错误码文案改动(去掉对「抢单池」页面的引用):
|
||||
|
||||
| 码 | 旧文案 | 新文案 | 触发场景 |
|
||||
|----|--------|--------|---------|
|
||||
| **808650** | "团期订单须整团认领,不支持逐户认领。请到团期抢单池整团认领" | "团期订单须整团认领后配房,不支持逐户认领 / 转单" | 试图逐户认领 / 转单一个团期订单 |
|
||||
| **808612** | "该团期尚未被房务认领,请先到团期抢单池认领" | "该团期尚未被房务整团认领" | 进入他人未认领的团期看板,或操作不满足条件的团期 |
|
||||
| **808001** | "需求已被其他房务抢到" | "该需求已被其他房务认领或状态已变化,请刷新后重试" | 户级并发认领冲突,或状态变化后重复调用 |
|
||||
|
||||
#### 房务抢单池菜单下线
|
||||
|
||||
随 PR-2 部署(Flyway `V20260926_001`):
|
||||
- 菜单 101(「抢单池·普通」,路径 `/housekeeper/grab-pool`)置为 INACTIVE
|
||||
- 菜单 102(「抢单池·团期」,路径 `/housekeeper/grab-pool-group`)置为 INACTIVE
|
||||
|
||||
菜单对所有角色同步生效(按 ACTIVE 状态过滤)。缓存于 user-service 启动完成时自动刷新;若启动日志出现"应用启动后刷新菜单缓存失败",需手工 Redis DEL 对应 key(1 小时 TTL 后自动过期)。
|
||||
|
||||
#### 团期通知链接改向
|
||||
|
||||
随 PR-2 部署(SQL Flyway 更新通知配置),三条团期站内链接由抢单池改指订单列表:
|
||||
|
||||
| 通知事件 | 原链接 | 新链接 | 内容变化 |
|
||||
|---------|--------|--------|---------|
|
||||
| GROUP_BATCH_HOUSE_CLAIMED | `/housekeeper/grab-pool-group?groupBatchId=` | `/housekeeper/orders?groupBatchId=` | 链接改向;内容不再含「抢单池」词语 |
|
||||
| GROUP_BATCH_HOUSE_RELEASED | `/housekeeper/grab-pool-group?groupBatchId=` | `/housekeeper/orders?groupBatchId=` | 同上 |
|
||||
| GROUP_BATCH_REQUIREMENT_CONFIRMED | `/housekeeper/grab-pool-group?groupBatchId=` | `/housekeeper/orders?groupBatchId=` | 同上 |
|
||||
|
||||
#### 旧读端点标废弃
|
||||
|
||||
五个旧端点的 Controller 方法加 `@Deprecated` 注解;Swagger 操作描述末尾补充「(已废弃,改用 /v3/admin/order/house-allocation/…)」。**行为与字段完全不变**,现有消费方在迁移完毕前仍可继续调用,但新代码禁止接入。
|
||||
|
||||
迁移完毕后(todos 与作废页签移至新端点或别处)方开工单删除。
|
||||
|
||||
---
|
||||
|
||||
## 五、数据库行为
|
||||
|
||||
无表结构变更,无 H2 迁移脚本改动。user-service Flyway `V20260926_001` 更新系统菜单与通知配置(非业务表)。
|
||||
|
||||
---
|
||||
|
||||
## 六、边界行为
|
||||
|
||||
- 两个新端点都挂读门 `HouseReadPermission`,非房务角色(或未登录)返回 808090;普通房务、组长、超管均可调(不限 `scope=all`),这是与旧 `all-claims/` 最大的权限差异。
|
||||
- 写口(认领、转单、释放)权限不变:写门只放行 ROOM_MANAGER 与 SUPER_ADMIN;房务组长(house_keeper_lead)调写口返回 808091,其他角色返回 808090。所以组长在两个新端点上所有行 `canStartAllocation=false`。
|
||||
- SSE 广播现有四类事件 ADDED / CLAIMED / RELEASED / URGENT 保留,团期认领、释放、接管不补新事件(现状事实:旧池亦不发,属既知设计)。
|
||||
- 他人认领的团期行只读:行操作(转单、释放等)只在 `isMine=true` 时展示;若直接访问团期看板详情,会得 808612/808613 拒绝。
|
||||
- 参数校验失败(如 status 值非法)走全局 `BindException`,HTTP 200,`code=400`(非 400 HTTP 状态)。
|
||||
|
||||
---
|
||||
|
||||
## 七、不影响范围
|
||||
|
||||
- **认领、转单、释放、接管的写逻辑**:完全不变,只改入口
|
||||
- **订单详情读权限**:不变
|
||||
- **小程序端**(`/v3/mp/`):无改动
|
||||
- **旧池的五个读端点在存量消费方(todos、作废页签)迁移完毕前**仍可继续调用
|
||||
- **SSE 通道与事件**:保留现有四类,不新增
|
||||
- **子订单状态机、配房流程**:不变
|
||||
- **身份权限种子与角色**:不变(仅房务菜单下线,不涉及角色、权限位、权限码)
|
||||
- **网关配置**:无改动;新路径在现有通配规则 `Path=/v3/admin/**` 下已生效
|
||||
|
||||
---
|
||||
|
||||
## 八、测试环境已验证
|
||||
|
||||
部署:`hl-gateway` / `hl-user-service` / `hl-product-service-v2` / `hl-order-service-v3` 四个服务均为 dev-v3 `12707c57c`(`deploy-status.sh` 四行 ok,2026-09-26 15:47~16:06 滚完)。以下读数都是经网关 `api.test.1814.love`、用真实账号鉴权的实测结果(2026-09-26)。
|
||||
|
||||
| # | 场景 | 实测结果 |
|
||||
|---|---|---|
|
||||
| 1 | 户级「开始配房」:两个普通房务并发认领同一行 | 一个 200,另一个 808001「已被认领或状态已变化」。随后另一人在列表里看到该行:`claimerName` = 认领人,`isMine=false`,`canStartAllocation=false` |
|
||||
| 2 | 普通房务对他人已认领的户级行调认领 / 转交 / 释放 | 分别返回 808001 / 808010 / 808020,行状态不变 |
|
||||
| 3 | 普通房务调户级列表 `scope=all` | code=200;旧端点 `GET /grab-pool/all-claims/hotel` 仍返回 808092(旧权限策略不变) |
|
||||
| 4 | 团期「开始配房」:两个普通房务同时点击 | 5 秒幂等窗口内,后到者 100502;窗口外重试 808652。列表中该团 `houseClaimerName` = 先到者 |
|
||||
| 5 | 房务主管(`house_keeper_lead`)调两个列表 | 均 code=200。全量翻页:户级 107 行、团期 109 行,`canStartAllocation` 全部为 false |
|
||||
| 6 | 房务主管调「开始配房」 | 808091「房务组长为只读监督角色,无权执行该操作」 |
|
||||
| 7 | 非房务角色调两个列表 | 808090「未登录或非房务角色,无权操作」 |
|
||||
| 8 | 户级列表传 `productType=GROUP` | HTTP 200,`{"code":400,"message":"productType 只能是 CORE 或 CUSTOM"}` |
|
||||
| 9 | 团期订单不进户级列表 | 全量翻页户级 107 行,与团期的需求 ID、订单 ID 交集均为 0;阳性对照(已知户级行)在列 |
|
||||
| 10 | 加急行排序 | 把原在第 2 页第 9 位的样本标为加急后,它移到第 1 页第 1 位,第 2 页没有加急行(样本已还原) |
|
||||
| 11 | `stats` 与列表同源 | 户级:不筛选 total=107,`productType=CORE` total=105,7 个状态分桶的 `stats` 与按该状态查询的 `total` 逐一相等。团期:不筛选 `stats` 为 45 / 64 / 109(pendingClaim / claimed / all),带关键字为 24 / 53 / 77,均与对应 `total` 相等 |
|
||||
| 12 | `scope=mine` 与 `status=pendingClaim` 同传 | code=200,空页 |
|
||||
| 13 | 整团认领后的站内信 | 6 条 CLAIMED 记录的链接为 `/housekeeper/orders?groupBatchId=<团期ID>`,正文不含「抢单池」;用该 `groupBatchId` 查团期列表,total=1 |
|
||||
| 14 | 5 个旧端点 | 均 code=200,响应结构不变;Swagger 中 `deprecated=true` |
|
||||
| 15 | 菜单 | 普通房务 ×2、房务主管、超管共 4 个账号,当前菜单树里都没有菜单 101 / 102 |
|
||||
| 16 | 户级列表 `productNo` | 抽 3 行,与库中产品编号一致 |
|
||||
| 17 | 关联订单已软删的存量需求行 | 该行 `orderNo` / `productName` / `productNo` 为 null,列表 code=200 照常返回 |
|
||||
|
||||
**本次未在测试服触发、只按代码契约给出的**:808612 / 808613(看他人认领的团期看板);`productNo` 取数失败时的降级(Feign fallback 置 null)。
|
||||
|
||||
---
|
||||
|
||||
## 十、相关文档
|
||||
|
||||
- **Issue**: [#8375](https://git.1814.love/wx/HL/issues/8375)
|
||||
- **PR**:
|
||||
- [#8381](https://git.1814.love/wx/HL/pulls/8381)(product-v2)
|
||||
- [#8382](https://git.1814.love/wx/HL/pulls/8382)(order-v3)
|
||||
- [#8379](https://git.1814.love/wx/HL/pulls/8379)(user-service)
|
||||
- **涉及表结构**: 无
|
||||
- **数据库变更**: user-service Flyway `V20260926_001`(菜单下线 + 通知链接改向)
|
||||
|
||||
## 关联 / 联系人
|
||||
|
||||
### 链接
|
||||
|
||||
- **Issue**: [#8375](https://git.1814.love/wx/HL/issues/8375)
|
||||
- **合并提交**:
|
||||
- product-v2: [#8381](https://git.1814.love/wx/HL/pulls/8381) @ commit d7a98f13f
|
||||
- order-v3: [#8382](https://git.1814.love/wx/HL/pulls/8382) @ commit 72d8fe310
|
||||
- user-service: [#8379](https://git.1814.love/wx/HL/pulls/8379) @ commit 12707c57c
|
||||
|
||||
### 联系人
|
||||
|
||||
- **后端负责人**: @wx
|
||||
- **前端负责人(hl-ui)**: @mmg
|
||||
在新工单中引用
屏蔽一个用户