1
This commit is contained in:
340
api/controller_admin/invite_register.js
Normal file
340
api/controller_admin/invite_register.js
Normal file
@@ -0,0 +1,340 @@
|
||||
/**
|
||||
* 邀请注册管理控制器(后台管理)
|
||||
* 提供邀请注册相关的接口,不需要登录验证
|
||||
*/
|
||||
|
||||
const Framework = require("../../framework/node-core-framework.js");
|
||||
const dayjs = require('dayjs');
|
||||
|
||||
module.exports = {
|
||||
/**
|
||||
* @swagger
|
||||
* /admin_api/invite/register:
|
||||
* post:
|
||||
* summary: 邀请注册
|
||||
* description: 通过邀请码注册新用户,注册成功后给邀请人增加3天试用期
|
||||
* tags: [后台-邀请注册]
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* required:
|
||||
* - phone
|
||||
* - password
|
||||
* - sms_code
|
||||
* - invite_code
|
||||
* properties:
|
||||
* phone:
|
||||
* type: string
|
||||
* description: 手机号
|
||||
* example: '13800138000'
|
||||
* password:
|
||||
* type: string
|
||||
* description: 密码
|
||||
* example: 'password123'
|
||||
* sms_code:
|
||||
* type: string
|
||||
* description: 短信验证码
|
||||
* example: '123456'
|
||||
* invite_code:
|
||||
* type: string
|
||||
* description: 邀请码
|
||||
* example: 'INV123_ABC123'
|
||||
* responses:
|
||||
* 200:
|
||||
* description: 注册成功
|
||||
*/
|
||||
'POST /invite/register': async (ctx) => {
|
||||
try {
|
||||
const body = ctx.getBody();
|
||||
const { phone, password, sms_code, invite_code } = body;
|
||||
|
||||
// 验证参数
|
||||
if (!phone || !password || !sms_code || !invite_code) {
|
||||
return ctx.fail('手机号、密码、短信验证码和邀请码不能为空');
|
||||
}
|
||||
|
||||
// 验证手机号格式
|
||||
const phoneRegex = /^1[3-9]\d{9}$/;
|
||||
if (!phoneRegex.test(phone)) {
|
||||
return ctx.fail('手机号格式不正确');
|
||||
}
|
||||
|
||||
// 验证密码长度
|
||||
if (password.length < 6) {
|
||||
return ctx.fail('密码长度不能少于6位');
|
||||
}
|
||||
|
||||
// 验证短信验证码(这里需要调用短信验证服务)
|
||||
const smsVerifyResult = await verifySmsCode(phone, sms_code);
|
||||
if (!smsVerifyResult.success) {
|
||||
return ctx.fail(smsVerifyResult.message || '短信验证码错误或已过期');
|
||||
}
|
||||
|
||||
const { pla_account } = await Framework.getModels();
|
||||
|
||||
// 检查手机号是否已注册
|
||||
const existingUser = await pla_account.findOne({
|
||||
where: { login_name: phone }
|
||||
});
|
||||
|
||||
if (existingUser) {
|
||||
return ctx.fail('该手机号已被注册');
|
||||
}
|
||||
|
||||
// 解析邀请码,获取邀请人ID
|
||||
// 邀请码格式:INV{user_id}_{timestamp}
|
||||
const inviteMatch = invite_code.match(/^INV(\d+)_/);
|
||||
if (!inviteMatch) {
|
||||
return ctx.fail('邀请码格式不正确');
|
||||
}
|
||||
|
||||
const inviter_id = parseInt(inviteMatch[1]);
|
||||
|
||||
// 验证邀请人是否存在
|
||||
const inviter = await pla_account.findOne({
|
||||
where: { id: inviter_id }
|
||||
});
|
||||
|
||||
if (!inviter) {
|
||||
return ctx.fail('邀请码无效,邀请人不存在');
|
||||
}
|
||||
|
||||
// 生成设备SN码(基于手机号和时间戳)
|
||||
const sn_code = `SN${Date.now()}${Math.random().toString(36).substr(2, 6).toUpperCase()}`;
|
||||
|
||||
// 创建新用户
|
||||
const newUser = await pla_account.create({
|
||||
name: phone, // 默认使用手机号作为名称
|
||||
sn_code: sn_code,
|
||||
device_id: '', // 设备ID由客户端登录时提供
|
||||
platform_type: 'boss', // 默认平台类型
|
||||
login_name: phone,
|
||||
pwd: password,
|
||||
keyword: '',
|
||||
is_enabled: 1,
|
||||
is_delete: 0,
|
||||
authorization_date: null,
|
||||
authorization_days: 0
|
||||
});
|
||||
|
||||
// 给邀请人增加3天试用期
|
||||
if (inviter) {
|
||||
const inviterData = inviter.toJSON();
|
||||
const currentAuthDate = inviterData.authorization_date;
|
||||
const currentAuthDays = inviterData.authorization_days || 0;
|
||||
|
||||
let newAuthDate = currentAuthDate;
|
||||
let newAuthDays = currentAuthDays + 3; // 增加3天
|
||||
|
||||
// 如果当前没有授权日期,则从今天开始
|
||||
if (!currentAuthDate) {
|
||||
newAuthDate = new Date();
|
||||
} else {
|
||||
// 如果当前授权已过期,从今天开始计算
|
||||
const currentEndDate = dayjs(currentAuthDate).add(currentAuthDays, 'day');
|
||||
const now = dayjs();
|
||||
if (currentEndDate.isBefore(now)) {
|
||||
newAuthDate = new Date();
|
||||
newAuthDays = 3; // 重新设置为3天
|
||||
}
|
||||
}
|
||||
|
||||
// 更新邀请人的授权信息
|
||||
await pla_account.update(
|
||||
{
|
||||
authorization_date: newAuthDate,
|
||||
authorization_days: newAuthDays
|
||||
},
|
||||
{ where: { id: inviter_id } }
|
||||
);
|
||||
|
||||
// 记录邀请记录
|
||||
const { invite_record } = await Framework.getModels();
|
||||
await invite_record.create({
|
||||
inviter_id: inviter_id,
|
||||
inviter_sn_code: inviter.sn_code,
|
||||
invitee_id: newUser.id,
|
||||
invitee_sn_code: newUser.sn_code,
|
||||
invitee_phone: phone,
|
||||
invite_code: invite_code,
|
||||
register_time: new Date(),
|
||||
reward_status: 1, // 已发放
|
||||
reward_type: 'trial_days',
|
||||
reward_value: 3,
|
||||
is_delete: 0
|
||||
});
|
||||
|
||||
console.log(`[邀请注册] 用户 ${phone} 通过邀请码 ${invite_code} 注册成功,邀请人 ${inviter.sn_code} 获得3天试用期`);
|
||||
}
|
||||
|
||||
return ctx.success({
|
||||
message: '注册成功',
|
||||
user: {
|
||||
id: newUser.id,
|
||||
sn_code: newUser.sn_code,
|
||||
login_name: newUser.login_name
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('邀请注册失败:', error);
|
||||
return ctx.fail('注册失败: ' + error.message);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /admin_api/invite/send-sms:
|
||||
* post:
|
||||
* summary: 发送短信验证码
|
||||
* description: 发送短信验证码到指定手机号
|
||||
* tags: [后台-邀请注册]
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* required:
|
||||
* - phone
|
||||
* properties:
|
||||
* phone:
|
||||
* type: string
|
||||
* description: 手机号
|
||||
* example: '13800138000'
|
||||
* responses:
|
||||
* 200:
|
||||
* description: 发送成功
|
||||
*/
|
||||
'POST /invite/send-sms': async (ctx) => {
|
||||
try {
|
||||
const body = ctx.getBody();
|
||||
const { phone } = body;
|
||||
|
||||
if (!phone) {
|
||||
return ctx.fail('手机号不能为空');
|
||||
}
|
||||
|
||||
// 验证手机号格式
|
||||
const phoneRegex = /^1[3-9]\d{9}$/;
|
||||
if (!phoneRegex.test(phone)) {
|
||||
return ctx.fail('手机号格式不正确');
|
||||
}
|
||||
|
||||
// 发送短信验证码
|
||||
const smsResult = await sendSmsCode(phone);
|
||||
if (!smsResult.success) {
|
||||
return ctx.fail(smsResult.message || '发送短信验证码失败');
|
||||
}
|
||||
|
||||
return ctx.success({
|
||||
message: '短信验证码已发送',
|
||||
expire_time: smsResult.expire_time || 300 // 默认5分钟过期
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('发送短信验证码失败:', error);
|
||||
return ctx.fail('发送短信验证码失败: ' + error.message);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 发送短信验证码
|
||||
* @param {string} phone 手机号
|
||||
* @returns {Promise<{success: boolean, message?: string, expire_time?: number}>}
|
||||
*/
|
||||
async function sendSmsCode(phone) {
|
||||
try {
|
||||
// TODO: 实现真实的短信发送逻辑
|
||||
// 这里可以使用第三方短信服务(如阿里云、腾讯云等)
|
||||
|
||||
// 生成6位随机验证码
|
||||
const code = Math.floor(100000 + Math.random() * 900000).toString();
|
||||
|
||||
// 将验证码存储到缓存中(可以使用Redis或内存缓存)
|
||||
// 格式:sms_code:{phone} = {code, expire_time}
|
||||
const expire_time = Date.now() + 5 * 60 * 1000; // 5分钟后过期
|
||||
|
||||
// 这里应该存储到缓存中,暂时使用全局变量(生产环境应使用Redis)
|
||||
if (!global.smsCodeCache) {
|
||||
global.smsCodeCache = {};
|
||||
}
|
||||
global.smsCodeCache[phone] = {
|
||||
code: code,
|
||||
expire_time: expire_time
|
||||
};
|
||||
|
||||
// TODO: 调用真实的短信发送接口
|
||||
console.log(`[短信验证] 发送验证码到 ${phone}: ${code} (5分钟内有效)`);
|
||||
|
||||
// 模拟发送成功
|
||||
return {
|
||||
success: true,
|
||||
expire_time: 300
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('发送短信验证码失败:', error);
|
||||
return {
|
||||
success: false,
|
||||
message: error.message || '发送短信验证码失败'
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证短信验证码
|
||||
* @param {string} phone 手机号
|
||||
* @param {string} code 验证码
|
||||
* @returns {Promise<{success: boolean, message?: string}>}
|
||||
*/
|
||||
async function verifySmsCode(phone, code) {
|
||||
try {
|
||||
if (!global.smsCodeCache) {
|
||||
return {
|
||||
success: false,
|
||||
message: '验证码不存在或已过期'
|
||||
};
|
||||
}
|
||||
|
||||
const cached = global.smsCodeCache[phone];
|
||||
if (!cached) {
|
||||
return {
|
||||
success: false,
|
||||
message: '验证码不存在或已过期'
|
||||
};
|
||||
}
|
||||
|
||||
// 检查是否过期
|
||||
if (Date.now() > cached.expire_time) {
|
||||
delete global.smsCodeCache[phone];
|
||||
return {
|
||||
success: false,
|
||||
message: '验证码已过期,请重新获取'
|
||||
};
|
||||
}
|
||||
|
||||
// 验证码是否正确
|
||||
if (cached.code !== code) {
|
||||
return {
|
||||
success: false,
|
||||
message: '验证码错误'
|
||||
};
|
||||
}
|
||||
|
||||
// 验证成功后删除缓存
|
||||
delete global.smsCodeCache[phone];
|
||||
|
||||
return {
|
||||
success: true
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('验证短信验证码失败:', error);
|
||||
return {
|
||||
success: false,
|
||||
message: error.message || '验证失败'
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user