Files
jurong_circle_black/routes/points.js
2025-08-26 10:06:23 +08:00

348 lines
10 KiB
JavaScript

const express = require('express');
const router = express.Router();
const { getDB } = require('../database');
const { auth, adminAuth } = require('../middleware/auth');
// 获取用户当前积分
router.get('/balance', auth, async (req, res) => {
try {
const userId = req.user.id;
const [users] = await getDB().execute(
'SELECT points FROM users WHERE id = ?',
[userId]
);
if (users.length === 0) {
return res.status(404).json({ success: false, message: '用户不存在' });
}
res.json({
success: true,
data: {
points: users[0].points
}
});
} catch (error) {
console.error('获取积分余额失败:', error);
res.status(500).json({ success: false, message: '获取积分余额失败' });
}
});
// 获取用户积分历史记录
router.get('/history', auth, async (req, res) => {
try {
const { page = 1, limit = 10, type, username, change, startDate, endDate } = req.query;
// 确保参数为有效数字
const pageNum = parseInt(page) || 1;
const limitNum = parseInt(limit) || 10;
const offset = (pageNum - 1) * limitNum;
let whereClause = '';
let queryParams = [];
// 如果是管理员,可以查看所有用户的积分历史
if (req.user.role === 'admin') {
whereClause = 'WHERE 1=1';
// 按用户名筛选
if (username) {
whereClause += ' AND u.username LIKE ?';
queryParams.push(`%${username}%`);
}
// 按类型筛选
if (type) {
whereClause += ' AND ph.type = ?';
queryParams.push(type);
}
// 按积分变化筛选
if (change === 'positive') {
whereClause += ' AND ph.amount > 0';
} else if (change === 'negative') {
whereClause += ' AND ph.amount < 0';
}
// 按时间范围筛选
if (startDate) {
whereClause += ' AND DATE(ph.created_at) >= ?';
queryParams.push(startDate);
}
if (endDate) {
whereClause += ' AND DATE(ph.created_at) <= ?';
queryParams.push(endDate);
}
} else {
// 普通用户只能查看自己的积分历史
whereClause = 'WHERE ph.user_id = ?';
queryParams.push(req.user.id);
if (type && ['earn', 'spend'].includes(type)) {
whereClause += ' AND ph.type = ?';
queryParams.push(type);
}
}
// 获取总数
const countQuery = req.user.role === 'admin'
? `SELECT COUNT(*) as total FROM points_history ph JOIN users u ON ph.user_id = u.id ${whereClause}`
: `SELECT COUNT(*) as total FROM points_history ph ${whereClause}`;
const [countResult] = await getDB().execute(countQuery, queryParams);
// 获取历史记录
const historyQuery = req.user.role === 'admin'
? `SELECT ph.id, ph.amount as points, ph.type, ph.description, ph.created_at,
u.username,
(SELECT points FROM users WHERE id = ph.user_id) as balance_after
FROM points_history ph
JOIN users u ON ph.user_id = u.id
${whereClause}
ORDER BY ph.created_at DESC
LIMIT ${limitNum} OFFSET ${offset}`
: `SELECT id, amount as points_change, type, description, created_at
FROM points_history ph
${whereClause}
ORDER BY created_at DESC
LIMIT ${limitNum} OFFSET ${offset}`;
const [records] = await getDB().execute(historyQuery, queryParams);
const responseData = req.user.role === 'admin'
? {
history: records,
total: countResult[0].total
}
: {
records,
pagination: {
page: pageNum,
limit: limitNum,
total: countResult[0].total,
totalPages: Math.ceil(countResult[0].total / limitNum)
}
};
res.json({
success: true,
data: responseData
});
} catch (error) {
console.error('获取积分历史失败:', error);
res.status(500).json({ success: false, message: '获取积分历史失败' });
}
});
// 管理员调整用户积分
router.post('/adjust', auth, adminAuth, async (req, res) => {
const connection = await getDB().getConnection();
try {
await connection.beginTransaction();
const { userId, points, reason } = req.body;
if (!userId || points === undefined || points === null || !reason) {
await connection.rollback();
return res.status(400).json({ success: false, message: '请提供有效的用户ID、积分数量和调整原因' });
}
// 检查用户是否存在
const [users] = await connection.execute(
'SELECT id, username, points FROM users WHERE id = ?',
[userId]
);
if (users.length === 0) {
await connection.rollback();
return res.status(404).json({ success: false, message: '用户不存在' });
}
const currentPoints = users[0].points;
const newPoints = currentPoints + points;
// 检查积分是否会变为负数
if (newPoints < 0) {
await connection.rollback();
return res.status(400).json({ success: false, message: '用户积分不足,无法扣除' });
}
// 更新用户积分
await connection.execute(
'UPDATE users SET points = ? WHERE id = ?',
[newPoints, userId]
);
// 记录积分历史
await connection.execute(
`INSERT INTO points_history (user_id, amount, type, description, created_at)
VALUES (?, ?, 'admin_adjust', ?, NOW())`,
[userId, points, reason]
);
await connection.commit();
res.json({
success: true,
message: '积分调整成功',
data: {
userId: userId,
pointsChanged: points,
newBalance: newPoints
}
});
} catch (error) {
await connection.rollback();
console.error('积分调整失败:', error);
res.status(500).json({ success: false, message: '积分调整失败' });
} finally {
connection.release();
}
});
// 管理员给用户充值积分
router.post('/recharge', auth, adminAuth, async (req, res) => {
const connection = await getDB().getConnection();
try {
await connection.beginTransaction();
const { user_id, points, description = '管理员充值' } = req.body;
if (!user_id || !points || points <= 0) {
await connection.rollback();
return res.status(400).json({ success: false, message: '请提供有效的用户ID和积分数量' });
}
// 检查用户是否存在
const [users] = await connection.execute(
'SELECT id, username FROM users WHERE id = ?',
[user_id]
);
if (users.length === 0) {
await connection.rollback();
return res.status(404).json({ success: false, message: '用户不存在' });
}
// 增加用户积分
await connection.execute(
'UPDATE users SET points = points + ? WHERE id = ?',
[points, user_id]
);
// 记录积分历史
await connection.execute(
`INSERT INTO points_history (user_id, amount, type, description, created_at)
VALUES (?, ?, 'earn', ?, NOW())`,
[user_id, points, description]
);
await connection.commit();
res.json({
success: true,
message: '积分充值成功',
data: {
userId: user_id,
pointsAdded: points
}
});
} catch (error) {
await connection.rollback();
console.error('积分充值失败:', error);
res.status(500).json({ success: false, message: '积分充值失败' });
} finally {
connection.release();
}
});
// 获取积分排行榜
router.get('/leaderboard', auth, async (req, res) => {
try {
const { limit = 10 } = req.query;
const [users] = await getDB().execute(
`SELECT id, username, points
FROM users
WHERE points > 0
ORDER BY points DESC
LIMIT ?`,
[parseInt(limit)]
);
res.json({
success: true,
data: {
leaderboard: users.map((user, index) => ({
rank: index + 1,
userId: user.id,
username: user.username,
points: user.points
}))
}
});
} catch (error) {
console.error('获取积分排行榜失败:', error);
res.status(500).json({ success: false, message: '获取积分排行榜失败' });
}
});
// 获取积分统计信息(管理员权限)
router.get('/stats', auth, adminAuth, async (req, res) => {
try {
// 总积分发放量
const [totalEarned] = await getDB().execute(
'SELECT SUM(amount) as total FROM points_history WHERE type = "earn"'
);
// 总积分消费量
const [totalConsumed] = await getDB().execute(
'SELECT SUM(ABS(amount)) as total FROM points_history WHERE type = "spend"'
);
// 本月积分发放
const [monthEarned] = await getDB().execute(
'SELECT SUM(amount) as total FROM points_history WHERE type = "earn" AND YEAR(created_at) = YEAR(NOW()) AND MONTH(created_at) = MONTH(NOW())'
);
// 上月积分发放(用于计算增长率)
const [lastMonthEarned] = await getDB().execute(
'SELECT SUM(amount) as total FROM points_history WHERE type = "earn" AND YEAR(created_at) = YEAR(DATE_SUB(NOW(), INTERVAL 1 MONTH)) AND MONTH(created_at) = MONTH(DATE_SUB(NOW(), INTERVAL 1 MONTH))'
);
// 计算月增长率
const lastMonthTotal = lastMonthEarned[0].total || 0;
const currentMonthTotal = monthEarned[0].total || 0;
let monthGrowthRate = 0;
if (lastMonthTotal > 0) {
monthGrowthRate = ((currentMonthTotal - lastMonthTotal) / lastMonthTotal * 100).toFixed(1);
}
// 活跃用户数(有积分记录的用户)
const [activeUsers] = await getDB().execute(
'SELECT COUNT(DISTINCT user_id) as count FROM points_history'
);
res.json({
success: true,
data: {
stats: {
totalPoints: totalEarned[0].total || 0,
totalEarned: totalEarned[0].total || 0,
totalSpent: totalConsumed[0].total || 0,
activeUsers: activeUsers[0].count
}
}
});
} catch (error) {
console.error('获取积分统计失败:', error);
res.status(500).json({ success: false, message: '获取积分统计失败' });
}
});
module.exports = router;