Files
jurong_circle_agent_black/routes/transfers.js

312 lines
11 KiB
JavaScript
Raw Normal View History

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;