# 用户使用流程图 — 购物车与优惠券 > **端口说明**: 📱 小程序 | 🖥 管理后台 | 📋 规划师端 | ⚙️ 系统自动 > > **分层说明**: 🏠 页面 → 🔗 API → ⚙️ Service → 📦 数据实体 ```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 %% ============ 角色 ============ 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`(含商品名/图/价格/规格) | | `POST /api/cart/update` | 更新商品数量 | 📱小程序 | `{productId, quantity}` | — | | `POST /api/cart/remove` | 从购物车移除商品 | 📱小程序 | `{productId}` | — | | `POST /api/cart/count` | 获取购物车条目数 | 📱小程序 | — | `int` | ### 优惠券(用户端) | 端点 | 说明 | 端口 | 请求数据 | 响应数据 | |------|------|------|---------|---------| | `POST /api/coupon/list` | 获取可用优惠券列表 | 📱小程序 | — | `List` | | `POST /api/coupon/claim` | 领取优惠券 | 📱小程序 | `{couponId}` | `String`("领取成功" / 错误消息) | | `POST /api/coupon/apply` | 应用优惠券计算折扣 | 📱小程序 | `{userCouponId, orderType, orderAmount}` | `{discount}`(折扣金额/分) | ### 优惠券(管理后台) | 端点 | 说明 | 端口 | 请求数据 | 响应数据 | |------|------|------|---------|---------| | `POST /api/admin/coupon/list` | 获取全部优惠券 | 🖥管理后台 | — | `List` | | `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` | ## 数据实体关系 ```mermaid 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方法名与实际代码一致 |