diff --git a/routes/agents/agents.js b/routes/agents/agents.js new file mode 100644 index 0000000..d05b488 --- /dev/null +++ b/routes/agents/agents.js @@ -0,0 +1,731 @@ +const express = require('express'); +const router = express.Router(); +const { getDB } = require('../../database'); +const bcrypt = require('bcryptjs'); +const { auth, adminAuth } = require('../../middleware/auth'); + +// 创建管理员认证中间件组合 +const authenticateAdmin = [auth, adminAuth]; + +// 获取数据库连接 +const db = { + query: async (sql, params = []) => { + const connection = getDB(); + const [rows] = await connection.execute(sql, params); + return rows; + } +}; + +// 获取代理列表和统计信息 +router.get('/', authenticateAdmin, async (req, res) => { + try { + const { page = 1, limit = 20, status, city, search } = req.query; + const pageNum = parseInt(page) || 1; + const limitNum = parseInt(limit) || 20; + const offset = (pageNum - 1) * limitNum; + + // 构建查询条件 + let whereConditions = []; + let queryParams = []; + + if (status) { + whereConditions.push('ra.status = ?'); + queryParams.push(status); + } + + if (city) { + whereConditions.push('zr.city_name = ?'); + queryParams.push(city); + } + + if (search) { + whereConditions.push('(ra.real_name LIKE ? OR ra.phone LIKE ?)'); + queryParams.push(`%${search}%`, `%${search}%`); + } + + const whereClause = whereConditions.length > 0 ? `WHERE ${whereConditions.join(' AND ')}` : ''; + + // 查询代理列表 + const agentsQuery = ` + SELECT + ra.*, + u.real_name, + u.phone, + u.id_card, + zr.city_name, + zr.district_name, + ( + SELECT COUNT(DISTINCT merchant_id) + FROM agent_merchants + WHERE agent_id = ra.id + ) as merchant_count, + ( + SELECT CAST(COALESCE(SUM(commission_amount), 0) AS DECIMAL(10,2)) + FROM agent_commission_records + WHERE agent_id = ra.id + ) as total_commission, + 0 as paid_commission, + ( + SELECT CAST(COALESCE(SUM(commission_amount), 0) AS DECIMAL(10,2)) + FROM agent_commission_records + WHERE agent_id = ra.id + ) as pending_commission + FROM regional_agents ra + LEFT JOIN users u ON ra.user_id = u.id + LEFT JOIN zhejiang_regions zr ON ra.region_id = zr.id + ${whereClause} + ORDER BY ra.created_at DESC + LIMIT ${limitNum} OFFSET ${offset} + `; + + const agents = await db.query(agentsQuery, queryParams); + + // 查询总数 + const countQuery = ` + SELECT COUNT(DISTINCT ra.id) as total + FROM regional_agents ra + LEFT JOIN users u ON ra.user_id = u.id + LEFT JOIN zhejiang_regions zr ON ra.region_id = zr.id + ${whereClause} + `; + + const totalResult = await db.query(countQuery, queryParams); + const total = totalResult && totalResult.length > 0 ? totalResult[0].total : 0; + + // 查询统计信息 + const statsQuery = ` + SELECT + COUNT(*) as total_agents, + COUNT(CASE WHEN status = 'pending' THEN 1 END) as pending_agents, + COUNT(CASE WHEN status = 'active' THEN 1 END) as active_agents, + CAST(COALESCE(SUM(commission_stats.total_commission), 0) AS DECIMAL(10,2)) as total_commission + FROM regional_agents ra + LEFT JOIN ( + SELECT + agent_id, + SUM(commission_amount) as total_commission + FROM agent_commission_records + GROUP BY agent_id + ) commission_stats ON ra.id = commission_stats.agent_id + `; + + const statsResult = await db.query(statsQuery); + const stats = statsResult && statsResult.length > 0 ? statsResult[0] : { + total_agents: 0, + pending_agents: 0, + active_agents: 0, + total_commission: 0 + }; + + res.json({ + success: true, + data: { + agents, + total: parseInt(total), + stats + } + }); + } catch (error) { + console.error('获取代理列表失败:', error); + res.status(500).json({ success: false, message: '获取代理列表失败' }); + } +}); + +// 获取代理详情 +router.get('/:id', authenticateAdmin, async (req, res) => { + try { + const { id } = req.params; + + const agentQuery = ` + SELECT + ra.*, + u.real_name as name, + u.phone, + u.id_card, + CONCAT(u.city, ' ', zr.district_name) as address, + zr.city_name, + zr.district_name, + ( + SELECT COUNT(DISTINCT merchant_id) + FROM agent_merchants + WHERE agent_id = ra.id + ) as merchant_count, + ( + SELECT COALESCE(SUM(commission_amount), 0) + FROM agent_commission_records + WHERE agent_id = ra.id + ) as total_commission, + 0 as paid_commission, + ( + SELECT COALESCE(SUM(commission_amount), 0) + FROM agent_commission_records + WHERE agent_id = ra.id + ) as pending_commission + FROM regional_agents ra + LEFT JOIN users u ON ra.user_id = u.id + LEFT JOIN zhejiang_regions zr ON ra.region_id = zr.id + WHERE ra.id = ? + `; + + const agentResult = await db.query(agentQuery, [id]); + + if (!agentResult || agentResult.length === 0) { + return res.status(404).json({ success: false, message: '代理不存在' }); + } + + const agent = agentResult[0]; + + res.json({ + success: true, + data: agent + }); + } catch (error) { + console.error('获取代理详情失败:', error); + res.status(500).json({ success: false, message: '获取代理详情失败' }); + } +}); + +// 审核通过代理申请 +router.put('/:id/approve', authenticateAdmin, async (req, res) => { + try { + const { id } = req.params; + const { password } = req.body; + + if (!password || password.length < 6) { + return res.status(400).json({ success: false, message: '密码长度不能少于6位' }); + } + + // 检查代理是否存在且状态为待审核 + const agents = await db.query( + 'SELECT * FROM regional_agents WHERE id = ? AND status = "pending"', + [id] + ); + + if (!agents || agents.length === 0) { + return res.status(404).json({ success: false, message: '代理不存在或状态不正确' }); + } + + const agent = agents[0]; + + // 检查该区域是否已有其他激活的代理 + const existingActiveAgents = await db.query( + 'SELECT id FROM regional_agents WHERE region_id = ? AND status = "active" AND id != ?', + [agent.region_id, id] + ); + + if (existingActiveAgents && existingActiveAgents.length > 0) { + return res.status(400).json({ success: false, message: '该区域已有激活的代理,每个区域只能有一个代理账号' }); + } + + // 加密密码并更新用户表 + const hashedPassword = await bcrypt.hash(password, 10); + + // 更新用户密码 + await db.query( + `UPDATE users SET password = ? WHERE id = ( + SELECT user_id FROM regional_agents WHERE id = ? + )`, + [hashedPassword, id] + ); + + // 更新代理状态 + await db.query( + `UPDATE regional_agents + SET status = 'active', approved_at = NOW(), approved_by_admin_id = ? + WHERE id = ?`, + [req.user.id, id] + ); + + res.json({ + success: true, + message: '代理申请已通过' + }); + } catch (error) { + console.error('审核代理申请失败:', error); + res.status(500).json({ success: false, message: '审核代理申请失败' }); + } +}); + +// 拒绝代理申请 +router.put('/:id/reject', authenticateAdmin, async (req, res) => { + try { + const { id } = req.params; + const { reason } = req.body; + + if (!reason || reason.trim() === '') { + return res.status(400).json({ success: false, message: '请输入拒绝原因' }); + } + + // 检查代理是否存在且状态为待审核 + const agentResult = await db.query( + 'SELECT * FROM regional_agents WHERE id = ? AND status = "pending"', + [id] + ); + + if (!agentResult || agentResult.length === 0) { + return res.status(404).json({ success: false, message: '代理不存在或状态不正确' }); + } + + const agent = agentResult[0]; + + // 更新代理状态 + await db.query( + `UPDATE regional_agents + SET status = 'rejected', reject_reason = ?, rejected_at = NOW(), rejected_by_admin_id = ? + WHERE id = ?`, + [reason.trim(), req.user.id, id] + ); + + res.json({ + success: true, + message: '代理申请已拒绝' + }); + } catch (error) { + console.error('拒绝代理申请失败:', error); + res.status(500).json({ success: false, message: '拒绝代理申请失败' }); + } +}); + +// 禁用代理 +router.put('/:id/disable', authenticateAdmin, async (req, res) => { + try { + const { id } = req.params; + + // 检查代理是否存在且状态为激活 + const agentResult = await db.query( + 'SELECT * FROM regional_agents WHERE id = ? AND status = "active"', + [id] + ); + + if (!agentResult || agentResult.length === 0) { + return res.status(404).json({ success: false, message: '代理不存在或状态不正确' }); + } + + const agent = agentResult[0]; + + // 更新代理状态 + await db.query( + 'UPDATE regional_agents SET status = "disabled", disabled_at = NOW() WHERE id = ?', + [id] + ); + + res.json({ + success: true, + message: '代理已禁用' + }); + } catch (error) { + console.error('禁用代理失败:', error); + res.status(500).json({ success: false, message: '禁用代理失败' }); + } +}); + +// 启用代理 +router.put('/:id/enable', authenticateAdmin, async (req, res) => { + try { + const { id } = req.params; + + // 检查代理是否存在且状态为禁用 + const agentResult = await db.query( + 'SELECT * FROM regional_agents WHERE id = ? AND status = "disabled"', + [id] + ); + + if (!agentResult || agentResult.length === 0) { + return res.status(404).json({ success: false, message: '代理不存在或状态不正确' }); + } + + const agent = agentResult[0]; + + // 检查该区域是否已有其他激活的代理 + const existingActiveAgentResult = await db.query( + 'SELECT id FROM regional_agents WHERE region_id = ? AND status = "active" AND id != ?', + [agent.region_id, id] + ); + + if (existingActiveAgentResult && existingActiveAgentResult.length > 0) { + return res.status(400).json({ success: false, message: '该区域已有激活的代理,每个区域只能有一个代理账号' }); + } + + // 更新代理状态 + await db.query( + 'UPDATE regional_agents SET status = "active", disabled_at = NULL WHERE id = ?', + [id] + ); + + res.json({ + success: true, + message: '代理已启用' + }); + } catch (error) { + console.error('启用代理失败:', error); + res.status(500).json({ success: false, message: '启用代理失败' }); + } +}); + +// 获取代理商户列表 +router.get('/:id/merchants', authenticateAdmin, async (req, res) => { + try { + const { id } = req.params; + const { page = 1, limit = 20 } = req.query; + const pageNum = parseInt(page) || 1; + const limitNum = parseInt(limit) || 20; + const offset = (pageNum - 1) * limitNum; + + // 检查代理是否存在 + const agentResult = await db.query('SELECT * FROM regional_agents WHERE id = ?', [id]); + if (!agentResult || agentResult.length === 0) { + return res.status(404).json({ success: false, message: '代理不存在' }); + } + const agent = agentResult[0]; + + // 查询代理的商户列表 + const merchantsQuery = ` + SELECT + u.id, + u.real_name, + u.phone, + u.created_at, + am.created_at as joined_at, + COUNT(mo.id) as match_count, + COUNT(CASE WHEN mo.status = 'completed' THEN 1 END) as completed_matches + FROM agent_merchants am + JOIN users u ON am.merchant_id = u.id + LEFT JOIN matching_orders mo ON u.id = mo.initiator_id + WHERE am.agent_id = ? + GROUP BY u.id, am.created_at + ORDER BY am.created_at DESC + LIMIT ${limitNum} OFFSET ${offset} + `; + + const merchants = await db.query(merchantsQuery, [id]); + + // 查询总数 + const totalResult = await db.query( + 'SELECT COUNT(*) as total FROM agent_merchants WHERE agent_id = ?', + [id] + ); + const total = totalResult && totalResult.length > 0 ? totalResult[0].total : 0; + + res.json({ + success: true, + data: { + merchants, + total: parseInt(total) + } + }); + } catch (error) { + console.error('获取代理商户列表失败:', error); + res.status(500).json({ success: false, message: '获取代理商户列表失败' }); + } +}); + +// 获取代理佣金记录 +router.get('/:id/commissions', authenticateAdmin, async (req, res) => { + try { + const { id } = req.params; + const { page = 1, limit = 20 } = req.query; + const pageNum = parseInt(page) || 1; + const limitNum = parseInt(limit) || 20; + const offset = (pageNum - 1) * limitNum; + + // 检查代理是否存在 + const agentResult = await db.query('SELECT * FROM regional_agents WHERE id = ?', [id]); + if (!agentResult || agentResult.length === 0) { + return res.status(404).json({ success: false, message: '代理不存在' }); + } + const agent = agentResult[0]; + + // 查询佣金记录 + const commissionsQuery = ` + SELECT + acr.*, + u.phone as merchant_phone + 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, [id]); + + // 查询总数 + const totalResult = await db.query( + 'SELECT COUNT(*) as total FROM agent_commission_records WHERE agent_id = ?', + [id] + ); + 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: '获取代理佣金记录失败' }); + } +}); + +// 获取代理商户的转账记录 +router.get('/:id/merchant-transfers', authenticateAdmin, async (req, res) => { + try { + const { id } = req.params; + const { page = 1, limit = 20, merchant_id } = req.query; + const pageNum = parseInt(page) || 1; + const limitNum = parseInt(limit) || 20; + const offset = (pageNum - 1) * limitNum; + + // 检查代理是否存在 + const agentResult = await db.query('SELECT * FROM regional_agents WHERE id = ?', [id]); + if (!agentResult || agentResult.length === 0) { + return res.status(404).json({ success: false, message: '代理不存在' }); + } + + // 构建查询条件 + let whereConditions = ['am.agent_id = ?']; + let queryParams = [id]; + + if (merchant_id) { + whereConditions.push('t.from_user_id = ?'); + queryParams.push(merchant_id); + } + + const whereClause = whereConditions.join(' AND '); + + // 查询商户转账记录 + const transfersQuery = ` + SELECT + t.id, + t.from_user_id, + t.to_user_id, + t.amount, + t.status, + t.transfer_type, + t.description, + t.created_at, + t.confirmed_at, + from_user.real_name as from_real_name, + CONCAT(SUBSTRING(from_user.phone, 1, 3), '****', SUBSTRING(from_user.phone, -4)) as from_phone_masked, + to_user.real_name as to_real_name, + CONCAT(SUBSTRING(to_user.phone, 1, 3), '****', SUBSTRING(to_user.phone, -4)) as to_phone_masked + FROM agent_merchants am + JOIN transfers t ON am.merchant_id = t.from_user_id + LEFT JOIN users from_user ON t.from_user_id = from_user.id + LEFT JOIN users to_user ON t.to_user_id = to_user.id + WHERE ${whereClause} + ORDER BY t.created_at DESC + LIMIT ${limitNum} OFFSET ${offset} + `; + + const transfers = await db.query(transfersQuery, queryParams); + + // 查询总数 + const totalQuery = ` + SELECT COUNT(*) as total + FROM agent_merchants am + JOIN transfers t ON am.merchant_id = t.from_user_id + WHERE ${whereClause} + `; + const totalResult = await db.query(totalQuery, queryParams); + const total = totalResult && totalResult.length > 0 ? totalResult[0].total : 0; + + res.json({ + success: true, + data: { + transfers, + total: parseInt(total) + } + }); + } catch (error) { + console.error('1:', error); + res.status(500).json({ success: false, message: '1获取代理商户转账记录失败' }); + } +}); + +/** + * 修改代理密码 + */ +router.put('/:id/password', authenticateAdmin, async (req, res) => { + try { + const { id } = req.params; + const { password } = req.body; + + if (!password || password.length < 6) { + return res.status(400).json({ success: false, message: '密码长度不能少于6位' }); + } + + // 检查代理是否存在且状态为激活 + const agentResult = await db.query( + 'SELECT * FROM regional_agents WHERE id = ? AND status = "active"', + [id] + ); + + if (!agentResult || agentResult.length === 0) { + return res.status(404).json({ success: false, message: '代理不存在或状态不正确' }); + } + + // 加密新密码 + const hashedPassword = await bcrypt.hash(password, 10); + + // 更新用户表中的密码(与审核通过时的逻辑一致) + await db.query( + `UPDATE users SET password = ? WHERE id = ( + SELECT user_id FROM regional_agents WHERE id = ? + )`, + [hashedPassword, id] + ); + + res.json({ + success: true, + message: '代理密码修改成功' + }); + } catch (error) { + console.error('修改代理密码失败:', error); + res.status(500).json({ success: false, message: '修改代理密码失败' }); + } +}); + +/** + * 删除代理 + */ +router.delete('/:id', authenticateAdmin, async (req, res) => { + try { + const { id } = req.params; + const { force = 'false' } = req.query; // 是否强制删除 + const forceDelete = force === 'true' + + // 检查代理是否存在 + const agentResult = await db.query( + 'SELECT * FROM regional_agents WHERE id = ?', + [id] + ); + + if (!agentResult || agentResult.length === 0) { + return res.status(404).json({ success: false, message: '代理不存在' }); + } + + const agent = agentResult[0]; + + // 检查代理是否有关联的商户 + const merchantCount = await db.query( + 'SELECT COUNT(*) as count FROM agent_merchants WHERE agent_id = ?', + [id] + ); + + const hasMerchants = merchantCount && merchantCount.length > 0 && merchantCount[0].count > 0; + + // 检查代理是否有佣金记录 + const commissionCount = await db.query( + 'SELECT COUNT(*) as count FROM agent_commission_records WHERE agent_id = ?', + [id] + ); + + const hasCommissions = commissionCount && commissionCount.length > 0 && commissionCount[0].count > 0; + + // 如果有关联数据且不是强制删除,则提示用户 + // if ((hasMerchants || hasCommissions) && !forceDelete) { + // return res.status(400).json({ + // success: false, + // message: '该代理存在关联数据(商户或佣金记录),请确认是否强制删除', + // data: { + // has_merchants: hasMerchants, + // has_commissions: hasCommissions, + // merchant_count: hasMerchants ? merchantCount[0].count : 0, + // commission_count: hasCommissions ? commissionCount[0].count : 0 + // }, + // require_force: true + // }); + // } + + // 开始事务删除 + const pool = getDB(); + const connection = await pool.getConnection(); + await connection.beginTransaction(); + + try { + // 删除代理商户关系 + if (hasMerchants) { + await connection.execute('DELETE FROM agent_merchants WHERE agent_id = ?', [id]); + } + + // 删除佣金记录(根据业务需求,可能需要保留历史记录) + if (hasCommissions && forceDelete) { + await connection.execute('DELETE FROM agent_commission_records WHERE agent_id = ?', [id]); + } + + // 删除代理记录 + await connection.execute('DELETE FROM regional_agents WHERE id = ?', [id]); + + // 获取区域信息用于日志 + const [regionResult] = await connection.execute( + 'SELECT * FROM zhejiang_regions WHERE id = ?', + [agent.region_id] + ); + const region = regionResult && regionResult.length > 0 ? regionResult[0] : null; + + await connection.commit(); + + // 记录操作日志 + const logMessage = `删除代理: ${agent.user_id} (区域: ${region ? `${region.city_name} ${region.district_name}` : '未知区域'})`; + console.log(`管理员 ${req.user.id} 执行操作: ${logMessage}`); + + res.json({ + success: true, + message: '代理删除成功', + data: { + deleted_agent_id: id, + deleted_merchants: hasMerchants ? merchantCount[0].count : 0, + deleted_commissions: (hasCommissions && forceDelete) ? commissionCount[0].count : 0 + } + }); + } catch (error) { + await connection.rollback(); + throw error; + } finally { + connection.release(); + } + } catch (error) { + console.error('删除代理失败:', error); + res.status(500).json({ success: false, message: '删除代理失败' }); + } +}); + +/** + * 获取可用的城市区域列表(用于代理城市更换) + */ +router.get('/available-regions', authenticateAdmin, async (req, res) => { + try { + // 查询所有区域,并标记是否已有激活代理 + const regionsQuery = ` + SELECT + zr.id, + zr.city_name, + zr.district_name, + CASE + WHEN ra.id IS NOT NULL THEN 1 + ELSE 0 + END as has_active_agent, + ra.id as agent_id, + u.real_name as agent_name + FROM zhejiang_regions zr + LEFT JOIN regional_agents ra ON zr.id = ra.region_id AND ra.status = 'active' + LEFT JOIN users u ON ra.user_id = u.id + ORDER BY zr.city_name, zr.district_name + `; + + const regions = await db.query(regionsQuery); + + res.json({ + success: true, + data: regions + }); + } catch (error) { + console.error('获取可用区域列表失败:', error); + res.status(500).json({ success: false, message: '获取可用区域列表失败' }); + } +}); + +module.exports = router; \ No newline at end of file diff --git a/routes/agents/withdrawals.js b/routes/agents/withdrawals.js new file mode 100644 index 0000000..e67a63f --- /dev/null +++ b/routes/agents/withdrawals.js @@ -0,0 +1,274 @@ +const express = require('express'); +const router = express.Router(); +const { getDB } = require('../../database'); +const { auth, adminAuth } = require('../../middleware/auth'); + +// 创建管理员认证中间件组合 +const authenticateAdmin = [auth, adminAuth]; + +// 获取数据库连接 +const db = { + query: async (sql, params = []) => { + const connection = getDB(); + const [rows] = await connection.execute(sql, params); + return rows; + } +}; + +/** + * 获取提现申请列表 + */ +router.get('/', authenticateAdmin, async (req, res) => { + try { + const { page = 1, limit = 20, status, agent_id } = req.query; + const pageNum = parseInt(page) || 1; + const limitNum = parseInt(limit) || 20; + const offset = (pageNum - 1) * limitNum; + + // 构建查询条件 + let whereConditions = []; + let queryParams = []; + + if (status) { + whereConditions.push('aw.status = ?'); + queryParams.push(status); + } + + if (agent_id) { + whereConditions.push('aw.agent_id = ?'); + queryParams.push(agent_id); + } + + const whereClause = whereConditions.length > 0 ? `WHERE ${whereConditions.join(' AND ')}` : ''; + + // 查询提现申请列表 + const withdrawalsQuery = ` + SELECT + aw.*, + ra.agent_code, + u.real_name as agent_name, + u.phone as agent_phone, + zr.city_name, + zr.district_name, + admin.real_name as processed_by_name + FROM agent_withdrawals aw + JOIN regional_agents ra ON aw.agent_id = ra.id + JOIN users u ON ra.user_id = u.id + LEFT JOIN zhejiang_regions zr ON ra.region_id = zr.id + LEFT JOIN users admin ON aw.processed_by = admin.id + ${whereClause} + ORDER BY aw.created_at DESC + LIMIT ${limitNum} OFFSET ${offset} + `; + + const withdrawals = await db.query(withdrawalsQuery, queryParams); + + // 查询总数 + const countQuery = ` + SELECT COUNT(*) as total + FROM agent_withdrawals aw + ${whereClause} + `; + + const totalResult = await db.query(countQuery, queryParams); + const total = totalResult && totalResult.length > 0 ? totalResult[0].total : 0; + + // 查询统计信息 + const statsQuery = ` + SELECT + COUNT(*) as total_applications, + COUNT(CASE WHEN status = 'pending' THEN 1 END) as pending_count, + COUNT(CASE WHEN status = 'approved' THEN 1 END) as approved_count, + COUNT(CASE WHEN status = 'completed' THEN 1 END) as completed_count, + COUNT(CASE WHEN status = 'rejected' THEN 1 END) as rejected_count, + CAST(COALESCE(SUM(CASE WHEN status = 'pending' THEN amount END), 0) AS DECIMAL(10,2)) as pending_amount, + CAST(COALESCE(SUM(CASE WHEN status = 'completed' THEN amount END), 0) AS DECIMAL(10,2)) as completed_amount + FROM agent_withdrawals + `; + + const statsResult = await db.query(statsQuery); + const stats = statsResult && statsResult.length > 0 ? statsResult[0] : { + total_applications: 0, + pending_count: 0, + approved_count: 0, + completed_count: 0, + rejected_count: 0, + pending_amount: 0, + completed_amount: 0 + }; + + res.json({ + success: true, + data: { + withdrawals, + total: parseInt(total), + stats + } + }); + } catch (error) { + console.error('获取提现申请列表失败:', error); + res.status(500).json({ success: false, message: '获取提现申请列表失败' }); + } +}); + +/** + * 审核提现申请 + */ +router.put('/:id/review', authenticateAdmin, async (req, res) => { + try { + const { id } = req.params; + const { action, admin_note } = req.body; + const adminId = req.user.id; + + if (!['approve', 'reject'].includes(action)) { + return res.status(400).json({ success: false, message: '无效的审核操作' }); + } + + // 检查提现申请是否存在且状态为待审核 + const withdrawalResult = await db.query( + 'SELECT * FROM agent_withdrawals WHERE id = ? AND status = "pending"', + [id] + ); + + if (!withdrawalResult || withdrawalResult.length === 0) { + return res.status(404).json({ success: false, message: '提现申请不存在或已处理' }); + } + + const withdrawal = withdrawalResult[0]; + const newStatus = action === 'approve' ? 'approved' : 'rejected'; + + // 开始事务 + const pool = getDB(); + const connection = await pool.getConnection(); + await connection.beginTransaction(); + + try { + // 更新提现申请状态 + await connection.execute( + 'UPDATE agent_withdrawals SET status = ?, admin_note = ?, processed_by = ?, processed_at = NOW() WHERE id = ?', + [newStatus, admin_note || null, adminId, id] + ); + + // 如果是拒绝,需要恢复代理的待提现金额 + if (action === 'reject') { + await connection.execute( + 'UPDATE regional_agents SET pending_withdrawal = pending_withdrawal - ? WHERE id = ?', + [withdrawal.amount, withdrawal.agent_id] + ); + } + + await connection.commit(); + connection.release(); // 释放连接回连接池 + + res.json({ + success: true, + message: action === 'approve' ? '提现申请已通过审核' : '提现申请已拒绝' + }); + } catch (error) { + await connection.rollback(); + connection.release(); // 释放连接回连接池 + throw error; + } + } catch (error) { + console.error('审核提现申请失败:', error); + res.status(500).json({ success: false, message: '审核提现申请失败' }); + } +}); + +/** + * 标记提现完成 + */ +router.put('/:id/complete', authenticateAdmin, async (req, res) => { + try { + const { id } = req.params; + const adminId = req.user.id; + + // 检查提现申请是否存在且状态为已审核 + const withdrawalResult = await db.query( + 'SELECT * FROM agent_withdrawals WHERE id = ? AND status = "approved"', + [id] + ); + + if (!withdrawalResult || withdrawalResult.length === 0) { + return res.status(404).json({ success: false, message: '提现申请不存在或状态不正确' }); + } + + const withdrawal = withdrawalResult[0]; + + // 开始事务 + const pool = getDB(); + const connection = await pool.getConnection(); + await connection.beginTransaction(); + + try { + // 更新提现申请状态为已完成 + await connection.execute( + 'UPDATE agent_withdrawals SET status = "completed", processed_by = ?, processed_at = NOW() WHERE id = ?', + [adminId, id] + ); + + // 更新代理的已提现金额和待提现金额 + await connection.execute( + 'UPDATE regional_agents SET withdrawn_amount = withdrawn_amount + ?, pending_withdrawal = pending_withdrawal - ? WHERE id = ?', + [withdrawal.amount, withdrawal.amount, withdrawal.agent_id] + ); + + await connection.commit(); + connection.release(); // 释放连接回连接池 + + res.json({ + success: true, + message: '提现已标记为完成' + }); + } catch (error) { + await connection.rollback(); + connection.release(); // 释放连接回连接池 + throw error; + } + } catch (error) { + console.error('标记提现完成失败:', error); + res.status(500).json({ success: false, message: '标记提现完成失败' }); + } +}); + +/** + * 获取提现申请详情 + */ +router.get('/:id', authenticateAdmin, async (req, res) => { + try { + const { id } = req.params; + + const withdrawalQuery = ` + SELECT + aw.*, + ra.agent_code, + u.real_name as agent_name, + u.phone as agent_phone, + zr.city_name, + zr.district_name, + admin.real_name as processed_by_name + FROM agent_withdrawals aw + JOIN regional_agents ra ON aw.agent_id = ra.id + JOIN users u ON ra.user_id = u.id + LEFT JOIN zhejiang_regions zr ON ra.region_id = zr.id + LEFT JOIN users admin ON aw.processed_by = admin.id + WHERE aw.id = ? + `; + + const withdrawalResult = await db.query(withdrawalQuery, [id]); + + if (!withdrawalResult || withdrawalResult.length === 0) { + return res.status(404).json({ success: false, message: '提现申请不存在' }); + } + + res.json({ + success: true, + data: withdrawalResult[0] + }); + } catch (error) { + console.error('获取提现申请详情失败:', error); + res.status(500).json({ success: false, message: '获取提现申请详情失败' }); + } +}); + +module.exports = router; \ No newline at end of file diff --git a/server.js b/server.js index adddadf..707158b 100644 --- a/server.js +++ b/server.js @@ -243,8 +243,8 @@ app.use('/api/admin/matching', require('./routes/matchingAdmin')); app.use('/api/system', require('./routes/system')); app.use('/api/risk', require('./routes/riskManagement')); app.use('/api/agents', require('./routes/agents')); -app.use('/api/admin/agents', require('./admin/routes/agents')); -app.use('/api/admin/withdrawals', require('./admin/routes/withdrawals')); +app.use('/api/admin/agents', require('./routes/agents/agents')); +app.use('/api/admin/withdrawals', require('./routes/agents/withdrawals')); app.use('/api/agent-withdrawals', require('./routes/agent-withdrawals')); app.use('/api/regions', require('./routes/regions')); app.use('/api/addresses', require('./routes/addresses'));