cart-coupon-flow.md 12 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_ADMIN(("🔧 管理员")):::actor

    %% ================================================================
    %% 阶段一:购物车管理
    %% ================================================================
    subgraph 阶段一[阶段一:购物车管理]
        direction TB

        P1["🏠 小程序:商品详情页"]:::page
        P1 -->|"选择SKU、数量"| P1a["🏠 加入购物车弹窗"]:::page
        P1a -->|"productId, quantity, skuId"| A1["🔗 POST /api/cart/add"]:::api
        A1 -->|"userId, productId, quantity, skuId"| S1["⚙️ CartService.addToCart()"]:::service
        S1 -->|"查询商品是否存在"| S1a["⚙️ ProductMapper.selectById()"]:::service
        S1a -->|"商品不存在返回null"| P1a
        S1 -->|"购物车中已有 → 累加数量"| S1b["⚙️ CartMapper.updateById()"]:::service
        S1 -->|"购物车中没有 → 新建记录"| S1c["⚙️ CartMapper.insert()"]:::service
        S1b -->|"Cart记录"| D1["📦 cart 表"]:::data
        S1c --> D1

        D1 -->|"userId"| P2["🏠 小程序:购物车列表页"]:::page
        P2 -->|"userId"| A2["🔗 POST /api/cart/list"]:::api
        A2 -->|"userId"| S2["⚙️ CartService.getCartList()"]:::service
        S2 -->|"按创建时间倒序查询"| S2a["⚙️ CartMapper.selectList()"]:::service
        S2a -->|"Cart列表"| D1
        S2 -->|"装配商品信息+SKU规格"| S2b["⚙️ buildCartItemDTO()"]:::service
        S2b -->|"CartItemDTO(含名称/图片/价格/规格)"| D2["📦 CartItemDTO(返回前端)"]:::data

        P2 -->|"调整数量"| P3["🏠 数量调整按钮"]:::page
        P3 -->|"productId, quantity"| A3["🔗 POST /api/cart/update"]:::api
        A3 -->|"userId, productId, quantity"| S3["⚙️ CartService.updateQuantity()"]:::service
        S3 -->|"数量≤0则删除,否则更新数量"| S3a["⚙️ CartMapper.updateById() / delete()"]:::service
        S3a -->|"更新记录"| D1

        P2 -->|"删除商品"| P4["🏠 删除按钮"]:::page
        P4 -->|"productId"| A4["🔗 POST /api/cart/remove"]:::api
        A4 -->|"userId, productId"| S4["⚙️ CartService.removeItem()"]:::service
        S4 -->|"按userId+productId删除"| S4a["⚙️ CartMapper.delete()"]:::service
        S4a --> D1

        P2 -->|"查看购物车角标"| P5["🏠 TabBar购物车角标"]:::page
        P5 -->|"userId"| A5["🔗 POST /api/cart/count"]:::api
        A5 -->|"userId"| S5["⚙️ CartService.getCartCount()"]:::service
        S5 -->|"统计该用户购物车条目数"| S5a["⚙️ CartMapper.selectCount()"]:::service
        S5a -->|"条目数"| D1
    end

    %% ================================================================
    %% 阶段二:优惠券领取与使用
    %% ================================================================
    subgraph 阶段二[阶段二:优惠券领取与使用]
        D1 -->|"userId"| P6["🏠 小程序:优惠券列表页"]:::page
        P6 -->|"userId"| A6["🔗 POST /api/coupon/list"]:::api
        A6 -->|"userId"| S6["⚙️ CouponService.listAvailable()"]:::service
        S6 -->|"查询用户可用券(状态=AVAILABLE、有效期內)"| S6a["⚙️ UserCouponMapper + CouponMapper 联合查询"]:::service
        S6a -->|"UserCoupon → Coupon"| D3["📦 user_coupon + coupon 表"]:::data

        P6 -->|"领取优惠券"| P7["🏠 领取按钮"]:::page
        P7 -->|"couponId"| A7["🔗 POST /api/coupon/claim"]:::api
        A7 -->|"userId, couponId"| S7["⚙️ CouponService.claim()"]:::service
        S7 -->|"检查: 券存在、未领完、有效期內、未重复领取"| S7a["⚙️ 校验条件"]:::service
        S7a -->|"校验不通过返回错误消息"| P7
        S7 -->|"创建UserCoupon记录"| S7b["⚙️ UserCouponMapper.insert()"]:::service
        S7b -->|"user_coupon记录(状态=AVAILABLE)"| D4["📦 user_coupon 表"]:::data
        S7 -->|"累加usedCount"| S7c["⚙️ CouponMapper.updateById()"]:::service
        S7c -->|"更新coupon.usedCount"| D5["📦 coupon 表"]:::data

        P6 -->|"下单时选择优惠券"| P8["🏠 订单确认页"]:::page
        P8 -->|"userCouponId, orderType, orderAmount"| A8["🔗 POST /api/coupon/apply"]:::api
        A8 -->|"userId, userCouponId, orderType, orderAmount"| S8["⚙️ CouponService.apply()"]:::service
        S8 -->|"校验: 券归属、有效期、适用范围、最低消费"| S8a["⚙️ 校验条件"]:::service
        S8a -->|"校验不通过返回null"| P8
        S8 -->|"计算折扣=min(券面值, 订单金额)"| S8b["⚙️ 折扣计算"]:::service
        S8b -->|"折扣金额"| D6["📦 discount(返回前端)"]:::data

        P8 -->|"提交订单 → 标记券已用"| A8b["🔗 POST /api/coupon/markUsed(内部调用)"]:::api
        A8b -->|"userCouponId, orderId"| S8c["⚙️ CouponService.markUsed()"]:::service
        S8c -->|"状态→USED, 记录使用时间/订单ID"| D4
    end

    %% ================================================================
    %% 阶段三:管理后台优惠券管理
    %% ================================================================
    subgraph 阶段三[阶段三:管理后台优惠券管理]
        P9["🏠 管理后台:优惠券管理页"]:::page
        P9 -->|"查看列表"| A9["🔗 POST /api/admin/coupon/list"]:::api
        A9 -->|"role=admin"| S9["⚙️ CouponService.listAll()"]:::service
        S9 -->|"查询所有优惠券"| D5

        P9 -->|"创建优惠券"| P9a["🏠 创建表单"]:::page
        P9a -->|"name, type, value, minSpend, validFrom, ..."| A10["🔗 POST /api/admin/coupon/create"]:::api
        A10 -->|"role=admin, Coupon对象"| S10["⚙️ CouponMapper.insert()"]:::service
        S10 -->|"写入新优惠券"| D5

        P9 -->|"编辑优惠券"| P9b["🏠 编辑表单"]:::page
        P9b -->|"id, 更新字段"| A11["🔗 POST /api/admin/coupon/update"]:::api
        A11 -->|"role=admin, Coupon对象"| S11["⚙️ CouponMapper.updateById()"]:::service
        S11 -->|"更新优惠券"| D5

        P9 -->|"发放给用户"| P9c["🏠 发放弹窗:选择用户"]:::page
        P9c -->|"couponId, userIds[]"| A12["🔗 POST /api/admin/coupon/issue"]:::api
        A12 -->|"role=admin, couponId, userIds"| S12["⚙️ CouponService.issueToUser()"]:::service
        S12 -->|"批量创建UserCoupon(状态=AVAILABLE)"| S12a["⚙️ UserCouponMapper.insert()"]:::service
        S12a -->|"user_coupon记录"| D4

        P9 -->|"删除优惠券"| P9d["🏠 删除确认弹窗"]:::page
        P9d -->|"id"| A13["🔗 POST /api/admin/coupon/delete"]:::api
        A13 -->|"role=admin, id"| S13["⚙️ CouponMapper.deleteById()"]:::service
        S13 -->|"删除优惠券"| D5
    end

    %% ================================================================
    %% 角色关联
    %% ================================================================
    ROLE_PARENT -.- P1
    ROLE_PARENT -.- P2
    ROLE_PARENT -.- P6
    ROLE_PARENT -.- P8
    ROLE_ADMIN -.- P9

端点明细

购物车

端点 说明 端口 请求数据 响应数据
POST /api/cart/add 添加商品到购物车 📱小程序 {productId, quantity(默认1), skuId(可选)} CartItemDTO
POST /api/cart/list 获取购物车列表 📱小程序 List<CartItemDTO>(含商品名/图/价格/规格)
POST /api/cart/update 更新商品数量 📱小程序 {productId, quantity}
POST /api/cart/remove 从购物车移除商品 📱小程序 {productId}
POST /api/cart/count 获取购物车条目数 📱小程序 int

优惠券(用户端)

端点 说明 端口 请求数据 响应数据
POST /api/coupon/list 获取可用优惠券列表 📱小程序 List<Coupon>
POST /api/coupon/claim 领取优惠券 📱小程序 {couponId} String("领取成功" / 错误消息)
POST /api/coupon/apply 应用优惠券计算折扣 📱小程序 {userCouponId, orderType, orderAmount} {discount}(折扣金额/分)

优惠券(管理后台)

端点 说明 端口 请求数据 响应数据
POST /api/admin/coupon/list 获取全部优惠券 🖥管理后台 List<Coupon>
POST /api/admin/coupon/create 创建优惠券 🖥管理后台 {name, type, value, minSpend, applicableTo, validFrom, validUntil, totalCount} String
POST /api/admin/coupon/update 更新优惠券 🖥管理后台 {id, ...更新字段} String
POST /api/admin/coupon/issue 向用户发放优惠券 🖥管理后台 {couponId, userIds[]} String
POST /api/admin/coupon/delete 删除优惠券 🖥管理后台 {id} String

数据实体关系

erDiagram
    Coupon ||--o{ UserCoupon : "一个券可被多次发放"
    User ||--o{ UserCoupon : "一个用户可有多张券"
    User ||--o{ Cart : "一个用户可有多个购物车条目"
    Product ||--o{ Cart : "一个商品可在多个购物车中"
    ProductSku ||--o{ Cart : "一个SKU可在多个购物车中"

    Cart {
        Long id PK
        Long userId FK
        Long productId FK
        Long skuId FK "nullable"
        string specOptionIds "JSON"
        int quantity
        datetime createdAt
        datetime updatedAt
    }

    Coupon {
        Long id PK
        string name
        string type "FIXED等"
        int value "金额(分)"
        int minSpend "最低消费(分)"
        string applicableTo "ALL / MEMBERSHIP"
        date validFrom
        date validUntil
        int totalCount "总发放量"
        int usedCount "已使用量"
        datetime createdAt
    }

    UserCoupon {
        Long id PK
        Long userId FK
        Long couponId FK
        string status "AVAILABLE / USED"
        datetime receivedAt
        datetime usedAt "nullable"
        Long orderId FK "nullable"
    }

完整性分析

# 维度 评估 说明
1 流程完整性 ✅ 完整 覆盖购物车全生命周期(增删改查计数)、用户优惠券(查看/领取/使用)、管理后台(CRUD/发放)3个阶段
2 异常路径 ⚠️ 部分覆盖 添加时商品不存在(返回null)、领取时券已领完/已过期/已重复领取(返回错误消息)、应用券时不满足条件(返回null)在图中体现;订单提交后券标记失败的补偿逻辑未画入
3 端点覆盖 ✅ 完整 13个端点全部映射到流程图中,与代码实际暴露的CartController(5个)、CouponController(3个)、AdminCouponController(5个)一致
4 角色覆盖 ✅ 完整 用户端(家长)进行购物车管理、优惠券领取与使用;管理员在后管端进行优惠券CRUD和发放
5 数据实体 ✅ 完整 cart表、coupon表、user_coupon表、CartItemDTO均在图中映射
6 一致性 ✅ 与代码一致 所有端点路径与实际Controller中的@PostMapping匹配,Service方法名与实际代码一致