117 lines
3.6 KiB
JavaScript
117 lines
3.6 KiB
JavaScript
const express = require('express');
|
|
const db = require('../config/database');
|
|
const { authenticate } = require('../middleware/auth');
|
|
const { asyncHandler, AppError } = require('../middleware/errorHandler');
|
|
const { validateRecordPayload, normalizeNote } = require('../utils/validators');
|
|
|
|
const router = express.Router();
|
|
|
|
// 获取账目列表
|
|
router.get('/', authenticate, asyncHandler(async (req, res) => {
|
|
const { month, type } = req.query;
|
|
|
|
let query = 'SELECT * FROM records WHERE user_id = ?';
|
|
const params = [req.userId];
|
|
|
|
if (month) {
|
|
query += ' AND date LIKE ?';
|
|
params.push(`${month}%`);
|
|
}
|
|
|
|
if (type && type !== 'all') {
|
|
query += ' AND type = ?';
|
|
params.push(type);
|
|
}
|
|
|
|
query += ' ORDER BY date DESC, id DESC';
|
|
|
|
const stmt = db.prepare(query);
|
|
const records = stmt.all(...params);
|
|
|
|
res.json(records);
|
|
}));
|
|
|
|
// 新增账目
|
|
router.post('/', authenticate, asyncHandler(async (req, res) => {
|
|
const { type, amount, category, date, note } = req.body;
|
|
|
|
const validationError = validateRecordPayload(req.body);
|
|
if (validationError) {
|
|
throw new AppError(validationError, 400, 'VALIDATION_ERROR');
|
|
}
|
|
|
|
const stmt = db.prepare(`
|
|
INSERT INTO records (user_id, type, amount, category, date, note)
|
|
VALUES (?, ?, ?, ?, ?, ?)
|
|
`);
|
|
|
|
const result = stmt.run(req.userId, type, amount, category.trim(), date, normalizeNote(note));
|
|
console.log(`Record created: user=${req.userId}, id=${result.lastInsertRowid}`);
|
|
|
|
res.json({ id: result.lastInsertRowid, message: '添加成功' });
|
|
}));
|
|
|
|
// 更新账目
|
|
router.put('/:id', authenticate, asyncHandler(async (req, res) => {
|
|
const { id } = req.params;
|
|
const { type, amount, category, date, note } = req.body;
|
|
|
|
const checkStmt = db.prepare('SELECT * FROM records WHERE id = ? AND user_id = ?');
|
|
const record = checkStmt.get(id, req.userId);
|
|
|
|
if (!record) {
|
|
throw new AppError('记录不存在', 404, 'NOT_FOUND');
|
|
}
|
|
|
|
const validationError = validateRecordPayload(req.body);
|
|
if (validationError) {
|
|
throw new AppError(validationError, 400, 'VALIDATION_ERROR');
|
|
}
|
|
|
|
const stmt = db.prepare(`
|
|
UPDATE records SET type = ?, amount = ?, category = ?, date = ?, note = ?
|
|
WHERE id = ? AND user_id = ?
|
|
`);
|
|
|
|
stmt.run(type, amount, category.trim(), date, normalizeNote(note), id, req.userId);
|
|
console.log(`Record updated: user=${req.userId}, id=${id}`);
|
|
|
|
res.json({ message: '更新成功' });
|
|
}));
|
|
|
|
// 删除账目
|
|
router.delete('/:id', authenticate, asyncHandler(async (req, res) => {
|
|
const { id } = req.params;
|
|
|
|
const checkStmt = db.prepare('SELECT * FROM records WHERE id = ? AND user_id = ?');
|
|
const record = checkStmt.get(id, req.userId);
|
|
|
|
if (!record) {
|
|
throw new AppError('记录不存在', 404, 'NOT_FOUND');
|
|
}
|
|
|
|
const stmt = db.prepare('DELETE FROM records WHERE id = ? AND user_id = ?');
|
|
stmt.run(id, req.userId);
|
|
console.log(`Record deleted: user=${req.userId}, id=${id}`);
|
|
|
|
res.json({ message: '删除成功' });
|
|
}));
|
|
|
|
// 批量删除指定分类的记录
|
|
router.delete('/by-category/:category', authenticate, asyncHandler(async (req, res) => {
|
|
const { category } = req.params;
|
|
|
|
if (!category || typeof category !== 'string' || !category.trim()) {
|
|
throw new AppError('分类不能为空', 400, 'VALIDATION_ERROR');
|
|
}
|
|
|
|
const stmt = db.prepare('DELETE FROM records WHERE category = ? AND user_id = ?');
|
|
const result = stmt.run(category.trim(), req.userId);
|
|
|
|
console.log(`Records deleted by category: user=${req.userId}, category=${category}, count=${result.changes}`);
|
|
|
|
res.json({ message: `已删除 ${result.changes} 条记录` });
|
|
}));
|
|
|
|
module.exports = router;
|