hl-api-changelog/changelogs/2026-04/2026-04-23_order-complaint-module.md

6.8 KiB

订单投诉模块 - 小程序发起 + 后台只读列表

  • 变更日期: 2026-04-23
  • PR: #1221 + #1222/#1223/#1225/#1235配套 hotfix
  • Closes: #1220
  • 影响面: 小程序端(新增 5 接口) + 管理端(新增 2 接口 + 1 菜单)
  • 兼容性: 纯新增,无既有接口变更

🎯 业务背景

客户在行程中任意一天(含"整程")可发起投诉;后端自动通过企业微信 + 短信双链路通知订单负责的定制师(管理员)。管理后台侧边栏新增"投诉管理"一级菜单,定制师只读查看自己订单的投诉,超管/主管看全部。无审批流,客户本人可填/改解决备注。


🛒 小程序端接口(/mp/complaint/**

统一前缀 /mp/complaint,userId 从网关注入的 token 取,前端无需传。

1. 发起投诉

POST /mp/complaint/create
Authorization: Bearer <mp-token>
Content-Type: application/json

{
  "orderId": 99988,
  "dayNumber": 2,              // 0 或 null = "整程投诉"; 1..N = 第 N 天
  "types": ["ITINERARY", "VEHICLE"], // 字典 complaint_type: ITINERARY / VEHICLE / HOTEL / OTHER
  "content": "第二天酒店入住流程混乱...",  // 必填 1~500 字
  "imageUrls": ["https://oss/.../1.jpg"],  // ≤9,前端 OSS 直传后给后端 URL
  "videoUrl": "https://oss/.../1.mp4"      // 可空 ≤1
}

返回:
{"code":200,"data":{"complaintId":1024},"success":true}

错误码

Code 含义 附加字段
20301 10 分钟冷却中(同一单同一天) remainingSeconds
20302 订单不属于当前用户
20303 dayNumber 超出已发生范围 maxDayNumber

2. 撤回投诉10 分钟内本人可)

POST /mp/complaint/{id}/cancel
返回: {"code":200,"data":{"success":true}}

错误:
- 20305 非本人投诉
- 20306 已超 10 分钟

3. 我的投诉列表

GET /mp/complaint/my-page?pageNo=1&pageSize=10

返回: Page<MpComplaintSimpleRespVO>:
- id / orderNo / groupCode
- dayNumber / dayLabel"整程" 或 "第N天"
- types: [{code, label}]
- contentSnippet前 50 字)
- imageCount / videoCount
- isResolvedresolutionNote 非空)
- resolutionEditCount / createdAt

4. 投诉详情

GET /mp/complaint/{id}

返回 MpComplaintRespVO在 SimpleRespVO 基础上 + content/imageUrls/videoUrl/resolutionNote/resolutionUpdatedAt/canCancel/canEditResolution

错误: 20304 不存在或已撤回 / 20305 非本人

5. 填/改解决备注(最多 2 次)

PUT /mp/complaint/{id}/resolution
{
  "resolutionNote": "已与定制师沟通完毕"
}

返回: {"code":200,"data":{"editCountLeft":1}}

错误:
- 20305 非本人
- 20307 已达 2 次上限

🧑‍💼 管理端接口(/admin/complaint/**,只读)

1. 投诉列表(含权限过滤)

GET /admin/complaint/page?pageNo=1&pageSize=10&keyword=&orderNo=&groupCode=&customizerNickname=&types=ITINERARY&isResolved=false&dateFrom=2026-04-01&dateTo=2026-04-23&dayScope=ALL

dayScope: ALL(默认) / WHOLE(整程=dayNumber=0) / SPECIFIC(具体天>=1)

返回 Page<ComplaintRespVO>:
- id / orderId / orderNo / groupCode
- customizerId / customizerNickname
- userId / userNickname
- contactName / contactPhoneMasked列表脱敏后 4 位)
- dayNumber / dayLabel
- types / content / contentSnippet / imageUrls / videoUrl
- resolutionNote / resolutionEditCount / resolutionUpdatedAt / isResolved
- notifyWechatStatus / notifySmsStatusPENDING/SUCCESS/FAIL/SKIP
- status / createdAt / updatedAt

2. 投诉详情

GET /admin/complaint/{id}

同 Page 返回结构 + contactPhoneDecrypted明文,仅 complaint:detail 权限 + 非 :self 或本人订单才返)

3. 权限模型R4

按钮权限 效果
complaint:list:self 定制师:强制 SQL WHERE customizer_id = currentAdminId
complaint:list:all 超管/主管:无过滤
complaint:detail 查看详情(基础权限)

已配菜单 + 角色绑定:

  • SUPER_ADMIN(1) / ADMIN(2) → :all + :detail
  • CUSTOMIZER(3) → :self + :detail

🔔 通知链路(后端自动,前端不关心)

投诉创建成功后 afterCommit → 异步双链路发给 order.customizerId

  • 企业微信(已有 WechatMessageDTO + MQ 优先 / Feign 降级):
    【客户投诉】
    团号NM20260422001
    订单号DD20260422001
    联系人:张三 13800138000
    第 2 天 · 行程/车
    内容第二天酒店入住流程混乱50字摘要
    图片 3 视频 0
    
  • 短信(阿里云模板 aliyun.sms.template.complaint-notify,签名"呼籁旅行"
    【呼籁旅行】团号${groupCode}订单${orderNo}${day}收到客户投诉(${type}),请登录后台查看。
    
    ⚠️ 当前测试服 SMS_MOCK_TBD(不真发),运营去阿里云控制台申请模板后 Nacos 替换即生效。

📂 数据字典(已执行)

  • complaint_typeITINERARY=行程 / VEHICLE=车 / HOTEL=房 / OTHER=其他
  • 菜单 投诉管理1250 系列,侧边栏末尾压底)

🎨 前端对接清单

管理端hl-ui admin

  • 侧边栏自动渲染"投诉管理"(后端 menu tree 已返回)
  • 列表页:表格 + 筛选6 条件 + dayScope
  • 详情页(只读):图/视频预览 + 完整文字 + 解决备注(客人本人写的)+ 通知状态
  • 字段精度id/orderId 全部 Long 序列化为 String防 JS 精度丢失,沿用项目全局 Jackson
  • 按钮权限:根据登录人 roleCodes 走 complaint:list:self:all 两套菜单,无管理操作按钮

小程序端hl-mp

  • 订单详情页"整程投诉"入口dayNumber=null/0
  • 每日行程卡片"本日投诉"入口dayNumber=具体天)
  • 投诉表单:类型多选 + 文字1~500+ OSS 直传图片≤9/ 视频≤1
  • 冷却拦截20301 时展示"10 分钟后再试,剩余 {remainingSeconds}s"
  • "我的投诉"列表 + 详情 + canCancel 显示撤回按钮 + canEditResolution 显示"填写解决备注"

⚠️ 注意

  • 投诉表 order_complaint 已在测试服 hl_order_service_v2 建好29 字段 + UNIQUE 防刷 + 4 索引)
  • 企微通知依赖 order.customizerId → admin_user.enterprise_wechat_id → wechat_user.mobile/name,定制师未绑企微则自动 SKIP 短信/企微两路
  • 同一用户 + 同一订单 + 同一 dayNumber 10 分钟只能一次Redis SETNX + DB UNIQUE 双层兜底)

🚨 需要后端重启的服务(已完成,此处仅记录)

  • hl-user-serviceFeign: getAdminNotifyProfile + sendComplaintSms + 字典菜单)
  • hl-order-service-v2投诉主逻辑 + admin controller + internal api
  • hl-mp-serviceMpComplaintController + Feign client + VO
  • hl-gatewayadmin-complaint-service 路由)