文件
hl-api-changelog/changelogs-v2/2026-10/03_8752_团期一键催办定制师提交房车需求-新增接口-管理后台.md
Mimingguang和Claude Opus 4.8 0c0d1ae396
changelog-filename-gate / validate (push) Failing after 2s
docs(changelog-v2): #8752 前端已交付(催需求按钮+看板铃铛,e4cd749bd)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-10-04 11:24:40 +08:00

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);既有接口零变化


⚠️ 关键变化

  1. 新增写端点 POST .../{groupBatchId}/requirement/nudge:团期管理员一键催本团所有「房型 / 用车需求未提交或被打回」户的定制师。此前前端写明「企微催需求无接口契约,不做」,底栏「去催需求」只跳需求 Tab;现在有接口了。
  2. 一位定制师一条:同一定制师名下多户合成一条通知,正文分列房型、用车待提交户数并列出订单号(最多 10 个,多的写「等 N 户」)。
  3. 只发员工:管理端站内信 + 企微,不发短信、不进客户收件箱。站内信链接是 /order/todos(定制师待办),不是团期详情——定制师角色没有「出团详情」菜单。
  4. 同一团 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 一键催办定制师提交房 / 车需求 ✅ 最新

十、相关文档

关联 / 联系人

链接

联系人

  • 后端负责人: @jw