# feat(banner): /mp/banner/active 顶层 tags + PRODUCT 类型补 tags / seasons fallback

> **仓库**: HL (后端 hl-mp-service + hl-user-service + hl-product-service-v2)
> **关联 PR/Issue**: PR #2952, Closes #2950
> **日期**: 2026-05-23
> **影响范围**: `/mp/banner/active` 响应新增顶层 `tags` + PRODUCT 类型 linkTarget 补 tags / seasons fallback
> **接收方**: mmg (前端)
> **前端**: **需要消费新字段**

---

## 🎯 wx 实测反馈

1. **轮播图自身标签** (admin 编辑 banner 时填的「研学证书」)在 `/mp/banner/active` 没返回
2. **PRODUCT 类型 banner** 跳产品时, linkTarget 缺产品自身标签 (`product.tags`), seasons 字段也常为空

## 改动

### 1. Banner 顶层 tags

`MpBannerVO` 加 `tags: List<String>` 字段, 来自 `sys_banner.tags`。

之前精简掉了 tags 字段, Feign 反序列化下游 `BannerVO.tags` 被 Jackson 自动丢弃。

### 2. PRODUCT 类型 linkTarget 补 tags + seasons fallback

- `InternalProductSimpleVO` (product-v2 + user-service 镜像) 加 `tags: List<String>` 字段
- `ProductMapper.selectSimpleInfoByIds` `.select()` 补 `ProductDO::getTags`
- `ProductHelperService.selectSimpleByIds` builder 补 `.tags(p.getTags())`
- `BannerService.enrichLinkTarget` PRODUCT 分支:
  - 透传 `p.getTags()` (**产品自身标签, 不 fallback 主题** — 产品有自己的标签语义)
  - **seasons fallback**: 产品自己 seasons 为空且有 line_id → 取 line.seasons
  - lineIds 收集逻辑扩到 productMap.values().lineId, 复用 lineMap 一次 Feign

### 3. PRODUCT_LINE 分支不动

PR #2938/#2941 已做 (description + tags), 本期不动。

## API 行为变化

### `GET /mp/banner/active` 响应

```json
{
  "id": "2033821591988748290",
  "title": "2026 亲子游学营",
  "tags": ["研学证书"],           // ← 新增, banner 自身标签 (sys_banner.tags)
  "linkType": "PRODUCT",
  "linkId": "...",
  "linkTarget": {
    "type": "PRODUCT",
    "id": "...",
    "name": "额吉的故乡V9·7天6晚旷野版",
    "subtitle": "",
    "coverImageUrl": "...",
    "productType": "CORE",
    "tags": ["亲子"],             // ← 新增, 产品自身标签 (product.tags)
    "seasons": ["winter"],        // ← 修复 fallback line.seasons
    "lineId": ...,
    "description": null,          // PRODUCT 场景不返 description (对称性)
  },
  "sortOrder": 1
}
```

### 两个 tags 字段独立语义

| 字段 | 来源 | 用途 |
|---|---|---|
| `banner.tags` | sys_banner.tags | 轮播图自身标签, 例「研学证书」、「私家团 / 亲子」 |
| `banner.linkTarget.tags` | PRODUCT_LINE: product_line.tags<br>PRODUCT: product.tags | 跳转目标自身标签, 例「限定」「亲子」「城记」 |

---

## 🚨 前端需要做的事

### 1. 读取顶层 tags

```ts
const banner = response.data[0];
const bannerTags = banner.tags;           // ["研学证书"] - banner 自身标签
const linkTargetTags = banner.linkTarget?.tags;  // ["亲子"] - 跳转目标标签
```

### 2. 区分两个 tags

前端轮播图卡片可在不同位置展示:
- `banner.tags` → 卡片右上角徽章 / 顶部 chip
- `banner.linkTarget.tags` → 跳转目标信息区(产品/主题卡片)

如果两个 tags 在 UI 上不区分, 可合并去重展示。

### 3. seasons fallback 透明

`banner.linkTarget.seasons` 现在更可靠 — 产品没填时自动 fallback 产品线的 seasons, 前端按字段渲染即可。

---

## 测试服真测记录

部署 user + mp + product-v2 (rolling-deploy 2026-05-23 11:20) 后真测:

| Banner | linkType | banner.tags | linkTarget.tags | linkTarget.seasons | linkTarget.description |
|---|---|---|---|---|---|
| #2033821591988748290 | PRODUCT | ✅ ['研学证书'] | ✅ ['亲子'] | ✅ ['winter'] (fallback line) | null (对称正确) |
| #5 (额吉的故乡) | PRODUCT_LINE | ✅ ['私家团','亲子'] | ✅ ['限定'] | ✅ ['winter'] | ✅ '公司的风格的' |

单测: BannerServiceTest **37** + ProductHelperServiceTest **18** + InternalProductControllerTest **8** + mp Banner/Home **20** 全绿。

---

## 联系人

后端: wx (呼籁旅行)
前端: mmg

如有疑问可在 [#2950](https://git.1814.love:8443/wx/HL/issues/2950) 评论区留言。
