diff --git a/changelogs-v2/2026-09/23_8231_配导游配摄影物资放开到出行前四态-修改接口-管理后台.md b/changelogs-v2/2026-09/23_8231_配导游配摄影物资放开到出行前四态-修改接口-管理后台.md new file mode 100644 index 00000000..708ec759 --- /dev/null +++ b/changelogs-v2/2026-09/23_8231_配导游配摄影物资放开到出行前四态-修改接口-管理后台.md @@ -0,0 +1,550 @@ +--- +schema: "hl-changelog/v2" +ticket: "8231" +title: "配导游 / 配摄影 / 物资取消阶段门——出行前四态均可随时配置;取消成团改为放行并回收导摄配置" +consumer: "admin" +author: "jw(GIT)" +change_type: "修改接口" +backend_status: "deployed" +gateway_status: "not_required" +frontend_status: "pending" +frontend_owner: "mmg" +frontend_ref: "" +target_release: "" +verified_at: "2026-09-23" +status_note: "jw 2026-09-23 裁决:配导游 / 配摄影 / 物资三项取消节点限制,只要在出行节点之前都可以随时配置。改前配导游 / 配摄影被 assertFormed 拦在招募中(589552),物资被 assertInMaterialStage 限死在 MATERIAL_PREPARING(589520)——而团期要集齐四项 ready(房 / 车 / 导 / 摄)才推得进 MATERIAL_PREPARING,实际「物资配不了」的根因多半是房车没配齐。本次三处写口统一引用新常量 PRE_DEPARTURE_CONFIGURABLE_STATUSES(RECRUITING / RESOURCE_PREPARING / MATERIAL_PREPARING / PENDING_DEPARTURE),出行后与已取消一律拒成新错误码 589598,未建团仍 589553。连带改的是取消成团:放开招募中可配之后,若导摄仍算「已派单资源」,招募中配过人的团一成团就再也取消不了成团(开工前实测:TEST 团期 2099750660965584898 在房车 ready 全 0、已确认子订单 0 的情况下,仅凭导游一项就返 589502)。故按方案 C,导摄两项移出 R10 判定,取消成团改为放行并在同事务内回收导摄配置(order_batch_staff 整期软删 + 各子订单 order_staff_assignment 中 source=GROUP_BATCH 的扇出行软删),房 / 车两项仍照旧阻断。取证阶段另修一处本单引入的回归:招募中清空导摄配置后 ready 位回不到 false(免闸豁免只对已成团成立,needs_* 招募中恒 0),已随 PR #8237 修复。TEST 实测 2026-09-23 12:15~12:25:物资三端点在四态各放行、在 REVIEWING / TRIP_FINISHED / CANCELLED 各返 589598 且零写入;配导摄在四态各落库成功、在三个出行后态返 589598 且零写入;取消成团对仅导摄 dispatched 的样本返 200 并完成回收,对 hotel_ready=1 / vehicle_ready=1 两个样本仍返 589502 且零写入;连续两次取消成团第二次返 589501、不重复回收。前端侧:配导游 / 配摄影按钮本来就不看 batchStatus,零改动;物资 tab 的操作列在 SuppliesPanel.vue 里按 MATERIAL_PREPARING 前置隐藏,后端放开后前端不改则本单无实际效果,交接件见同批 frontend 条目,故 frontend_status 记 pending。" +updated_at: "2026-09-23" +base: "dev-v3" +--- + +# 团期资源配置: 配导游 / 配摄影 / 物资放开到出行前四态(管理后台) + +> **服务**: hl-order-service-v3(端口 8086/8186) +> **PR**: #8234、#8237 +> **Issue**: #8231 +> **日期**: 2026-09-23 +> **影响范围**: 管理后台团期详情页的「配导游 / 配摄影」弹窗、「物资」tab、「取消成团」按钮 + +--- + +## ⚠️ 关键变化 + +本次是**行为变更,不是纯增字段**,三条都与调用方此前的预期不同: + +1. **可配窗口扩大**。以前「招募中配不了导摄」「物资只有到了准备物资阶段才配得了」,现在**出行前四态都能配**。 +2. **拒绝时的错误码换了**。以前物资拒是 `589520`、导摄拒是 `589552`,现在统一是新码 **`589598`**。按 589520 / 589552 做文案分支的前端要改。 +3. **取消成团的阻塞条件收窄了**。以前「已派导游 / 已派摄影」会把取消成团拦住(589502),**现在不会**;作为代价,取消成团成功后会把该团期的导摄配置一并回收,配人列表会变空。 + +--- + +## 一、背景 + +`GroupBatchStatus` 状态机里,「出行之前」= 前四态: + +| 允许配置 | 拒绝 | +|---|---| +| `RECRUITING` 招募中 · `RESOURCE_PREPARING` 资源准备中 · `MATERIAL_PREPARING` 物料准备中 · `PENDING_DEPARTURE` 待出发 | `TRAVELLING` 出行中 · `TRIP_FINISHED` 出行完毕 · `REVIEWING` 核单中 · `SETTLED` 已结算 · `CANCELLED` 已取消 | + +`CANCELLED` 按拒绝处理:它是终态取消,不属于「出行前」语义。 + +**物资的实际约束比表面更紧**:团期要先走到 `MATERIAL_PREPARING` 才开窗,而 +`RESOURCE_PREPARING → MATERIAL_PREPARING` 的推进条件是四项 ready 齐(房 / 车 / 导 / 摄)+ 合同 / 保险。 +即今天「物资配不了」的根因多数是房车没配齐。本次放开后,物资配置不再依赖这条链。 + +**状态机推进逻辑本身不动**:`MATERIAL_PREPARING` 这个阶段、以及「四项 ready 齐才推进」那条链一律不变。 + +--- + +## 二、变更接口清单 + +| # | 接口 | 方法 | 路径 | 变更类型 | 说明 | +|---|------|------|------|----------|------| +| 1 | 保存团期人员配置 | PUT | `/v3/admin/group-batch/{productBatchId}/staff` | 修改接口 | 阶段门从「已成团」放宽到出行前四态;拒绝码 589552 → 589598 | +| 2 | 设置报账人等级 | PUT | `/v3/admin/group-batch/{productBatchId}/staff/{staffId}/reporter-rank` | 修改接口 | 同上,与保存口同窗口 | +| 3 | 新增团期备品行 | POST | `/v3/admin/order/group-batch/{groupBatchId}/supplies` | 修改接口 | 阶段门从 `MATERIAL_PREPARING` 放宽到出行前四态;拒绝码 589520 → 589598 | +| 4 | 调整团期备品数量 | PUT | `/v3/admin/order/group-batch/supplies/{batchSuppliesId}/quantity` | 修改接口 | 同上 | +| 5 | 软删团期备品行 | DELETE | `/v3/admin/order/group-batch/supplies/{batchSuppliesId}` | 修改接口 | 同上 | +| 6 | 取消成团 | POST | `/v3/admin/order/group-batch/{groupBatchId}/cancel-group` | 修改接口 | 导摄两项不再阻断;成功时额外回收导摄配置 | + +路径、入参结构、权限码、成功响应结构均零变化;网关无改动。 + +--- + +## 三、接口详情 + +### 1. 保存团期人员配置 `PUT /v3/admin/group-batch/{productBatchId}/staff` + +**VO**: `BatchStaffConfigReqVO` → `BatchStaffConfigRespVO` + +#### 使用场景 + +团期详情页「配导游 / 配摄影」弹窗点保存。整期全量覆盖:按 `scopeRoles`(不传即全量)软删旧配置、 +写入新配置、异步扇出到各活跃子订单,并按配置结果回填 `guide_ready` / `photographer_ready`。 + +#### 入参 + +| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | +|---|---|---|---|---|---| +| productBatchId | path | Long | 是 | 正整数,产品侧排期 ID | 团期所属班期;未建团返 589553 | +| scopeRoles | body | List<String> | 否 | 元素非空 | 限定本次覆盖的角色范围,不传则整期覆盖 | +| staffList | body | List<Item> | 否 | null 按空列表处理 | 传空列表 = 清空覆盖范围内的配置 | +| staffList[].staffId | body | Long | 是 | 须命中候选人员 | 人员 ID | +| staffList[].staffRole | body | String | 是 | 须与人员类型相符,否则 582114 | 角色(GUIDE / LEADER / PHOTOGRAPHER …) | +| staffList[].sortOrder | body | Integer | 否 | — | 展示排序 | +| staffList[].remark | body | String | 否 | — | 备注 | + +#### 出参 + +| 字段 | 类型 | 说明 | +|---|---|---| +| productBatchId | Long | 回显路径参数 | +| groupBatchId | Long | 团期聚合主键,取守卫阶段那一次既有反查的结果,不额外查库 | +| staffList | List | 保存后的整期最终状态 | +| affectedOrderCount | Integer | 本次扇出触及的活跃子订单数 | + +#### 请求示例 + +```http +PUT /v3/admin/group-batch/2097250420299530242/staff HTTP/1.1 +Host: api.test.1814.love:9443 +Authorization: Bearer +Content-Type: application/json + +{"staffList":[{"staffId":1002,"staffRole":"GUIDE","sortOrder":0},{"staffId":1003,"staffRole":"PHOTOGRAPHER","sortOrder":1}]} +``` + +#### 响应示例 + +```json +{ + "code": 200, + "message": "成功", + "data": { + "productBatchId": "2097250420299530242", + "groupBatchId": "2097250563497385985", + "affectedOrderCount": 0, + "staffList": [ + {"staffId": 1002, "staffRole": "GUIDE", "staffName": "李雪梅", "reporterRank": "NONE"}, + {"staffId": 1003, "staffRole": "PHOTOGRAPHER", "staffName": "王强", "reporterRank": "NONE"} + ] + } +} +``` + +#### 空数据 / 降级响应 + +`staffList` 传空列表即清空覆盖范围内的配置,返回 200,`staffList` 为空数组、`affectedOrderCount` 为实际扇出订单数。 +**清空后 ready 位的回落口径本次有修正**:已成团且该位 `needs_*=false`(成团免闸置位)时保持就绪、不回落; +其余情形(含**招募中**)一律回落为 false。改前招募中清空后 ready 位会卡在 true,与配置行数 0 自相矛盾。 + +#### 错误响应 + +```json +{"code": 589598, "message": "出行后不可再配置导游 / 摄影 / 物资", "data": null} +``` + +未建团(该班期还没有任何订单,团期行尚未 Lazy 建)仍是另一个码,两者不可合并: + +```json +{"code": 589553, "message": "团期尚未创建(该班期还没有任何订单),请先建团并完成成团后再操作", "data": null} +``` + +#### 业务边界 + +- 出行前四态(`RECRUITING` / `RESOURCE_PREPARING` / `MATERIAL_PREPARING` / `PENDING_DEPARTURE`)放行 +- `TRAVELLING` / `TRIP_FINISHED` / `REVIEWING` / `SETTLED` / `CANCELLED` 返 589598,**被拒时一行都不写**(闸在写库之前) +- 未建团返 589553,且**不会为配置动作提前建团期行** +- 589552「团期尚未成团」不再由本接口抛出,但该码仍被别处(车辆派单、房务)使用,未退役 + +--- + +### 2. 设置报账人等级 `PUT /v3/admin/group-batch/{productBatchId}/staff/{staffId}/reporter-rank` + +**VO**: `ReporterRank`(枚举入参) + +#### 使用场景 + +团期人员名单里把某个已配人员标为主报账人 / 协助报账人。它与保存口是同构写口——同样写 +`order_batch_staff` 并扇出 `order_staff_assignment`,故口径必须与保存口完全一致。 + +#### 入参 + +| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | +|---|---|---|---|---|---| +| productBatchId | path | Long | 是 | 正整数 | 产品侧排期 ID | +| staffId | path | Long | 是 | 须命中该团期已配人员 | 人员 ID | +| rank | body | String | 是 | PRIMARY / ASSIST / NONE | 报账人等级 | + +#### 出参 + +| 字段 | 类型 | 说明 | +|---|---|---| +| data | Void | 成功返回 null,判成败看 `code` | + +#### 请求示例 + +```http +PUT /v3/admin/group-batch/2097250420299530242/staff/1002/reporter-rank HTTP/1.1 +Host: api.test.1814.love:9443 +Authorization: Bearer +Content-Type: application/json + +{"rank":"PRIMARY"} +``` + +#### 响应示例 + +```json +{"code": 200, "message": "成功", "data": null} +``` + +#### 空数据 / 降级响应 + +本接口无列表出参,无空数据形态;团期已配人员为空时会先因 staffId 未命中报错,不会静默成功。 + +#### 错误响应 + +```json +{"code": 589598, "message": "出行后不可再配置导游 / 摄影 / 物资", "data": null} +``` + +#### 业务边界 + +- 窗口与保存口完全一致,不允许两个方法口径漂移 +- 被拒时连「查已派 staff」这一步读都不发生,零写入 +- 未建团仍返 589553 + +--- + +### 3. 新增团期备品行 `POST /v3/admin/order/group-batch/{groupBatchId}/supplies` + +**VO**: `AddSuppliesReqVO` + +#### 使用场景 + +团期详情页「物资」tab 手工录入一行备品(产品侧没有、临时采购的)。 + +#### 入参 + +| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | +|---|---|---|---|---|---| +| groupBatchId | path | Long | 是 | 正整数,团期聚合主键 | 不存在返 GROUP_BATCH_NOT_FOUND | +| suppliesName | body | String | 否 | 传 suppliesResourceId 时可空 | 备品名称;纯手填时必填 | +| suppliesResourceId | body | Long | 否 | — | 备品库资源 ID,传了则名称取库值 | +| category | body | String | 否 | — | 分类 | +| hasCost | body | Boolean | 否 | — | 是否计费 | +| billingType | body | String | 否 | PER_PERSON / PER_QUANTITY | 计费方式 | +| unitPrice | body | BigDecimal | 否 | — | 单价 | +| quantity | body | Integer | 是 | ≥ 1,否则 589522 | 数量 | +| sortOrder | body | Integer | 否 | 默认 0 | 展示排序 | + +#### 出参 + +| 字段 | 类型 | 说明 | +|---|---|---| +| data | Long | 新建备品行 ID(`batchSuppliesId`),用于后续改数量 / 软删 | + +#### 请求示例 + +```http +POST /v3/admin/order/group-batch/2099750365778886657/supplies HTTP/1.1 +Host: api.test.1814.love:9443 +Authorization: Bearer +Content-Type: application/json + +{"suppliesName":"临时采购的雨衣","quantity":1,"sortOrder":999} +``` + +#### 响应示例 + +```json +{"code": 200, "message": "成功", "data": "2102611411027066881"} +``` + +#### 空数据 / 降级响应 + +本接口是写接口,无空数据形态。创单时由系统固化产品侧备品的 `freezeFromProduct` 路径**不过本阶段门**—— +它是首单懒建事务内的系统行为,加门会把建团直接打断,该豁免本次不变。 + +#### 错误响应 + +```json +{"code": 589598, "message": "出行后不可再配置导游 / 摄影 / 物资", "data": null} +``` + +#### 业务边界 + +- 出行前四态放行,尤其 `RESOURCE_PREPARING`——改前该态必被 589520 拒 +- 出行后与 `CANCELLED` 返 589598,不落库 +- 团期不存在返 `GROUP_BATCH_NOT_FOUND`,不是阶段错误 +- 数量非法返 589522 参数错误,不是状态错误 + +--- + +### 4. 调整团期备品数量 `PUT /v3/admin/order/group-batch/supplies/{batchSuppliesId}/quantity` + +**VO**: `AdjustSuppliesQuantityReqVO` + +#### 使用场景 + +物资 tab 行内编辑数量。 + +#### 入参 + +| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | +|---|---|---|---|---|---| +| batchSuppliesId | path | Long | 是 | 须命中活跃备品行 | 不存在返 589521 | +| quantity | body | Integer | 是 | ≥ 1,否则 589522 | 新数量 | + +#### 出参 + +| 字段 | 类型 | 说明 | +|---|---|---| +| data | Void | 成功返回 null | + +#### 请求示例 + +```http +PUT /v3/admin/order/group-batch/supplies/2102611411027066881/quantity HTTP/1.1 +Host: api.test.1814.love:9443 +Authorization: Bearer +Content-Type: application/json + +{"quantity":5} +``` + +#### 响应示例 + +```json +{"code": 200, "message": "成功", "data": null} +``` + +#### 空数据 / 降级响应 + +无列表出参,无空数据形态。备品行已被软删时返 589521,不会静默成功。 + +#### 错误响应 + +```json +{"code": 589598, "message": "出行后不可再配置导游 / 摄影 / 物资", "data": null} +``` + +#### 业务边界 + +- 阶段门由该备品行反查所属团期后判定,窗口与新增口一致 +- **「确认物资之后能不能改」不归本门管**:确认后仍可增删改是有意为之,窗口扩大后该结论不变 +- 被拒时数量不变、行不被软删 + +--- + +### 5. 软删团期备品行 `DELETE /v3/admin/order/group-batch/supplies/{batchSuppliesId}` + +**VO**: `Result`(无请求体) + +#### 使用场景 + +物资 tab 删除一行备品。 + +#### 入参 + +| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | +|---|---|---|---|---|---| +| batchSuppliesId | path | Long | 是 | 须命中活跃备品行 | 不存在返 589521 | + +#### 出参 + +| 字段 | 类型 | 说明 | +|---|---|---| +| data | Void | 成功返回 null | + +#### 请求示例 + +```http +DELETE /v3/admin/order/group-batch/supplies/2102611411027066881 HTTP/1.1 +Host: api.test.1814.love:9443 +Authorization: Bearer +``` + +#### 响应示例 + +```json +{"code": 200, "message": "成功", "data": null} +``` + +#### 空数据 / 降级响应 + +软删是幂等的:对已软删的行再调返 589521「备品行不存在」,不会重复写。 + +#### 错误响应 + +```json +{"code": 589598, "message": "出行后不可再配置导游 / 摄影 / 物资", "data": null} +``` + +#### 业务边界 + +- 窗口与新增 / 改数量完全一致 +- 被拒时行的 `deleted_at` 保持为空 + +--- + +### 6. 取消成团 `POST /v3/admin/order/group-batch/{groupBatchId}/cancel-group` + +**VO**: `Result`(无请求体) + +#### 使用场景 + +团期从「资源准备中」退回「招募中」。本次**没有改它的入参或路径**,改的是它的阻塞条件与成功时的副作用。 + +#### 入参 + +| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | +|---|---|---|---|---|---| +| groupBatchId | path | Long | 是 | 正整数,团期聚合主键 | 不存在返 GROUP_BATCH_NOT_FOUND;非 `RESOURCE_PREPARING` 返 589501 | + +#### 出参 + +| 字段 | 类型 | 说明 | +|---|---|---| +| data | Void | 成功返回 null,团期状态已回到 `RECRUITING` | + +#### 请求示例 + +```http +POST /v3/admin/order/group-batch/2099750660965584898/cancel-group HTTP/1.1 +Host: api.test.1814.love:9443 +Authorization: Bearer +``` + +#### 响应示例 + +```json +{"code": 200, "message": "成功", "data": null} +``` + +#### 空数据 / 降级响应 + +成功时无返回体。该团期没有任何导摄配置时,回收步骤是零行软删的空操作,不影响成功。 + +#### 错误响应 + +```json +{"code": 589502, "message": "取消成团被阻塞(有已确认子订单或已派单资源)", "data": null} +``` + +连续两次调用,第二次因状态已不是 `RESOURCE_PREPARING` 被 CAS 拒: + +```json +{"code": 589501, "message": "团期状态不允许当前操作", "data": null} +``` + +#### 业务边界 + +- 仍阻塞:有已确认子订单(`PENDING_DEPARTURE` / `TRAVELLING` / `COMPLETED`)、`hotel_ready=true`、 + `vehicle_ready=true`(且非整团免车) +- **不再阻塞**:已派导游、已派摄影 +- 成功时依次:状态 CAS 回 `RECRUITING` → 四项 ready 与物资确认全部重置 → **回收导摄配置** → 登记配车释放命令 +- 回收范围只含 `source=GROUP_BATCH` 的扇出行,子订单自己单独派的人不受影响 +- 幂等:第二次调用被 589501 拒,不重复回收 + +--- + +## 四、契约约束与正确调用方式 + +- **判拒绝原因不要再认 589520 / 589552**。这两个码不再由上述五个配置接口抛出(589520 保留占位防号段复用,589552 仍由车辆派单、房务等别处使用)。统一认 **589598**。 +- **589598 与 589553 是两件事**,不要合并成一个 toast:前者是「这个团已经出发了,配不了了」,后者是「这个班期还没有任何订单,先去建团」。 +- 配导摄成功后,若调用方缓存了 `guide_ready` / `photographer_ready`,需重新拉取团期详情——本次修正了清空时的回落口径。 +- 取消成功后,**团期人员名单会变空**,调用方若停在配人弹窗需主动刷新。 + +--- + +## 五、数据库行为 + +- 配导摄保存:整期(或 `scopeRoles` 范围内)软删旧配置行 + 写入新配置行 + 异步扇出到各活跃子订单;随后按配置结果回填团期行的两个 ready 标志 +- 物资三口:分别为插入一行、更新一行的数量、软删一行 +- 取消成团:状态 CAS 一行 + 重置该团期四项 ready 与物资确认 + 软删该团期全部导摄配置行 + 软删其各子订单中来源为团期扇出的人员分配行,**全部在同一个事务内**,任一步失败整体回滚 +- 被阶段门拒绝时零写入:闸在所有写库动作之前 + +--- + +## 六、边界行为 + +- `CANCELLED`(已流团)按拒绝处理,返 589598 +- 未建团(团期行尚未 Lazy 建)返 589553,**不会为配置动作提前建行**——否则会出现「零单可配 → 首单落地反而不可配 → 成团后又可配」这种非单调行为 +- 创单时固化产品侧备品的系统路径不过阶段门,该豁免不变 +- 「确认物资之后仍可增删改」不变 + +--- + +## 六.6、修改前后对比 + +| 维度 | 改前 | 改后 | +|---|---|---| +| 配导摄可配状态 | 已成团各态(招募中被拒) | `RECRUITING` / `RESOURCE_PREPARING` / `MATERIAL_PREPARING` / `PENDING_DEPARTURE` | +| 配导摄拒绝码 | 589552(未成团)/ 589553(未建团) | 589598(已出行 / 已取消)/ 589553(未建团) | +| 物资三口可配状态 | 仅 `MATERIAL_PREPARING` | 同上四态 | +| 物资三口拒绝码 | 589520 | 589598 | +| 取消成团:已派导游 / 摄影 | 返 589502 被阻塞 | 放行,且回收导摄配置 | +| 取消成团:房 / 车 ready | 返 589502 被阻塞 | **不变**,仍返 589502 | +| 招募中清空导摄后的 ready 位 | 卡在 true(与配置行数 0 矛盾) | 回落为 false | + +--- + +## 六.7、影响评估 + +| 面 | 评估 | +|---|---| +| 管理后台配导摄 | 按钮本来就不看 `batchStatus`,招募中点得下去、只是被后端拒。后端放开后**前端零改动即可生效** | +| 管理后台物资 tab | 操作列按 `MATERIAL_PREPARING` 前置隐藏,**前端不改则本次无实际效果**,交接件见同批 frontend 条目 | +| 已有错误文案分支 | 按 589520 / 589552 做文案的地方需改认 589598 | +| 取消成团 | 可取消的团期变多;成功后人员名单会被清空,属预期 | +| 小程序端 | 不受影响,物资清单在小程序端是只读视图 | +| 状态机 | 不变,`MATERIAL_PREPARING` 阶段与「四项 ready 齐才推进」那条链一律不动 | + +--- + +## 七、不影响范围 + +- 团期状态机的推进逻辑、四项 ready 的计算口径 +- 流团(`disband`):只校验状态白名单,不看 ready 位,本次完全不受影响 +- 子订单自己单独派的人员(`order_staff_assignment` 中 source 非 `GROUP_BATCH` 的行):回收不碰它们 +- 车辆派单、房务等仍在用 `assertFormed` 的写口:口径不变 +- 权限码、路径、入参结构、成功响应结构、网关配置 + +--- + +## 八、测试环境已验证 + +2026-09-23 12:15~12:25,`api.test.1814.love:9443`,分支 `dev-v3`(`fe752f16c`)。 + +| AC | 内容 | 结果 | +|---|---|---| +| 物资四态放行 | `RECRUITING` / `RESOURCE_PREPARING` / `MATERIAL_PREPARING` / `PENDING_DEPARTURE` 各跑「增 → 改数量 → 删」三端点 | 12 次调用全 200,自造行自删、零残留 | +| 物资出行后拒 | `REVIEWING` / `TRIP_FINISHED` / `CANCELLED` 各跑三端点 | 全返 589598;既有行的 `quantity` 未变、未软删、未新增行 | +| 配导摄四态放行 | 四态各保存「1002 GUIDE + 1003 PHOTOGRAPHER」 | 全 200 且落库;逐个还原为改前配置,四组还原判定全 ✔ | +| 配导摄出行后拒 | `REVIEWING` / `TRIP_FINISHED` / `CANCELLED` | 全返 589598;活跃行与表内总行数逐字未变 | +| 未建团 | 不存在的 `productBatchId` | 返 589553,未被新码吞掉 | +| 取消成团放行 + 回收 | 团期 `2099750660965584898`(`needs_guide=1 & guide_ready=1`,房车 ready 全 0,已确认子订单 0)——同一样本开工前实测返 589502 | 返 200;状态 `RESOURCE_PREPARING → RECRUITING`;`guide_ready` / `photographer_ready` 归 0;配置行与子订单扇出行同时间戳软删 | +| 房车仍阻断 | `hotel_ready=1` 与 `vehicle_ready=1` 两个样本 | 均返 589502;团期行与两张配置表逐字未变 | +| 幂等 | 对同一团期连调两次取消成团 | 第二次返 589501;三处读数与第一次后完全一致,无重复回收 | + +本地单测:assignment + groupbatch + house 4103 条、archunit / core / requirement 等 3456 条、其余 26 个包 4621 条,全绿。 + +取证用到的写操作及还原:新增的备品行均由本次自行软删;配导摄的四个团期均按改前配置逐条还原; +取消成团样本 `2099750660965584898` 已按改前值还原(状态、两个 ready 位、配置行与扇出行的软删标记)。 + +--- + +## 十、相关文档 + +- Issue #8231(含开工前的 AC-6 实测与方案 C 裁决) +- PR #8234(主体)、PR #8237(ready 回落回归修复) +- 被推翻:#7287 T5(`assertFormed`)、#7023 AC-TD-13(物资单一阶段窗口)、wx 2026-09-15「放行但配置行保留」 +- 保持不变:#7023 AC-TD-15(确认后仍可改)、#7441 PR-2e(整团免车的 ready 剥离) + +--- + +## 关联 / 联系人 + +- 后端:jw +- 前端:mmg(物资 tab 显隐条件,见同批 frontend 条目) diff --git a/changelogs-v2/2026-09/23_frontend_物资tab操作列仍按准备物资阶段隐藏致后端放开无效-前端优化-管理后台.md b/changelogs-v2/2026-09/23_frontend_物资tab操作列仍按准备物资阶段隐藏致后端放开无效-前端优化-管理后台.md new file mode 100644 index 00000000..1d9e263b --- /dev/null +++ b/changelogs-v2/2026-09/23_frontend_物资tab操作列仍按准备物资阶段隐藏致后端放开无效-前端优化-管理后台.md @@ -0,0 +1,119 @@ +--- +schema: "hl-changelog/v2" +ticket: "8231" +title: "物资 tab 的写入口仍按 MATERIAL_PREPARING 前置隐藏——后端已放开到出行前四态,前端不改则运营点不到入口" +consumer: "admin" +author: "jw(GIT)" +change_type: "前端优化" +backend_status: "not_required" +gateway_status: "not_required" +frontend_status: "pending" +frontend_owner: "mmg" +frontend_ref: "" +target_release: "" +verified_at: "" +status_note: "#8231 后端已把物资三个写接口(新增行 / 改数量 / 软删行)的阶段门从单一 MATERIAL_PREPARING 放宽到出行前四态(RECRUITING / RESOURCE_PREPARING / MATERIAL_PREPARING / PENDING_DEPARTURE),2026-09-23 已部署 TEST 并四态逐一实测通过。但 SuppliesPanel.vue 里有一个 isMaterialPreparing 计算属性把手工录入按钮、操作列表头、数量行内编辑、删除按钮四处一并前置隐藏,非 MATERIAL_PREPARING 阶段物资 tab 仍是一张没有操作列的只读表,运营点不到任何入口——后端这次放开在界面上等于没发生。需要把这四处的判据从「等于 MATERIAL_PREPARING」改成「在出行前四态之内」。注意「确认物资」按钮(同文件 28 行)走的是另一个接口 confirm-material,#8231 没有放开它,那一处的阶段门要原样保留、不要跟着一起改。配导游 / 配摄影侧前端零改动:ChipItemsPanel.vue 的配置按钮条件只有 v-if=configRole,不看 batchStatus,后端放开后即刻生效。" +updated_at: "2026-09-23" +base: "dev-v3" +--- + +# 团期物资 tab: 写入口的阶段门需从单一阶段放宽到出行前四态(管理后台) + +> **仓库 / 分支**: `mmg/hl-ui` @ `v2.1` +> **文件**: `src/views/order-v2/batch/detail/components/SuppliesPanel.vue` +> **Issue**: #8231 +> **日期**: 2026-09-23 +> **影响范围**: 团期详情页「物资」tab 的操作列与三个写入口 + +--- + +## ⚠️ 关键变化 + +后端已经放开,**前端不改则本次改动在界面上等于没发生**。 + +`RESOURCE_PREPARING`(资源准备中)是最典型的一态:团期要集齐四项 ready(房 / 车 / 导 / 摄)才推得进 +`MATERIAL_PREPARING`,所以今天运营抱怨「物资配不了」,多数时候团期正停在 `RESOURCE_PREPARING`。 +后端这次就是为这个场景放开的,而前端在这一态下连操作列都不渲染。 + +--- + +## 一、后端现状(已部署 TEST 并实测) + +| 接口 | 方法 | 路径 | 改后可用状态 | +|---|---|---|---| +| 新增备品行 | POST | `/v3/admin/order/group-batch/{groupBatchId}/supplies` | 出行前四态 | +| 调整数量 | PUT | `/v3/admin/order/group-batch/supplies/{batchSuppliesId}/quantity` | 出行前四态 | +| 软删备品行 | DELETE | `/v3/admin/order/group-batch/supplies/{batchSuppliesId}` | 出行前四态 | + +出行前四态 = `RECRUITING` / `RESOURCE_PREPARING` / `MATERIAL_PREPARING` / `PENDING_DEPARTURE`。 + +出行后(`TRAVELLING` / `TRIP_FINISHED` / `REVIEWING` / `SETTLED`)与 `CANCELLED` 仍拒, +**错误码从 589520 换成了 589598**,文案「出行后不可再配置导游 / 摄影 / 物资」。 + +TEST 实测(2026-09-23,`dev-v3` @ `fe752f16c`):四态各跑「增 → 改数量 → 删」三端点共 12 次调用全 200; +三个出行后态各返 589598 且零写入。 + +--- + +## 二、前端需要改的四处(行号按 `origin/v2.1` @ `f713b1c6`) + +| # | 行 | 现状 | 期望 | +|---|---|---|---| +| 1 | 16 | `v-if="isMaterialPreparing"` —— 「手工录入」按钮 | 出行前四态可见 | +| 2 | 52 | `操作` —— 操作列表头 | 出行前四态可见 | +| 3 | 81 | `v-if="isMaterialPreparing"` —— 数量 `n-input-number` 行内编辑(否则走 `v-else` 的只读纯文本) | 出行前四态可编辑 | +| 4 | 94 | `` —— 整个删除按钮单元格 | 出行前四态可见 | + +判据单源在 179 行: + +```js +// #7528 阶段门:仅物料准备中可见三个写操作与确认入口(其余状态后端仍守,前端前置隐藏) +const isMaterialPreparing = computed(() => props.detail?.batchStatus === 'MATERIAL_PREPARING') +``` + +连带两处会自动跟着变,确认改后表现正常即可: + +- 183 行 `gridColumns`:操作列出现与否决定列宽是 6 列还是 5 列 +- 188 行 `emptyText`:空态文案分「可从备品库选择或手工录入」与「本期尚未配置物资」两种 + +--- + +## 三、⚠️ 不要一起改的两处 + +| 位置 | 原因 | +|---|---| +| 28 行「确认物资」按钮 | 它调的是 `POST /v3/admin/order/group-batch/{groupBatchId}/confirm-material`,属七项硬门准入链路,**#8231 没有放开它**。那一处的 `MATERIAL_PREPARING` 判据要原样保留 | +| 4 行「从备品库选择」按钮 | 它本来就没挂阶段门、一直可见。改前它在非 `MATERIAL_PREPARING` 下点了会被 589520 拒,改后四态内可正常落库——**不需要改代码,但回归时要覆盖它** | + +因为 28 行与那四处不再同一个判据,建议把 179 行拆成两个计算属性(例如「可配置窗口」与「可确认物资」), +而不是把现有的 `isMaterialPreparing` 就地改语义——后者会把确认物资一起放开,那是另一件事。 + +--- + +## 四、配导游 / 配摄影侧:前端零改动 + +`ChipItemsPanel.vue` 的配置按钮条件只有 `v-if="configRole"`,不看 `batchStatus`; +弹窗只有 `:disabled="!rosterReady"`(名单加载态)。招募中按钮本来就渲染、点得下去, +只是改前后端回 589552 被拦截器透成 toast。后端放开后该路径即刻可用,无需前端配合。 + +--- + +## 五、错误文案 + +按 589520 做分支的地方需要改认 **589598**。589520 未退役(保留占位防号段复用),但物资三口不再抛它。 + +--- + +## 六、回归建议 + +在 `RESOURCE_PREPARING` 的团期上验:操作列出现 → 手工录入一行 → 改数量 → 删除 → 从备品库选择再加一行。 +再在 `REVIEWING` 或 `TRIP_FINISHED` 的团期上验:操作列不出现,且即便直接打接口也返 589598。 + +--- + +## 关联 / 联系人 + +- 后端:jw(#8231,PR #8234 / #8237,已部署 TEST) +- 前端:mmg +- 同批后端条目:`23_8231_配导游配摄影物资放开到出行前四态-修改接口-管理后台.md` +- 前例:`17_frontend_团期物资清单补改数量删除与手工录入-前端优化-管理后台.md`