更改位置
This commit is contained in:
731
routes/agents/agents.js
Normal file
731
routes/agents/agents.js
Normal file
@@ -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;
|
||||
274
routes/agents/withdrawals.js
Normal file
274
routes/agents/withdrawals.js
Normal file
@@ -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;
|
||||
@@ -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'));
|
||||
|
||||
Reference in New Issue
Block a user