2025-09-04 10:49:10 +08:00
const express = require ( 'express' ) ;
const router = express . Router ( ) ;
2025-09-10 18:09:38 +08:00
const { getDB } = require ( '../database' ) ;
const { agentAuth } = require ( '../middleware/agentAuth' ) ;
const { logger } = require ( '../config/logger' ) ;
2025-09-04 10:49:10 +08:00
/ * *
* 获取代理下级用户转账记录列表
* GET / api / transfers
* /
router . get ( '/' , agentAuth , async ( req , res ) => {
2025-09-10 18:09:38 +08:00
try {
const agentId = req . agent . id ;
const {
page = 1 ,
limit = 20 ,
size = 20 ,
search ,
status ,
type ,
start _date ,
end _date ,
min _amount ,
max _amount ,
sort _by = 'created_at' ,
sort _order = 'desc'
} = req . query ;
const pageNum = parseInt ( page ) || 1 ;
const limitNum = parseInt ( size || limit ) || 20 ;
const offset = ( pageNum - 1 ) * limitNum ;
// 构建查询条件
let whereConditions = [
'(am1.agent_id = ? OR am2.agent_id = ?)' // 转出方或转入方属于当前代理
] ;
let queryParams = [ agentId , agentId ] ;
if ( search ) {
whereConditions . push ( '(u1.username LIKE ? OR u1.real_name LIKE ? OR u1.phone LIKE ? OR u2.username LIKE ? OR u2.real_name LIKE ? OR u2.phone LIKE ?)' ) ;
queryParams . push ( ` % ${ search } % ` , ` % ${ search } % ` , ` % ${ search } % ` , ` % ${ search } % ` , ` % ${ search } % ` , ` % ${ search } % ` ) ;
}
if ( status ) {
whereConditions . push ( 't.status = ?' ) ;
queryParams . push ( status ) ;
}
if ( type ) {
whereConditions . push ( 't.source_type = ?' ) ;
queryParams . push ( type ) ;
}
if ( start _date ) {
whereConditions . push ( 'DATE(t.created_at) >= ?' ) ;
queryParams . push ( start _date ) ;
}
if ( end _date ) {
whereConditions . push ( 'DATE(t.created_at) <= ?' ) ;
queryParams . push ( end _date ) ;
}
if ( min _amount ) {
whereConditions . push ( 't.amount >= ?' ) ;
queryParams . push ( parseFloat ( min _amount ) ) ;
}
if ( max _amount ) {
whereConditions . push ( 't.amount <= ?' ) ;
queryParams . push ( parseFloat ( max _amount ) ) ;
}
const whereClause = whereConditions . join ( ' AND ' ) ;
// 验证排序字段
const allowedSortFields = [ 'created_at' , 'amount' , 'status' ] ;
const sortBy = allowedSortFields . includes ( sort _by ) ? sort _by : 'created_at' ;
const sortOrder = sort _order . toLowerCase ( ) === 'asc' ? 'ASC' : 'DESC' ;
// 查询转账记录列表
const transfersQuery = `
SELECT t . id ,
t . from _user _id ,
t . to _user _id ,
t . amount ,
t . source _type ,
t . status ,
t . description ,
t . matching _order _id ,
t . created _at ,
t . updated _at ,
u1 . username as from _username ,
u1 . real _name as from _real _name ,
u1 . phone as from _phone ,
u1 . avatar as from _avatar ,
u2 . username as to _username ,
u2 . real _name as to _real _name ,
u2 . phone as to _phone ,
u2 . avatar as to _avatar ,
CASE
WHEN am1 . agent _id = ? THEN 'out'
WHEN am2 . agent _id = ? THEN 'in'
ELSE 'both'
END as direction
FROM transfers t
LEFT JOIN users u1 ON t . from _user _id = u1 . id
LEFT JOIN users u2 ON t . to _user _id = u2 . id
LEFT JOIN agent _merchants am1 ON t . from _user _id = am1 . merchant _id
LEFT JOIN agent _merchants am2 ON t . to _user _id = am2 . merchant _id
WHERE $ { whereClause }
ORDER BY t . $ { sortBy } $ { sortOrder }
LIMIT $ { limitNum }
OFFSET $ { offset }
` ;
console . log ( transfersQuery , [ agentId , agentId , ... queryParams ] ) ;
const [ transfers ] = await getDB ( ) . execute ( transfersQuery , [ agentId , agentId , ... queryParams ] ) ;
// 查询总数
const countQuery = `
SELECT COUNT ( * ) as total
FROM transfers t
LEFT JOIN agent _merchants am1 ON t . from _user _id = am1 . merchant _id
LEFT JOIN agent _merchants am2 ON t . to _user _id = am2 . merchant _id
LEFT JOIN users u1 ON t . from _user _id = u1 . id
LEFT JOIN users u2 ON t . to _user _id = u2 . id
WHERE $ { whereClause }
` ;
console . log ( countQuery , [ agentId , agentId , ... queryParams ] ) ;
const [ countResult ] = await getDB ( ) . execute ( countQuery , [ ... queryParams ] ) ;
const total = countResult [ 0 ] ? . total || 0 ;
// 查询统计信息
let statsResult ;
[ statsResult ] = await getDB ( ) . execute ( `
SELECT COUNT ( * ) as total _transfers ,
2025-09-17 14:01:10 +08:00
COUNT ( CASE WHEN t . status = 'received' THEN 1 END ) as completed _transfers ,
2025-09-10 18:09:38 +08:00
COUNT ( CASE WHEN t . status = 'pending' THEN 1 END ) as pending _transfers ,
COUNT ( CASE WHEN t . status = 'failed' THEN 1 END ) as failed _transfers ,
2025-09-17 14:01:10 +08:00
CAST ( COALESCE ( SUM ( CASE WHEN t . status = 'received' THEN t . amount ELSE 0 END ) ,
2025-09-10 18:09:38 +08:00
0 ) AS DECIMAL ( 10 , 2 ) ) as total _amount ,
CAST ( COALESCE (
2025-09-17 14:01:10 +08:00
SUM ( CASE WHEN t . status = 'received' AND DATE ( t . created _at ) = CURDATE ( ) THEN t . amount ELSE 0
2025-09-10 18:09:38 +08:00
END ) , 0 ) AS DECIMAL ( 10 , 2 ) ) as today _amount ,
COUNT ( CASE WHEN DATE ( t . created _at ) = CURDATE ( ) THEN 1 END ) as today _transfers
FROM transfers t
LEFT JOIN agent _merchants am1 ON t . from _user _id = am1 . merchant _id
LEFT JOIN agent _merchants am2 ON t . to _user _id = am2 . merchant _id
WHERE ( am1 . agent _id = ? OR am2 . agent _id = ? )
` , [agentId, agentId]);
const stats = statsResult [ 0 ] || {
total _transfers : 0 ,
completed _transfers : 0 ,
pending _transfers : 0 ,
failed _transfers : 0 ,
total _amount : '0.00' ,
today _amount : '0.00' ,
today _transfers : 0
} ;
res . json ( {
success : true ,
data : {
transfers ,
pagination : {
current _page : pageNum ,
per _page : limitNum ,
total ,
total _pages : Math . ceil ( total / limitNum )
} ,
stats
}
} ) ;
} catch ( error ) {
logger . error ( '获取转账记录失败' , {
error : error . message ,
stack : error . stack ,
agentId : req . agent ? . id
} ) ;
res . status ( 500 ) . json ( {
success : false ,
message : '获取转账记录失败'
} ) ;
2025-09-04 10:49:10 +08:00
}
} ) ;
/ * *
* 获取单个转账记录详情
* GET / api / transfers / : id
* /
router . get ( '/:id' , agentAuth , async ( req , res ) => {
2025-09-10 18:09:38 +08:00
try {
const agentId = req . agent . id ;
const transferId = req . params . id ;
// 查询转账记录详情
const [ transfers ] = await getDB ( ) . execute ( `
SELECT t . id ,
t . from _user _id ,
t . to _user _id ,
t . amount ,
t . source _type ,
t . status ,
t . description ,
t . matching _order _id ,
t . created _at ,
t . updated _at ,
u1 . username as from _username ,
u1 . real _name as from _real _name ,
u1 . phone as from _phone ,
u1 . avatar as from _avatar ,
u1 . city as from _city ,
u1 . district as from _district ,
u2 . username as to _username ,
u2 . real _name as to _real _name ,
u2 . phone as to _phone ,
u2 . avatar as to _avatar ,
u2 . city as to _city ,
u2 . district as to _district
FROM transfers t
LEFT JOIN users u1 ON t . from _user _id = u1 . id
LEFT JOIN users u2 ON t . to _user _id = u2 . id
LEFT JOIN agent _merchants am1 ON t . from _user _id = am1 . merchant _id
LEFT JOIN agent _merchants am2 ON t . to _user _id = am2 . merchant _id
WHERE t . id = ?
AND ( am1 . agent _id = ? OR am2 . agent _id = ? )
` , [transferId, agentId, agentId]);
if ( transfers . length === 0 ) {
return res . status ( 404 ) . json ( {
success : false ,
message : '转账记录不存在或无权限查看'
} ) ;
}
const transfer = transfers [ 0 ] ;
res . json ( {
success : true ,
data : transfer
} ) ;
} catch ( error ) {
logger . error ( '获取转账记录详情失败' , {
error : error . message ,
stack : error . stack ,
agentId : req . agent ? . id ,
transferId : req . params . id
} ) ;
res . status ( 500 ) . json ( {
success : false ,
message : '获取转账记录详情失败'
} ) ;
2025-09-04 10:49:10 +08:00
}
} ) ;
/ * *
* 获取转账趋势数据
* GET / api / transfers / trend
* /
router . get ( '/trend/data' , agentAuth , async ( req , res ) => {
2025-09-10 18:09:38 +08:00
try {
const agentId = req . agent . id ;
const { days = 7 , type = 'amount' } = req . query ;
let selectField = 'CAST(COALESCE(SUM(t.amount), 0) AS DECIMAL(10,2)) as value' ;
if ( type === 'count' ) {
selectField = 'COUNT(*) as value' ;
}
const [ trendData ] = await getDB ( ) . execute ( `
SELECT
DATE ( t . created _at ) as date , $ { selectField }
FROM transfers t
LEFT JOIN agent _merchants am1
ON t . from _user _id = am1 . merchant _id
LEFT JOIN agent _merchants am2 ON t . to _user _id = am2 . merchant _id
WHERE ( am1 . agent _id = ?
OR am2 . agent _id = ? )
AND t . status = 'completed'
AND t . created _at >= DATE _SUB ( CURDATE ( )
, INTERVAL ? DAY )
GROUP BY DATE ( t . created _at )
ORDER BY date ASC
` , [agentId, agentId, parseInt(days)]);
res . json ( {
success : true ,
data : trendData
} ) ;
} catch ( error ) {
logger . error ( '获取转账趋势失败' , {
error : error . message ,
stack : error . stack ,
agentId : req . agent ? . id
} ) ;
res . status ( 500 ) . json ( {
success : false ,
message : '获取转账趋势失败'
} ) ;
2025-09-04 10:49:10 +08:00
}
} ) ;
2025-09-10 18:09:38 +08:00
2025-09-04 10:49:10 +08:00
module . exports = router ;