|
|
@@ -0,0 +1,423 @@
|
|
|
+# CFC 电商原生扩展设计方案
|
|
|
+
|
|
|
+> **版本:** v1.0
|
|
|
+> **日期:** 2026-06-24
|
|
|
+> **优先级:** P0+P1
|
|
|
+
|
|
|
+## 1. 决策背景
|
|
|
+
|
|
|
+原计划将 DanShop(`dan/danshop/`)作为独立 Spring Boot 模块部署在 9081 端口,与 cfc-backend(9082)通过 Feign 跨服务通信。经评估:
|
|
|
+
|
|
|
+| 方案 | 优势 | 劣势 |
|
|
|
+|------|------|------|
|
|
|
+| **独立模块 (DanShop)** | 代码隔离、独立部署 | 双 JVM 运维、Feign 网络开销、共享 DB 仍耦合、重复认证逻辑 |
|
|
|
+| **CFC 原生扩展** | 单 JVM 运维、直接服务调用、统一认证、统一事务 | 单体代码量增加 |
|
|
|
+
|
|
|
+**决策:** 所有电商功能直接构建在 `cfc-backend`,使用 `shop/` 子包隔离,表使用 `shop_` 前缀。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 2. 架构概览
|
|
|
+
|
|
|
+```
|
|
|
+┌──────────────────────────────────────────────────────────────┐
|
|
|
+│ cfc-frontend (uni-app) │
|
|
|
+│ pages/shop/* → /api/product/*, /api/cart/* 等 CFC 原生 API │
|
|
|
+└──────────────────────┬───────────────────────────────────────┘
|
|
|
+ │ JWT + POST Mapping
|
|
|
+┌──────────────────────▼───────────────────────────────────────┐
|
|
|
+│ cfc-backend (9082) │
|
|
|
+├──────────────────────────────────────────────────────────────┤
|
|
|
+│ controller/ │
|
|
|
+│ ├── product/ ← 现有: Product/ProductOrder │
|
|
|
+│ ├── cart/ ← 新增: 购物车 │
|
|
|
+│ ├── shop/ ← 新增: 类目/售后/折扣 │
|
|
|
+│ ├── admin/ ← 新增: 分销体系/折扣管理 │
|
|
|
+│ └── payment/ ← 增强: PaymentService (真实微信支付) │
|
|
|
+├──────────────────────────────────────────────────────────────┤
|
|
|
+│ service/ + entity/ + mapper/ ← 按模块组织 │
|
|
|
+└──────────────────────┬───────────────────────────────────────┘
|
|
|
+ │ 单数据源
|
|
|
+┌──────────────────────▼───────────────────────────────────────┐
|
|
|
+│ MySQL 8.0 (zxyj) │
|
|
|
+│ 表: products, product_orders, cart_items, shop_categories, │
|
|
|
+│ shop_discount_rules, distribution_systems, │
|
|
|
+│ distribution_relations, after_sales_requests ... │
|
|
|
+└──────────────────────────────────────────────────────────────┘
|
|
|
+```
|
|
|
+
|
|
|
+### 2.1 模块位置
|
|
|
+
|
|
|
+```
|
|
|
+cfc-backend/src/main/java/com/etotem/cfc/
|
|
|
+├── controller/
|
|
|
+│ ├── product/ProductController.java ← 现有,增强
|
|
|
+│ ├── product/ProductOrderController.java ← 现有,增强
|
|
|
+│ ├── cart/CartController.java ← 新增:购物车
|
|
|
+│ ├── payment/PaymentController.java ← 新增:支付
|
|
|
+│ ├── shop/
|
|
|
+│ │ ├── ProductCategoryController.java ← 新增:商品类目(小程序)
|
|
|
+│ │ ├── AfterSalesController.java ← 新增:售后
|
|
|
+│ │ └── RegionController.java ← 现有地址区域接口
|
|
|
+│ └── admin/
|
|
|
+│ ├── AdminCategoryController.java ← 新增:类目管理
|
|
|
+│ ├── AdminDistributionController.java ← 新增:分销体系管理
|
|
|
+│ └── AdminDiscountController.java ← 新增:折扣管理
|
|
|
+├── entity/
|
|
|
+│ ├── Product.java ← 增强(categoryId, distributionSystemId, images)
|
|
|
+│ ├── ProductOrder.java ← 增强(discountAmount, couponId, cancelAt, items)
|
|
|
+│ ├── CartItem.java ← 新增
|
|
|
+│ ├── ProductCategory.java ← 新增
|
|
|
+│ ├── DiscountRule.java ← 新增
|
|
|
+│ ├── DistributionSystem.java ← 新增
|
|
|
+│ ├── DistributionRelation.java ← 新增
|
|
|
+│ └── AfterSalesRequest.java ← 新增
|
|
|
+├── service/
|
|
|
+│ ├── ProductService.java ← 现有,增强
|
|
|
+│ ├── ProductOrderService.java ← 现有,增强
|
|
|
+│ ├── CartService.java ← 新增
|
|
|
+│ ├── PaymentService.java ← 重写(真实微信支付)
|
|
|
+│ ├── ProductCategoryService.java ← 新增
|
|
|
+│ ├── DiscountService.java ← 新增
|
|
|
+│ ├── DistributionService.java ← 新增
|
|
|
+│ └── AfterSalesService.java ← 新增
|
|
|
+└── mapper/ ← 每个实体对应 Mapper
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 3. 模块设计
|
|
|
+
|
|
|
+### 3.1 [P0] 支付统一(PaymentService 重构)
|
|
|
+
|
|
|
+**现状:** `PaymentService` 目前为桩代码,返回 mock 数据。`PackageOrder` 使用,`ProductOrder` 下单后直接调 `pay()` 改状态。
|
|
|
+
|
|
|
+**改造目标:**
|
|
|
+
|
|
|
+```java
|
|
|
+@Service
|
|
|
+public class PaymentService {
|
|
|
+ // 微信支付预下单 - 统一下单API
|
|
|
+ public Map<String, Object> createWechatPrepay(String orderNo, String description, Integer totalFee);
|
|
|
+
|
|
|
+ // 处理微信支付回调通知
|
|
|
+ public String handleWechatNotify(String requestBody, String signatureHeader);
|
|
|
+
|
|
|
+ // 处理支付宝回调
|
|
|
+ public boolean handleAlipayNotify(Map<String, String> params);
|
|
|
+
|
|
|
+ // 统一支付结果查询
|
|
|
+ public PaymentStatus queryPaymentStatus(String orderNo);
|
|
|
+
|
|
|
+ // 退款
|
|
|
+ public boolean refund(String orderNo, Integer amount, String reason);
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+**配置:**
|
|
|
+
|
|
|
+```yaml
|
|
|
+payment:
|
|
|
+ wechat:
|
|
|
+ app-id: wx5ba8038ef16fb245
|
|
|
+ mch-id: ${WX_MCH_ID}
|
|
|
+ api-v3-key: ${WX_API_V3_KEY}
|
|
|
+ private-key-path: ${WX_PRIVATE_KEY_PATH}
|
|
|
+ notify-url: https://cfc.etotem.com.cn/api/payment/wechat/notify
|
|
|
+ cert-path: ${WX_CERT_PATH}
|
|
|
+```
|
|
|
+
|
|
|
+### 3.2 [P0] 购物车
|
|
|
+
|
|
|
+**数据模型:** MySQL 持久化(`cart_items` 表)
|
|
|
+
|
|
|
+```java
|
|
|
+@TableName("cart_items")
|
|
|
+public class CartItem {
|
|
|
+ Long id;
|
|
|
+ Long userId;
|
|
|
+ Long productId;
|
|
|
+ Integer quantity;
|
|
|
+ Boolean selected; // 是否选中
|
|
|
+ Date createdAt;
|
|
|
+ Date updatedAt;
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+**API:**
|
|
|
+
|
|
|
+| 端点 | 说明 |
|
|
|
+|------|------|
|
|
|
+| `POST /api/cart/list` | 我的购物车(返回商品实时信息 + 价格同步) |
|
|
|
+| `POST /api/cart/add` | 加入购物车(已有则增加数量) |
|
|
|
+| `POST /api/cart/update` | 修改数量 (`productId` + `quantity`) |
|
|
|
+| `POST /api/cart/remove` | 移除商品(支持批量) |
|
|
|
+| `POST /api/cart/toggle` | 切换选中状态 |
|
|
|
+
|
|
|
+**校验:**
|
|
|
+- 加入时校验商品存在且 `on_shelf`
|
|
|
+- list 时检查库存和价格同步
|
|
|
+- 下架/删除商品标记失效(仍显示但不允许勾选结算)
|
|
|
+
|
|
|
+### 3.3 [P0] 结算 + 待支付
|
|
|
+
|
|
|
+**当前 ProductOrder 增强:**
|
|
|
+
|
|
|
+```java
|
|
|
+@TableName("product_orders")
|
|
|
+public class ProductOrder {
|
|
|
+ // 现有字段保留
|
|
|
+ Long id; String orderNo; Long productId; String productName;
|
|
|
+ String productType; Long buyerId; Long familyId;
|
|
|
+ Integer quantity; Integer unitPrice; Integer totalAmount;
|
|
|
+ String status; String paymentMethod; String remark;
|
|
|
+ Date paidAt; Date createdAt; Date updatedAt;
|
|
|
+
|
|
|
+ // 新增字段
|
|
|
+ String coverImage; // 商品封面(快照)
|
|
|
+ Integer discountAmount; // 优惠金额(分)
|
|
|
+ Long couponId; // 使用的优惠券/折扣ID
|
|
|
+ Date cancelAt; // 自动取消时间(createdAt+30min)
|
|
|
+ String transactionId; // 支付平台交易号
|
|
|
+ String addressSnapshot; // 收货地址快照(JSON)
|
|
|
+ String logisticsNo; // 物流单号
|
|
|
+ String logisticsCompany; // 物流公司
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+**前端改造:** 订单列表按状态 tab(全部/待支付/已完成/已取消),待支付订单显示支付倒计时和「去支付」按钮。
|
|
|
+
|
|
|
+### 3.4 [P0] 售后(人工客服版)
|
|
|
+
|
|
|
+```java
|
|
|
+@TableName("after_sales_requests")
|
|
|
+public class AfterSalesRequest {
|
|
|
+ Long id;
|
|
|
+ Long orderId;
|
|
|
+ String orderNo;
|
|
|
+ Long userId;
|
|
|
+ String type; // REFUND(仅退款) / RETURN_REFUND(退货退款)
|
|
|
+ String reason;
|
|
|
+ String description;
|
|
|
+ String images; // 凭证图片(JSON数组)
|
|
|
+ Integer refundAmount; // 退款金额(分)
|
|
|
+ String status; // pending(待审核)/approved(已通过)/rejected(驳回)/completed(已完成)
|
|
|
+ String rejectReason;
|
|
|
+ String handledBy; // 处理人ID
|
|
|
+ Date handledAt;
|
|
|
+ Date createdAt;
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+**流程:** 买家提交 → 管理员审核 → 线下退款 → 标记完成。无自动退款。
|
|
|
+
|
|
|
+**API:**
|
|
|
+
|
|
|
+| 端点 | 端 | 说明 |
|
|
|
+|------|----|------|
|
|
|
+| `POST /api/shop/after-sales/create` | 小程序 | 提交售后申请 |
|
|
|
+| `POST /api/shop/after-sales/list` | 小程序 | 我的售后记录 |
|
|
|
+| `POST /api/shop/after-sales/detail` | 小程序 | 售后详情 |
|
|
|
+| `POST /api/admin/shop/after-sales/list` | Web | 售后列表(管理端) |
|
|
|
+| `POST /api/admin/shop/after-sales/review` | Web | 审核售后申请 |
|
|
|
+
|
|
|
+### 3.5 [P1] 商品类目(多维度 + 多种类)
|
|
|
+
|
|
|
+```java
|
|
|
+@TableName("shop_categories")
|
|
|
+public class ProductCategory {
|
|
|
+ Long id;
|
|
|
+ String name;
|
|
|
+ Long parentId; // 0=根节点
|
|
|
+ Integer level; // 0/1/2/3
|
|
|
+ Integer sort;
|
|
|
+ String image;
|
|
|
+ Boolean enabled;
|
|
|
+ String dimensionCodes; // "body,mind,heart" 多维度关联
|
|
|
+ String productTypes; // "PHYSICAL,COURSE,ASSESSMENT,VIRTUAL"
|
|
|
+ Date createdAt;
|
|
|
+ Date updatedAt;
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+**Product 增加字段:**
|
|
|
+- `Long categoryId` — 所属类目
|
|
|
+- `Long distributionSystemId` — 分销体系归属
|
|
|
+
|
|
|
+**维度继承:**
|
|
|
+```
|
|
|
+类目(维度=身,智) →
|
|
|
+ 子类目(继承维度=身,智, 可追加指定) →
|
|
|
+ 商品(继承类目维度)
|
|
|
+```
|
|
|
+
|
|
|
+**API:**
|
|
|
+
|
|
|
+| 端点 | 端 | 说明 |
|
|
|
+|------|----|------|
|
|
|
+| `POST /api/admin/shop/category/create` | Web | 创建类目 |
|
|
|
+| `POST /api/admin/shop/category/update` | Web | 更新类目 |
|
|
|
+| `POST /api/admin/shop/category/delete` | Web | 删除类目 |
|
|
|
+| `POST /api/admin/shop/category/tree` | Web | 管理端树形 |
|
|
|
+| `POST /api/shop/category/tree` | 小程序 | 商城端类目树 |
|
|
|
+| `POST /api/shop/category/products` | 小程序 | 类目下商品列表 |
|
|
|
+
|
|
|
+### 3.6 [P1] 商品相册
|
|
|
+
|
|
|
+**Product.images 增强:**
|
|
|
+- `coverImage` 作为主图(封面)
|
|
|
+- `images` 存储 JSON 数组 `["url1","url2","url3"]`
|
|
|
+- 管理端商品编辑支持多图上传/排序/删除
|
|
|
+
|
|
|
+**前端展示:**
|
|
|
+- 详情页轮播图(coverImage + images)
|
|
|
+- 列表页使用 coverImage
|
|
|
+
|
|
|
+### 3.7 [P1] 多分销体系
|
|
|
+
|
|
|
+```java
|
|
|
+@TableName("distribution_systems")
|
|
|
+public class DistributionSystem {
|
|
|
+ Long id;
|
|
|
+ String name;
|
|
|
+ String description;
|
|
|
+ Long ownerId; // 创建者
|
|
|
+ Integer profitRate; // 平台利润率(千分比),仅管理员可修改
|
|
|
+ Boolean enabled;
|
|
|
+ Date createdAt;
|
|
|
+ Date updatedAt;
|
|
|
+}
|
|
|
+
|
|
|
+@TableName("distribution_relations")
|
|
|
+public class DistributionRelation {
|
|
|
+ Long id;
|
|
|
+ Long systemId;
|
|
|
+ Long userId;
|
|
|
+ Long parentId; // 上级(null=根)
|
|
|
+ Integer depth;
|
|
|
+ Date createdAt;
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+**业务规则:**
|
|
|
+- `profitRate` 管理员在 Web 端设置,分销商不可修改
|
|
|
+- 每个分销体系有自己的上下级关系树
|
|
|
+- 商品归属一个分销体系(`product.distributionSystemId`)
|
|
|
+- 下单时通过用户 → 分销关系链查找上级,按体系规则分润
|
|
|
+- 平台只记录外部分销关系(external),不计算外部利润
|
|
|
+
|
|
|
+**API(Web 管理端):**
|
|
|
+
|
|
|
+| 端点 | 说明 |
|
|
|
+|------|------|
|
|
|
+| `POST /api/admin/distribution/system/create` | 创建分销体系 |
|
|
|
+| `POST /api/admin/distribution/system/update` | 更新(含 profitRate 设置) |
|
|
|
+| `POST /api/admin/distribution/system/list` | 体系列表 |
|
|
|
+| `POST /api/admin/distribution/system/toggle` | 启用/禁用 |
|
|
|
+| `POST /api/admin/distribution/relation/list` | 查看某体系的关系树 |
|
|
|
+| `POST /api/admin/distribution/relation/add` | 手动添加关系 |
|
|
|
+| `POST /api/admin/distribution/relation/remove` | 移除关系 |
|
|
|
+
|
|
|
+### 3.8 [P1] 折扣管理
|
|
|
+
|
|
|
+```java
|
|
|
+@TableName("shop_discount_rules")
|
|
|
+public class DiscountRule {
|
|
|
+ Long id;
|
|
|
+ String name;
|
|
|
+ String type; // PERCENT(打折) / FIXED(减额) / THRESHOLD(满减)
|
|
|
+ Integer value; // PERCENT: 打折值(如10=9折); FIXED/THRESHOLD: 金额(分)
|
|
|
+ Integer thresholdAmount; // 满减门槛(分), THRESHOLD时使用
|
|
|
+ Long categoryId; // 适用类目(null=全部)
|
|
|
+ Long distributionSystemId;// 适用体系(null=全部)
|
|
|
+ String productIds; // 适用商品(逗号分隔, null=全部)
|
|
|
+ Date startTime;
|
|
|
+ Date endTime;
|
|
|
+ Integer maxUses; // 最大使用次数(0=不限)
|
|
|
+ Integer usedCount;
|
|
|
+ Boolean enabled;
|
|
|
+ Date createdAt;
|
|
|
+ Date updatedAt;
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+**API(Web 管理端):**
|
|
|
+
|
|
|
+| 端点 | 说明 |
|
|
|
+|------|------|
|
|
|
+| `POST /api/admin/shop/discount/create` | 创建折扣规则 |
|
|
|
+| `POST /api/admin/shop/discount/update` | 更新 |
|
|
|
+| `POST /api/admin/shop/discount/list` | 规则列表 |
|
|
|
+| `POST /api/admin/shop/discount/toggle` | 启用/禁用 |
|
|
|
+
|
|
|
+**结算页集成:** 下单时 `DiscountService.calculateBestDiscount()` 自动计算可享最优折扣,返回优惠信息。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 4. 前端改造(小程序 cfc-frontend)
|
|
|
+
|
|
|
+### 4.1 API 切换
|
|
|
+
|
|
|
+所有 `config.danshop(...)` → `config.baseUrl(...)` / CFC 原生 API:
|
|
|
+
|
|
|
+| 文件 | 当前 | 改造后 |
|
|
|
+|------|------|--------|
|
|
|
+| `pages/shop/cart/cart.vue` | `danshop/cart/list` → `danshop/cart/remove` | `/api/cart/list` → `/api/cart/remove` |
|
|
|
+| `pages/shop/checkout/checkout.vue` | `danshop/address/list` → `danshop/order/create` | `/api/user/address/list` → `/api/product/order/create` |
|
|
|
+| `pages/shop/payment/payment.vue` | `danshop/payment/precreate` → `danshop/order/cancel` | `/api/product/order/pay` → `/api/product/order/cancel` |
|
|
|
+| `pages/shop/address/address.vue` | `danshop/address/list/delete/setDefault` | `/api/user/address/*` (已有 CFC API) |
|
|
|
+| `pages/shop/address-edit/address-edit.vue` | `danshop/address/get/save` + `danshop/region/*` | `/api/user/address/*` + `/api/region/*` |
|
|
|
+| `pages/shop/logistics/logistics.vue` | `danshop/logistics/query` | `/api/shop/logistics/query` |
|
|
|
+| `pages/shop/order-list/order-list.vue` | 可能 mock | `/api/product/order/list` |
|
|
|
+| `pages/shop/order-detail/order-detail.vue` | 可能 mock | `/api/product/order/detail` |
|
|
|
+| `pages/shop/detail/detail.vue` | — | 增加「加入购物车」按钮 |
|
|
|
+
|
|
|
+### 4.2 新增/增强功能
|
|
|
+
|
|
|
+- **detail.vue**:增加「加入购物车」按钮、数量选择
|
|
|
+- **order-list.vue**:按状态 tab 分组(全部/待付款/已付款/已完成/已取消),待付款显示倒计时和「去支付」
|
|
|
+- **cart.vue**:商品失效标记、直接从 CFC API 获取
|
|
|
+- **checkout.vue**:优惠信息展示(后续对接折扣系统)
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 5. 实施顺序
|
|
|
+
|
|
|
+| 阶段 | 模块 | 后端 | 前端 | Web | 依赖 |
|
|
|
+|:----:|------|:----:|:----:|:---:|:----:|
|
|
|
+| 1 | 购物车 CartItem + CartService + CartController | ✅ | ✅ | — | 无 |
|
|
|
+| 2 | PaymentService 重构(真实微信支付) | ✅ | — | — | 无 |
|
|
|
+| 3 | 结算 + 待支付(ProductOrder 增强) | ✅ | ✅ | — | 阶段1,2 |
|
|
|
+| 4 | 售后(人工审核) | ✅ | ✅ | ✅ | 阶段3 |
|
|
|
+| 5 | 商品类目(多维度+多种类) | ✅ | ✅ | ✅ | 无 |
|
|
|
+| 6 | 商品相册(多图支持) | ✅ | — | ✅ | 阶段5 |
|
|
|
+| 7 | 多分销体系 | ✅ | — | ✅ | 无 |
|
|
|
+| 8 | 折扣管理 | ✅ | — | ✅ | 阶段5 |
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 6. 数据库表变更总览
|
|
|
+
|
|
|
+| 表名 | 操作 | 说明 |
|
|
|
+|------|------|------|
|
|
|
+| `products` | 增强 | 加 `category_id`, `distribution_system_id`, `images` JSON 格式 |
|
|
|
+| `product_orders` | 增强 | 加 `discount_amount`, `coupon_id`, `cancel_at`, `transaction_id`, 地址快照等 |
|
|
|
+| `cart_items` | 新建 | 购物车 |
|
|
|
+| `shop_categories` | 新建 | 商品类目(树形) |
|
|
|
+| `shop_discount_rules` | 新建 | 折扣规则 |
|
|
|
+| `distribution_systems` | 新建 | 分销体系 |
|
|
|
+| `distribution_relations` | 新建 | 分销关系 |
|
|
|
+| `after_sales_requests` | 新建 | 售后申请 |
|
|
|
+| `user_address` | 已有 | CFC 现有地址表(复用) |
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 7. 关键约定
|
|
|
+
|
|
|
+- 所有新接口使用 `@PostMapping`,遵循 CFC 项目规范
|
|
|
+- 新实体使用 `@TableName` + `@TableId(type = IdType.AUTO)`
|
|
|
+- 统一返回 `Result<T>` 包装
|
|
|
+- JWT 认证:`@RequestAttribute("userId")` 获取当前用户
|
|
|
+- 金额统一使用 **分(Integer)** 存储
|
|
|
+- 状态字段使用字符串(可读性)
|
|
|
+- 新 Controller/Service 名避免与其他包 Bean Name 冲突
|