Files
accountbook/server/routes/stats.js
T

124 lines
3.0 KiB
JavaScript
Raw Normal View History

const express = require('express');
const db = require('../config/database');
const { authenticate } = require('../middleware/auth');
const { asyncHandler, AppError } = require('../middleware/errorHandler');
const { isValidMonth, VALID_STATS_PERIODS, VALID_STATS_TYPES } = require('../utils/validators');
const router = express.Router();
// 获取月度统计
router.get('/', authenticate, asyncHandler(async (req, res) => {
const { month } = req.query;
if (!month) {
throw new AppError('请指定月份', 400, 'MISSING_MONTH');
}
const stmt = db.prepare(`
SELECT
SUM(CASE WHEN type = 'income' THEN amount ELSE 0 END) as totalIncome,
SUM(CASE WHEN type = 'expense' THEN amount ELSE 0 END) as totalExpense
FROM records
WHERE user_id = ? AND date LIKE ?
`);
const result = stmt.get(req.userId, `${month}%`);
res.json({
income: result.totalIncome || 0,
expense: result.totalExpense || 0,
balance: (result.totalIncome || 0) - (result.totalExpense || 0),
});
}));
// 收支趋势统计
router.get('/trend', authenticate, asyncHandler(async (req, res) => {
const { period = 'month', month } = req.query;
if (!VALID_STATS_PERIODS.includes(period)) {
throw new AppError('统计周期错误', 400, 'INVALID_PERIOD');
}
if (month && !isValidMonth(month)) {
throw new AppError('月份格式错误', 400, 'INVALID_MONTH');
}
let dateGroup;
if (period === 'year') {
dateGroup = "strftime('%Y', date)";
} else if (period === 'week') {
dateGroup = "strftime('%Y-%W', date)";
} else {
dateGroup = "strftime('%Y-%m', date)";
}
let query = `
SELECT
${dateGroup} as period,
SUM(CASE WHEN type = 'income' THEN amount ELSE 0 END) as income,
SUM(CASE WHEN type = 'expense' THEN amount ELSE 0 END) as expense
FROM records
WHERE user_id = ?
`;
const params = [req.userId];
if (month) {
query += ' AND date LIKE ?';
params.push(`${month}%`);
}
query += `
GROUP BY ${dateGroup}
ORDER BY period DESC
LIMIT 12
`;
const stmt = db.prepare(query);
const result = stmt.all(...params);
res.json(result.reverse());
}));
// 分类统计
router.get('/category', authenticate, asyncHandler(async (req, res) => {
const { month, type = 'all' } = req.query;
if (!VALID_STATS_TYPES.includes(type)) {
throw new AppError('统计类型错误', 400, 'INVALID_TYPE');
}
if (month && !isValidMonth(month)) {
throw new AppError('月份格式错误', 400, 'INVALID_MONTH');
}
let query = `
SELECT
category,
SUM(amount) as total,
type
FROM records
WHERE user_id = ?
`;
const params = [req.userId];
if (month) {
query += ' AND date LIKE ?';
params.push(`${month}%`);
}
if (type !== 'all') {
query += ' AND type = ?';
params.push(type);
}
query += `
GROUP BY category, type
ORDER BY total DESC
`;
const stmt = db.prepare(query);
const result = stmt.all(...params);
res.json(result);
}));
module.exports = router;