diff --git a/changelogs-v2/2026-09/30_8654_团期正式派车司机投影到人员配置表-修改接口-管理后台.md b/changelogs-v2/2026-09/30_8654_团期正式派车司机投影到人员配置表-修改接口-管理后台.md new file mode 100644 index 00000000..3e9d682d --- /dev/null +++ b/changelogs-v2/2026-09/30_8654_团期正式派车司机投影到人员配置表-修改接口-管理后台.md @@ -0,0 +1,485 @@ +--- +schema: "hl-changelog/v2" +ticket: "8654" +title: "团期正式派车司机投影到人员配置表,DRIVER 角色改系统托管" +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-30" +status_note: "" +updated_at: "2026-09-30" +base: "dev-v3" +--- + +# 团期人员配置: 正式派车司机投影到人员配置表,DRIVER 改系统托管 + +> **存放目录**: `changelogs-v2/2026-09/` +> +> **服务**: hl-order-service-v3 +> **PR**: #8669 +> **Issue**: #8653, #8654 +> **日期**: 2026-09-30 +> **影响范围**: 管理后台团期人员配置页、团期核单按团看人的名册读取 + +--- + +## ⚠️ 关键变化 + +**团期人员配置表 `order_batch_staff` 现在会有系统自动生成的 DRIVER 行(司机),前端必须适配两个关键变化:** + +1. **同一批数据的两个读口口径不同**: 保存接口响应里**不含**司机行,但查询接口(`getConfig` / 名册读取)**含**司机行。前端不要假设响应即全量。 + +2. **司机行不可编辑**: 这些 DRIVER 行由车务派车自动投影产生,不是运营配置的,前端不要在人员编辑表单提供编辑/删除入口。 + +3. **新的拒绝错误**(582120):保存请求的 `staffList` 或 `scopeRoles` 里出现 DRIVER,后端会拒绝**整批保存、零写入**。 + +--- + +## 一、背景 + +工单 #8653 与 #8654 合并的功能:**把车务派车产生的司机自动投影到团期人员配置表**,供核单时按团看人、按天算账。 + +此前司机事实分散在每一户订单的用车需求上,现在统一投影到团期维度,简化核单逻辑。 + + +--- + +## 二、变更接口清单 + +| # | 接口 | 方法 | 路径 | 变更类型 | 说明 | +|---|------|------|------|----------|------| +| 1 | 保存团期 staff 配置 | PUT | `/v3/admin/group-batch/{productBatchId}/staff` | 新增错误码 + 响应内容变化 | DRIVER 行系统管理,拒绝人工写入 | + +--- + +## 三、接口详情 + +### 1. 保存团期 staff 配置 `PUT /v3/admin/group-batch/{productBatchId}/staff` + +**VO**: `BatchStaffConfigReqVO → BatchStaffConfigRespVO` + +#### 使用场景 + +管理后台团期人员配置页,点「保存」按钮时调用此接口保存本期的团队成员(导游、摄影等)。支持按配置位(导游位 GUIDE+LEADER / 摄影位 PHOTOGRAPHER)分范围保存,避免一个弹窗保存时把另一个弹窗的既有数据清空。 + +保存成功后异步扇出到团内所有活跃订单的人员分配表 `order_staff_assignment`(source=GROUP_BATCH)。 + +#### 入参 + +| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | +|------|------|------|------|------|------| +| productBatchId | Path | Long | ✅ | 必须是有效的产品侧排期 ID | 团期所属产品侧班期 ID(非运营团期主键,由 group_tour_batch.batch_id 对应) | +| staffList | Body | List | ✅ | 非 null;显式传 [] 表示清空,不能省略 | 本次保存覆盖范围内的最终成员列表。**禁止含 staffRole=DRIVER 的行**(582120)。若覆盖范围是导游位,必须同时列出 GUIDE 与 LEADER 两个角色成员(工单 #8122)。 | +| staffList[].staffId | Body | Long | ✅ | 有效的员工 ID | 用户域员工 ID | +| staffList[].staffRole | Body | String | ✅ | 取值: LEADER / GUIDE / PHOTOGRAPHER / OTHER / GUIDE_ASSISTANT / STUDY_TEACHER / LIFE_TEACHER;**不可含 DRIVER**(582120) | 员工角色。司机行由车务派车自动投影,一律不由本接口写入。 | +| staffList[].sortOrder | Body | Integer | ❌ | 缺省 0 | 显示排序值(升序排列) | +| staffList[].remark | Body | String | ❌ | ≤500 字符;null 表示保留原值,传空串清空 | 备注,仅供参考 | +| staffList[].serviceStartDate | Body | LocalDate | ❌ | yyyy-MM-dd;不传时保留下来的人沿用原值、新选人员跟随团期;传值若与团期出发日相同则存 null(即跟随团期) | 有效服务开始日(#8468)。若自定义则必须在团期出发日到结束日之间,否则 582119 拒绝。 | +| staffList[].serviceEndDate | Body | LocalDate | ❌ | yyyy-MM-dd;规则同 serviceStartDate;对照团期结束日 | 有效服务结束日(#8468)。 | +| scopeRoles | Body | List | ❌ | 元素不能为 null / 空串 / 纯空白;传了必须 size ≥ 1 | 本次保存覆盖的角色范围。不传 = 整期全量覆盖(历史行为);传了 = 只覆盖这些角色,范围外既有行不动(工单 #8006)。导游位必须同时传 GUIDE 与 LEADER(工单 #8122),只传一个拒绝 582116 且零写入。staffList 里出现范围外角色拒绝 582115 且零写入。**禁止传 DRIVER**(582120)。 | + +#### 出参 `Result` + +| 字段 | 类型 | 说明 | +|------|------|------| +| data.productBatchId | Long | 路径参数回显 | +| data.groupBatchId | Long | 运营团期 ID(order_group_batch 主键) | +| data.staffList | List | 本次保存后**保留下来的整期非司机成员**的最新快照。**不含 DRIVER 行**(工单 #8654)。 | +| data.staffList[].id | Long | 记录 ID(batch_staff_id) | +| data.staffList[].staffId | Long | 员工 ID | +| data.staffList[].staffRole | String | 员工角色(LEADER / GUIDE / PHOTOGRAPHER 等,响应侧**不含 DRIVER**) | +| data.staffList[].staffRoleName | String | 员工角色中文名(「导游」「领队」等;取值不在字典内时回落原 code) | +| data.staffList[].staffName | String | 员工姓名(配置时快照) | +| data.staffList[].staffPhone | String | 员工手机(脱敏:前 3 后 4,如 `138****6677`) | +| data.staffList[].avatarUrl | String | 头像 URL(配置时快照) | +| data.staffList[].sortOrder | Integer | 显示排序值 | +| data.staffList[].remark | String | 备注 | +| data.staffList[].reporterRank | String | 报账人等级:PRIMARY(主) / SECONDARY(次) / NONE(非报账人) | +| data.staffList[].reporterRankName | String | 报账人等级中文名 | +| data.staffList[].serviceStartDate | LocalDate | 有效服务开始日(未自定义时 = 团期出发日,团期改期后跟着变;#8468) | +| data.staffList[].serviceEndDate | LocalDate | 有效服务结束日(规则同上) | +| data.staffList[].serviceDateCustom | Boolean | 是否自定义过服务日期;true 时开始/结束至少一个有自定义值 | +| data.staffList[].baseDailyWage | BigDecimal | 基础日薪(选人时从人员档案快照带出,团期内不可改;仅供参考;单位元;金额以字符串格式返回) | +| data.staffList[].occupancyStatus | String | 占用状态(#8468):FREE / PARTIAL / FULL;按本人有效服务日期段比对其他团期与直派订单;本团未建或日期不完整时为 null;仅提示,不拦截 | +| data.staffList[].occupiedDays | Integer | 被占天数(两端都算);null 时为 0 | +| data.staffList[].freeRanges | List | 可派日期段列表(本人有效日期段内未被占的连续区间);恒非 null;全程占用时为 [] | +| data.staffList[].occupancies | List | 占用明细数组;恒非 null;空闲时为 [] | +| data.affectedOrderCount | Integer | 扇出影响的订单数(已触发异步写入的活跃子订单数) | + +#### 请求示例 + +```http +PUT /v3/admin/group-batch/80001/staff HTTP/1.1 +Host: admin-api.test.example.com +Authorization: Bearer {token} +Content-Type: application/json + +{ + "scopeRoles": ["GUIDE", "LEADER"], + "staffList": [ + { + "staffId": 40001, + "staffRole": "LEADER", + "sortOrder": 0, + "remark": "首席领队", + "serviceStartDate": "2026-10-01", + "serviceEndDate": "2026-10-06" + }, + { + "staffId": 40002, + "staffRole": "GUIDE", + "sortOrder": 1, + "remark": null, + "serviceStartDate": null, + "serviceEndDate": null + } + ] +} +``` + +#### 响应示例 + +```json +{ + "code": 200, + "message": "成功", + "data": { + "productBatchId": 80001, + "groupBatchId": 90211, + "staffList": [ + { + "id": 770001, + "staffId": 40001, + "staffRole": "LEADER", + "staffRoleName": "领队", + "staffName": "刘领队", + "staffPhone": "138****6677", + "avatarUrl": "https://example.com/avatar/40001.jpg", + "sortOrder": 0, + "remark": "首席领队", + "reporterRank": "PRIMARY", + "reporterRankName": "主报账人", + "serviceStartDate": "2026-10-01", + "serviceEndDate": "2026-10-06", + "serviceDateCustom": true, + "baseDailyWage": "600.00", + "occupancyStatus": "PARTIAL", + "occupiedDays": 2, + "freeRanges": ["2026-10-01~2026-10-03", "2026-10-05~2026-10-06"], + "occupancies": [ + { + "groupBatchId": 90212, + "groupBatchName": "十一国庆游 V2 期", + "conflictDates": ["2026-10-02", "2026-10-04"] + } + ] + }, + { + "id": 770002, + "staffId": 40002, + "staffRole": "GUIDE", + "staffRoleName": "导游", + "staffName": "王导游", + "staffPhone": "138****5678", + "avatarUrl": "https://example.com/avatar/40002.jpg", + "sortOrder": 1, + "remark": null, + "reporterRank": "NONE", + "reporterRankName": "非报账人", + "serviceStartDate": "2026-10-01", + "serviceEndDate": "2026-10-06", + "serviceDateCustom": false, + "baseDailyWage": "500.00", + "occupancyStatus": "FREE", + "occupiedDays": 0, + "freeRanges": ["2026-10-01~2026-10-06"], + "occupancies": [] + } + ], + "affectedOrderCount": 3 + }, + "success": true +} +``` + +#### 空数据 / 降级响应 + +整期清空后的响应(`staffList=[]` 加 `scopeRoles` 不传): + +```json +{ + "code": 200, + "message": "成功", + "data": { + "productBatchId": 80001, + "groupBatchId": 90211, + "staffList": [], + "affectedOrderCount": 3 + }, + "success": true +} +``` + +#### 错误响应 + +**错误码 582120**(司机行系统管理,拒绝人工写入): + +```json +{ + "code": 200, + "message": "司机由车务派车自动带入团期人员,不能在这里新增或删除;如需调整请到车务派单中维护", + "success": false, + "data": null +} +``` + +**错误码 582116**(导游位只传半个配置位): + +```json +{ + "code": 200, + "message": "团期人员配置位 GUIDE 成员缺失,导游位(导游+领队)须同时声明两个角色", + "success": false, + "data": null +} +``` + +**错误码 582115**(staffList 包含 scopeRoles 范围外的角色): + +```json +{ + "code": 200, + "message": "员工角色 PHOTOGRAPHER 不在覆盖范围 [GUIDE,LEADER] 内,请修正请求", + "success": false, + "data": null +} +``` + +**错误码 582119**(服务日期校验失败): + +```json +{ + "code": 200, + "message": "刘领队 的服务日期(2026-10-06 至 2026-10-05)不合法:开始日期不能晚于结束日期,且须在团期日期(2026-10-01 至 2026-10-10)之内", + "success": false, + "data": null +} +``` + +#### 业务边界 + +- **权限**: 接口接 `GroupBatchPermissionGuard.PERMISSION_MANAGE`,需要团期管理权限;权限校验在 Controller 层,拒绝时零写入。 +- **幂等性**: 同一请求重复提交视为覆盖保存,第二次提交时无新改动则库表无变化、响应同样 200。 +- **扇出并发**: 保存成功后异步扇出到团内全部活跃订单的 `order_staff_assignment(source=GROUP_BATCH)`,前端无需等待此异步过程即可收到 200。 +- **DRIVER 行系统管理**: 司机行由车务派车通过 `GroupBatchDriverProjectionService` 自动投影维护,人工配置侧严禁涉及。staffList 或 scopeRoles 里出现 DRIVER 一律拒绝(582120),**整批保存零写入**,连软删都不执行。 +- **两个读口口径不同**: + - 本接口(PUT)保存成功后返回的 `staffList` **不含司机行**(只含人工配置的非 DRIVER 角色)。 + - 查询接口 `GET /v3/admin/group-batch/{productBatchId}/staff` 与单人查询 `GET .../staff/{staffId}` **含司机行**。 + - 前端不要假设响应即全量,名册读取时必须从查询接口获取完整名单(含司机)。 +- **团期状态检查**: 入口第一步检查团期成团状态(未建团 589553 / 已确认或已取消 589598);不满足直接拒,代码不走到保存逻辑。 +- **服务日期有效期**: serviceStartDate 与 serviceEndDate 必须满足: + - 开始日 ≤ 结束日 + - 双双在团期出发日到结束日之间 + - 违反任一条拒绝 582119,**整批零写入**。 + +--- + +## 四、契约约束与正确调用方式 + +### ✅ 正确 / ❌ 错误 payload 对照 + +| 场景 | payload | 结果 | +|------|---------|------| +| ✅ 导游位全量覆盖 | `{ "scopeRoles": ["GUIDE","LEADER"], "staffList": [{staffId:40001, staffRole:"LEADER"}, {staffId:40002, staffRole:"GUIDE"}] }` | 200,只有这两人留在 GUIDE 和 LEADER 行,其他既有行不动 | +| ✅ 清空整期 | `{ "staffList": [] }` (不传 scopeRoles) | 200,整期人员全清,库表此后仅含司机行 | +| ✅ 导演位自定义服务日期 | `{ "staffList": [{staffId:40001, staffRole:"LEADER", serviceStartDate:"2026-10-01", serviceEndDate:"2026-10-05"}] }` | 200 | +| ❌ 导游位只传半个配置位 | `{ "scopeRoles": ["GUIDE"], "staffList": [...] }` | 拒绝 582116、零写入(缺少 LEADER 配角) | +| ❌ staffList 包含 DRIVER | `{ "staffList": [{staffId:40001, staffRole:"DRIVER"}] }` | 拒绝 582120、零写入(司机由车务派车投影) | +| ❌ scopeRoles 包含 DRIVER | `{ "scopeRoles": ["DRIVER"], "staffList": [] }` | 拒绝 582120、零写入 | +| ❌ 服务开始日晚于结束日 | `{ "staffList": [{staffId:40001, staffRole:"GUIDE", serviceStartDate:"2026-10-05", serviceEndDate:"2026-10-01"}] }` | 拒绝 582119、零写入 | +| ❌ 服务日期越出团期 | `{ "staffList": [{staffId:40001, staffRole:"GUIDE", serviceStartDate:"2026-09-30"}] }` (团期出发日 2026-10-01) | 拒绝 582119、零写入 | + +### scopeRoles 的语义 + +- **不传**: 整期全量覆盖。staffList 即为团期的最终全量人员配置(除去司机),其他所有角色的既有行会被软删。 +- **传了**: 仅覆盖声明的角色。比如只想更新导演位不动摄影位,传 `["GUIDE","LEADER"]` 即可;摄影位的既有行保持不变。 +- **导游位特殊性**: 因为导游位同时收 GUIDE 与 LEADER 两个角色,声明导游位必须两个都传。只传其中一个会被拒(582116)——因为「少那一个」意味着覆盖范围不完整,不能正确表达"我只想改导游位"的意图。 +- **DRIVER 禁令**: scopeRoles 里出现 DRIVER 拒绝 582120。虽然 DRIVER 在结构上不属于任何配置位(系统管理),但这条禁令是恒定的——不能通过改 scopeRoles 来迂回删除司机行。 + +--- + +## 五、数据库行为 + +保存请求成功后的库表变化: + +| 操作 | 对象 | 行为 | +|------|------|------| +| 软删 | `order_batch_staff` | 按 scopeRoles(若不传则整期)清除人工行,**不删司机行**(502120 保护) | +| 插入 | `order_batch_staff` | 按 staffList 新增非 DRIVER 行 | +| 异步扇出 | `order_staff_assignment(source=GROUP_BATCH)` | 更新团内活跃订单的 GROUP_BATCH 副本,内容为最新的整期非司机成员 | + +**核心不变量**: 人工配置(GroupBatchStaffConfigService)**只碰非 DRIVER 行**;司机投影(GroupBatchDriverProjectionService)**只碰 DRIVER 行**。两边各管各的子集,交集为空。 + +--- + +## 六、边界行为 + +- **未登录** → 401(网关拦截) +- **无团期管理权限** → 403(权限校验) +- **团期不存在** → 589553(未建团)或 589598(已确认/已取消) +- **下游服务(人员服务、图片服务)降级** → 快照字段(姓名、手机、头像)回落配置时快照,接口仍 200;不阻断保存流程 +- **并发冲突** → 保存成功(最后提交的版本胜出,不走 CAS),查询时可能看到中间态 +- **司机行来自** → 由 `fleet-service` 派车回调、经 `GroupBatchDriverProjectionService` 投影维护,非人工配置 + +--- + +## 六.5、枚举 + +### staffRole(员工角色) + +**所属字段**: `staffList[].staffRole` (请求) / `data.staffList[].staffRole` (响应) | **类型**: `String` + +| 值 | 中文 | 说明 | +|----|------|------| +| `LEADER` | 领队 | 导游位成员之一 | +| `GUIDE` | 导游 | 导游位成员之一(与 LEADER 并收) | +| `PHOTOGRAPHER` | 摄影 | 摄影位成员 | +| `GUIDE_ASSISTANT` | 导游助理 | 其他配置位成员 | +| `STUDY_TEACHER` | 研学老师 | 其他配置位成员 | +| `LIFE_TEACHER` | 生活老师 | 其他配置位成员 | +| `OTHER` | 其他 | 杂项角色(不属于任何标准配置位) | +| `DRIVER` | 司机 | **本接口禁止人工写入**(582120);由车务派车自动投影;查询时可见 | + +### reporterRank(报账人等级) + +**所属字段**: `data.staffList[].reporterRank` (响应) | **类型**: `String` + +| 值 | 中文 | 说明 | +|----|------|------| +| `PRIMARY` | 主报账人 | 团期内唯一;预支款打给此人 | +| `SECONDARY` | 次报账人 | 团期内唯一;备选收款人 | +| `NONE` | 非报账人 | 缺省值;不参与结算 | + +### occupancyStatus(占用状态) + +**所属字段**: `data.staffList[].occupancyStatus` (响应) | **类型**: `String` + +| 值 | 中文 | 说明 | +|----|------|------| +| `FREE` | 空闲 | 有效服务日期段内无其他团期或订单占用 | +| `PARTIAL` | 部分占用 | 有效日期段内某些天被占,某些天可派 | +| `FULL` | 全程占用 | 有效日期段全部被占,无可派日期 | +| `null` | - | 团期未建成或服务日期不完整时为 null;仅提示,不拦截提交 | + +--- + +## 六.6、修改前后对比 + +### 接口逻辑变化 + +| 维度 | 改前 | 改后 | +|------|------|------| +| **司机行管理** | 团期人员配置由运营全手工维护,无系统投影 | 司机行由车务派车自动投影,人工配置侧严禁涉及 | +| **保存响应** | 返回整期人员全量(包含一切手工配置) | 返回**非司机成员**快照(DRIVER 行被筛除) | +| **查询响应** | 同保存响应 | **含司机行**(与保存响应口径不同) | +| **错误码新增** | 无 DRIVER 相关拒绝 | 新增 582120:司机行拒绝码,整批零写入 | +| **权限校验** | 无 | 新增 Controller 层权限校验(PERMISSION_MANAGE),拒绝时零写入 | + +### 字段级变化 + +| 字段 | 改前状态 | 改后状态 | +|------|----------|----------| +| `serviceStartDate` / `serviceEndDate` | 无此字段 | 新增可选字段;支持按人自定义服务有效期 | +| `serviceDateCustom` | 无 | 新增,标记是否自定义过服务日期 | +| `baseDailyWage` | 无 | 新增,人员档案快照(配置时带出,不可修改) | +| `occupancyStatus` / `occupiedDays` / `freeRanges` | 无 | 新增,占用查询结果(#8468 D8,仅提示不拦截) | + +--- + +## 六.7、影响评估 + +- **是否破坏向后兼容**: 是(一定程度) + - 响应体新增字段:`serviceStartDate` / `serviceEndDate` / `serviceDateCustom` / `baseDailyWage` / `occupancyStatus` / `occupiedDays` / `freeRanges` / `occupancies`,但字段全可空,字段层兼容。 + - 响应 `staffList` 内容变化:**不再包含司机行**(之前如果有系统产生的司机行会出现,现在被筛除)。前端若依赖"返回即全量"会破损。 + - 新增错误码 582120:拒绝 DRIVER 行,整批零写入——改动前的正常请求可能现在被拒。 + +- **前端是否必须同步上线**: 是 + - 如果前端在"人员名册""核单名单"等读取页面会显示司机信息,必须从查询接口(GET)而非缓存保存接口的响应来获取;否则缺司机行。 + - 如果前端在人员编辑表单提供了 DRIVER 行的编辑/删除入口,必须移除,改为呈现"这是由车务派车产生的"提示。 + - UI 需要适配新字段(服务日期、日薪、占用)的显示。 + +- **前端 workaround 清理点**: + - 若前端之前硬编码了"司机只能通过XX页面配置",现在这句不再对。 + - 若前端假设"保存响应即全量名册"来渲染名册卡片,需改为调查询接口。 + - 若前端在人员编辑表单里有 DRIVER 选项,需删除;前端用户无法(也不应该)在这里新增/删除司机。 + +--- + +## 七、不影响范围 + +- **仅影响**: 管理后台「团期人员配置」页面与「团期核单」按团看人的名册展示 +- **零影响**: + - 订单侧人员分配(仍独立维护 `order_staff_assignment(source=ORDER)`) + - 车务派车流程(按 fleet 业务正常发车、自动投影) + - 人员候选列表查询(`GET .../staff/candidates`)的返回格式 + - 团期总体状态、成团判断、团期改期逻辑 + - 后端其他模块对人员表的现有查询(如财务核对) + +--- + +## 八、测试环境已验证 + +以 productBatchId=80001(groupBatchId=90211)为例,真实接口测试: + +``` +PUT /v3/admin/group-batch/80001/staff + Request: scopeRoles=["GUIDE","LEADER"], staffList=[{staffId:40001, staffRole:"LEADER"}] + → 200 OK ✓ + +GET /v3/admin/group-batch/80001/staff + → 200 OK,staffList 含导游位成员及系统投影司机行 ✓ + +PUT /v3/admin/group-batch/80001/staff + Request: staffList=[{staffId:40001, staffRole:"DRIVER"}] + → 拒绝 582120(司机由车务派车自动带入...)✓ + +PUT /v3/admin/group-batch/80001/staff + Request: scopeRoles=["GUIDE"], staffList=[...](缺 LEADER) + → 拒绝 582116(导游位成员缺失...)✓ +``` + +--- + +## 九、相关历史 PR + +| PR | Issue | 说明 | 是否仍有效 | +|----|-------|------|-----------| +| #8669 | #8653, #8654 | 本次变更:司机投影落地,DRIVER 改系统管理 | ✅ 最新 | + +--- + +## 十、相关文档 + +- 关联 Issue: [#8653](https://git.1814.love:8443/wx/HL/issues/8653), [#8654](https://git.1814.love:8443/wx/HL/issues/8654) +- 关联 PR: [#8669](https://git.1814.love:8443/wx/HL/pulls/8669) +- Merge commit: [5c50782717d6](https://git.1814.love:8443/wx/HL/commit/5c50782717d6) + +--- + +## 关联 / 联系人 + +### 链接 + +- **Issue**: [#8653](https://git.1814.love:8443/wx/HL/issues/8653) / [#8654](https://git.1814.love:8443/wx/HL/issues/8654) +- **PR**: [#8669](https://git.1814.love:8443/wx/HL/pulls/8669) +- **Merge commit**: [5c50782717d6](https://git.1814.love:8443/wx/HL/commit/5c50782717d6) + +### 联系人 + +- **后端负责人**: @wx