diff --git a/changelogs/2026-04/2026-04-13_product-v2_frontend_guide.md b/changelogs/2026-04/2026-04-13_product-v2_frontend_guide.md new file mode 100644 index 0000000..8058ac1 --- /dev/null +++ b/changelogs/2026-04/2026-04-13_product-v2_frontend_guide.md @@ -0,0 +1,634 @@ +# 产品模块v2 — 前端联调指南 + +> **日期**:2026-04-13 +> **服务**:hl-product-service-v2(端口待定,Knife4j: `http://localhost:{port}/doc.html`) +> **网关路由**:`/product-v2/**` → hl-product-service-v2 +> **重要**:本模块是全新服务,与旧 hl-product-service 并行运行。所有接口路径不同,不会冲突。 +> **参考**:完整接口字段定义见同目录 `2026-04-12_1538_273bef51_feat_product-v2_Co.md` 和 `2026-04-12_1538_ff42bed5_feat_product-v2_VO.md` + +--- + +## 一、整体架构变化 + +### 旧服务 vs 新服务 + +| 维度 | 旧 hl-product-service | 新 hl-product-service-v2 | +|------|----------------------|--------------------------| +| 产品类型 | CORE/GROUP/CUSTOM/ROUTE(4种) | CORE/GROUP/CUSTOM(3种,ROUTE废弃) | +| 保存方式 | 每个字段独立接口 | **5个业务域整体保存**(基础/行程/路线/定价/补充) | +| 定价模型 | 统一价格日历 | **双模型**:价格区间(CORE/CUSTOM)+ 班期(GROUP) | +| 住宿 | 统一 | 支持**多档位**(舒适/豪华/高端等) | +| 人群分档 | 成人/儿童 | **4档**:成人/儿童/小童/幼童 | +| 并发控制 | 无 | **乐观锁**(version字段) | + +### 乐观锁机制(所有保存接口通用) + +``` +1. GET 详情 → 拿到 version 字段 +2. PUT 保存 → 请求体带 version +3. 成功 → version+1(下次保存用新version) +4. 失败(409) → 提示"数据已被其他人修改,请刷新",重新GET +``` + +> **已上架产品调价**:用 `priceVersion` 而非 `version`(调价不占主version,允许调价和内容编辑互不阻塞) + +--- + +## 二、管理端页面接口对照 + +### 页面1:产品列表 + +``` +┌──────────────────────────────────────────────────────────────┐ +│ [搜索: 名称/编号] [类型▼] [产品线▼] [状态▼] [标签▼] │ +│ [+ 新建产品] │ +├──────────────────────────────────────────────────────────────┤ +│ 封面 │ 名称/编号 │ 类型 │ 产品线 │ 状态 │ 操作 │ +│ ... │ ... │ ... │ ... │ ... │ 编辑/复制/删除│ +└──────────────────────────────────────────────────────────────┘ +``` + +**接口**: + +| 场景 | 方法 | 路径 | 说明 | +|------|------|------|------| +| 产品列表 | GET | `/admin/product/item/list` | 分页,支持keyword/productType/lineId/status/tag筛选 | +| 产品线下拉 | GET | `/admin/product/line/simple-list` | 返回 `[{lineId, name}]`,用于筛选和创建 | +| 创建产品 | POST | `/admin/product/item` | 传 name+productType+lineId+tripDays,返回productId | +| 删除产品 | DELETE | `/admin/product/item/{id}` | 需先下架 | +| 复制产品 | POST | `/admin/product/item/{id}/copy` | 返回新productId | +| 状态变更 | PUT | `/admin/product/item/{id}/action` | 传 action 枚举,见下方状态操作表 | +| 操作记录 | GET | `/admin/product/item/{id}/operation-logs` | 分页,查看历史操作 | + +**状态操作枚举**(action字段): + +| action值 | 操作 | 前置状态 | 目标状态 | +|----------|------|---------|---------| +| SUBMIT_PUBLISH | 提交上架 | DRAFT | PENDING_REVIEW | +| WITHDRAW | 撤回审批 | PENDING_REVIEW | DRAFT | +| DIRECT_PUBLISH | 直接上架(超管) | DRAFT | PUBLISHED | +| UNPUBLISH | 申请下架 | PUBLISHED | PENDING_REVIEW(下架) | +| FORCE_UNPUBLISH | 强制下架(超管) | PUBLISHED | UNPUBLISHED | +| COMPLETE | 完成设计(定制) | DRAFT | COMPLETED | + +--- + +### 页面2:产品编辑 — Step1 基础信息 + +``` +┌──────────────────────────────────────────────────┐ +│ Step1 Step2 Step3 Step4 Step5 │ +│ ●基础 ○行程 ○路线 ○定价 ○补充 │ +├──────────────────────────────────────────────────┤ +│ 产品名称: [____________] │ +│ 副标题: [____________] │ +│ 产品类型: CORE (只读,创建时选定) │ +│ 产品线: [下拉选择▼] │ +│ 行程天数: [6] 晚数: [5] │ +│ 住宿规格: ○单一 ○多档 → [舒适][豪华][+添加档位] │ +│ 季节: □春 ☑夏 ☑秋 □冬 │ +│ 标签: ☑亲子 ☑研学 □露营 │ +│ 封面图: [上传] │ +│ 轮播图: [上传1] [上传2] ... (≤10张) │ +│ 年龄设置: 幼童≤[1]岁 小童≤[3]岁 儿童[4]-[12]岁│ +│ 幼童默认价: [0]元 │ +│ 支付方式: ○全款 ○订金([30]%/固定[___]元) │ +│ 产品简介: [富文本编辑器] │ +│ [保存] │ +└──────────────────────────────────────────────────┘ +``` + +**接口**: + +| 场景 | 方法 | 路径 | 说明 | +|------|------|------|------| +| 获取详情(回显) | GET | `/admin/product/item/{id}` | 返回全部5步数据,取basic部分回显 | +| 保存基础信息 | PUT | `/admin/product/item/{id}/basic` | `ProductBasicSaveReqVO`,带version | +| 产品线下拉 | GET | `/admin/product/line/simple-list` | 创建/修改时选产品线 | + +**关键字段**: + +```json +{ + "version": 1, + "name": "额吉的故乡·亲子版", + "subtitle": "6天5晚草原环线", + "tripDays": 6, + "tripNights": 5, + "lineId": 100, + "tiers": [ + {"tierSeq": 1, "tierName": "舒适"}, + {"tierSeq": 2, "tierName": "豪华"} + ], + "seasons": ["summer", "autumn"], + "tags": ["亲子", "研学"], + "coverImageUrl": "https://...", + "carouselImages": ["https://...", "https://..."], + "infantAgeMax": 1, + "toddlerAgeMax": 3, + "childAgeMin": 4, + "childAgeMax": 12, + "infantDefaultPrice": 0, + "paymentType": "FULL", + "showReview": true +} +``` + +--- + +### 页面3:产品编辑 — Step2 行程编排 + +``` +┌──────────────────────────────────────────────────┐ +│ DAY1 DAY2 DAY3 DAY4 DAY5 DAY6 [+添加] │ +├──────┬───────────────────────────────────────────┤ +│ │ 标题: [海拉尔→额尔古纳] │ +│ DAY1 │ 金句: [让草原成为孩子的第一个课堂] │ +│ │ 描述: [富文本] │ +│ │ 封面: [上传] 里程: [290]km │ +│ │ │ +│ │ 途经路线: │ +│ │ [海拉尔] → [莫日格勒河] → [额尔古纳] │ +│ │ │ +│ │ 活动安排: │ +│ │ ☐ 10:00 莫日格勒河观景台 (景区) 60分钟 │ +│ │ ☐ 14:00 骑马体验 (活动) 120分钟 │ +│ │ [+ 从资源库添加] [+ 自定义活动] │ +│ │ │ +│ │ 住宿安排: (多档时按档位Tab切换) │ +│ │ [舒适] 额尔古纳大酒店 │ +│ │ [豪华] 额尔古纳国际酒店 │ +│ │ │ +│ │ 餐饮: 早[酒店▼] 中[自理▼] 晚[特色餐▼] │ +│ │ 照片: [上传1] [上传2] │ +│ │ │ +│ │ [整体保存] │ +└──────┴───────────────────────────────────────────┘ +``` + +**接口**: + +| 场景 | 方法 | 路径 | 说明 | +|------|------|------|------| +| 获取行程(回显) | GET | `/admin/product/item/{id}` | 从详情中取 `itinerary` 部分 | +| 整体保存行程 | PUT | `/admin/product/item/{id}/itinerary` | **整棵行程树一次提交**,后端用EntityDiffUtil对比增删改 | +| 增加一天 | POST | `/admin/product/item/{id}/itinerary/day` | 追加末尾天,返回dayId | +| 删除一天 | DELETE | `/admin/product/item/{id}/itinerary/day/{dayNumber}` | 级联删节点+住宿+路线点 | +| 费用推导预览 | GET | `/admin/product/item/{id}/fee-deduction-preview` | 根据行程自动推导费用包含,进入Step5前调用 | + +**整体保存请求结构**: + +```json +{ + "productId": 123, + "version": 2, + "days": [ + { + "dayId": null, // 新增不传,已有传ID + "dayNumber": 1, + "dayTitle": "海拉尔→额尔古纳", + "quoteText": "让草原成为孩子的第一个课堂", + "description": "...", + "coverImageUrl": "https://...", + "dailyMileage": 290, + "breakfast": "HOTEL", // HOTEL/CAMP/SPECIAL/SELF + "lunch": "SELF", + "dinner": "SPECIAL", + "photoUrls": ["https://..."], + "nodes": [ + { + "nodeId": null, // 新增不传 + "sortOrder": 1, + "nodeType": "SCENIC", + "nodeName": "莫日格勒河观景台", + "resourceType": "SCENIC_SPOT", + "resourceId": 456, + "startTime": "10:00", + "durationMinutes": 60, + "description": "...", + "images": ["https://..."] + } + ], + "hotels": [ + { + "id": null, + "tierSeq": 1, // 档位序号,单一档=1 + "hotelId": 789, + "roomTypeId": null, // 私人定制才选房型 + "isDefault": true, + "sortOrder": 1 + } + ], + "routePoints": [ + { + "resourceId": 456, + "name": "莫日格勒河", + "longitude": 119.123, + "latitude": 49.456, + "sortOrder": 1 + } + ] + } + ] +} +``` + +> **增删改对比规则**:后端按ID判断——有ID且在提交中=更新,有ID但不在提交中=删除,无ID=新增。前端直接提交当前完整状态,不需要自己标记增删改。 + +--- + +### 页面4:产品编辑 — Step3 路线与备品 + +``` +┌──────────────────────────────────────────────────┐ +│ 路线信息 │ +│ 路线名称: [草原环线体验] │ +│ 路线图: [上传] │ +│ 总里程: [1200] km (自动计算,可手动改) │ +│ 线路描述: [____________] │ +│ │ +│ 备品清单 │ +│ 名称 │ 涉及成本 │ 计费方式 │ 单价 │ 数量 │ +│ 防晒霜SPF50+ │ ☐ │ — │ — │ — │ +│ 一次性雨衣 │ ☑ │ 按人头 │ 5 │ — │ +│ [+ 从资源库选] [+ 自定义] │ +│ │ +│ 全程成本项 │ +│ 实际用车: [车型下拉▼] │ +│ 服务人员: [选择▼] │ +│ 额外费用: [名称] [单价] [数量] [按天☐] │ +│ [保存] │ +└──────────────────────────────────────────────────┘ +``` + +**接口**: + +| 场景 | 方法 | 路径 | 说明 | +|------|------|------|------| +| 保存路线与备品 | PUT | `/admin/product/item/{id}/route` | `ProductRouteSaveReqVO`,一次提交全部 | +| 车型下拉 | — | 调资源服务 `/internal/vehicle-model/list` | 从资源模块获取车型列表 | +| 人员下拉 | — | 调资源服务 `/internal/staff/list` | 从资源模块获取人员列表 | +| 备品下拉 | — | 调资源服务 `/internal/supplies/list` | 从资源模块获取备品列表 | + +--- + +### 页面5:产品编辑 — Step4 定价管理 + +#### 核心产品/私人定制 → 价格区间 + +``` +┌──────────────────────────────────────────────────┐ +│ 价格区间列表 │ +│ 日期范围 │ 类型 │ 成人价 │ 儿童价 │ 库存 │ +│ 07.01 - 07.31 │ 旺季 │ 4980 │ 3980 │ 10 │ +│ 08.01 - 08.31 │ 旺季 │ 5280 │ 4280 │ 10 │ +│ 09.01 - 09.30 │ 平日 │ 3980 │ 2980 │ 不限 │ +│ [+ 新增区间] │ +│ │ +│ (多档时每个区间按档位平铺多组价格) │ +│ [保存] │ +└──────────────────────────────────────────────────┘ +``` + +**接口**: + +| 场景 | 方法 | 路径 | 说明 | +|------|------|------|------| +| 查询价格日历 | GET | `/admin/product/item/{id}/price-calendar` | 参数 month(yyyy-MM)、tierSeq(档位) | +| 批量设置价格 | POST | `/admin/product/item/{id}/price-calendar/batch` | 按日期范围+档位UPSERT | +| 删除价格区间 | DELETE | `/admin/product/item/{id}/price-calendar` | 按日期范围+档位删除 | +| 报价测算 | POST | `/admin/product/item/{id}/quote` | 输入日期+人数,预览总价 | + +**批量设置请求**: + +```json +{ + "productId": 123, + "version": 3, // 草稿用version,已上架用priceVersion + "startDate": "2026-07-01", + "endDate": "2026-07-31", + "tierSeq": 1, // 档位序号,单一=1 + "priceType": "PEAK", // NORMAL/PEAK/HOLIDAY/SPECIAL + "adultSellPrice": 4980, + "childSellPrice": 3980, + "toddlerDiscount": -500, // 小童优惠额(负数),小童价=儿童价-|优惠额| + "infantPrice": 0, // 幼童价,0=免费 + "dailyStock": 10 // NULL=不限量 +} +``` + +#### 小蒙马 → 班期管理 + +``` +┌──────────────────────────────────────────────────┐ +│ 班期列表 │ +│ 班期名 │ 出发日 │ 状态 │ 成人价 │ 已报/上限 │ +│ 第1期 │ 07.01 │ 报名中│ 4980 │ 8/20 │ +│ 第2期 │ 07.15 │ 报名中│ 4980 │ 3/20 │ +│ [+ 新增] [批量创建] │ +└──────────────────────────────────────────────────┘ +``` + +**接口**: + +| 场景 | 方法 | 路径 | 说明 | +|------|------|------|------| +| 班期列表 | GET | `/admin/product/item/{id}/schedule/list` | 返回全部班期 | +| 创建班期 | POST | `/admin/product/item/{id}/schedule` | `ScheduleSaveReqVO`,不传batchId | +| 修改班期 | PUT | `/admin/product/item/{id}/schedule` | 传batchId | +| 删除班期 | DELETE | `/admin/product/item/{id}/schedule/{scheduleId}` | 有订单不可删 | +| 取消班期 | POST | `/admin/product/item/{id}/schedule/{scheduleId}/cancel` | 有订单触发退款 | +| 批量创建 | POST | `/admin/product/item/{id}/schedule/batch-create` | 按重复模式批量 | +| 团队查询 | GET | `/admin/product/item/{id}/schedule/team?batchId=xxx` | 班期团队成员 | +| 团队保存 | PUT | `/admin/product/item/{id}/schedule/team?batchId=xxx` | 全量替换 | + +--- + +### 页面6:产品编辑 — Step5 补充信息 + +``` +┌──────────────────────────────────────────────────┐ +│ 费用包含 (自动推导+手动编辑) │ +│ ☑ 门票 (自动) │ ☑ 住宿 (自动) │ ☐ 旅拍 (手动) │ +│ │ +│ 费用不含 │ +│ ☑ 个人消费 │ ☑ 自费项目 │ +│ │ +│ 人群优惠 │ +│ 儿童门票: [免票▼] 住宿: [不占床▼] 餐饮: [半额▼]│ +│ 老人门票: [半价▼] 住宿: [同成人▼] │ +│ │ +│ 车辆展示: [选择车型▼] (纯展示) │ +│ 退改政策: [选择模板▼] │ +│ 预订条款: [选择模板▼] │ +│ 装备建议: [富文本] │ +│ 保险告知: ○含 ○不含 ○可选升级 │ +│ │ +│ 产品卖点 │ +│ 快速理解: [富文本+图片] │ +│ 孩子经历: [富文本+图片] │ +│ 成长收获: [探索力] [协作力] [+添加] │ +│ [保存] │ +└──────────────────────────────────────────────────┘ +``` + +**接口**: + +| 场景 | 方法 | 路径 | 说明 | +|------|------|------|------| +| 保存补充信息 | PUT | `/admin/product/item/{id}/supplement` | `ProductSupplementSaveReqVO` | +| 费用推导预览 | GET | `/admin/product/item/{id}/fee-deduction-preview` | 根据行程自动计算费用包含 | +| 退改政策模板 | GET | `/admin/product/refund-policy/enabled` | 下拉选择 | +| 预订条款模板 | GET | `/admin/product/booking-terms/enabled` | 下拉选择 | +| 温馨提示模板 | GET | `/admin/product/warm-tips/enabled` | 下拉选择 | + +--- + +### 页面7:产品线管理 + +``` +┌──────────────────────────────────────────────────┐ +│ [+ 新增产品线] │ +│ ┌──────┐ ┌──────┐ ┌──────┐ │ +│ │ 封面 │ │ 封面 │ │ 封面 │ │ +│ │ 名称 │ │ 名称 │ │ 名称 │ │ +│ │ 类型 │ │ 类型 │ │ 类型 │ │ +│ └──────┘ └──────┘ └──────┘ │ +└──────────────────────────────────────────────────┘ +``` + +**接口**: + +| 场景 | 方法 | 路径 | 说明 | +|------|------|------|------| +| 产品线列表 | GET | `/admin/product/line/list` | 分页 | +| 创建产品线 | POST | `/admin/product/line` | name+productType+coverImageUrl+seasons+tags | +| 编辑产品线 | PUT | `/admin/product/line/{lineId}` | | +| 删除产品线 | DELETE | `/admin/product/line/{lineId}` | 有产品时不可删 | +| 简单列表(下拉) | GET | `/admin/product/line/simple-list` | 返回 [{lineId, name, productType}] | + +--- + +## 三、C端(小程序)页面接口对照 + +### 页面1:主题精选页(产品线列表) + +**接口**:`GET /mp/product/line/list` +- 参数:productType(可选)、season(可选)、page、pageSize +- 返回:产品线卡片列表(name, description, coverImageUrl, startPrice, productType, seasons) + +### 页面2:产品列表(产品线下的产品) + +**接口**:`GET /mp/product/list` +- 参数:lineId(产品线ID)、tag(产品标签Tab)、page、pageSize +- 返回:产品卡片列表 + +**产品卡片关键字段**: + +```json +{ + "productId": 123, + "name": "额吉的故乡·亲子版", + "subtitle": "6天5晚草原环线", + "coverImageUrl": "https://...", + "tripDays": 6, + "productType": "CORE", + "tags": ["亲子", "研学"], + "startPrice": 3980, // 起步价(¥X起) + "startPriceLabel": "¥3980起/人" +} +``` + +### 页面3:产品详情页 + +**接口**:`GET /mp/product/{productId}` +- 返回:`MpProductDetailRespVO`(聚合全部展示数据) + +**返回结构**: + +```json +{ + "productId": 123, + "productType": "CORE", + "name": "额吉的故乡·亲子版", + "subtitle": "...", + "coverImageUrl": "...", + "carouselImages": ["...", "..."], + "tripDays": 6, + "tripNights": 5, + "routeMapUrl": "...", + "creatorAvatarUrl": "...", + "creatorIntro": "...", + + "itinerary": [ + { + "dayNumber": 1, + "dayTitle": "海拉尔→额尔古纳", + "description": "...", + "coverImageUrl": "...", + "breakfast": "HOTEL", + "lunch": "SELF", + "dinner": "SPECIAL", + "nodes": [ + { + "nodeType": "SCENIC", + "nodeName": "莫日格勒河观景台", + "startTime": "10:00", + "durationMinutes": 60, + "description": "..." + } + ] + } + ], + + "includedFees": [ + {"feeType": "TICKET", "name": "门票", "source": "AUTO"}, + {"feeType": "ACCOMMODATION", "name": "住宿", "source": "AUTO"} + ], + "excludedFees": [ + {"feeType": "PERSONAL", "name": "个人消费"} + ], + + "crowdBenefit": { + "childTicket": "FREE", + "childAccommodation": "NO_BED", + "childMeal": "HALF", + "elderTicket": "HALF_PRICE", + "tips": "..." + } +} +``` + +### 页面4:价格日历(弹窗) + +**接口**:`GET /mp/product/{productId}/price-calendar` +- 参数:month(yyyy-MM) +- 返回: + +```json +{ + "days": [ + { + "date": "2026-07-01", + "priceType": "PEAK", + "adultPrice": 4980, + "childPrice": 3980, + "isSelectable": true, // 连续N天有价格且有库存 + "remainStock": 8 // null=不限量 + } + ] +} +``` + +### 页面5:报价计算(选日期+人数后) + +**接口**:`POST /mp/product/{productId}/quote` + +**请求**: +```json +{ + "departureDate": "2026-07-01", + "adultCount": 2, + "childCount": 1, + "youngChildCount": 0, + "babyCount": 0, + "batchId": null, // 小蒙马传班期ID + "tierSeq": 1 // 多档时传档位序号 +} +``` + +**响应**: +```json +{ + "totalAdultPrice": 9960, + "totalChildPrice": 3980, + "grandTotal": 13940, + "dailyDetails": [ + {"date": "2026-07-01", "adultPrice": 4980, "childPrice": 3980}, + {"date": "2026-07-02", "adultPrice": 4980, "childPrice": 3980} + ], + "paymentType": "FULL", + "stock": 8, + "available": true +} +``` + +### 页面6:小蒙马班期列表(弹窗) + +**接口**:`GET /mp/product/{productId}/schedule/list` + +**返回**: +```json +[ + { + "batchId": 456, + "batchName": "第1期", + "departureDate": "2026-07-01", + "endDate": "2026-07-06", + "enrollmentDeadline": "2026-06-30", + "batchStatus": "ENROLLING", + "adultPrice": 4980, + "childPrice": 3980, + "maxParticipants": 20, + "enrolledCount": 8, + "maxRooms": 10, + "bookedRooms": 4 + } +] +``` + +--- + +## 四、字典值速查 + +| 字典 | 值 | 中文 | +|------|-----|------| +| product_type | CORE | 核心产品 | +| product_type | GROUP | 小蒙马跟团游 | +| product_type | CUSTOM | 私人定制 | +| product_status | DRAFT | 草稿 | +| product_status | PENDING_REVIEW | 待审核 | +| product_status | PUBLISHED | 已上架 | +| product_status | UNPUBLISHED | 已下架 | +| product_status | REJECTED | 已驳回 | +| product_status | COMPLETED | 已完成(定制) | +| product_status | ORDERED | 已下单(定制) | +| payment_type | FULL | 全款支付 | +| payment_type | DEPOSIT | 订金+尾款 | +| price_type | NORMAL | 平日 | +| price_type | PEAK | 旺季 | +| price_type | HOLIDAY | 节假日 | +| price_type | SPECIAL | 特价 | +| meal_option | HOTEL | 含(酒店) | +| meal_option | CAMP | 含(营地) | +| meal_option | SPECIAL | 含(特色餐) | +| meal_option | SELF | 自理 | +| schedule_status | ENROLLING | 报名中 | +| schedule_status | NEARLY_FULL | 即将满员 | +| schedule_status | FULL | 已满 | +| schedule_status | FINISHED | 已结束 | +| schedule_status | CANCELLED | 已取消 | +| insurance_notice | INCLUDED | 含保险 | +| insurance_notice | EXCLUDED | 不含保险 | +| insurance_notice | OPTIONAL | 可选升级 | + +--- + +## 五、与旧服务的切换说明 + +1. **管理端**:产品管理页面整体切换到v2接口,旧产品管理页面下线 +2. **C端**:小程序的产品列表/详情/报价/下单全部切换到v2接口 +3. **订单服务不改**:订单的Feign调用仍走旧接口(产品v2会兼容旧Feign路径) +4. **旧产品数据清空**:上线后旧产品数据全部删除,从零录入 + +--- + +## 六、联调注意事项 + +1. **所有保存接口都要传version**——忘传会返回400 +2. **行程整体保存**——不是一个节点一个接口,是整棵行程树一次提交(`PUT /itinerary`) +3. **价格区间制vs班期制**——看productType:CORE/CUSTOM用价格日历接口,GROUP用班期接口 +4. **多档位**——tierSeq从1开始递增,单一档位=1。价格日历和住宿都按tierSeq关联 +5. **小童价格特殊**——前端传的是优惠额(负数),实际小童价=儿童价-|优惠额| +6. **C端只展示PUBLISHED产品**——其他状态的产品C端接口不会返回 +7. **Knife4j文档**——本地启动服务后访问 `http://localhost:{port}/doc.html` 查看完整Swagger文档