文件
hl-api-changelog/changelogs-v2-mp/2026-08/23_6207_AI推荐产品多维筛选开放接口-新增接口-小程序端.md
T
API Changelog Bot和Claude 89a08e4e50
changelog-filename-gate / validate (push) Successful in 2s
changelog(mp): AI推荐产品多维筛选开放接口 (#6207)
新增 GET /mp/product/ai-recommend 免登录开放接口,供 AI 推荐
调用。支持多维筛选(关键词/目的地/天数/季节/标签/报价/出发
日期/人数/资源类型等),排除私人定制 CUSTOM。

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-23 13:48:45 +00:00

234 行
9.6 KiB
Markdown
原始文件 Blame 文件历史

此文件含有模棱两可的 Unicode 字符
此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。
---
schema: "hl-changelog/v2"
ticket: "6207"
title: "AI 推荐产品多维筛选开放接口(免登录,排除私人定制)"
consumer: "mp"
author: "wx(GIT)"
change_type: "新增接口"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "pending"
frontend_owner: "mmg"
frontend_ref: ""
target_release: ""
verified_at: "2026-08-23"
status_note: "GET /mp/product/ai-recommend 免登录开放接口,AI 推荐用。默认返回 PUBLISHED + CORE/GROUP(排除 CUSTOM 私人定制),支持多维筛选。后端/网关已测试服验证,前端待消费。"
updated_at: "2026-08-23"
base: "dev-v3"
---
# 【新增接口·小程序端】AI 推荐产品多维筛选开放接口(#6207)
> **PR**: #6220 | **服务**: hl-mp-service / hl-product-service-v2 / hl-gateway | **作者**: wx | **更新时间**: 2026-08-23
> 免登录开放接口,供 AI 做产品推荐调用。**除私人定制(CUSTOM)以外的全部已上架(PUBLISHED)产品**,多维筛选,全部条件可选可组合。
---
## 一、背景
AI 做产品推荐需要一个查询接口:能筛选除私人定制以外的全部已上架产品,条件越多越好(目的地、天数、报价范围、团期、包含资源、人数、季节等),**不需要登录**。
---
## 二、变更接口清单
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|---|------|------|------|----------|------|
| 1 | AI推荐产品查询 | GET | `/mp/product/ai-recommend` | 🆕 新增 | 免登录,多维筛选,分页 |
> 网关白名单已放行(`JwtAuthFilter` SKIP_URLS),无 token 可直接调用。
---
## 三、接口详情
### 1. AI推荐产品查询 `GET /mp/product/ai-recommend`
BFF 透传至 product-service `GET /internal/mp/product/ai-query`。pageSize 最大 50。
**数据范围(硬性)**:
- `product.status = PUBLISHED`(已上架)
- `product_type IN (CORE, GROUP)`(**排除 CUSTOM 私人定制**)
#### 入参(全部可选,可任意组合)
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|------|------|------|------|------|------|
| keyword | Query | String | 否 | ≤100 字符 | 关键词/目的地(匹配产品名/副标题) |
| productType | Query | String | 否 | CORE/GROUP | 产品类型(默认 CORE+GROUP,传单一值可收窄) |
| category | Query | String | 否 | family/honeymoon/photography/experience/driving | 产品分类 |
| lineId | Query | Long | 否 | - | 产品线ID |
| minDays | Query | Integer | 否 | ≥1 | 最短天数 |
| maxDays | Query | Integer | 否 | ≥1 | 最长天数 |
| seasons | Query | String | 否 | spring/summer/autumn/winter,逗号分隔多值 | 季节 |
| tags | Query | String | 否 | 逗号分隔多值 | 产品标签 |
| minPrice | Query | BigDecimal | 否 | - | 最低起步价 |
| maxPrice | Query | BigDecimal | 否 | - | 最高起步价 |
| startDate | Query | String | 否 | yyyy-MM-dd | 出发日期起始 |
| endDate | Query | String | 否 | yyyy-MM-dd | 出发日期结束 |
| partySize | Query | Integer | 否 | ≥1 | 人数(仅与 startDate+endDate 组合时生效,过滤「订不下」的产品) |
| resourceType | Query | String | 否 | SCENIC/ACTIVITY/RESTAURANT/SERVICE/CUSTOM | 包含资源类型 |
| resourceKeyword | Query | String | 否 | - | 包含资源关键词 |
| orderBy | Query | String | 否 | sort/price_asc/price_desc/newest | 排序 |
| page | Query | Integer | 否 | 默认1,≥1 | 页码 |
| pageSize | Query | Integer | 否 | 默认10,1~50 | 每页条数(**最大 50**,>50 返 400) |
> **seasons/tags 传法**:逗号分隔多值,如 `seasons=summer,winter`、`tags=亲子,摄影`。
#### 出参 `Result<PageResult<MpProductAiQueryItemVO>>`
| 字段 | 类型 | 说明 |
|------|------|------|
| records[].productId | String | 产品ID(雪花,字符串防精度丢失) |
| records[].productNo | String | 产品编号 |
| records[].productType | String | CORE/GROUP |
| records[].name | String | 产品名称 |
| records[].subtitle | String | 副标题 |
| records[].introduction | String | 产品简介 |
| records[].category | String | 产品分类 |
| records[].tripDays / tripNights | Integer | 天数 / 晚数 |
| records[].coverImageUrl | String | 封面图 |
| records[].carouselImages | String[] | 轮播图 |
| records[].tags / seasons | String[] | 标签 / 季节 |
| records[].lineId | String | 产品线ID |
| records[].lineName | String | 产品线名称 |
| records[].startPrice | String | 起步价(字符串) |
| records[].startPriceLabel | String | `¥3980起/人` |
| records[].paymentType | String | FULL / DEPOSIT |
| records[].status | String | PUBLISHED |
| records[].sortOrder | Integer | 排序号 |
| records[].earliestBookingDate | String | 最早可订日期 yyyy-MM-dd |
| records[].availableDateSummary | String | 可订日期摘要(如 `2026-09-11 起`) |
| records[].availabilitySummary | String | 余位摘要(GROUP: `8个班期可报名,余位充足(2026-09-11 ~ 2026-10-30)`;CORE: `9天可订(2026-08-23 ~ 2026-08-31)`) |
| records[].matchedDestinations | String[] | 匹配到的目的地/途经点摘要 |
| total | Integer | 总条数 |
| page / pageSize | Integer | 页码 / 每页条数 |
#### 请求示例
```
GET /mp/product/ai-recommend?productType=GROUP&seasons=summer&minPrice=0&maxPrice=20000&page=1&pageSize=5
```
#### 响应示例(测试服实测)
```json
{
"code": 200,
"message": "成功",
"data": {
"records": [
{
"productId": "2056947670512971778",
"productNo": "G260423004",
"productType": "GROUP",
"name": "测试小蒙马-多档-固定金额",
"subtitle": "",
"introduction": "测试产品简介",
"category": "photography",
"tripDays": 5,
"tripNights": 4,
"coverImageUrl": "https://hlgl-test.oss-cn-beijing.aliyuncs.com/...",
"tags": ["小蒙马"],
"seasons": ["summer"],
"lineId": "2001",
"lineName": "测试产品线",
"startPrice": "8800.00",
"startPriceLabel": "¥8800起/人",
"paymentType": "FULL",
"status": "PUBLISHED",
"sortOrder": 0,
"earliestBookingDate": "2026-09-11",
"availableDateSummary": "2026-09-11 起",
"availabilitySummary": "8个班期可报名,余位充足(2026-09-11 ~ 2026-10-30)"
}
],
"total": 5,
"page": 1,
"pageSize": 5
},
"success": true
}
```
#### 空数据响应(无匹配条件)
```json
{
"code": 200,
"message": "成功",
"data": { "records": [], "total": 0, "page": 1, "pageSize": 5 },
"success": true
}
```
#### 错误响应(参数防御)
```json
{
"code": 400,
"message": "每页条数不能大于50",
"data": null,
"success": false
}
```
---
## 四、契约约束与正确调用方式
### 筛选语义(后端为准)
- **所有条件 AND 组合**:同时传多个条件时,返回同时满足全部条件的产品。
- **seasons / tags 多值取 OR**:`seasons=summer,winter` 表示「夏季 **或** 冬季」。
- **报价范围按起步价过滤**:起步价 = GROUP 未来班期最低成人价 或 CORE 价格日历未来最低价,`minPrice/maxPrice` 作用于该值。
- **人数(partySize)过滤语义**:**仅当同时传了出发日期范围(startDate/endDate 至少一个)+ partySize 才生效**——过滤「订不下」的产品:
- GROUP:看日期范围内是否有余位 ≥ partySize 的可报名班期(ENROLLING/NEARLY_FULL)
- CORE:看日期范围内是否有库存(dailyStock - sold)≥ partySize 的日期
- **只传 partySize 不传日期 → 不触发人数过滤**。
- **目的地关键词**:匹配产品名/副标题 **或** 途经点名称 **或** 行程节点名称(任一处命中即算)。
- **日期倒置自动修正**:startDate 晚于 endDate 时后端自动交换,不报错。
### ✅ 正确 / ⚠️ 注意
| 场景 | 行为 |
|------|------|
| ✅ 无条件调用 | 返回全部在售(CORE+GROUP 且 PUBLISHED)分页 |
| ✅ `seasons=summer,winter` | 夏季或冬季的产品 |
| ✅ `minPrice=1000&maxPrice=5000` | 起步价在区间内的产品 |
| ✅ `startDate=2026-09-01&endDate=2026-10-01&partySize=2` | 该日期范围内能订下 2 人的产品 |
| ⚠️ `pageSize=999` | 400 拒绝(上限 50) |
| ⚠️ 只传 `partySize` 不传日期 | 人数条件不生效 |
---
## 五、测试环境已验证(2026-08-23)
```
GET /mp/product/ai-recommend?page=1&pageSize=5 → 200 total=22 ✓
GET /mp/product/ai-recommend?keyword=草原&page=1&pageSize=5 → 200 total=13 ✓
GET /mp/product/ai-recommend?productType=GROUP&page=1&pageSize=3 → 200 total=6 ✓
GET /mp/product/ai-recommend?category=family&page=1&pageSize=5 → 200 total=12 ✓
GET /mp/product/ai-recommend?seasons=summer,winter&page=1&pageSize=5 → 200 total=19 ✓
GET /mp/product/ai-recommend?minPrice=1000&maxPrice=5000&page=1&pageSize=3 → 200 ✓
GET /mp/product/ai-recommend?orderBy=price_asc&page=1&pageSize=5 → 200 ✓(第一条约 2980 便宜档)
GET /mp/product/ai-recommend?productType=GROUP&seasons=summer&minPrice=0&maxPrice=20000 → 200 total=5 ✓
GET /mp/product/ai-recommend?startDate=2026-08-24&endDate=2026-10-22 → 200 total=14 ✓
GET /mp/product/ai-recommend?pageSize=999 → 400 每页条数不能大于50 ✓
GET /mp/product/ai-recommend?category=driving&seasons=winter&keyword=不存在xyz → 200 empty ✓
```
免登录(无 token)经网关调用全部返回 200。
---
## 六、相关历史
- 关联 Issue: [wx/HL#6207](https://git.1814.love:8443/wx/HL/issues/6207)
- 关联 PR: [wx/HL#6220](https://git.1814.love:8443/wx/HL/pulls/6220)
### 联系人
- **后端负责人**: @wx
- **前端负责人**: @mmg