From c30d301fbce1acfca866f294fd78b7799a9058e9 Mon Sep 17 00:00:00 2001 From: sp mac bookpro 2605 Date: Tue, 2 Jun 2026 23:49:12 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E6=B7=BB=E5=8A=A0=E7=A7=AF=E5=88=86?= =?UTF-8?q?=E5=95=86=E5=9F=8E=E5=AE=8C=E6=95=B4API=E8=AE=BE=E8=AE=A1?= =?UTF-8?q?=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 7张数据库表结构设计(用户积分、积分流水、商品、分类、订单、banner、促销入口) - 8个核心API接口详细定义(含请求参数、响应格式、错误码) - 积分累积逻辑:1 USD = 1000 积分 - 兑换流程与并发控制方案 - 管理后台接口建议 --- docs/points-mall-api-full.md | 578 +++++++++++++++++++++++++++++++++++ 1 file changed, 578 insertions(+) create mode 100644 docs/points-mall-api-full.md diff --git a/docs/points-mall-api-full.md b/docs/points-mall-api-full.md new file mode 100644 index 0000000..43bd5dd --- /dev/null +++ b/docs/points-mall-api-full.md @@ -0,0 +1,578 @@ +# 积分商城后端 API 设计文档 + +## 一、整体设计概述 + +### 1.1 设计目标 +- 实现 API 调用消费金额与积分的自动累积(1 美元 = 1000 积分) +- 提供完整的积分商城商品管理与兑换流程 +- 支持实物商品的收货地址管理 +- 积分与用户 ID 强绑定,确保数据一致性 + +### 1.2 汇率规则 +- **1 USD = 1000 积分** +- 积分计算以实际消费金额为准,精确到小数点后 2 位 +- 消费金额四舍五入后转换为积分 + +--- + +## 二、数据库表结构设计 + +### 2.1 用户积分表 (user_points) + +| 字段名 | 类型 | 说明 | 约束 | +|--------|------|------|------| +| id | BIGINT | 主键 | PRIMARY KEY, AUTO_INCREMENT | +| user_id | VARCHAR(64) | 用户 ID | NOT NULL, INDEX | +| points | BIGINT | 当前积分余额 | NOT NULL, DEFAULT 0 | +| total_earned | BIGINT | 累计获得积分 | NOT NULL, DEFAULT 0 | +| total_spent | BIGINT | 累计消耗积分 | NOT NULL, DEFAULT 0 | +| level | VARCHAR(32) | 用户等级 | DEFAULT 'Lv.1' | +| created_at | DATETIME | 创建时间 | NOT NULL | +| updated_at | DATETIME | 更新时间 | NOT NULL | +| version | INT | 乐观锁版本 | NOT NULL, DEFAULT 0 | + +**索引:** +- `uk_user_id`: UNIQUE INDEX on `user_id` + +### 2.2 积分流水表 (point_transactions) + +| 字段名 | 类型 | 说明 | 约束 | +|--------|------|------|------| +| id | BIGINT | 主键 | PRIMARY KEY, AUTO_INCREMENT | +| user_id | VARCHAR(64) | 用户 ID | NOT NULL, INDEX | +| type | VARCHAR(32) | 类型:earn/spend | NOT NULL | +| points | BIGINT | 变动积分(正数获得,负数消耗) | NOT NULL | +| balance | BIGINT | 变动后余额 | NOT NULL | +| source_type | VARCHAR(32) | 来源类型 | NOT NULL | +| source_id | VARCHAR(64) | 来源 ID | NULL | +| description | VARCHAR(255) | 描述 | NULL | +| created_at | DATETIME | 创建时间 | NOT NULL | + +**说明:** +- `source_type` 枚举:`api_call`(API 调用)、`exchange`(兑换商品)、`activity`(活动奖励) +- `source_id`:对应 API 调用记录 ID 或订单 ID 等 + +### 2.3 积分商城商品表 (point_products) + +| 字段名 | 类型 | 说明 | 约束 | +|--------|------|------|------| +| id | VARCHAR(64) | 商品 ID | PRIMARY KEY | +| category_id | VARCHAR(64) | 分类 ID | NOT NULL, INDEX | +| name | VARCHAR(128) | 商品名称 | NOT NULL | +| subtitle | VARCHAR(255) | 副标题 | NULL | +| description | TEXT | 详细描述 | NULL | +| cover_url | VARCHAR(512) | 封面图片 | NULL | +| points_price | BIGINT | 所需积分 | NOT NULL | +| original_price | DECIMAL(10,2) | 原价(美元) | NULL | +| stock | INT | 库存 | NOT NULL, DEFAULT 0 | +| sold | INT | 已售数量 | NOT NULL, DEFAULT 0 | +| tags | JSON | 标签数组 | NULL | +| weight | DECIMAL(8,2) | 重量(kg) | NULL | +| is_physical | TINYINT | 是否实物商品 | NOT NULL, DEFAULT 1 | +| is_published | TINYINT | 是否上架 | NOT NULL, DEFAULT 0 | +| sort_order | INT | 排序权重 | NOT NULL, DEFAULT 0 | +| created_at | DATETIME | 创建时间 | NOT NULL | +| updated_at | DATETIME | 更新时间 | NOT NULL | + +### 2.4 商品分类表 (point_categories) + +| 字段名 | 类型 | 说明 | 约束 | +|--------|------|------|------| +| id | VARCHAR(64) | 分类 ID | PRIMARY KEY | +| name | VARCHAR(64) | 分类名称 | NOT NULL | +| icon_url | VARCHAR(512) | 图标 | NULL | +| sort_order | INT | 排序权重 | NOT NULL, DEFAULT 0 | +| is_enabled | TINYINT | 是否启用 | NOT NULL, DEFAULT 1 | +| created_at | DATETIME | 创建时间 | NOT NULL | + +### 2.5 兑换订单表 (point_orders) + +| 字段名 | 类型 | 说明 | 约束 | +|--------|------|------|------| +| id | VARCHAR(64) | 订单 ID | PRIMARY KEY | +| user_id | VARCHAR(64) | 用户 ID | NOT NULL, INDEX | +| product_id | VARCHAR(64) | 商品 ID | NOT NULL | +| product_name | VARCHAR(128) | 商品名称快照 | NOT NULL | +| points_price | BIGINT | 消耗积分 | NOT NULL | +| status | VARCHAR(32) | 订单状态 | NOT NULL, INDEX | +| recipient_name | VARCHAR(64) | 收货人姓名 | NOT NULL | +| phone | VARCHAR(32) | 联系电话 | NOT NULL | +| province | VARCHAR(64) | 省份 | NOT NULL | +| city | VARCHAR(64) | 城市 | NOT NULL | +| district | VARCHAR(64) | 区/县 | NOT NULL | +| address | VARCHAR(512) | 详细地址 | NOT NULL | +| zip_code | VARCHAR(16) | 邮政编码 | NULL | +| tracking_company | VARCHAR(64) | 物流公司 | NULL | +| tracking_number | VARCHAR(64) | 物流单号 | NULL | +| shipped_at | DATETIME | 发货时间 | NULL | +| delivered_at | DATETIME | 签收时间 | NULL | +| remark | VARCHAR(255) | 备注 | NULL | +| created_at | DATETIME | 创建时间 | NOT NULL | +| updated_at | DATETIME | 更新时间 | NOT NULL | + +**状态枚举 (status):** +- `pending`:待处理 +- `confirmed`:已确认 +- `shipped`:已发货 +- `delivered`:已签收 +- `cancelled`:已取消 +- `refunded`:已退款 + +### 2.6 Banner 表 (point_banners) + +| 字段名 | 类型 | 说明 | 约束 | +|--------|------|------|------| +| id | VARCHAR(64) | Banner ID | PRIMARY KEY | +| title | VARCHAR(128) | 标题 | NOT NULL | +| subtitle | VARCHAR(255) | 副标题 | NULL | +| image_url | VARCHAR(512) | 图片 URL | NOT NULL | +| link_url | VARCHAR(512) | 跳转链接 | NULL | +| sort_order | INT | 排序权重 | NOT NULL, DEFAULT 0 | +| is_enabled | TINYINT | 是否启用 | NOT NULL, DEFAULT 1 | +| created_at | DATETIME | 创建时间 | NOT NULL | + +### 2.7 促销入口表 (point_promo_entries) + +| 字段名 | 类型 | 说明 | 约束 | +|--------|------|------|------| +| id | VARCHAR(64) | 入口 ID | PRIMARY KEY | +| title | VARCHAR(64) | 标题 | NOT NULL | +| subtitle | VARCHAR(128) | 副标题 | NULL | +| icon_url | VARCHAR(512) | 图标 URL | NULL | +| link_url | VARCHAR(512) | 跳转链接 | NULL | +| sort_order | INT | 排序权重 | NOT NULL, DEFAULT 0 | +| is_enabled | TINYINT | 是否启用 | NOT NULL, DEFAULT 1 | +| created_at | DATETIME | 创建时间 | NOT NULL | + +--- + +## 三、API 接口设计 + +### 3.1 通用响应格式 + +```json +{ + "code": 0, + "message": "success", + "data": {} +} +``` + +--- + +### 3.2 积分商城概览接口 + +**GET** `/points-mall/overview` + +**描述:** 获取积分商城首页概览数据,包括用户积分、分类、Banner、促销入口等 + +**响应数据:** +```json +{ + "me": { + "points": 1280, + "level": "Lv.2", + "totalEarned": 5680, + "totalSpent": 4400 + }, + "categories": [ + { + "id": "all", + "name": "全部", + "sort": 0 + }, + { + "id": "digital", + "name": "虚拟权益", + "sort": 1 + } + ], + "banners": [ + { + "id": "b1", + "title": "限时活动", + "subtitle": "Up to 25% Off", + "imageUrl": "https://...", + "linkUrl": "https://..." + } + ], + "promoEntries": [ + { + "id": "p1", + "title": "促销活动", + "subtitle": "本周精选", + "iconUrl": "https://...", + "linkUrl": "https://..." + } + ] +} +``` + +--- + +### 3.3 商品列表接口 + +**GET** `/points-mall/products` + +**描述:** 获取商品列表,支持分页、筛选、排序 + +**请求参数:** + +| 参数名 | 类型 | 必填 | 说明 | +|--------|------|------|------| +| categoryId | String | 否 | 分类 ID,不传则查询全部 | +| q | String | 否 | 搜索关键词 | +| sort | String | 否 | 排序方式:`popular`(热度)、`newest`(最新)、`price_asc`(价格升序)、`price_desc`(价格降序),默认 `popular` | +| page | Int | 否 | 页码,默认 1 | +| pageSize | Int | 否 | 每页数量,默认 24 | + +**响应数据:** +```json +{ + "page": 1, + "pageSize": 24, + "total": 120, + "items": [ + { + "id": "prod_001", + "categoryId": "digital", + "name": "商品名称", + "subtitle": "商品简短描述", + "coverUrl": "https://...", + "pointsPrice": 1990, + "stock": 99, + "sold": 12, + "tags": ["限时", "热卖"], + "isPhysical": true + } + ] +} +``` + +--- + +### 3.4 商品详情接口 + +**GET** `/points-mall/products/{id}` + +**描述:** 获取单个商品的详细信息 + +**路径参数:** +- `id`: 商品 ID + +**响应数据:** +```json +{ + "id": "prod_001", + "categoryId": "digital", + "name": "商品名称", + "subtitle": "商品简短描述", + "description": "商品详细描述...", + "coverUrl": "https://...", + "imageUrls": ["https://...", "https://..."], + "pointsPrice": 1990, + "originalPrice": 19.90, + "stock": 99, + "sold": 12, + "tags": ["限时", "热卖"], + "isPhysical": true, + "weight": 0.5 +} +``` + +--- + +### 3.5 兑换商品接口 + +**POST** `/points-mall/exchange` + +**描述:** 提交兑换订单,扣减积分,创建订单 + +**请求体:** +```json +{ + "productId": "prod_001", + "recipientName": "张三", + "phone": "13800138000", + "province": "广东省", + "city": "深圳市", + "district": "南山区", + "address": "科技园南区XX路XX号", + "zipCode": "518000" +} +``` + +**字段说明:** + +| 字段名 | 类型 | 必填 | 说明 | +|--------|------|------|------| +| productId | String | 是 | 商品 ID | +| recipientName | String | 是 | 收货人姓名 | +| phone | String | 是 | 手机号码 | +| province | String | 是 | 省份 | +| city | String | 是 | 城市 | +| district | String | 是 | 区/县 | +| address | String | 是 | 详细地址 | +| zipCode | String | 否 | 邮政编码 | + +**响应数据:** +```json +{ + "orderId": "order_20240601_0001", + "pointsDeducted": 1990, + "remainingPoints": 10810 +} +``` + +**错误码:** + +| code | message | 说明 | +|------|---------|------| +| 40001 | 积分不足 | 用户积分不足以兑换该商品 | +| 40002 | 商品已下架 | 商品未发布或已下架 | +| 40003 | 库存不足 | 商品库存不足 | +| 40004 | 商品不存在 | 商品 ID 无效 | + +--- + +### 3.6 兑换订单列表接口 + +**GET** `/points-mall/orders` + +**描述:** 获取用户的兑换订单列表 + +**请求参数:** + +| 参数名 | 类型 | 必填 | 说明 | +|--------|------|------|------| +| status | String | 否 | 订单状态筛选 | +| page | Int | 否 | 页码,默认 1 | +| pageSize | Int | 否 | 每页数量,默认 20 | + +**响应数据:** +```json +{ + "page": 1, + "pageSize": 20, + "total": 5, + "items": [ + { + "id": "order_20240601_0001", + "productId": "prod_001", + "productName": "商品名称", + "coverUrl": "https://...", + "pointsPrice": 1990, + "status": "shipped", + "statusText": "已发货", + "trackingCompany": "顺丰速运", + "trackingNumber": "SF1234567890", + "createdAt": "2024-06-01T10:30:00Z" + } + ] +} +``` + +--- + +### 3.7 订单详情接口 + +**GET** `/points-mall/orders/{id}` + +**描述:** 获取单个订单的详细信息 + +**路径参数:** +- `id`: 订单 ID + +**响应数据:** +```json +{ + "id": "order_20240601_0001", + "productId": "prod_001", + "productName": "商品名称", + "coverUrl": "https://...", + "pointsPrice": 1990, + "status": "shipped", + "statusText": "已发货", + "recipientName": "张三", + "phone": "13800138000", + "province": "广东省", + "city": "深圳市", + "district": "南山区", + "address": "科技园南区XX路XX号", + "zipCode": "518000", + "trackingCompany": "顺丰速运", + "trackingNumber": "SF1234567890", + "shippedAt": "2024-06-02T14:00:00Z", + "createdAt": "2024-06-01T10:30:00Z" +} +``` + +--- + +### 3.8 积分流水接口 + +**GET** `/points-mall/transactions` + +**描述:** 获取用户积分变动记录 + +**请求参数:** + +| 参数名 | 类型 | 必填 | 说明 | +|--------|------|------|------| +| type | String | 否 | 类型:`earn`(收入)、`spend`(支出) | +| page | Int | 否 | 页码,默认 1 | +| pageSize | Int | 否 | 每页数量,默认 20 | + +**响应数据:** +```json +{ + "page": 1, + "pageSize": 20, + "total": 150, + "items": [ + { + "id": 1001, + "type": "earn", + "points": 500, + "balance": 12800, + "sourceType": "api_call", + "description": "API 调用奖励", + "createdAt": "2024-06-01T10:30:00Z" + }, + { + "id": 1000, + "type": "spend", + "points": -1990, + "balance": 12300, + "sourceType": "exchange", + "sourceId": "order_20240601_0001", + "description": "兑换商品:XXX", + "createdAt": "2024-06-01T09:00:00Z" + } + ] +} +``` + +--- + +## 四、积分累积逻辑 + +### 4.1 积分累积触发时机 + +积分累积在以下场景触发: +1. **API 调用完成时**:每次成功的 LLM API 调用后,根据实际消费金额计算积分 +2. **活动奖励**:通过活动接口手动发放积分 + +### 4.2 积分计算公式 + +``` +积分 = 实际消费金额(USD) × 1000 +``` + +**示例:** +- 消费 $0.002 → 2 积分 +- 消费 $0.5 → 500 积分 +- 消费 $1.2 → 1200 积分 + +### 4.3 积分入账流程 + +1. API 调用完成,记录 token 使用量和费用 +2. 计算积分:`points = floor(costUSD * 1000)` 或四舍五入 +3. 使用事务更新 `user_points` 表: + - `points` += 新增积分 + - `total_earned` += 新增积分 +4. 写入 `point_transactions` 流水记录 +5. **注意**:需要使用乐观锁防止并发问题 + +--- + +## 五、兑换流程设计 + +### 5.1 兑换流程图 + +``` +用户点击兑换 + ↓ +验证积分是否足够 + ↓ +验证商品是否上架 + ↓ +验证库存是否充足 + ↓ +【事务开始】 +扣减用户积分 + ↓ +扣减商品库存 + ↓ +增加商品已售数量 + ↓ +创建兑换订单 + ↓ +写入积分消费流水 + ↓ +【事务提交】 + ↓ +返回订单信息 +``` + +### 5.2 并发控制 + +1. **用户积分表**:使用乐观锁(`version` 字段)防止超扣 +2. **商品库存**:使用 `UPDATE ... WHERE stock >= 1` 原子操作 +3. **事务隔离**:使用可重复读(REPEATABLE READ)级别 + +--- + +## 六、管理后台接口(可选) + +### 6.1 商品管理 + +- **POST** `/admin/points-mall/products` - 创建商品 +- **PUT** `/admin/points-mall/products/{id}` - 更新商品 +- **DELETE** `/admin/points-mall/products/{id}` - 删除商品 +- **PATCH** `/admin/points-mall/products/{id}/publish` - 上架/下架商品 + +### 6.2 订单管理 + +- **GET** `/admin/points-mall/orders` - 订单列表 +- **PUT** `/admin/points-mall/orders/{id}/ship` - 发货(填写物流信息) +- **PUT** `/admin/points-mall/orders/{id}/confirm` - 确认订单 +- **PUT** `/admin/points-mall/orders/{id}/cancel` - 取消订单(退还积分) + +--- + +## 七、注意事项 + +### 7.1 数据一致性 +- 所有涉及积分变动的操作必须使用数据库事务 +- 使用乐观锁防止并发扣减问题 +- 积分流水表是审计的重要依据,不可删除或修改 + +### 7.2 安全考虑 +- 所有接口必须经过用户认证 +- 积分扣减必须验证当前用户的积分余额 +- 防止重复提交兑换请求(可使用幂等键) + +### 7.3 性能优化 +- 用户积分数据可考虑缓存(如 Redis) +- 商品列表接口建议加缓存 +- 积分流水表建议按时间分区 + +### 7.4 监控告警 +- 积分扣除失败告警 +- 库存不足告警 +- 异常大额积分变动告警 + +--- + +## 八、前端已实现功能 + +前端已完成以下功能开发,等待后端接口对接: + +1. ✅ 积分商城首页 UI,包含积分展示 +2. ✅ 商品分类筛选、搜索、排序 +3. ✅ 商品卡片列表展示 +4. ✅ 兑换弹窗,包含收货地址表单 +5. ✅ 积分不足提示 +6. ✅ 统计页面展示消费金额与积分对应关系 +7. ✅ 1 USD = 1000 积分汇率展示