mirror of
https://codeup.aliyun.com/67c68d4e484ca2f0a13ac3c1/ydc/jsowell-charger-web.git
synced 2026-04-20 11:05:18 +08:00
369 lines
18 KiB
Markdown
369 lines
18 KiB
Markdown
# PRD:优惠券功能
|
||
|
||
**版本**: v1.1
|
||
**日期**: 2026-03-03
|
||
**项目**: 万车充运营管理平台
|
||
**状态**: 草稿
|
||
|
||
---
|
||
|
||
## 变更记录
|
||
|
||
| 版本 | 日期 | 变更内容 |
|
||
|------|------|---------|
|
||
| v1.0 | 2026-03-03 | 初稿:积分兑换洗车券功能 |
|
||
| v1.1 | 2026-03-03 | 新增:券创建权限体系(平台人员 vs 运营商人员);新增充电折扣券规划;更新数据库设计与业务规则 |
|
||
|
||
---
|
||
|
||
## 一、背景与目标
|
||
|
||
### 背景
|
||
|
||
平台现有积分系统(`member_points_info`)支持充电消费奖励积分,但积分使用场景单一(仅支持抵扣充电费用)。为提升用户留存与活跃度,引入优惠券体系,首期以「积分兑换洗车券」为切入点,同时建立支持平台与运营商双层管理的券权限体系,为后续充电折扣券等功能奠定基础。
|
||
|
||
### 目标
|
||
|
||
- 为用户提供积分消耗渠道,提升积分价值感知
|
||
- 通过洗车权益与充电绑定,增强用户充电粘性
|
||
- 建立可扩展的优惠券基础架构,支持后续更多券类型
|
||
- 建立平台与运营商双层券管理权限,支持精细化运营
|
||
|
||
### 成功指标
|
||
|
||
- 积分兑换率(兑换用户数 / 持有积分用户数)≥ 15%
|
||
- 洗车券核销率 ≥ 60%
|
||
- 功能上线后次月充电频次同比提升 ≥ 5%
|
||
|
||
---
|
||
|
||
## 二、用户角色
|
||
|
||
| 角色 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| **平台管理员** | 创券方 | 平台运营人员,可创建全平台范围或指定运营商范围的优惠券 |
|
||
| **运营商管理员** | 创券方 | 运营商后台人员,只能创建本运营商范围内可用的优惠券 |
|
||
| **会员用户** | 使用方 | 通过充电获得积分,在 App/小程序中兑换并使用券 |
|
||
| **合作洗车商** | 核销方 | 扫码核销洗车券(可通过独立 H5 页面或 API 对接) |
|
||
|
||
---
|
||
|
||
## 三、券可用范围权限设计
|
||
|
||
### 3.1 核心规则
|
||
|
||
| 创建人角色 | 可设置的最大可用范围 | 说明 |
|
||
|-----------|-------------------|------|
|
||
| **平台管理员** | 全平台 | 可选:全平台 / 指定运营商 / 指定站点 |
|
||
| **运营商管理员** | 本运营商 | 可选:本运营商全部站点 / 指定站点(仅限本运营商下) |
|
||
|
||
### 3.2 可用范围枚举
|
||
|
||
| 范围值 | 说明 | 可创建角色 |
|
||
|--------|------|----------|
|
||
| `1` - 全平台 | 所有运营商、所有站点均可使用 | 仅平台管理员 |
|
||
| `2` - 指定运营商 | 仅指定运营商下的站点可使用 | 平台管理员(可多选);运营商管理员(固定为本运营商) |
|
||
| `3` - 指定站点 | 仅指定站点可使用 | 平台管理员;运营商管理员(仅限本运营商下的站点) |
|
||
|
||
### 3.3 业务规则
|
||
|
||
1. 运营商管理员创建券时,`scope_type` 最高只能选 `2`(本运营商),**不能选** `1`(全平台)
|
||
2. 运营商管理员创建的指定站点券,`scope_merchant_id` 强制写入本运营商 ID,不可修改
|
||
3. 平台管理员可查看所有运营商的券;运营商管理员只能查看和管理本运营商创建的券
|
||
4. 用户兑换或领取券时,系统根据券的 `scope_type` 及关联数据校验该用户是否符合领取资格(如充电站是否在券可用范围内)
|
||
5. 充电折扣券使用时额外校验:本次充电所在站点是否在券的可用范围内
|
||
|
||
---
|
||
|
||
## 四、功能范围(首期 v1.0)
|
||
|
||
### 4.1 功能清单
|
||
|
||
| 模块 | 功能点 | 优先级 |
|
||
|------|--------|--------|
|
||
| 券模板管理 | 平台管理员创建/编辑/下架洗车券模板 | P0 |
|
||
| 券模板管理 | 运营商管理员创建/编辑/下架洗车券模板 | P0 |
|
||
| 券模板管理 | 设置券可用范围(全平台 / 指定运营商 / 指定站点) | P0 |
|
||
| 券模板管理 | 设置积分兑换比例(N 积分 = 1 张券) | P0 |
|
||
| 券模板管理 | 设置券有效期(固定日期 / 领取后 N 天) | P0 |
|
||
| 积分兑换 | 用户查看可兑换券列表 | P0 |
|
||
| 积分兑换 | 用户用积分兑换洗车券 | P0 |
|
||
| 积分兑换 | 兑换记录查询 | P0 |
|
||
| 我的券包 | 查看持有的洗车券(未使用/已使用/已过期) | P0 |
|
||
| 券核销 | 展示券码(二维码 / 核销码) | P0 |
|
||
| 券核销 | 合作商扫码核销 | P0 |
|
||
| 数据看板 | 兑换量、核销量、积分消耗统计 | P1 |
|
||
| 运营配置 | 单用户每日/每月兑换上限 | P1 |
|
||
| 运营配置 | 券库存上限控制 | P1 |
|
||
|
||
### 4.2 首期不包含
|
||
|
||
- 现金购买券
|
||
- 券转赠
|
||
- 充电折扣券(规划于 v1.2)
|
||
- 第三方洗车平台 API 对接(仅本地核销)
|
||
|
||
---
|
||
|
||
## 五、业务流程
|
||
|
||
### 5.1 创建券模板流程
|
||
|
||
```
|
||
管理员进入券模板管理页
|
||
→ 选择券类型(首期仅洗车券)
|
||
→ 系统根据登录角色自动限制可用范围选项
|
||
├─ 平台管理员:可选 全平台 / 指定运营商 / 指定站点
|
||
└─ 运营商管理员:可选 本运营商 / 本运营商下指定站点
|
||
→ 填写积分兑换价格、库存、有效期、兑换限额等配置
|
||
→ 提交 → 系统二次校验 scope 权限边界
|
||
→ 保存,默认下架状态,手动上架后对用户可见
|
||
```
|
||
|
||
### 5.2 积分兑换流程
|
||
|
||
```
|
||
用户进入积分商城
|
||
→ 系统查询该用户可见的洗车券列表
|
||
(过滤逻辑:券为上架状态 + 未过期 + 有库存 + 用户所在运营商/站点在券可用范围内)
|
||
→ 用户查看洗车券兑换入口(展示所需积分、库存、有效期)
|
||
→ 确认兑换
|
||
→ 系统校验:积分是否足够 + 库存是否充足 + 兑换限额检查
|
||
→ 原子操作:扣减积分 + 生成用户券记录
|
||
→ 写入积分变更日志(member_points_record,类型=积分兑换消耗)
|
||
→ 返回兑换成功,展示券码
|
||
```
|
||
|
||
### 5.3 洗车券核销流程
|
||
|
||
```
|
||
用户出示洗车券二维码
|
||
→ 洗车商扫码 → 调用核销接口
|
||
→ 系统校验:券是否有效 + 是否已使用 + 是否在有效期内
|
||
→ 更新券状态为「已使用」,记录核销时间、核销门店
|
||
→ 核销成功响应
|
||
```
|
||
|
||
---
|
||
|
||
## 六、数据库设计
|
||
|
||
### 6.1 券模板表 `coupon_template`
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| `id` | bigint PK | 主键 |
|
||
| `name` | varchar(50) | 券名称,如"洗车券" |
|
||
| `type` | tinyint | 券类型:1=洗车券 2=充电折扣券 |
|
||
| `creator_type` | tinyint | 创建人类型:1=平台管理员 2=运营商管理员 |
|
||
| `creator_merchant_id` | bigint | 创建人所属运营商 ID(平台管理员为 NULL) |
|
||
| `scope_type` | tinyint | 可用范围:1=全平台 2=指定运营商 3=指定站点 |
|
||
| `points_cost` | int | 兑换所需积分(洗车券用) |
|
||
| `discount_rate` | decimal(4,2) | 折扣比例(充电折扣券用,如 0.85 表示 85 折) |
|
||
| `stock_total` | int | 总库存(-1 表示不限制) |
|
||
| `stock_remain` | int | 剩余库存 |
|
||
| `validity_type` | tinyint | 有效期类型:1=固定日期 2=领取后N天 |
|
||
| `valid_start_time` | datetime | 固定有效期开始(validity_type=1) |
|
||
| `valid_end_time` | datetime | 固定有效期结束(validity_type=1) |
|
||
| `valid_days` | int | 领取后有效天数(validity_type=2) |
|
||
| `daily_limit` | int | 单用户每日兑换上限(0=不限) |
|
||
| `monthly_limit` | int | 单用户每月兑换上限(0=不限) |
|
||
| `status` | tinyint | 状态:0=下架 1=上架 |
|
||
| `description` | varchar(500) | 券使用说明 |
|
||
| `create_by` | varchar(64) | 创建人账号 |
|
||
| `create_time` | datetime | 创建时间 |
|
||
| `update_time` | datetime | 更新时间 |
|
||
| `del_flag` | char(1) | 删除标志 |
|
||
|
||
### 6.2 券可用范围明细表 `coupon_template_scope`
|
||
|
||
> 用于存储 `scope_type=2`(指定运营商)或 `scope_type=3`(指定站点)时的具体关联数据
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| `id` | bigint PK | 主键 |
|
||
| `template_id` | bigint | 关联券模板 ID |
|
||
| `scope_type` | tinyint | 范围类型:2=运营商 3=站点 |
|
||
| `scope_id` | bigint | 运营商 ID 或站点 ID |
|
||
|
||
### 6.3 用户券表 `member_coupon`
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| `id` | bigint PK | 主键 |
|
||
| `coupon_no` | varchar(32) | 券编号(唯一,用于核销) |
|
||
| `template_id` | bigint | 关联券模板 ID |
|
||
| `member_id` | bigint | 关联会员 ID |
|
||
| `coupon_type` | tinyint | 券类型快照:1=洗车券 2=充电折扣券 |
|
||
| `points_cost` | int | 兑换时消耗的积分(快照,折扣券为 0) |
|
||
| `discount_rate` | decimal(4,2) | 折扣比例快照(洗车券为 NULL) |
|
||
| `status` | tinyint | 状态:0=未使用 1=已使用 2=已过期 |
|
||
| `source` | tinyint | 来源:1=积分兑换 |
|
||
| `exchange_time` | datetime | 兑换时间 |
|
||
| `expire_time` | datetime | 过期时间 |
|
||
| `use_time` | datetime | 核销时间 |
|
||
| `use_store_id` | bigint | 核销门店/站点 ID |
|
||
| `use_operator` | varchar(64) | 核销操作人 |
|
||
| `create_time` | datetime | 创建时间 |
|
||
| `del_flag` | char(1) | 删除标志 |
|
||
|
||
### 6.4 依赖现有表
|
||
|
||
- `member_points_info`:积分余额更新
|
||
- `member_points_record`:新增消耗类型(`type=3` 积分兑换)
|
||
- `pile_merchant_info`:运营商信息(校验 creator_merchant_id)
|
||
- `pile_station_info`:站点信息(校验 scope 范围)
|
||
|
||
---
|
||
|
||
## 七、接口设计
|
||
|
||
### App/小程序端
|
||
|
||
| 接口 | 方法 | 说明 |
|
||
|------|------|------|
|
||
| `/coupon/template/list` | GET | 获取用户可兑换券模板列表(按用户所属范围过滤) |
|
||
| `/coupon/exchange` | POST | 积分兑换(入参:templateId) |
|
||
| `/coupon/my/list` | GET | 我的券包列表(入参:status) |
|
||
| `/coupon/my/detail/{couponNo}` | GET | 券详情(含核销二维码) |
|
||
|
||
### 管理后台
|
||
|
||
| 接口 | 方法 | 说明 |
|
||
|------|------|------|
|
||
| `/admin/coupon/template/list` | GET | 券模板列表(运营商管理员仅返回本运营商数据) |
|
||
| `/admin/coupon/template/add` | POST | 新增券模板(含 scope 权限校验) |
|
||
| `/admin/coupon/template/edit` | PUT | 编辑券模板 |
|
||
| `/admin/coupon/template/changeStatus` | PUT | 上下架 |
|
||
| `/admin/coupon/record/list` | GET | 兑换记录查询(运营商管理员仅查本运营商数据) |
|
||
| `/admin/coupon/verify` | POST | 核销券(入参:couponNo) |
|
||
| `/admin/coupon/stats` | GET | 数据统计(运营商管理员仅查本运营商数据) |
|
||
|
||
---
|
||
|
||
## 八、关键业务规则
|
||
|
||
1. **原子性保障**:扣减积分与生成券记录必须在同一事务中完成,防止积分扣了但券没生成
|
||
2. **库存防超卖**:使用数据库乐观锁(`UPDATE ... WHERE stock_remain >= 1`)或 Redis 原子操作控制库存
|
||
3. **幂等兑换**:前端提交带客户端请求 ID,防止重复点击导致多次扣分
|
||
4. **券码安全**:`coupon_no` 使用 UUID 或带校验位的随机串,不可预测
|
||
5. **过期处理**:Quartz 定时任务每日凌晨扫描并更新过期券状态
|
||
6. **积分变更日志**:兑换成功后写入 `member_points_record`,确保积分流水可追溯
|
||
7. **Scope 权限隔离**:
|
||
- 运营商管理员提交创建/编辑接口时,后端强制校验 `scope_type <= 2`,且 `creator_merchant_id` 必须与登录账号所属运营商一致,防止越权
|
||
- 运营商管理员只能查看和操作本运营商创建的券模板,列表接口自动按 `creator_merchant_id` 过滤
|
||
8. **折扣券使用校验**(v1.2 实现):充电结算时校验充电站是否在折扣券的 `scope` 范围内,不在范围内的券不可抵扣
|
||
|
||
---
|
||
|
||
## 九、非功能需求
|
||
|
||
| 项目 | 要求 |
|
||
|------|------|
|
||
| 性能 | 兑换接口 P99 < 500ms |
|
||
| 并发 | 支持同一券模板 100 QPS 并发兑换 |
|
||
| 可靠性 | 积分扣减与券生成保证原子性 |
|
||
| 安全 | 核销接口需鉴权;创券接口需强制 scope 边界校验,防止运营商越权 |
|
||
|
||
---
|
||
|
||
## 十、数据库建表语句
|
||
|
||
```sql
|
||
-- ----------------------------
|
||
-- 券模板表
|
||
-- ----------------------------
|
||
CREATE TABLE `coupon_template` (
|
||
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||
`name` VARCHAR(50) NOT NULL COMMENT '券名称,如洗车券',
|
||
`type` TINYINT NOT NULL DEFAULT 1 COMMENT '券类型:1=洗车券 2=充电折扣券',
|
||
`creator_type` TINYINT NOT NULL DEFAULT 1 COMMENT '创建人类型:1=平台管理员 2=运营商管理员',
|
||
`creator_merchant_id` BIGINT DEFAULT NULL COMMENT '创建人所属运营商ID,平台管理员为NULL',
|
||
`scope_type` TINYINT NOT NULL DEFAULT 1 COMMENT '可用范围:1=全平台 2=指定运营商 3=指定站点',
|
||
`points_cost` INT DEFAULT NULL COMMENT '兑换所需积分(洗车券使用)',
|
||
`discount_rate` DECIMAL(4, 2) DEFAULT NULL COMMENT '折扣比例(充电折扣券使用,如0.85表示85折)',
|
||
`stock_total` INT NOT NULL DEFAULT -1 COMMENT '总库存,-1表示不限制',
|
||
`stock_remain` INT NOT NULL DEFAULT -1 COMMENT '剩余库存,-1表示不限制',
|
||
`validity_type` TINYINT NOT NULL DEFAULT 2 COMMENT '有效期类型:1=固定日期 2=领取后N天',
|
||
`valid_start_time` DATETIME DEFAULT NULL COMMENT '固定有效期开始时间(validity_type=1时有效)',
|
||
`valid_end_time` DATETIME DEFAULT NULL COMMENT '固定有效期结束时间(validity_type=1时有效)',
|
||
`valid_days` INT DEFAULT NULL COMMENT '领取后有效天数(validity_type=2时有效)',
|
||
`daily_limit` INT NOT NULL DEFAULT 0 COMMENT '单用户每日兑换上限,0=不限',
|
||
`monthly_limit` INT NOT NULL DEFAULT 0 COMMENT '单用户每月兑换上限,0=不限',
|
||
`status` TINYINT NOT NULL DEFAULT 0 COMMENT '状态:0=下架 1=上架',
|
||
`description` VARCHAR(500) DEFAULT NULL COMMENT '券使用说明',
|
||
`create_by` VARCHAR(64) DEFAULT '' COMMENT '创建人账号',
|
||
`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||
`update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||
`del_flag` CHAR(1) NOT NULL DEFAULT '0' COMMENT '删除标志:0=存在 2=删除',
|
||
PRIMARY KEY (`id`),
|
||
KEY `idx_creator_merchant` (`creator_merchant_id`, `status`, `del_flag`),
|
||
KEY `idx_scope_type` (`scope_type`, `status`)
|
||
) ENGINE = InnoDB
|
||
DEFAULT CHARSET = utf8mb4
|
||
COMMENT = '优惠券模板表';
|
||
|
||
|
||
-- ----------------------------
|
||
-- 券可用范围明细表(scope_type=2 或 3 时使用)
|
||
-- ----------------------------
|
||
CREATE TABLE `coupon_template_scope` (
|
||
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||
`template_id` BIGINT NOT NULL COMMENT '关联券模板ID',
|
||
`scope_type` TINYINT NOT NULL COMMENT '范围类型:2=运营商 3=站点',
|
||
`scope_id` BIGINT NOT NULL COMMENT '运营商ID 或 站点ID',
|
||
PRIMARY KEY (`id`),
|
||
KEY `idx_template_id` (`template_id`),
|
||
UNIQUE KEY `uk_template_scope` (`template_id`, `scope_type`, `scope_id`)
|
||
) ENGINE = InnoDB
|
||
DEFAULT CHARSET = utf8mb4
|
||
COMMENT = '优惠券可用范围明细表';
|
||
|
||
|
||
-- ----------------------------
|
||
-- 用户券表
|
||
-- ----------------------------
|
||
CREATE TABLE `member_coupon` (
|
||
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||
`coupon_no` VARCHAR(32) NOT NULL COMMENT '券编号(唯一,用于核销)',
|
||
`template_id` BIGINT NOT NULL COMMENT '关联券模板ID',
|
||
`member_id` BIGINT NOT NULL COMMENT '关联会员ID',
|
||
`coupon_type` TINYINT NOT NULL COMMENT '券类型快照:1=洗车券 2=充电折扣券',
|
||
`points_cost` INT NOT NULL DEFAULT 0 COMMENT '兑换时消耗的积分快照,折扣券为0',
|
||
`discount_rate` DECIMAL(4, 2) DEFAULT NULL COMMENT '折扣比例快照,洗车券为NULL',
|
||
`status` TINYINT NOT NULL DEFAULT 0 COMMENT '状态:0=未使用 1=已使用 2=已过期',
|
||
`source` TINYINT NOT NULL DEFAULT 1 COMMENT '来源:1=积分兑换',
|
||
`exchange_time` DATETIME DEFAULT NULL COMMENT '兑换时间',
|
||
`expire_time` DATETIME NOT NULL COMMENT '过期时间',
|
||
`use_time` DATETIME DEFAULT NULL COMMENT '核销时间',
|
||
`use_store_id` BIGINT DEFAULT NULL COMMENT '核销门店/站点ID',
|
||
`use_operator` VARCHAR(64) DEFAULT NULL COMMENT '核销操作人',
|
||
`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||
`del_flag` CHAR(1) NOT NULL DEFAULT '0' COMMENT '删除标志:0=存在 2=删除',
|
||
PRIMARY KEY (`id`),
|
||
UNIQUE KEY `uk_coupon_no` (`coupon_no`),
|
||
KEY `idx_member_id` (`member_id`, `status`),
|
||
KEY `idx_template_id` (`template_id`),
|
||
KEY `idx_expire_time` (`expire_time`, `status`)
|
||
) ENGINE = InnoDB
|
||
DEFAULT CHARSET = utf8mb4
|
||
COMMENT = '会员优惠券表';
|
||
```
|
||
|
||
> **索引说明**
|
||
> - `coupon_template.idx_creator_merchant`:运营商管理员查看本运营商券模板列表的高频查询
|
||
> - `coupon_template_scope.uk_template_scope`:防止同一模板下重复添加相同范围记录
|
||
> - `member_coupon.idx_expire_time`:供 Quartz 定时任务扫描过期券使用
|
||
> - `member_coupon.uk_coupon_no`:唯一索引防止重复券码、保证核销安全
|
||
|
||
---
|
||
|
||
## 十一、后续迭代规划
|
||
|
||
| 阶段 | 功能 |
|
||
|------|------|
|
||
| v1.1 | 第三方洗车平台 API 对接(自动核销) |
|
||
| v1.2 | 充电折扣券:运营商/平台创建折扣券,充电结算时自动抵扣,校验站点范围 |
|
||
| v1.3 | 运营活动:充电满额赠券、节日送券 |
|
||
| v2.0 | 积分商城完整体验(多商品、排行榜) |
|