const express = require('express'); const db = require('../db'); const config = require('../config'); const logger = require('../utils/logger'); const { getMonthRange, AppError, validateRequired, validateNumber, validateInList, validatePage, validateLimit, validateIsoDate, optionalString } = require('../utils/helpers'); const router = express.Router(); // 新增记录 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 = category === '派单' ? validateNumber(amount, '金额') : validateNumber(amount, '金额', 0); const validatedQuantity = quantity === undefined || quantity === null || quantity === '' ? null : validateNumber(quantity, '数量', 0); const validatedUnitPrice = unit_price === undefined || unit_price === null || unit_price === '' ? null : validateNumber(unit_price, '单价', 0); const validatedRebate = rebate === undefined || rebate === null || rebate === '' ? null : validateNumber(rebate, '返点'); const validatedCreatedAt = validateIsoDate(created_at, '创建时间'); 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, validatedQuantity, validatedUnitPrice, validatedRebate, optionalString(boss, '老板', 100), optionalString(partner, '陪玩', 100), optionalString(source, '来源', 100), optionalString(destination, '去向', 100), optionalString(note, '备注', 500), validatedCreatedAt ); logger.info(`用户 ${req.user.username} 新增记录: ${category} ${validatedAmount}`); res.json({ id: result.lastInsertRowid }); } catch (err) { next(err); } }); // 通用分页查询函数 function queryPagedRecords(userId, year, month, options) { const page = validatePage(options.page, 1); const limit = validateLimit(options.limit, config.pagination.defaultLimit, config.pagination.maxLimit); const offset = (page - 1) * limit; const { startDate, endDate } = getMonthRange(year, month); let whereClause = `user_id = ? AND DATE(created_at, 'localtime') >= ? AND DATE(created_at, 'localtime') < ?`; const params = [userId, startDate, endDate]; if (options.category) { whereClause += ` AND category = ?`; params.push(options.category); } if (options.type) { whereClause += ` AND type = ?`; params.push(options.type); } if (options.excludeCategories && options.excludeCategories.length > 0) { whereClause += ` AND category NOT IN (${options.excludeCategories.map(() => '?').join(',')})`; params.push(...options.excludeCategories); } const total = db.prepare( `SELECT COUNT(*) as count FROM records WHERE ${whereClause}` ).get(...params).count; const records = db.prepare( `SELECT * FROM records WHERE ${whereClause} ORDER BY created_at DESC LIMIT ? OFFSET ?` ).all(...params, limit, offset); return { records, total, page, limit }; } // 接单列表 router.get('/orders', (req, res) => { const result = queryPagedRecords(req.user.id, req.query.year, req.query.month, { category: '接单', page: req.query.page, limit: req.query.limit }); res.json(result); }); // 红包及其他收入列表 router.get('/other-income', (req, res) => { const result = queryPagedRecords(req.user.id, req.query.year, req.query.month, { type: 'income', excludeCategories: ['接单', '派单'], page: req.query.page, limit: req.query.limit }); res.json(result); }); // 红包收入列表 router.get('/red-envelope', (req, res) => { const result = queryPagedRecords(req.user.id, req.query.year, req.query.month, { type: 'income', category: '红包收入', page: req.query.page, limit: req.query.limit }); res.json(result); }); // 奶茶收入列表 router.get('/milk-tea', (req, res) => { const result = queryPagedRecords(req.user.id, req.query.year, req.query.month, { type: 'income', category: '奶茶', page: req.query.page, limit: req.query.limit }); res.json(result); }); // 派单列表 router.get('/dispatches', (req, res) => { const result = queryPagedRecords(req.user.id, req.query.year, req.query.month, { category: '派单', page: req.query.page, limit: req.query.limit }); res.json(result); }); // 获取记录列表 router.get('/', (req, res) => { const { type, page = 1, limit = 20 } = req.query; const validatedPage = validatePage(page, 1); const validatedLimit = validateLimit(limit, config.pagination.defaultLimit, config.pagination.maxLimit); const offset = (validatedPage - 1) * validatedLimit; let sql = 'SELECT * FROM records WHERE user_id = ?'; const params = [req.user.id]; if (type) { sql += ' AND type = ?'; params.push(type); } sql += ' ORDER BY created_at DESC LIMIT ? OFFSET ?'; params.push(validatedLimit, offset); res.json(db.prepare(sql).all(...params)); }); // 更新记录 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 existing = db.prepare('SELECT category FROM records WHERE id = ? AND user_id = ?').get(id, req.user.id); if (!existing) { throw new AppError('记录不存在', 404); } const validatedAmount = existing.category === '派单' ? validateNumber(amount, '金额') : validateNumber(amount, '金额', 0); const validatedQuantity = quantity === undefined || quantity === null || quantity === '' ? null : validateNumber(quantity, '数量', 0); const validatedUnitPrice = unit_price === undefined || unit_price === null || unit_price === '' ? null : validateNumber(unit_price, '单价', 0); const validatedRebate = rebate === undefined || rebate === null || rebate === '' ? null : validateNumber(rebate, '返点'); const validatedCreatedAt = validateIsoDate(created_at, '创建时间'); db.prepare(` UPDATE records SET quantity = ?, unit_price = ?, rebate = ?, amount = ?, boss = ?, partner = ?, source = ?, destination = ?, note = ?, created_at = ? WHERE id = ? AND user_id = ? `).run( validatedQuantity, validatedUnitPrice, validatedRebate, validatedAmount, optionalString(boss, '老板', 100), optionalString(partner, '陪玩', 100), optionalString(source, '来源', 100), optionalString(destination, '去向', 100), optionalString(note, '备注', 500), validatedCreatedAt, id, req.user.id ); logger.debug(`用户 ${req.user.username} 更新记录: ${id}`); res.json({ success: true }); } catch (err) { next(err); } }); // 删除记录 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;