fix: /mp/product reviewSummary 字段从 null 恢复(测试服已部署验证) (PR #2984)
这个提交包含在:
父节点
4d914be807
当前提交
1538a0b2eb
@ -0,0 +1,89 @@
|
|||||||
|
# fix(小程序): `/mp/product/{id}` 接口 `reviewSummary` 字段从今天起返真实数据(之前全是 null)
|
||||||
|
|
||||||
|
> **类型**: fix (纯后端 contract 修复,前端**无需改动代码**,只是数据从 null 变成有值)
|
||||||
|
> **关联 PR/Issue**: PR #2984 (Closes #2980) 已合 dev,**测试服已部署 + API 真测通过**
|
||||||
|
> **正式服**: ⚠️ **本次未部署正式**,用户安排后续窗口再部
|
||||||
|
> **日期**: 2026-05-25
|
||||||
|
> **影响范围**: 小程序端产品详情页 `GET /mp/product/{productId}` 响应里的 `reviewSummary` 字段
|
||||||
|
> **接收方**: mmg
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 现象(修复前)
|
||||||
|
|
||||||
|
小程序产品详情接口 `GET /mp/product/{id}` 返回的 `reviewSummary` 对象 4 个字段**全是 null**,不论该产品在 admin 评价审核里有多少条已通过评价:
|
||||||
|
|
||||||
|
```json
|
||||||
|
"reviewSummary": {
|
||||||
|
"avgScore": null,
|
||||||
|
"totalCount": null,
|
||||||
|
"topReview": null,
|
||||||
|
"tags": null
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
测试服 + 正式服都一样。所有产品的"评价摘要"区从来没有真数据。
|
||||||
|
|
||||||
|
## 🩺 根因
|
||||||
|
|
||||||
|
后端两层 Feign 契约字段名对不上:
|
||||||
|
- `hl-product-service-v2` 的 `ReviewFeignClient` 声明返回 `ReviewSummaryVO`(字段 `avgScore/totalCount/topReview/tags`)
|
||||||
|
- 后端 `hl-order-service-v2.InternalReviewController.getProductHighlights` 实际返 `Map<String,Object>`(keys: `stats/topRatedReview/topLikedReview`)
|
||||||
|
|
||||||
|
Jackson 反序列化 Map → ReviewSummaryVO 时无一字段名匹配,全部赋 null。
|
||||||
|
|
||||||
|
## ✅ 修复后
|
||||||
|
|
||||||
|
```json
|
||||||
|
"reviewSummary": {
|
||||||
|
"avgScore": 5.0,
|
||||||
|
"totalCount": 159,
|
||||||
|
"topReview": {
|
||||||
|
"reviewId": "17767518569310317",
|
||||||
|
"nickname": "汪***",
|
||||||
|
"avatarUrl": "https://wx.qlogo.cn/.../132",
|
||||||
|
"score": 5,
|
||||||
|
"content": "行程安排很舒服,避开了拥堵,人少景美,很美好的旅行会议!",
|
||||||
|
"images": [
|
||||||
|
"https://hlgl-test.oss-cn-beijing.aliyuncs.com/test/review/2026/04/21/...jpg"
|
||||||
|
],
|
||||||
|
"likeCount": 0,
|
||||||
|
"reviewTime": "2024-10-10T16:18:57"
|
||||||
|
},
|
||||||
|
"tags": null
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
字段说明:
|
||||||
|
| 字段 | 类型 | 含义 |
|
||||||
|
|------|------|------|
|
||||||
|
| `avgScore` | BigDecimal | 整体评价平均分(1-5);无评价时 0 |
|
||||||
|
| `totalCount` | Integer | 已通过评价总数;无评价时 0 |
|
||||||
|
| `topReview` | Object/null | 精选评价(优先取最高评分;与最高点赞同条时取最高点赞次条);无评价时 null |
|
||||||
|
| `topReview.score` | Integer/BigDecimal | 该条评价的整体评分(1-5) |
|
||||||
|
| `topReview.reviewTime` | ISO 字符串 | 评价时间 |
|
||||||
|
| `tags` | null | 关键词标签 - 后端目前不输出,保留占位等后续(预计 6 月以后才上) |
|
||||||
|
|
||||||
|
## 📋 前端要做的事
|
||||||
|
|
||||||
|
**理论上无需改动** — `ReviewSummaryVO` 这个 VO 的字段名/类型这次没动,前端原本按 null 处理的代码现在会直接拿到真值,自然展示出来。
|
||||||
|
|
||||||
|
⚠️ 唯一可能踩坑:之前因为后端永远返 null,部分前端代码可能写了「reviewSummary 没法用」的兜底(如直接隐藏评价区)。**请检查产品详情页是否有这类硬编码空逻辑**,确保后端有数据时能正常渲染。
|
||||||
|
|
||||||
|
## 🚀 部署状态
|
||||||
|
|
||||||
|
| 环境 | 状态 | 验证 |
|
||||||
|
|------|------|------|
|
||||||
|
| 测试服 | ✅ 已部署(order-v2 / product-v2 / mp 三服务) | 4 个产品(159/69/10/2 评价)逐一 curl 字段全对,DB 数据精确匹配 |
|
||||||
|
| 正式服 | ⏳ **未部署**,等用户安排窗口 | 待部署后由 wx curl 正式 `/mp/product/2055092537149804545`(已导入 172 条有赞迁移评价)验证 |
|
||||||
|
|
||||||
|
## 🔍 不破坏的契约
|
||||||
|
|
||||||
|
mp-service 自身的 `/mp/review/product/{productId}/highlights` 接口(产品详情页的「精选评价区」)**对外字段结构未变**,三个顶层 key `topRatedReview / topLikedReview / stats` 全保留,子字段一个不少。这次只是后端内部把弱类型 `Map<String,Object>` 改成强类型 DTO,对前端透明。
|
||||||
|
|
||||||
|
## 📁 涉及后端模块(影响重启)
|
||||||
|
|
||||||
|
- `hl-common-core`(新增共享 DTO `InternalProductReviewHighlightsDTO`)
|
||||||
|
- `hl-order-service-v2`
|
||||||
|
- `hl-product-service-v2`
|
||||||
|
- `hl-mp-service`
|
||||||
正在加载...
x
在新工单中引用
屏蔽一个用户