hl-api-changelog/changelogs/2026-04/2026-04-19_mp-product-detail-hotel-cover.md
API Changelog Bot c27eb63425 小程序产品详情补酒店封面图/类型/城市
fix/0419-business-hotfixes commit 2625331f
GET /mp/product/{id} 返回 itinerary[].hotels[] 每项新增 coverUrl/hotelType/city
原型 S6-住宿安排卡片左侧 100x100 封面图
2026-04-19 03:49:43 +08:00

5.8 KiB

小程序产品详情 - 住宿信息补酒店封面图 / 类型 / 城市

  • 日期: 2026-04-19
  • Commit: 2625331f (分支 fix/0419-business-hotfixes,批量 PR 待合)
  • 类型: FIX
  • 状态: 已 commit + push,待批量 PR 合入 dev + 部署测试环境
  • 服务: hl-product-service-v2端口 8083,通过网关暴露 /mp/product/**

一、为什么加这三个字段

原型(小蒙马.penS6-住宿安排)的每晚住宿卡片结构:

┌────────┬──────────────────────┐
│        │ 第N晚·城市名小标签 │
│ 封面图 │ 酒店名称(粗体)      │
│ 100x100│ 一句话描述            │
└────────┴──────────────────────┘

此前后端返回的 HotelInfo 只有 hotelName + 档位字段,前端拿不到封面图 URL、酒店类型五星/四星等)、酒店所在城市,小程序端显示为空白图位。

根因:MpProductDetailAssembler.fetchResourceDetails(...) 原先只收集 nodeType=HOTEL 节点的 hotelId 去批量查 ResourceDetailDTO,而 product_day_hotel 表里的 hotelId 从未进入批量查参数,所以 HotelInfo 始终拿不到酒店详情。


二、变更接口清单

# 方法 路径 影响
1 GET /mp/product/{id} 返回的 itinerary[].hotels[] 每项新增 coverUrl / hotelType / city 三字段

其他接口(如 /mp/product/{id}/day/{dayNumber}/hotels 住宿详情弹窗)已有 coverUrl不变


三、字段定义

MpProductDetailRespVO.HotelInfo 新增字段

字段 类型 说明 示例 可能为 null
coverUrl String 酒店封面图 URL来自资源服务的酒店 cover "https://oss.1814.love/hotel/9001/cover.jpg" 当酒店资源未配封面或 Feign 异常时为 null
hotelType String 酒店类型(字典 hotel_typeFIVE_STAR / FOUR_STAR / BOUTIQUE / HOMESTAY / ... "FIVE_STAR" 可能为 null
city String 酒店所在城市 "海拉尔" 可能为 null

既有字段(不变)

hotelName / tierSeq / tierName / roomTypeId / roomTypeName / roomCount

此外,本次修复顺带加强了 hotelName 的补齐语义:当资源服务返回了 name会覆盖 DB 快照字段(更新鲜),快照只作为 Feign 降级时的兜底。


四、响应示例对比

{
  "code": 200,
  "data": {
    "productId": 1001,
    "name": "小蒙马·呼伦贝尔5日",
    "itinerary": [{
      "dayNumber": 1,
      "hotels": [{
        "hotelName": "海拉尔精选酒店",
        "tierSeq": 1,
        "tierName": "标准",
        "roomTypeName": "大床房",
        "roomCount": 1
      }]
    }]
  }
}

{
  "code": 200,
  "data": {
    "productId": 1001,
    "name": "小蒙马·呼伦贝尔5日",
    "itinerary": [{
      "dayNumber": 1,
      "hotels": [{
        "hotelName": "海拉尔精选酒店",
        "tierSeq": 1,
        "tierName": "标准",
        "roomTypeName": "大床房",
        "roomCount": 1,
        "coverUrl": "https://oss.1814.love/hotel/9001/cover.jpg",
        "hotelType": "FIVE_STAR",
        "city": "海拉尔"
      }]
    }]
  }
}

五、前端渲染建议

原型 S6-住宿安排 每日住宿卡片:

<div class="hotel-card" v-for="hotel in day.hotels">
  <!-- 左侧 100x100 封面图 -->
  <image
    class="hotel-cover"
    :src="hotel.coverUrl || DEFAULT_HOTEL_COVER"
    mode="aspectFill" />

  <!-- 右侧文字信息 -->
  <view class="hotel-info">
    <text class="hotel-city">第{{ day.dayNumber }}晚·{{ hotel.city }}</text>
    <text class="hotel-name">{{ hotel.hotelName }}</text>
    <!-- 房型/档位信息 -->
    <text class="hotel-room">{{ hotel.tierName }} · {{ hotel.roomTypeName }}</text>
  </view>
</div>

⚠️ 容错要求

  • coverUrl / hotelType / city 三个字段均可能为 nullFeign 失败 / 酒店资源未配封面 / 老数据没录入城市),前端务必做 null/空字符串判断:
    • coverUrl 为空时显示默认占位图(避免整个卡片布局错乱)
    • city 为空时可以只显示"第N晚"
    • hotelType 用于可选的类型标签展示,为空时整个标签隐藏即可

六、不兼容变更

。纯新增字段,前端不读不受影响;既有字段(hotelName / 档位 / 房型)全部保留,语义不变。


七、运维注意事项(⚠️ 发布后必做)

本接口有 5 分钟 Redis 缓存key 前缀 mp:product:detail:)。测试 / 生产部署 hl-product-service-v2必须清一次缓存,否则 C 端最长 5 分钟内仍返回旧缓存(无封面图):

# 测试环境192.168.100.236 或 1.182.108.58
redis-cli -h <redis_host> -p 6379 --scan --pattern 'mp:product:detail:*' | xargs -r redis-cli -h <redis_host> -p 6379 del

# 或者粗暴重启服务强制清本地进程缓存Redis 不会自动失效)

八、回归验证

测试环境部署完成后:

# 选一个小蒙马 GROUP 产品的 productId
curl "https://api.test.1814.love/mp/product/{productId}" \
  -H "Authorization: Bearer {mp-token}" \
  | jq '.data.itinerary[0].hotels[0] | {hotelName, coverUrl, hotelType, city}'

预期:三个新字段都在响应 JSON 中出现;若酒店资源已配封面,coverUrl 为完整 http(s) URL;city / hotelType 应与后台管理端该酒店的配置一致。

如果 coverUrl 仍为 null

  1. 先确认 Redis 缓存已清(见第七节)
  2. 再排查酒店资源是否在资源服务后台配了封面图(管理端 → 酒店管理 → 编辑 → 封面图)