207 lines
5.8 KiB
TypeScript
207 lines
5.8 KiB
TypeScript
/**
|
||
* 推荐码绑定API - 使用 Prisma ORM
|
||
*
|
||
* 核心规则:
|
||
* 1. 链接带ID:谁发的链接,进的人就绑谁
|
||
* 2. 一级、一月:只有一级分销;绑定有效期一个月
|
||
* 3. 长期不发:别人发得多,客户会被「抢走」
|
||
* 4. 每天发:持续发的人绑定一直有效,收益越来越高
|
||
* 5. 约90%给分发:谁发得多谁拿得多
|
||
*/
|
||
|
||
import { NextRequest, NextResponse } from 'next/server'
|
||
import { prisma } from '@/lib/prisma'
|
||
import { getPrismaConfig } from '@/lib/prisma-helpers'
|
||
|
||
const DEFAULT_BINDING_DAYS = 30
|
||
|
||
export async function POST(request: NextRequest) {
|
||
try {
|
||
const body = await request.json()
|
||
const { userId, referralCode, openId, source } = body
|
||
|
||
const effectiveUserId = userId || (openId ? `user_${openId.slice(-8)}` : null)
|
||
if (!effectiveUserId || !referralCode) {
|
||
return NextResponse.json({
|
||
success: false,
|
||
error: '用户ID和推荐码不能为空'
|
||
}, { status: 400 })
|
||
}
|
||
|
||
// 获取绑定天数配置
|
||
let bindingDays = DEFAULT_BINDING_DAYS
|
||
try {
|
||
const config = await getPrismaConfig('referral_config')
|
||
if (config?.bindingDays) {
|
||
bindingDays = Number(config.bindingDays)
|
||
}
|
||
} catch (e) {
|
||
console.warn('[Referral Bind] 使用默认配置', DEFAULT_BINDING_DAYS)
|
||
}
|
||
|
||
// 查找推荐人(使用 Prisma)
|
||
const referrer = await prisma.users.findUnique({
|
||
where: { referral_code: referralCode },
|
||
select: {
|
||
id: true,
|
||
nickname: true,
|
||
referral_code: true
|
||
}
|
||
})
|
||
|
||
if (!referrer) {
|
||
return NextResponse.json({
|
||
success: false,
|
||
error: '推荐码无效'
|
||
}, { status: 400 })
|
||
}
|
||
|
||
// 不能自己推荐自己
|
||
if (referrer.id === effectiveUserId) {
|
||
return NextResponse.json({
|
||
success: false,
|
||
error: '不能使用自己的推荐码'
|
||
}, { status: 400 })
|
||
}
|
||
|
||
// 检查用户是否存在
|
||
const user = await prisma.users.findFirst({
|
||
where: {
|
||
OR: [
|
||
{ id: effectiveUserId },
|
||
{ open_id: openId || effectiveUserId }
|
||
]
|
||
}
|
||
})
|
||
|
||
if (!user) {
|
||
return NextResponse.json({
|
||
success: false,
|
||
error: '用户不存在'
|
||
}, { status: 400 })
|
||
}
|
||
|
||
// 检查现有绑定关系
|
||
const existingBinding = await prisma.referral_bindings.findFirst({
|
||
where: {
|
||
referee_id: user.id,
|
||
status: 'active'
|
||
},
|
||
orderBy: { binding_date: 'desc' }
|
||
})
|
||
|
||
let action = 'new'
|
||
let oldReferrerId = null
|
||
|
||
// 计算新的过期时间
|
||
const expiryDate = new Date()
|
||
expiryDate.setDate(expiryDate.getDate() + bindingDays)
|
||
|
||
if (existingBinding) {
|
||
if (existingBinding.referrer_id === referrer.id) {
|
||
// 同一个推荐人 - 续期
|
||
action = 'renew'
|
||
|
||
await prisma.referral_bindings.update({
|
||
where: { id: existingBinding.id },
|
||
data: {
|
||
expiry_date: expiryDate,
|
||
binding_date: new Date()
|
||
}
|
||
})
|
||
|
||
console.log(`[Referral Bind] 续期: ${user.id} -> ${referrer.id}`)
|
||
} else {
|
||
// 不同推荐人 - 立即切换
|
||
action = 'switch'
|
||
oldReferrerId = existingBinding.referrer_id
|
||
|
||
// 使用 Prisma 事务确保原子性
|
||
await prisma.$transaction([
|
||
// 将旧绑定标记为 cancelled
|
||
prisma.referral_bindings.update({
|
||
where: { id: existingBinding.id },
|
||
data: { status: 'cancelled' }
|
||
}),
|
||
// 创建新绑定
|
||
prisma.referral_bindings.create({
|
||
data: {
|
||
id: `bind_${Date.now()}_${Math.random().toString(36).substr(2, 6)}`,
|
||
referrer_id: referrer.id,
|
||
referee_id: user.id,
|
||
referral_code: referralCode,
|
||
status: 'active',
|
||
expiry_date: expiryDate,
|
||
binding_date: new Date()
|
||
}
|
||
})
|
||
])
|
||
|
||
console.log(`[Referral Bind] 立即切换: ${user.id}: ${oldReferrerId} -> ${referrer.id}`)
|
||
}
|
||
} else {
|
||
// 新绑定
|
||
await prisma.referral_bindings.create({
|
||
data: {
|
||
id: `bind_${Date.now()}_${Math.random().toString(36).substr(2, 6)}`,
|
||
referrer_id: referrer.id,
|
||
referee_id: user.id,
|
||
referral_code: referralCode,
|
||
status: 'active',
|
||
expiry_date: expiryDate,
|
||
binding_date: new Date()
|
||
}
|
||
})
|
||
|
||
// 更新推荐人的推广数量
|
||
await prisma.users.update({
|
||
where: { id: referrer.id },
|
||
data: {
|
||
referral_count: { increment: 1 }
|
||
}
|
||
})
|
||
|
||
console.log(`[Referral Bind] 新绑定: ${user.id} -> ${referrer.id}`)
|
||
}
|
||
|
||
// 记录访问(如果有 referral_visits 表)
|
||
if (source) {
|
||
try {
|
||
await prisma.referral_visits.create({
|
||
data: {
|
||
referrer_id: referrer.id,
|
||
visitor_id: user.id,
|
||
visitor_openid: openId || null,
|
||
source: source || 'miniprogram',
|
||
page: null
|
||
}
|
||
})
|
||
} catch (e) {
|
||
console.log('[Referral Bind] 记录访问失败(表可能不存在)')
|
||
}
|
||
}
|
||
|
||
return NextResponse.json({
|
||
success: true,
|
||
message: action === 'renew' ? '绑定已续期' : action === 'switch' ? '推荐人已切换' : '绑定成功',
|
||
data: {
|
||
action,
|
||
referrer: {
|
||
id: referrer.id,
|
||
nickname: referrer.nickname
|
||
},
|
||
expiryDate,
|
||
bindingDays,
|
||
oldReferrerId
|
||
}
|
||
})
|
||
|
||
} catch (error) {
|
||
console.error('[Referral Bind] 错误:', error)
|
||
return NextResponse.json({
|
||
success: false,
|
||
error: '绑定失败: ' + (error as Error).message
|
||
}, { status: 500 })
|
||
}
|
||
}
|