--- schema: "hl-changelog/v2" ticket: "8601" title: "逐户提交车务 / 打回的 kind 参数取消默认值 TRAVEL,两类活跃需求并存时必须显式指定(新错误码 809012)" consumer: "admin" author: "wx(GIT)" change_type: "修改接口" backend_status: "deployed" gateway_status: "verified" frontend_status: "pending" frontend_owner: "" frontend_ref: "" target_release: "" verified_at: "" status_note: "PR #8610 已 squash 合并 dev-v3(a2ba628ecb),hl-order-service-v3 dev-v3 分支已滚测试服。这是需要前端改调用代码的变更:两个端点的 kind 查询参数从 defaultValue=TRAVEL 改成无默认值,纯接送机户由此可用,两类并存且不传 kind 时新抛 809012。" updated_at: "2026-09-30" base: "dev-v3" --- # hl-order-service-v3: 逐户提交车务 / 打回的 `kind` 参数取消默认值 `TRAVEL` > **存放目录**: `changelogs-v2/2026-09/` > **服务**: hl-order-service-v3 (端口 8086) > **PR**: #8610 > **Issue**: #8601 > **日期**: 2026-09-30 > **影响范围**: 团期需求管理 Tab 的逐户「提交车务」与「打回定制师」两个按钮所调的端点,其 `kind` 查询参数语义 --- ## ⚠️ 关键变化 - 🔴 **这是需要前端改调用代码的变更**:两个端点的 `kind` 查询参数由 `@RequestParam(defaultValue = "TRAVEL")` 改为 `@RequestParam(required = false)`,**没有默认值了**。 - **前端以前可以怎么写**:不传 `kind`,后端按 `TRAVEL` 处理。**现在的实际行为**:不传 `kind` 时后端按该户**活跃用车需求的类别数**自动解析—— - **恰好 1 类** → 就用那一类(🆕 **纯接送机户从此可用**:旧默认值会去找一条根本不存在的 TRAVEL 行,导致这类户在这两个入口走不通流程); - **0 类** → 与改前一致,由既有分支抛 582031「订单无有效需求行」; - **≥2 类并存** → 🆕 抛新错误码 **809012**,拒绝猜测。 - 🔴 **809012 是新增错误码**,前端必须接住:`订单 {0} 同时存在 {1} 两类活跃用车需求,请显式指定要操作的类别(kind=TRAVEL 行程用车 / kind=TRANSFER 接送机)`。撞到它的正确处置是**带上 `kind` 重发**(由用户选,或由页面上下文决定),不是重试。 - **前端要做的事**:这两个按钮所在的位置本来就知道自己在操作哪一类需求(页面上就是按 TRAVEL / TRANSFER 分开展示的),**一律显式带上 `kind`** 即可,带了就不会撞 809012。传了值的行为与改前逐字相同(含非法值仍由 809000 拒)。 - **请求体、响应体、权限、HTTP 形态全部未变**:两个端点仍是 `Result`,`dispatchRemark` 仍选填、`returnRemark` 仍必填。 --- ## 一、背景 一户订单的用车需求按类别分行,两类可以同时活跃: | 类别 | 含义 | |------|------| | `TRAVEL` | 团期行程用车 | | `TRANSFER` | 接送机 | 这两个端点都按 `kind` **精确定位一行**再迁移状态、写备注。`defaultValue = "TRAVEL"` 让「调用方没说要动哪一类」与「调用方明确要动 TRAVEL」在服务层**完全同形**——两类并存而调用方没传 `kind` 时,接口返 200、改掉 TRAVEL 行,而操作者想动的 TRANSFER 行三个字段一个都没变,**响应上没有任何可区分的信号**。这是静默错写。 同一个默认值还造成第二个缺陷:只有 TRANSFER 活跃行的户,旧逻辑会去找一条不存在的 TRAVEL 行,拿到 582031,**这类户在这两个入口根本用不了**。 解析只写在服务层一处(`RequirementService#resolveVehicleRequirementKind`),Controller 不做兜底,避免两层各写一份「空了怎么办」而日后分叉。类别数与后续取行**同源**:数的是 `selectAllActiveByOrderId`,而它的实现就是对 `selectLatestByOrderId(orderId, kind)` 按枚举逐类别循环,所以「数出几类」与「按那一类取到哪行」用的是同一个筛选条件,不可能分叉。 > 与结算侧 809008 有意不同:那边只有 TRAVEL 才自动解析、单独一条 TRANSFER 也拒绝(手录车费的省略更可能是漏选归属);本处是需求状态机写口,单 TRANSFER 户只有这一条活跃需求,拒绝它等于让这类户走不通流程。 --- ## 二、变更接口清单 | # | 接口 | 方法 | 路径 | 变更类型 | 说明 | |---|------|------|------|----------|------| | 1 | 团期管理员提交车务 | POST | `/v3/admin/order/{id}/vehicle-requirement/dispatch` | 查询参数取消默认值 + 新增错误码 | `kind` 不再默认 TRAVEL;两类并存且不传抛 809012 | | 2 | 团期管理员打回定制师(车需求) | POST | `/v3/admin/order/{id}/vehicle-requirement/reject` | 查询参数取消默认值 + 新增错误码 | 同上 | --- ## 三、接口详情 ### 1. 团期管理员提交车务 `POST /v3/admin/order/{id}/vehicle-requirement/dispatch` **VO**: `DispatchReqVO → Result` #### 使用场景 团期需求管理 Tab 里对某一户点「提交车务」时调用,把该户指定类别的用车需求从 `PENDING_REVIEW` 推进到 `PENDING` 并写入提交备注(提供给车队人员查看)。**仅团期子订单可用**。权限点 `group-batch:demand:confirm`。 #### 入参 | 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | |------|------|------|------|------|------| | `id` | Path | Long | ✅ | - | 子订单 ID | | `kind` | Query | String | ❌ | 取值 `TRAVEL` / `TRANSFER` | 🔴 **改动点**:不再有默认值 `TRAVEL`。不传时按该户活跃需求类别自动解析(恰好 1 类用那一类;0 类抛 582031;≥2 类抛 809012)。**建议一律显式传**。非法值仍抛 809000 | | `dispatchRemark` | Body | String | ❌ | `@Size(max=500)` | 提交备注,提供给车队的审核意见;上限对齐库列宽 `VARCHAR(500)` | #### 出参 `Result` | 字段 | 类型 | 说明 | |------|------|------| | `code` | Integer | 200 = 成功 | | `message` | String | `成功` | | `success` | Boolean | `true` | | `data` | null | **本端点无业务数据返回**(`Result`),成功即以 `code=200` 为准,不要读 `data` | #### 请求示例 ```http POST /v3/admin/order/2099459272533323777/vehicle-requirement/dispatch?kind=TRANSFER Content-Type: application/json { "dispatchRemark": "需求已确认,请尽快派接送机车辆" } ``` #### 响应示例 ```json { "code": 200, "message": "成功", "success": true, "data": null } ``` #### 空数据 / 降级响应 本端点恒无业务数据,成功时 `data` 恒为 `null`——这是正常成功形态,不是空数据降级: ```json { "code": 200, "message": "成功", "success": true, "data": null } ``` 该户没有任何活跃用车需求行时不降级、不静默成功,直接抛 582031(下面的错误响应)。 #### 错误响应 🆕 809012(本次新增;`{0}` = 订单 ID,`{1}` = 两类名以 ` / ` 连接)。以下为测试服实测原文(订单 ID 2105173274755534850): ```json { "code": 809012, "message": "订单 2105173274755534850 同时存在 TRAVEL / TRANSFER 两类活跃用车需求,请显式指定要操作的类别(kind=TRAVEL 行程用车 / kind=TRANSFER 接送机)", "success": false, "data": null } ``` 其余错误码未变: | 码 | 报文 | 触发 | |----|------|------| | 809000 | `用车需求类别非法:{0}` | `kind` 传了 TRAVEL / TRANSFER 之外的值 | | 809007 | `接送机需求 {0} 的服务日期尚未回填,无法下发车务` | 解析到 TRANSFER 但该行 `service_dates` 为 NULL 或空数组 | | 582031 | `订单无有效需求行` | 该户按解析出的类别取不到活跃行(含「一条都没有」) | | 582083 | `需求状态不允许此操作,请检查当前状态` | 非团期子订单,或最新需求不在 `PENDING_REVIEW` | #### 业务边界 - **鉴权**:权限点 `group-batch:demand:confirm`(Controller 入口执行,走 user-service Feign);未登录由网关拦截返 401。 - **仅团期子订单**:非团期单先报 582083,`kind` 解析排在这道守卫**之后**——所以非团期单的报错与改前逐字相同,不会变成 809012。 - **解析只在不传 `kind` 时发生**:传了值就原样使用,包括非法值(仍由 809000 拒),本次改动不改变既有的非法值行为。 - **🔴 809012 不是可重试错误**:同一请求重发多少次都是同一个码。处置是**带上 `kind` 重发**。 - **纯接送机户现在可用**:只有一条活跃 TRANSFER 行时不传 `kind` 会被解析成 TRANSFER(改前拿 582031)。 - **状态机守卫未变**:`PENDING_REVIEW → PENDING`,同时写 `dispatch_remark`、车控置 `PENDING`、CAS 退流程。 - **失败零写入**:809012 抛在取行之前、任何写入之前;809007 抛在服务日校验处,同样不落写。 --- ### 2. 团期管理员打回定制师(车需求) `POST /v3/admin/order/{id}/vehicle-requirement/reject` **VO**: `RejectReqVO → Result` #### 使用场景 团期需求管理 Tab 里对某一户点「打回」时调用,把该户指定类别的用车需求退回定制师重提(`PENDING_REVIEW` / `PENDING` → `REJECTED_TO_CONSULTANT`),写入打回备注,并**同时清掉团级 `requirement_confirmed` 标记 + 写团级时间线**(否则会出现「该户未提交、整团已确认」的矛盾态)。权限点 `group-batch:demand:confirm`。 #### 入参 | 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | |------|------|------|------|------|------| | `id` | Path | Long | ✅ | - | 子订单 ID | | `kind` | Query | String | ❌ | 取值 `TRAVEL` / `TRANSFER` | 🔴 **改动点**:不再有默认值 `TRAVEL`,规则与 dispatch 端点逐条相同。**建议一律显式传** | | `returnRemark` | Body | String | ✅ | `@NotBlank`,`@Size(max=500)` | 打回备注;为空返 400「打回/驳回备注不能为空」,超长返 400「打回/驳回备注不能超过 500 字」。定制师重新提交时会创建新需求 | #### 出参 `Result` | 字段 | 类型 | 说明 | |------|------|------| | `code` | Integer | 200 = 成功 | | `message` | String | `成功` | | `success` | Boolean | `true` | | `data` | null | **本端点无业务数据返回**(`Result`) | #### 请求示例 ```http POST /v3/admin/order/2099459272533323777/vehicle-requirement/reject?kind=TRAVEL Content-Type: application/json { "returnRemark": "行程日与团期不符,请定制师重新确认用车日期" } ``` #### 响应示例 ```json { "code": 200, "message": "成功", "success": true, "data": null } ``` #### 空数据 / 降级响应 本端点恒无业务数据,成功时 `data` 恒为 `null`: ```json { "code": 200, "message": "成功", "success": true, "data": null } ``` 打回既要写需求行、又要清团级标记并写团级时间线,是跨聚合编排且与整团确认共用团级锁——**不存在「只做了一半」的降级形态**,要么整套生效要么整体回滚。 #### 错误响应 🆕 809012(本次新增,与 dispatch 端点同码同文案)。以下为测试服实测原文(订单 ID 2105173313083080706): ```json { "code": 809012, "message": "订单 2105173313083080706 同时存在 TRAVEL / TRANSFER 两类活跃用车需求,请显式指定要操作的类别(kind=TRAVEL 行程用车 / kind=TRANSFER 接送机)", "success": false, "data": null } ``` 其余错误码未变: | 码 | 报文 | 触发 | |----|------|------| | 809000 | `用车需求类别非法:{0}` | `kind` 传了非法值 | | 582031 | `订单无有效需求行` | 按解析出的类别取不到活跃行 | | 582083 | `需求状态不允许此操作,请检查当前状态` | 非团期子订单,或最新需求不在 `PENDING_REVIEW` / `PENDING` | | 400 | `打回/驳回备注不能为空` | `returnRemark` 空 | > `589535`(子订单已分房)**不适用于本端点**:占用探测方法对 `resourceType=VEHICLE` 硬编码返回"无占用"(车侧无配房概念),该码只在 `resourceType=HOTEL` 时可能触发;已派车的拦截由另一套栅栏机制负责,不经过本码。这是既有行为,本次未改。 #### 业务边界 - **鉴权**:权限点 `group-batch:demand:confirm`;未登录由网关拦截返 401。 - **kind 解析结果同时用于占用探测与实际取行**:两步必须看同一个类别,避免错位——但车需求侧的占用探测恒不拦截(见上方说明),此为既有行为,本次未改。 - **只对车需求解析**:同一条服务方法也承接房需求打回(`resourceType=HOTEL`),`kind` 对它无意义、不触发解析,**酒店打回不会被车侧的两类并存误伤**。 - **副作用是跨聚合的**:除需求行外还会清团级 `requirement_confirmed` 并写团级时间线 `BATCH_REQUIREMENT_REJECT`,与批量打回落同一套副作用。 - **打回后需求要重提**:定制师重新提交会创建**新的需求行**,不是在原行上改。 - **🔴 809012 不是可重试错误**:处置是带上 `kind` 重发。 - **失败零写入**:809012 抛在取行与实写之前。 --- ## 四、契约约束与正确调用方式 > 本节只写后端接受 / 拒绝请求的规则,不写 UI 渲染建议。 ### ✅ 正确 / ❌ 错误 调用对照 | 场景 | 请求 | 结果 | |------|------|------| | ✅ 显式指定行程用车(**推荐写法**) | `POST /v3/admin/order/{id}/vehicle-requirement/dispatch?kind=TRAVEL` + `{ "dispatchRemark": "..." }` | 200 | | ✅ 显式指定接送机(**推荐写法**) | `POST /v3/admin/order/{id}/vehicle-requirement/dispatch?kind=TRANSFER` + `{ "dispatchRemark": "..." }` | 200 | | ✅ 不传 kind,该户只有一类活跃需求 | `POST /v3/admin/order/{id}/vehicle-requirement/dispatch` | 200,按那一类处理(纯接送机户从此可用) | | ✅ 打回(备注必填) | `POST /v3/admin/order/{id}/vehicle-requirement/reject?kind=TRAVEL` + `{ "returnRemark": "请重新确认用车日期" }` | 200 | | ❌ 不传 kind,该户两类活跃需求并存 | `POST /v3/admin/order/{id}/vehicle-requirement/reject` | **809012**,必须带 kind 重发 | | ❌ kind 传非法值 | `?kind=travel2` | 809000 | | ❌ 打回不带备注 | `{ "returnRemark": "" }` | 400「打回/驳回备注不能为空」 | | ❌ 备注超 500 字 | `{ "returnRemark": "<501 字>" }` | 400「打回/驳回备注不能超过 500 字」 | ### 前端必须做的改动 1. **两个端点的调用一律显式带上 `kind`**。页面上这两个按钮本来就分挂在 TRAVEL / TRANSFER 两块需求下,取值是现成的;带上之后永远不会撞 809012。 2. **接住 809012**:若某处确实拿不到类别,撞到 809012 时要提示用户选择类别并**带上 `kind` 重发**,不要做自动重试(同一请求重发永远同码)。 3. **不要再依赖「不传 = TRAVEL」这个隐含约定**——它已经不成立了。 > 🔴 **落点已查明(2026-09-30 对 `hl-ui` `origin/v2.1` 查证)**:`src/api/orderV2.js` 里 > `rejectVehicleRequirement` 的 JSDoc 写着「`TRAVEL / TRANSFER`;不传保持旧行为(按 TRAVEL)」、 > `dispatchVehicleRequirement` 写着「不传=后端缺省 TRAVEL」——**这两句现在都是错的**, > 两处都是 `const query = kind ? { kind } : null`,调用方不传就会走到新行为上。 > 另外全仓 `809012` 命中数为 **0**,即该码今天没有任何接住的地方。 --- ## 五、数据库行为 本次改动**没有任何表结构变化**,变的是「写哪一行」的定位规则。 | 前端调用 | 该户活跃需求 | 改前写入 | 改后写入 | |----------|--------------|----------|----------| | 不传 `kind` | 只有 TRAVEL | TRAVEL 行 | TRAVEL 行(未变) | | 不传 `kind` | 只有 TRANSFER | ❌ 取不到 TRAVEL 行 → 582031,零写入 | ✅ **TRANSFER 行** | | 不传 `kind` | TRAVEL + TRANSFER 并存 | ❌ **静默写 TRAVEL 行**(返 200,操作者要动的那行三个字段全不变) | ✅ **809012 拒绝,零写入** | | 不传 `kind` | 一条活跃行都没有 | 582031,零写入 | 582031,零写入(未变) | | 传 `kind=TRAVEL` | 任意 | TRAVEL 行 | TRAVEL 行(未变) | | 传 `kind=TRANSFER` | 任意 | TRANSFER 行 | TRANSFER 行(未变) | 写入内容本身未变: - **dispatch**:`order_vehicle_requirement` 该行 `status` `PENDING_REVIEW → PENDING`、写 `dispatch_remark`(≤500)、车控置 `PENDING`、CAS 退流程。 - **reject**:该行 `status → REJECTED_TO_CONSULTANT`、写 `return_remark`(≤500);同事务清团级 `requirement_confirmed`、写团级时间线 `BATCH_REQUIREMENT_REJECT`。 **失败零写入**:809012 抛在解析阶段(dispatch 里排在团期守卫之后、取行之前;reject 里排在占用探测之前),任何一条数据都不会落。 --- ## 六、边界行为 - 未登录 → 401(网关拦截)。 - 权限点 `group-batch:demand:confirm` 缺失 → 403。 - 非团期子订单 → 582083(这道守卫排在 `kind` 解析之前,报错与改前逐字相同)。 - 需求状态不在允许的源状态集合 → 582083。 - 该户按解析出的类别取不到活跃行 → 582031。 - 解析到 TRANSFER 但服务日未回填 → 809007(dispatch 端点,失败关闭不放行)。 - `kind` 传非法值 → 809000(与改前一致,本次未改变非法值行为)。 - 老数据兼容:不改表、不迁移;存量订单下次调用时按新解析规则生效。 --- ## 六.5、枚举 / 数据字典 ### kind(用车需求类别) **所属字段**: 两个端点的查询参数 `kind` | **类型**: `String` | 值 | 中文 | 说明 | |----|------|------| | `TRAVEL` | 团期行程用车 | 汇总进团级乘车分组、整团逐日配车的那一类 | | `TRANSFER` | 接送机 | 逐户派车的那一类;服务日由大交通派生,未回填时 dispatch 抛 809007 | | (不传) | — | 🔴 **不再等价于 `TRAVEL`**。按该户活跃需求类别数解析:1 类用那一类 / 0 类抛 582031 / ≥2 类抛 809012 | | 其他任意值 | — | 非法,抛 809000 | --- ## 六.6、修改前后对比 ### 字段级对比 | 字段 | 改前 | 改后 | |------|------|------| | `kind`(两个端点的查询参数) | `@RequestParam(defaultValue = "TRAVEL")`,Swagger 标 `defaultValue=TRAVEL` | `@RequestParam(required = false)`,**无默认值**;Swagger 文案改为「不传按该户活跃需求类别自动解析,两类并存时必须显式指定」 | | `DispatchReqVO.dispatchRemark` | 选填 ≤500 | 未变 | | `RejectReqVO.returnRemark` | 必填 ≤500 | 未变 | | 两个端点的响应 | `Result` | 未变 | | 错误码集合 | 809000 / 809007(仅 dispatch)/ 582031 / 582083 | 🆕 **增加 809012** | ### 行为级对比 | 行为 | 改前 | 改后 | |------|------|------| | 不传 `kind` + 两类并存 | **静默改 TRAVEL 行,返 200**;操作者要动的 TRANSFER 行原封不动,响应上无任何信号 | 抛 **809012**,零写入 | | 不传 `kind` + 只有 TRANSFER | 去找不存在的 TRAVEL 行 → 582031,**这类户走不通流程** | 解析成 TRANSFER,正常执行 | | 不传 `kind` + 只有 TRAVEL | TRAVEL 行 | 未变 | | 不传 `kind` + 一条活跃行都没有 | 582031 | 未变 | | 传了 `kind`(合法或非法) | 原样使用 / 809000 | 未变 | | 非团期子订单 | 582083 | 未变(守卫排在解析之前) | | 房需求打回(`resourceType=HOTEL`) | `kind` 无意义 | 未变(不触发车侧解析,不会被两类并存误伤) | --- ## 六.7、影响评估 - **是否破坏向后兼容**: **是**。旧调用方「不传 `kind` = 按 TRAVEL」的隐含约定已失效;两类活跃需求并存的户上,原本返 200 的请求现在会返 809012。 - **前端是否必须同步上线**: **是(建议)**。不改也不会报错的前提是「该户只有一类活跃需求」,一旦出现两类并存就会撞 809012。改法极小:调用时把已知的类别放进 `kind` 查询参数,并接住 809012。 - **前端 workaround 清理点**: 若为绕开「纯接送机户点提交车务报 582031」做过按钮置灰、隐藏或提示,可以撤掉——该场景已修好。 --- ## 七、不影响范围 - **仅影响**: `POST /v3/admin/order/{id}/vehicle-requirement/dispatch` 与 `POST /v3/admin/order/{id}/vehicle-requirement/reject` 两个端点的 `kind` 参数语义。 - **零影响**: - 房需求(`resourceType=HOTEL`)的提交与打回链路 - 定制师侧提交 / 修改 / 调整用车需求 `PUT /v3/admin/order/{id}/vehicle-requirement` - 团级正式用车需求的保存 / 汇总 / 预检 / 确认 / 撤回 / 免车 - 批量打回、整团确认的既有行为 - 结算侧手录车费的归属解析(809008,口径有意不同,本次未动) - 车务侧(hl-fleet-service)配车、派单 - 历史数据:不改表、不迁移 --- ## 八、测试环境已验证 - **代码事实**(对 `origin/dev-v3` 逐一查证): - 合并提交 `a2ba628ecb`(PR #8610 squash 合并进 `dev-v3`),7 文件 / +491 −27。 - `VehicleRequirementAdminController` 两处 `@RequestParam(defaultValue = "TRAVEL")` → `@RequestParam(required = false)`,`@ApiParam` 文案同步改写,diff 已逐行核对。 - 新增 `VehicleRequirementKindErrorCode.VEHICLE_REQUIREMENT_KIND_REQUIRED = IErrorCode.of(809012, …)`,消息模板与占位符含义(`{0}`=订单 ID、`{1}`=两类名以 ` / ` 连接)已核对;同段既有码 809000/809001/809002/809007/809008/809009/809010/809011 未变。 - 新增私有方法 `RequirementService#resolveVehicleRequirementKind(Long, String)`,三条分支(非空白原样返回 / 0 类原样返回 / 1 类用那一类 / ≥2 类抛 809012)逐行核对;dispatch 里的调用点排在团期守卫之后、取行之前,reject 里排在 `probeGroupAdminReject` 之前且仅对 `resourceType=VEHICLE` 生效。 - 回归覆盖:`RequirementServiceTest` +301 行、`VehicleRequirementAdminControllerTest` +72 行、`VehicleRequirementKindErrorCodeMessageTest` +22 行(含 809012 报文渲染断言)。 - **部署**:`hl-order-service-v3` 的 `dev-v3` 分支已滚到测试服,两个端点走管理端网关 `/v3/admin/order/**` 既有路由,无新增路由。 ``` POST /v3/admin/order/{id}/vehicle-requirement/dispatch?kind=TRANSFER → 200 ✓ POST /v3/admin/order/{id}/vehicle-requirement/reject?kind=TRAVEL → 200 ✓ POST /v3/admin/order/{id}/vehicle-requirement/dispatch(两类并存不传 kind) → 809012 ✓ POST /v3/admin/order/{id}/vehicle-requirement/dispatch(纯接送机户不传 kind) → 200 ✓(改前 582031) ``` --- ## 九、相关历史 PR | PR | Issue | 说明 | 是否仍有效 | |----|-------|------|------------| | — | #7210 | 逐单打回源状态放宽到 PENDING,接团期权限守卫 | ✅ 有效 | | — | #7439 | 用车需求按 kind 分家,两个端点加 `kind` 参数(当时带默认值 TRAVEL) | ⚠️ 默认值部分已被本单撤销 | | — | #8435 | 团期订单接送变更走团期放行(809011) | ✅ 有效 | | **本 PR #8610** | **#8601** | `kind` 取消默认值,空值按活跃类别数分流,新增 809012 | ✅ 最新 | --- ## 十、相关文档 - 关联 Issue: [wx/HL#8601](https://git.1814.love:8443/wx/HL/issues/8601) - 关联 PR: [wx/HL#8610](https://git.1814.love:8443/wx/HL/pulls/8610) ## 关联 / 联系人 ### 链接 - **Issue**: [#8601](https://git.1814.love:8443/wx/HL/issues/8601) - **PR**: [#8610](https://git.1814.love:8443/wx/HL/pulls/8610) - **Merge commit**: [a2ba628ecb](https://git.1814.love:8443/wx/HL/commit/a2ba628ecb) ### 联系人 - **后端负责人**: @wx