# 会员码管理API使用说明

## 功能概述

会员码管理系统包含两个主要功能：
1. **会员码生成**：管理员可以批量生成会员码，用于分发给用户
2. **会员码激活**：用户通过输入有效的会员码来延长或激活会员服务

系统会校验会员码的有效性，并根据会员码设定的月数来更新用户的会员到期时间。

## 接口信息

### 1. 批量生成会员码

**接口地址：** `POST /vip-code/generate`

**请求参数：**

```json
{
    "numCodes": 100,
    "vipExpireTime": 12
}
```

**参数说明：**

| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| numCodes | Integer | 是 | 生成数量（1-1000） |
| vipExpireTime | Integer | 是 | 会员有效月数 |

**响应示例：**

成功响应：
```json
{
    "code": 0,
    "data": 100,
    "message": "ok"
}
```

失败响应：
```json
{
    "code": 40000,
    "data": null,
    "message": "生成数量必须大于0"
}
```

### 2. 获取可用会员码

**接口地址：** `GET /vip-code/available?vipExpireTime=1`

**请求参数：**

| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| vipExpireTime | Integer | 是 | 会员有效月数（1或12） |

**响应示例：**

成功响应：
```json
{
    "code": 0,
    "data": "ABC123DEF456GHI7",
    "message": "ok"
}
```

失败响应：
```json
{
    "code": 40400,
    "data": null,
    "message": "没有找到可用的会员码"
}
```

### 3. 激活会员码

**接口地址：** `POST /user/activate-vip`

**请求参数：**

```json
{
    "userId": 1,
    "code": "VIP_CODE_123456"
}
```

**参数说明：**

| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| userId | Long | 是 | 用户ID |
| code | String | 是 | 会员码 |

**响应示例：**

成功响应：
```json
{
    "code": 0,
    "data": true,
    "message": "ok"
}
```

失败响应：
```json
{
    "code": 40000,
    "data": null,
    "message": "会员码不存在或无效"
}
```

## 业务逻辑

### 会员码生成流程

1. **参数校验**
   - 验证生成数量大于0且不超过1000
   - 验证会员有效月数大于0

2. **生成唯一会员码**
   - 使用随机算法生成16位会员码
   - 检查数据库确保会员码唯一性
   - 重复生成直到达到指定数量

3. **会员编号分配**
   - 查询当前最大会员编号
   - 从最大编号+1开始连续分配

4. **批量插入数据库**
   - 使用事务确保数据一致性
   - 批量插入提高性能

### 获取可用会员码流程

1. **参数校验**
   - 验证会员有效月数只能是1或12

2. **数据库查询**
   - 查询指定月数的未使用会员码
   - 按创建时间升序排列，获取最早的一个
   - 确保返回的会员码处于可用状态

3. **结果返回**
   - 如果找到可用会员码，返回会员码字符串
   - 如果没有找到，返回错误信息

### 会员码激活流程

1. **参数校验**
   - 验证userId不为空
   - 验证会员码不为空或空字符串

2. **用户存在性校验**
   - 检查用户ID对应的用户是否存在
   - 不存在则抛出"用户不存在"异常

3. **会员码有效性校验**
   - 根据会员码查询vip_code表
   - 检查会员码是否存在
   - 检查会员码是否已被使用（isUse字段）

4. **会员时间计算**
   - 获取用户当前的会员到期时间（vipExpire）
   - 如果当前时间晚于会员到期时间或会员到期时间为空，则从当前时间开始计算
   - 如果当前时间早于会员到期时间，则从会员到期时间开始计算
   - 添加会员码对应的月数（vipExpireTime字段）

5. **数据库更新**
   - 更新用户表：设置isVip=1，更新vipExpire为新计算的时间
   - 更新会员码表：设置isUse=1，标记为已使用

### 数据库表结构

**vip_code表：**
- `id`: 主键
- `code`: 会员码（唯一）
- `vipExpireTime`: 会员有效月数
- `vipNumber`: 会员编号
- `isUse`: 是否使用（0-未使用，1-已使用）
- `createTime`: 创建时间
- `updateTime`: 更新时间

**user表：**
- `isVip`: 是否会员（0-非会员，1-会员）
- `vipExpire`: 会员到期时间

## 错误码说明

| 错误码 | 说明 |
|--------|------|
| 40000 | 参数错误（用户ID为空、会员码为空、用户不存在、会员码无效等） |
| 50000 | 系统错误（数据库操作失败等） |

## 使用示例

### cURL 示例

**生成会员码：**
```bash
curl -X POST http://localhost:8080/vip-code/generate \
  -H "Content-Type: application/json" \
  -d '{
    "numCodes": 100,
    "vipExpireTime": 12
  }'
```

**获取可用会员码：**
```bash
curl -X GET "http://localhost:8080/vip-code/available?vipExpireTime=1"
```

**激活会员码：**
```bash
curl -X POST http://localhost:8080/user/activate-vip \
  -H "Content-Type: application/json" \
  -d '{
    "userId": 1,
    "code": "VIP_CODE_123456"
  }'
```

### JavaScript 示例

**生成会员码：**
```javascript
const generateVipCodes = async (numCodes, vipExpireTime) => {
  try {
    const response = await fetch('/vip-code/generate', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        numCodes: numCodes,
        vipExpireTime: vipExpireTime
      })
    });
    
    const result = await response.json();
    if (result.code === 0) {
      console.log('会员码生成成功，数量:', result.data);
      return result.data;
    } else {
      console.error('会员码生成失败:', result.message);
      return 0;
    }
  } catch (error) {
    console.error('请求失败:', error);
    return 0;
  }
};
```

**获取可用会员码：**
```javascript
const getAvailableVipCode = async (vipExpireTime) => {
  try {
    const response = await fetch(`/vip-code/available?vipExpireTime=${vipExpireTime}`, {
      method: 'GET'
    });
    
    const result = await response.json();
    if (result.code === 0) {
      console.log('获取可用会员码成功:', result.data);
      return result.data;
    } else {
      console.error('获取可用会员码失败:', result.message);
      return null;
    }
  } catch (error) {
    console.error('请求失败:', error);
    return null;
  }
};
```

**激活会员码：**
```javascript
const activateVipCode = async (userId, code) => {
  try {
    const response = await fetch('/user/activate-vip', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        userId: userId,
        code: code
      })
    });
    
    const result = await response.json();
    if (result.code === 0) {
      console.log('会员码激活成功');
      return true;
    } else {
      console.error('会员码激活失败:', result.message);
      return false;
    }
  } catch (error) {
    console.error('请求失败:', error);
    return false;
  }
};
```

## 注意事项

### 会员码生成
1. **批量限制**：单次最多生成1000个会员码，避免系统负载过高
2. **唯一性保证**：系统会检查数据库确保生成的会员码唯一
3. **事务管理**：使用数据库事务确保批量插入的数据一致性
4. **性能优化**：使用批量插入提高大量数据的插入性能

### 获取可用会员码
1. **参数限制**：只支持1个月和12个月两种类型的会员码
2. **优先级策略**：按创建时间升序返回，优先返回最早创建的会员码
3. **状态检查**：只返回未使用状态的会员码
4. **库存管理**：如果指定类型的会员码已用完，会返回相应错误信息

### 会员码激活
1. **事务管理**：整个激活过程使用数据库事务，确保数据一致性
2. **重复使用**：每个会员码只能使用一次，使用后会被标记为已使用
3. **时间计算**：会员时间会根据用户当前状态智能计算，不会丢失已有的会员时间
4. **日志记录**：所有操作都有详细的日志记录，便于问题排查
5. **异常处理**：完善的异常处理机制，提供清晰的错误信息

## 测试数据

在测试环境中，可以在vip_code表中插入测试数据：

```sql
INSERT INTO vip_code (id, code, vipExpireTime, vipNumber, isUse, createTime, updateTime) 
VALUES (1, 'TEST_CODE_001', 1, 1001, 0, NOW(), NOW());

INSERT INTO vip_code (id, code, vipExpireTime, vipNumber, isUse, createTime, updateTime) 
VALUES (2, 'TEST_CODE_002', 3, 1002, 0, NOW(), NOW());

INSERT INTO vip_code (id, code, vipExpireTime, vipNumber, isUse, createTime, updateTime) 
VALUES (3, 'TEST_CODE_003', 12, 1003, 0, NOW(), NOW());
```

这些测试数据分别对应1个月、3个月和12个月的会员时长。 