提交
This commit is contained in:
@@ -1,186 +1,190 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const { getDB } = require('../database');
|
||||
const { agentAuth } = require('../middleware/agentAuth');
|
||||
const { logger } = require('../config/logger');
|
||||
const {getDB} = require('../database');
|
||||
const {agentAuth} = require('../middleware/agentAuth');
|
||||
const {logger} = require('../config/logger');
|
||||
|
||||
/**
|
||||
* 获取代理下级用户转账记录列表
|
||||
* GET /api/transfers
|
||||
*/
|
||||
router.get('/', agentAuth, async (req, res) => {
|
||||
try {
|
||||
const agentId = req.agent.id;
|
||||
const {
|
||||
page = 1,
|
||||
limit = 20,
|
||||
search,
|
||||
status,
|
||||
type,
|
||||
start_date,
|
||||
end_date,
|
||||
min_amount,
|
||||
max_amount,
|
||||
sort_by = 'created_at',
|
||||
sort_order = 'desc'
|
||||
} = req.query;
|
||||
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(limit) || 20;
|
||||
const offset = (pageNum - 1) * limitNum;
|
||||
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];
|
||||
// 构建查询条件
|
||||
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 (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,
|
||||
COUNT(CASE WHEN t.status = 'completed' THEN 1 END) as completed_transfers,
|
||||
COUNT(CASE WHEN t.status = 'pending' THEN 1 END) as pending_transfers,
|
||||
COUNT(CASE WHEN t.status = 'failed' THEN 1 END) as failed_transfers,
|
||||
CAST(COALESCE(SUM(CASE WHEN t.status = 'completed' THEN t.amount ELSE 0 END),
|
||||
0) AS DECIMAL(10, 2)) as total_amount,
|
||||
CAST(COALESCE(
|
||||
SUM(CASE WHEN t.status = 'completed' AND DATE (t.created_at) = CURDATE() THEN t.amount ELSE 0
|
||||
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: '获取转账记录失败'
|
||||
});
|
||||
}
|
||||
|
||||
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}
|
||||
`;
|
||||
|
||||
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}
|
||||
`;
|
||||
|
||||
const [countResult] = await getDB().execute(countQuery, [agentId, agentId, ...queryParams]);
|
||||
const total = countResult[0]?.total || 0;
|
||||
|
||||
// 查询统计信息
|
||||
const [statsResult] = await getDB().execute(`
|
||||
SELECT
|
||||
COUNT(*) as total_transfers,
|
||||
COUNT(CASE WHEN t.status = 'completed' THEN 1 END) as completed_transfers,
|
||||
COUNT(CASE WHEN t.status = 'pending' THEN 1 END) as pending_transfers,
|
||||
COUNT(CASE WHEN t.status = 'failed' THEN 1 END) as failed_transfers,
|
||||
CAST(COALESCE(SUM(CASE WHEN t.status = 'completed' THEN t.amount ELSE 0 END), 0) AS DECIMAL(10,2)) as total_amount,
|
||||
CAST(COALESCE(SUM(CASE WHEN t.status = 'completed' AND DATE(t.created_at) = CURDATE() THEN t.amount ELSE 0 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: '获取转账记录失败'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -188,70 +192,70 @@ router.get('/', agentAuth, async (req, res) => {
|
||||
* GET /api/transfers/:id
|
||||
*/
|
||||
router.get('/:id', agentAuth, async (req, res) => {
|
||||
try {
|
||||
const agentId = req.agent.id;
|
||||
const transferId = req.params.id;
|
||||
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]);
|
||||
// 查询转账记录详情
|
||||
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: '转账记录不存在或无权限查看'
|
||||
});
|
||||
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: '获取转账记录详情失败'
|
||||
});
|
||||
}
|
||||
|
||||
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: '获取转账记录详情失败'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -259,46 +263,48 @@ router.get('/:id', agentAuth, async (req, res) => {
|
||||
* GET /api/transfers/trend
|
||||
*/
|
||||
router.get('/trend/data', agentAuth, async (req, res) => {
|
||||
try {
|
||||
const agentId = req.agent.id;
|
||||
const { days = 7, type = 'amount' } = req.query;
|
||||
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';
|
||||
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: '获取转账趋势失败'
|
||||
});
|
||||
}
|
||||
|
||||
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: '获取转账趋势失败'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -306,129 +312,128 @@ router.get('/trend/data', agentAuth, async (req, res) => {
|
||||
* GET /api/transfers/export
|
||||
*/
|
||||
router.get('/export/data', agentAuth, async (req, res) => {
|
||||
try {
|
||||
const agentId = req.agent.id;
|
||||
const {
|
||||
format = 'json',
|
||||
search,
|
||||
status,
|
||||
type,
|
||||
start_date,
|
||||
end_date,
|
||||
min_amount,
|
||||
max_amount
|
||||
} = req.query;
|
||||
try {
|
||||
const agentId = req.agent.id;
|
||||
const {
|
||||
format = 'json',
|
||||
search,
|
||||
status,
|
||||
type,
|
||||
start_date,
|
||||
end_date,
|
||||
min_amount,
|
||||
max_amount
|
||||
} = req.query;
|
||||
|
||||
// 构建查询条件
|
||||
let whereConditions = ['(am1.agent_id = ? OR am2.agent_id = ?)'];
|
||||
let queryParams = [agentId, agentId];
|
||||
// 构建查询条件
|
||||
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 u2.username LIKE ? OR u2.real_name LIKE ?)');
|
||||
queryParams.push(`%${search}%`, `%${search}%`, `%${search}%`, `%${search}%`);
|
||||
if (search) {
|
||||
whereConditions.push('(u1.username LIKE ? OR u1.real_name LIKE ? OR u2.username LIKE ? OR u2.real_name LIKE ?)');
|
||||
queryParams.push(`%${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 [transfers] = await getDB().execute(`
|
||||
SELECT t.id,
|
||||
t.amount,
|
||||
t.source_type,
|
||||
t.status,
|
||||
t.description,
|
||||
t.matching_order_id,
|
||||
t.created_at,
|
||||
u1.username as from_username,
|
||||
u1.real_name as from_real_name,
|
||||
u1.phone as from_phone,
|
||||
u2.username as to_username,
|
||||
u2.real_name as to_real_name,
|
||||
u2.phone as to_phone
|
||||
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.created_at DESC
|
||||
`, queryParams);
|
||||
|
||||
if (format === 'csv') {
|
||||
// 生成CSV格式
|
||||
const csvHeader = 'ID,金额,类型,状态,描述,交易ID,转出用户,转出手机,转入用户,转入手机,创建时间\n';
|
||||
const csvData = transfers.map(transfer => {
|
||||
return [
|
||||
transfer.id,
|
||||
transfer.amount,
|
||||
transfer.type || '',
|
||||
transfer.status || '',
|
||||
(transfer.description || '').replace(/,/g, ','), // 替换逗号避免CSV格式问题
|
||||
transfer.matching_order_id || '',
|
||||
transfer.from_real_name || transfer.from_username || '',
|
||||
transfer.from_phone || '',
|
||||
transfer.to_real_name || transfer.to_username || '',
|
||||
transfer.to_phone || '',
|
||||
transfer.created_at || ''
|
||||
].join(',');
|
||||
}).join('\n');
|
||||
|
||||
res.setHeader('Content-Type', 'text/csv; charset=utf-8');
|
||||
res.setHeader('Content-Disposition', `attachment; filename="transfers_${Date.now()}.csv"`);
|
||||
res.send(csvHeader + csvData);
|
||||
} else {
|
||||
// 默认JSON格式
|
||||
res.json({
|
||||
success: true,
|
||||
data: transfers,
|
||||
exported_at: new Date().toISOString(),
|
||||
total: transfers.length
|
||||
});
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
logger.error('导出转账记录失败', {
|
||||
error: error.message,
|
||||
stack: error.stack,
|
||||
agentId: req.agent?.id
|
||||
});
|
||||
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '导出转账记录失败'
|
||||
});
|
||||
}
|
||||
|
||||
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 [transfers] = await getDB().execute(`
|
||||
SELECT
|
||||
t.id,
|
||||
t.amount,
|
||||
t.source_type,
|
||||
t.status,
|
||||
t.description,
|
||||
t.matching_order_id,
|
||||
t.created_at,
|
||||
u1.username as from_username,
|
||||
u1.real_name as from_real_name,
|
||||
u1.phone as from_phone,
|
||||
u2.username as to_username,
|
||||
u2.real_name as to_real_name,
|
||||
u2.phone as to_phone
|
||||
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.created_at DESC
|
||||
`, queryParams);
|
||||
|
||||
if (format === 'csv') {
|
||||
// 生成CSV格式
|
||||
const csvHeader = 'ID,金额,类型,状态,描述,交易ID,转出用户,转出手机,转入用户,转入手机,创建时间\n';
|
||||
const csvData = transfers.map(transfer => {
|
||||
return [
|
||||
transfer.id,
|
||||
transfer.amount,
|
||||
transfer.type || '',
|
||||
transfer.status || '',
|
||||
(transfer.description || '').replace(/,/g, ','), // 替换逗号避免CSV格式问题
|
||||
transfer.matching_order_id || '',
|
||||
transfer.from_real_name || transfer.from_username || '',
|
||||
transfer.from_phone || '',
|
||||
transfer.to_real_name || transfer.to_username || '',
|
||||
transfer.to_phone || '',
|
||||
transfer.created_at || ''
|
||||
].join(',');
|
||||
}).join('\n');
|
||||
|
||||
res.setHeader('Content-Type', 'text/csv; charset=utf-8');
|
||||
res.setHeader('Content-Disposition', `attachment; filename="transfers_${Date.now()}.csv"`);
|
||||
res.send(csvHeader + csvData);
|
||||
} else {
|
||||
// 默认JSON格式
|
||||
res.json({
|
||||
success: true,
|
||||
data: transfers,
|
||||
exported_at: new Date().toISOString(),
|
||||
total: transfers.length
|
||||
});
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
logger.error('导出转账记录失败', {
|
||||
error: error.message,
|
||||
stack: error.stack,
|
||||
agentId: req.agent?.id
|
||||
});
|
||||
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '导出转账记录失败'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
Reference in New Issue
Block a user