|
|
@@ -0,0 +1,249 @@
|
|
|
+# 用户使用流程图 — 财富能量兑换优惠券
|
|
|
+
|
|
|
+> **端口说明**: 📱 小程序 | 🖥 管理后台 | 📋 规划师端 | ⚙️ 系统自动
|
|
|
+>
|
|
|
+> **分层说明**: 🏠 页面 → 🔗 API → ⚙️ Service → 📦 数据实体
|
|
|
+
|
|
|
+## 核心概念
|
|
|
+
|
|
|
+| 概念 | 说明 |
|
|
|
+|------|------|
|
|
|
+| 财富能量 | 五维中的"富"维度能量,通过消费、推广等行为获得 |
|
|
|
+| 行动能量 | 五维中的"行"维度能量,代表行动力 |
|
|
|
+| 优惠券兑换 | 消耗财富能量兑换平台优惠券,同时同数值增加行动能量 |
|
|
|
+
|
|
|
+**兑换规则:**
|
|
|
+- 消耗 `N` 点财富能量(富维度)
|
|
|
+- 获得 `N` 点行动能量(行维度)
|
|
|
+- 获得对应面值的优惠券
|
|
|
+- 优惠券可在消费时抵扣金额
|
|
|
+
|
|
|
+```mermaid
|
|
|
+flowchart TD
|
|
|
+ %% ============ 颜色定义 ============
|
|
|
+ classDef page fill:#e3f2fd,stroke:#1565c0,stroke-width:2px
|
|
|
+ classDef api fill:#fff3e0,stroke:#f57c00,stroke-width:1px
|
|
|
+ classDef service fill:#e8f5e9,stroke:#388e3c,stroke-width:1px
|
|
|
+ classDef data fill:#f3e5f5,stroke:#7b1fa2,stroke-width:1px
|
|
|
+ classDef external fill:#fce4ec,stroke:#d32f2f,stroke-width:1px,stroke-dasharray:3 2
|
|
|
+ classDef actor fill:#e1f5fe,stroke:#0288d1,stroke-width:2px,stroke-dasharray:5 3
|
|
|
+
|
|
|
+ %% ============ 角色 ============
|
|
|
+ A0(("👤 家长")):::actor
|
|
|
+ B0(("👶 孩子")):::actor
|
|
|
+ C0(("🖥 管理员")):::actor
|
|
|
+
|
|
|
+ %% ================================================================
|
|
|
+ %% 阶段一:管理员创建可兑换优惠券
|
|
|
+ %% ================================================================
|
|
|
+ subgraph 阶段一[阶段一:管理员创建可兑换优惠券]
|
|
|
+ direction TB
|
|
|
+
|
|
|
+ P1["🖥 管理员:创建优惠券页"]:::page
|
|
|
+ P1 -->|"填写优惠券信息"| A1["🔗 POST /api/admin/coupon/create"]:::api
|
|
|
+ A1 -->|"名称, 类型, 面值, 最低消费,<br>有效期, 总量, 适用范围,<br>**wealthEnergyCost(财富能量兑换价)**"| S1["⚙️ AdminCouponController.create()"]:::service
|
|
|
+ S1 -->|"写入优惠券记录"| D1["📦 coupon 表<br>包含 wealth_energy_cost 字段"]:::data
|
|
|
+ end
|
|
|
+
|
|
|
+ %% ================================================================
|
|
|
+ %% 阶段二:查看可兑换优惠券
|
|
|
+ %% ================================================================
|
|
|
+ subgraph 阶段二[阶段二:查看可兑换优惠券]
|
|
|
+ D1 --> P2["🏠 富页面:我的优惠券"]:::page
|
|
|
+ P2 -->|"查看可兑换列表"| A2["🔗 POST /api/coupon/exchange/list"]:::api
|
|
|
+ A2 -->|"用户ID, 孩子ID"| S2["⚙️ 查询 wealth_energy_cost > 0 的优惠券"]:::service
|
|
|
+ S2 -->|"返回可兑换优惠券列表<br>含 wealthEnergyCost, 面值, 有效期"| D2["📦 可兑换优惠券列表"]:::data
|
|
|
+
|
|
|
+ D2 --> P2a["🏠 展示每张优惠券:<br>面值 10元 | 需 100 财富能量<br>面值 20元 | 需 200 财富能量"]:::page
|
|
|
+ end
|
|
|
+
|
|
|
+ %% ================================================================
|
|
|
+ %% 阶段三:兑换流程(两种入口)
|
|
|
+ %% ================================================================
|
|
|
+ subgraph 阶段三[阶段三:兑换流程]
|
|
|
+ direction TB
|
|
|
+
|
|
|
+ P3_entry{"兑换入口"}:::page
|
|
|
+ P3_entry -->|"入口A: 富页面→我的优惠券"| P3a["🏠 富页面:优惠券管理处"]:::page
|
|
|
+ P3_entry -->|"入口B: 消费时直接兑换"| P3b["🏠 商品确认页:选择优惠券"]:::page
|
|
|
+
|
|
|
+ P3a -->|"点击兑换"| P3_confirm["🏠 兑换确认弹窗:<br>消耗 100 财富能量<br>获得 10元 优惠券<br>获得 100 行动能量"]:::page
|
|
|
+ P3b -->|"可选优惠券为空<br>点击'去兑换'"| P3_confirm
|
|
|
+
|
|
|
+ P3_confirm -->|"确认兑换"| A3["🔗 POST /api/coupon/exchange"]:::api
|
|
|
+ A3 -->|"用户ID, 孩子ID, 优惠券ID"| S3["⚙️ CouponService.exchangeWithEnergy()"]:::service
|
|
|
+ end
|
|
|
+
|
|
|
+ %% ================================================================
|
|
|
+ %% 阶段四:能量扣除+发放+优惠券发放
|
|
|
+ %% ================================================================
|
|
|
+ subgraph 阶段四[阶段四:能量转换与优惠券发放]
|
|
|
+ S3 --> S4a{"⚙️ 校验财富能量余额<br>childId + wealth 维度"}:::service
|
|
|
+ S4a -->|"余额不足"| D4a["📦 返回错误: 财富能量不足"]:::data
|
|
|
+ S4a -->|"余额充足"| S4b["⚙️ ① 扣除财富能量<br>EnergyService.deductEnergyByCode()<br>dimensionCode=wealth"]:::service
|
|
|
+ S4b -->|"扣除N点, 写流水"| D4b["📦 energy_log 表<br>财富能量 -N"]:::data
|
|
|
+
|
|
|
+ S4b --> S4c["⚙️ ② 发放行动能量<br>EnergyService.awardEnergy()<br>sourceType=coupon_exchange<br>数量=N"]:::service
|
|
|
+ S4c -->|"发放N点, 写流水"| D4c["📦 energy_log 表<br>行动能量 +N<br>+ energy_balance 更新"]:::data
|
|
|
+
|
|
|
+ S4c --> S4d["⚙️ ③ 发放优惠券到用户账户<br>CouponService.issueToUser()"]:::service
|
|
|
+ S4d -->|"写入用户-优惠券关联"| D4d["📦 user_coupon 表<br>userId, couponId,<br>status=AVAILABLE"]:::data
|
|
|
+
|
|
|
+ S4d -->|"更新优惠券已领数量"| D4e["📦 coupon 表<br>usedCount++"]:::data
|
|
|
+ end
|
|
|
+
|
|
|
+ %% ================================================================
|
|
|
+ %% 阶段五:使用优惠券消费
|
|
|
+ %% ================================================================
|
|
|
+ subgraph 阶段五[阶段五:使用优惠券消费]
|
|
|
+ D4d --> P5["🏠 商品确认页:选择优惠券"]:::page
|
|
|
+ P5 -->|"查看可用优惠券"| A5["🔗 POST /api/coupon/list"]:::api
|
|
|
+ A5 -->|"用户ID"| S5["⚙️ CouponService.listAvailable()"]:::service
|
|
|
+ S5 -->|"返回可用优惠券列表"| D5["📦 用户可用优惠券列表"]:::data
|
|
|
+
|
|
|
+ P5 -->|"选择优惠券"| A5a["🔗 POST /api/coupon/apply"]:::api
|
|
|
+ A5a -->|"用户优惠券ID, 订单类型, 订单金额"| S5a["⚙️ CouponService.apply()"]:::service
|
|
|
+ S5a -->|"校验有效期/适用范围/最低消费"| D5a["📦 返回折扣金额"]:::data
|
|
|
+
|
|
|
+ P5 -->|"提交订单"| A5b["🔗 POST /api/product/order/create"]:::api
|
|
|
+ A5b -->|"商品ID, 数量, 优惠券ID"| S5b["⚙️ ProductOrderService.create()"]:::service
|
|
|
+ S5b -->|"创建订单, 标记优惠券"| D5b["📦 product_orders 表<br>coupon_id 关联"]:::data
|
|
|
+
|
|
|
+ D5b -->|"支付成功"| S5c["⚙️ CouponService.markUsed()"]:::service
|
|
|
+ S5c -->|"标记优惠券已使用"| D5c["📦 user_coupon 表<br>status=USED, orderId"]:::data
|
|
|
+ end
|
|
|
+
|
|
|
+ %% ================================================================
|
|
|
+ %% 角色关联
|
|
|
+ %% ================================================================
|
|
|
+ A0 -.- P2
|
|
|
+ A0 -.- P3a
|
|
|
+ A0 -.- P3b
|
|
|
+ A0 -.- P5
|
|
|
+ B0 -.- P3a
|
|
|
+ C0 -.- P1
|
|
|
+```
|
|
|
+
|
|
|
+## 端点明细
|
|
|
+
|
|
|
+### 优惠券兑换
|
|
|
+
|
|
|
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
|
|
|
+|------|------|------|---------|---------|
|
|
|
+| `POST /api/coupon/exchange/list` | 可兑换优惠券列表 | 📱小程序 | 用户ID, 孩子ID | 含 wealthEnergyCost 的优惠券列表 |
|
|
|
+| `POST /api/coupon/exchange` | 兑换优惠券 | 📱小程序 | 用户ID, 孩子ID, 优惠券ID | 兑换结果, 剩余财富能量 |
|
|
|
+
|
|
|
+### 能量操作
|
|
|
+
|
|
|
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
|
|
|
+|------|------|------|---------|---------|
|
|
|
+| `POST /api/energy/deduct-by-code` | 扣除指定维度能量 | ⚙️系统 | 孩子ID, 维度代码, 数量, 原因 | 扣除后余额, -1=余额不足 |
|
|
|
+| `POST /api/energy/grant` | 发放能量 | ⚙️系统 | 孩子ID, 数量, 维度代码 | 发放结果 |
|
|
|
+
|
|
|
+### 优惠券管理
|
|
|
+
|
|
|
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
|
|
|
+|------|------|------|---------|---------|
|
|
|
+| `POST /api/admin/coupon/create` | 创建优惠券(含财富能量兑换价) | 🖥管理后台 | 名称, 面值, 有效期, **wealthEnergyCost** | 成功/失败 |
|
|
|
+| `POST /api/admin/coupon/update` | 更新优惠券 | 🖥管理后台 | 优惠券ID, 更新字段 | 成功/失败 |
|
|
|
+| `POST /api/coupon/list` | 用户可用优惠券列表 | 📱小程序 | 用户ID | 可用优惠券列表 |
|
|
|
+| `POST /api/coupon/claim` | 领取免费优惠券 | 📱小程序 | 优惠券ID | 领取结果 |
|
|
|
+| `POST /api/coupon/apply` | 使用优惠券计算折扣 | 📱小程序 | 用户优惠券ID, 订单类型, 订单金额 | 折扣金额 |
|
|
|
+| `POST /api/admin/coupon/issue` | 管理员发放优惠券 | 🖥管理后台 | 优惠券ID, 用户ID列表 | 成功/失败 |
|
|
|
+
|
|
|
+## 数据实体变更
|
|
|
+
|
|
|
+### Coupon 表新增字段
|
|
|
+
|
|
|
+```mermaid
|
|
|
+erDiagram
|
|
|
+ Coupon {
|
|
|
+ Long id PK
|
|
|
+ string name "优惠券名称"
|
|
|
+ string type "FIXED/PERCENT"
|
|
|
+ int value "面值(分)"
|
|
|
+ int minSpend "最低消费(分)"
|
|
|
+ string applicableTo "适用范围"
|
|
|
+ date validFrom
|
|
|
+ date validUntil
|
|
|
+ int totalCount "总数量"
|
|
|
+ int usedCount "已使用"
|
|
|
+ int wealthEnergyCost "NEW: 兑换所需财富能量,0=不可兑换"
|
|
|
+ date createdAt
|
|
|
+ }
|
|
|
+
|
|
|
+ UserCoupon {
|
|
|
+ Long id PK
|
|
|
+ Long userId FK "用户ID"
|
|
|
+ Long couponId FK "优惠券ID"
|
|
|
+ string status "AVAILABLE/USED"
|
|
|
+ string source "NEW: 来源(claim/exchange/admin)"
|
|
|
+ date receivedAt
|
|
|
+ date usedAt
|
|
|
+ Long orderId "使用订单ID"
|
|
|
+ }
|
|
|
+```
|
|
|
+
|
|
|
+### 兑换逻辑(伪代码)
|
|
|
+
|
|
|
+```
|
|
|
+exchangeCoupon(userId, childId, couponId):
|
|
|
+ coupon = getCoupon(couponId)
|
|
|
+ if coupon.wealthEnergyCost == null || coupon.wealthEnergyCost <= 0:
|
|
|
+ return error("该优惠券不可兑换")
|
|
|
+
|
|
|
+ // 1. 扣除财富能量
|
|
|
+ wealthResult = energyService.deductEnergyByCode(childId, "wealth", coupon.wealthEnergyCost, "优惠券兑换")
|
|
|
+ if wealthResult == -1:
|
|
|
+ return error("财富能量不足")
|
|
|
+
|
|
|
+ // 2. 发放等额行动能量
|
|
|
+ energyService.awardEnergy(childId, "coupon_exchange", couponId, coupon.wealthEnergyCost, "优惠券兑换", null)
|
|
|
+
|
|
|
+ // 3. 发放优惠券
|
|
|
+ userCoupon = new UserCoupon()
|
|
|
+ userCoupon.userId = userId
|
|
|
+ userCoupon.couponId = couponId
|
|
|
+ userCoupon.status = "AVAILABLE"
|
|
|
+ userCoupon.source = "exchange"
|
|
|
+ userCoupon.receivedAt = now()
|
|
|
+ userCouponMapper.insert(userCoupon)
|
|
|
+
|
|
|
+ // 4. 更新优惠券领取计数
|
|
|
+ coupon.usedCount = (coupon.usedCount ?? 0) + 1
|
|
|
+ couponMapper.updateById(coupon)
|
|
|
+
|
|
|
+ return success("兑换成功")
|
|
|
+```
|
|
|
+
|
|
|
+## 完整性分析
|
|
|
+
|
|
|
+### 流程完整性
|
|
|
+- ✅ 管理员创建可兑换优惠券(指定 wealthEnergyCost)
|
|
|
+- ✅ 用户查看可兑换优惠券列表
|
|
|
+- ✅ 两种兑换入口(富页面/消费时)
|
|
|
+- ✅ 兑换确认弹窗展示能量消耗明细
|
|
|
+- ✅ 扣财富能量 + 发行动能量的能量转换
|
|
|
+- ✅ 优惠券发放到用户账户
|
|
|
+- ✅ 消费时使用优惠券抵扣
|
|
|
+
|
|
|
+### 异常路径
|
|
|
+- ❌ 财富能量不足时提示用户通过消费/推广积累
|
|
|
+- ❌ 优惠券库存不足的提示
|
|
|
+- ❌ 兑换失败时能量回滚(事务处理)
|
|
|
+- ❌ 优惠券过期后的兑换限制
|
|
|
+
|
|
|
+### 角色覆盖
|
|
|
+- ✅ 管理员(创建可兑换优惠券)
|
|
|
+- ✅ 家长(查看/兑换/使用优惠券)
|
|
|
+- ✅ 孩子(查看/兑换优惠券)
|
|
|
+
|
|
|
+### 数据流向
|
|
|
+- ✅ 管理员创建 → 用户查看 → 兑换→扣能量→发能量→发券→消费使用
|
|
|
+
|
|
|
+### 前端页面建议
|
|
|
+| 页面 | 说明 |
|
|
|
+|------|------|
|
|
|
+| 富页面 → 我的优惠券 | 展示已拥有的优惠券 + 可兑换的优惠券 |
|
|
|
+| 商品确认页 → 选择优惠券 | 支持直接兑换(如果无可用优惠券) |
|
|
|
+| 兑换确认弹窗 | 显示消耗/获得的能量明细 |
|