初次提交
This commit is contained in:
348
routes/points.js
Normal file
348
routes/points.js
Normal file
@@ -0,0 +1,348 @@
|
||||
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;
|
||||
Reference in New Issue
Block a user