const express = require('express'); const router = express.Router(); const { getDB } = require('../database'); const { agentAuth } = require('../middleware/agentAuth'); const { logger } = require('../config/logger'); /** * 获取代理佣金记录列表 * GET /api/commissions */ router.get('/', agentAuth, async (req, res) => { try { const agentId = req.agent.id; const { page = 1, limit = 20, search, status, commission_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; // 构建查询条件 let whereConditions = ['acr.agent_id = ?']; let queryParams = [agentId]; if (search) { whereConditions.push('(u.username LIKE ? OR u.real_name LIKE ? OR u.phone LIKE ?)'); queryParams.push(`%${search}%`, `%${search}%`, `%${search}%`); } if (status) { whereConditions.push('acr.status = ?'); queryParams.push(status); } if (commission_type) { whereConditions.push('acr.commission_type = ?'); queryParams.push(commission_type); } if (start_date) { whereConditions.push('DATE(acr.created_at) >= ?'); queryParams.push(start_date); } if (end_date) { whereConditions.push('DATE(acr.created_at) <= ?'); queryParams.push(end_date); } if (min_amount) { whereConditions.push('acr.commission_amount >= ?'); queryParams.push(parseFloat(min_amount)); } if (max_amount) { whereConditions.push('acr.commission_amount <= ?'); queryParams.push(parseFloat(max_amount)); } const whereClause = whereConditions.join(' AND '); // 验证排序字段 const allowedSortFields = ['created_at', 'commission_amount', 'status', 'commission_type']; const sortBy = allowedSortFields.includes(sort_by) ? sort_by : 'created_at'; const sortOrder = sort_order.toLowerCase() === 'asc' ? 'ASC' : 'DESC'; // 查询佣金记录列表 const commissionsQuery = ` SELECT acr.id, acr.agent_id, acr.merchant_id, acr.commission_type, acr.commission_amount, acr.status, acr.description, acr.reference_id, acr.created_at, acr.updated_at, acr.paid_at, u.username, u.real_name, u.phone, u.avatar FROM agent_commission_records acr LEFT JOIN users u ON acr.merchant_id = u.id WHERE ${whereClause} ORDER BY acr.${sortBy} ${sortOrder} LIMIT ${limitNum} OFFSET ${offset} `; const [commissions] = await getDB().execute(commissionsQuery, queryParams); // 查询总数 const countQuery = ` SELECT COUNT(*) as total FROM agent_commission_records acr LEFT JOIN users u ON acr.merchant_id = u.id WHERE ${whereClause} `; const [countResult] = await getDB().execute(countQuery, queryParams); const total = countResult[0]?.total || 0; // 查询统计信息 const [statsResult] = await getDB().execute(` SELECT COUNT(*) as total_commissions, COUNT(CASE WHEN status = 'pending' THEN 1 END) as pending_commissions, COUNT(CASE WHEN status = 'paid' THEN 1 END) as paid_commissions, CAST(COALESCE(SUM(commission_amount), 0) AS DECIMAL(10,2)) as total_amount, CAST(COALESCE(SUM(CASE WHEN status = 'pending' THEN commission_amount ELSE 0 END), 0) AS DECIMAL(10,2)) as pending_amount, CAST(COALESCE(SUM(CASE WHEN status = 'paid' THEN commission_amount ELSE 0 END), 0) AS DECIMAL(10,2)) as paid_amount, CAST(COALESCE(SUM(CASE WHEN DATE(created_at) = CURDATE() THEN commission_amount ELSE 0 END), 0) AS DECIMAL(10,2)) as today_amount FROM agent_commission_records WHERE agent_id = ? `, [agentId]); const stats = statsResult[0] || { total_commissions: 0, pending_commissions: 0, paid_commissions: 0, total_amount: '0.00', pending_amount: '0.00', paid_amount: '0.00', today_amount: '0.00' }; res.json({ success: true, data: { commissions, 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: '获取佣金记录失败' }); } }); /** * 获取单个佣金记录详情 * GET /api/commissions/:id */ router.get('/:id', agentAuth, async (req, res) => { try { const agentId = req.agent.id; const commissionId = req.params.id; // 查询佣金记录详情 const [commissions] = await getDB().execute(` SELECT acr.id, acr.agent_id, acr.merchant_id, acr.commission_type, acr.commission_amount, acr.status, acr.description, acr.reference_id, acr.created_at, acr.updated_at, acr.paid_at, u.username, u.real_name, u.phone, u.avatar, u.city, u.district FROM agent_commission_records acr LEFT JOIN users u ON acr.merchant_id = u.id WHERE acr.id = ? AND acr.agent_id = ? `, [commissionId, agentId]); if (commissions.length === 0) { return res.status(404).json({ success: false, message: '佣金记录不存在或无权限查看' }); } const commission = commissions[0]; res.json({ success: true, data: commission }); } catch (error) { logger.error('获取佣金记录详情失败', { error: error.message, stack: error.stack, agentId: req.agent?.id, commissionId: req.params.id }); res.status(500).json({ success: false, message: '获取佣金记录详情失败' }); } }); /** * 申请佣金发放(单个) * POST /api/commissions/:id/request-payment */ router.post('/:id/request-payment', agentAuth, async (req, res) => { try { const agentId = req.agent.id; const commissionId = req.params.id; // 检查佣金记录是否存在且属于当前代理 const [commissions] = await getDB().execute(` SELECT id, status, commission_amount FROM agent_commission_records WHERE id = ? AND agent_id = ? `, [commissionId, agentId]); if (commissions.length === 0) { return res.status(404).json({ success: false, message: '佣金记录不存在或无权限操作' }); } const commission = commissions[0]; if (commission.status !== 'pending') { return res.status(400).json({ success: false, message: '只能申请待发放状态的佣金' }); } // 更新佣金状态为申请中 await getDB().execute(` UPDATE agent_commission_records SET status = 'requested', updated_at = NOW() WHERE id = ? `, [commissionId]); logger.info('代理申请佣金发放', { agentId, commissionId, amount: commission.commission_amount }); res.json({ success: true, message: '佣金发放申请已提交,请等待审核' }); } catch (error) { logger.error('申请佣金发放失败', { error: error.message, stack: error.stack, agentId: req.agent?.id, commissionId: req.params.id }); res.status(500).json({ success: false, message: '申请佣金发放失败' }); } }); /** * 批量申请佣金发放 * POST /api/commissions/batch-request-payment */ router.post('/batch-request-payment', agentAuth, async (req, res) => { try { const agentId = req.agent.id; const { commission_ids } = req.body; if (!commission_ids || !Array.isArray(commission_ids) || commission_ids.length === 0) { return res.status(400).json({ success: false, message: '请选择要申请发放的佣金记录' }); } // 检查所有佣金记录是否存在且属于当前代理 const placeholders = commission_ids.map(() => '?').join(','); const [commissions] = await getDB().execute(` SELECT id, status, commission_amount FROM agent_commission_records WHERE id IN (${placeholders}) AND agent_id = ? `, [...commission_ids, agentId]); if (commissions.length !== commission_ids.length) { return res.status(400).json({ success: false, message: '部分佣金记录不存在或无权限操作' }); } // 检查状态 const invalidCommissions = commissions.filter(c => c.status !== 'pending'); if (invalidCommissions.length > 0) { return res.status(400).json({ success: false, message: '只能申请待发放状态的佣金' }); } // 批量更新状态 await getDB().execute(` UPDATE agent_commission_records SET status = 'requested', updated_at = NOW() WHERE id IN (${placeholders}) AND agent_id = ? `, [...commission_ids, agentId]); const totalAmount = commissions.reduce((sum, c) => sum + parseFloat(c.commission_amount), 0); logger.info('代理批量申请佣金发放', { agentId, commissionIds: commission_ids, count: commission_ids.length, totalAmount }); res.json({ success: true, message: `已提交${commission_ids.length}条佣金发放申请,总金额${totalAmount.toFixed(2)}元` }); } catch (error) { logger.error('批量申请佣金发放失败', { error: error.message, stack: error.stack, agentId: req.agent?.id }); res.status(500).json({ success: false, message: '批量申请佣金发放失败' }); } }); /** * 获取佣金趋势数据 * GET /api/commissions/trend */ router.get('/trend/data', agentAuth, async (req, res) => { try { const agentId = req.agent.id; const { days = 7, type = 'amount' } = req.query; let selectField = 'CAST(COALESCE(SUM(commission_amount), 0) AS DECIMAL(10,2)) as value'; if (type === 'count') { selectField = 'COUNT(*) as value'; } const [trendData] = await getDB().execute(` SELECT DATE(created_at) as date, ${selectField} FROM agent_commission_records WHERE agent_id = ? AND created_at >= DATE_SUB(CURDATE(), INTERVAL ? DAY) GROUP BY DATE(created_at) ORDER BY date ASC `, [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: '获取佣金趋势失败' }); } }); /** * 导出佣金记录 * GET /api/commissions/export */ router.get('/export/data', agentAuth, async (req, res) => { try { const agentId = req.agent.id; const { format = 'json', search, status, commission_type, start_date, end_date, min_amount, max_amount } = req.query; // 构建查询条件 let whereConditions = ['acr.agent_id = ?']; let queryParams = [agentId]; if (search) { whereConditions.push('(u.username LIKE ? OR u.real_name LIKE ? OR u.phone LIKE ?)'); queryParams.push(`%${search}%`, `%${search}%`, `%${search}%`); } if (status) { whereConditions.push('acr.status = ?'); queryParams.push(status); } if (commission_type) { whereConditions.push('acr.commission_type = ?'); queryParams.push(commission_type); } if (start_date) { whereConditions.push('DATE(acr.created_at) >= ?'); queryParams.push(start_date); } if (end_date) { whereConditions.push('DATE(acr.created_at) <= ?'); queryParams.push(end_date); } if (min_amount) { whereConditions.push('acr.commission_amount >= ?'); queryParams.push(parseFloat(min_amount)); } if (max_amount) { whereConditions.push('acr.commission_amount <= ?'); queryParams.push(parseFloat(max_amount)); } const whereClause = whereConditions.join(' AND '); // 查询佣金记录 const [commissions] = await getDB().execute(` SELECT acr.id, acr.commission_type, acr.commission_amount, acr.status, acr.description, acr.reference_id, acr.created_at, acr.paid_at, u.username, u.real_name, u.phone FROM agent_commission_records acr LEFT JOIN users u ON acr.merchant_id = u.id WHERE ${whereClause} ORDER BY acr.created_at DESC `, queryParams); if (format === 'csv') { // 生成CSV格式 const csvHeader = 'ID,佣金类型,佣金金额,状态,描述,关联ID,用户名,真实姓名,手机号,创建时间,发放时间\n'; const csvData = commissions.map(commission => { return [ commission.id, commission.commission_type || '', commission.commission_amount, commission.status || '', (commission.description || '').replace(/,/g, ','), // 替换逗号避免CSV格式问题 commission.reference_id || '', commission.username || '', commission.real_name || '', commission.phone || '', commission.created_at || '', commission.paid_at || '' ].join(','); }).join('\n'); res.setHeader('Content-Type', 'text/csv; charset=utf-8'); res.setHeader('Content-Disposition', `attachment; filename="commissions_${Date.now()}.csv"`); res.send(csvHeader + csvData); } else { // 默认JSON格式 res.json({ success: true, data: commissions, exported_at: new Date().toISOString(), total: commissions.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;