# 小程序产品详情备品图片不显示修复

> **服务**: hl-product-service-v2 (端口 8083) + hl-resource-service (端口 8082)
> **PR**: #2421
> **Issue**: #2420
> **日期**: 2026-05-16
> **影响范围**: 小程序产品详情「出行备品」section 的封面图

---

## ⚠️ 关键变化

之前小程序产品详情「出行备品」**所有备品图片都不显示**(灰色占位)。本 PR 后:
- 正式存量 85 条 `product_supplies.cover_url` 已立即手动回填(用户无需等部署),刷新小程序即可看到图
- 编辑产品 Step3 备品保存后,新增/修改的备品会自动写入封面快照

---

## 一、根因

`ProductRouteService.saveRoute` Step3 备品保存逻辑历来未走 Feign 回填封面快照:
- `SuppliesItem` 请求 VO 不含 coverUrl 字段(前端不应该传)
- `BeanUtil.toBean(SuppliesItem, ProductSuppliesDO.class)` 拷贝出来 `coverUrl` 必然 null
- 哪怕走 `ProductSuppliesComboExpander` 组合展开路径,也会被中间的 DO→VO→DO 反复拷贝丢字段

结果: 正式 `product_supplies.cover_url` 全表 85/85 全 NULL。C 端 `SuppliesVO.coverUrl` 直接来自该列,前端必然渲染空图。

---

## 二、变更接口清单

| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|---|------|------|------|----------|------|
| 1 | 批量获取备品封面图 | GET | `/internal/supplies/covers/batch` | 新增内部接口 | 资源服务暴露,产品服务 Feign 调用 |
| 2 | Step3 路线与备品保存 | POST | `/admin/product-v2/{id}/route` | 行为修复 | 保存后自动回填 cover_url,前端 payload 不变 |
| 3 | C 端产品详情 | GET | `/mp/product/{id}/detail` | 行为修复 | `supplies[].coverUrl` 不再为 null |

前端接口契约**完全不变**,前端无需修改任何代码。

---

## 三、数据库变更

```sql
-- V20260516_002__backfill_supplies_cover_url.sql
-- 跨库 JOIN, hl_app 账号对两个库都有权限
UPDATE product_supplies ps
JOIN hl_resource_service.supplies_item si ON si.supplies_id = ps.supplies_resource_id
JOIN hl_resource_service.material m ON m.material_id = si.cover_material_id
SET ps.cover_url = m.oss_url
WHERE ps.cover_url IS NULL
  AND ps.supplies_resource_id IS NOT NULL
  AND m.oss_url IS NOT NULL
  AND m.oss_url <> '';
```

- 正式 RDS 已于 2026-05-16 13:41 手动跑过相同 SQL, affected=85,补全后 null_or_empty=0
- 测试服: 下次部署跑 Flyway 自动生效(幂等 WHERE IS NULL)

---

## 四、边界行为

- **自定义备品(suppliesResourceId=NULL)**: 不会调 Feign,coverUrl 保持 NULL(本来就没有资源库材料可拷)
- **资源服务不可用**: Feign Fallback 降级返空列表,本次保存 cover_url 保持 NULL,**不阻断产品保存**,下次保存重试。区别于 ComboExpander 失败必须阻断保存。
- **资源库材料已软删 / 无封面材料**: 服务端 `batchGetCoverUrls` 自动过滤,消费方按 ID 取不到即视为无封面,DO.coverUrl 保持 null。

---

## 五、不影响范围

- **仅影响**: 管理端 Step3 备品保存 + 小程序产品详情 supplies[].coverUrl
- **零影响**:
  - 其它管理端步骤(step1/2/4/5)
  - 订单 / 商家 / 用户服务
  - 备品组合 (`supplies_combo`) 自身的 cover_url(走 ComboFeignClient,不变)
  - `product_supplies` 表其它列(supplies_name / category / billing_type 等)
  - 自定义备品(无资源库 ID 那种)

---

## 六、测试环境已验证

- [x] hl-resource-service / hl-product-service-v2 mvn compile SUCCESS
- [x] 正式 RDS DESC product_supplies + 抽查 22 条 cover_url 全 OSS URL
- [x] 复现产品 `2055092537149804545` 备品 22 条 (车上拖鞋成人/儿童/指甲刀/晕车贴等) cover_url 全部 OSS URL
- [ ] 测试服部署后小程序详情备品图片可见 (待 mmg 部署后回归)

---

## 七、相关文档

- 关联 Issue: [wx/HL#2420](https://git.1814.love:8443/wx/HL/issues/2420)
- 关联 PR: [wx/HL#2421](https://git.1814.love:8443/wx/HL/pulls/2421)
