2025-08-26 10:06:23 +08:00
const express = require ( 'express' ) ;
const bcrypt = require ( 'bcryptjs' ) ;
const { getDB } = require ( '../database' ) ;
const { auth , adminAuth } = require ( '../middleware/auth' ) ;
const dayjs = require ( 'dayjs' ) ;
const router = express . Router ( ) ;
2025-08-28 09:14:56 +08:00
/ * *
* @ swagger
* tags :
* name : Users
* description : 用户管理API
* /
/ * *
* @ swagger
* components :
* schemas :
* User :
* type : object
* required :
* - username
* - password
* - real _name
* - id _card
* properties :
* id :
* type : integer
* description : 用户ID
* username :
* type : string
* description : 用户名
* role :
* type : string
* description : 用户角色
* enum : [ user , admin , merchant ]
* avatar :
* type : string
* description : 用户头像URL
* points :
* type : integer
* description : 用户积分
* real _name :
* type : string
* description : 真实姓名
* id _card :
* type : string
* description : 身份证号
* phone :
* type : string
* description : 手机号
* is _system _account :
* type : boolean
* description : 是否为系统账户
* created _at :
* type : string
* format : date - time
* description : 创建时间
* updated _at :
* type : string
* format : date - time
* description : 更新时间
* /
/ * *
* @ swagger
* / u s e r s :
* post :
* summary : 创建用户 ( 管理员权限 )
* tags : [ Users ]
* security :
* - bearerAuth : [ ]
* requestBody :
* required : true
* content :
* application / json :
* schema :
* type : object
* required :
* - username
* - password
* - real _name
* - id _card
* properties :
* username :
* type : string
* password :
* type : string
* role :
* type : string
* enum : [ user , admin , merchant ]
* default : user
* is _system _account :
* type : boolean
* default : false
* real _name :
* type : string
* id _card :
* type : string
* wechat _qr :
* type : string
* alipay _qr :
* type : string
* bank _card :
* type : string
* unionpay _qr :
* type : string
* phone :
* type : string
* responses :
* 201 :
* description : 用户创建成功
* content :
* application / json :
* schema :
* type : object
* properties :
* success :
* type : boolean
* message :
* type : string
* user :
* $ref : '#/components/schemas/User'
* 400 :
* description : 请求参数错误
* 401 :
* description : 未授权
* 403 :
* description : 权限不足
* 500 :
* description : 服务器错误
* /
2025-08-26 10:06:23 +08:00
router . post ( '/' , auth , adminAuth , async ( req , res ) => {
try {
const db = getDB ( ) ;
await db . query ( 'START TRANSACTION' ) ;
const {
username ,
password ,
role = 'user' ,
isSystemAccount = false , // 是否为虚拟商户
realName ,
idCard ,
wechatQr ,
alipayQr ,
bankCard ,
unionpayQr ,
phone
} = req . body ;
if ( ! username || ! password ) {
return res . status ( 400 ) . json ( { success : false , message : '用户名和密码不能为空' } ) ;
}
if ( ! realName || ! idCard ) {
return res . status ( 400 ) . json ( { success : false , message : '姓名和身份证号不能为空' } ) ;
}
// 验证身份证号格式
const idCardRegex = /^[1-9]\d{5}(18|19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/ ;
if ( ! idCardRegex . test ( idCard ) ) {
return res . status ( 400 ) . json ( { success : false , message : '身份证号格式不正确' } ) ;
}
// 检查用户是否已存在
const [ existingUsers ] = await db . execute (
'SELECT id FROM users WHERE username = ? OR id_card = ? OR (phone IS NOT NULL AND phone = ?)' ,
[ username , idCard , phone || null ]
) ;
if ( existingUsers . length > 0 ) {
return res . status ( 400 ) . json ( { success : false , message : '用户名、身份证号或手机号已存在' } ) ;
}
// 加密密码
const hashedPassword = await bcrypt . hash ( password , 10 ) ;
// 创建用户
const [ result ] = await db . execute (
'INSERT INTO users (username, password, role, is_system_account, points, real_name, id_card, wechat_qr, alipay_qr, bank_card, unionpay_qr, phone) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)' ,
[ username , hashedPassword , role , isSystemAccount , 0 , realName , idCard , wechatQr , alipayQr , bankCard , unionpayQr , phone ]
) ;
const userId = result . insertId ;
// 用户余额已在创建用户时设置为默认值0.00,无需额外操作
await db . query ( 'COMMIT' ) ;
// 返回创建的用户信息(不包含密码)
const [ newUser ] = await db . execute (
'SELECT id, username, role, avatar, points, real_name, phone, created_at, updated_at FROM users WHERE id = ?' ,
[ userId ]
) ;
res . status ( 201 ) . json ( {
success : true ,
message : '用户创建成功' ,
user : newUser [ 0 ]
} ) ;
} catch ( error ) {
try {
await getDB ( ) . query ( 'ROLLBACK' ) ;
} catch ( rollbackError ) {
console . error ( '回滚错误:' , rollbackError ) ;
}
console . error ( '创建用户错误:' , error ) ;
res . status ( 500 ) . json ( { success : false , message : '创建用户失败' } ) ;
}
} ) ;
/ * *
2025-08-28 09:14:56 +08:00
* @ swagger
* / u s e r s / p e n d i n g - a u d i t :
* get :
* summary : 获取待审核用户列表 ( 管理员权限 )
* tags : [ Users ]
* security :
* - bearerAuth : [ ]
* parameters :
* - in : query
* name : page
* schema :
* type : integer
* default : 1
* description : 页码
* - in : query
* name : limit
* schema :
* type : integer
* default : 10
* description : 每页数量
* responses :
* 200 :
* description : 成功获取待审核用户列表
* content :
* application / json :
* schema :
* type : object
* properties :
* success :
* type : boolean
* data :
* type : object
* properties :
* users :
* type : array
* items :
* $ref : '#/components/schemas/User'
* pagination :
* type : object
* properties :
* page :
* type : integer
* limit :
* type : integer
* total :
* type : integer
* pages :
* type : integer
* 401 :
* description : 未授权
* 403 :
* description : 权限不足
* 500 :
* description : 服务器错误
2025-08-26 10:06:23 +08:00
* /
router . get ( '/pending-audit' , auth , adminAuth , async ( req , res ) => {
try {
const db = getDB ( ) ;
const { page = 1 , limit = 10 } = req . query ;
const pageNum = parseInt ( page ) || 1 ;
const limitNum = parseInt ( limit ) || 10 ;
const offset = ( pageNum - 1 ) * limitNum ;
// 获取待审核用户总数
const [ countResult ] = await db . execute (
'SELECT COUNT(*) as total FROM users WHERE audit_status = ?' ,
[ 'pending' ]
) ;
const total = countResult [ 0 ] . total ;
// 获取待审核用户列表
const [ users ] = await db . execute (
` SELECT id, username, phone, real_name, business_license, id_card_front, id_card_back,
wechat _qr , alipay _qr , unionpay _qr , bank _card , audit _status , created _at
FROM users
WHERE audit _status = ?
ORDER BY created _at ASC
LIMIT $ { limitNum } OFFSET $ { offset } ` ,
[ 'pending' ]
) ;
res . json ( {
success : true ,
data : {
users ,
pagination : {
page : pageNum ,
limit : limitNum ,
total ,
pages : Math . ceil ( total / limitNum )
}
}
} ) ;
} catch ( error ) {
console . error ( '获取待审核用户列表错误:' , error ) ;
res . status ( 500 ) . json ( { success : false , message : '获取待审核用户列表失败' } ) ;
}
} ) ;
// 获取用户列表用于转账(普通用户权限)
router . get ( '/for-transfer' , auth , async ( req , res ) => {
try {
const db = getDB ( ) ;
// 获取所有用户的基本信息(用于转账选择)
const [ users ] = await db . execute (
'SELECT id, username, real_name FROM users WHERE id != ? ORDER BY username' ,
[ req . user . id ]
) ;
res . json ( {
success : true ,
data : users
} ) ;
} catch ( error ) {
console . error ( '获取转账用户列表错误:' , error ) ;
res . status ( 500 ) . json ( { success : false , message : '获取用户列表失败' } ) ;
}
} ) ;
// 获取用户列表(管理员权限)
router . get ( '/' , auth , adminAuth , async ( req , res ) => {
try {
const db = getDB ( ) ;
const { page = 1 , limit = 10 , search = '' , role = '' , city = '' , district = '' , sort = 'created_at' , order = 'desc' } = req . query ;
// 确保参数为有效数字
const pageNum = Math . max ( 1 , parseInt ( page ) || 1 ) ;
const limitNum = Math . max ( 1 , Math . min ( 100 , parseInt ( limit ) || 10 ) ) ;
const offset = Math . max ( 0 , ( pageNum - 1 ) * limitNum ) ;
let whereConditions = [ ] ;
let countParams = [ ] ;
let listParams = [ ] ;
// 构建查询条件
if ( search ) {
whereConditions . push ( '(u.username LIKE ? OR u.real_name LIKE ?)' ) ;
countParams . push ( ` % ${ search } % ` , ` % ${ search } % ` ) ;
listParams . push ( ` % ${ search } % ` , ` % ${ search } % ` ) ;
}
if ( role && role !== 'all' ) {
whereConditions . push ( 'u.role = ?' ) ;
countParams . push ( role ) ;
listParams . push ( role ) ;
}
if ( city ) {
whereConditions . push ( 'u.city = ?' ) ;
countParams . push ( city ) ;
listParams . push ( city ) ;
}
if ( district ) {
whereConditions . push ( 'u.district_id = ?' ) ;
countParams . push ( district ) ;
listParams . push ( district ) ;
}
const whereClause = whereConditions . length > 0 ? ` WHERE ${ whereConditions . join ( ' AND ' ) } ` : '' ;
// 添加分页参数
listParams . push ( limitNum . toString ( ) , offset . toString ( ) ) ;
// 获取总数
const [ countResult ] = await db . execute (
` SELECT COUNT(*) as total FROM users u
LEFT JOIN zhejiang _regions r ON u . district _id = r . id
$ { whereClause } ` ,
countParams
) ;
// 验证排序字段, 防止SQL注入
const validSortFields = [ 'id' , 'username' , 'role' , 'points' , 'balance' , 'created_at' , 'updated_at' ] ;
const sortField = validSortFields . includes ( sort ) ? sort : 'created_at' ;
// 验证排序方向
const sortOrder = ( order && ( order . toUpperCase ( ) === 'ASC' || order . toUpperCase ( ) === 'DESC' ) )
? order . toUpperCase ( )
: 'DESC' ;
// 获取用户列表,关联地区信息和转账统计
const [ users ] = await db . execute (
` SELECT u.id, u.username, u.role, u.avatar, u.points, u.balance, u.real_name, u.id_card, u.phone,
u . wechat _qr , u . alipay _qr , u . bank _card , u . unionpay _qr , u . audit _status , u . is _system _account ,
u . created _at , u . updated _at , u . city , u . district _id , u . id _card _front , u . id _card _back ,
u . business _license ,
r . city _name , r . district _name ,
COALESCE ( yesterday _out . amount , 0 ) as yesterday _transfer _amount ,
COALESCE ( today _in . amount , 0 ) as today _received _amount
FROM users u
LEFT JOIN zhejiang _regions r ON u . district _id = r . id
LEFT JOIN (
SELECT from _user _id , SUM ( amount ) as amount
FROM transfers
WHERE created _at >= DATE ( DATE _SUB ( NOW ( ) , INTERVAL 1 DAY ) )
AND created _at < DATE ( NOW ( ) )
AND status IN ( 'confirmed' , 'received' )
GROUP BY from _user _id
) yesterday _out ON u . id = yesterday _out . from _user _id
LEFT JOIN (
SELECT to _user _id , SUM ( amount ) as amount
FROM transfers
WHERE created _at >= DATE ( NOW ( ) )
AND created _at < DATE ( DATE _ADD ( NOW ( ) , INTERVAL 1 DAY ) )
AND status IN ( 'confirmed' , 'received' )
GROUP BY to _user _id
) today _in ON u . id = today _in . to _user _id
$ { whereClause }
ORDER BY u . $ { sortField } $ { sortOrder }
LIMIT ? OFFSET ? ` ,
listParams
) ;
res . json ( {
success : true ,
users ,
total : countResult [ 0 ] . total ,
page : pageNum ,
limit : limitNum ,
totalPages : Math . ceil ( countResult [ 0 ] . total / limitNum )
} ) ;
} catch ( error ) {
console . error ( '获取用户列表错误:' , error ) ;
res . status ( 500 ) . json ( { success : false , message : '获取用户列表失败' } ) ;
}
} ) ;
// 获取当前用户的个人资料
router . get ( '/profile' , auth , async ( req , res ) => {
try {
const db = getDB ( ) ;
const userId = req . user . id ;
const [ users ] = await db . execute (
'SELECT * FROM users WHERE id = ?' ,
[ userId ]
) ;
if ( users . length === 0 ) {
return res . status ( 404 ) . json ( { success : false , message : '用户不存在' } ) ;
}
const profile = {
... users [ 0 ] ,
nickname : users [ 0 ] . username , // 添加nickname字段, 映射到username
realName : users [ 0 ] . real _name ,
idCard : users [ 0 ] . id _card ,
wechatQr : users [ 0 ] . wechat _qr ,
alipayQr : users [ 0 ] . alipay _qr ,
bankCard : users [ 0 ] . bank _card ,
unionpayQr : users [ 0 ] . unionpay _qr ,
businessLicense : users [ 0 ] . business _license ,
idCardFront : users [ 0 ] . id _card _front ,
idCardBack : users [ 0 ] . id _card _back
} ;
res . json ( { success : true , user : profile } ) ;
} catch ( error ) {
console . error ( '获取用户资料错误:' , error ) ;
res . status ( 500 ) . json ( { success : false , message : '获取用户资料失败' } ) ;
}
} ) ;
/ * *
* 获取当前用户的收款码状态
* 用于检查用户是否已上传微信 、 支付宝 、 云闪付收款码
* /
router . get ( '/payment-codes-status' , auth , async ( req , res ) => {
try {
const db = getDB ( ) ;
const userId = req . user . id ;
const [ users ] = await db . execute (
'SELECT wechat_qr, alipay_qr, unionpay_qr FROM users WHERE id = ?' ,
[ userId ]
) ;
if ( users . length === 0 ) {
return res . status ( 404 ) . json ( { success : false , message : '用户不存在' } ) ;
}
const paymentCodes = users [ 0 ] ;
res . json ( {
success : true ,
data : {
wechat _qr : paymentCodes . wechat _qr || '' ,
alipay _qr : paymentCodes . alipay _qr || '' ,
unionpay _qr : paymentCodes . unionpay _qr || ''
}
} ) ;
} catch ( error ) {
console . error ( '获取收款码状态错误:' , error ) ;
res . status ( 500 ) . json ( { success : false , message : '获取收款码状态失败' } ) ;
}
} ) ;
// 获取用户收款信息
router . get ( '/payment-info/:userId' , auth , async ( req , res ) => {
try {
const db = getDB ( ) ;
const targetUserId = req . params . userId ;
const [ users ] = await db . execute (
'SELECT id, username, wechat_qr, alipay_qr, unionpay_qr, bank_card FROM users WHERE id = ?' ,
[ targetUserId ]
) ;
if ( users . length === 0 ) {
return res . status ( 404 ) . json ( { success : false , message : '用户不存在' } ) ;
}
const user = users [ 0 ] ;
res . json ( {
success : true ,
data : {
id : user . id ,
username : user . username ,
wechat _qr : user . wechat _qr ,
alipay _qr : user . alipay _qr ,
unionpay _qr : user . unionpay _qr ,
bank _card : user . bank _card
}
} ) ;
} catch ( error ) {
console . error ( '获取用户收款信息错误:' , error ) ;
res . status ( 500 ) . json ( { success : false , message : '获取用户收款信息失败' } ) ;
}
} ) ;
// 获取当前用户的统计信息
router . get ( '/stats' , auth , async ( req , res ) => {
try {
const db = getDB ( ) ;
const userId = req . user . id ;
// 如果是管理员,返回全局统计
if ( req . user . role === 'admin' ) {
// 总用户数
const [ totalUsers ] = await db . execute ( 'SELECT COUNT(*) as count FROM users' ) ;
// 管理员数量
const [ adminUsers ] = await db . execute ( 'SELECT COUNT(*) as count FROM users WHERE role = "admin"' ) ;
// 普通用户数量
const [ regularUsers ] = await db . execute ( 'SELECT COUNT(*) as count FROM users WHERE role = "user"' ) ;
// 本月新增用户
const [ monthUsers ] = await db . execute (
'SELECT COUNT(*) as count FROM users WHERE YEAR(created_at) = YEAR(NOW()) AND MONTH(created_at) = MONTH(NOW())'
) ;
// 上月新增用户
const [ lastMonthUsers ] = await db . execute (
'SELECT COUNT(*) as count FROM users WHERE YEAR(created_at) = YEAR(DATE_SUB(NOW(), INTERVAL 1 MONTH)) AND MONTH(created_at) = MONTH(DATE_SUB(NOW(), INTERVAL 1 MONTH))'
) ;
// 计算月增长率
const monthGrowthRate = lastMonthUsers [ 0 ] . count > 0
? ( ( monthUsers [ 0 ] . count - lastMonthUsers [ 0 ] . count ) / lastMonthUsers [ 0 ] . count * 100 ) . toFixed ( 2 )
: 0 ;
// 用户总积分
const [ totalPoints ] = await db . execute ( 'SELECT COALESCE(SUM(points), 0) as total FROM users' ) ;
// 今日新增用户
const [ todayUsers ] = await db . execute (
'SELECT COUNT(*) as count FROM users WHERE DATE(created_at) = CURDATE()'
) ;
// 昨日新增用户
const [ yesterdayUsers ] = await db . execute (
'SELECT COUNT(*) as count FROM users WHERE DATE(created_at) = DATE_SUB(CURDATE(), INTERVAL 1 DAY)'
) ;
// 活跃用户数(有订单的用户)
const [ activeUsers ] = await db . execute (
'SELECT COUNT(DISTINCT user_id) as count FROM orders'
) ;
res . json ( {
success : true ,
stats : {
totalUsers : totalUsers [ 0 ] . count ,
adminUsers : adminUsers [ 0 ] . count ,
regularUsers : regularUsers [ 0 ] . count ,
monthNewUsers : monthUsers [ 0 ] . count ,
todayUsers : todayUsers [ 0 ] . count ,
yesterdayUsers : yesterdayUsers [ 0 ] . count ,
monthlyGrowth : parseFloat ( monthGrowthRate ) ,
totalPoints : totalPoints [ 0 ] . total ,
activeUsers : activeUsers [ 0 ] . count
}
} ) ;
} else {
// 普通用户返回个人统计
// 用户订单数
const [ orderCount ] = await db . execute (
'SELECT COUNT(*) as count FROM orders WHERE user_id = ?' ,
[ userId ]
) ;
// 用户总消费
const [ totalSpent ] = await db . execute (
'SELECT COALESCE(SUM(total_amount), 0) as total FROM orders WHERE user_id = ? AND status = "completed"' ,
[ userId ]
) ;
// 用户积分历史
const [ pointsEarned ] = await db . execute (
'SELECT COALESCE(SUM(amount), 0) as total FROM points_history WHERE user_id = ? AND type = "earn"' ,
[ userId ]
) ;
const [ pointsSpent ] = await db . execute (
'SELECT COALESCE(SUM(amount), 0) as total FROM points_history WHERE user_id = ? AND type = "spend"' ,
[ userId ]
) ;
res . json ( {
success : true ,
stats : {
orderCount : orderCount [ 0 ] . count ,
totalSpent : totalSpent [ 0 ] . total ,
pointsEarned : pointsEarned [ 0 ] . total ,
pointsSpent : pointsSpent [ 0 ] . total ,
currentPoints : req . user . points || 0
}
} ) ;
}
} catch ( error ) {
console . error ( '获取用户统计错误:' , error ) ;
res . status ( 500 ) . json ( { success : false , message : '获取用户统计失败' } ) ;
}
} ) ;
// 获取用户统计信息(管理员权限)- 必须在/:id路由之前定义
router . get ( '/admin/stats' , auth , adminAuth , async ( req , res ) => {
try {
const db = getDB ( ) ;
// 总用户数
const [ totalUsers ] = await db . execute ( 'SELECT COUNT(*) as count FROM users' ) ;
// 管理员数量
const [ adminUsers ] = await db . execute ( 'SELECT COUNT(*) as count FROM users WHERE role = "admin"' ) ;
// 普通用户数量
const [ regularUsers ] = await db . execute ( 'SELECT COUNT(*) as count FROM users WHERE role = "user"' ) ;
// 本月新增用户
const [ monthUsers ] = await db . execute (
'SELECT COUNT(*) as count FROM users WHERE YEAR(created_at) = YEAR(NOW()) AND MONTH(created_at) = MONTH(NOW())'
) ;
// 上月新增用户
const [ lastMonthUsers ] = await db . execute (
'SELECT COUNT(*) as count FROM users WHERE YEAR(created_at) = YEAR(DATE_SUB(NOW(), INTERVAL 1 MONTH)) AND MONTH(created_at) = MONTH(DATE_SUB(NOW(), INTERVAL 1 MONTH))'
) ;
// 计算月增长率
const monthGrowthRate = lastMonthUsers [ 0 ] . count > 0
? ( ( monthUsers [ 0 ] . count - lastMonthUsers [ 0 ] . count ) / lastMonthUsers [ 0 ] . count * 100 ) . toFixed ( 2 )
: 0 ;
// 用户总积分
const [ totalPoints ] = await db . execute ( 'SELECT COALESCE(SUM(points), 0) as total FROM users' ) ;
// 今日新增用户
const [ todayUsers ] = await db . execute (
'SELECT COUNT(*) as count FROM users WHERE DATE(created_at) = CURDATE()'
) ;
// 昨日新增用户
const [ yesterdayUsers ] = await db . execute (
'SELECT COUNT(*) as count FROM users WHERE DATE(created_at) = DATE_SUB(CURDATE(), INTERVAL 1 DAY)'
) ;
// 活跃用户数(有订单的用户)
const [ activeUsers ] = await db . execute (
'SELECT COUNT(DISTINCT user_id) as count FROM orders'
) ;
res . json ( {
success : true ,
stats : {
totalUsers : totalUsers [ 0 ] . count ,
adminUsers : adminUsers [ 0 ] . count ,
regularUsers : regularUsers [ 0 ] . count ,
monthNewUsers : monthUsers [ 0 ] . count ,
todayUsers : todayUsers [ 0 ] . count ,
yesterdayUsers : yesterdayUsers [ 0 ] . count ,
monthlyGrowth : parseFloat ( monthGrowthRate ) ,
totalPoints : totalPoints [ 0 ] . total ,
activeUsers : activeUsers [ 0 ] . count
}
} ) ;
} catch ( error ) {
console . error ( '获取用户统计错误:' , error ) ;
res . status ( 500 ) . json ( { success : false , message : '获取用户统计失败' } ) ;
}
} ) ;
// 获取当前用户积分
router . get ( '/points' , auth , async ( req , res ) => {
try {
const userId = req . user . id ;
const [ users ] = await getDB ( ) . execute (
'SELECT points FROM users WHERE id = ?' ,
[ userId ]
) ;
if ( users . length === 0 ) {
return res . status ( 404 ) . json ( { success : false , message : '用户不存在' } ) ;
}
res . json ( {
success : true ,
points : users [ 0 ] . points
} ) ;
} catch ( error ) {
console . error ( '获取用户积分错误:' , error ) ;
res . status ( 500 ) . json ( { success : false , message : '获取用户积分失败' } ) ;
}
} ) ;
// 获取用户积分历史记录
router . get ( '/points/history' , auth , async ( req , res ) => {
try {
const userId = req . user . id ;
const { page = 1 , limit = 20 , type } = req . query ;
// 确保参数为有效数字
const pageNum = Math . max ( 1 , parseInt ( page ) || 1 ) ;
const limitNum = Math . max ( 1 , Math . min ( 100 , parseInt ( limit ) || 20 ) ) ;
const offset = Math . max ( 0 , ( pageNum - 1 ) * limitNum ) ;
let whereClause = 'WHERE user_id = ?' ;
let queryParams = [ userId ] ;
if ( type && [ 'earn' , 'spend' ] . includes ( type ) ) {
whereClause += ' AND type = ?' ;
queryParams . push ( type ) ;
}
// 获取总数
const [ countResult ] = await getDB ( ) . execute (
` SELECT COUNT(*) as total FROM points_history ${ whereClause } ` ,
queryParams
) ;
// 获取历史记录
const [ records ] = await getDB ( ) . execute (
` SELECT id, type, amount, description, order_id, created_at
FROM points _history
$ { whereClause }
ORDER BY created _at DESC
LIMIT ? OFFSET ? ` ,
[ ... queryParams , limitNum . toString ( ) , offset . toString ( ) ]
) ;
res . json ( {
success : true ,
data : {
records ,
pagination : {
page : pageNum ,
limit : limitNum ,
total : countResult [ 0 ] . total ,
totalPages : Math . ceil ( countResult [ 0 ] . total / limitNum )
}
}
} ) ;
} catch ( error ) {
console . error ( '获取积分历史失败:' , error ) ;
res . status ( 500 ) . json ( { success : false , message : '获取积分历史失败' } ) ;
}
} ) ;
// 获取用户增长趋势数据(管理员权限)
router . get ( '/growth-trend' , auth , adminAuth , async ( req , res ) => {
try {
const db = getDB ( ) ;
const { days = 7 } = req . query ;
const daysNum = Math . min ( 90 , Math . max ( 1 , parseInt ( days ) || 7 ) ) ;
// 获取指定天数内的用户注册趋势
const [ trendData ] = await db . execute ( `
SELECT
DATE ( created _at ) as date ,
COUNT ( * ) as count
FROM users
WHERE created _at >= DATE _SUB ( NOW ( ) , INTERVAL ? DAY )
GROUP BY DATE ( created _at )
ORDER BY date ASC
` , [daysNum]);
// 填充缺失的日期( 注册数为0)
const result = [ ] ;
for ( let i = daysNum - 1 ; i >= 0 ; i -- ) {
const date = dayjs ( ) . subtract ( i , 'day' ) ;
const dateStr = date . format ( 'YYYY-MM-DD' ) ;
// 修复日期比较: 将数据库返回的Date对象转换为字符串进行比较
const existingData = trendData . find ( item => {
const itemDateStr = dayjs ( item . date ) . format ( 'YYYY-MM-DD' ) ;
return itemDateStr === dateStr ;
} ) ;
result . push ( {
date : date . format ( 'MM-DD' ) ,
count : existingData ? existingData . count : 0
} ) ;
}
res . json ( {
success : true ,
data : result
} ) ;
} catch ( error ) {
console . error ( '获取用户增长趋势错误:' , error ) ;
res . status ( 500 ) . json ( { success : false , message : '获取用户增长趋势失败' } ) ;
}
} ) ;
// 获取日收入统计数据(管理员权限)
router . get ( '/daily-revenue' , auth , adminAuth , async ( req , res ) => {
try {
const db = getDB ( ) ;
const { days = 30 } = req . query ;
const daysNum = Math . min ( 90 , Math . max ( 1 , parseInt ( days ) || 30 ) ) ;
// 获取指定天数内的用户注册数据,按天统计
const [ dailyData ] = await db . execute ( `
SELECT
DATE ( created _at ) as date ,
COUNT ( * ) as user _count
FROM users
WHERE created _at >= DATE _SUB ( NOW ( ) , INTERVAL ? DAY )
GROUP BY DATE ( created _at )
ORDER BY date ASC
` , [daysNum]);
// 填充缺失的日期( 注册数为0)
const result = [ ] ;
for ( let i = daysNum - 1 ; i >= 0 ; i -- ) {
const date = dayjs ( ) . subtract ( i , 'day' ) ;
const dateStr = date . format ( 'YYYY-MM-DD' ) ; // YYYY-MM-DD格式
const dateDisplay = date . format ( 'M/D' ) ; // 显示格式
const existingData = dailyData . find ( item => {
const itemDateStr = dayjs ( item . date ) . format ( 'YYYY-MM-DD' ) ;
return itemDateStr === dateStr ;
} ) ;
const userCount = existingData ? existingData . user _count : 0 ;
const revenue = userCount * 398 ; // 每个用户398元收入
result . push ( {
date : dateDisplay ,
userCount : userCount ,
amount : revenue
} ) ;
}
res . json ( {
success : true ,
data : result
} ) ;
} catch ( error ) {
console . error ( '获取日收入统计错误:' , error ) ;
res . status ( 500 ) . json ( { success : false , message : '获取日收入统计失败' } ) ;
}
} ) ;
// 生成注册码(管理员权限)==================== 激活码管理 ====================
/ * *
* 生成激活码 ( 管理员权限 )
* /
router . post ( '/registration-codes' , auth , adminAuth , async ( req , res ) => {
try {
const db = getDB ( ) ;
const adminId = req . user . id ;
// 生成6位随机激活码
const crypto = require ( 'crypto' ) ;
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' ;
let code = '' ;
for ( let i = 0 ; i < 6 ; i ++ ) {
code += chars . charAt ( Math . floor ( Math . random ( ) * chars . length ) ) ;
}
// 设置过期时间为1小时后
const expiresAt = req . body . expiresAt || new Date ( Date . now ( ) + 60 * 60 * 1000 ) ;
// 插入激活码
const [ result ] = await db . execute (
'INSERT INTO registration_codes (code, expires_at, created_by_admin_id) VALUES (?, ?, ?)' ,
[ code , expiresAt , adminId ]
) ;
res . status ( 201 ) . json ( {
success : true ,
message : '激活码生成成功' ,
data : {
id : result . insertId ,
code ,
expiresAt ,
createdAt : new Date ( )
}
} ) ;
} catch ( error ) {
console . error ( '生成激活码错误:' , error ) ;
res . status ( 500 ) . json ( { success : false , message : '生成激活码失败' } ) ;
}
} ) ;
/ * *
* 批量生成激活码 ( 管理员权限 )
* /
router . post ( '/registration-codes/batch' , auth , adminAuth , async ( req , res ) => {
try {
const db = getDB ( ) ;
const adminId = req . user . id ;
const { count = 1 } = req . body ;
// 验证参数
const codeCount = Math . max ( 1 , Math . min ( 100 , parseInt ( count ) || 1 ) ) ;
const crypto = require ( 'crypto' ) ;
const codes = [ ] ;
const values = [ ] ;
const expiresAt = req . body . expiresAt || new Date ( Date . now ( ) + 60 * 60 * 1000 ) ;
// 生成指定数量的激活码
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' ;
for ( let i = 0 ; i < codeCount ; i ++ ) {
let code = '' ;
for ( let j = 0 ; j < 6 ; j ++ ) {
code += chars . charAt ( Math . floor ( Math . random ( ) * chars . length ) ) ;
}
codes . push ( code ) ;
values . push ( code , expiresAt , adminId ) ;
}
// 批量插入数据库
const placeholders = Array ( codeCount ) . fill ( '(?, ?, ?)' ) . join ( ', ' ) ;
await db . execute (
` INSERT INTO registration_codes (code, expires_at, created_by_admin_id) VALUES ${ placeholders } ` ,
values
) ;
res . status ( 201 ) . json ( {
success : true ,
message : ` 成功生成 ${ codeCount } 个激活码 ` ,
data : {
codes ,
count : codeCount ,
expiresAt ,
}
} ) ;
} catch ( error ) {
console . error ( '批量生成激活码错误:' , error ) ;
res . status ( 500 ) . json ( { success : false , message : '批量生成激活码失败' } ) ;
}
} ) ;
/ * *
* 获取激活码列表 ( 管理员权限 )
* /
router . get ( '/registration-codes' , auth , adminAuth , async ( req , res ) => {
try {
const db = getDB ( ) ;
const { page = 1 , limit = 20 , status , keyword , sort = 'created_at' , order = 'desc' } = req . query ;
const offset = ( page - 1 ) * limit ;
let whereClause = '' ;
let whereConditions = [ ] ;
let countParams = [ ] ;
let listParams = [ ] ;
// 根据状态筛选
if ( status === 'unused' ) {
whereConditions . push ( 'rc.is_used = FALSE AND rc.expires_at > NOW()' ) ;
} else if ( status === 'used' ) {
whereConditions . push ( 'rc.is_used = TRUE' ) ;
} else if ( status === 'expired' ) {
whereConditions . push ( 'rc.is_used = FALSE AND rc.expires_at <= NOW()' ) ;
}
// 关键词搜索
if ( keyword ) {
whereConditions . push ( ` rc.code LIKE '% ${ keyword } %' ` ) ;
}
// 构建WHERE子句
if ( whereConditions . length > 0 ) {
whereClause = 'WHERE ' + whereConditions . join ( ' AND ' ) ;
}
// 处理排序参数
const allowedSortFields = [ 'created_at' , 'expires_at' , 'used_at' , 'code' , 'status' ] ;
const allowedOrders = [ 'asc' , 'desc' ] ;
let sortField = 'rc.created_at' ;
let sortOrder = 'DESC' ;
if ( allowedSortFields . includes ( sort ) ) {
if ( sort === 'status' ) {
// 状态字段需要使用CASE表达式
sortField = ` CASE
WHEN rc . is _used = TRUE THEN 'used'
WHEN rc . expires _at <= NOW ( ) THEN 'expired'
ELSE 'unused'
END ` ;
} else {
sortField = ` rc. ${ sort } ` ;
}
}
if ( allowedOrders . includes ( order . toLowerCase ( ) ) ) {
sortOrder = order . toUpperCase ( ) ;
}
// 设置查询参数( MySQL驱动需要字符串形式的LIMIT和OFFSET)
const limitStr = String ( parseInt ( limit ) ) ;
const offsetStr = String ( parseInt ( offset ) ) ;
listParams = [ limitStr , offsetStr ] ;
countParams = [ ] ;
// 获取激活码列表
const [ codes ] = await db . execute ( `
SELECT
rc . id ,
rc . code ,
rc . created _at ,
rc . expires _at ,
rc . used _at ,
rc . is _used ,
admin . username as created _by _admin ,
user . username as used _by _user ,
CASE
WHEN rc . is _used = TRUE THEN 'used'
WHEN rc . expires _at <= NOW ( ) THEN 'expired'
ELSE 'unused'
END as status
FROM registration _codes rc
LEFT JOIN users admin ON rc . created _by _admin _id = admin . id
LEFT JOIN users user ON rc . used _by _user _id = user . id
$ { whereClause }
ORDER BY $ { sortField } $ { sortOrder }
LIMIT ? OFFSET ?
` , listParams);
// 获取总数
const [ countResult ] = await db . execute ( `
SELECT COUNT ( * ) as total
FROM registration _codes rc
$ { whereClause }
` , countParams);
const total = countResult [ 0 ] . total ;
res . json ( {
success : true ,
data : {
codes ,
pagination : {
page : parseInt ( page ) ,
limit : parseInt ( limit ) ,
total ,
pages : Math . ceil ( total / limit )
}
}
} ) ;
} catch ( error ) {
console . error ( '获取激活码列表错误:' , error ) ;
res . status ( 500 ) . json ( { success : false , message : '获取激活码列表失败' } ) ;
}
} ) ;
/ * *
* 删除激活码 ( 管理员权限 )
* /
router . delete ( '/registration-codes/:id' , auth , adminAuth , async ( req , res ) => {
try {
const db = getDB ( ) ;
const codeId = req . params . id ;
// 检查激活码是否存在
const [ codes ] = await db . execute (
'SELECT id, is_used FROM registration_codes WHERE id = ?' ,
[ codeId ]
) ;
if ( codes . length === 0 ) {
return res . status ( 404 ) . json ( { success : false , message : '激活码不存在' } ) ;
}
// 不能删除已使用的激活码
if ( codes [ 0 ] . is _used ) {
return res . status ( 400 ) . json ( { success : false , message : '不能删除已使用的激活码' } ) ;
}
// 删除激活码
await db . execute ( 'DELETE FROM registration_codes WHERE id = ?' , [ codeId ] ) ;
res . json ( { success : true , message : '激活码删除成功' } ) ;
} catch ( error ) {
console . error ( '删除激活码错误:' , error ) ;
res . status ( 500 ) . json ( { success : false , message : '删除激活码失败' } ) ;
}
} ) ;
// 获取当前用户个人资料
router . get ( '/profile' , auth , async ( req , res ) => {
try {
const db = getDB ( ) ;
const userId = req . user . id ;
const [ users ] = await db . execute (
'SELECT id, username, role, avatar, points, real_name, id_card, phone, wechat_qr, alipay_qr, bank_card, unionpay_qr, business_license, id_card_front, id_card_back, audit_status, created_at, updated_at FROM users WHERE id = ?' ,
[ userId ]
) ;
if ( users . length === 0 ) {
return res . status ( 404 ) . json ( { success : false , message : '用户不存在' } ) ;
}
// 转换字段名以匹配前端
const user = users [ 0 ] ;
const profile = {
... user ,
nickname : user . username , // 添加nickname字段, 映射到username
realName : user . real _name ,
idCard : user . id _card ,
wechatQr : user . wechat _qr ,
alipayQr : user . alipay _qr ,
bankCard : user . bank _card ,
unionpayQr : user . unionpay _qr ,
businessLicense : user . business _license ,
idCardFront : user . id _card _front ,
idCardBack : user . id _card _back ,
auditStatus : user . audit _status
} ;
res . json ( { success : true , user : profile } ) ;
} catch ( error ) {
console . error ( '获取用户个人资料错误:' , error ) ;
res . status ( 500 ) . json ( { success : false , message : '获取用户个人资料失败' } ) ;
}
} ) ;
// 更新当前用户个人资料
router . put ( '/profile' , auth , async ( req , res ) => {
try {
const db = getDB ( ) ;
const userId = req . user . id ;
const {
username ,
nickname ,
avatar ,
realName ,
idCard ,
phone ,
wechatQr ,
alipayQr ,
bankCard ,
unionpayQr ,
businessLicense ,
idCardFront ,
idCardBack ,
city ,
districtId
} = req . body ;
// 处理nickname字段, 如果提供了nickname, 则使用nickname作为username
const finalUsername = nickname || username ;
// 检查用户名、身份证号和手机号是否已被其他用户使用
if ( finalUsername || idCard || phone ) {
const conditions = [ ] ;
const checkValues = [ ] ;
if ( finalUsername ) {
conditions . push ( 'username = ?' ) ;
checkValues . push ( finalUsername ) ;
}
if ( idCard ) {
conditions . push ( 'id_card = ?' ) ;
checkValues . push ( idCard ) ;
}
if ( phone ) {
conditions . push ( 'phone = ?' ) ;
checkValues . push ( phone ) ;
}
if ( conditions . length > 0 ) {
const [ existingUsers ] = await db . execute (
` SELECT id FROM users WHERE ( ${ conditions . join ( ' OR ' ) } ) AND id != ? ` ,
[ ... checkValues , userId ]
) ;
if ( existingUsers . length > 0 ) {
return res . status ( 400 ) . json ( { success : false , message : '用户名、身份证号或手机号已被使用' } ) ;
}
}
}
// 验证身份证号格式
if ( idCard ) {
const idCardRegex = /^[1-9]\d{5}(18|19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/ ;
if ( ! idCardRegex . test ( idCard ) ) {
return res . status ( 400 ) . json ( { success : false , message : '身份证号格式不正确' } ) ;
}
}
// 构建更新字段
const updateFields = [ ] ;
const updateValues = [ ] ;
if ( finalUsername !== undefined ) {
updateFields . push ( 'username = ?' ) ;
updateValues . push ( finalUsername ) ;
}
if ( avatar !== undefined ) {
updateFields . push ( 'avatar = ?' ) ;
updateValues . push ( avatar ) ;
}
if ( realName !== undefined ) {
updateFields . push ( 'real_name = ?' ) ;
updateValues . push ( realName ) ;
}
if ( idCard !== undefined ) {
updateFields . push ( 'id_card = ?' ) ;
updateValues . push ( idCard ) ;
}
if ( phone !== undefined ) {
updateFields . push ( 'phone = ?' ) ;
updateValues . push ( phone ) ;
}
// 添加城市和地区字段更新
if ( city !== undefined ) {
updateFields . push ( 'city = ?' ) ;
updateValues . push ( city ) ;
}
if ( districtId !== undefined ) {
updateFields . push ( 'district_id = ?' ) ;
updateValues . push ( districtId ) ;
}
// 检查是否更新了需要重新审核的关键信息
let needsReaudit = false ;
if ( wechatQr !== undefined ) {
updateFields . push ( 'wechat_qr = ?' ) ;
updateValues . push ( wechatQr ) ;
needsReaudit = true ;
}
if ( alipayQr !== undefined ) {
updateFields . push ( 'alipay_qr = ?' ) ;
updateValues . push ( alipayQr ) ;
needsReaudit = true ;
}
if ( bankCard !== undefined ) {
updateFields . push ( 'bank_card = ?' ) ;
updateValues . push ( bankCard ) ;
needsReaudit = true ;
}
if ( unionpayQr !== undefined ) {
updateFields . push ( 'unionpay_qr = ?' ) ;
updateValues . push ( unionpayQr ) ;
needsReaudit = true ;
}
if ( city !== undefined ) {
updateFields . push ( 'city = ?' ) ;
updateValues . push ( city ) ;
}
if ( districtId !== undefined ) {
updateFields . push ( 'district_id = ?' ) ;
updateValues . push ( districtId ) ;
}
if ( businessLicense !== undefined ) {
updateFields . push ( 'business_license = ?' ) ;
updateValues . push ( businessLicense ) ;
needsReaudit = true ;
}
if ( idCardFront !== undefined ) {
updateFields . push ( 'id_card_front = ?' ) ;
updateValues . push ( idCardFront ) ;
needsReaudit = true ;
}
if ( idCardBack !== undefined ) {
updateFields . push ( 'id_card_back = ?' ) ;
updateValues . push ( idCardBack ) ;
needsReaudit = true ;
}
// 如果更新了关键信息且用户不是管理员,则重置审核状态为待审核
if ( needsReaudit && req . user . role !== 'admin' ) {
updateFields . push ( 'audit_status = ?' ) ;
updateValues . push ( 'pending' ) ;
}
if ( updateFields . length === 0 ) {
return res . status ( 400 ) . json ( { success : false , message : '没有要更新的字段' } ) ;
}
updateValues . push ( userId ) ;
await db . execute (
` UPDATE users SET ${ updateFields . join ( ', ' ) } WHERE id = ? ` ,
updateValues
) ;
// 返回更新后的用户信息
const [ updatedUsers ] = await db . execute (
'SELECT id, username, role, avatar, points, real_name, id_card, phone, wechat_qr, alipay_qr, bank_card, unionpay_qr, business_license, id_card_front, id_card_back, audit_status, is_system_account, created_at, updated_at FROM users WHERE id = ?' ,
[ userId ]
) ;
// 转换字段名以匹配前端
const user = updatedUsers [ 0 ] ;
const profile = {
... user ,
nickname : user . username , // 添加nickname字段, 映射到username
realName : user . real _name ,
idCard : user . id _card ,
wechatQr : user . wechat _qr ,
alipayQr : user . alipay _qr ,
bankCard : user . bank _card ,
unionpayQr : user . unionpay _qr ,
businessLicense : user . business _license ,
idCardFront : user . id _card _front ,
idCardBack : user . id _card _back ,
auditStatus : user . audit _status
} ;
res . json ( {
success : true ,
message : '个人资料更新成功' ,
data : profile
} ) ;
} catch ( error ) {
console . error ( '更新个人资料错误:' , error ) ;
res . status ( 500 ) . json ( { success : false , message : '更新个人资料失败' } ) ;
}
} ) ;
// 获取用户详情
router . get ( '/:id' , auth , async ( req , res ) => {
try {
const db = getDB ( ) ;
const userId = req . params . id ;
// 只有管理员或用户本人可以查看详情
if ( req . user . role !== 'admin' && req . user . id != userId ) {
return res . status ( 403 ) . json ( { success : false , message : '权限不足' } ) ;
}
const [ users ] = await db . execute (
'SELECT id, username, role, avatar, points, real_name, id_card, phone, wechat_qr, alipay_qr, bank_card, unionpay_qr, created_at, updated_at FROM users WHERE id = ?' ,
[ userId ]
) ;
if ( users . length === 0 ) {
return res . status ( 404 ) . json ( { success : false , message : '用户不存在' } ) ;
}
res . json ( { success : true , user : users [ 0 ] } ) ;
} catch ( error ) {
console . error ( '获取用户详情错误:' , error ) ;
res . status ( 500 ) . json ( { success : false , message : '获取用户详情失败' } ) ;
}
} ) ;
// 更新用户信息
router . put ( '/:id' , auth , async ( req , res ) => {
try {
const db = getDB ( ) ;
const userId = req . params . id ;
const {
username ,
password ,
role ,
isSystemAccount ,
avatar ,
realName ,
idCard ,
phone ,
wechatQr ,
alipayQr ,
bankCard ,
unionpayQr ,
city ,
districtId ,
idCardFront ,
idCardBack ,
businessLicense ,
} = req . body ;
// 只有管理员或用户本人可以更新信息
if ( req . user . role !== 'admin' && req . user . id != userId ) {
return res . status ( 403 ) . json ( { success : false , message : '权限不足' } ) ;
}
// 非管理员不能修改角色
if ( req . user . role !== 'admin' && role ) {
return res . status ( 403 ) . json ( { success : false , message : '无权限修改用户角色' } ) ;
}
// 检查用户名、身份证号和手机号是否已被其他用户使用
if ( username || idCard || phone ) {
const conditions = [ ] ;
const checkValues = [ ] ;
if ( username ) {
conditions . push ( 'username = ?' ) ;
checkValues . push ( username ) ;
}
if ( idCard ) {
conditions . push ( 'id_card = ?' ) ;
checkValues . push ( idCard ) ;
}
if ( phone ) {
conditions . push ( 'phone = ?' ) ;
checkValues . push ( phone ) ;
}
if ( conditions . length > 0 ) {
const [ existingUsers ] = await db . execute (
` SELECT id FROM users WHERE ( ${ conditions . join ( ' OR ' ) } ) AND id != ? ` ,
[ ... checkValues , userId ]
) ;
if ( existingUsers . length > 0 ) {
return res . status ( 400 ) . json ( { success : false , message : '用户名、身份证号或手机号已被使用' } ) ;
}
}
}
// 验证身份证号格式
if ( idCard ) {
const idCardRegex = /^[1-9]\d{5}(18|19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/ ;
if ( ! idCardRegex . test ( idCard ) ) {
return res . status ( 400 ) . json ( { success : false , message : '身份证号格式不正确' } ) ;
}
}
// 构建更新字段
const updateFields = [ ] ;
const updateValues = [ ] ;
if ( username ) {
updateFields . push ( 'username = ?' ) ;
updateValues . push ( username ) ;
}
// 处理密码更新
if ( password && password . trim ( ) !== '' ) {
const hashedPassword = await bcrypt . hash ( password , 10 ) ;
updateFields . push ( 'password = ?' ) ;
updateValues . push ( hashedPassword ) ;
}
if ( role && req . user . role === 'admin' ) {
updateFields . push ( 'role = ?' ) ;
updateValues . push ( role ) ;
}
// 只有管理员可以修改账户类型
if ( isSystemAccount !== undefined && req . user . role === 'admin' ) {
updateFields . push ( 'is_system_account = ?' ) ;
updateValues . push ( isSystemAccount ) ;
}
if ( avatar !== undefined ) {
updateFields . push ( 'avatar = ?' ) ;
updateValues . push ( avatar ) ;
}
if ( realName !== undefined ) {
updateFields . push ( 'real_name = ?' ) ;
updateValues . push ( realName ) ;
}
if ( idCard !== undefined ) {
updateFields . push ( 'id_card = ?' ) ;
updateValues . push ( idCard ) ;
}
if ( phone !== undefined ) {
updateFields . push ( 'phone = ?' ) ;
updateValues . push ( phone ) ;
}
if ( city !== undefined ) {
updateFields . push ( 'city = ?' ) ;
updateValues . push ( city ) ;
}
if ( districtId !== undefined ) {
updateFields . push ( 'district_id = ?' ) ;
updateValues . push ( districtId ) ;
}
// 检查是否更新了需要重新审核的关键信息
let needsReaudit = false ;
if ( wechatQr !== undefined ) {
updateFields . push ( 'wechat_qr = ?' ) ;
updateValues . push ( wechatQr ) ;
needsReaudit = true ;
}
if ( alipayQr !== undefined ) {
updateFields . push ( 'alipay_qr = ?' ) ;
updateValues . push ( alipayQr ) ;
needsReaudit = true ;
}
if ( bankCard !== undefined ) {
updateFields . push ( 'bank_card = ?' ) ;
updateValues . push ( bankCard ) ;
needsReaudit = true ;
}
if ( unionpayQr !== undefined ) {
updateFields . push ( 'unionpay_qr = ?' ) ;
updateValues . push ( unionpayQr ) ;
needsReaudit = true ;
}
if ( idCardFront !== undefined ) {
updateFields . push ( 'id_card_front = ?' ) ;
updateValues . push ( idCardFront ) ;
needsReaudit = true ;
}
if ( idCardBack !== undefined ) {
updateFields . push ( 'id_card_back = ?' ) ;
updateValues . push ( idCardBack ) ;
needsReaudit = true ;
}
if ( businessLicense !== undefined ) {
updateFields . push ( 'business_license = ?' ) ;
updateValues . push ( businessLicense ) ;
needsReaudit = true ;
}
// 如果更新了关键信息且用户不是管理员,则重置审核状态为待审核
if ( needsReaudit && req . user . role !== 'admin' ) {
updateFields . push ( 'audit_status = ?' ) ;
updateValues . push ( 'pending' ) ;
}
if ( updateFields . length === 0 ) {
return res . status ( 400 ) . json ( { success : false , message : '没有要更新的字段' } ) ;
}
updateValues . push ( userId ) ;
await db . execute (
` UPDATE users SET ${ updateFields . join ( ', ' ) } WHERE id = ? ` ,
updateValues
) ;
// 返回更新后的用户信息
const [ updatedUsers ] = await db . execute (
'SELECT id, username, role, avatar, points, real_name, id_card, phone, wechat_qr, alipay_qr, bank_card, unionpay_qr, city, district_id, created_at, updated_at FROM users WHERE id = ?' ,
[ userId ]
) ;
res . json ( {
success : true ,
message : '用户信息更新成功' ,
user : updatedUsers [ 0 ]
} ) ;
} catch ( error ) {
console . error ( '更新用户信息错误:' , error ) ;
res . status ( 500 ) . json ( { success : false , message : '更新用户信息失败' } ) ;
}
} ) ;
// 删除用户(管理员权限)
router . delete ( '/:id' , auth , adminAuth , async ( req , res ) => {
try {
const db = getDB ( ) ;
const userId = req . params . id ;
// 不能删除自己
if ( req . user . id == userId ) {
return res . status ( 400 ) . json ( { success : false , message : '不能删除自己的账户' } ) ;
}
// 检查用户是否存在
const [ users ] = await db . execute (
'SELECT id FROM users WHERE id = ?' ,
[ userId ]
) ;
if ( users . length === 0 ) {
return res . status ( 404 ) . json ( { success : false , message : '用户不存在' } ) ;
}
// 删除用户
await db . execute ( 'DELETE FROM users WHERE id = ?' , [ userId ] ) ;
res . json ( { success : true , message : '用户删除成功' } ) ;
} catch ( error ) {
console . error ( '删除用户错误:' , error ) ;
res . status ( 500 ) . json ( { success : false , message : '删除用户失败' } ) ;
}
} ) ;
/ * *
* 审核用户 ( 管理员权限 )
* /
router . put ( '/:id/audit' , auth , adminAuth , async ( req , res ) => {
try {
const db = getDB ( ) ;
const userId = req . params . id ;
const { action , note } = req . body ; // action: 'approve' 或 'reject'
if ( ! action || ! [ 'approve' , 'reject' ] . includes ( action ) ) {
return res . status ( 400 ) . json ( { success : false , message : '审核操作无效' } ) ;
}
// 检查用户是否存在且为待审核状态
const [ users ] = await db . execute (
'SELECT id, username, audit_status FROM users WHERE id = ?' ,
[ userId ]
) ;
if ( users . length === 0 ) {
return res . status ( 404 ) . json ( { success : false , message : '用户不存在' } ) ;
}
const user = users [ 0 ] ;
if ( user . audit _status !== 'pending' ) {
return res . status ( 400 ) . json ( { success : false , message : '该用户不是待审核状态' } ) ;
}
// 更新审核状态
const auditStatus = action === 'approve' ? 'approved' : 'rejected' ;
await db . execute (
` UPDATE users SET
audit _status = ? ,
audit _note = ? ,
audited _by = ? ,
audited _at = NOW ( )
WHERE id = ? ` ,
[ auditStatus , note || null , req . user . id , userId ]
) ;
const message = action === 'approve' ? '用户审核通过' : '用户审核拒绝' ;
res . json ( { success : true , message } ) ;
} catch ( error ) {
console . error ( '审核用户错误:' , error ) ;
res . status ( 500 ) . json ( { success : false , message : '审核用户失败' } ) ;
}
} ) ;
/ * *
* 获取用户审核详情 ( 管理员权限 )
* /
router . get ( '/:id/audit-detail' , auth , adminAuth , async ( req , res ) => {
try {
const db = getDB ( ) ;
const userId = req . params . id ;
// 获取用户详细信息
const [ users ] = await db . execute (
` SELECT u.id, u.username, u.phone, u.real_name, u.business_license,
u . id _card _front , u . id _card _back , u . audit _status , u . audit _note ,
u . audited _at , u . created _at ,
auditor . username as auditor _name
FROM users u
LEFT JOIN users auditor ON u . audited _by = auditor . id
WHERE u . id = ? ` ,
[ userId ]
) ;
if ( users . length === 0 ) {
return res . status ( 404 ) . json ( { success : false , message : '用户不存在' } ) ;
}
res . json ( {
success : true ,
data : users [ 0 ]
} ) ;
} catch ( error ) {
console . error ( '获取用户审核详情错误:' , error ) ;
res . status ( 500 ) . json ( { success : false , message : '获取用户审核详情失败' } ) ;
}
} ) ;
module . exports = router ;