6.9 KiB
6.9 KiB
促销活动用户端展示方案
现状分析
- 后端已有用户端促销查询 API:
GET /api/v1/promotions/skill/{skillId}— 查询单个 Skill 的促销信息POST /api/v1/promotions/skills/batch— 批量查询促销信息
- 前端
SkillCard.vue和detail.vue尚未调用这些 API,也没有展示促销标签、促销价等信息 - 当前用户看到的只有:原价、划线价、"新品/免费/热门"标签
展示触点与优先级
促销信息应出现在 4 个触点,形成从"发现 → 浏览 → 决策"的完整转化路径:
| 优先级 | 触点 | 工作量 | 转化价值 |
|---|---|---|---|
| P0 | SkillCard 组件(促销标签 + 价格替换) | 小 | 高(覆盖所有列表场景) |
| P0 | Skill 详情页(促销信息条 + 价格替换) | 中 | 最高(直接影响购买决策) |
| P1 | 首页新增"限时特惠"专区 | 中 | 高(流量入口曝光) |
| P2 | 商城列表页新增"促销中"筛选项 | 小 | 中(锦上添花) |
P0-1:SkillCard 组件 — 促销角标 + 价格替换
位置
frontend/src/components/SkillCard.vue
改动点
1. 封面左上角标签区
- 有促销时,在已有标签(新品/免费/热门)旁新增一个红色促销标签
- 标签文字使用后端返回的
tagText(如"限时特惠"、"618折扣") - 若
tagText为空则显示默认文案"促销中"
<!-- 新增促销标签 -->
<a-tag v-if="promotion" color="red">{{ promotion.tagText || '促销中' }}</a-tag>
2. 底部价格区域
- 有促销时:促销价作为主价格显示,原价显示为划线样式
- 无促销时:保持现有逻辑不变
<!-- 有促销时的价格展示 -->
<span v-if="promotion" class="price promotion">
<span class="promo-price">¥{{ promotion.promotionPrice || calcDiscountPrice }}</span>
<span class="original">¥{{ skill.price }}</span>
</span>
3. 数据获取方式
- 方案 A(推荐):在列表页加载 Skill 列表后,批量调用
POST /promotions/skills/batch获取促销信息,合并到 skill 数据中传给 SkillCard - 方案 B:SkillCard 内部自己请求(不推荐,N+1 问题)
涉及文件
frontend/src/components/SkillCard.vue— 添加促销标签和价格展示frontend/src/views/skill/list.vue— 批量获取促销数据frontend/src/views/home/index.vue— 首页推荐区也需批量获取frontend/src/service/apiService.js— 新增用户端促销 API 调用
P0-2:Skill 详情页 — 促销信息条 + 价格替换
位置
frontend/src/views/skill/detail.vue
改动点
1. 价格区域上方新增促销横条
- 醒目的渐变背景横条,包含:
- 促销标签(tagText)
- 倒计时:
距结束 XX:XX:XX - 节省金额:
省 ¥XX
<div v-if="promotion" class="promotion-banner">
<div class="promo-tag">{{ promotion.tagText || '限时折扣' }}</div>
<div class="promo-countdown">
<ClockCircleOutlined />
距结束 {{ countdown }}
</div>
<div class="promo-save">省 ¥{{ savingAmount }}</div>
</div>
2. 价格区域替换
- 促销价作为主价格(大字、红色/品牌色)
- 原价小字划线
- 折扣率角标(如 "8折")
<div class="skill-price" v-if="promotion">
<span class="promo-label">促销价</span>
<span class="promo-current">¥{{ promotionFinalPrice }}</span>
<span class="original-price">¥{{ skill.price }}</span>
<a-tag color="red" v-if="promotion.discountRate">
{{ Math.round(promotion.discountRate * 10) }}折
</a-tag>
</div>
3. 购买按钮文案变化
- 有促销时:按钮文案从"现金购买"变为"立即抢购"
- 可选:按钮旁显示库存紧张提示(如
promotion.stockLimit - promotion.soldCount较小时)
4. 数据获取
- 在详情页
onMounted时调用GET /promotions/skill/{skillId}获取促销信息
涉及文件
frontend/src/views/skill/detail.vue— 促销横条、价格替换、按钮文案frontend/src/service/apiService.js— 用户端促销 API
P1:首页 — 限时特惠专区
位置
frontend/src/views/home/index.vue,在"热门分类"(category-section)和"精选推荐"(content-section)之间
展示形式
- 区块标题:
限时特惠+ 全局倒计时(取最近结束的促销活动时间) - 横向滚动卡片列表,每张卡片展示:
- Skill 封面缩略图
- Skill 名称
- 促销价 + 原价划线
- 促销标签(tagText)
- 折扣率角标
- 右侧"查看更多"按钮跳转到商城列表页(带促销筛选)
数据获取
- 需要后端新增接口:
GET /promotions/active-skills— 返回当前所有进行中促销关联的 Skill 列表(含促销信息) - 或前端先获取活动列表再批量查询(多一次请求但不需改后端)
涉及文件
frontend/src/views/home/index.vue— 新增促销专区- 可能需要后端新增接口
P2:商城列表页 — 促销筛选
位置
frontend/src/views/skill/list.vue 筛选栏
改动点
- 筛选栏新增一个"促销中"筛选项(标签按钮或下拉选项)
- 选中后只显示有促销的 Skill
实现方式
- 方案 A:后端支持
hasPromotion=true查询参数 - 方案 B:前端获取所有促销 Skill ID 后前端过滤(数据量小时可行)
涉及文件
frontend/src/views/skill/list.vue— 新增筛选项- 可能需要后端 Skill 列表接口支持促销筛选参数
前端新增 API 汇总
在 frontend/src/service/apiService.js 中新增用户端促销 API:
// ===================== 促销模块(用户端) =====================
export const promotionApi = {
// 查询单个 Skill 的促销信息
getSkillPromotion: (skillId) => api.get(`/promotions/skill/${skillId}`),
// 批量查询多个 Skill 的促销信息
batchGetSkillPromotions: (skillIds) => api.post('/promotions/skills/batch', skillIds),
}
样式规范
| 元素 | 颜色 | 字号 | 说明 |
|---|---|---|---|
| 促销标签 | #ff4d4f(红色) |
12px | 与"热门"标签同层 |
| 促销价 | #ff4d4f 或品牌主色 |
20px bold | 替代原价作为主价格 |
| 原价划线 | var(--text-muted) |
12px | 划线样式 |
| 促销横条背景 | 渐变 #fff1f0 → #fff7e6 |
— | 温暖的促销氛围 |
| 倒计时 | #ff4d4f |
14px | 紧迫感 |
| 折扣角标 | #ff4d4f 背景白字 |
11px bold | 如 "8折" |
实施顺序
- apiService.js — 新增用户端促销 API 方法
- SkillCard.vue — 接收 promotion prop,展示标签和促销价
- list.vue — 加载列表后批量获取促销,传给 SkillCard
- home/index.vue — 首页推荐区也做相同处理
- detail.vue — 详情页促销横条、价格替换、按钮文案
- (P1)首页限时特惠专区
- (P2)列表页促销筛选