/** * 邀请注册管理控制器(后台管理) * 提供邀请注册相关的接口,不需要登录验证 */ const Framework = require("../../framework/node-core-framework.js"); const dayjs = require('dayjs'); const email_service = require('../services/email_service.js'); module.exports = { /** * @swagger * /admin_api/invite/register: * post: * summary: 邀请注册 * description: 通过邀请码注册新用户,注册成功后给邀请人增加3天试用期 * tags: [后台-邀请注册] * requestBody: * required: true * content: * application/json: * schema: * type: object * required: * - email * - password * - email_code * properties: * email: * type: string * description: 邮箱地址 * example: 'user@example.com' * password: * type: string * description: 密码 * example: 'password123' * email_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 { email, password, email_code, invite_code } = body; // 验证必填参数 if (!email || !password || !email_code) { return ctx.fail('邮箱、密码和验证码不能为空'); } // 验证邮箱格式 const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; if (!emailRegex.test(email)) { return ctx.fail('邮箱格式不正确'); } // 验证密码长度 if (password.length < 6) { return ctx.fail('密码长度不能少于6位'); } // 验证验证码 const emailVerifyResult = await verifyEmailCode(email, email_code); if (!emailVerifyResult.success) { return ctx.fail(emailVerifyResult.message || '验证码错误或已过期'); } const { pla_account } = await Framework.getModels(); // 检查邮箱是否已注册 const existingUser = await pla_account.findOne({ where: { login_name: email } }); if (existingUser) { return ctx.fail('该邮箱已被注册'); } // 验证邀请码(如果提供了邀请码) let inviter = null; let inviter_id = null; if (invite_code) { // 解析邀请码,获取邀请人ID // 邀请码格式:INV{user_id}_{timestamp} const inviteMatch = invite_code.match(/^INV(\d+)_/); if (!inviteMatch) { return ctx.fail('邀请码格式不正确'); } inviter_id = parseInt(inviteMatch[1]); // 验证邀请人是否存在 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: email.split('@')[0], // 默认使用邮箱用户名作为名称 sn_code: sn_code, device_id: '', // 设备ID由客户端登录时提供 platform_type: 'boss', // 默认平台类型 login_name: email, 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: email, // 使用邮箱代替手机号 invite_code: invite_code, register_time: new Date(), reward_status: 1, // 已发放 reward_type: 'trial_days', reward_value: 3, is_delete: 0 }); console.log(`[邀请注册] 用户 ${email} 通过邀请码 ${invite_code} 注册成功,邀请人 ${inviter.sn_code} 获得3天试用期`); } else { console.log(`[邀请注册] 用户 ${email} 注册成功(无邀请码)`); } 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-email-code: * post: * summary: 发送验证码 * description: 发送验证码到指定邮箱地址 * tags: [后台-邀请注册] * requestBody: * required: true * content: * application/json: * schema: * type: object * required: * - email * properties: * email: * type: string * description: 邮箱地址 * example: 'user@example.com' * responses: * 200: * description: 发送成功 */ 'POST /invite/send-email-code': async (ctx) => { try { const body = ctx.getBody(); const { email } = body; if (!email) { return ctx.fail('邮箱地址不能为空'); } // 验证邮箱格式 const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; if (!emailRegex.test(email)) { return ctx.fail('邮箱格式不正确'); } // 发送验证码 const emailResult = await sendEmailCode(email); if (!emailResult.success) { return ctx.fail(emailResult.message || '发送验证码失败'); } return ctx.success({ message: '验证码已发送', expire_time: emailResult.expire_time || 300 // 默认5分钟过期 }); } catch (error) { console.error('发送验证码失败:', error); return ctx.fail('发送验证码失败: ' + error.message); } } }; /** * 发送验证码 * @param {string} email 邮箱地址 * @returns {Promise<{success: boolean, message?: string, expire_time?: number}>} */ async function sendEmailCode(email) { try { // 生成6位随机验证码 const code = Math.floor(100000 + Math.random() * 900000).toString(); // 将验证码存储到缓存中(可以使用Redis或内存缓存) // 格式:email_code:{email} = {code, expire_time} const expire_time = Date.now() + 5 * 60 * 1000; // 5分钟后过期 // 这里应该存储到缓存中,暂时使用全局变量(生产环境应使用Redis) if (!global.emailCodeCache) { global.emailCodeCache = {}; } global.emailCodeCache[email] = { code: code, expire_time: expire_time }; // 调用邮件服务发送验证码 const email_result = await email_service.send_verification_code(email, code); if (!email_result.success) { // 如果邮件发送失败,删除已生成的验证码 delete global.emailCodeCache[email]; return { success: false, message: email_result.message || '发送验证码失败' }; } console.log(`[邮箱验证] 验证码已发送到 ${email}: ${code} (5分钟内有效)`); return { success: true, expire_time: 300 }; } catch (error) { console.error('发送验证码失败:', error); return { success: false, message: error.message || '发送验证码失败' }; } } /** * 验证验证码 * @param {string} email 邮箱地址 * @param {string} code 验证码 * @returns {Promise<{success: boolean, message?: string}>} */ async function verifyEmailCode(email, code) { try { if (!global.emailCodeCache) { return { success: false, message: '验证码不存在或已过期' }; } const cached = global.emailCodeCache[email]; if (!cached) { return { success: false, message: '验证码不存在或已过期' }; } // 检查是否过期 if (Date.now() > cached.expire_time) { delete global.emailCodeCache[email]; return { success: false, message: '验证码已过期,请重新获取' }; } // 验证码是否正确 if (cached.code !== code) { return { success: false, message: '验证码错误' }; } // 验证成功后删除缓存 delete global.emailCodeCache[email]; return { success: true }; } catch (error) { console.error('验证验证码失败:', error); return { success: false, message: error.message || '验证失败' }; } }