Files
soul-yongping/app/api/wechat/login/route.ts

148 lines
4.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// app/api/wechat/login/route.ts
// 微信小程序登录接口
import { NextRequest, NextResponse } from 'next/server'
import { query } from '@/lib/db'
// 使用真实的小程序AppID和Secret
const APPID = process.env.WECHAT_APPID || 'wxb8bbb2b10dec74aa'
const SECRET = process.env.WECHAT_APPSECRET || '3c1fb1f63e6e052222bbcead9d07fe0c'
// POST: 微信小程序登录
export async function POST(req: NextRequest) {
try {
const body = await req.json()
const { code, referralCode } = body
if (!code) {
return NextResponse.json(
{ error: '缺少code参数' },
{ status: 400 }
)
}
// 调用微信API获取session_key和openid
const wxUrl = `https://api.weixin.qq.com/sns/jscode2session?appid=${APPID}&secret=${SECRET}&js_code=${code}&grant_type=authorization_code`
const wxResponse = await fetch(wxUrl)
const wxData = await wxResponse.json()
if (wxData.errcode) {
console.error('微信登录失败:', wxData)
return NextResponse.json(
{ error: wxData.errmsg || '微信登录失败' },
{ status: 400 }
)
}
const { openid, session_key, unionid } = wxData
// 生成token
const token = Buffer.from(`${openid}:${Date.now()}`).toString('base64')
// 查询或创建用户
let user: any = null
let isNewUser = false
try {
// 先查询用户是否存在
const existingUsers = await query('SELECT * FROM users WHERE open_id = ?', [openid]) as any[]
if (existingUsers.length > 0) {
// 用户已存在更新session_key
user = existingUsers[0]
await query('UPDATE users SET session_key = ?, updated_at = NOW() WHERE open_id = ?', [session_key, openid])
console.log('[WechatLogin] 用户已存在:', user.id)
} else {
// 创建新用户
isNewUser = true
const userId = 'user_' + Date.now().toString(36) + Math.random().toString(36).substr(2, 6)
const userReferralCode = generateInviteCode(openid)
const nickname = '用户' + openid.substr(-4)
// 注意:推荐绑定逻辑已移至 /api/referral/bind这里只创建用户
// 如果有 referralCode会在前端调用 /api/referral/bind 建立绑定关系
await query(`
INSERT INTO users (
id, open_id, session_key, nickname, avatar, referral_code,
has_full_book, purchased_sections, earnings, pending_earnings, referral_count
) VALUES (?, ?, ?, ?, ?, ?, FALSE, '[]', 0, 0, 0)
`, [
userId, openid, session_key, nickname,
'https://picsum.photos/200/200?random=' + openid.substr(-2),
userReferralCode
])
// 获取新创建的用户
const newUsers = await query('SELECT * FROM users WHERE id = ?', [userId]) as any[]
user = newUsers[0]
console.log('[WechatLogin] 新用户创建成功:', userId)
}
} catch (dbError) {
console.error('[WechatLogin] 数据库操作失败,使用临时用户:', dbError)
// 数据库失败时使用临时用户信息
user = {
id: openid,
open_id: openid,
nickname: '用户' + openid.substr(-4),
avatar: 'https://picsum.photos/200/200?random=' + openid.substr(-2),
referral_code: generateInviteCode(openid),
has_full_book: false,
purchased_sections: [],
earnings: 0,
pending_earnings: 0,
referral_count: 0,
created_at: new Date().toISOString()
}
}
// 统一用户数据格式
const responseUser = {
id: user.id,
openId: user.open_id || openid,
unionid,
nickname: user.nickname,
avatar: user.avatar,
phone: user.phone,
wechatId: user.wechat_id,
referralCode: user.referral_code,
hasFullBook: user.has_full_book || false,
purchasedSections: typeof user.purchased_sections === 'string'
? JSON.parse(user.purchased_sections || '[]')
: (user.purchased_sections || []),
earnings: parseFloat(user.earnings) || 0,
pendingEarnings: parseFloat(user.pending_earnings) || 0,
referralCount: user.referral_count || 0,
createdAt: user.created_at
}
return NextResponse.json({
success: true,
token,
user: responseUser,
isNewUser,
message: isNewUser ? '注册成功' : '登录成功'
})
} catch (error) {
console.error('登录接口错误:', error)
return NextResponse.json(
{ error: '服务器错误' },
{ status: 500 }
)
}
}
// 生成邀请码
function generateInviteCode(openid: string): string {
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
const hash = openid.split('').reduce((acc, char) => acc + char.charCodeAt(0), 0)
let code = ''
for (let i = 0; i < 6; i++) {
code += chars.charAt((hash + i) % chars.length)
}
return code
}