2025-08-26 10:06:23 +08:00
const express = require ( 'express' ) ;
const bcrypt = require ( 'bcryptjs' ) ;
const jwt = require ( 'jsonwebtoken' ) ;
const { getDB } = require ( '../database' ) ;
const router = express . Router ( ) ;
const JWT _SECRET = process . env . JWT _SECRET || 'your-secret-key' ;
router . post ( '/register' , async ( req , res ) => {
try {
const db = getDB ( ) ;
await db . query ( 'START TRANSACTION' ) ;
2025-09-05 16:48:53 +08:00
2025-08-26 10:06:23 +08:00
const {
2025-09-05 16:48:53 +08:00
username ,
phone ,
password ,
2025-08-26 10:06:23 +08:00
city ,
2025-09-05 16:48:53 +08:00
district _id : district ,
2025-09-10 18:10:40 +08:00
province ,
inviter = '' ,
2025-08-26 10:06:23 +08:00
captchaId ,
captchaText ,
smsCode , // 短信验证码
role = 'user'
} = req . body ;
2025-09-05 16:48:53 +08:00
2025-09-10 18:10:40 +08:00
if ( ! username || ! phone || ! password || ! city || ! district || ! province ) {
2025-09-05 16:48:53 +08:00
return res . status ( 400 ) . json ( { success : false , message : '用户名、手机号、密码、城市和区域不能为空' } ) ;
2025-08-26 10:06:23 +08:00
}
2025-09-05 16:48:53 +08:00
2025-08-26 10:06:23 +08:00
if ( ! captchaId || ! captchaText ) {
return res . status ( 400 ) . json ( { success : false , message : '图形验证码不能为空' } ) ;
}
2025-09-05 16:48:53 +08:00
2025-08-26 10:06:23 +08:00
if ( ! smsCode ) {
return res . status ( 400 ) . json ( { success : false , message : '短信验证码不能为空' } ) ;
}
// 验证短信验证码
const smsAPI = require ( './sms' ) ;
const smsValid = smsAPI . verifySMSCode ( phone , smsCode ) ;
if ( ! smsValid ) {
return res . status ( 400 ) . json ( { success : false , message : '短信验证码错误或已过期' } ) ;
}
2025-09-05 16:48:53 +08:00
2025-08-26 10:06:23 +08:00
// 验证手机号格式
const phoneRegex = /^1[3-9]\d{9}$/ ;
if ( ! phoneRegex . test ( phone ) ) {
return res . status ( 400 ) . json ( { success : false , message : '手机号格式不正确' } ) ;
}
2025-09-05 16:48:53 +08:00
2025-08-26 10:06:23 +08:00
// 检查用户是否已存在
const [ existingUsers ] = await db . execute (
2025-09-05 16:48:53 +08:00
'SELECT id, payment_status FROM users WHERE username = ? OR phone = ?' ,
2025-08-26 10:06:23 +08:00
[ username , phone ]
) ;
2025-09-05 16:48:53 +08:00
2025-08-26 10:06:23 +08:00
if ( existingUsers . length > 0 ) {
2025-09-10 18:10:40 +08:00
return res . status ( 400 ) . json ( { success : false , message : '用户名或手机号已存在' } ) ;
2025-08-26 10:06:23 +08:00
}
2025-09-05 16:48:53 +08:00
2025-08-26 10:06:23 +08:00
// 加密密码
const hashedPassword = await bcrypt . hash ( password , 10 ) ;
2025-09-05 16:48:53 +08:00
// 创建用户(初始状态为未支付)
2025-08-26 10:06:23 +08:00
const [ result ] = await db . execute (
2025-09-10 18:10:40 +08:00
'INSERT INTO users (username, phone, password, role, points, audit_status, city, district_id, payment_status, province, inviter) VALUES (?, ?, ?, ?, ?, ?, ?, ?, "unpaid", ?, ?)' ,
[ username , phone , hashedPassword , role , 0 , 'pending' , city , district , province , inviter ]
2025-08-26 10:06:23 +08:00
) ;
2025-09-05 16:48:53 +08:00
2025-08-26 10:06:23 +08:00
const userId = result . insertId ;
2025-09-05 16:48:53 +08:00
// 根据地区自动关联代理
const [ agents ] = await db . execute (
'SELECT ra.id FROM users u INNER JOIN regional_agents ra ON u.id = ra.user_id WHERE ra.region_id = ? AND ra.status = "active" ORDER BY ra.created_at ASC LIMIT 1' ,
[ district ]
2025-08-26 10:06:23 +08:00
) ;
2025-09-05 16:48:53 +08:00
if ( agents . length > 0 ) {
await db . execute (
'INSERT INTO agent_merchants (agent_id, merchant_id, created_at) VALUES (?, ?, NOW())' ,
[ agents [ 0 ] . id , userId ]
2025-08-26 10:06:23 +08:00
) ;
}
2025-09-05 16:48:53 +08:00
2025-08-26 10:06:23 +08:00
await db . query ( 'COMMIT' ) ;
2025-09-05 16:48:53 +08:00
// 生成JWT token( 用于支付流程)
2025-08-26 10:06:23 +08:00
const token = jwt . sign (
{ userId : userId , username , role } ,
JWT _SECRET ,
{ expiresIn : '24h' }
) ;
2025-09-05 16:48:53 +08:00
2025-08-26 10:06:23 +08:00
res . status ( 201 ) . json ( {
success : true ,
2025-09-05 16:48:53 +08:00
message : '用户信息创建成功,请完成支付以激活账户' ,
2025-08-26 10:06:23 +08:00
token ,
user : {
id : userId ,
username ,
phone ,
role ,
points : 0 ,
audit _status : 'pending' ,
city ,
2025-09-05 16:48:53 +08:00
district ,
paymentStatus : 'unpaid'
} ,
needPayment : true
2025-08-26 10:06:23 +08:00
} ) ;
} catch ( error ) {
try {
2025-09-10 18:10:40 +08:00
// await getDB().query('ROLLBACK');
2025-08-26 10:06:23 +08:00
} catch ( rollbackError ) {
console . error ( '回滚错误:' , rollbackError ) ;
}
console . error ( '注册错误详情:' , error ) ;
console . error ( '错误堆栈:' , error . stack ) ;
2025-09-05 16:48:53 +08:00
res . status ( 500 ) . json ( {
success : false ,
2025-08-26 10:06:23 +08:00
message : '注册失败' ,
error : process . env . NODE _ENV === 'development' ? error . message : undefined
} ) ;
}
} ) ;
2025-09-10 18:10:40 +08:00
2025-08-26 10:06:23 +08:00
router . post ( '/login' , async ( req , res ) => {
try {
const db = getDB ( ) ;
const { username , password , captchaId , captchaText } = req . body ;
2025-09-05 16:48:53 +08:00
2025-08-26 10:06:23 +08:00
if ( ! username || ! password ) {
return res . status ( 400 ) . json ( { success : false , message : '用户名和密码不能为空' } ) ;
}
2025-09-05 16:48:53 +08:00
2025-08-28 09:14:56 +08:00
if ( ! captchaId || ! captchaText ) {
return res . status ( 400 ) . json ( { success : false , message : '验证码不能为空' } ) ;
}
2025-09-05 16:48:53 +08:00
// 获取存储的验证码
2025-08-28 09:14:56 +08:00
const storedCaptcha = global . captchaStore . get ( captchaId ) ;
console . log ( storedCaptcha ) ;
2025-09-05 16:48:53 +08:00
2025-08-28 09:14:56 +08:00
if ( ! storedCaptcha ) {
return res . status ( 400 ) . json ( {
success : false ,
message : '验证码不存在或已过期'
} ) ;
}
2025-09-05 16:48:53 +08:00
2025-08-28 09:14:56 +08:00
// 检查是否过期
if ( Date . now ( ) > storedCaptcha . expires ) {
global . captchaStore . delete ( captchaId ) ;
return res . status ( 400 ) . json ( {
success : false ,
message : '验证码已过期'
} ) ;
}
2025-09-05 16:48:53 +08:00
2025-08-28 09:14:56 +08:00
// 验证验证码(不区分大小写)
const isValid = storedCaptcha . text === captchaText . toLowerCase ( ) ;
2025-09-05 16:48:53 +08:00
2025-08-28 09:14:56 +08:00
// 删除已验证的验证码
global . captchaStore . delete ( captchaId ) ;
2025-09-05 16:48:53 +08:00
2025-08-28 09:14:56 +08:00
if ( ! isValid ) {
return res . status ( 400 ) . json ( {
success : false ,
message : '验证码错误'
} ) ;
}
2025-09-05 16:48:53 +08:00
2025-08-26 10:06:23 +08:00
// 注意:验证码已在前端通过 /captcha/verify 接口验证过,这里不再重复验证
2025-09-05 16:48:53 +08:00
// 查找用户(包含支付状态)
2025-08-26 10:06:23 +08:00
console . log ( '登录尝试 - 用户名:' , username ) ;
const [ users ] = await db . execute (
'SELECT * FROM users WHERE username = ?' ,
[ username ]
) ;
2025-09-05 16:48:53 +08:00
2025-08-26 10:06:23 +08:00
console . log ( '查找到的用户数量:' , users . length ) ;
if ( users . length === 0 ) {
console . log ( '用户不存在:' , username ) ;
return res . status ( 401 ) . json ( { success : false , message : '用户名或密码错误' } ) ;
}
2025-09-05 16:48:53 +08:00
2025-08-26 10:06:23 +08:00
const user = users [ 0 ] ;
console . log ( '找到用户:' , user . username , '密码长度:' , user . password ? user . password . length : 'null' ) ;
2025-09-05 16:48:53 +08:00
2025-08-26 10:06:23 +08:00
// 验证密码
console . log ( '验证密码 - 输入密码:' , password , '数据库密码前10位:' , user . password ? user . password . substring ( 0 , 10 ) : 'null' ) ;
const isValidPassword = await bcrypt . compare ( password , user . password ) ;
console . log ( '密码验证结果:' , isValidPassword ) ;
2025-09-05 16:48:53 +08:00
2025-08-26 10:06:23 +08:00
if ( ! isValidPassword ) {
console . log ( '密码验证失败' ) ;
return res . status ( 401 ) . json ( { success : false , message : '用户名或密码错误' } ) ;
}
2025-09-05 16:48:53 +08:00
// 检查支付状态(管理员除外)
if ( user . role !== 'admin' && user . payment _status === 'unpaid' ) {
const token = jwt . sign (
{ userId : user . id , username : user . username , role : user . role } ,
JWT _SECRET ,
{ expiresIn : '5m' }
) ;
return res . status ( 200 ) . json ( {
success : false ,
message : '您的账户尚未激活,请完成支付后再登录' ,
needPayment : true ,
user : user [ 0 ] ,
token
} ) ;
}
2025-08-26 10:06:23 +08:00
// 检查用户审核状态(管理员除外,只阻止被拒绝的用户)
if ( user . role !== 'admin' && user . audit _status === 'rejected' ) {
return res . status ( 403 ) . json ( { success : false , message : '您的账户审核未通过,请联系管理员' } ) ;
}
// 待审核用户可以正常登录使用系统,但匹配功能会有限制
2025-09-05 16:48:53 +08:00
2025-08-26 10:06:23 +08:00
// 生成JWT token
const token = jwt . sign (
{ userId : user . id , username : user . username , role : user . role } ,
JWT _SECRET ,
{ expiresIn : '24h' }
) ;
2025-09-05 16:48:53 +08:00
2025-08-26 10:06:23 +08:00
res . json ( {
success : true ,
message : '登录成功' ,
token ,
user : {
id : user . id ,
username : user . username ,
role : user . role ,
avatar : user . avatar ,
2025-09-05 16:48:53 +08:00
points : user . points ,
payment _status : user . payment _status
2025-08-26 10:06:23 +08:00
}
} ) ;
} catch ( error ) {
console . error ( '登录错误:' , error ) ;
res . status ( 500 ) . json ( { success : false , message : '登录失败' } ) ;
}
} ) ;
// 验证token中间件
const authenticateToken = ( req , res , next ) => {
const authHeader = req . headers [ 'authorization' ] ;
const token = authHeader && authHeader . split ( ' ' ) [ 1 ] ;
2025-09-05 16:48:53 +08:00
2025-08-26 10:06:23 +08:00
if ( ! token ) {
return res . status ( 401 ) . json ( { success : false , message : '访问令牌缺失' } ) ;
}
2025-09-05 16:48:53 +08:00
2025-08-26 10:06:23 +08:00
jwt . verify ( token , JWT _SECRET , ( err , user ) => {
if ( err ) {
return res . status ( 403 ) . json ( { success : false , message : '访问令牌无效' } ) ;
}
req . user = user ;
next ( ) ;
} ) ;
} ;
// 获取当前用户信息
router . get ( '/me' , authenticateToken , async ( req , res ) => {
try {
const db = getDB ( ) ;
const [ users ] = await db . execute (
'SELECT id, username, role, avatar, points, created_at FROM users WHERE id = ?' ,
[ req . user . userId ]
) ;
2025-09-05 16:48:53 +08:00
2025-08-26 10:06:23 +08:00
if ( users . length === 0 ) {
return res . status ( 404 ) . json ( { success : false , message : '用户不存在' } ) ;
}
2025-09-05 16:48:53 +08:00
2025-08-26 10:06:23 +08:00
res . json ( { success : true , user : users [ 0 ] } ) ;
} catch ( error ) {
console . error ( '获取用户信息错误:' , error ) ;
res . status ( 500 ) . json ( { success : false , message : '获取用户信息失败' } ) ;
}
} ) ;
// 修改密码
router . put ( '/change-password' , authenticateToken , async ( req , res ) => {
try {
const db = getDB ( ) ;
const { currentPassword , newPassword } = req . body ;
2025-09-05 16:48:53 +08:00
2025-08-26 10:06:23 +08:00
if ( ! currentPassword || ! newPassword ) {
return res . status ( 400 ) . json ( { success : false , message : '旧密码和新密码不能为空' } ) ;
}
2025-09-05 16:48:53 +08:00
2025-08-26 10:06:23 +08:00
// 获取用户当前密码
const [ users ] = await db . execute (
'SELECT password FROM users WHERE id = ?' ,
[ req . user . userId ]
) ;
2025-09-05 16:48:53 +08:00
2025-08-26 10:06:23 +08:00
if ( users . length === 0 ) {
return res . status ( 404 ) . json ( { success : false , message : '用户不存在' } ) ;
}
2025-09-05 16:48:53 +08:00
2025-08-26 10:06:23 +08:00
// 验证旧密码
const isValidPassword = await bcrypt . compare ( currentPassword , users [ 0 ] . password ) ;
2025-09-05 16:48:53 +08:00
2025-08-26 10:06:23 +08:00
if ( ! isValidPassword ) {
return res . status ( 400 ) . json ( { success : false , message : '旧密码错误' } ) ;
}
2025-09-05 16:48:53 +08:00
2025-08-26 10:06:23 +08:00
// 加密新密码
const hashedNewPassword = await bcrypt . hash ( newPassword , 10 ) ;
2025-09-05 16:48:53 +08:00
2025-08-26 10:06:23 +08:00
// 更新密码
await db . execute (
'UPDATE users SET password = ? WHERE id = ?' ,
[ hashedNewPassword , req . user . userId ]
) ;
2025-09-05 16:48:53 +08:00
2025-08-26 10:06:23 +08:00
res . json ( { success : true , message : '密码修改成功' } ) ;
} catch ( error ) {
console . error ( '修改密码错误:' , error ) ;
res . status ( 500 ) . json ( { success : false , message : '修改密码失败' } ) ;
}
} ) ;
module . exports = router ;
module . exports . authenticateToken = authenticateToken ;