PR #7085 合入 dev-v3(合并提交 d1b724d59),2026-09-04 部署测试环境 并经真实网关鉴权实测 7 条用例。 核心证据:15:30:33 往 group_batch_staff_slot_guide 插一行 GUIDE_ASSISTANT, 15:35:44(301 秒后)导游位候选由 7 人变 8 人——未改代码、未重启、未重新部署。 随后连打 8 次全部返回 8 人,两个实例都已回源。演示行验证后已撤除。 2 个接口的候选池来源与落库取值变更,路径/入参/出参结构全部不变: - GET /v3/admin/group-batch/:groupBatchId/staff/candidates 候选池成员由字典决定,582113 文案变更 - PUT /v3/admin/group-batch/:groupBatchId/staff staffRole 落真实 staffType 含字典初始化脚本 sql/dict_group_batch_staff_slot.sql(幂等,需手工执行)。 dict_type_id 取 8071/8072——8021/8022 在本机与测试环境都已被 contract_status / contract_platform 占用。 staff_role 取值域测试环境实测三处一致(字典 = 枚举 = @Pattern,8 项)。 frontend_status=not_required:路径、入参、出参结构均未变,前端无需改动; 但不要再硬编码候选池成员,也不要沿用自己提交的 staffRole 回显。
14 KiB
schema, ticket, title, consumer, author, change_type, backend_status, gateway_status, frontend_status, frontend_owner, frontend_ref, target_release, verified_at, status_note, updated_at, base
| schema | ticket | title | consumer | author | change_type | backend_status | gateway_status | frontend_status | frontend_owner | frontend_ref | target_release | verified_at | status_note | updated_at | base |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| hl-changelog/v2 | 7079 | 团期人员配置位成员改由字典决定,取值域三处对齐 | admin | jw(GIT) | 修改接口 | deployed | verified | not_required | PR #7085 已合入 dev-v3(合并提交 d1b724d59);2026-09-04 部署测试环境并经网关实测。含字典初始化脚本 sql/dict_group_batch_staff_slot.sql,需手工执行 | 2026-09-04 | dev-v3 |
团期人员配置: 配置位收哪些人员类型改由数据字典决定
服务: hl-order-service-v3 PR: #7085 | Issue: #7079 | 合并提交:
d1b724d59影响范围: 管理后台「团期详情 → 配置导游/摄影」弹窗的候选池
⚠️ 关键变化
「导游位收哪些人员类型」不再写死在代码里,改由数据字典决定。业务在字典管理页面加一行,最多 5 分钟后生效,不需要发版。
group_batch_staff_slot_guide → GUIDE、LEADER
group_batch_staff_slot_photographer → PHOTOGRAPHER
另有一处落库取值变化:导游位并收导游与领队,改前不论选的是谁,order_batch_staff.staff_role 落的都是前端传的配置位名(往往是 GUIDE),「这一位上站的到底是导游还是领队」在数据里就丢了。现在落该人员在资源域的真实 staffType。
一、背景
人员类型 staff_type 本来就是「服务人员管理」里维护的字典,实有 7 项。而团期人员配置位只认死了导游位与摄影位两个、成员也写死在 Java 字面量里,要让研学老师也能配进导游位就得改代码发版。本次把这件事交还给业务。
二、变更接口清单
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|---|---|---|---|---|---|
| 1 | 团期人员候选列表 | GET | /v3/admin/group-batch/:groupBatchId/staff/candidates |
候选池来源变更 | 成员由字典决定;582113 文案变更 |
| 2 | 全量保存团期人员配置 | PUT | /v3/admin/group-batch/:groupBatchId/staff |
落库取值变更 | staffRole 落真实 staffType |
三、接口详情
1. 团期人员候选列表 GET /v3/admin/group-batch/:groupBatchId/staff/candidates
VO: StaffCandidateRespVO
使用场景
「配置导游 / 配置摄影」弹窗打开时调用,渲染可选人员列表。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
groupBatchId |
Path | Long | ✅ | — | 产品侧团期 batchId |
role |
Query | String | ✅ | GUIDE / PHOTOGRAPHER,大小写敏感 |
配置位标识;未知值返回 582113 |
出参 Result<List<StaffCandidateRespVO>>
| 字段 | 类型 | 说明 |
|---|---|---|
staffId |
Long | 人员 ID,未变 |
staffName |
String | 姓名,未变 |
staffType |
String | 资源域人员类型,未变 |
staffPhone |
String | 脱敏手机号,未变 |
assigned |
Boolean | 是否已选,未变 |
出参结构完全没有变化,变的是这个列表里会出现哪些人——由字典
group_batch_staff_slot_*决定。
请求示例
GET /v3/admin/group-batch/990707900901/staff/candidates?role=GUIDE
响应示例
{
"code": 200,
"message": "成功",
"success": true,
"data": [
{
"staffId": 1002,
"staffName": "李雪梅",
"staffType": "GUIDE",
"staffPhone": "138****1002",
"assigned": false
},
{
"staffId": 1005,
"staffName": "刘大山",
"staffType": "LEADER",
"staffPhone": "138****1005",
"assigned": false
}
]
}
空数据 / 降级响应
字典读空或字典服务不可用时不报错,回落到内置默认值(导游位 GUIDE+LEADER,摄影位 PHOTOGRAPHER)并打 WARN,候选列表照常返回。资源域无可用人员时返回空数组:
{
"code": 200,
"message": "成功",
"success": true,
"data": []
}
错误响应
配置位标识未知(含小写 guide、DRIVER):
{
"code": 582113,
"message": "人员配置位不合法,请检查配置位标识",
"success": false,
"data": null
}
业务边界
- 配置位成员来自字典,改字典后各实例最多 5 分钟内生效(本地缓存有界 TTL)
- 字典里写了取值域外的人员类型会被忽略并 WARN,其余行照常生效
- 字典整体读不到时回落内置默认值,行为与改前一致
role大小写敏感,小写不认(沿用既有口径)- 司机不设配置位,由车务派车投影产生
2. 全量保存团期人员配置 PUT /v3/admin/group-batch/:groupBatchId/staff
VO: BatchStaffConfigReqVO
使用场景
「配置导游 / 配置摄影」弹窗点保存时调用,全量覆盖该团期人员配置。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
groupBatchId |
Path | Long | ✅ | — | 产品侧团期 batchId |
staffList |
Body | Array | ❌ | 传空则清空 | 全量覆盖 |
staffList[].staffId |
Body | Long | ✅ | — | 资源域人员 ID |
staffList[].staffRole |
Body | String | ✅ | 取值域本次扩至 8 项 | 见下方取值域说明 |
staffList[].sortOrder |
Body | Integer | ❌ | 缺省 0 | 展示排序 |
出参 Result<BatchStaffConfigRespVO>
| 字段 | 类型 | 说明 |
|---|---|---|
staffList |
Array | 落库后的人员快照;其中 staffRole 取值口径变更 |
affectedOrderCount |
Integer | 扇出到的活跃子订单数,未变 |
请求示例
{
"staffList": [
{
"staffId": 1005,
"staffRole": "GUIDE",
"sortOrder": 0
}
]
}
响应示例
请求传的是配置位名 GUIDE,但 1005 在资源域是领队,出参与落库都归一为 LEADER:
{
"code": 200,
"message": "成功",
"success": true,
"data": {
"staffList": [
{
"staffId": 1005,
"staffRole": "LEADER",
"staffName": "刘大山",
"staffPhone": "138****1005",
"sortOrder": 0
}
],
"affectedOrderCount": 1
}
}
空数据 / 降级响应
staffList 传空数组即清空该团期全部人员配置:
{
"code": 200,
"message": "成功",
"success": true,
"data": {
"staffList": [],
"affectedOrderCount": 1
}
}
错误响应
staffRole 不在取值域内:
{
"code": 400,
"message": "员工角色不在取值域内,取值域对齐 SettlementStaffRoleEnum 与 staff_role 字典",
"success": false,
"data": null
}
业务边界
- 落库
staffRole只在配置位内部归一:请求角色能解析到配置位、且该人员真实类型也在这个配置位成员里时才替换 - 跨位不匹配(领队被配到摄影位)沿用入参,本次不做拒绝
DRIVER/OTHER不属于任何配置位,沿用入参- 资源域反查不到人员类型时沿用入参
- 导游位有人(
GUIDE或LEADER)即置guide_ready,与改前一致
四、契约约束与正确调用方式
- 候选池成员不再由代码保证,前端不要硬编码「导游位只会出现导游和领队」;以接口返回为准。
staffRole落库值可能与提交值不同:提交配置位名,落库是该人员的真实人员类型。前端若需回显角色,读出参里的staffRole,不要沿用自己提交的值。staffRole取值域本次由 5 项扩至 8 项:新增GUIDE_ASSISTANT/STUDY_TEACHER/LIFE_TEACHER。- 改字典不是立即全局生效:各实例本地缓存 5 分钟有界 TTL,期间不同实例口径可能不同,只影响候选池多列/少列一类人员。
五、数据库行为
无 DDL、无 Flyway 迁移。但需手工执行一个字典初始化脚本:
sql/dict_group_batch_staff_slot.sql 新增,幂等,可重复执行
| 表 | 变化 |
|---|---|
sys_dict_type |
新增 2 行:group_batch_staff_slot_guide(8071) / group_batch_staff_slot_photographer(8072) |
sys_dict_data |
新增 3 行配置位成员;staff_role 补 STUDY_TEACHER / LIFE_TEACHER 两行 |
order_batch_staff.staff_role |
结构未变;新写入的取值口径变了,存量行不动 |
dict_type_id取 8071/8072 而非号段顺序的 8021/8022——后者在本机与测试环境都已被contract_status/contract_platform占用(两处实测确认)。
六、边界行为
- 字典未初始化 → 回落内置默认值,行为与改前完全一致
- 字典含非法人员类型 → 忽略该行 + WARN,其余生效
- 字典全部非法 → 视同读空,回落默认值
- 字典行
dictValue为空或空白 → 直接跳过,不刷告警 - Feign 返回 null / 失败 / 抛异常 → 三种都回落默认值,不把异常透给调用方
role小写 / 未知 →582113
六.5、枚举 / 数据字典
新增字典类型 2 个:group_batch_staff_slot_guide、group_batch_staff_slot_photographer。取值域 = 资源域 staff_type。
staff_role 字典扩至 8 项,与 SettlementStaffRoleEnum 和接口 @Pattern 三处对齐(测试环境实测三处完全一致)。
六.6、修改前后对比
| 项 | 变更前 | 变更后 |
|---|---|---|
| 配置位成员 | 写死在 3 处 Java 字面量 | 由字典决定,加一行即生效 |
| 扩一种人员类型 | 改代码 + 发版 | 改字典,最多 5 分钟生效 |
落库 staffRole |
前端传的配置位名 | 该人员真实 staffType |
staffRole 取值域 |
5 项 | 8 项 |
582113 文案 |
「只支持导游位与摄影位」 | 「请检查配置位标识」 |
| 字典不可用 | — | 回落内置默认值,不中断 |
| 路径 / 入参 / 出参结构 | — | 全部不变 |
六.7、影响评估
| 维度 | 评估 |
|---|---|
| 兼容性 | 字典未初始化时回落默认值,与改前完全一致,不会坏 |
| 前端 | 无需改动。路径、入参、出参结构均未变;但不要再硬编码候选池成员,也不要沿用自己提交的 staffRole 回显 |
| 数据 | 无 DDL;需手工执行一个幂等字典脚本;存量 staff_role 行不动 |
| 性能 | 每个配置位一次字典 Feign,5 分钟缓存;候选池按类型逐类拉取,类型多一种多一次资源域调用 |
| 回滚 | git revert;字典行留着无害(回滚后代码不读它) |
| 风险 | 中低。主要风险是下游若有按 staff_role == 'GUIDE' 硬比对处会受落库取值变化影响;order-v3 内已全部改为按配置位归组 |
七、不影响范围
- 零影响:两个接口的路径、HTTP 方法、入参字段、出参结构
- 零影响:摄影位口径,字典默认仍只收
PHOTOGRAPHER - 零影响:staff-fees 费用录入分流——只加枚举取值域,未动
SettlementStaffFeeDetailCodec的GUIDE/PHOTOGRAPHER两族判定 - 零影响:存量
order_batch_staff/order_staff_assignment数据 - 零影响:
DRIVER/OTHER角色的处理 - 未新建端点
八、测试环境已验证
✅ 2026-09-04 于测试环境网关实测,真实鉴权(管理端 test_admin,角色定制师)。
- 网关
https://api.test.1814.love:9443,分支dev-v3,合并提交d1b724d59 - 部署方式:双实例滚动更新(8186 → 8086),各 10s 就绪,零停机
- 部署内容经部署面板
/api/git/backend交叉核对:构建时点d1b724d59已是dev-v3顶端 - 字典初始化脚本已在测试环境执行,幂等
| # | 用例 | 期望 | 实测 |
|---|---|---|---|
| 1 | 导游位候选(字典 GUIDE+LEADER) | 与改前一致 | ✅ 7 人 |
| 2 | 摄影位候选 | 口径不变 | ✅ 1 人 |
| 3 | role=DRIVER |
582113 新文案 |
✅ 「请检查配置位标识」 |
| 4 | 导游位选领队(提交 GUIDE) |
落库真实类型 | ✅ 出参与落库均为 LEADER |
| 5 | 同场景 guide_ready |
仍置位 | ✅ 1 |
| 6 | staff_role 取值域三处对齐 |
字典 = 枚举 = @Pattern |
✅ 8 项完全一致 |
| 7 | 字典加一行 GUIDE_ASSISTANT |
无需发版即生效 | ✅ 301 秒后候选 7 → 8 人,陈小燕出现;两个实例连打 8 次均为 8 |
观察:双实例持续 running,服务日志最近 200 行 ERROR / Exception 命中 0 条;配置位字典相关 WARN 0 条,说明字典读取正常、未走降级。
用例 7 是本单的核心证据:15:30:33 往字典插一行,15:35:44(301 秒后)候选列表由 7 人变 8 人——没有改代码、没有重启服务、没有重新部署。延迟符合 5 分钟有界 TTL 的设计;随后连打 8 次全部返回 8 人,两个实例都已回源。演示用的那一行验证后已撤除,出厂默认仍是 GUIDE + LEADER。
本地单测:431 例全过。新增 GroupBatchStaffSlotResolverTest 14 例(正常读取、加行即生效、去重、TTL 命中缓存、读空/Feign null/Feign 异常三种降级、降级后判定仍工作、非法值过滤、全非法回落、空白值跳过、未知角色无配置位、枚举大小写敏感);GroupBatchStaffConfigServiceTest 新增 3 例覆盖落库取值三个分支。
测试数据:一律 T7079- 前缀,验证后物理删除。test_admin 口令一次性置换,取到令牌后立即按备份还原,逐字节一致;共享库写入全程持 test-db 租约。
九、相关历史 PR
- #7065(Refs #7063 第 1 波)本 PR 承接它,
StaffSlotRoles由事实源退化为兜底默认值 - 裁决来源:#7063 的 D-1 / D-3 / D-4(jw 2026-09-04)
十、相关文档
- 团期需求文档:
docs/group/(dev-v3 分支) - 字典初始化脚本:
sql/dict_group_batch_staff_slot.sql
关联 / 联系人
- Issue: #7079
- PR: #7085(合并提交
d1b724d59)