This commit is contained in:
张成
2025-12-16 15:55:42 +08:00
parent f3e6413bfe
commit 41e03daa50
7 changed files with 1077 additions and 28 deletions

View File

@@ -0,0 +1,38 @@
/**
* 邀请注册 API 服务
* 封装邀请注册相关的API调用
*/
class InviteRegisterServer {
/**
* 发送短信验证码
* @param {string} phone 手机号
* @returns {Promise}
*/
sendSmsCode(phone) {
return window.framework.http.post('/invite/send-sms', {
phone: phone
});
}
/**
* 邀请注册
* @param {Object} params 注册参数
* @param {string} params.phone 手机号
* @param {string} params.password 密码
* @param {string} params.sms_code 短信验证码
* @param {string} params.invite_code 邀请码
* @returns {Promise}
*/
register(params) {
return window.framework.http.post('/invite/register', {
phone: params.phone,
password: params.password,
sms_code: params.sms_code,
invite_code: params.invite_code
});
}
}
export default new InviteRegisterServer();

View File

@@ -25,6 +25,9 @@ import JobTypes from '@/views/work/job_types.vue'
// 首页模块
import HomeIndex from '@/views/home/index.vue'
// 邀请注册模块
import InviteRegister from '@/views/invite/invite_register.vue'
/**
@@ -53,6 +56,7 @@ const componentMap = {
'system/version': Version,
'work/job_types': JobTypes,
'home/index': HomeIndex,
'invite/invite_register': InviteRegister,
}
export default componentMap

View File

@@ -0,0 +1,359 @@
<template>
<div class="invite-register-page">
<div class="register-container">
<Card class="register-card">
<div slot="title" class="card-title">
<Icon type="ios-person-add" size="24" />
<span>邀请注册</span>
</div>
<div class="register-form">
<!-- 邀请码提示 -->
<Alert v-if="inviteCode" type="success" show-icon style="margin-bottom: 20px;">
<span slot="desc">您正在通过邀请码 <strong>{{ inviteCode }}</strong> 进行注册</span>
</Alert>
<Alert v-else type="warning" show-icon style="margin-bottom: 20px;">
<span slot="desc">未检测到邀请码请通过邀请链接访问</span>
</Alert>
<Form ref="registerForm" :model="formData" :rules="formRules" :label-width="100">
<!-- 手机号 -->
<FormItem label="手机号" prop="phone">
<Input
v-model="formData.phone"
placeholder="请输入手机号"
:maxlength="11"
@on-blur="validatePhone"
>
<Icon type="ios-phone-portrait" slot="prefix" />
</Input>
</FormItem>
<!-- 密码 -->
<FormItem label="密码" prop="password">
<Input
v-model="formData.password"
type="password"
placeholder="请输入密码至少6位"
:maxlength="50"
password
>
<Icon type="ios-lock" slot="prefix" />
</Input>
</FormItem>
<!-- 确认密码 -->
<FormItem label="确认密码" prop="confirmPassword">
<Input
v-model="formData.confirmPassword"
type="password"
placeholder="请再次输入密码"
:maxlength="50"
password
>
<Icon type="ios-lock" slot="prefix" />
</Input>
</FormItem>
<!-- 短信验证码 -->
<FormItem label="短信验证码" prop="sms_code">
<div class="sms-code-wrapper">
<Input
v-model="formData.sms_code"
placeholder="请输入短信验证码"
:maxlength="6"
style="width: 200px;"
>
<Icon type="ios-keypad" slot="prefix" />
</Input>
<Button
:disabled="smsCodeDisabled"
:loading="smsCodeLoading"
@click="handleSendSmsCode"
style="margin-left: 10px;"
>
{{ smsCodeButtonText }}
</Button>
</div>
</FormItem>
<!-- 提交按钮 -->
<FormItem>
<Button
type="primary"
size="large"
:loading="registerLoading"
@click="handleRegister"
style="width: 100%;"
>
注册
</Button>
</FormItem>
</Form>
<!-- 注册说明 -->
<div class="register-tips">
<p><strong>注册说明</strong></p>
<ul>
<li>手机号将作为您的登录账号</li>
<li>密码长度至少6位建议使用字母+数字组合</li>
<li>短信验证码有效期为5分钟</li>
<li>注册成功后邀请人将获得3天试用期奖励</li>
</ul>
</div>
</div>
</Card>
</div>
</div>
</template>
<script>
import inviteRegisterServer from '@/api/invite/invite_register_server.js';
export default {
name: 'InviteRegister',
data() {
// 验证确认密码
const validateConfirmPassword = (rule, value, callback) => {
if (!value) {
callback(new Error('请再次输入密码'));
} else if (value !== this.formData.password) {
callback(new Error('两次输入的密码不一致'));
} else {
callback();
}
};
return {
inviteCode: '', // 邀请码从URL参数获取
formData: {
phone: '',
password: '',
confirmPassword: '',
sms_code: ''
},
formRules: {
phone: [
{ required: true, message: '请输入手机号', trigger: 'blur' },
{ pattern: /^1[3-9]\d{9}$/, message: '手机号格式不正确', trigger: 'blur' }
],
password: [
{ required: true, message: '请输入密码', trigger: 'blur' },
{ min: 6, message: '密码长度不能少于6位', trigger: 'blur' }
],
confirmPassword: [
{ required: true, message: '请再次输入密码', trigger: 'blur' },
{ validator: validateConfirmPassword, trigger: 'blur' }
],
sms_code: [
{ required: true, message: '请输入短信验证码', trigger: 'blur' },
{ pattern: /^\d{6}$/, message: '验证码为6位数字', trigger: 'blur' }
]
},
smsCodeLoading: false,
smsCodeDisabled: false,
smsCodeCountdown: 0,
registerLoading: false
};
},
computed: {
smsCodeButtonText() {
if (this.smsCodeCountdown > 0) {
return `${this.smsCodeCountdown}秒后重新获取`;
}
return '获取验证码';
}
},
mounted() {
// 从URL参数获取邀请码
this.getInviteCodeFromUrl();
},
methods: {
/**
* 从URL参数获取邀请码
*/
getInviteCodeFromUrl() {
const urlParams = new URLSearchParams(window.location.search);
const code = urlParams.get('code');
if (code) {
this.inviteCode = code;
} else {
this.$Message.warning('未检测到邀请码,请通过邀请链接访问');
}
},
/**
* 验证手机号
*/
validatePhone() {
this.$refs.registerForm.validateField('phone');
},
/**
* 发送短信验证码
*/
async handleSendSmsCode() {
// 先验证手机号
this.$refs.registerForm.validateField('phone', async (valid) => {
if (!valid) {
return;
}
if (!this.formData.phone) {
this.$Message.error('请先输入手机号');
return;
}
// 验证手机号格式
const phoneRegex = /^1[3-9]\d{9}$/;
if (!phoneRegex.test(this.formData.phone)) {
this.$Message.error('手机号格式不正确');
return;
}
this.smsCodeLoading = true;
try {
const result = await inviteRegisterServer.sendSmsCode(this.formData.phone);
if (result.code === 0) {
this.$Message.success('短信验证码已发送,请注意查收');
// 开始倒计时
this.startCountdown();
} else {
this.$Message.error(result.message || '发送短信验证码失败');
}
} catch (error) {
const errorMessage = error.response?.data?.message || error.message || '发送短信验证码失败';
this.$Message.error(errorMessage);
} finally {
this.smsCodeLoading = false;
}
});
},
/**
* 开始倒计时
*/
startCountdown() {
this.smsCodeCountdown = 60;
this.smsCodeDisabled = true;
const timer = setInterval(() => {
this.smsCodeCountdown--;
if (this.smsCodeCountdown <= 0) {
clearInterval(timer);
this.smsCodeDisabled = false;
}
}, 1000);
},
/**
* 注册
*/
async handleRegister() {
// 验证表单
this.$refs.registerForm.validate(async (valid) => {
if (!valid) {
return;
}
if (!this.inviteCode) {
this.$Message.error('邀请码不能为空,请通过邀请链接访问');
return;
}
this.registerLoading = true;
try {
const result = await inviteRegisterServer.register({
phone: this.formData.phone,
password: this.formData.password,
sms_code: this.formData.sms_code,
invite_code: this.inviteCode
});
if (result.code === 0) {
this.$Message.success('注册成功!');
// 延迟跳转到登录页面或提示用户登录
setTimeout(() => {
this.$Message.info('请使用注册的手机号和密码登录');
// 可以跳转到登录页面
// this.$router.push('/login');
}, 2000);
} else {
this.$Message.error(result.message || '注册失败');
}
} catch (error) {
const errorMessage = error.response?.data?.message || error.message || '注册失败';
this.$Message.error(errorMessage);
} finally {
this.registerLoading = false;
}
});
}
}
};
</script>
<style lang="less" scoped>
.invite-register-page {
min-height: 100vh;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
}
.register-container {
width: 100%;
max-width: 500px;
}
.register-card {
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.2);
border-radius: 8px;
overflow: hidden;
}
.card-title {
display: flex;
align-items: center;
gap: 10px;
font-size: 20px;
font-weight: 600;
color: #2d8cf0;
}
.register-form {
padding: 20px 0;
}
.sms-code-wrapper {
display: flex;
align-items: center;
}
.register-tips {
margin-top: 30px;
padding: 15px;
background: #f8f8f9;
border-radius: 4px;
border-left: 4px solid #2d8cf0;
p {
margin: 0 0 10px 0;
font-weight: 600;
color: #515a6e;
}
ul {
margin: 0;
padding-left: 20px;
color: #808695;
li {
margin-bottom: 5px;
line-height: 1.6;
}
}
}
</style>

View 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 || '验证失败'
};
}
}

View File

@@ -9,32 +9,59 @@ module.exports = {
/**
* @swagger
* /api/invite/info:
* get:
* post:
* summary: 获取邀请信息
* description: 根据用户ID获取邀请码和邀请链接
* description: 根据设备SN码获取邀请码和邀请链接
* tags: [前端-推广邀请]
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* required:
* - sn_code
* properties:
* sn_code:
* type: string
* description: 设备SN码
* responses:
* 200:
* description: 获取成功
*/
'GET /invite/info': async (ctx) => {
'POST /invite/info': async (ctx) => {
try {
// 从query或body中获取user_id实际应该从token中解析
// 从body中获取sn_code
const body = ctx.getBody();
const user_id = body.user_id || ctx.query?.user_id;
const { sn_code } = body;
if (!user_id) {
return ctx.fail('请先登录');
if (!sn_code) {
return ctx.fail('请提供设备SN码');
}
// 生成邀请码基于用户ID
const invite_code = `INV${user_id}${Date.now().toString(36).toUpperCase()}`;
const { pla_account } = await Framework.getModels();
// 根据sn_code查找用户
const user = await pla_account.findOne({
where: { sn_code }
});
if (!user) {
return ctx.fail('用户不存在');
}
// 生成邀请码基于用户ID和sn_code
const invite_code = `INV${user.id}_${Date.now().toString(36).toUpperCase()}`;
const invite_link = `https://work.light120.com/invite?code=${invite_code}`;
// 保存邀请码到用户记录可以保存到invite_code字段如果没有则保存到备注或其他字段
// 这里暂时不保存到数据库,每次生成新的
return ctx.success({
invite_code,
invite_link,
user_id
user_id: user.id,
sn_code: user.sn_code
});
} catch (error) {
console.error('获取邀请信息失败:', error);
@@ -45,30 +72,83 @@ module.exports = {
/**
* @swagger
* /api/invite/statistics:
* get:
* post:
* summary: 获取邀请统计
* description: 根据用户ID获取邀请统计数据
* description: 根据设备SN码获取邀请统计数据
* tags: [前端-推广邀请]
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* required:
* - sn_code
* properties:
* sn_code:
* type: string
* description: 设备SN码
* responses:
* 200:
* description: 获取成功
*/
'GET /invite/statistics': async (ctx) => {
'POST /invite/statistics': async (ctx) => {
try {
// 从query或body中获取user_id实际应该从token中解析
// 从body中获取sn_code
const body = ctx.getBody() || {};
const user_id = body.user_id || ctx.query?.user_id;
const { sn_code } = body;
if (!user_id) {
return ctx.fail('请先登录');
if (!sn_code) {
return ctx.fail('请提供设备SN码');
}
// 这里可以从数据库查询邀请统计,暂时返回模拟数据
const { pla_account } = await Framework.getModels();
// 根据sn_code查找用户
const user = await pla_account.findOne({
where: { sn_code }
});
if (!user) {
return ctx.fail('用户不存在');
}
// 查询邀请统计
const { invite_record } = await Framework.getModels();
// 查询总邀请数
const totalInvites = await invite_record.count({
where: {
inviter_id: user.id,
is_delete: 0
}
});
// 查询已发放奖励的邀请数(活跃邀请)
const activeInvites = await invite_record.count({
where: {
inviter_id: user.id,
reward_status: 1,
is_delete: 0
}
});
// 查询总奖励天数
const rewardRecords = await invite_record.findAll({
where: {
inviter_id: user.id,
reward_status: 1,
is_delete: 0
},
attributes: ['reward_value']
});
const totalRewardDays = rewardRecords.reduce((sum, record) => {
return sum + (record.reward_value || 0);
}, 0);
return ctx.success({
totalInvites: 0,
activeInvites: 0,
rewardPoints: 0,
rewardAmount: 0
totalInvites: totalInvites || 0
});
} catch (error) {
console.error('获取邀请统计失败:', error);
@@ -89,16 +169,27 @@ module.exports = {
*/
'POST /invite/generate': async (ctx) => {
try {
// 从query或body中获取user_id实际应该从token中解析
// 从body中获取sn_code
const body = ctx.getBody() || {};
const user_id = body.user_id || ctx.query?.user_id;
const { sn_code } = body;
if (!user_id) {
return ctx.fail('请先登录');
if (!sn_code) {
return ctx.fail('请提供设备SN码');
}
const { pla_account } = await Framework.getModels();
// 根据sn_code查找用户
const user = await pla_account.findOne({
where: { sn_code }
});
if (!user) {
return ctx.fail('用户不存在');
}
// 生成新的邀请码
const invite_code = `INV${user_id}${Date.now().toString(36).toUpperCase()}`;
const invite_code = `INV${user.id}_${Date.now().toString(36).toUpperCase()}`;
const invite_link = `https://work.light120.com/invite?code=${invite_code}`;
return ctx.success({
@@ -109,6 +200,100 @@ module.exports = {
console.error('生成邀请码失败:', error);
return ctx.fail('生成邀请码失败: ' + error.message);
}
},
/**
* @swagger
* /api/invite/records:
* post:
* summary: 获取邀请记录列表
* description: 根据设备SN码获取邀请记录列表
* tags: [前端-推广邀请]
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* required:
* - sn_code
* properties:
* sn_code:
* type: string
* description: 设备SN码
* page:
* type: integer
* description: 页码可选默认1
* pageSize:
* type: integer
* description: 每页数量可选默认20
* responses:
* 200:
* description: 获取成功
*/
'POST /invite/records': async (ctx) => {
try {
const body = ctx.getBody() || {};
const { sn_code, page = 1, pageSize = 20 } = body;
if (!sn_code) {
return ctx.fail('请提供设备SN码');
}
const { pla_account, invite_record } = await Framework.getModels();
// 根据sn_code查找用户
const user = await pla_account.findOne({
where: { sn_code }
});
if (!user) {
return ctx.fail('用户不存在');
}
// 查询邀请记录列表
const offset = (page - 1) * pageSize;
const records = await invite_record.findAll({
where: {
inviter_id: user.id,
is_delete: 0
},
order: [['register_time', 'DESC']],
limit: pageSize,
offset: offset
});
const total = await invite_record.count({
where: {
inviter_id: user.id,
is_delete: 0
}
});
// 格式化记录数据
const formattedRecords = records.map(record => {
const recordData = record.toJSON();
return {
id: recordData.id,
invitee_phone: recordData.invitee_phone,
invite_code: recordData.invite_code,
register_time: recordData.register_time,
reward_status: recordData.reward_status,
reward_value: recordData.reward_value,
reward_type: recordData.reward_type
};
});
return ctx.success({
list: formattedRecords,
total: total,
page: page,
pageSize: pageSize
});
} catch (error) {
console.error('获取邀请记录列表失败:', error);
return ctx.fail('获取邀请记录列表失败: ' + error.message);
}
}
};

123
api/model/invite_record.js Normal file
View File

@@ -0,0 +1,123 @@
/**
* 邀请记录表模型
* 记录用户邀请注册的信息
*/
const Sequelize = require('sequelize');
module.exports = (db) => {
const invite_record = db.define("invite_record", {
// 邀请人ID关联 pla_account.id
inviter_id: {
comment: '邀请人ID',
type: Sequelize.INTEGER,
allowNull: false,
references: {
model: 'pla_account',
key: 'id'
}
},
// 邀请人SN码
inviter_sn_code: {
comment: '邀请人SN码',
type: Sequelize.STRING(50),
allowNull: false,
defaultValue: ''
},
// 被邀请人ID关联 pla_account.id
invitee_id: {
comment: '被邀请人ID',
type: Sequelize.INTEGER,
allowNull: false,
references: {
model: 'pla_account',
key: 'id'
}
},
// 被邀请人SN码
invitee_sn_code: {
comment: '被邀请人SN码',
type: Sequelize.STRING(50),
allowNull: false,
defaultValue: ''
},
// 被邀请人手机号
invitee_phone: {
comment: '被邀请人手机号',
type: Sequelize.STRING(20),
allowNull: false,
defaultValue: ''
},
// 邀请码
invite_code: {
comment: '邀请码',
type: Sequelize.STRING(100),
allowNull: false,
defaultValue: ''
},
// 注册时间
register_time: {
comment: '注册时间',
type: Sequelize.DATE,
allowNull: false,
defaultValue: Sequelize.NOW
},
// 奖励状态0=未发放1=已发放)
reward_status: {
comment: '奖励状态0=未发放1=已发放)',
type: Sequelize.TINYINT(1),
allowNull: false,
defaultValue: 0
},
// 奖励类型trial_days=试用期天数)
reward_type: {
comment: '奖励类型',
type: Sequelize.STRING(50),
allowNull: false,
defaultValue: 'trial_days'
},
// 奖励值(试用期天数)
reward_value: {
comment: '奖励值(试用期天数)',
type: Sequelize.INTEGER,
allowNull: false,
defaultValue: 3
},
// 备注
remark: {
comment: '备注',
type: Sequelize.TEXT,
allowNull: true
}
}, {
tableName: 'invite_record',
indexes: [
{
name: 'idx_inviter_id',
fields: ['inviter_id']
},
{
name: 'idx_invitee_id',
fields: ['invitee_id']
},
{
name: 'idx_invite_code',
fields: ['invite_code']
},
{
name: 'idx_register_time',
fields: ['register_time']
},
{
name: 'idx_reward_status',
fields: ['reward_status']
}
]
});
// invite_record.sync({ alter: true });
return invite_record;
};

View File

@@ -64,7 +64,7 @@ module.exports = {
},
// 白名单URL - 不需要token验证的接口
"allowUrls": ["/admin_api/sys_user/login", "/admin_api/sys_user/authorityMenus", "/admin_api/sys_user/register", "/api/user/loginByWeixin", "/file/", "/sys_file/", "/admin_api/win_data/viewLogInfo", "/api/user/wx_auth", '/api/docs', 'api/swagger.json', 'payment/notify', 'payment/refund-notify', 'wallet/transfer_notify', 'user/sms/send', 'user/sms/verify', '/api/version/check','/api/file/upload_file_to_oss_by_auto_work','/api/version/create'],
"allowUrls": ["/admin_api/sys_user/login", "/admin_api/sys_user/authorityMenus", "/admin_api/sys_user/register", "/api/user/loginByWeixin", "/file/", "/sys_file/", "/admin_api/win_data/viewLogInfo", "/api/user/wx_auth", '/api/docs', 'api/swagger.json', 'payment/notify', 'payment/refund-notify', 'wallet/transfer_notify', 'user/sms/send', 'user/sms/verify', '/api/version/check','/api/file/upload_file_to_oss_by_auto_work','/api/version/create', '/admin_api/invite/register', '/admin_api/invite/send-sms'],
// AI服务配置