points-exchange-flow.md 15 KB

用户使用流程图 — 积分兑换

端口说明: 📱 小程序 | 🖥 管理后台 | 📋 规划师端 | ⚙️ 系统自动

分层说明: 🏠 页面 → 🔗 API → ⚙️ Service → 📦 数据实体

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

    %% ============ 角色 ============
    ROLE_PARENT(("👤 家长")):::actor
    ROLE_CHILD(("👶 孩子")):::actor
    ROLE_SYSTEM(("⚙️ 积分引擎")):::actor

    %% ================================================================
    %% 阶段一:积分概览
    %% ================================================================
    subgraph 阶段一[阶段一:积分概览]
        direction TB

        P1["🏠 小程序:积分中心"]:::page
        P1 -->|"选择操作"| P1_choice{"查看余额 / 流水 / 系统积分"}

        P1_choice -->|"查看余额"| P1a["🏠 积分余额页"]
        P1a -->|"孩子ID"| A1["🔗 POST /api/points/balance"]:::api
        A1 -->|"孩子ID"| S1["⚙️ PointsService.getBalance()"]:::service
        S1 -->|"当前积分 + 过期时间"| D1["📦 family_members 表(totalPoints查询)"]:::data

        P1_choice -->|"积分流水"| P1b["🏠 积分流水页"]
        P1b -->|"孩子ID, 分页"| A2["🔗 POST /api/points/logs"]:::api
        A2 -->|"孩子ID, 页码, 页大小"| S2["⚙️ PointsService.getPointsLogs()"]:::service
        S2 -->|"积分变动记录(类型+金额+描述)"| D2["📦 points_logs 表"]:::data

        P1_choice -->|"按分类筛选"| P1c["🏠 流水分类筛选"]
        P1c -->|"孩子ID, 分类, 分页"| A3["🔗 POST /api/points/logs-by-category"]:::api
        A3 -->|"分类(task/system)"| S3["⚙️ PointsService.getPointsLogsByCategory()"]:::service
        S3 -->|"按分类过滤的流水"| D2

        P1_choice -->|"系统积分余额"| P1d["🏠 系统积分页"]
        P1d -->|"孩子ID"| A4["🔗 POST /api/points/system-balance"]:::api
        A4 -->|"孩子ID"| S4["⚙️ PointsService.getSystemPointsBalance()"]:::service
        S4 -->|"系统积分数量"| D1
    end

    %% ================================================================
    %% 阶段二:积分调整
    %% ================================================================
    subgraph 阶段二[阶段二:积分调整]
        D1 -->|"孩子积分"| P2["🖥 管理后台:积分调整页"]:::page
        P2 -->|"手动调整"| A5["🔗 POST /api/points/adjust"]:::api
        A5 -->|"孩子ID, 调整金额, 原因, 家长密码"| S5["⚙️ PointsService.adjustPoints()"]:::service
        S5 -->|"更新余额 + 写入流水"| D1
        S5 -->|"调整记录"| D2

        P2 -->|"系统发放"| P2a["⚙️ 系统自动奖励"]
        P2a -->|"孩子ID, 金额, 原因"| S5a["⚙️ PointsService.awardSystemPoints()"]:::service
        S5a -->|"增加系统积分 + 流水"| D1
        S5a -->|"奖励记录"| D2

        P2a -->|"系统扣除"| P2b["⚙️ 系统自动扣除"]
        P2b -->|"孩子ID, 金额, 原因"| S5b["⚙️ PointsService.deductSystemPoints()"]:::service
        S5b -->|"余额不足返回-1, 否则扣除"| D1
        S5b -->|"扣除记录"| D2
    end

    %% ================================================================
    %% 阶段三:积分兑换商城
    %% ================================================================
    subgraph 阶段三[阶段三:积分兑换商城]
        D1 -->|"积分余额"| P3["📱 小程序:兑换商城页"]:::page
        P3 -->|"商品列表"| A6["🔗 POST /api/points/exchange/product/list"]:::api
        A6 -->|"分类, 分页"| S6["⚙️ PointsExchangeService.getProductList()"]:::service
        S6 -->|"已启用的兑换商品(按排序)"| D3["📦 points_exchange_products 表"]:::data

        P3 -->|"商品详情"| P3a["📱 商品详情页"]
        P3a -->|"商品ID"| A7["🔗 POST /api/points/exchange/product/detail"]:::api
        A7 -->|"商品ID"| S7["⚙️ PointsExchangeService.getProductDetail()"]:::service
        S7 -->|"商品完整信息"| D3

        P3a -->|"提交兑换"| P3b["📱 兑换确认"]
        P3b -->|"商品ID, 孩子ID, 数量"| A8["🔗 POST /api/points/exchange/submit"]:::api
        A8 -->|"商品ID, 孩子ID, 数量"| S8["⚙️ PointsExchangeService.exchangeProduct()"]:::service
        S8 -->|"校验库存/每日限额/积分→扣积分→生成兑换码"| S8a["⚙️ PointsService.deductSystemPoints()"]:::service
        S8a -->|"扣除积分"| D1
        S8 -->|"写入兑换记录"| D4["📦 points_exchange_records 表"]:::data
        S8 -->|"扣减库存"| D3

        P3 -->|"兑换记录"| P3c["📱 兑换记录页"]
        P3c -->|"用户ID"| A9["🔗 POST /api/points/exchange/records"]:::api
        A9 -->|"用户ID"| S9["⚙️ PointsExchangeService.getExchangeRecords()"]:::service
        S9 -->|"兑换记录列表"| D4

        P3 -->|"兑换统计"| P3d["📱 今日兑换次数"]
        P3d -->|"用户ID"| A10["🔗 POST /api/points/exchange/stats"]:::api
        A10 -->|"用户ID"| S10["⚙️ PointsExchangeService.getExchangeStats()"]:::service
        S10 -->|"今日兑换次数"| D4
    end

    %% ================================================================
    %% 阶段四:奖励心愿系统
    %% ================================================================
    subgraph 阶段四[阶段四:奖励心愿系统]
        D1 -->|"孩子积分"| P4["📱 孩子端:心愿页"]:::page
        P4 -->|"创建心愿"| P4a["📱 心愿表单"]
        P4a -->|"标题, 分类"| A11["🔗 POST /api/rewards/create"]:::api
        A11 -->|"用户ID, 标题, 分类, 孩子ID"| S11["⚙️ RewardService.createReward()"]:::service
        S11 -->|"写入心愿, 状态=available"| D5["📦 rewards 表"]:::data

        P4a -->|"创建心愿(孩子→等待家长填积分)"| P4b["📱 孩子创建待审批心愿"]
        P4b -->|"标题, 分类"| A11a["🔗 POST /api/reward-wishlist/create"]:::api
        A11a -->|"用户ID, 心愿信息"| S11a["⚙️ RewardWishlistService.create()"]:::service
        S11a -->|"写入心愿单, 状态=pending"| D6["📦 reward_wishlists 表"]:::data

        P4 -->|"心愿列表"| P4c["📱 心愿列表"]
        P4c -->|"孩子ID"| A12["🔗 POST /api/rewards/wishlist"]:::api
        A12 -->|"孩子ID"| S12["⚙️ RewardService.getWishlist()"]:::service
        S12 -->|"可兑换的心愿列表"| D5

        P4 -->|"奖励模板"| P4d["📱 奖励模板"]
        P4d -->|""| A13["🔗 POST /api/rewards/templates"]:::api
        A13 -->|""| S13["⚙️ RewardService.getTemplates()"]:::service
        S13 -->|"奖励模板列表"| D5

        D5 -->|"可兑换心愿"| P4e["📱 兑换心愿"]
        P4e -->|"心愿ID, 孩子ID"| A14["🔗 POST /api/rewards/{id}/exchange"]:::api
        A14 -->|"心愿ID, 孩子ID"| S14["⚙️ RewardService.exchangeReward()"]:::service
        S14 -->|"校验积分→扣积分→状态=pending"| D1
        S14 -->|"记录积分消耗"| D2
        S14 -->|"更新心愿状态"| D5

        D6 -->|"待审批心愿"| P4f["🖥 家长端:审批心愿页"]
        P4f -->|"获取家庭心愿"| A15["🔗 POST /api/reward-wishlist/family"]:::api
        A15 -->|"用户ID"| S15["⚙️ RewardWishlistService.getByFamilyId()"]:::service
        S15 -->|"家庭所有心愿单"| D6

        P4f -->|"审批通过"| P4g["🖥 审批弹窗"]
        P4g -->|"心愿ID"| A16["🔗 POST /api/reward-wishlist/{id}/approve"]:::api
        A16 -->|"心愿ID, approved=true"| S16["⚙️ RewardWishlistService.approve()"]:::service
        S16 -->|"更新状态=exchanged"| D6

        P4f -->|"审批拒绝"| P4h["🖥 拒绝弹窗"]
        P4h -->|"心愿ID"| A16
        S16 -->|"更新状态=rejected"| D6

        D5 -->|"待审批兑换"| P4i["🖥 家长端:审批兑换页"]
        P4i -->|"审批"| A17["🔗 POST /api/rewards/{id}/approve"]:::api
        A17 -->|"心愿ID, approved"| S17["⚙️ RewardService.approveReward()"]:::service
        S17 -->|"同意→状态=exchanged; 拒绝→退积分"| D5

        P4 -->|"兑换历史"| P4j["📱 兑换历史"]
        P4j -->|"孩子ID, 分页"| A18["🔗 POST /api/rewards/exchange-history"]:::api
        A18 -->|"孩子ID, 页码, 页大小"| S18["⚙️ RewardService.getExchangeHistory()"]:::service
        S18 -->|"已兑换/已拒绝的心愿历史"| D5
    end

    %% ================================================================
    %% 角色关联
    %% ================================================================
    ROLE_PARENT -.- P1
    ROLE_PARENT -.- P2
    ROLE_PARENT -.- P4f
    ROLE_PARENT -.- P4i
    ROLE_CHILD -.- P1
    ROLE_CHILD -.- P4
    ROLE_CHILD -.- P4e
    ROLE_SYSTEM -.- P2a
    ROLE_SYSTEM -.- P2b

端点明细

积分概览与流水

端点 说明 端口 请求数据 响应数据
POST /api/points/balance 获取积分余额 📱小程序 {childId} {balance, expireDate}
POST /api/points/logs 获取积分流水 📱小程序 {childId, page, size} 分页积分流水(类型/金额/描述)
POST /api/points/logs-by-category 按分类查询流水 📱小程序 {childId, category, page, size} 按分类过滤的流水
POST /api/points/system-balance 系统积分余额 📱小程序 {childId} {systemPoints}

积分调整

端点 说明 端口 请求数据 响应数据
POST /api/points/adjust 手动调整积分 🖥管理后台 {childId, amount, reason, password} {newBalance}
POST /api/points/adjust 手动调整积分 📱小程序 {childId, amount, reason, password} {newBalance}

积分兑换商城

端点 说明 端口 请求数据 响应数据
POST /api/points/exchange/product/list 兑换商品列表 📱小程序 {category, pageNum, pageSize} 分页兑换商品列表
POST /api/points/exchange/product/detail 商品详情 📱小程序 {id} PointsExchangeProduct对象
POST /api/points/exchange/submit 提交兑换 📱小程序 {productId, childId, quantity} PointsExchangeRecord(含兑换码)
POST /api/points/exchange/records 兑换记录 📱小程序 Header: userId 兑换记录列表
POST /api/points/exchange/stats 兑换统计 📱小程序 Header: userId {todayCount}

奖励心愿系统

端点 说明 端口 请求数据 响应数据
POST /api/rewards/create 创建奖励(家长直接创建) 📱小程序 {childId, title, pointsRequired, category} 奖励ID
POST /api/rewards/wishlist 获取心愿列表 📱小程序 {childId} 可兑换的心愿列表(含进度)
POST /api/rewards/{id}/exchange 兑换奖励 📱小程序 {childId} {success, newBalance}
POST /api/rewards/{id}/approve 审批奖励(家长) 📱小程序 {approved} boolean
POST /api/rewards/templates 获取奖励模板 📱小程序 奖励模板列表
POST /api/rewards/exchange-history 兑换历史 📱小程序 {childId, page, size} 分页兑换历史
POST /api/reward-wishlist/create 创建心愿(孩子→待家长审批) 📱小程序 {title, description, category} 心愿ID
POST /api/reward-wishlist/my 我的心愿单 📱小程序 Header: userId 心愿单列表
POST /api/reward-wishlist/family 家庭心愿单 📱小程序 Header: userId 家庭所有心愿单
POST /api/reward-wishlist/{id}/exchange 兑换心愿 📱小程序 path: id boolean
POST /api/reward-wishlist/{id}/approve 审核心愿 📱小程序 {approved} boolean

数据实体关系

erDiagram
    FamilyMember ||--o{ PointsLog : "一个孩子多条积分流水"
    FamilyMember ||--o{ Reward : "一个孩子多个心愿"
    FamilyMember ||--o{ PointsExchangeRecord : "一个孩子多次兑换"
    FamilyMember ||--o{ RewardWishlist : "一个孩子多个心愿单"
    PointsExchangeProduct ||--o{ PointsExchangeRecord : "一个商品多次兑换"

    FamilyMember {
        Long id PK
        int totalPoints "总积分"
        int systemPoints "系统积分"
        string nickname
    }

    PointsLog {
        Long id PK
        Long childId FK
        int amount "正=收入, 负=支出"
        string type "earn / spend / adjust / refund"
        string category "task / system"
        string description
    }

    PointsExchangeProduct {
        Long id PK
        string name
        int pointsPrice
        int stock "-1=不限"
        string category
        string status "enabled / disabled"
    }

    PointsExchangeRecord {
        Long id PK
        Long userId FK
        Long familyMemberId FK
        Long productId FK
        string productName
        int pointsCost
        int quantity
        string status "completed / expired"
        string redeemCode
    }

    Reward {
        Long id PK
        Long familyId FK
        Long childId FK
        string title
        int pointsRequired
        string category
        string status "pending_approval / available / pending / exchanged / rejected"
        int exchangeApproved
    }

    RewardWishlist {
        Long id PK
        Long familyId FK
        Long userId FK
        string title
        string description
        int pointsRequired
        string status "pending / exchanged / rejected"
        int exchangeApproved
    }

完整性分析

# 维度 评估 说明
1 流程完整性 ✅ 完整 覆盖积分概览→积分调整→兑换商城→奖励心愿系统4个阶段,包含家长端、孩子端、管理后台、系统自动4种视角
2 异常路径 ⚠️ 部分覆盖 积分不足、余额为负保护、每日兑换限额、库存不足已覆盖;心愿审批拒绝退积分逻辑已覆盖;密码验证失败等前端校验未在图里展开
3 端点覆盖 ✅ 完整 16个端点全部映射到流程图中,与代码中PointsController、PointsExchangeController、RewardController、RewardWishlistController一致
4 角色覆盖 ✅ 完整 家长(查看/调整积分/审批心愿)、孩子(查看/兑换/创建心愿)、系统(自动奖励/扣除)、管理后台(调整积分)均已覆盖
5 数据实体 ✅ 完整 family_members、points_logs、points_exchange_products、points_exchange_records、rewards、reward_wishlists 6张表均在图中映射
6 一致性 ✅ 与代码一致 所有端点路径与实际Controller中的@PostMapping匹配,Service方法名与代码中的业务方法一致(getBalance/getPointsLogs/exchangeProduct/createReward等)