# 注册积分奖励功能说明

## 📋 功能概述

新用户注册后将自动获得积分奖励，使用邀请码注册的用户，邀请人也会获得积分奖励。所有积分变动都会记录在 `points_consumption_log` 表中。

---

## 🎁 奖励规则

| 奖励类型 | 积分数量 | 说明 |
|---------|---------|------|
| **新用户注册奖励** | **200 积分** | 所有新注册用户（手机号注册/微信注册）都会获得 |
| **邀请人奖励** | **500 积分** | 当被邀请用户完成注册后，邀请人自动获得 |

---

## 🔧 实现细节

### 1. 新增 `PointsService.grantPoints()` 方法

**位置**: `src/main/java/com/dora/service/PointsService.java`

```java
/**
 * 发放积分（用于注册奖励、邀请奖励等）。
 *
 * @param userId      用户ID
 * @param amount      要发放的积分数量 (必须为正数)
 * @param description 发放原因
 */
void grantPoints(Long userId, Integer amount, String description);
```

### 2. 实现 `grantPoints()` 方法

**位置**: `src/main/java/com/dora/service/impl/PointsServiceImpl.java`

```java
@Override
@Transactional(rollbackFor = Exception.class)
public void grantPoints(Long userId, Integer amount, String description) {
    if (amount <= 0) {
        throw new IllegalArgumentException("发放积分数量必须为正数。");
    }

    User user = userMapper.findById(userId);
    if (user == null) {
        throw new IllegalArgumentException("用户不存在: " + userId);
    }

    int balanceBefore = user.getPoints();
    userMapper.updateUserPoints(userId, amount);
    int balanceAfter = balanceBefore + amount;

    createLog(userId, null, "grant", amount, balanceBefore, balanceAfter, description);
}
```

**功能说明**:
- ✅ 验证积分数量为正数
- ✅ 验证用户是否存在
- ✅ 更新用户积分余额
- ✅ 创建积分变动记录（类型: `grant`）

### 3. 手机号注册流程集成

**位置**: `src/main/java/com/dora/service/impl/UserServiceImpl.java` - `register()` 方法

**步骤10**: 在设置VIP身份后、生成JWT令牌前

```java
// 10. 发放新用户注册奖励积分
try {
    pointsService.grantPoints(userId, 200, "新用户注册奖励");
    log.info("新用户注册积分发放成功 - userId: {}, 积分: 200", userId);
    
    // 10.1 如果有邀请人，发放邀请奖励积分
    if (inviterId != null) {
        pointsService.grantPoints(inviterId, 500, "邀请新用户注册奖励");
        log.info("邀请人奖励积分发放成功 - inviterId: {}, 积分: 500, newUserId: {}", inviterId, userId);
    }
} catch (Exception e) {
    log.error("注册积分发放异常，但不影响注册流程 - userId: {}, inviterId: {}", userId, inviterId, e);
}
```

### 4. 微信用户注册流程集成

**位置**: `src/main/java/com/dora/service/impl/UserServiceImpl.java` - `getOrCreateUserByWechatOpenid()` 方法

**步骤8**: 在设置VIP身份后、初始化推广等级前

```java
// 8. 发放新用户注册奖励积分
try {
    pointsService.grantPoints(userId, 200, "新用户注册奖励");
    log.info("微信新用户注册积分发放成功 - userId: {}, 积分: 200", userId);
    
    // 8.1 如果有邀请人，发放邀请奖励积分
    if (inviterId != null) {
        pointsService.grantPoints(inviterId, 500, "邀请新用户注册奖励");
        log.info("邀请人奖励积分发放成功 - inviterId: {}, 积分: 500, newUserId: {}", inviterId, userId);
    }
} catch (Exception e) {
    log.error("微信用户注册积分发放异常，但不影响注册流程 - userId: {}, inviterId: {}", userId, inviterId, e);
}
```

---

## 📊 数据库记录

### `points_consumption_log` 表记录示例

#### 新用户注册奖励记录

```sql
INSERT INTO points_consumption_log (
    user_id, 
    task_no, 
    change_type, 
    change_amount, 
    balance_before, 
    balance_after, 
    description
) VALUES (
    17563793187762127,  -- 新用户ID
    NULL,               -- 无关联任务
    'grant',            -- 变动类型：发放
    200,                -- 发放200积分
    0,                  -- 发放前余额
    200,                -- 发放后余额
    '新用户注册奖励'
);
```

#### 邀请人奖励记录

```sql
INSERT INTO points_consumption_log (
    user_id, 
    task_no, 
    change_type, 
    change_amount, 
    balance_before, 
    balance_after, 
    description
) VALUES (
    17543607206742139,  -- 邀请人ID
    NULL,               -- 无关联任务
    'grant',            -- 变动类型：发放
    500,                -- 发放500积分
    500,                -- 发放前余额
    1000,               -- 发放后余额
    '邀请新用户注册奖励'
);
```

---

## 🔄 注册流程图

### 无邀请码注册

```
用户提交注册请求
    ↓
验证短信验证码
    ↓
检查手机号是否已注册
    ↓
创建用户记录
    ↓
设置默认VIP身份（2天）
    ↓
【发放200积分】← 新增
    ↓
生成JWT令牌
    ↓
返回用户信息（含200积分）
```

### 有邀请码注册

```
用户提交注册请求（含邀请码）
    ↓
验证短信验证码
    ↓
检查手机号是否已注册
    ↓
验证邀请码有效性
    ↓
创建用户记录
    ↓
设置默认VIP身份（2天）
    ↓
建立推广关系
    ↓
【发放200积分给新用户】← 新增
【发放500积分给邀请人】← 新增
    ↓
更新推广等级
    ↓
生成JWT令牌
    ↓
返回用户信息（含200积分）
```

---

## ⚠️ 异常处理

- **积分发放异常不影响注册流程**: 如果积分发放过程中发生异常，会记录错误日志，但不会阻止用户注册成功。
- **事务保证**: `grantPoints()` 方法使用 `@Transactional` 注解，确保积分更新和日志记录的原子性。
- **重复注册检查**: 在发放积分前已经验证用户是否存在，避免重复发放。

---

## 📝 日志记录

### 成功日志示例

```log
新用户注册积分发放成功 - userId: 17563793187762127, 积分: 200
邀请人奖励积分发放成功 - inviterId: 17543607206742139, 积分: 500, newUserId: 17563793187762127
```

### 异常日志示例

```log
ERROR - 注册积分发放异常，但不影响注册流程 - userId: 17563793187762127, inviterId: 17543607206742139
```

---

## 🧪 测试建议

### 测试场景1: 无邀请码注册
1. 使用新手机号注册
2. 验证注册成功
3. 查询用户积分余额，应为 **200**
4. 查询 `points_consumption_log` 表，应有1条 `grant` 类型记录

### 测试场景2: 有邀请码注册
1. 获取现有用户的邀请码
2. 记录邀请人的当前积分余额
3. 使用新手机号和邀请码注册
4. 验证注册成功
5. 查询新用户积分余额，应为 **200**
6. 查询邀请人积分余额，应增加 **500**
7. 查询 `points_consumption_log` 表，应有2条 `grant` 类型记录

### 测试场景3: 微信用户注册（无邀请）
1. 使用新微信openid进行微信登录
2. 验证用户自动创建
3. 查询用户积分余额，应为 **200**
4. 查询 `points_consumption_log` 表，应有1条 `grant` 类型记录

### 测试场景4: 微信用户注册（有邀请）
1. 准备一个邀请码
2. 使用新微信openid和邀请码进行微信登录
3. 验证用户自动创建
4. 查询新用户积分余额，应为 **200**
5. 查询邀请人积分余额，应增加 **500**
6. 查询 `points_consumption_log` 表，应有2条 `grant` 类型记录

---

## ✅ 修改文件清单

| 文件 | 修改内容 |
|------|---------|
| `PointsService.java` | 新增 `grantPoints()` 接口方法 |
| `PointsServiceImpl.java` | 实现 `grantPoints()` 方法 |
| `UserServiceImpl.java` | 注入 `PointsService`，在注册流程中调用积分发放 |

---

## 🎯 总结

✅ **新用户注册奖励**: 200积分  
✅ **邀请人奖励**: 500积分  
✅ **完整日志记录**: 所有积分变动都记录在数据库  
✅ **异常容错**: 积分发放失败不影响注册  
✅ **支持多种注册方式**: 手机号注册、微信注册  

---

## 📞 技术支持

如有问题，请查看日志文件或联系技术团队。

**日志关键字**:
- `新用户注册积分发放成功`
- `邀请人奖励积分发放成功`
- `注册积分发放异常`

