const express = require('express'); const router = express.Router(); const { getDB } = require('../database'); const { auth } = require('../middleware/auth'); const multer = require('multer'); const path = require('path'); const fs = require('fs'); // 配置multer用于文件上传 const storage = multer.diskStorage({ destination: function (req, file, cb) { const uploadDir = 'uploads/qr-codes'; // 确保上传目录存在 if (!fs.existsSync(uploadDir)) { fs.mkdirSync(uploadDir, { recursive: true }); } cb(null, uploadDir); }, filename: function (req, file, cb) { // 生成唯一文件名 const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9); cb(null, 'qr-code-' + uniqueSuffix + path.extname(file.originalname)); } }); // 文件过滤器 const fileFilter = (req, file, cb) => { // 只允许图片文件 if (file.mimetype.startsWith('image/')) { cb(null, true); } else { cb(new Error('只允许上传图片文件'), false); } }; const upload = multer({ storage: storage, fileFilter: fileFilter, limits: { fileSize: 5 * 1024 * 1024 // 限制文件大小为5MB } }); // 获取数据库连接 const db = { query: async (sql, params = []) => { const connection = getDB(); const [rows] = await connection.execute(sql, params); return rows; } }; /** * 检查用户是否为代理商 */ const requireAgent = async (req, res, next) => { try { const userId = req.user.id; // 查询用户是否为代理商 const agentResult = await db.query( 'SELECT * FROM regional_agents WHERE user_id = ? AND status = "active"', [userId] ); if (!agentResult || agentResult.length === 0) { return res.status(403).json({ success: false, message: '您不是活跃的代理商' }); } req.agent = agentResult[0]; next(); } catch (error) { console.error('检查代理商身份失败:', error); res.status(500).json({ success: false, message: '检查代理商身份失败' }); } }; /** * 获取代理商佣金统计信息 */ router.get('/stats', auth, requireAgent, async (req, res) => { try { const agentId = req.agent.id; // 查询佣金统计 const statsQuery = ` SELECT CAST(COALESCE(commission_sum.total_commission, 0) AS DECIMAL(10,2)) as total_commission, CAST(COALESCE(ra.withdrawn_amount, 0) AS DECIMAL(10,2)) as withdrawn_amount, CAST(COALESCE(ra.pending_withdrawal, 0) AS DECIMAL(10,2)) as pending_withdrawal, CAST(COALESCE(commission_sum.total_commission, 0) - COALESCE(ra.withdrawn_amount, 0) - COALESCE(ra.pending_withdrawal, 0) AS DECIMAL(10,2)) as available_amount FROM regional_agents ra LEFT JOIN ( SELECT agent_id, SUM(commission_amount) as total_commission FROM agent_commission_records WHERE agent_id = ? GROUP BY agent_id ) commission_sum ON ra.id = commission_sum.agent_id WHERE ra.id = ? `; const statsResult = await db.query(statsQuery, [agentId, agentId]); const stats = statsResult && statsResult.length > 0 ? statsResult[0] : { total_commission: 0, withdrawn_amount: 0, pending_withdrawal: 0, available_amount: 0 }; // 查询代理商信息包括收款方式 const agentInfo = await db.query( 'SELECT payment_type, bank_name, account_number, account_holder, qr_code_url, bank_account FROM regional_agents WHERE id = ?', [agentId] ); const agent = agentInfo[0] || {}; // 构建收款方式信息,兼容旧数据 const paymentInfo = { payment_type: agent.payment_type || 'bank', bank_name: agent.bank_name || '', account_number: agent.account_number || agent.bank_account, // 兼容旧字段 account_holder: agent.account_holder, qr_code_url: agent.qr_code_url || '' }; // 兼容旧的bankInfo字段 const bankInfo = { bank_name: agent.bank_name || '', bank_account: agent.bank_account || agent.account_number, account_holder: agent.account_holder }; res.json({ success: true, data: { ...stats, paymentInfo: paymentInfo, bank_info: bankInfo // 保持向后兼容 } }); } catch (error) { console.error('获取佣金统计失败:', error); res.status(500).json({ success: false, message: '获取佣金统计失败' }); } }); /** * 更新收款方式信息 */ router.put('/payment-info', auth, requireAgent, async (req, res) => { try { const { payment_type, bank_name, account_number, account_holder, qr_code_url } = req.body; const agentId = req.agent.id; // 验证收款方式类型 const validPaymentTypes = ['bank', 'wechat', 'alipay', 'unionpay']; if (!validPaymentTypes.includes(payment_type)) { return res.status(400).json({ success: false, message: '收款方式类型不正确' }); } // 根据收款方式类型进行不同的验证 if (payment_type === 'bank') { // 银行卡验证 if (!bank_name || !account_number || !account_holder) { return res.status(400).json({ success: false, message: '银行信息不完整' }); } // 验证银行账号格式(简单验证) if (!/^\d{10,25}$/.test(account_number.replace(/\s/g, ''))) { return res.status(400).json({ success: false, message: '银行账号格式不正确' }); } } else { // 收款码验证 if (!account_holder || !qr_code_url) { return res.status(400).json({ success: false, message: '收款码信息不完整' }); } } // 更新收款方式信息 await db.query( 'UPDATE regional_agents SET payment_type = ?, bank_name = ?, account_number = ?, account_holder = ?, qr_code_url = ? WHERE id = ?', [payment_type, bank_name, account_number, account_holder, qr_code_url, agentId] ); res.json({ success: true, message: '收款方式信息更新成功' }); } catch (error) { console.error('更新收款方式信息失败:', error); res.status(500).json({ success: false, message: '更新收款方式信息失败' }); } }); /** * 上传收款码图片 */ router.post('/upload-qr-code', auth, requireAgent, upload.single('qrCode'), async (req, res) => { try { if (!req.file) { return res.status(400).json({ success: false, message: '请选择要上传的图片' }); } // 构建文件访问URL const fileUrl = `/uploads/qr-codes/${req.file.filename}`; res.json({ success: true, message: '收款码上传成功', data: { url: fileUrl, filename: req.file.filename } }); } catch (error) { console.error('上传收款码失败:', error); res.status(500).json({ success: false, message: '上传收款码失败' }); } }); /** * 兼容旧的银行信息接口 */ router.put('/bank-info', auth, requireAgent, async (req, res) => { try { const agentId = req.agent.id; const { bank_name, bank_account, account_holder } = req.body; // 验证必填字段 if (!bank_name || !bank_account || !account_holder) { return res.status(400).json({ success: false, message: '银行信息不完整' }); } // 验证银行账号格式(简单验证) if (!/^\d{10,25}$/.test(bank_account)) { return res.status(400).json({ success: false, message: '银行账号格式不正确' }); } // 更新银行信息 await db.query( 'UPDATE regional_agents SET payment_type = "bank", bank_name = ?, account_number = ?, account_holder = ?, bank_account = ? WHERE id = ?', [bank_name, bank_account, account_holder, bank_account, agentId] ); res.json({ success: true, message: '银行信息更新成功' }); } catch (error) { console.error('更新银行信息失败:', error); res.status(500).json({ success: false, message: '更新银行信息失败' }); } }); /** * 申请提现 */ router.post('/apply', auth, requireAgent, async (req, res) => { try { const agentId = req.agent.id; const { amount, apply_note } = req.body; // 验证提现金额 if (!amount || amount <= 0) { return res.status(400).json({ success: false, message: '提现金额必须大于0' }); } if (amount < 10) { return res.status(400).json({ success: false, message: '最低提现金额为100元' }); } // 查询代理商信息和可提现金额 const agentQuery = ` SELECT ra.*, CAST(COALESCE(SUM(acr.commission_amount), 0) - COALESCE(ra.withdrawn_amount, 0) - COALESCE(ra.pending_withdrawal, 0) AS DECIMAL(10,2)) as available_amount FROM regional_agents ra LEFT JOIN agent_commission_records acr ON ra.id = acr.agent_id WHERE ra.id = ? GROUP BY ra.id `; const agentResult = await db.query(agentQuery, [agentId]); if (!agentResult || agentResult.length === 0) { return res.status(404).json({ success: false, message: '代理商信息不存在' }); } const agent = agentResult[0]; // 检查收款方式信息是否完整 const paymentType = agent.payment_type || 'bank'; if (paymentType === 'bank') { // 银行卡收款方式验证 if (!agent.bank_name || !agent.account_number || !agent.account_holder) { return res.status(400).json({ success: false, message: '请先完善银行信息' }); } } else { // 收款码收款方式验证 if (!agent.account_holder || !agent.qr_code_url) { return res.status(400).json({ success: false, message: '请先完善收款码信息' }); } } // 检查可提现金额 if (amount > agent.available_amount) { return res.status(400).json({ success: false, message: `可提现金额不足,当前可提现:¥${agent.available_amount}` }); } // 开始事务 const pool = getDB(); const connection = await pool.getConnection(); await connection.beginTransaction(); try { // 创建提现申请 await connection.execute( 'INSERT INTO agent_withdrawals (agent_id, amount, payment_type, bank_name, account_number, account_holder, qr_code_url, apply_note, bank_account) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)', [agentId, amount, paymentType, agent.bank_name || '', agent.account_number, agent.account_holder, agent.qr_code_url, apply_note || null, agent.account_number] ); // 更新代理的待提现金额 await connection.execute( 'UPDATE regional_agents SET pending_withdrawal = pending_withdrawal + ? WHERE id = ?', [amount, agentId] ); await connection.commit(); connection.release(); // 释放连接回连接池 res.json({ success: true, message: '提现申请提交成功,请等待审核', data: { paymentType: paymentType } }); } catch (error) { await connection.rollback(); connection.release(); // 释放连接回连接池 throw error; } } catch (error) { console.error('申请提现失败:', error); res.status(500).json({ success: false, message: '申请提现失败' }); } }); /** * 获取提现记录 */ router.get('/records', auth, requireAgent, async (req, res) => { try { const agentId = req.agent.id; const { page = 1, limit = 20, status } = req.query; const pageNum = parseInt(page) || 1; const limitNum = parseInt(limit) || 20; const offset = (pageNum - 1) * limitNum; // 构建查询条件 let whereConditions = ['agent_id = ?']; let queryParams = [agentId]; if (status) { whereConditions.push('status = ?'); queryParams.push(status); } const whereClause = whereConditions.join(' AND '); // 查询提现记录 const recordsQuery = ` SELECT id, amount, payment_type, bank_name, account_number, account_holder, qr_code_url, status, apply_note, admin_note, created_at, processed_at, bank_account FROM agent_withdrawals WHERE ${whereClause} ORDER BY created_at DESC LIMIT ${limitNum} OFFSET ${offset} `; const records = await db.query(recordsQuery, queryParams); // 处理记录数据,兼容旧格式 const processedRecords = records.map(record => ({ ...record, payment_type: record.payment_type || 'bank', account_number: record.account_number || record.bank_account, qr_code_url: record.qr_code_url || '', // 保持向后兼容 bank_account: record.bank_account || record.account_number })); // 查询总数 const totalResult = await db.query( `SELECT COUNT(*) as total FROM agent_withdrawals WHERE ${whereClause}`, queryParams ); const total = totalResult && totalResult.length > 0 ? totalResult[0].total : 0; res.json({ success: true, data: { records: processedRecords, total: parseInt(total) } }); } catch (error) { console.error('获取提现记录失败:', error); res.status(500).json({ success: false, message: '获取提现记录失败' }); } }); /** * 获取佣金明细 */ router.get('/commissions', auth, requireAgent, async (req, res) => { try { const agentId = req.agent.id; const { page = 1, limit = 20 } = req.query; const pageNum = parseInt(page) || 1; const limitNum = parseInt(limit) || 20; const offset = (pageNum - 1) * limitNum; // 查询佣金记录 const commissionsQuery = ` SELECT acr.*, u.real_name as merchant_name, CONCAT(SUBSTRING(u.phone, 1, 3), '****', SUBSTRING(u.phone, -4)) as merchant_phone_masked FROM agent_commission_records acr JOIN users u ON acr.merchant_id = u.id WHERE acr.agent_id = ? ORDER BY acr.created_at DESC LIMIT ${limitNum} OFFSET ${offset} `; const commissions = await db.query(commissionsQuery, [agentId]); // 查询总数 const totalResult = await db.query( 'SELECT COUNT(*) as total FROM agent_commission_records WHERE agent_id = ?', [agentId] ); const total = totalResult && totalResult.length > 0 ? totalResult[0].total : 0; res.json({ success: true, data: { commissions, total: parseInt(total) } }); } catch (error) { console.error('获取佣金明细失败:', error); res.status(500).json({ success: false, message: '获取佣金明细失败' }); } }); module.exports = router;