# 会员码管理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个月的会员时长。