81 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 | 8468 | 团期导领摄配置加服务日期与基础日薪,选人列表与名册显示占用状态,导摄芯片去掉逐户人员 | admin | jw(GIT) | 修改接口 | deployed | verified | implemented | mmg | 838b80d69dd1ff5a96e6a95e886d979dac5f452c | v2.1 | 2026-09-28 | PR #8475(bf65803b7)与 #8476(623c932bd)已合入 dev-v3,TEST 的 hl-resource-service 与 hl-order-service-v3 均运行 dev-v3 623c932bd;经网关 api.test.1814.love 用真实 admin token 实测 AC-1、3、6~13、15、16 主路径全部通过,金额字段字符串形态已复验。前端需接:选人弹窗展示等级、服务区域、擅长、基础日薪与占用标签,占用明细弹层,保存弹窗编辑服务日期,服务人员管理基础日薪回显与列表列,导摄页签与看板芯片弹层去掉逐户人员表(见第四节交接清单),故 frontend_status 记 pending。前端已交付(人员画像/占用标签/服务日期三态+导摄芯片去逐户人员),详见 hl-admin v2.1 提交 838b80d6。 | 2026-09-28 | dev-v3 |
团期人员配置:服务日期、基础日薪与占用状态(管理后台)
服务: hl-order-service-v3(团期人员配置、导/摄芯片明细)、hl-resource-service(服务人员管理) PR: #8475(主体,合入 dev-v3 为
bf65803b7)、#8476(金额字段改字符串输出,合入 dev-v3 为623c932bd) Issue: #8468 日期: 2026-09-28 影响范围: 团期详情「配导游」「配摄影」的选人弹窗、已配置人员名册与保存弹窗,看板导/摄芯片弹层,服务人员管理新建/编辑/详情/列表
⚠️ 关键变化
- 名册与候选新增占用:已配置人员名册(以及保存、更换、删除响应里的
staffList[])和两个候选接口的每一项都新增occupancyStatus(FREE空闲 /PARTIAL部分占用 /FULL全程占用)、occupiedDays、freeRanges、occupancies[]。占用只提示、不拦截,有占用照样能保存。 - 名册新增服务日期与基础日薪:
serviceStartDate、serviceEndDate、serviceDateCustom、baseDailyWage。保存接口每人可选传serviceStartDate/serviceEndDate;日期不合法返回新错误码582119(文案带人名,整批不写入)。 - 候选新增人员画像并改为全局排序:候选项新增
level、serviceAreas、specialties、baseDailyWage;排序改为「本团本位已选 → 空闲 → 部分占用 → 全程占用 → 等级从高到低 →sortOrder升序 →staffId升序」,分页版逐页翻完不重不漏。 - 金额字段是 JSON 字符串:order-v3 的
baseDailyWage与服务人员管理的basePrice都以字符串输出(如"600.00")。做数值运算、比较大小或回填数字输入框前先Number()。 - 导/摄芯片不再逐户返回人员:
GET .../chips/guide、GET .../chips/photo的items恒为[],只看staffList(团期名册)。aggregateStatus/totalCount/doneCount口径不变。 - 修复:保存导游位后主报账人与备注被重置。保留下来的人(即使请求只带
staffId、staffRole、sortOrder)沿用原来的报账人等级、备注、服务日期与日薪。随之remark口径变化:不传(null)= 沿用原备注;要清空请传空串""。
一、背景
选人弹窗原来只有姓名、手机号、类型,看不到等级、服务区域、擅长和日薪,也看不出这个人同一时段是否已派到别的团或订单;导游/摄影页签下的逐户表把团期名册在每个子订单上重复列一遍;每保存一次导游位,主报账人被重置、备注被清空;服务人员管理的「基础日薪」输入框填了不保存。
jw 2026-09-28 定案口径:
| # | 口径 |
|---|---|
| D1 | 基础日薪在选人时从服务人员管理的「基础日薪」带出,团期里不能改。更换人员取新人的档案值。档案值为 0 或空时返回 null。快照为空时,下次保存补取一次档案当前值;已有值不刷新 |
| D2 | 服务日期不填就跟随团期:读的时候换算成团期出发日和结束日,团期改期后自动跟着变。提交的日期和团期起止相同也按跟随团期处理 |
| D3 | 招募中(还没成团)的团期里派了的人,也算占用 |
| D4 | 日期段两端都算:前一个团结束当天、后一个团出发,这种首尾相接也算占用 |
| D5 | 占用只提示,不拦截。有占用照样能保存,也不要求二次确认 |
| D6 | 保存时,保留下来的人员沿用原来那一行的报账人等级、备注、服务日期和日薪;请求里传了的以请求为准 |
| D7 | 占用有两个来源:①其他团期的人员配置;②普通订单(不属于任何团期)上定制师直接派的人。团期同步到子订单的人员副本不重复计算。已取消的订单不算,其余订单状态都算 |
| D8 | 占用分三档:被占 0 天为空闲,被占满整段为全程占用,其余为部分占用 |
| D9 | 本单不做「只看空闲」筛选 |
| D10 | 导游/摄影不再按子订单逐户展示配置人员,看团期整体名册即可 |
二、变更接口清单
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|---|---|---|---|---|---|
| 1 | 保存团期人员配置 | PUT | /v3/admin/group-batch/{productBatchId}/staff |
修改:入参加字段、新错误码、出参加字段 | 每人可选 serviceStartDate、serviceEndDate;日薪由服务端带出;新错误码 582119;保留人员沿用原等级、备注、日期、日薪 |
| 2 | 查询团期人员名册 | GET | /v3/admin/group-batch/{productBatchId}/staff |
修改:出参加字段 | 每人加服务日期、是否自定义、基础日薪与四个占用字段 |
| 3 | 团期单人更换 | PUT | /v3/admin/group-batch/{productBatchId}/staff/{staffId}/replace |
修改:行为、新错误码、出参加字段 | 新人沿用原人服务日期,日薪取新人档案;可能返回 582119 |
| 4 | 团期单人删除 | DELETE | /v3/admin/group-batch/{productBatchId}/staff/{staffId} |
修改:出参加字段 | 响应 staffList[] 加字段 |
| 5 | 团期人员候选分页 | GET | /v3/admin/group-batch/{productBatchId}/staff/candidates/page |
修改:出参加字段、排序变化 | 加等级、区域、擅长、日薪与占用;全局排序后分页 |
| 6 | 团期人员候选列表 | GET | /v3/admin/group-batch/{productBatchId}/staff/candidates |
修改:出参加字段、排序变化 | 与 5 相同(全量版) |
| 7 | 配导游芯片明细 | GET | /v3/admin/order/group-batch/{groupBatchId}/chips/guide |
修改:出参取值变化 | items 恒为 [],只看 staffList |
| 8 | 配摄影芯片明细 | GET | /v3/admin/order/group-batch/{groupBatchId}/chips/photo |
修改:出参取值变化 | items 恒为 [],只看 staffList |
| 9 | 新建服务人员 | POST | /admin/staff |
修改:入参加字段、出参加字段 | 可传 basePrice;响应 basePrice 为字符串 |
| 10 | 编辑服务人员 | PUT | /admin/staff/{staffId} |
修改:入参加字段、出参加字段 | basePrice 可改,不传不改;负数或超过 2 位小数返回 400 |
| 11 | 服务人员详情 | GET | /admin/staff/{staffId} |
修改:出参加字段 | 返回字符串 basePrice |
| 12 | 服务人员列表 | GET | /admin/staff/list |
修改:出参加字段 | 每条返回字符串 basePrice |
三、接口详情
1. 保存团期人员配置 PUT /v3/admin/group-batch/{productBatchId}/staff
VO: BatchStaffConfigReqVO → BatchStaffConfigRespVO
使用场景
「配导游」「配摄影」保存弹窗点「保存」时调用。本单起弹窗里可以给每个人填服务开始 / 结束日期(不填 = 跟随团期);基础日薪只读展示,不提交。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| productBatchId | Path | Long | 是 | 产品侧排期 ID | 取 detail.productBatchId,不是团期 ID(既有) |
| scopeRoles | Body | String[] | 否 | 传了就不能是 [];导游位必须同时含 GUIDE 与 LEADER |
本次覆盖的角色范围;不传 = 整期覆盖(既有) |
| staffList | Body | Object[] | 是 | 显式传 [] = 清空覆盖范围 |
覆盖范围内的最终名单(既有) |
| staffList[].staffId | Body | Long | 是 | - | 人员 ID(既有) |
| staffList[].staffRole | Body | String | 是 | 取值域不变 | 角色,如 LEADER、GUIDE、PHOTOGRAPHER(既有) |
| staffList[].sortOrder | Body | Integer | 否 | 缺省 0 | 展示排序(既有;不沿用原值) |
| staffList[].remark | Body | String | 否 | ≤500 字 | 口径变化:不传(null)时,保留下来的人沿用原备注;传空串 "" 才是清空;新选的人不传即无备注 |
| staffList[].serviceStartDate | Body | String(yyyy-MM-dd) | 否 | 有效开始日不晚于有效结束日,且在团期出发日到结束日之间,否则 582119 | 新增。服务开始日。不传:保留下来的人沿用原值,新选的人跟随团期。与团期出发日相同按跟随团期处理。要把自定义日期改回跟随团期,传团期出发日本身 |
| staffList[].serviceEndDate | Body | String(yyyy-MM-dd) | 否 | 同上 | 新增。服务结束日,口径同上,对照团期结束日 |
| staffList[].baseDailyWage | Body | - | 否 | 不接收 | 请求里带了会被忽略(不报错、不落库);日薪一律由服务端从服务人员档案带出 |
出参 Result<BatchStaffConfigRespVO>
| 字段 | 类型 | 说明 |
|---|---|---|
| productBatchId | String | 回显路径参数(既有) |
| groupBatchId | String | 运营团期 ID(既有) |
| affectedOrderCount | Integer | 同步到的活跃子订单数(既有) |
| staffList | Object[] | 保存后的整期名单(既有)。既有字段 id、staffId、staffRole、staffRoleName、staffName、staffPhone、avatarUrl、sortOrder、remark、reporterRank、reporterRankName 不变;staffStatus、liveInfoDegraded 在本接口为 null(既有) |
| staffList[].serviceStartDate | String(yyyy-MM-dd) | 新增。有效服务开始日:没自定义 = 团期出发日(团期改期后跟着变);自定义值原样显示;只有团期出发日为空时为 null |
| staffList[].serviceEndDate | String(yyyy-MM-dd) | 新增。有效服务结束日,口径同上,对照团期结束日 |
| staffList[].serviceDateCustom | Boolean | 新增。开始或结束任一自定义过为 true;都跟随团期为 false;恒非 null |
| staffList[].baseDailyWage | String | 新增。基础日薪快照,字符串如 "1000.00";档案未填或为 0 时为 null;前端运算前 Number() |
| staffList[].occupancyStatus | String | 新增。FREE / PARTIAL / FULL,按这个人在本团的服务日期段比对;本团期未建或团期起止不全时为 null |
| staffList[].occupiedDays | Integer | 新增。服务日期段内被占的天数(两端都算);occupancyStatus 为 null 时为 0 |
| staffList[].freeRanges | String[] | 新增。可派日期段,形如 2026-10-28~2026-10-28,按日期升序;全程占用或 occupancyStatus 为 null 时为 [] |
| staffList[].occupancies | Object[] | 新增。占用明细,按 startDate 升序;空闲或 occupancyStatus 为 null 时为 [] |
| staffList[].occupancies[].sourceType | String | 来源:GROUP_BATCH 其他团期的人员配置 / ORDER 普通订单上定制师直派 |
| staffList[].occupancies[].sourceId | String | 来源 ID:GROUP_BATCH 为运营团期 ID,ORDER 为订单 ID |
| staffList[].occupancies[].refNo | String | 团期号 / 订单号;源数据为空时为 null |
| staffList[].occupancies[].title | String | 团期名称(为空时取产品名)/ 订单的产品名;都为空时为 null |
| staffList[].occupancies[].statusName | String | 来源当前状态中文名,如「招募中」「待出行」 |
| staffList[].occupancies[].staffRole / staffRoleName | String | 他在那边的角色及中文名(跨角色也计入占用) |
| staffList[].occupancies[].startDate / endDate | String(yyyy-MM-dd) | 他在那边的服务起止:团期为他在那个团的有效服务日期(自定义日期先夹进那个团当前起止);订单为出发日到返回日(返回日为空按出发日当天) |
| staffList[].occupancies[].overlapStartDate / overlapEndDate | String(yyyy-MM-dd) | 与本团服务日期段重叠的起止,两端都算,恒在本团服务日期段内 |
请求示例
PUT /v3/admin/group-batch/2104455374549721090/staff
Authorization: Bearer <admin token>
Content-Type: application/json
{
"scopeRoles": ["GUIDE", "LEADER"],
"staffList": [
{
"staffId": 1005,
"staffRole": "LEADER",
"sortOrder": 1,
"remark": "负责额尔古纳段",
"serviceStartDate": "2026-10-27",
"serviceEndDate": "2026-10-28"
}
]
}
响应示例
2026-09-28 测试服实测(班期 10-26 ~ 10-28,刘大山 10-27 已被一张普通订单派为领队;金额按当前契约写成字符串):
{
"code": 200,
"message": "成功",
"data": {
"productBatchId": "2104455374549721090",
"groupBatchId": "2104455377657724930",
"staffList": [
{
"id": "2104456232708509698",
"staffId": 1005,
"staffRole": "LEADER",
"staffRoleName": "领队",
"staffName": "刘大山",
"staffPhone": "138****1005",
"avatarUrl": "https://hlgl-test.oss-cn-beijing.aliyuncs.com/test/material/2026/03/26/45d9abebc569ca7b7ab13cac212ca38a.png",
"sortOrder": 1,
"remark": "负责额尔古纳段",
"reporterRank": "NONE",
"reporterRankName": "非报账人",
"staffStatus": null,
"liveInfoDegraded": null,
"serviceStartDate": "2026-10-27",
"serviceEndDate": "2026-10-28",
"serviceDateCustom": true,
"baseDailyWage": "1000.00",
"occupancyStatus": "PARTIAL",
"occupiedDays": 1,
"freeRanges": ["2026-10-28~2026-10-28"],
"occupancies": [
{
"sourceType": "ORDER",
"sourceId": "2100743225424621570",
"refNo": "HL20260918082629372",
"title": "测试核心产品-单档-固定比例",
"statusName": "待出行",
"staffRole": "LEADER",
"staffRoleName": "领队",
"startDate": "2026-10-25",
"endDate": "2026-10-27",
"overlapStartDate": "2026-10-27",
"overlapEndDate": "2026-10-27"
}
]
}
],
"affectedOrderCount": 1
},
"traceId": null,
"success": true
}
空数据 / 降级响应
staffList: [](清空覆盖范围):照常 200,响应staffList是保存后的整期名单,范围内的人已移除(既有)。- 团期起止任一端为空时:名册项
serviceStartDate/serviceEndDate可能为 null,占用四字段为null/0/[]/[]。 - 占用不影响保存结果:有占用、全程占用都照样 200。
错误响应
{
"code": 582119,
"message": "萨仁高娃 的服务日期(2026-11-16 至 2026-11-19)不合法:开始日期不能晚于结束日期,且须在团期日期(2026-11-17 至 2026-11-19)之内",
"data": null,
"traceId": null,
"success": false
}
| code | 触发条件 |
|---|---|
582119 |
新增。某人的有效服务开始日晚于结束日,或越出团期出发日到结束日;文案里是人名和他的有效起止、团期起止(团期日期不全时写「未定」);整批不写入 |
582115 / 582116 |
角色超出 scopeRoles / 只声明了半个配置位(既有;同时触犯时先报这两个) |
589553 / 589598 |
团期尚未创建 / 团期已确认或已取消(既有) |
400 |
缺 staffList、remark 超 500 字、日期格式不对等参数校验(既有机制) |
业务边界
- 判权未改:需要团期管理权限
group-batch:manage。 - 「保留下来的人」= 本次提交里、且在本次覆盖范围内原本就有记录的人(按
staffId认)。他们的报账人等级一律沿用(本接口改不了等级,改等级走PUT .../staff/{staffId}/reporter-rank);备注、服务日期请求没传时沿用;日薪原快照非空时沿用。 - 日薪(D1):新选的人取服务人员档案当前的基础日薪(0 或空 → null);保留下来的人原快照非空不刷新,原快照为空时补取一次档案当前值;请求里的
baseDailyWage一律忽略。 - 服务日期(D2):与团期起止相同按跟随团期处理,名册
serviceDateCustom=false;自定义才算true。开始、结束两端各自判断。 - 582119 校验的是本次所有要写入的人,包括沿用来的旧日期:团期改期后旧的自定义日期可能已落在新团期外,这时保存同样返回 582119,文案点名,先把那个人的日期改到团期内再保存。
- 返回 582119 时整批不写入:原名册一行不变。
- 占用只提示不拦截(D5)。
2. 查询团期人员名册 GET /v3/admin/group-batch/{productBatchId}/staff
VO: List<BatchStaffConfigRespVO.BatchStaffItemVO>
使用场景
「配导游」「配摄影」页签打开时拉已配置人员,前端按 staffRole 分到导游位(GUIDE / LEADER)与摄影位(PHOTOGRAPHER)两张表。本单起每行可展示服务日期、基础日薪与占用标签。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| productBatchId | Path | Long | 是 | 产品侧排期 ID | 取 detail.productBatchId,不是团期 ID(既有) |
出参 Result<List<BatchStaffItemVO>>
| 字段 | 类型 | 说明 |
|---|---|---|
| id | String | 团期人员记录 ID(既有;整位保存后会变,单人操作用 staffId) |
| staffId | Long | 人员 ID(既有) |
| staffRole / staffRoleName | String | 角色及中文名(既有) |
| staffName / staffPhone / avatarUrl | String | 姓名、脱敏手机号、头像(既有) |
| sortOrder | Integer | 排序(既有) |
| remark | String | 备注(既有) |
| reporterRank / reporterRankName | String | 报账人等级及中文名(既有) |
| staffStatus / liveInfoDegraded | String / Boolean | 人员在资源库的状态、是否降级为快照(既有,仅本接口填充) |
| serviceStartDate | String(yyyy-MM-dd) | 新增。有效服务开始日:没自定义 = 团期出发日(团期改期后跟着变);自定义值原样显示;只有团期出发日为空时为 null |
| serviceEndDate | String(yyyy-MM-dd) | 新增。有效服务结束日,口径同上,对照团期结束日 |
| serviceDateCustom | Boolean | 新增。开始或结束任一自定义过为 true;恒非 null |
| baseDailyWage | String | 新增。基础日薪快照,字符串如 "1000.00";档案未填或为 0 时为 null;前端运算前 Number() |
| occupancyStatus | String | 新增。FREE / PARTIAL / FULL,按这个人在本团的服务日期段比对;本团期未建或团期起止不全时为 null |
| occupiedDays | Integer | 新增。服务日期段内被占天数(两端都算);occupancyStatus 为 null 时为 0 |
| freeRanges | String[] | 新增。可派日期段 yyyy-MM-dd~yyyy-MM-dd,升序;全程占用或 occupancyStatus 为 null 时为 [] |
| occupancies | Object[] | 新增。占用明细,按 startDate 升序;空闲或 occupancyStatus 为 null 时为 [] |
| occupancies[].sourceType | String | GROUP_BATCH 其他团期的人员配置 / ORDER 普通订单上定制师直派 |
| occupancies[].sourceId | String | GROUP_BATCH 为运营团期 ID,ORDER 为订单 ID |
| occupancies[].refNo | String | 团期号 / 订单号;源数据为空时为 null |
| occupancies[].title | String | 团期名称(为空时取产品名)/ 订单的产品名;都为空时为 null |
| occupancies[].statusName | String | 来源当前状态中文名,如「招募中」「待出行」 |
| occupancies[].staffRole / staffRoleName | String | 他在那边的角色及中文名(跨角色也计入占用) |
| occupancies[].startDate / endDate | String(yyyy-MM-dd) | 他在那边的服务起止:团期为他在那个团的有效服务日期(自定义日期先夹进那个团当前起止);订单为出发日到返回日(返回日为空按出发日当天) |
| occupancies[].overlapStartDate / overlapEndDate | String(yyyy-MM-dd) | 与本团服务日期段重叠的起止,两端都算 |
请求示例
GET /v3/admin/group-batch/2104455359768993795/staff
Authorization: Bearer <admin token>
无请求体。
响应示例
2026-09-28 测试服实测(班期 11-17 ~ 11-19;白云飞跟随团期,萨仁高娃自定义为 11-18 单日;金额按当前契约写成字符串):
{
"code": 200,
"message": "成功",
"data": [
{
"id": "2104455839127633921",
"staffId": 1007,
"staffRole": "LEADER",
"staffRoleName": "领队",
"staffName": "白云飞",
"staffPhone": "139****1007",
"avatarUrl": null,
"sortOrder": 1,
"remark": null,
"reporterRank": "NONE",
"reporterRankName": "非报账人",
"staffStatus": "ON_SHELF",
"liveInfoDegraded": false,
"serviceStartDate": "2026-11-17",
"serviceEndDate": "2026-11-19",
"serviceDateCustom": false,
"baseDailyWage": "800.00",
"occupancyStatus": "FREE",
"occupiedDays": 0,
"freeRanges": ["2026-11-17~2026-11-19"],
"occupancies": []
},
{
"id": "2104455839131828226",
"staffId": 1008,
"staffRole": "LEADER",
"staffRoleName": "领队",
"staffName": "萨仁高娃",
"staffPhone": "139****1008",
"avatarUrl": null,
"sortOrder": 2,
"remark": null,
"reporterRank": "NONE",
"reporterRankName": "非报账人",
"staffStatus": "ON_SHELF",
"liveInfoDegraded": false,
"serviceStartDate": "2026-11-18",
"serviceEndDate": "2026-11-18",
"serviceDateCustom": true,
"baseDailyWage": null,
"occupancyStatus": "FREE",
"occupiedDays": 0,
"freeRanges": ["2026-11-18~2026-11-18"],
"occupancies": []
}
],
"traceId": null,
"success": true
}
空数据 / 降级响应
- 未配置人员:
data: [](测试服未建团期的班期实测即为[])。 - 本团期未建或团期起止不全:每行
occupancyStatus=null、occupiedDays=0、freeRanges=[]、occupancies=[]。 - 资源服务不可用:姓名手机回落快照、
liveInfoDegraded=true(既有);本单新增的服务日期、日薪、占用字段照常返回,不依赖资源服务。
错误响应
判权未改动(group-batch:view)。
{
"code": 589507,
"message": "无操作权限(当前角色未授予团期权限,或该团期不在您名下)",
"data": null,
"success": false
}
业务边界
- 名册项不含等级、服务区域、擅长(这几列只在两个候选接口返回);名册要展示时从候选接口按
staffId取。 - 占用比对用的日期段 = 这个人在本团的有效服务日期,先夹进本团当前起止;展示的
serviceStartDate/serviceEndDate不夹。团期改期后旧的自定义日期越出团期时,名册照实显示越界日期,保存时会 582119。 - 占用来源口径见第六节;占用只提示不拦截。
3. 团期单人更换 PUT /v3/admin/group-batch/{productBatchId}/staff/{staffId}/replace
VO: BatchStaffReplaceReqVO → BatchStaffReplaceRespVO
使用场景
名册表格某一行点「更换」,从候选里选一个新人替换原人。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| productBatchId | Path | Long | 是 | 产品侧排期 ID | 同名册接口(既有) |
| staffId | Path | Long | 是 | 须在本团名册中 | 被换下的人(既有) |
| newStaffId | Body | Long | 是 | 上架、类型符合原配置位、不在本团、不等于 staffId |
换上的人(既有) |
出参 Result<BatchStaffReplaceRespVO>
| 字段 | 类型 | 说明 |
|---|---|---|
| productBatchId / groupBatchId | String | 回显 / 运营团期 ID(既有) |
| oldStaffId / newStaffId | Long | 被换下 / 换上的人员 ID(既有) |
| staffRole | String | 新人落库角色(既有) |
| reporterRank | String | 新人继承的报账人等级(既有) |
| primaryReporterTransferred | Boolean | 主报账人是否转给了新人(既有) |
| affectedOrderCount | Integer | 同步替换的活跃子订单数(既有) |
| staffList | Object[] | 更换后的整期名单(既有字段不变,staffStatus、liveInfoDegraded 为 null) |
| staffList[].serviceStartDate / serviceEndDate | String(yyyy-MM-dd) | 新增。有效服务起止;新人沿用原人的服务日期 |
| staffList[].serviceDateCustom | Boolean | 新增。是否自定义过服务日期 |
| staffList[].baseDailyWage | String | 新增。基础日薪快照(新人取新人档案值),字符串;0 或空为 null |
| staffList[].occupancyStatus | String | 新增。FREE / PARTIAL / FULL;本团期未建或团期起止不全时为 null |
| staffList[].occupiedDays | Integer | 新增。被占天数 |
| staffList[].freeRanges | String[] | 新增。可派日期段 yyyy-MM-dd~yyyy-MM-dd |
| staffList[].occupancies | Object[] | 新增。占用明细,按 startDate 升序 |
| staffList[].occupancies[].sourceType / sourceId | String | GROUP_BATCH + 运营团期 ID,或 ORDER + 订单 ID |
| staffList[].occupancies[].refNo / title / statusName | String | 团期号或订单号 / 团期名称或产品名 / 来源状态中文名 |
| staffList[].occupancies[].staffRole / staffRoleName | String | 他在那边的角色及中文名 |
| staffList[].occupancies[].startDate / endDate | String(yyyy-MM-dd) | 他在那边的服务起止 |
| staffList[].occupancies[].overlapStartDate / overlapEndDate | String(yyyy-MM-dd) | 与本团服务日期段重叠的起止 |
请求示例
PUT /v3/admin/group-batch/2104455374549721090/staff/1005/replace
Authorization: Bearer <admin token>
Content-Type: application/json
{ "newStaffId": 1007 }
响应示例
2026-09-28 测试服实测:原人刘大山(主报账人,服务日期 10-27 ~ 10-28,日薪 1000)换成白云飞(档案日薪 800)。等级、备注、服务日期随位置转给新人,日薪取新人档案:
{
"code": 200,
"message": "成功",
"data": {
"productBatchId": "2104455374549721090",
"groupBatchId": "2104455377657724930",
"oldStaffId": 1005,
"newStaffId": 1007,
"staffRole": "LEADER",
"reporterRank": "PRIMARY",
"primaryReporterTransferred": true,
"affectedOrderCount": 1,
"staffList": [
{
"id": "2104456292880023553",
"staffId": 1007,
"staffRole": "LEADER",
"staffRoleName": "领队",
"staffName": "白云飞",
"staffPhone": "139****1007",
"avatarUrl": null,
"sortOrder": 1,
"remark": "负责额尔古纳段",
"reporterRank": "PRIMARY",
"reporterRankName": "主报账人",
"staffStatus": null,
"liveInfoDegraded": null,
"serviceStartDate": "2026-10-27",
"serviceEndDate": "2026-10-28",
"serviceDateCustom": true,
"baseDailyWage": "800.00",
"occupancyStatus": "FREE",
"occupiedDays": 0,
"freeRanges": ["2026-10-27~2026-10-28"],
"occupancies": []
}
]
},
"traceId": null,
"success": true
}
空数据 / 降级响应
写接口,无空数据形态;任何校验失败都不写入。新人档案日薪为 0 或空时,新行 baseDailyWage 为 null。
错误响应
以下 582119 按源码文案模板拼出(示意,测试服未造「团期改期后旧日期越界再更换」的数据):
{
"code": 582119,
"message": "白云飞 的服务日期(2026-10-25 至 2026-10-28)不合法:开始日期不能晚于结束日期,且须在团期日期(2026-10-26 至 2026-10-28)之内",
"data": null,
"success": false
}
| code | 触发条件 |
|---|---|
582119 |
新增。原人的自定义服务日期已不在团期起止内(团期改期后没重新保存);文案里是新人的名字;不写入。先在保存弹窗把这个位置的日期改到团期内,再换人 |
100001 / 589508 / 589582 |
新旧相同 / 原人不在本团 / 新人已在本团(既有) |
582103 / 582118 / 582114 |
资源库取不到新人 / 新人已下架 / 新人类型不符合配置位(既有) |
589553 / 589598 |
未建团 / 团期已确认或已取消(既有) |
业务边界
- 服务日期跟位置走:新人原样沿用原人的服务日期(包括「跟随团期」)。
- 日薪跟人走:取新人服务人员档案的基础日薪(D1),不沿用原人的日薪。
- 排序、备注、报账人等级转给新人(既有)。
4. 团期单人删除 DELETE /v3/admin/group-batch/{productBatchId}/staff/{staffId}
VO: BatchStaffRemoveRespVO
使用场景
名册表格某一行点「删除」,只移除这一个人。本单只给响应的 staffList[] 加字段,删除行为不变。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| productBatchId | Path | Long | 是 | 产品侧排期 ID | 同名册接口(既有) |
| staffId | Path | Long | 是 | 须在本团名册中 | 要删除的人(既有) |
出参 Result<BatchStaffRemoveRespVO>
| 字段 | 类型 | 说明 |
|---|---|---|
| productBatchId / groupBatchId | String | 回显 / 运营团期 ID(既有) |
| removedStaffId | Long | 被删除的人员 ID(既有) |
| removedStaffRole | String | 被删除人员的角色(既有) |
| primaryReporterRemoved | Boolean | 删的是否是主报账人(既有) |
| affectedOrderCount | Integer | 同步删除副本的活跃子订单数(既有) |
| staffList | Object[] | 删除后的整期名单(既有字段不变,staffStatus、liveInfoDegraded 为 null) |
| staffList[].serviceStartDate / serviceEndDate | String(yyyy-MM-dd) | 新增。有效服务起止(没自定义 = 团期起止) |
| staffList[].serviceDateCustom | Boolean | 新增。是否自定义过服务日期 |
| staffList[].baseDailyWage | String | 新增。基础日薪快照,字符串;0 或空为 null |
| staffList[].occupancyStatus | String | 新增。FREE / PARTIAL / FULL;本团期未建或团期起止不全时为 null |
| staffList[].occupiedDays | Integer | 新增。被占天数 |
| staffList[].freeRanges | String[] | 新增。可派日期段 yyyy-MM-dd~yyyy-MM-dd |
| staffList[].occupancies | Object[] | 新增。占用明细,按 startDate 升序 |
| staffList[].occupancies[].sourceType / sourceId | String | GROUP_BATCH + 运营团期 ID,或 ORDER + 订单 ID |
| staffList[].occupancies[].refNo / title / statusName | String | 团期号或订单号 / 团期名称或产品名 / 来源状态中文名 |
| staffList[].occupancies[].staffRole / staffRoleName | String | 他在那边的角色及中文名 |
| staffList[].occupancies[].startDate / endDate | String(yyyy-MM-dd) | 他在那边的服务起止 |
| staffList[].occupancies[].overlapStartDate / overlapEndDate | String(yyyy-MM-dd) | 与本团服务日期段重叠的起止 |
请求示例
DELETE /v3/admin/group-batch/2104455356057034754/staff/1009
Authorization: Bearer <admin token>
无请求体。
响应示例
2026-09-28 测试服实测节选(班期 11-16 ~ 11-18;staffList 只保留两行;金额按当前契约写成字符串):
{
"code": 200,
"message": "成功",
"data": {
"productBatchId": "2104455356057034754",
"groupBatchId": "2104455358355509249",
"removedStaffId": 1009,
"removedStaffRole": "LEADER",
"primaryReporterRemoved": false,
"affectedOrderCount": 1,
"staffList": [
{
"id": "2104456120838062081",
"staffId": 1005,
"staffRole": "LEADER",
"staffRoleName": "领队",
"staffName": "刘大山",
"staffPhone": "138****1005",
"sortOrder": 1,
"remark": "负责草原段带队",
"reporterRank": "PRIMARY",
"reporterRankName": "主报账人",
"staffStatus": null,
"liveInfoDegraded": null,
"serviceStartDate": "2026-11-16",
"serviceEndDate": "2026-11-16",
"serviceDateCustom": true,
"baseDailyWage": "1000.00",
"occupancyStatus": "FREE",
"occupiedDays": 0,
"freeRanges": ["2026-11-16~2026-11-16"],
"occupancies": []
},
{
"id": "2104456120838062082",
"staffId": 1002,
"staffRole": "GUIDE",
"staffRoleName": "导游",
"staffName": "李雪梅",
"staffPhone": "138****1002",
"sortOrder": 2,
"remark": null,
"reporterRank": "NONE",
"reporterRankName": "非报账人",
"staffStatus": null,
"liveInfoDegraded": null,
"serviceStartDate": "2026-11-16",
"serviceEndDate": "2026-11-18",
"serviceDateCustom": false,
"baseDailyWage": "600.00",
"occupancyStatus": "PARTIAL",
"occupiedDays": 1,
"freeRanges": ["2026-11-16~2026-11-17"],
"occupancies": [
{
"sourceType": "GROUP_BATCH",
"sourceId": "2104455369311031298",
"refNo": "Q202611182104455365389361153",
"title": "11月18日海拉尔-额尔古纳3日团",
"statusName": "招募中",
"staffRole": "GUIDE",
"staffRoleName": "导游",
"startDate": "2026-11-18",
"endDate": "2026-11-20",
"overlapStartDate": "2026-11-18",
"overlapEndDate": "2026-11-18"
}
]
}
]
},
"traceId": null,
"success": true
}
空数据 / 降级响应
删光后 staffList 为 [](既有)。本团期未建或团期起止不全时,名单项占用四字段为 null / 0 / [] / []。
错误响应
错误码未改动。
{
"code": 589508,
"message": "报账人不是该团期已派员工",
"data": null,
"success": false
}
业务边界
- 删除行为、错误码与判权(
group-batch:manage)都未改,只是响应staffList[]多了字段。 - 删掉的人在其他团的占用计算里立即消失(已删除的配置行不算占用)。
5. 团期人员候选分页 GET /v3/admin/group-batch/{productBatchId}/staff/candidates/page
VO: PageResult<StaffCandidateRespVO>
使用场景
「配导游」「配摄影」选人弹窗的人员列表(带关键词搜索、分页)。本单起每行可展示等级、服务区域、擅长、基础日薪和占用标签,点占用标签看 occupancies 明细与 freeRanges。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| productBatchId | Path | Long | 是 | 产品侧排期 ID | 取 detail.productBatchId(既有) |
| role | Query | String | 是 | GUIDE / PHOTOGRAPHER |
配置位;导游位并收导游与领队(既有) |
| keyword | Query | String | 否 | ≤50 字 | 姓名包含;纯数字另按手机号尾号匹配(既有) |
| page | Query | Integer | 否 | 缺省 1 | 页码(既有) |
| pageSize | Query | Integer | 否 | 缺省 20,最大 100 | 每页条数(既有) |
出参 Result<PageResult<StaffCandidateRespVO>>
| 字段 | 类型 | 说明 |
|---|---|---|
| total / page / pageSize | Integer | 分页信息(既有) |
| records | Object[] | 候选项(既有字段 productBatchId、groupBatchId、staffId、staffName、staffPhone、staffType、staffTypeName、avatarUrl、assigned、assignedRole、assignedRoleName、reporterRank、reporterRankName 不变) |
| records[].level | String | 新增。导游等级:初级 / 中级 / 高级 / 特级,档案里认不出的写法原样返回;未填为 null |
| records[].serviceAreas | String[] | 新增。服务区域;未填为 [],恒非 null |
| records[].specialties | String[] | 新增。擅长;未填为 [],恒非 null |
| records[].baseDailyWage | String | 新增。服务人员档案的基础日薪,字符串如 "600.00",仅供参考;未填或为 0 时为 null;前端运算前 Number() |
| records[].occupancyStatus | String | 新增。FREE / PARTIAL / FULL,按本团出发日到结束日比对;本团期未建(groupBatchId 为 null)或团期起止不全时为 null |
| records[].occupiedDays | Integer | 新增。本团日期段内被占天数(两端都算);occupancyStatus 为 null 时为 0 |
| records[].freeRanges | String[] | 新增。可派日期段 yyyy-MM-dd~yyyy-MM-dd,升序;全程占用或 occupancyStatus 为 null 时为 [] |
| records[].occupancies | Object[] | 新增。占用明细,按 startDate 升序;空闲或 occupancyStatus 为 null 时为 [] |
| records[].occupancies[].sourceType | String | GROUP_BATCH 其他团期的人员配置 / ORDER 普通订单上定制师直派 |
| records[].occupancies[].sourceId | String | GROUP_BATCH 为运营团期 ID,ORDER 为订单 ID |
| records[].occupancies[].refNo | String | 团期号 / 订单号;源数据为空时为 null |
| records[].occupancies[].title | String | 团期名称(为空时取产品名)/ 订单的产品名;都为空时为 null |
| records[].occupancies[].statusName | String | 来源当前状态中文名,如「招募中」「待支付」 |
| records[].occupancies[].staffRole / staffRoleName | String | 他在那边的角色及中文名(跨角色也计入占用) |
| records[].occupancies[].startDate / endDate | String(yyyy-MM-dd) | 他在那边的服务起止:团期为他在那个团的有效服务日期(自定义日期先夹进那个团当前起止);订单为出发日到返回日(返回日为空按出发日当天) |
| records[].occupancies[].overlapStartDate / overlapEndDate | String(yyyy-MM-dd) | 与本团日期段重叠的起止,两端都算,恒在本团日期段内 |
请求示例
GET /v3/admin/group-batch/2104455359768993795/staff/candidates/page?role=GUIDE&page=1&pageSize=20
Authorization: Bearer <admin token>
无请求体。
响应示例
2026-09-28 测试服实测节选(班期 11-17 ~ 11-19,共 7 人,只保留三行:本团已选 → 空闲 → 部分占用;金额按当前契约写成字符串):
{
"code": 200,
"message": "成功",
"data": {
"records": [
{
"productBatchId": "2104455359768993795",
"groupBatchId": "2104455363380285441",
"staffId": 1007,
"staffName": "白云飞",
"staffPhone": "139****1007",
"staffType": "LEADER",
"staffTypeName": "领队",
"avatarUrl": null,
"assigned": true,
"assignedRole": "LEADER",
"assignedRoleName": "领队",
"reporterRank": "NONE",
"reporterRankName": "非报账人",
"level": null,
"serviceAreas": ["内蒙古", "新疆"],
"specialties": ["户外探险", "亲子活动", "草原穿越"],
"baseDailyWage": "800.00",
"occupancyStatus": "FREE",
"occupiedDays": 0,
"freeRanges": ["2026-11-17~2026-11-19"],
"occupancies": []
},
{
"productBatchId": "2104455359768993795",
"groupBatchId": "2104455363380285441",
"staffId": 1005,
"staffName": "刘大山",
"staffPhone": "138****1005",
"staffType": "LEADER",
"staffTypeName": "领队",
"avatarUrl": "https://hlgl-test.oss-cn-beijing.aliyuncs.com/test/material/2026/03/26/45d9abebc569ca7b7ab13cac212ca38a.png",
"assigned": false,
"assignedRole": null,
"assignedRoleName": null,
"reporterRank": null,
"reporterRankName": null,
"level": null,
"serviceAreas": ["内蒙古", "新疆", "青海", "甘肃", "西藏"],
"specialties": ["户外探险", "高原旅行", "沙漠旅行", "自驾越野"],
"baseDailyWage": "1000.00",
"occupancyStatus": "FREE",
"occupiedDays": 0,
"freeRanges": ["2026-11-17~2026-11-19"],
"occupancies": []
},
{
"productBatchId": "2104455359768993795",
"groupBatchId": "2104455363380285441",
"staffId": 1002,
"staffName": "李雪梅",
"staffPhone": "138****1002",
"staffType": "GUIDE",
"staffTypeName": "导游",
"avatarUrl": null,
"assigned": false,
"assignedRole": null,
"assignedRoleName": null,
"reporterRank": null,
"reporterRankName": null,
"level": "中级",
"serviceAreas": ["云南", "四川", "贵州"],
"specialties": ["民俗风情", "美食体验", "自然风光"],
"baseDailyWage": "600.00",
"occupancyStatus": "PARTIAL",
"occupiedDays": 2,
"freeRanges": ["2026-11-19~2026-11-19"],
"occupancies": [
{
"sourceType": "GROUP_BATCH",
"sourceId": "2104455358355509249",
"refNo": "Q202611162104455356057034753",
"title": "11月16日海拉尔-额尔古纳3日团",
"statusName": "招募中",
"staffRole": "GUIDE",
"staffRoleName": "导游",
"startDate": "2026-11-16",
"endDate": "2026-11-18",
"overlapStartDate": "2026-11-17",
"overlapEndDate": "2026-11-18"
}
]
}
],
"total": 7,
"page": 1,
"pageSize": 20
},
"traceId": null,
"success": true
}
空数据 / 降级响应
本团期还没建(班期有、团期无)时,groupBatchId 为 null,占用四字段为空值(测试服班期 11-26 实测节选):
{
"productBatchId": "2104455372507095042",
"groupBatchId": null,
"staffId": 1002,
"staffName": "李雪梅",
"level": "中级",
"baseDailyWage": "600.00",
"occupancyStatus": null,
"occupiedDays": 0,
"freeRanges": [],
"occupancies": []
}
- 页码越界:
records为[],total为真实总数(既有)。 - 资源服务不可用:返回 582103(见下)。
错误响应
{
"code": 582103,
"message": "员工信息查询失败,请稍后重试",
"data": null,
"success": false
}
| code | 触发条件 |
|---|---|
582103 |
资源服务查询候选失败(既有码,本单起候选分页经资源服务新的排序分页查询取数) |
582113 |
role 不是 GUIDE / PHOTOGRAPHER(既有) |
589507 |
无团期查看权限(既有) |
400 |
keyword 超 50 字(既有) |
业务边界
- 全局排序:本团本位已选(即
assigned=true)→ 空闲 → 部分占用 → 全程占用;同组内按等级从高到低(特级 → 高级 → 中级 → 初级 → 未填)→ 人员sortOrder升序 →staffId升序。先按同一筛选条件(类型、关键词)取全体候选排好再切页,逐页翻完不重不漏,与第 6 个接口的顺序一致。 - 本团期未建时没有占用分组,只有「本团本位已选」排最前,其余人按等级 →
sortOrder→staffId排(改前只按sortOrder、staffId)。 - 本团其他配置位上的人(例如在导游位看摄影师)不算占用(本团自己不算),
assigned=false,照常用assignedRole提示「已在其他位」。 - 占用只提示不拦截;本单不提供「只看空闲」筛选参数(D9)。
- 保存仍以
GET .../staff为已选名单来源,不能只凭当前页勾选拼保存请求(既有)。
6. 团期人员候选列表 GET /v3/admin/group-batch/{productBatchId}/staff/candidates
VO: List<StaffCandidateRespVO>
使用场景
旧的全量候选接口(不分页)。条目结构、占用口径、排序规则与候选分页完全一致。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| productBatchId | Path | Long | 是 | 产品侧排期 ID | 取 detail.productBatchId(既有) |
| role | Query | String | 是 | GUIDE / PHOTOGRAPHER |
配置位;导游位并收导游与领队(既有) |
出参 Result<List<StaffCandidateRespVO>>
| 字段 | 类型 | 说明 |
|---|---|---|
| 既有字段 | - | productBatchId、groupBatchId、staffId、staffName、staffPhone、staffType、staffTypeName、avatarUrl、assigned、assignedRole、assignedRoleName、reporterRank、reporterRankName 不变 |
| level | String | 新增。导游等级:初级 / 中级 / 高级 / 特级,认不出的写法原样返回;未填为 null |
| serviceAreas | String[] | 新增。服务区域;未填为 [] |
| specialties | String[] | 新增。擅长;未填为 [] |
| baseDailyWage | String | 新增。档案基础日薪,字符串,仅供参考;未填或为 0 时为 null |
| occupancyStatus | String | 新增。FREE / PARTIAL / FULL,按本团出发日到结束日比对;本团期未建或团期起止不全时为 null |
| occupiedDays | Integer | 新增。被占天数;occupancyStatus 为 null 时为 0 |
| freeRanges | String[] | 新增。可派日期段 yyyy-MM-dd~yyyy-MM-dd;全程占用或 null 状态时为 [] |
| occupancies | Object[] | 新增。占用明细,按 startDate 升序 |
| occupancies[].sourceType / sourceId | String | GROUP_BATCH + 运营团期 ID,或 ORDER + 订单 ID |
| occupancies[].refNo / title / statusName | String | 团期号或订单号 / 团期名称或产品名 / 来源状态中文名 |
| occupancies[].staffRole / staffRoleName | String | 他在那边的角色及中文名 |
| occupancies[].startDate / endDate | String(yyyy-MM-dd) | 他在那边的服务起止 |
| occupancies[].overlapStartDate / overlapEndDate | String(yyyy-MM-dd) | 与本团日期段重叠的起止 |
请求示例
GET /v3/admin/group-batch/2104455359768993795/staff/candidates?role=GUIDE
Authorization: Bearer <admin token>
无请求体。
响应示例
2026-09-28 测试服实测节选(班期 11-17 ~ 11-19;陈志远只有 11-18 被占,可派日期被切成两段;李雪梅被两个招募中的团占满整段):
{
"code": 200,
"message": "成功",
"data": [
{
"productBatchId": "2104455359768993795",
"groupBatchId": "2104455363380285441",
"staffId": 1009,
"staffName": "陈志远",
"staffPhone": "139****1009",
"staffType": "LEADER",
"staffTypeName": "领队",
"avatarUrl": null,
"assigned": false,
"assignedRole": null,
"assignedRoleName": null,
"reporterRank": null,
"reporterRankName": null,
"level": null,
"serviceAreas": ["内蒙古", "黑龙江", "吉林"],
"specialties": ["户外探险", "高原旅行", "冬季活动"],
"baseDailyWage": null,
"occupancyStatus": "PARTIAL",
"occupiedDays": 1,
"freeRanges": ["2026-11-17~2026-11-17", "2026-11-19~2026-11-19"],
"occupancies": [
{
"sourceType": "GROUP_BATCH",
"sourceId": "2104455358355509249",
"refNo": "Q202611162104455356057034753",
"title": "11月16日海拉尔-额尔古纳3日团",
"statusName": "招募中",
"staffRole": "LEADER",
"staffRoleName": "领队",
"startDate": "2026-11-18",
"endDate": "2026-11-18",
"overlapStartDate": "2026-11-18",
"overlapEndDate": "2026-11-18"
}
]
},
{
"productBatchId": "2104455359768993795",
"groupBatchId": "2104455363380285441",
"staffId": 1002,
"staffName": "李雪梅",
"staffPhone": "138****1002",
"staffType": "GUIDE",
"staffTypeName": "导游",
"avatarUrl": null,
"assigned": false,
"assignedRole": null,
"assignedRoleName": null,
"reporterRank": null,
"reporterRankName": null,
"level": "中级",
"serviceAreas": ["云南", "四川", "贵州"],
"specialties": ["民俗风情", "美食体验", "自然风光"],
"baseDailyWage": "600.00",
"occupancyStatus": "FULL",
"occupiedDays": 3,
"freeRanges": [],
"occupancies": [
{
"sourceType": "GROUP_BATCH",
"sourceId": "2104455358355509249",
"refNo": "Q202611162104455356057034753",
"title": "11月16日海拉尔-额尔古纳3日团",
"statusName": "招募中",
"staffRole": "GUIDE",
"staffRoleName": "导游",
"startDate": "2026-11-16",
"endDate": "2026-11-18",
"overlapStartDate": "2026-11-17",
"overlapEndDate": "2026-11-18"
},
{
"sourceType": "GROUP_BATCH",
"sourceId": "2104455369311031298",
"refNo": "Q202611182104455365389361153",
"title": "11月18日海拉尔-额尔古纳3日团",
"statusName": "招募中",
"staffRole": "GUIDE",
"staffRoleName": "导游",
"startDate": "2026-11-18",
"endDate": "2026-11-20",
"overlapStartDate": "2026-11-18",
"overlapEndDate": "2026-11-19"
}
]
}
],
"traceId": null,
"success": true
}
空数据 / 降级响应
- 资源库没有可用人员:
data: [](既有)。 - 本团期未建:
groupBatchId为 null,每人occupancyStatus=null、occupiedDays=0、freeRanges=[]、occupancies=[]。
错误响应
{
"code": 582113,
"message": "人员配置位不合法,请检查配置位标识",
"data": null,
"success": false
}
| code | 触发条件 |
|---|---|
582113 |
role 不是 GUIDE / PHOTOGRAPHER(既有) |
582103 |
资源服务查询候选失败(既有) |
589507 |
无团期查看权限(既有) |
业务边界
- 排序与候选分页同一规则:本团本位已选 → 空闲 → 部分占用 → 全程占用 → 等级从高到低 →
sortOrder升序 →staffId升序。 - 同一来源(同一个团期或同一张订单)即使有多行也只出一条明细;
occupiedDays按实际被占的日子算,重叠部分只算一次。 - 占用只提示不拦截。
7. 配导游芯片明细 GET /v3/admin/order/group-batch/{groupBatchId}/chips/guide
VO: GroupBatchChipDetailVO
使用场景
团期详情「配导游」页签、看板点导游芯片弹出的明细。本单起只看团期名册 staffList,不再有逐户人员表。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| groupBatchId | Path | Long | 是 | 运营团期 ID | 路由上的团期 ID(既有) |
出参 Result<GroupBatchChipDetailVO>
| 字段 | 类型 | 说明 |
|---|---|---|
| batchId / groupBatchId | String | 团期 ID(batchId 已废弃,同值;既有) |
| chipLabel | String | 芯片中文名(既有) |
| aggregateStatus / aggregateStatusName | String | 整团聚合态及中文名(既有,口径不变,仍按户计) |
| totalCount / doneCount | Integer | 计入统计的户数 / 已完成户数(既有,口径不变) |
| staffList | Object[] | 本团导游位(导游 + 领队)已配置人员(既有,内容不变);元素字段 staffId、staffRole、staffRoleName、staffName、staffPhone、reporterRank、reporterRankName、source、sourceName |
| items | Object[] | 取值变化:恒为 [],不再逐户返回(改前每户一行并带 items[].staffs) |
请求示例
GET /v3/admin/order/group-batch/2104455358355509249/chips/guide
Authorization: Bearer <admin token>
无请求体。
响应示例
2026-09-28 测试服实测:
{
"code": 200,
"message": "成功",
"data": {
"batchId": "2104455358355509249",
"groupBatchId": "2104455358355509249",
"chipLabel": "配导游",
"aggregateStatus": "TODO",
"aggregateStatusName": "待开始",
"totalCount": 0,
"doneCount": 0,
"staffList": [
{
"staffId": "1005",
"staffRole": "LEADER",
"staffRoleName": "领队",
"staffName": "刘大山",
"staffPhone": "138****1005",
"reporterRank": "PRIMARY",
"reporterRankName": "主报账人",
"source": null,
"sourceName": null
},
{
"staffId": "1002",
"staffRole": "GUIDE",
"staffRoleName": "导游",
"staffName": "李雪梅",
"staffPhone": "138****1002",
"reporterRank": "NONE",
"reporterRankName": "非报账人",
"source": null,
"sourceName": null
}
],
"items": []
},
"traceId": null,
"success": true
}
空数据 / 降级响应
未配置导游位人员时 staffList: []、items: [](改前 items 会列出每户,本单起恒为 [])。
错误响应
错误码未改动。
{
"code": 589500,
"message": "团期不存在",
"data": null,
"success": false
}
业务边界
- 判权未改(
group-batch:view,无权限 589507)。 staffList不带服务日期、日薪、占用;需要这些时调GET /v3/admin/group-batch/{productBatchId}/staff。- 芯片聚合态(
aggregateStatus、totalCount、doneCount)仍按户计算,本单不改;改按团期名册计算的口径见 #8469。 - 配房、配车、合同、保险四个芯片完全不变。
8. 配摄影芯片明细 GET /v3/admin/order/group-batch/{groupBatchId}/chips/photo
VO: GroupBatchChipDetailVO
使用场景
团期详情「配摄影」页签、看板点摄影芯片弹出的明细。本单起只看团期名册 staffList,不再有逐户人员表。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| groupBatchId | Path | Long | 是 | 运营团期 ID | 路由上的团期 ID(既有) |
出参 Result<GroupBatchChipDetailVO>
| 字段 | 类型 | 说明 |
|---|---|---|
| batchId / groupBatchId | String | 团期 ID(batchId 已废弃,同值;既有) |
| chipLabel | String | 芯片中文名(既有) |
| aggregateStatus / aggregateStatusName | String | 整团聚合态及中文名(既有,口径不变,仍按户计) |
| totalCount / doneCount | Integer | 计入统计的户数 / 已完成户数(既有,口径不变) |
| staffList | Object[] | 本团摄影位已配置人员(既有,内容不变);元素字段 staffId、staffRole、staffRoleName、staffName、staffPhone、reporterRank、reporterRankName、source、sourceName |
| items | Object[] | 取值变化:恒为 [],不再逐户返回(改前每户一行并带 items[].staffs) |
请求示例
GET /v3/admin/order/group-batch/2104455358355509249/chips/photo
Authorization: Bearer <admin token>
无请求体。
响应示例
2026-09-28 测试服实测:
{
"code": 200,
"message": "成功",
"data": {
"batchId": "2104455358355509249",
"groupBatchId": "2104455358355509249",
"chipLabel": "配摄影",
"aggregateStatus": "TODO",
"aggregateStatusName": "待开始",
"totalCount": 0,
"doneCount": 0,
"staffList": [
{
"staffId": "1003",
"staffRole": "PHOTOGRAPHER",
"staffRoleName": "摄影",
"staffName": "王强",
"staffPhone": "138****1003",
"reporterRank": "NONE",
"reporterRankName": "非报账人",
"source": null,
"sourceName": null
}
],
"items": []
},
"traceId": null,
"success": true
}
空数据 / 降级响应
未配置摄影位人员时 staffList: []、items: [](改前 items 会列出每户,本单起恒为 [])。
错误响应
错误码未改动。
{
"code": 589507,
"message": "无操作权限(当前角色未授予团期权限,或该团期不在您名下)",
"data": null,
"success": false
}
业务边界
- 判权未改(
group-batch:view);团期不存在 589500(既有)。 staffList不带服务日期、日薪、占用;需要这些时调GET /v3/admin/group-batch/{productBatchId}/staff。- 芯片聚合态仍按户计算,本单不改;改按团期名册计算的口径见 #8469。
9. 新建服务人员 POST /admin/staff
VO: StaffCreateRequest → StaffVO
使用场景
服务人员管理「新建」弹窗保存。本单起「基础日薪」输入框的值会保存(改前填了不保存)。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| name | Body | String | 是 | ≤100 字 | 姓名(既有) |
| staffType | Body | String | 是 | 人员类型字典 | 人员类型(既有) |
| basePrice | Body | Number | 否 | ≥0;最多 8 位整数、2 位小数 | 新增。基础日薪(元/天);不传按 0 保存(= 没填) |
其余字段与改前一致。
出参 Result<StaffVO>
| 字段 | 类型 | 说明 |
|---|---|---|
| basePrice | String | 新增。基础日薪,按库值原样返回的字符串,如 "650.00";没填为 "0.00"(不是 null)。回填数字输入框用 Number(basePrice) |
| 其余字段 | - | 与改前一致 |
请求示例
{
"name": "孟和巴雅尔",
"staffType": "LEADER",
"gender": 1,
"serviceAreas": ["内蒙古"],
"specialties": ["草原穿越"],
"basePrice": 650,
"description": "熟悉呼伦贝尔草原线路,常带亲子团"
}
响应示例
2026-09-28 测试服实测节选(验收后已软删;金额按当前契约写成字符串):
{
"code": 200,
"message": "成功",
"data": {
"staffId": "2104454928988823553",
"name": "孟和巴雅尔",
"staffType": "LEADER",
"specialties": ["草原穿越"],
"serviceAreas": ["内蒙古"],
"basePrice": "650.00",
"sortOrder": 0,
"status": 0
},
"traceId": null,
"success": true
}
空数据 / 降级响应
写接口,无空数据形态。不传 basePrice 时按 0 保存,详情与列表返回 "0.00"。
错误响应
与编辑接口同一组校验(测试服在编辑接口实测):
{
"code": 400,
"message": "基础日薪不能为负数",
"data": null,
"traceId": null,
"success": false
}
| code | 触发条件 |
|---|---|
400 |
basePrice 为负数(「基础日薪不能为负数」);超过 8 位整数或 2 位小数(「基础日薪最多8位整数、2位小数」) |
业务边界
- 判权与审批上架流程未改。
- 校验失败不写入。
- 团期选人时取的就是这里保存的基础日薪(0 视为没填,团期侧显示 null)。
10. 编辑服务人员 PUT /admin/staff/{staffId}
VO: StaffUpdateRequest → StaffVO
使用场景
服务人员管理「编辑」弹窗保存。弹窗打开时用详情接口回显 Number(basePrice),保存时把数值传回。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| staffId | Path | Long | 是 | - | 人员 ID(既有) |
| basePrice | Body | Number | 否 | ≥0;最多 8 位整数、2 位小数 | 新增。基础日薪(元/天);不传不改原值;传 0 = 清成没填 |
其余字段与改前一致(均为不传不改)。
出参 Result<StaffVO>
| 字段 | 类型 | 说明 |
|---|---|---|
| basePrice | String | 新增。保存后的基础日薪字符串,如 "800.00";没填为 "0.00" |
| 其余字段 | - | 与改前一致 |
请求示例
{ "basePrice": 800 }
响应示例
2026-09-28 测试服实测节选(金额按当前契约写成字符串):
{
"code": 200,
"message": "成功",
"data": {
"staffId": "1007",
"name": "白云飞",
"phone": "139****1007",
"staffType": "LEADER",
"basePrice": "800.00",
"sortOrder": 90,
"status": 1
},
"traceId": null,
"success": true
}
空数据 / 降级响应
写接口,无空数据形态。请求不带 basePrice(如 { "sortOrder": 90 })时原值不变,测试服实测保持 800。
错误响应
测试服实测:
{
"code": 400,
"message": "基础日薪最多8位整数、2位小数",
"data": null,
"traceId": null,
"success": false
}
| code | 触发条件 |
|---|---|
400 |
basePrice=-1 →「基础日薪不能为负数」;basePrice=12.345 →「基础日薪最多8位整数、2位小数」;均不写入 |
业务边界
- 不传不改:只提交部分字段的调用方不会把日薪清掉。
- 改了档案日薪后,已经选进团期的人日薪快照不刷新;之后新选、或更换进来的人才取新值(D1)。
- 判权未改。
11. 服务人员详情 GET /admin/staff/{staffId}
VO: StaffVO
使用场景
服务人员详情页、编辑弹窗回显。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| staffId | Path | Long | 是 | - | 人员 ID(既有) |
出参 Result<StaffVO>
| 字段 | 类型 | 说明 |
|---|---|---|
| basePrice | String | 新增。基础日薪字符串,按库值原样返回,如 "600.00";没填为 "0.00"(不是 null) |
| 其余字段 | - | 与改前一致 |
请求示例
GET /admin/staff/1007
Authorization: Bearer <admin token>
无请求体。
响应示例
测试服实测节选(1007 验收后已恢复为没填;金额为字符串):
{
"code": 200,
"message": "成功",
"data": {
"staffId": "1007",
"name": "白云飞",
"phone": "139****1007",
"staffType": "LEADER",
"guideLevel": null,
"serviceAreas": ["内蒙古", "新疆"],
"specialties": ["户外探险", "亲子活动", "草原穿越"],
"basePrice": "0.00",
"sortOrder": 90,
"status": 1
},
"traceId": null,
"success": true
}
空数据 / 降级响应
没填日薪的人 basePrice 为 "0.00",前端按「未填」展示即可。
错误响应
错误码未改动(人员不存在时 HTTP 200 + 业务码 404):
{
"code": 404,
"message": "服务人员不存在",
"data": null,
"success": false
}
业务边界
- 详情返回库里的原值(0 就是
"0.00");团期侧把 0 视为没填、返回 null,两处口径不同是有意的。 - 判权未改。
12. 服务人员列表 GET /admin/staff/list
VO: PageResult<StaffAdminListVO>
使用场景
服务人员管理列表页。本单起每条记录带 basePrice,列表可恢复「基础日薪」列。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| keyword | Query | String | 否 | - | 姓名 / 描述模糊匹配(既有) |
| staffType | Query | String | 否 | - | 人员类型筛选(既有) |
| status | Query | Integer | 否 | 0 / 1 | 下架 / 上架(既有) |
| page | Query | Integer | 否 | ≥1,缺省 1 | 页码(既有) |
| pageSize | Query | Integer | 否 | 1~100,缺省 20 | 每页条数(既有) |
出参 Result<PageResult<StaffAdminListVO>>
| 字段 | 类型 | 说明 |
|---|---|---|
| records[].basePrice | String | 新增。基础日薪字符串,按库值原样返回,如 "1000.00";没填为 "0.00" |
| records[] 其余字段 | - | 与改前一致 |
请求示例
GET /admin/staff/list?staffType=LEADER&page=1&pageSize=20
Authorization: Bearer <admin token>
无请求体。
响应示例
2026-09-28 测试服实测节选:
{
"code": 200,
"message": "成功",
"data": {
"records": [
{
"staffId": "1005",
"name": "刘大山",
"staffType": "LEADER",
"phone": "138****1005",
"basePrice": "1000.00",
"sortOrder": 95,
"status": 1,
"supplierFullName": "陈巴尔虎旗天下草原旅游服务有限"
},
{
"staffId": "1007",
"name": "白云飞",
"staffType": "LEADER",
"phone": "139****1007",
"basePrice": "0.00",
"sortOrder": 90,
"status": 1
}
]
},
"traceId": null,
"success": true
}
空数据 / 降级响应
无匹配记录时 records: [](既有)。没填日薪的人 basePrice 为 "0.00"。
错误响应
参数校验错误码未改动:
{
"code": 400,
"message": "页码不能小于1",
"data": null,
"success": false
}
业务边界
- 列表排序、筛选、判权都未改,只多了
basePrice。 basePrice是字符串,排序或求和前先Number()。
四、契约约束与正确调用方式
✅ 正确 / ❌ 错误 payload 对照(保存团期人员配置)
| 场景 | payload(staffList[] 单项) |
结果 |
|---|---|---|
| ✅ 前端现有写法,保留的人只传三项 | { "staffId": 1005, "staffRole": "LEADER", "sortOrder": 1 } |
沿用原报账人等级、备注、服务日期、日薪 |
| ✅ 自定义服务日期 | { "staffId": 1008, "staffRole": "LEADER", "sortOrder": 2, "serviceStartDate": "2026-11-18", "serviceEndDate": "2026-11-18" } |
落为自定义,serviceDateCustom=true |
| ✅ 改回跟随团期 | 传团期起止本身,如团期 11-17 ~ 11-19 时 "serviceStartDate": "2026-11-17", "serviceEndDate": "2026-11-19" |
按跟随团期处理,serviceDateCustom=false |
| ✅ 清空备注 | { ..., "remark": "" } |
备注清空 |
| ⚠️ 想清空备注却传 null 或不传 | { ..., "remark": null } |
保留下来的人沿用原备注(不会清空) |
| ⚠️ 想改回跟随团期却不传日期 | { "staffId": 1008, "staffRole": "LEADER" } |
保留下来的人沿用原自定义日期 |
| ❌ 开始晚于结束 | "serviceStartDate": "2026-11-19", "serviceEndDate": "2026-11-18" |
582119,整批不写入 |
| ❌ 越出团期 | 团期 11-17 ~ 11-19 时 "serviceStartDate": "2026-11-16" |
582119,整批不写入 |
| ➖ 带日薪 | { ..., "baseDailyWage": 9999 } |
不报错,但被忽略;日薪取档案值 |
金额字段
baseDailyWage(团期名册、候选)与basePrice(服务人员管理详情、列表、新建与编辑响应)都是 JSON 字符串,如"600.00"。展示可直接用;运算、比较、回填数字输入框前Number()。- 团期侧
baseDailyWage为 null 表示「档案没填日薪」;服务人员管理侧basePrice为"0.00"表示同一件事。 - 服务人员新建 / 编辑的请求体里
basePrice传数字即可(如800)。
前端交接清单
- 选人弹窗(候选分页 / 候选列表):每行展示等级
level、服务区域serviceAreas、擅长specialties、基础日薪baseDailyWage(标「参考」),以及占用标签(FREE空闲 /PARTIAL部分占用 /FULL全程占用)和被占天数occupiedDays;occupancyStatus为 null(团期未建)时不显示占用标签。列表顺序直接用接口顺序,不要在前端重排。 - 占用明细弹层:点占用标签弹出
occupancies[](来源类型sourceType、团期号或订单号refNo、名称title、状态statusName、角色staffRoleName、他那边的服务起止startDateendDate、与本团重叠的起止overlapStartDateoverlapEndDate)和可派日期段freeRanges。 - 保存弹窗:每个人可编辑服务开始 / 结束日期(不填 = 跟随团期),基础日薪只读展示。回显用名册的
serviceStartDate/serviceEndDate/serviceDateCustom;把自定义日期改回跟随团期时提交团期起止本身(不传会沿用原值);收到 582119 直接展示接口文案(带人名)。有占用不需要二次确认(D5)。 - 已配置人员名册:可加服务日期、基础日薪、占用标签三列(字段见接口 2)。
- 服务人员管理:编辑框回显用
Number(row.basePrice)(出参是字符串);列表恢复「基础日薪」列,"0.00"按未填展示。 - 团期详情导游 / 摄影页签、看板导 / 摄芯片弹层:去掉逐户人员表(
items恒为[])及其「共 N 户计入」汇总行,只展示团期名册staffList。 - 本单不做:「只看空闲」筛选(D9);导 / 摄芯片状态颜色口径另见 #8469,本单不改。
服务间内部接口(前端不可调)
资源服务的 /internal/staff/... 系列接口也随本单加了字段,并新增 POST /internal/staff/page-available(候选分页的全局排序由它完成)。这些接口不经网关,前端无需关注;候选分页在资源服务不可用时返回 582103。
五、数据库行为
| 前端动作 | 可观察到的存储结果 |
|---|---|
| 保存时服务日期不传 / 与团期起止相同 | 按「跟随团期」存,名册返回团期起止,serviceDateCustom=false,团期改期后跟着变 |
| 保存时服务日期自定义 | 原样保存,serviceDateCustom=true,团期改期后不变 |
| 保存 / 更换选人 | 基础日薪快照在选人那一刻从服务人员档案带出并保存;档案之后再改,快照不变 |
| 保存返回 582119 | 整批不写入,名册前后一致(测试服前后比对) |
服务人员新建 / 编辑带 basePrice |
档案基础日薪保存;编辑不传不改;新建不传为 0 |
- 存量团期人员配置:服务日期全部视为「跟随团期」,基础日薪快照为 null;下次保存这些人时会补取一次档案当前日薪。
- 查询接口只读。
六、边界行为
- 占用来源(D3 / D7):
- 计入:其他团期里这个人的有效配置(含招募中团期;在那个团当任何角色都算);普通订单(不属于任何团期)上定制师直接派的人(未取消的订单,任何订单状态都算)。
- 不计:本团自己;已取消的团期(含流团);出发日或结束日为空的团期;已删除的配置;团期同步到子订单的人员副本;车务派车的司机;已取消的订单;没有出发日的订单。
- 日期段:候选接口用本团出发日到结束日;名册(及保存、更换、删除响应)用这个人在本团的有效服务日期,先夹进本团当前起止。其他团的自定义服务日期同样先夹进那个团当前起止,完全越界时按那个团整段算。订单用出发日到返回日,返回日为空按出发日一天。
- 两端都算(D4):首尾相接那一天算占用。测试服实测:本团 11-18 ~ 11-20,另一团 11-16 ~ 11-18,重叠 1 天(11-18)。
- 三档(D8):被占 0 天 →
FREE;被占满整段 →FULL;其余 →PARTIAL。守恒:FREE⇔occupiedDays=0⇔occupancies为空;FULL⇔freeRanges为空;occupiedDays+ 可派天数 = 日期段天数。 - 多段:多条占用重叠部分只算一次;被占日子在中间时可派日期切成两段。
- 只提示不拦截(D5):有占用照样能保存。
- 未建团期:候选能查、团期还没有是正常态,占用四字段为
null/0/[]/[]。 - 未登录:网关拦截返回 401(既有)。
- 向后兼容:团期侧全部为新增字段,旧前端不读也不报错;例外见六.6 的
items与remark两处行为变化。
六.5、枚举 / 数据字典
occupancyStatus(常量定义于 com.hulalv.order.assignment.helper.StaffOccupancyCalculator)
所属字段: BatchStaffItemVO.occupancyStatus、StaffCandidateRespVO.occupancyStatus | 类型: String
| 值 | 中文 | 说明 |
|---|---|---|
FREE |
空闲 | 日期段内被占 0 天 |
PARTIAL |
部分占用 | 被占天数大于 0 且小于日期段天数 |
FULL |
全程占用 | 日期段每一天都被占 |
null |
- | 本团期未建或团期起止不全,算不出 |
occupancies[].sourceType(常量定义于 com.hulalv.order.assignment.helper.StaffOccupancyCalculator)
所属字段: StaffOccupancyItemVO.sourceType | 类型: String
| 值 | 中文 | 说明 |
|---|---|---|
GROUP_BATCH |
团期 | 其他团期的人员配置;sourceId 为运营团期 ID,refNo 为团期号 |
ORDER |
订单 | 普通订单上定制师直派;sourceId 为订单 ID,refNo 为订单号 |
level(com.hulalv.resource.staff.constant.StaffGuideLevel)
所属字段: StaffCandidateRespVO.level | 类型: String
| 值 | 中文 | 说明 |
|---|---|---|
特级 |
特级 | 排序最高 |
高级 |
高级 | - |
中级 |
中级 | - |
初级 |
初级 | 已知等级中排最后 |
| 其他原样值 / null | - | 档案写法认不出时原样返回;未填为 null;都排在已知等级之后 |
occupancies[].statusName
所属字段: StaffOccupancyItemVO.statusName | 类型: String(中文名,不是编码)
| 值 | 中文 | 说明 |
|---|---|---|
| 团期来源 | 招募中 / 资源准备中 / 物料准备中 / 待出发 / 出行中 / 出行完毕 / 核单中 / 已结算 | 团期当前状态(已取消的团期不计入,不会出现) |
| 订单来源 | 待支付 / 定制中 / 待出行 / 出行中 / 已完成 | 订单当前状态(已取消的订单不计入,不会出现) |
六.6、修改前后对比
字段级对比
| 字段 | 改前 | 改后 |
|---|---|---|
| 名册 / 保存 / 更换 / 删除响应的人员项 | 无服务日期、日薪、占用 | 新增 serviceStartDate、serviceEndDate、serviceDateCustom、baseDailyWage、occupancyStatus、occupiedDays、freeRanges、occupancies |
保存请求 staffList[] |
无日期字段 | 新增可选 serviceStartDate、serviceEndDate |
| 候选项 | 只有姓名、手机、类型等 | 新增 level、serviceAreas、specialties、baseDailyWage 与四个占用字段 |
导 / 摄芯片 items |
每户一行,带 items[].staffs |
恒为 [] |
服务人员 basePrice |
请求传了不保存,响应不返回 | 可保存;详情、列表、新建与编辑响应返回字符串 |
行为级对比
| 行为 | 改前 | 改后 |
|---|---|---|
| 保存导游位(前端只传三项) | 主报账人被打回非报账人、备注被清空 | 沿用原等级、备注、服务日期、日薪 |
保存时 remark 不传 |
清空备注 | 保留下来的人沿用原备注;要清空传 "" |
| 候选排序 | 资源库原顺序(sortOrder、staffId) |
本团本位已选 → 空闲 → 部分占用 → 全程占用 → 等级 → sortOrder → staffId |
| 服务日期不合法 | 无此校验 | 582119,整批不写入 |
| 更换人员 | 新人不带服务日期、日薪 | 新人沿用原人服务日期,日薪取新人档案 |
| 导 / 摄页签逐户表 | 每户显示分到的人 | 不再提供,只看团期名册 |
六.7、影响评估
- 是否破坏向后兼容: 部分。团期侧与服务人员管理都是新增字段;有两处行为变化:①导 / 摄芯片
items恒为[],旧页面的逐户人员表会变空;②保存时remark不传不再清空备注。候选顺序也变了(接口顺序即展示顺序)。 - 前端是否必须同步上线: 否。新字段不读不会报错;逐户表变空只影响展示,按交接清单第 6 项去掉即可。
- 前端 workaround 清理点: 如果前端为规避「保存后主报账人丢失」在保存后补调过设置报账人接口,可以删掉;导 / 摄页签里按
items[].staffs渲染的「人员」列与「共 N 户计入」汇总行可以删掉。
七、不影响范围
- 仅影响: 团期人员配置的保存 / 名册 / 更换 / 删除 / 两个候选接口,导 / 摄两个芯片明细,服务人员管理新建 / 编辑 / 详情 / 列表。
- 零影响:
- 设置报账人等级
PUT /v3/admin/group-batch/{productBatchId}/staff/{staffId}/reporter-rank - 配房、配车、合同、保险四个芯片明细与看板聚合
- 订单侧人员接口(
/v3/admin/order/{orderId}/staff)与团期同步到子订单的人员副本 - 出团通知书里的人员默认值
- 核团费用(本单不用「日薪 × 服务天数」预填)
- 服务人员价格日历
- 设置报账人等级
八、测试环境已验证
- 环境:TEST,
hl-resource-service与hl-order-service-v3均为 dev-v3623c932bd(含bf65803b7与623c932bd两次合入;resource 14:28、order-v3 14:31 双实例滚动完成,先 resource 后 order-v3)。 - 方式:经网关
https://api.test.1814.love,真实 admin token;每批取证前做构建身份探针(候选响应含occupancyStatus等新键),5 次全部命中。手机号均为接口脱敏值。 - 造数:五个班期(A 11-16、B 11-17、C 11-18、D 11-26 未建团期、E 10-26)与两张普通订单;验收后配置清空、团期流团、订单取消,新建人员已软删,1007 基础日薪已恢复为 0。
| AC | 检验点 | 结果 | 证据 |
|---|---|---|---|
| 1 | basePrice 编辑 800 后详情 / 列表都为 800;再次编辑不带 basePrice 仍 800;-1、12.345 返回 400 且库值不变;新建带 650 → 650 |
✅ | 会话证据 accept/AC-1.json |
| 3 | 候选带等级、服务区域、擅长、日薪;档案为 0 返回 null,1005 为 1000 | ✅ | accept/AC-3.json |
| 6 | 新选 1007 日薪 800、1008 为 null;请求夹 baseDailyWage=9999 不生效;档案改回 0 后再保存,已有 800 快照不刷新 |
✅ | accept/AC-6.json |
| 7 | 1005 设为主报账人、备注「负责草原段带队」,用前端现有请求体(只含 staffId/staffRole/sortOrder)重存导游位:仍为主报账人,备注、日薪、1009 的自定义日期都保留 |
✅ | accept/AC-7.json |
| 8 | 不传存为跟随团期且名册返回团期起止、serviceDateCustom=false;与团期起止相同同样跟随;自定义 → true;开始晚于结束 / 早于团期 / 晚于团期 → 582119,文案含「萨仁高娃」,名册前后一致 |
✅ | accept/AC-8.json |
| 9 | E 团 1005 → 1007:沿用 10-27 ~ 10-28,日薪 800,等级与备注随之转移 | ✅ | accept/AC-9.json |
| 10 | 产品侧把 C 改期到 11-19 后,团期变为 11-19 ~ 11-21,1002 名册日期随之变化 | ✅ | accept/AC-10.json |
| 11 | 名册与两个候选接口字段齐全,占用明细 11 个字段齐全;未建团期的班期 D 候选占用为 null / 0 / [] / [] | ✅ | accept/AC-11.json |
| 12 | 重叠 2 天、首尾相接 1 天、招募中算、本团不算、缩短日期后不算、删除后不算、流团后不算、多段合并、中间切两段、普通订单直派算、取消订单后不算、跨角色(订单上当摄影)算、团期副本不重复算 | ✅ | accept/AC-12.json |
| 13 | E 团派已被普通订单占用的 1005,保存成功,名册显示部分占用 | ✅ | accept/AC-13.json |
| 15 | A / B / C / E 四团每页 2 条翻完:本团已选 → 空闲 → 部分 → 全程 → 等级 → sortOrder,与全量接口一致,total 不变 |
✅ | accept/AC-15.json |
| 16 | A 团导游 / 摄影芯片 items=[]、staffList 有人;配房、配车芯片照常逐户返回 |
✅ | accept/AC-16.json |
| 18 | #8476 合入后复验:候选 baseDailyWage 为 "600.00" / "1000.00";人员详情与列表 basePrice 为 "600.00" / "0.00"(字符串) |
✅ | accept/AC-18-wage-string.json |
说明:本文各响应示例取自 AC-6 ~ AC-16 的实测响应(取证时金额字段仍为数字),示例里的金额已按 AC-18 复验过的字符串形态书写,其余字段为原值。「司机行不算」在测试服造不出司机来源数据,由真库单测覆盖。
九、相关历史 PR
| PR | Issue | 说明 | 是否仍有效 |
|---|---|---|---|
| #7831 | #7827 | 团期人员候选分页与模糊搜索 | ✅ 有效(本单改了排序与条目字段) |
| #7856 | #7853 | 导 / 摄芯片带出 staffList 与逐户 items[].staffs |
⚠️ staffList 有效;逐户人员已被本单撤掉 |
| #8357 | #8354 | 名册实时姓名手机、单人删除 / 更换 | ✅ 有效(本单给响应加字段、更换沿用服务日期) |
| #8475 | #8468 | 本单主体 | ✅ 最新 |
| #8476 | #8468 | 金额字段改字符串输出 | ✅ 最新 |
十、相关文档
- 工单 #8468: wx/HL#8468
- 导 / 摄芯片状态改按团期名册计算:wx/HL#8469
- 团期人员配置二期改表:wx/HL#8258
关联 / 联系人
链接
联系人
- 后端负责人: @jw