# 积分充值系统使用指南

## 📋 功能概述

本系统实现了完整的积分直接购买功能，用户可以通过支付宝/微信支付直接购买积分，无需依赖礼品码。

### ✨ 核心特性

- ✅ **多套餐选择**：支持不同价格和数量的积分套餐
- ✅ **首充奖励**：首次充值额外赠送10%积分
- ✅ **赠送积分**：每个套餐可配置赠送积分
- ✅ **支付方式**：支持支付宝和微信支付
- ✅ **充值记录**：完整的充值历史记录
- ✅ **自动到账**：支付成功后自动充值到账
- ✅ **积分有效期**：可配置积分有效期（默认365天）

---

## 🗂️ 数据库结构

### 新增表

#### 1. `points_package` - 积分套餐表
```sql
CREATE TABLE `points_package` (
  `id` bigint PRIMARY KEY AUTO_INCREMENT,
  `name` varchar(64) NOT NULL COMMENT '套餐名称',
  `points` int NOT NULL COMMENT '基础积分',
  `bonus_points` int DEFAULT 0 COMMENT '赠送积分',
  `total_points` int NOT NULL COMMENT '总积分',
  `price` decimal(10,2) NOT NULL COMMENT '价格',
  `original_price` decimal(10,2) COMMENT '原价',
  `points_expire_days` int DEFAULT 365 COMMENT '有效期',
  `discount_label` varchar(32) COMMENT '优惠标签',
  `is_hot` tinyint(1) DEFAULT 0 COMMENT '是否热门',
  `is_active` tinyint(1) DEFAULT 1 COMMENT '是否上架'
);
```

**默认数据**：
| 套餐名称 | 积分 | 赠送 | 总计 | 价格 | 原价 |
|---------|------|------|------|------|------|
| 体验包 | 100 | 0 | 100 | ¥10 | - |
| 标准包 | 500 | 50 | 550 | ¥48 | ¥50 |
| 超值包 | 1000 | 150 | 1150 | ¥88 | ¥100 |
| 豪华包 | 3000 | 500 | 3500 | ¥258 | ¥300 |
| 至尊包 | 5000 | 1000 | 6000 | ¥398 | ¥500 |
| 旗舰包 | 10000 | 3000 | 13000 | ¥688 | ¥1000 |

### 扩展表

#### 2. `order` 表扩展
新增字段：
```sql
ALTER TABLE `order`
ADD COLUMN `order_type` tinyint DEFAULT 1 COMMENT '1-会员订单/2-积分订单',
ADD COLUMN `points_package_id` bigint COMMENT '积分套餐ID',
ADD COLUMN `points_amount` int COMMENT '积分数量';
```

---

## 🔌 API接口文档

### 用户端接口（`/user/points`）

#### 1. 获取积分套餐列表

**接口**：`GET /user/points/packages`

**权限**：公开访问（无需登录）

**响应示例**：
```json
{
  "code": 200,
  "message": "成功",
  "data": [
    {
      "id": 2,
      "name": "标准包",
      "description": "日常使用推荐",
      "points": 500,
      "bonusPoints": 50,
      "totalPoints": 550,
      "price": 48.00,
      "originalPrice": 50.00,
      "pointsExpireDays": 365,
      "discountLabel": "赠送50积分",
      "isHot": true,
      "isActive": true
    }
  ]
}
```

---

#### 2. 获取热门套餐

**接口**：`GET /user/points/packages/hot?limit=3`

**权限**：公开访问

**参数**：
- `limit`：数量限制，默认3

---

#### 3. 创建充值订单 ⭐

**接口**：`POST /user/points/recharge`

**权限**：需要登录

**请求体**：
```json
{
  "packageId": 2,
  "paymentMethod": 2
}
```

**参数说明**：
- `packageId`：套餐ID（必填）
- `paymentMethod`：支付方式（必填）
  - `1` = 支付宝
  - `2` = 微信支付

**响应示例**：
```json
{
  "code": 200,
  "message": "成功",
  "data": {
    "orderNo": "ORD20251021123456",
    "amount": 48.00,
    "pointsAmount": 605,
    "paymentMethod": 2,
    "paymentParams": "{\"prepay_id\":\"wx2025102112345678\"}",
    "createTime": "2025-10-21T12:34:56"
  }
}
```

**注意**：
- 首次充值会额外赠送10%积分
- `pointsAmount` = 基础积分 + 赠送积分 + 首充奖励（如果是首次）
- `paymentParams` 需要传给前端调起支付

---

#### 4. 获取充值记录

**接口**：`GET /user/points/recharge/records?page=1&size=10`

**权限**：需要登录

**响应示例**：
```json
{
  "code": 200,
  "message": "成功",
  "data": [
    {
      "orderNo": "ORD20251021123456",
      "packageName": "标准包",
      "pointsAmount": 605,
      "amount": 48.00,
      "paymentMethodName": "微信支付",
      "statusName": "已完成",
      "createTime": "2025-10-21T12:34:56",
      "paidAt": "2025-10-21T12:35:10"
    }
  ]
}
```

---

#### 5. 获取充值统计

**接口**：`GET /user/points/recharge/stats`

**权限**：需要登录

**响应示例**：
```json
{
  "code": 200,
  "message": "成功",
  "data": {
    "totalRechargeCount": 5,
    "totalAmount": 240.00,
    "totalPoints": 3025,
    "isFirstRecharge": false,
    "lastRechargeTime": "2025-10-21T12:35:10"
  }
}
```

---

### 支付回调接口（`/payment/callback`）

#### 1. 支付宝回调

**接口**：`POST /payment/callback/alipay`

**权限**：公开访问（支付宝服务器调用）

**处理流程**：
1. 验证支付宝签名
2. 检查交易状态（`TRADE_SUCCESS` 或 `TRADE_FINISHED`）
3. 调用充值处理逻辑
4. 返回 `success` 给支付宝

---

#### 2. 微信支付回调

**接口**：`POST /payment/callback/wechat`

**权限**：公开访问（微信服务器调用）

**处理流程**：
1. 解析XML数据
2. 验证微信签名
3. 检查支付结果
4. 调用充值处理逻辑
5. 返回XML响应给微信

---

#### 3. 测试回调（仅开发环境）

**接口**：`POST /payment/callback/test?orderNo=ORD20251021123456`

**权限**：公开访问

**用途**：在没有真实支付的情况下测试充值流程

**示例**：
```bash
curl -X POST "http://localhost:8080/payment/callback/test?orderNo=ORD20251021123456"
```

---

## 🔄 业务流程

### 完整充值流程

```
用户端                     后端                      支付平台
  |                         |                           |
  | 1. 浏览套餐列表          |                           |
  |------------------------>|                           |
  |    GET /packages        |                           |
  |<------------------------|                           |
  |                         |                           |
  | 2. 创建充值订单          |                           |
  |------------------------>|                           |
  |  POST /recharge         |                           |
  |    {packageId: 2}       |                           |
  |                         | 3. 生成订单               |
  |                         | 4. 生成支付参数           |
  |<------------------------|                           |
  |  {orderNo, paymentParams}                          |
  |                         |                           |
  | 5. 调起支付             |                           |
  |-------------------------------------------------->|
  |                         |                           |
  |                         |      6. 支付成功           |
  |                         |<---------------------------|
  |                         | POST /callback/alipay     |
  |                         |                           |
  |                         | 7. 验证签名               |
  |                         | 8. 增加用户积分           |
  |                         | 9. 更新订单状态           |
  |                         | 10. 记录变动日志          |
  |                         |-------------------------->|
  |                         |    返回 "success"         |
  |                         |                           |
  | 11. 查询充值记录         |                           |
  |------------------------>|                           |
  |<------------------------|                           |
```

---

## 💻 前端集成示例

### 1. 获取套餐列表

```javascript
// 获取积分套餐
async function getPackages() {
  const response = await fetch('/user/points/packages');
  const result = await response.json();
  
  if (result.code === 200) {
    displayPackages(result.data);
  }
}
```

---

### 2. 创建充值订单

```javascript
// 创建充值订单
async function recharge(packageId, paymentMethod) {
  const response = await fetch('/user/points/recharge', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': 'Bearer ' + getToken()
    },
    body: JSON.stringify({
      packageId: packageId,
      paymentMethod: paymentMethod  // 1=支付宝, 2=微信
    })
  });
  
  const result = await response.json();
  
  if (result.code === 200) {
    const { orderNo, paymentParams } = result.data;
    
    // 调起支付
    if (paymentMethod === 1) {
      // 支付宝支付
      alipay(paymentParams);
    } else {
      // 微信支付
      wechatPay(paymentParams);
    }
  }
}
```

---

### 3. 支付宝支付（示例）

```javascript
function alipay(paymentParams) {
  // 创建表单并提交
  const form = document.createElement('form');
  form.action = 'https://openapi.alipay.com/gateway.do';
  form.method = 'POST';
  form.innerHTML = paymentParams; // 支付宝SDK生成的表单
  document.body.appendChild(form);
  form.submit();
}
```

---

### 4. 微信支付（示例）

```javascript
function wechatPay(paymentParams) {
  const params = JSON.parse(paymentParams);
  
  // 调起微信支付
  WeixinJSBridge.invoke('getBrandWCPayRequest', {
    appId: params.appId,
    timeStamp: params.timeStamp,
    nonceStr: params.nonceStr,
    package: params.package,
    signType: params.signType,
    paySign: params.paySign
  }, function(res) {
    if (res.err_msg === 'get_brand_wcpay_request:ok') {
      // 支付成功，跳转到充值记录页面
      window.location.href = '/points/records';
    }
  });
}
```

---

## 🔧 后端开发说明

### 1. 支付接口对接

目前 `generatePaymentParams()` 方法返回的是模拟数据，需要对接真实的支付宝/微信SDK：

#### 支付宝SDK集成

```xml
<!-- pom.xml -->
<dependency>
    <groupId>com.alipay.sdk</groupId>
    <artifactId>alipay-sdk-java</artifactId>
    <version>4.38.0.ALL</version>
</dependency>
```

```java
// 生成支付宝支付参数
private String generateAlipayParams(Order order) {
    AlipayClient alipayClient = new DefaultAlipayClient(
        "https://openapi.alipay.com/gateway.do",
        APP_ID,
        PRIVATE_KEY,
        "json",
        "UTF-8",
        ALIPAY_PUBLIC_KEY,
        "RSA2"
    );
    
    AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
    request.setNotifyUrl("https://yourdomain.com/payment/callback/alipay");
    
    JSONObject bizContent = new JSONObject();
    bizContent.put("out_trade_no", order.getOrderNo());
    bizContent.put("total_amount", order.getAmount());
    bizContent.put("subject", "积分充值");
    bizContent.put("product_code", "QUICK_MSECURITY_PAY");
    
    request.setBizContent(bizContent.toString());
    
    AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
    return response.getBody();
}
```

#### 微信支付SDK集成

```xml
<!-- pom.xml -->
<dependency>
    <groupId>com.github.wechatpay-apiv3</groupId>
    <artifactId>wechatpay-java</artifactId>
    <version>0.2.12</version>
</dependency>
```

```java
// 生成微信支付参数
private String generateWechatPayParams(Order order) {
    // 使用微信支付SDK创建预支付订单
    // 返回prepay_id等参数
}
```

---

### 2. 回调签名验证

#### 支付宝签名验证

```java
@PostMapping("/alipay")
public String alipayCallback(HttpServletRequest request) {
    Map<String, String> params = new HashMap<>();
    Map<String, String[]> requestParams = request.getParameterMap();
    
    for (String name : requestParams.keySet()) {
        params.put(name, request.getParameter(name));
    }
    
    // 验证签名
    boolean signVerified = AlipaySignature.rsaCheckV1(
        params,
        ALIPAY_PUBLIC_KEY,
        "UTF-8",
        "RSA2"
    );
    
    if (!signVerified) {
        return "fail";
    }
    
    // 验证通过，处理业务
    String orderNo = params.get("out_trade_no");
    String tradeStatus = params.get("trade_status");
    
    if ("TRADE_SUCCESS".equals(tradeStatus)) {
        pointsRechargeService.handleRechargePaymentSuccess(orderNo);
    }
    
    return "success";
}
```

#### 微信支付签名验证

```java
@PostMapping("/wechat")
public String wechatCallback(@RequestBody String xmlData) {
    // 解析XML
    Map<String, String> params = WXPayUtil.xmlToMap(xmlData);
    
    // 验证签名
    boolean signVerified = WXPayUtil.isSignatureValid(
        params,
        WECHAT_API_KEY
    );
    
    if (!signVerified) {
        return errorXml();
    }
    
    // 验证通过，处理业务
    String orderNo = params.get("out_trade_no");
    String resultCode = params.get("result_code");
    
    if ("SUCCESS".equals(resultCode)) {
        pointsRechargeService.handleRechargePaymentSuccess(orderNo);
    }
    
    return successXml();
}
```

---

## 📊 数据库迁移

### 执行迁移脚本

```bash
# 1. 备份数据库
mysqldump -u root -p 1818ai > backup_$(date +%Y%m%d).sql

# 2. 执行V6迁移脚本
mysql -u root -p 1818ai < V6__add_points_recharge_system.sql

# 3. 验证结果
mysql -u root -p 1818ai -e "SELECT * FROM points_package;"
mysql -u root -p 1818ai -e "DESC \`order\`;"
```

---

## 🧪 测试流程

### 1. 开发环境测试

```bash
# 1. 获取套餐列表
curl -X GET "http://localhost:8080/user/points/packages"

# 2. 创建充值订单（需要登录token）
curl -X POST "http://localhost:8080/user/points/recharge" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"packageId":2,"paymentMethod":2}'

# 3. 模拟支付成功（测试用）
curl -X POST "http://localhost:8080/payment/callback/test?orderNo=ORD20251021123456"

# 4. 查看充值记录
curl -X GET "http://localhost:8080/user/points/recharge/records?page=1&size=10" \
  -H "Authorization: Bearer YOUR_TOKEN"

# 5. 查看用户积分
curl -X GET "http://localhost:8080/user/info" \
  -H "Authorization: Bearer YOUR_TOKEN"
```

### 2. 生产环境验证

1. ✅ 确认支付宝/微信支付配置正确
2. ✅ 确认回调URL可以被外网访问
3. ✅ 小额充值测试（¥0.01）
4. ✅ 验证积分到账是否正确
5. ✅ 验证首充奖励是否生效
6. ✅ 验证充值记录是否正确

---

## 🛡️ 安全配置

### SecurityConfig 配置说明

```java
// 公开接口（无需登录）
"/user/points/packages/**"  // 套餐浏览
"/payment/callback/**"      // 支付回调

// 需要登录的接口
"/user/points/recharge"     // 创建充值订单
"/user/points/recharge/**"  // 充值记录、统计
```

---

## 📈 运营建议

### 1. 套餐定价策略

- **体验包**：吸引新用户尝试
- **标准包**：日常充值主力
- **超值包**：性价比标杆，设置为热门
- **豪华包/至尊包**：满足重度用户
- **旗舰包**：年度大额充值，最高性价比

### 2. 营销活动

- **首充奖励**：已自动实现，首次充值额外赠送10%
- **限时优惠**：通过 `discount_label` 标签展示
- **热门推荐**：将主推套餐设置为 `is_hot=1`
- **节日活动**：临时调整 `bonus_points` 赠送比例

### 3. 数据分析

查看充值统计视图：
```sql
SELECT * FROM v_points_recharge_stats 
ORDER BY recharge_date DESC 
LIMIT 30;
```

---

## ❓ 常见问题

### Q1: 支付成功但积分没到账？

**检查步骤**：
1. 查看订单状态：`SELECT * FROM order WHERE order_no = 'xxx';`
2. 查看支付回调日志：检查 `/payment/callback/alipay` 日志
3. 查看用户积分：`SELECT points FROM user WHERE id = xxx;`
4. 查看积分变动日志：`SELECT * FROM points_consumption_log WHERE user_id = xxx;`

**手动补单**：
```bash
curl -X POST "http://localhost:8080/payment/callback/test?orderNo=xxx"
```

---

### Q2: 如何修改套餐价格？

```sql
UPDATE points_package 
SET price = 45.00, 
    update_time = NOW() 
WHERE id = 2;
```

---

### Q3: 如何下架某个套餐？

```sql
UPDATE points_package 
SET is_active = 0, 
    update_time = NOW() 
WHERE id = 6;
```

---

### Q4: 如何查看用户充值历史？

```sql
SELECT 
    o.order_no,
    o.amount,
    o.points_amount,
    pp.name as package_name,
    o.create_time,
    o.paid_at,
    CASE o.status
        WHEN 0 THEN '待支付'
        WHEN 1 THEN '已完成'
        WHEN 2 THEN '已取消'
        WHEN 3 THEN '支付失败'
    END as status_name
FROM `order` o
LEFT JOIN points_package pp ON o.points_package_id = pp.id
WHERE o.user_id = 123 
  AND o.order_type = 2
ORDER BY o.create_time DESC;
```

---

## 🎯 总结

✅ **功能完整**：支持套餐管理、订单创建、支付回调、充值到账全流程

✅ **安全可靠**：JWT认证、订单防重、支付签名验证

✅ **易于扩展**：支持新增支付方式、调整套餐策略

✅ **数据完整**：充值记录、变动日志、统计分析

现在用户可以直接购买积分，不再依赖礼品码！🎉

