Files
gamer/public/js/order-list.js
T
lizhilunandClaude Opus 4.6 9126348d1b fix: 修复分页和缓存相关bug
- 前端: 移除无限滚动,改为一次性加载全部数据
- 前端: monthly-records接口添加limit=1000参数
- 前端: 修复edit-modal.js中loadListData调用参数
- 后端: 修复stats.js中getCached函数Promise处理
- 后端: 修复records.js各接口正确传递limit参数
- 后端: 修复partner-records SQL参数数量问题
- 统一版本号强制浏览器刷新缓存

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-25 22:12:11 +08:00

189 lines
7.3 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// ============================================
// 通用列表管理 - 一次性加载
// ============================================
// 当前活动的列表状态
let currentListId = null;
// 通用列表配置
const listConfig = {
orderList: { endpoint: '/api/records/orders', emptyMsg: '暂无接单记录', renderItem: renderOrderItem },
otherIncomeList: { endpoint: '/api/records/other-income', emptyMsg: '暂无红包及其他收入记录', renderItem: renderOtherIncomeItem },
dispatchList: { endpoint: '/api/records/dispatches', emptyMsg: '暂无派单记录', renderItem: renderDispatchItem },
redEnvelopeList: { endpoint: '/api/records/red-envelope', emptyMsg: '暂无红包收入记录', renderItem: renderRedEnvelopeItem },
milkTeaList: { endpoint: '/api/records/milk-tea', emptyMsg: '暂无奶茶收入记录', renderItem: renderMilkTeaItem }
};
// 通用列表加载状态(按 listId 存储)
const listState = {
orderList: { loading: false, records: [] },
otherIncomeList: { loading: false, records: [] },
dispatchList: { loading: false, records: [] },
redEnvelopeList: { loading: false, records: [] },
milkTeaList: { loading: false, records: [] }
};
// 初始化列表 - 清空状态
function initList(listId) {
const state = listState[listId];
if (!state) return;
state.loading = false;
state.records = [];
const container = document.getElementById(listId);
if (container) {
container.innerHTML = '';
}
}
// 加载列表数据
async function loadListData(listId) {
const config = listConfig[listId];
const state = listState[listId];
if (!config || !state) return;
// 防止重复加载
if (state.loading) {
console.log('[loadListData] already loading, skip');
return;
}
state.loading = true;
showLoading(listId, true);
try {
console.log(`[loadListData] fetching ${listId}`);
// 一次性加载全部数据,不做分页
const res = await fetch(API + config.endpoint + '?page=1&limit=1000&year=' + currentYear + '&month=' + currentMonth, { headers: headers() });
if (!res.ok) {
console.error(`[loadListData] fetch failed: ${res.status}`);
state.loading = false;
showLoading(listId, false);
return;
}
const data = await res.json();
console.log(`[loadListData] got ${data.records?.length || 0} records`);
state.records = data.records || [];
// 渲染
renderList(listId);
console.log(`[loadListData] ${listId} done, total records=${state.records.length}`);
} catch (e) {
console.error(`[loadListData] error:`, e);
} finally {
state.loading = false;
showLoading(listId, false);
}
}
// 显示/隐藏加载指示器
function showLoading(listId, show) {
const loadingId = listId.replace('List', 'Loading');
const loadingEl = document.getElementById(loadingId);
if (loadingEl) {
loadingEl.style.display = show ? 'block' : 'none';
}
}
// 渲染列表
function renderList(listId) {
const config = listConfig[listId];
const state = listState[listId];
if (!config || !state) return;
const container = document.getElementById(listId);
if (!container) return;
if (state.records.length === 0) {
container.innerHTML = '<div class="ranking-empty">' + config.emptyMsg + '</div>';
return;
}
// 按日期分组
const grouped = {};
state.records.forEach(r => {
const date = formatLocalDate(r.created_at);
if (!grouped[date]) grouped[date] = [];
grouped[date].push(r);
});
container.innerHTML = '';
// 生成 HTML
let html = '';
for (const [date, records] of Object.entries(grouped)) {
html += '<div class="order-date-group" data-date="' + date + '"><div class="order-date-label">' + date + '</div>';
records.forEach(r => {
html += config.renderItem(r);
});
html += '</div>';
}
container.innerHTML = html;
}
// ============================================
// 列表滚动(已简化为一次性加载)
// ============================================
function setupInfiniteScroll(listId) {
// 不再需要无限滚动,一次性加载全部数据
}
// ============================================
// 兼容接口
// ============================================
async function loadOrders() { return loadListData('orderList'); }
async function loadOtherIncome() { return loadListData('otherIncomeList'); }
async function loadDispatches() { return loadListData('dispatchList'); }
async function loadRedEnvelope() { return loadListData('redEnvelopeList'); }
async function loadMilkTea() { return loadListData('milkTeaList'); }
// ============================================
// 渲染函数
// ============================================
function renderOrderItem(r) {
const time = formatLocalTime(r.created_at);
return '<div class="order-item" onclick=\'openEditModal(' + JSON.stringify(r).replace(/'/g, "&#39;") + ')\'>' +
'<div class="order-item-top"><span class="order-item-boss">' + (r.boss || '-') + '</span><span class="order-item-amount">' + (r.amount || 0).toFixed(2) + '</span></div>' +
'<div class="order-item-bottom"><span>' + (r.quantity || 0) + '单 × ' + (r.unit_price || 0).toFixed(2) + '</span><span>' + time + (r.partner ? ' · ' + r.partner : '') + '</span></div></div>';
}
function renderOtherIncomeItem(r) {
const time = formatLocalTime(r.created_at);
const displayCategory = r.category === '红包收入' ? '红包' : (r.category || '-');
return '<div class="order-item" onclick=\'openEditModal(' + JSON.stringify(r).replace(/'/g, "&#39;") + ')\'>' +
'<div class="order-item-top"><span class="order-item-boss">' + displayCategory + (r.boss ? ' · ' + r.boss : '') + '</span><span class="order-item-amount">' + (r.amount || 0).toFixed(2) + '</span></div>' +
'<div class="order-item-bottom"><span>' + (r.source || '') + '</span><span>' + time + '</span></div></div>';
}
function renderDispatchItem(r) {
const time = formatLocalTime(r.created_at);
const unitPrice = r.unit_price || (r.quantity ? r.amount / r.quantity : 0);
return '<div class="order-item" onclick=\'openEditModal(' + JSON.stringify(r).replace(/'/g, "&#39;") + ')\'>' +
'<div class="order-item-top"><span class="order-item-boss">' + (r.boss || '-') + '</span><span class="order-item-amount">' + (r.amount || 0).toFixed(2) + '</span></div>' +
'<div class="order-item-bottom"><span>' + (r.quantity || 0) + '单 × ' + (r.rebate || 0).toFixed(2) + '(单价' + unitPrice.toFixed(2) + '</span><span>' + time + (r.partner ? ' · ' + r.partner : '') + '</span></div></div>';
}
function renderRedEnvelopeItem(r) {
const time = formatLocalTime(r.created_at);
return '<div class="order-item" onclick=\'openEditModal(' + JSON.stringify(r).replace(/'/g, "&#39;") + ')\'>' +
'<div class="order-item-top"><span class="order-item-boss">红包</span><span class="order-item-amount">' + (r.amount || 0).toFixed(2) + '</span></div>' +
'<div class="order-item-bottom"><span>' + (r.source || '') + '</span><span>' + time + '</span></div></div>';
}
function renderMilkTeaItem(r) {
const time = formatLocalTime(r.created_at);
return '<div class="order-item" onclick=\'openEditModal(' + JSON.stringify(r).replace(/'/g, "&#39;") + ')\'>' +
'<div class="order-item-top"><span class="order-item-boss">奶茶</span><span class="order-item-amount">' + (r.amount || 0).toFixed(2) + '</span></div>' +
'<div class="order-item-bottom"><span>' + (r.source || '') + '</span><span>' + time + '</span></div></div>';
}