Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
20 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 | 8752 | 团期管理员一键催办未提交房 / 车需求的定制师:新增 POST requirement/nudge,按定制师每人一条站内信 + 企微,无定制师的户列为跳过 | admin | jw(GIT) | 新增接口 | deployed | verified | implemented | mmg | e4cd749bd0afe7388218fe5a538b54cf62269b4f | v2.1 | 2026-10-04 | 新增 POST /v3/admin/order/group-batch/{groupBatchId}/requirement/nudge(权限码 group-batch:manage:团期管理员 / ADMIN / SUPER_ADMIN,定制师 589507)。圈本团「该定制师动手」的户(与定制师待办同源:资源准备中、房 / 车需求未提交或被打回定制师),按定制师聚合每人一条通知(管理端站内信 + 企微,站内信点开到「定制师待办」/order/todos),只投员工不触达客户;无定制师的户在 skipped 里列出。同团 300 秒冷却(589852 带剩余秒数),一条都没发出时不占冷却。已合并 dev-v3(5b204b9d2)并部署 TEST(user-service、order-v3),经网关真实鉴权验收 AC-1~AC-10 通过,工单 #8752 已关。前端待做:团期详情需求 Tab「企微催需求」按钮、看板铃铛接本接口;成功后按 recipients / skipped 提示,wecomBound=false 的定制师提示「未绑企微,只收到站内信」,按钮按 cooldownSeconds 置灰倒计时。前端已交付(2026-10-04):需求 Tab 头「企微催需求」按钮 + 出团管理期行铃铛双挂载点,阶段驱动显隐(招募中置灰/资源准备中可点/之后不展示),结果 dialog 按 recipients/skipped/wecomBound 组文案(null 不提示未绑),冷却按响应 cooldownSeconds 与 589852 报文抠秒双路倒计时,提交 e4cd749bd。 | 2026-10-03 | dev-v3 |
团期催办:新增一键催办定制师提交房 / 车需求(管理后台)
服务: hl-order-service-v3(端口 8086/8186)+ hl-user-service(通知配置迁移) PR: #8777 Issue: #8752 日期: 2026-10-03 影响范围: 管理后台团期详情「需求」Tab 的「企微催需求」按钮、团期看板铃铛(原型
batchDetail.jsx:889/batchBoard.jsx:495);既有接口零变化
⚠️ 关键变化
- 新增写端点
POST .../{groupBatchId}/requirement/nudge:团期管理员一键催本团所有「房型 / 用车需求未提交或被打回」户的定制师。此前前端写明「企微催需求无接口契约,不做」,底栏「去催需求」只跳需求 Tab;现在有接口了。 - 一位定制师一条:同一定制师名下多户合成一条通知,正文分列房型、用车待提交户数并列出订单号(最多 10 个,多的写「等 N 户」)。
- 只发员工:管理端站内信 + 企微,不发短信、不进客户收件箱。站内信链接是
/order/todos(定制师待办),不是团期详情——定制师角色没有「出团详情」菜单。 - 同一团 300 秒冷却:冷却期内再点返回 589852,
message里带剩余秒数;前端拿cooldownSeconds做倒计时置灰即可。
一、背景
成团后系统按户给定制师开了「房型需求 · 待提交」「用车需求 · 待提交」待办,但待办只在后台列表里,不推送;团期管理员发现有户没提交,只能线下去找定制师。原型团期详情有「企微催需求」按钮、看板有铃铛,本单给它补后端。
二、变更接口清单
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|---|---|---|---|---|---|
| 1 | 一键催办定制师提交房 / 车需求 | POST | /v3/admin/order/group-batch/{groupBatchId}/requirement/nudge |
新增接口 | 无请求体;按定制师每人一条站内信 + 企微;同团 300 秒冷却 |
网关无改动(在既有 /v3/admin/** → order-service-v3 通配下)。
三、接口详情
1. 一键催办定制师提交房 / 车需求 POST /v3/admin/order/group-batch/{groupBatchId}/requirement/nudge
VO: GroupBatchRequirementNudgeRespVO
使用场景
团期详情「需求」Tab 的「企微催需求」按钮、团期看板铃铛。团期已成团(资源准备中)、还有户没提交房 / 车需求时,团期管理员点一下,系统按定制师聚合、每人发一条站内信 + 企微。成功后用 recipients 提示「已催 N 位定制师(M 户)」,skipped 非空时提示「K 户未指派定制师,未催」,wecomBound=false 的定制师提示「未绑企微,只收到站内信」;按 cooldownSeconds 倒计时置灰按钮。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| groupBatchId | Path | Long | ✅ | 团期主键 | 不存在返 589500 |
无请求体、无查询参数。
出参
| 字段 | 类型 | 说明 |
|---|---|---|
| groupBatchId | String | 团期主键(雪花 id,按字符串返回) |
| groupBatchNo | String | 团号,如 T26-0938 |
| departDate | String | 出发日期 yyyy-MM-dd |
| eventCode | String | 固定 GROUP_BATCH_REQUIREMENT_NUDGE |
| pendingHouseholdCount | Integer | 待定制师提交的户数(含 skipped 里无定制师的户) |
| consultantCount | Integer | 本次催到的定制师人数(= recipients 条数) |
| enqueuedCount | Integer | 通知成功投进通知中心的定制师人数(≤ consultantCount) |
| skippedHouseholdCount | Integer | 因无定制师跳过的户数(= skipped 条数) |
| recipients | Array | 逐定制师结果,按首个待提交户的顺序 |
| recipients[].consultantId | String | 定制师(员工)id |
| recipients[].consultantName | String | 定制师姓名(企微名,缺省登录名);员工信息查不到时为 null |
| recipients[].wecomBound | Boolean | 是否绑企微:true 同时收到企微;false 只收站内信;查不到时为 null(未知) |
| recipients[].householdCount | Integer | 该定制师名下待提交户数 |
| recipients[].hotelPendingCount | Integer | 其中房型需求待提交 / 被打回的户数 |
| recipients[].vehiclePendingCount | Integer | 其中用车需求待提交 / 被打回的户数 |
| recipients[].households | Array | 该定制师名下待提交户明细(结构同下 skipped[],skipReason 为 null) |
| recipients[].enqueued | Boolean | 通知是否已投进通知中心 |
| recipients[].message | String | 未投进的原因(如「通知中心投递失败」);成功为 null |
| skipped | Array | 无定制师、没人可催的户 |
| skipped[].orderId | String | 子订单 id |
| skipped[].orderNo | String | 订单号 |
| skipped[].teamNo | String | 团号(子订单级) |
| skipped[].customerName | String | 客户姓名 |
| skipped[].hotelPending | Boolean | 房型需求是否待提交 / 被打回 |
| skipped[].vehiclePending | Boolean | 用车需求是否待提交 / 被打回 |
| skipped[].skipReason | String | 跳过原因,现为「订单未指派定制师」 |
| notifiedAt | String | 本次催办时间 yyyy-MM-dd HH:mm:ss;一条都没发时为 null |
| cooldownSeconds | Integer | 下次可催前的冷却秒数:有通知发出时 300;一条都没发(全部户无定制师)时 0 |
请求示例
POST /v3/admin/order/group-batch/2106397492469985281/requirement/nudge
Authorization: Bearer <团期管理员 token>
响应示例
TEST 实测(团期 T26-0938,两位定制师 + 一户无定制师):
{
"code": 200,
"message": "成功",
"data": {
"groupBatchId": "2106397492469985281",
"groupBatchNo": "T26-0938",
"departDate": "2026-11-18",
"eventCode": "GROUP_BATCH_REQUIREMENT_NUDGE",
"pendingHouseholdCount": 4,
"consultantCount": 2,
"enqueuedCount": 2,
"skippedHouseholdCount": 1,
"recipients": [
{
"consultantId": "1002",
"consultantName": "test_admin",
"wecomBound": true,
"householdCount": 2,
"hotelPendingCount": 2,
"vehiclePendingCount": 1,
"households": [
{
"orderId": "2106397492268658689",
"orderNo": "HL20261003225431608",
"teamNo": "26-2132",
"customerName": "乌云毕力格",
"hotelPending": true,
"vehiclePending": true,
"skipReason": null
},
{
"orderId": "2106397493581516801",
"orderNo": "HL20261003225431974",
"teamNo": "26-9255",
"customerName": "王淑芬",
"hotelPending": true,
"vehiclePending": false,
"skipReason": null
}
],
"enqueued": true,
"message": null
},
{
"consultantId": "2073973862738944001",
"consultantName": "designer_4760",
"wecomBound": false,
"householdCount": 1,
"hotelPendingCount": 1,
"vehiclePendingCount": 1,
"households": [
{
"orderId": "2106397494344839169",
"orderNo": "HL20261003225432223",
"teamNo": "26-6378",
"customerName": "刘志强",
"hotelPending": true,
"vehiclePending": true,
"skipReason": null
}
],
"enqueued": true,
"message": null
}
],
"skipped": [
{
"orderId": "2106397494781087745",
"orderNo": "HL20261003225432341",
"teamNo": "26-3501",
"customerName": "高玉梅",
"hotelPending": true,
"vehiclePending": true,
"skipReason": "订单未指派定制师"
}
],
"notifiedAt": "2026-10-03 22:57:38",
"cooldownSeconds": 300
}
}
空数据 / 降级响应
待提交的户全部没有定制师(TEST 实测团期 T26-7327):返回 200,不发任何通知、不写时间线、不占冷却,cooldownSeconds=0、notifiedAt=null,可立即再点:
{
"code": 200,
"message": "成功",
"data": {
"groupBatchId": "2106397514322350082",
"groupBatchNo": "T26-7327",
"departDate": "2026-11-24",
"eventCode": "GROUP_BATCH_REQUIREMENT_NUDGE",
"pendingHouseholdCount": 1,
"consultantCount": 0,
"enqueuedCount": 0,
"skippedHouseholdCount": 1,
"recipients": [],
"skipped": [
{
"orderId": "2106397514263629826",
"orderNo": "HL20261003225436973",
"teamNo": "26-0624",
"customerName": "孙德胜",
"hotelPending": true,
"vehiclePending": true,
"skipReason": "订单未指派定制师"
}
],
"notifiedAt": null,
"cooldownSeconds": 0
}
}
员工信息查询降级(user-service 不可用)时照常催办,只是 consultantName、wecomBound 为 null(未知),不要显示成「未绑企微」。
错误响应
冷却期内重复催办({0} 为剩余秒数,TEST 实测):
{ "code": 589852, "message": "催办过于频繁,请 298 秒后再试", "success": false, "data": null }
没有可催的户(在团户的房 / 车需求都已提交):
{ "code": 589850, "message": "本团期在团户的房型 / 用车需求均已提交,无需催办", "success": false, "data": null }
团期还在招募中:
{ "code": 589552, "message": "团期尚未成团,请先完成成团后再操作", "success": false, "data": null }
团期已过资源准备中(物料准备中及以后、已取消),定制师已不能提交需求:
{ "code": 589851, "message": "团期当前状态为「已取消」,定制师已不能提交房型 / 用车需求,无法催办", "success": false, "data": null }
无权限(如定制师):
{ "code": 589507, "message": "无操作权限(当前角色未授予团期权限,或该团期不在您名下)", "success": false, "data": null }
| code | 含义 | 前端处理 |
|---|---|---|
| 589500 | 团期不存在 | 提示后返回列表 |
| 589507 | 当前角色无 group-batch:manage(定制师、财务等) |
不展示按钮 |
| 589552 | 团期还在招募中 | 按钮置灰「成团后可催」 |
| 589850 | 没有可催的户 | 提示「需求已全部提交」 |
| 589851 | 团期已过资源准备中,需求已冻结 | 不展示按钮 |
| 589852 | 冷却中,message 带剩余秒数 |
按剩余秒数倒计时置灰 |
| 589853 | 通知中心暂不可用,一条都没发出 | 提示稍后重试(冷却已释放,可立即重试) |
业务边界
- 权限码
group-batch:manage(授GROUP_BATCH_MANAGER/ADMIN/SUPER_ADMIN),定制师不能点。 - 「待提交」的口径与定制师待办同源:在团户中订单处于资源准备中,且需要房(或车)、对应需求从未提交或被打回定制师;车侧整团已声明免车的户不算。
- 被房务 / 车队退回团期管理员重审(
REJECTED_TO_ADMIN)的户不催——球在管理员手里,不在定制师。需求 Tab 车侧逐户页把这类户显示为「待重提」,与催办户数可能差这一类。 - 一次催全团,不支持按户 / 按定制师勾选;同一定制师名下多户合成一条。
- 只发员工:管理端站内信 + 企微,不发短信 / 小程序 / 公众号,客户收件箱不会出现。
- 冷却按团计 300 秒;一条都没发出(无人可催、通知中心不可用)不占冷却。部分定制师投递失败时冷却照常生效,失败的那几位也要等冷却结束才能再催(看
recipients[].enqueued)。 - 「已投进通知中心」不等于「已送达」:站内信 / 企微的实际结果由通知中心异步记录;未绑企微的定制师只收到站内信。
- 停用 / 离职的定制师照样会被催;订单需要改派定制师的请先改派。
- 每次点击都会写一条团期时间线(GB-ADM-096 事件类型
BATCH_REQUIREMENT_NUDGE「催办定制师提交需求」),不要轮询调用。
四、契约约束与正确调用方式
✅ 正确 / ❌ 错误调用顺序
- ✅ 进入需求 Tab 时按团期状态决定按钮:资源准备中才展示可点;招募中置灰;之后的阶段不展示。
- ✅ 点击后用响应里的
cooldownSeconds做倒计时;收到 589852 时从message解析剩余秒数或直接展示message。 - ✅ 用
recipients/skipped组提示文案,wecomBound为 null 时不要提示「未绑企微」。 - ❌ 不要把
enqueued=true说成「已送达」。 - ❌ 不要拿响应里的户数去和需求 Tab 车侧「待重提」户数强行对齐(见业务边界第 3 条)。
五、数据库行为
- order-v3:不建表、不改表;每次成功催办在
group_batch_status_log追加一条 DATA 流水(event_type=BATCH_REQUIREMENT_NUDGE,content「催办定制师提交需求(N 位定制师 · M 户)」,extra 记定制师 / 订单 / 跳过户 id 与房车户数)。冷却只在 Redis(键order:gb:requirement-nudge:{groupBatchId},TTL 300 秒),不落库。 - user-service:Flyway
V20261003_8752__group_batch_requirement_nudge_notification.sql往notification_event_config插(或按uk_event_code收敛)一行GROUP_BATCH_REQUIREMENT_NUDGE:站内信 + 企微开、短信 / 小程序 / 公众号关、接收人ORDER_CONSULTANT、站内信链接/order/todos。通知中心消费后写admin_message与notification_send_log,不写user_message。
六、边界行为
| 场景 | 行为 |
|---|---|
| 团期不存在 | 589500 |
| 招募中 | 589552 |
| 物料准备中 / 待出发 / 出行中 / 核单 / 已结算 / 已取消 | 589851 |
| 资源准备中但全部户已提交 | 589850 |
| 全部待提交户都没有定制师 | 200,consultantCount=0、cooldownSeconds=0,不发不留痕 |
| 部分户无定制师 | 有定制师的照发,无定制师的列入 skipped |
| 300 秒内再点 | 589852,带剩余秒数 |
| 通知中心不可用(一条都没投进) | 589853,冷却释放可立即重试 |
| 部分定制师投递失败 | 200,失败者 enqueued=false、message 有原因;冷却生效 |
| 员工信息查不到 | 照常催办,consultantName / wecomBound 为 null |
六.5、枚举 / 数据字典
skipped[].skipReason:目前只有「订单未指派定制师」。- 时间线事件类型
BATCH_REQUIREMENT_NUDGE,中文名「催办定制师提交需求」,变更类型 DATA。 - 新错误码段 589850-589899:589850 无可催的户、589851 阶段已冻结、589852 冷却中、589853 通知中心不可用。
七、不影响范围
- 仅影响: 新增一个写端点 + 一条通知事件配置。
- 零影响:
- 需求 Tab 既有接口(requirement-summary、hotel-households、vehicle-households、confirm、reject 等)的入参、出参与错误码
- 定制师待办的开单 / 关单逻辑(判定抽成单源后行为不变)
- 补发成团通知
notify-formed及其冷却 - 小程序端、客户通知
- 零表结构变更、零网关变更、零权限种子变更(复用
group-batch:manage)。
八、测试环境已验证
部署:hl-user-service 与 hl-order-service-v3 = dev-v3 @ 5b204b9d2(2026-10-03 22:31 / 22:34,user-service 先上);TEST flyway_schema_history 20261003.8752 success=1;四批取证前各打一次构建身份探针(不存在的团期 → 589500),经网关 https://api.test.1814.love 真实鉴权实测(2026-10-03 22:40–23:05);工单 #8752 已验收关单。
| # | 场景 | 结果 |
|---|---|---|
| 1 | 团期管理员(gbm8154test,单角色)催两位定制师 + 一户无定制师的团 | 200;每位定制师恰好一条;无定制师户进 skipped;户数与定制师待办逐户一致 |
| 2 | 落库:admin_message / notification_send_log / user_message |
站内信 2 行(link /order/todos)、ADMIN_INAPP 两行 status=0;user_message 前后 0 行 |
| 3 | 企微 | 未绑定的定制师 wecomBound=false、WEWORK status=2「无企微接收人」;已绑定的测试号调到真实企微接口、因测试假 userid 被拒(errcode 81013),未真实送达 |
| 4 | 冷却 | 1 秒后再点 589852「298 秒」、13 秒后「286 秒」;300 秒后再点 200 |
| 5 | ADMIN / 定制师 | ADMIN 200;定制师 589507 |
| 6 | 招募中 / 全部已提交 / 已取消 / 核单中 / 不存在 | 589552 / 589850 / 589851 / 589851 / 589500 |
| 7 | 全部户无定制师的团 | 200、cooldownSeconds=0,不写站内信、不写发送记录、不写时间线 |
| 8 | 时间线 GB-ADM-096 | 读到 BATCH_REQUIREMENT_NUDGE「催办定制师提交需求(2 位定制师 · 3 户)」 |
| 9 | 投递失败释放冷却 | 本机真组件注入(真 Redis + 不可达的真 RocketMQ):589853、冷却键已释放、立即重试仍 589853 |
九、相关历史 PR
| PR | Issue | 说明 | 是否仍有效 |
|---|---|---|---|
| — | #7534 | 补发成团通知(300 秒冷却先例) | ✅ |
| — | #7105 | 团期批量催签合同(批量触达 + 逐户结果先例) | ✅ |
| — | #8562 | 用车逐户区分从未提交 / 被打回 | ✅ |
| — | #8228 | 站内信 link 留空成死链(本单 link 不留空的原因) | ✅ |
| 本 PR #8777 | #8752 | 一键催办定制师提交房 / 车需求 | ✅ 最新 |
十、相关文档
- 关联 Issue: wx/HL#8752
- 关联 PR: wx/HL#8777
关联 / 联系人
链接
联系人
- 后端负责人: @jw