refactor: 系统优化 - 错误处理、输入验证、无限滚动

主要改进:
- 新增配置管理 (server/config.js)
- 新增日志工具 (server/utils/logger.js)
- 添加全局错误处理中间件,统一错误响应格式
- 添加输入验证和 AppError 错误类
- 重构 db.js 迁移逻辑,代码更清晰
- 前端列表改为无限滚动加载,每页 20 条
- 封装 AppState 状态管理模块

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
lizhilun
2026-03-26 10:39:58 +08:00
co-authored by Claude Opus 4.6
parent 19e5a48f07
commit d551841035
12 changed files with 789 additions and 350 deletions
+63 -19
View File
@@ -1,18 +1,36 @@
const express = require('express');
const db = require('../db');
const { getMonthRange } = require('../utils/helpers');
const config = require('../config');
const logger = require('../utils/logger');
const { getMonthRange, AppError, validateRequired, validateNumber, validateInList } = require('../utils/helpers');
const router = express.Router();
// 新增记录
router.post('/', (req, res) => {
const { type, category, amount, quantity, unit_price, rebate, boss, partner, source, destination, note, created_at } = req.body;
const stmt = db.prepare(`
INSERT INTO records (user_id, type, category, amount, quantity, unit_price, rebate, boss, partner, source, destination, note, created_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`);
const result = stmt.run(req.user.id, type, category, amount, quantity || null, unit_price || null, rebate || null, boss || null, partner || null, source || null, destination || null, note || null, created_at || new Date().toISOString());
res.json({ id: result.lastInsertRowid });
router.post('/', (req, res, next) => {
try {
const { type, category, amount, quantity, unit_price, rebate, boss, partner, source, destination, note, created_at } = req.body;
// 输入验证
validateRequired(req.body, ['type', 'category', 'amount']);
validateInList(type, 'type', ['income', 'expense']);
const allCategories = [...config.categories.income, ...config.categories.expense];
validateInList(category, 'category', allCategories);
const validatedAmount = validateNumber(amount, '金额', 0);
const stmt = db.prepare(`
INSERT INTO records (user_id, type, category, amount, quantity, unit_price, rebate, boss, partner, source, destination, note, created_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`);
const result = stmt.run(req.user.id, type, category, validatedAmount, quantity || null, unit_price || null, rebate || null, boss || null, partner || null, source || null, destination || null, note || null, created_at || new Date().toISOString());
logger.info(`用户 ${req.user.username} 新增记录: ${category} ${validatedAmount}`);
res.json({ id: result.lastInsertRowid });
} catch (err) {
next(err);
}
});
// 通用分页查询函数
@@ -117,19 +135,45 @@ router.get('/', (req, res) => {
});
// 更新记录
router.put('/:id', (req, res) => {
const { quantity, unit_price, rebate, amount, boss, partner, source, destination, note, created_at } = req.body;
db.prepare(`
UPDATE records SET quantity = ?, unit_price = ?, rebate = ?, amount = ?, boss = ?, partner = ?, source = ?, destination = ?, note = ?, created_at = ?
WHERE id = ? AND user_id = ?
`).run(quantity || null, unit_price || null, rebate || null, amount, boss || null, partner || null, source || null, destination || null, note || null, created_at || null, req.params.id, req.user.id);
res.json({ success: true });
router.put('/:id', (req, res, next) => {
try {
const { quantity, unit_price, rebate, amount, boss, partner, source, destination, note, created_at } = req.body;
const id = Number(req.params.id);
if (!id || id <= 0) {
throw new AppError('无效的记录ID', 400);
}
const validatedAmount = validateNumber(amount, '金额', 0);
db.prepare(`
UPDATE records SET quantity = ?, unit_price = ?, rebate = ?, amount = ?, boss = ?, partner = ?, source = ?, destination = ?, note = ?, created_at = ?
WHERE id = ? AND user_id = ?
`).run(quantity || null, unit_price || null, rebate || null, validatedAmount, boss || null, partner || null, source || null, destination || null, note || null, created_at || null, id, req.user.id);
logger.debug(`用户 ${req.user.username} 更新记录: ${id}`);
res.json({ success: true });
} catch (err) {
next(err);
}
});
// 删除记录
router.delete('/:id', (req, res) => {
db.prepare('DELETE FROM records WHERE id = ? AND user_id = ?').run(req.params.id, req.user.id);
res.json({ success: true });
router.delete('/:id', (req, res, next) => {
try {
const id = Number(req.params.id);
if (!id || id <= 0) {
throw new AppError('无效的记录ID', 400);
}
db.prepare('DELETE FROM records WHERE id = ? AND user_id = ?').run(id, req.user.id);
logger.info(`用户 ${req.user.username} 删除记录: ${id}`);
res.json({ success: true });
} catch (err) {
next(err);
}
});
module.exports = router;