e-scooter-rental-system/server/routes/finance.js

150 lines
5.1 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const express = require('express');
const router = express.Router();
const Payment = require('../models/Payment');
const { authMiddleware, requireRole } = require('../middleware/auth');
// 获取收支明细(仅 admin
router.get('/', authMiddleware, requireRole('admin'), async (req, res) => {
try {
const { type, startDate, endDate, party } = req.query;
const filter = {};
if (type) filter.type = type;
if (party) filter.party = new RegExp(party, 'i');
if (startDate || endDate) {
filter.createdAt = {};
if (startDate) filter.createdAt.$gte = new Date(startDate);
if (endDate) filter.createdAt.$lte = new Date(endDate);
}
const payments = await Payment.find(filter).sort('-createdAt').limit(100);
let totalIncome = 0;
let totalExpense = 0;
const incomeMap = {};
const expenseMap = {};
const allPayments = await Payment.find(filter);
for (const p of allPayments) {
if (['income', '收入', '租金收入', '押金退还', '租金'].includes(p.type)) {
totalIncome += p.amount;
incomeMap[p.category || '其他'] = (incomeMap[p.category || '其他'] || 0) + p.amount;
} else {
totalExpense += p.amount;
expenseMap[p.category || '其他'] = (expenseMap[p.category || '其他'] || 0) + p.amount;
}
}
res.json({
success: true,
data: {
list: payments,
summary: {
totalIncome,
totalExpense,
balance: totalIncome - totalExpense
},
incomeByCategory: incomeMap,
expenseByCategory: expenseMap
}
});
} catch (error) {
res.status(500).json({ success: false, message: "服务器内部错误" });
}
});
// 创建收支记录(仅 admin
router.post('/', authMiddleware, requireRole('admin'), async (req, res) => {
try {
const payment = new Payment(req.body);
await payment.save();
res.json({ success: true, data: payment });
} catch (error) {
res.status(400).json({ success: false, message: "服务器内部错误" });
}
});
// 更新收支记录(仅 admin
router.put('/:id', authMiddleware, requireRole('admin'), async (req, res) => {
try {
const payment = await Payment.findByIdAndUpdate(req.params.id, req.body, { new: true });
res.json({ success: true, data: payment });
} catch (error) {
res.status(400).json({ success: false, message: "服务器内部错误" });
}
});
// 删除收支记录(仅 admin
router.delete('/:id', authMiddleware, requireRole('admin'), async (req, res) => {
try {
await Payment.findByIdAndDelete(req.params.id);
res.json({ success: true });
} catch (error) {
res.status(400).json({ success: false, message: "服务器内部错误" });
}
});
// 清空所有收支记录(仅 admin
router.post('/delete-all', authMiddleware, requireRole('admin'), async (req, res) => {
try {
await Payment.deleteMany({});
res.json({ success: true, message: 'All payments deleted' });
} catch (error) {
res.status(400).json({ success: false, message: "服务器内部错误" });
}
});
// 收支统计(仅 admin
router.get('/stats', authMiddleware, requireRole('admin'), async (req, res) => {
try {
const { period = 'month' } = req.query;
let startDate;
const now = new Date();
switch (period) {
case 'week': startDate = new Date(now - 7 * 24 * 60 * 60 * 1000); break;
case 'month': startDate = new Date(now.getFullYear(), now.getMonth(), 1); break;
case 'quarter': startDate = new Date(now.getFullYear(), Math.floor(now.getMonth() / 3) * 3, 1); break;
case 'year': startDate = new Date(now.getFullYear(), 0, 1); break;
default: startDate = new Date(now.getFullYear(), now.getMonth(), 1);
}
const incomeAgg = await Payment.aggregate([
{ $match: { type: '收入', createdAt: { $gte: startDate } } },
{ $group: { _id: null, total: { $sum: '$amount' } } }
]);
const expenseAgg = await Payment.aggregate([
{ $match: { type: '支出', createdAt: { $gte: startDate } } },
{ $group: { _id: null, total: { $sum: '$amount' } } }
]);
const incomeByCategory = await Payment.aggregate([
{ $match: { type: '收入', createdAt: { $gte: startDate } } },
{ $group: { _id: '$category', total: { $sum: '$amount' } } }
]);
const expenseByCategory = await Payment.aggregate([
{ $match: { type: '支出', createdAt: { $gte: startDate } } },
{ $group: { _id: '$category', total: { $sum: '$amount' } } }
]);
const totalIncome = incomeAgg[0]?.total || 0;
const totalExpense = expenseAgg[0]?.total || 0;
res.json({
success: true,
data: {
income: totalIncome,
expense: totalExpense,
balance: totalIncome - totalExpense,
incomeByCategory: incomeByCategory.reduce((acc, item) => {
acc[item._id || '其他'] = item.total; return acc;
}, {}),
expenseByCategory: expenseByCategory.reduce((acc, item) => {
acc[item._id || '其他'] = item.total; return acc;
}, {})
}
});
} catch (error) {
res.status(500).json({ success: false, message: "服务器内部错误" });
}
});
module.exports = router;