refactor: 重构代码减少重复并添加分页

后端 (records.js):
- 提取通用分页查询函数 queryPagedRecords
- 5个列表接口 (orders/other-income/red-envelope/milk-tea/dispatches) 复用同一函数

后端 (stats.js):
- 为 monthly-records, boss-records, partner-records, daily-detail 添加分页支持
- 新增 page, limit, totalCount 返回字段

前端 (order-list.js):
- 提取通用列表配置 listConfig
- 统一渲染函数 renderOrderItem/renderOtherIncomeItem 等
- 大幅减少代码重复

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
lizhilun
2026-03-18 09:53:48 +08:00
co-authored by Claude Opus 4.6
parent a03e92d437
commit 2ebac98f07
3 changed files with 196 additions and 338 deletions
+52 -61
View File
@@ -15,89 +15,80 @@ router.post('/', (req, res) => {
res.json({ id: result.lastInsertRowid });
});
// 接单列表
router.get('/orders', (req, res) => {
const { page = 1, limit = 20 } = req.query;
// 通用分页查询函数
function queryPagedRecords(userId, year, month, options) {
const { page = 1, limit = 20 } = options;
const offset = (Number(page) - 1) * Number(limit);
const { startDate, endDate } = getMonthRange(req.query.year, req.query.month);
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 user_id = ? AND category = '接单' AND DATE(created_at, 'localtime') >= ? AND DATE(created_at, 'localtime') < ?`
).get(req.user.id, startDate, endDate).count;
`SELECT COUNT(*) as count FROM records WHERE ${whereClause}`
).get(...params).count;
const records = db.prepare(
`SELECT * FROM records WHERE user_id = ? AND category = '接单' AND DATE(created_at, 'localtime') >= ? AND DATE(created_at, 'localtime') < ? ORDER BY created_at DESC LIMIT ? OFFSET ?`
).all(req.user.id, startDate, endDate, Number(limit), offset);
`SELECT * FROM records WHERE ${whereClause} ORDER BY created_at DESC LIMIT ? OFFSET ?`
).all(...params, Number(limit), offset);
res.json({ records, total, page: Number(page), limit: Number(limit) });
return { records, total, page: Number(page), limit: Number(limit) };
}
// 接单列表
router.get('/orders', (req, res) => {
const result = queryPagedRecords(req.user.id, req.query.year, req.query.month, {
category: '接单'
});
res.json(result);
});
// 红包及其他收入列表
router.get('/other-income', (req, res) => {
const { page = 1, limit = 20 } = req.query;
const offset = (Number(page) - 1) * Number(limit);
const { startDate, endDate } = getMonthRange(req.query.year, req.query.month);
const total = db.prepare(
`SELECT COUNT(*) as count FROM records WHERE user_id = ? AND type = 'income' AND category != '接单' AND category != '派单' AND DATE(created_at, 'localtime') >= ? AND DATE(created_at, 'localtime') < ?`
).get(req.user.id, startDate, endDate).count;
const records = db.prepare(
`SELECT * FROM records WHERE user_id = ? AND type = 'income' AND category != '接单' AND category != '派单' AND DATE(created_at, 'localtime') >= ? AND DATE(created_at, 'localtime') < ? ORDER BY created_at DESC LIMIT ? OFFSET ?`
).all(req.user.id, startDate, endDate, Number(limit), offset);
res.json({ records, total, page: Number(page), limit: Number(limit) });
const result = queryPagedRecords(req.user.id, req.query.year, req.query.month, {
type: 'income',
excludeCategories: ['接单', '派单']
});
res.json(result);
});
// 红包收入列表
router.get('/red-envelope', (req, res) => {
const { page = 1, limit = 20 } = req.query;
const offset = (Number(page) - 1) * Number(limit);
const { startDate, endDate } = getMonthRange(req.query.year, req.query.month);
const total = db.prepare(
`SELECT COUNT(*) as count FROM records WHERE user_id = ? AND type = 'income' AND category = '红包收入' AND DATE(created_at, 'localtime') >= ? AND DATE(created_at, 'localtime') < ?`
).get(req.user.id, startDate, endDate).count;
const records = db.prepare(
`SELECT * FROM records WHERE user_id = ? AND type = 'income' AND category = '红包收入' AND DATE(created_at, 'localtime') >= ? AND DATE(created_at, 'localtime') < ? ORDER BY created_at DESC LIMIT ? OFFSET ?`
).all(req.user.id, startDate, endDate, Number(limit), offset);
res.json({ records, total, page: Number(page), limit: Number(limit) });
const result = queryPagedRecords(req.user.id, req.query.year, req.query.month, {
type: 'income',
category: '红包收入'
});
res.json(result);
});
// 奶茶收入列表
router.get('/milk-tea', (req, res) => {
const { page = 1, limit = 20 } = req.query;
const offset = (Number(page) - 1) * Number(limit);
const { startDate, endDate } = getMonthRange(req.query.year, req.query.month);
const total = db.prepare(
`SELECT COUNT(*) as count FROM records WHERE user_id = ? AND type = 'income' AND category = '奶茶' AND DATE(created_at, 'localtime') >= ? AND DATE(created_at, 'localtime') < ?`
).get(req.user.id, startDate, endDate).count;
const records = db.prepare(
`SELECT * FROM records WHERE user_id = ? AND type = 'income' AND category = '奶茶' AND DATE(created_at, 'localtime') >= ? AND DATE(created_at, 'localtime') < ? ORDER BY created_at DESC LIMIT ? OFFSET ?`
).all(req.user.id, startDate, endDate, Number(limit), offset);
res.json({ records, total, page: Number(page), limit: Number(limit) });
const result = queryPagedRecords(req.user.id, req.query.year, req.query.month, {
type: 'income',
category: '奶茶'
});
res.json(result);
});
// 派单列表
router.get('/dispatches', (req, res) => {
const { page = 1, limit = 20 } = req.query;
const offset = (Number(page) - 1) * Number(limit);
const { startDate, endDate } = getMonthRange(req.query.year, req.query.month);
const total = db.prepare(
`SELECT COUNT(*) as count FROM records WHERE user_id = ? AND category = '派单' AND DATE(created_at, 'localtime') >= ? AND DATE(created_at, 'localtime') < ?`
).get(req.user.id, startDate, endDate).count;
const records = db.prepare(
`SELECT * FROM records WHERE user_id = ? AND category = '派单' AND DATE(created_at, 'localtime') >= ? AND DATE(created_at, 'localtime') < ? ORDER BY created_at DESC LIMIT ? OFFSET ?`
).all(req.user.id, startDate, endDate, Number(limit), offset);
res.json({ records, total, page: Number(page), limit: Number(limit) });
const result = queryPagedRecords(req.user.id, req.query.year, req.query.month, {
category: '派单'
});
res.json(result);
});
// 获取记录列表
+47 -14
View File
@@ -35,22 +35,28 @@ router.get('/monthly', (req, res) => {
// 月收入/支出记录列表
router.get('/monthly-records', (req, res) => {
const { type } = req.query;
const { type, page = 1, limit = 20 } = req.query;
if (!type || !['income', 'expense'].includes(type)) return res.status(400).json({ error: '缺少类型参数' });
const { startDate, endDate } = getMonthRange(req.query.year, req.query.month);
const offset = (Number(page) - 1) * Number(limit);
const summary = db.prepare(`
SELECT COALESCE(SUM(amount), 0) as total
FROM records WHERE user_id = ? AND type = ? AND DATE(created_at, 'localtime') >= ? AND DATE(created_at, 'localtime') < ?
`).get(req.user.id, type, startDate, endDate);
const total = db.prepare(`
SELECT COUNT(*) as count FROM records
WHERE user_id = ? AND type = ? AND DATE(created_at, 'localtime') >= ? AND DATE(created_at, 'localtime') < ?
`).get(req.user.id, type, startDate, endDate).count;
const records = db.prepare(`
SELECT * FROM records
WHERE user_id = ? AND type = ? AND DATE(created_at, 'localtime') >= ? AND DATE(created_at, 'localtime') < ?
ORDER BY created_at DESC
`).all(req.user.id, type, startDate, endDate);
ORDER BY created_at DESC LIMIT ? OFFSET ?
`).all(req.user.id, type, startDate, endDate, Number(limit), offset);
res.json({ total: summary.total, records });
res.json({ total: summary.total, records, page: Number(page), limit: Number(limit), totalCount: total });
});
// 年度净收入按年统计
@@ -236,7 +242,9 @@ router.get('/total', (req, res) => {
// 老板交易记录
router.get('/boss-records', (req, res) => {
const boss = req.query.boss;
const { page = 1, limit = 20 } = req.query;
if (!boss) return res.status(400).json({ error: '缺少老板参数' });
const offset = (Number(page) - 1) * Number(limit);
// 我的收入:只统计 type='income' 的记录(接单、派单返点、红包收入等)
// 使用 COALESCE(boss, source) 兼容旧数据(之前的红包收入只有 source 字段)
@@ -256,21 +264,30 @@ router.get('/boss-records', (req, res) => {
const boss_total_expense = expenseSummary.dispatch_expense + expenseSummary.order_expense + expenseSummary.redEnvelope_expense;
const total = db.prepare(`
SELECT COUNT(*) as count FROM records WHERE user_id = ? AND COALESCE(boss, source) = ?
`).get(req.user.id, boss).count;
const records = db.prepare(`
SELECT * FROM records WHERE user_id = ? AND COALESCE(boss, source) = ? ORDER BY created_at DESC
`).all(req.user.id, boss);
SELECT * FROM records WHERE user_id = ? AND COALESCE(boss, source) = ? ORDER BY created_at DESC LIMIT ? OFFSET ?
`).all(req.user.id, boss, Number(limit), offset);
res.json({
my_income: myIncomeSummary.total,
boss_total_expense: boss_total_expense,
records
records,
page: Number(page),
limit: Number(limit),
totalCount: total
});
});
// 陪玩交易记录
router.get('/partner-records', (req, res) => {
const partner = req.query.partner;
const { page = 1, limit = 20 } = req.query;
if (!partner) return res.status(400).json({ error: '缺少陪玩参数' });
const offset = (Number(page) - 1) * Number(limit);
const dispatchStats = db.prepare(`
SELECT
@@ -285,20 +302,31 @@ router.get('/partner-records', (req, res) => {
FROM records WHERE user_id = ? AND type = 'income' AND category != '派单' AND category != '接单' AND source = ?
`).get(req.user.id, partner);
const total = db.prepare(`
SELECT COUNT(*) as count FROM records
WHERE user_id = ? AND (
(category = '派单' AND partner = ?) OR
(type = 'income' AND category != '派单' AND category != '接单' AND source = ?)
)
`).get(req.user.id, partner, partner).count;
const records = db.prepare(`
SELECT * FROM records
WHERE user_id = ? AND (
(category = '派单' AND partner = ?) OR
(type = 'income' AND category != '派单' AND category != '接单' AND source = ?)
) ORDER BY created_at DESC
`).all(req.user.id, partner, partner);
) ORDER BY created_at DESC LIMIT ? OFFSET ?
`).all(req.user.id, partner, partner, Number(limit), offset);
res.json({
dispatch_count: dispatchStats.dispatch_count,
spread_income: dispatchStats.spread_income,
rebate_income: dispatchStats.rebate_income,
other_income: otherIncome.total,
records
records,
page: Number(page),
limit: Number(limit),
totalCount: total
});
});
@@ -329,8 +357,9 @@ router.get('/daily-income', (req, res) => {
// 某天收入记录详情
router.get('/daily-detail', (req, res) => {
const { date } = req.query;
const { date, page = 1, limit = 20 } = req.query;
if (!date) return res.status(400).json({ error: '缺少日期参数' });
const offset = (Number(page) - 1) * Number(limit);
const nextDay = new Date(date);
nextDay.setDate(nextDay.getDate() + 1);
const endDate = formatLocalDate(nextDay);
@@ -340,12 +369,16 @@ router.get('/daily-detail', (req, res) => {
FROM records WHERE user_id = ? AND type = 'income' AND DATE(created_at, 'localtime') >= ? AND DATE(created_at, 'localtime') < ?
`).get(req.user.id, date, endDate);
const total = db.prepare(`
SELECT COUNT(*) as count FROM records WHERE user_id = ? AND type = 'income' AND DATE(created_at, 'localtime') >= ? AND DATE(created_at, 'localtime') < ?
`).get(req.user.id, date, endDate).count;
const records = db.prepare(`
SELECT * FROM records WHERE user_id = ? AND type = 'income' AND DATE(created_at, 'localtime') >= ? AND DATE(created_at, 'localtime') < ?
ORDER BY created_at DESC
`).all(req.user.id, date, endDate);
ORDER BY created_at DESC LIMIT ? OFFSET ?
`).all(req.user.id, date, endDate, Number(limit), offset);
res.json({ total_income: summary.total_income, records });
res.json({ total_income: summary.total_income, records, page: Number(page), limit: Number(limit), totalCount: total });
});
// 老板收入排行 - 首页预览