--- 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\ | 分页结果行 | | 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\ | 城市列表 | | 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\ | 分页结果行 | | 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 | 加急行排序 | 打标前第 1、2 页都没有加急行;把原在第 2 页第 10 行的样本标为加急后,它移到第 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