const express = require('express'); router = express.Router(); /** * @swagger * tags: * name: RiskManagement * description: 风险管理API */ const { auth } = require('../middleware/auth'); const timeoutService = require('../services/timeoutService'); const { getDB } = require('../database'); /** * 检查管理员权限 */ const requireAdmin = (req, res, next) => { if (req.user.role !== 'admin') { return res.status(403).json({ success: false, message: '需要管理员权限' }); } next(); }; /** * @swagger * /risk-management/users: * get: * summary: 获取风险用户列表 * tags: [RiskManagement] * security: * - bearerAuth: [] * parameters: * - in: query * name: page * schema: * type: integer * default: 1 * description: 页码 * - in: query * name: limit * schema: * type: integer * default: 10 * description: 每页数量 * - in: query * name: is_blacklisted * schema: * type: integer * enum: [0, 1] * description: 是否被拉黑 * - in: query * name: username * schema: * type: string * description: 用户名 * responses: * 200: * description: 成功获取风险用户列表 * content: * application/json: * schema: * type: object * properties: * success: * type: boolean * data: * type: object * properties: * users: * type: array * items: * type: object * properties: * id: * type: integer * username: * type: string * real_name: * type: string * is_blacklisted: * type: boolean * blacklist_reason: * type: string * blacklisted_at: * type: string * format: date-time * pagination: * type: object * properties: * total: * type: integer * page: * type: integer * limit: * type: integer * pages: * type: integer * 401: * description: 未授权 * 403: * description: 权限不足 * 500: * description: 服务器错误 */ router.get('/users', auth, requireAdmin, async (req, res) => { try { const { page = 1, limit = 10, is_blacklisted, username } = req.query; const filters = {}; if (is_blacklisted !== undefined) { filters.is_blacklisted = parseInt(is_blacklisted); } if (username) { filters.username = username; } const result = await timeoutService.getRiskUsers(filters, { page, limit }); res.json({ success: true, data: result }); } catch (error) { console.error('获取风险用户列表失败:', error); res.status(500).json({ success: false, message: '获取风险用户列表失败' }); } }); /** * @swagger * /risk-management/blacklist/{userId}: * post: * summary: 拉黑用户 * tags: [RiskManagement] * security: * - bearerAuth: [] * parameters: * - in: path * name: userId * schema: * type: integer * required: true * description: 用户ID * requestBody: * required: true * content: * application/json: * schema: * type: object * required: * - reason * properties: * reason: * type: string * description: 拉黑原因 * responses: * 200: * description: 用户已被拉黑 * content: * application/json: * schema: * type: object * properties: * success: * type: boolean * example: true * message: * type: string * example: 用户已被拉黑 * 400: * description: 请求参数错误 * 401: * description: 未授权 * 403: * description: 权限不足 * 500: * description: 服务器错误 */ router.post('/blacklist/:userId', auth, requireAdmin, async (req, res) => { try { const { userId } = req.params; const { reason } = req.body; const operatorId = req.user.id; if (!reason || reason.trim() === '') { return res.status(400).json({ success: false, message: '请提供拉黑原因' }); } await timeoutService.blacklistUser(parseInt(userId), reason.trim(), operatorId); res.json({ success: true, message: '用户已被拉黑' }); } catch (error) { console.error('拉黑用户失败:', error); res.status(500).json({ success: false, message: error.message || '拉黑用户失败' }); } }); /** * @swagger * /risk-management/unblacklist/{userId}: * post: * summary: 解除拉黑 * tags: [RiskManagement] * security: * - bearerAuth: [] * parameters: * - in: path * name: userId * schema: * type: integer * required: true * description: 用户ID * responses: * 200: * description: 已解除拉黑 * content: * application/json: * schema: * type: object * properties: * success: * type: boolean * example: true * message: * type: string * example: 已解除拉黑 * 401: * description: 未授权 * 403: * description: 权限不足 * 500: * description: 服务器错误 */ router.post('/unblacklist/:userId', auth, requireAdmin, async (req, res) => { try { const { userId } = req.params; const operatorId = req.user.id; await timeoutService.unblacklistUser(parseInt(userId), operatorId); res.json({ success: true, message: '已解除拉黑' }); } catch (error) { console.error('解除拉黑失败:', error); res.status(500).json({ success: false, message: error.message || '解除拉黑失败' }); } }); /** * @swagger * /risk-management/overdue-transfers: * get: * summary: 获取超时转账列表 * tags: [RiskManagement] * security: * - bearerAuth: [] * parameters: * - in: query * name: page * schema: * type: integer * default: 1 * description: 页码 * - in: query * name: limit * schema: * type: integer * default: 10 * description: 每页数量 * responses: * 200: * description: 成功获取超时转账列表 * content: * application/json: * schema: * type: object * properties: * success: * type: boolean * data: * type: object * properties: * transfers: * type: array * items: * type: object * properties: * id: * type: integer * user_id: * type: integer * recipient_id: * type: integer * amount: * type: number * status: * type: string * created_at: * type: string * format: date-time * username: * type: string * recipient_name: * type: string * overdue_hours: * type: number * pagination: * type: object * properties: * total: * type: integer * page: * type: integer * limit: * type: integer * pages: * type: integer * 401: * description: 未授权 * 403: * description: 权限不足 * 500: * description: 服务器错误 */ router.get('/overdue-transfers', auth, requireAdmin, async (req, res) => { try { const { page = 1, limit = 10 } = req.query; const pageNum = parseInt(page, 10) || 1; const limitNum = parseInt(limit, 10) || 10; const offset = (pageNum - 1) * limitNum; const db = getDB(); // 获取总数 const [countResult] = await db.execute( 'SELECT COUNT(*) as total FROM transfers WHERE is_overdue = 1' ); const total = countResult[0].total; // 获取数据 const [transfers] = await db.execute( `SELECT t.*, fu.username as from_username, fu.real_name as from_real_name, tu.username as to_username, tu.real_name as to_real_name FROM transfers t LEFT JOIN users fu ON t.from_user_id = fu.id LEFT JOIN users tu ON t.to_user_id = tu.id WHERE t.is_overdue = 1 ORDER BY t.overdue_at DESC LIMIT ${limitNum} OFFSET ${offset}` ); res.json({ success: true, data: { transfers, pagination: { page: pageNum, limit: limitNum, total, pages: Math.ceil(total / limitNum) } } }); } catch (error) { console.error('获取超时转账列表失败:', error); res.status(500).json({ success: false, message: '获取超时转账列表失败' }); } }); /** * 手动检查转账超时 */ router.post('/check-timeouts', auth, requireAdmin, async (req, res) => { try { await timeoutService.checkTransferTimeouts(); res.json({ success: true, message: '转账超时检查已完成' }); } catch (error) { console.error('手动检查转账超时失败:', error); res.status(500).json({ success: false, message: '检查转账超时失败' }); } }); /** * 获取风险管理统计信息 */ router.get('/stats', auth, requireAdmin, async (req, res) => { try { const db = getDB(); // 获取统计数据 const [stats] = await db.execute( `SELECT COUNT(CASE WHEN is_risk_user = 1 THEN 1 END) as risk_users_count, COUNT(CASE WHEN is_blacklisted = 1 THEN 1 END) as blacklisted_users_count, COUNT(CASE WHEN is_risk_user = 1 AND is_blacklisted = 0 THEN 1 END) as risk_not_blacklisted_count FROM users` ); const [overdueStats] = await db.execute( `SELECT COUNT(*) as overdue_transfers_count, SUM(amount) as overdue_amount_total FROM transfers WHERE is_overdue = 1` ); const [todayOverdue] = await db.execute( `SELECT COUNT(*) as today_overdue_count FROM transfers WHERE is_overdue = 1 AND DATE(overdue_at) = CURDATE()` ); res.json({ success: true, data: { riskUsersCount: stats[0].risk_users_count, blacklistedUsersCount: stats[0].blacklisted_users_count, riskNotBlacklistedCount: stats[0].risk_not_blacklisted_count, overdueTransfersCount: overdueStats[0].overdue_transfers_count, overdueAmountTotal: overdueStats[0].overdue_amount_total || 0, todayOverdueCount: todayOverdue[0].today_overdue_count } }); } catch (error) { console.error('获取风险管理统计失败:', error); res.status(500).json({ success: false, message: '获取统计信息失败' }); } }); module.exports = router;