async function loadStats() { try { // 并行加载所有数据 const [monthlyRes, bossRankRes, partnerRankRes, weeklyRes] = await Promise.all([ fetch(API + '/api/stats/monthly?year=' + currentYear + '&month=' + currentMonth, { headers: headers() }), fetch(API + '/api/stats/boss-ranking/preview?year=' + currentYear + '&month=' + currentMonth, { headers: headers() }), fetch(API + '/api/stats/partner-ranking/preview?year=' + currentYear + '&month=' + currentMonth, { headers: headers() }), fetch(API + '/api/stats/daily-income', { headers: headers() }) ]); if (monthlyRes.ok) { const s = await monthlyRes.json(); document.getElementById('takeCount').textContent = s.take_order_count; document.getElementById('dispatchCount').textContent = s.dispatch_order_count; document.getElementById('takeIncome').textContent = '' + s.take_order_income.toFixed(2); document.getElementById('dispatchIncome').textContent = '' + s.dispatch_order_income.toFixed(2); document.getElementById('redEnvelopeCount').textContent = s.redEnvelope_count || 0; document.getElementById('redEnvelopeIncome').textContent = '' + (s.redEnvelope_income || 0).toFixed(2); document.getElementById('milkTeaCount').textContent = s.milkTea_count || 0; document.getElementById('milkTeaIncome').textContent = '' + (s.milkTea_income || 0).toFixed(2); document.getElementById('totalIncome').textContent = '' + s.total_income.toFixed(2); document.getElementById('totalExpense').textContent = '' + s.total_expense.toFixed(2); document.getElementById('netIncome').textContent = '' + (s.total_income - s.total_expense).toFixed(2); } if (bossRankRes.ok) { const data = await bossRankRes.json(); renderBossRankingPreview(data || []); } if (partnerRankRes.ok) { const data = await partnerRankRes.json(); renderPartnerRankingPreview(data || []); } if (weeklyRes.ok) { const days = await weeklyRes.json(); renderWeeklyChart(days); } } catch (e) { console.error(e); } } async function loadWeeklyChart() { try { const res = await fetch(API + '/api/stats/daily-income', { headers: headers() }); if (!res.ok) return; const days = await res.json(); renderWeeklyChart(days); } catch (e) { console.error(e); } } function renderWeeklyChart(days) { const container = document.getElementById('weeklyChartBars'); if (!days || days.length === 0) { container.innerHTML = '
暂无数据
'; return; } const max = Math.max(...days.map(d => d.income), 1); container.innerHTML = days.map(d => { const pct = Math.max((d.income / max) * 100, 3); const label = d.date.slice(5).replace('-', '/'); const amount = d.income > 0 ? '' + d.income.toFixed(0) : '0'; return `
${amount}
${label}
`; }).join(''); } let currentDailyDate = ''; async function openDailyDetail(date) { currentDailyDate = date; document.getElementById('dailyDetailTitle').textContent = date + ' 收入'; document.getElementById('dailyNavDate').textContent = date; document.getElementById('dailySummary').innerHTML = '
加载中...
'; document.getElementById('dailyDetailList').innerHTML = ''; if (!document.getElementById('dailyDetailPage').classList.contains('active')) { showPage('dailyDetailPage'); } try { const res = await fetch(API + '/api/stats/daily-detail?date=' + date, { headers: headers() }); if (!res.ok) return; const data = await res.json(); document.getElementById('dailySummary').innerHTML = `
${data.total_income.toFixed(2)}
当日总收入
`; const container = document.getElementById('dailyDetailList'); if (data.records.length === 0) { container.innerHTML = '
当日暂无收入记录
'; return; } container.innerHTML = data.records.map(r => { const time = formatLocalTime(r.created_at); const displayCategory = r.category === '红包收入' ? '红包' : (r.category || '-'); return `
${displayCategory}${r.boss ? ' · ' + r.boss : ''} ${(r.amount || 0).toFixed(2)}
${r.quantity ? r.quantity + '单 × ' + (r.category === '派单' ? (r.rebate || r.amount / r.quantity).toFixed(2) + '(单价' + (r.unit_price || 0).toFixed(2) + ')' : (r.unit_price || 0).toFixed(2)) : (r.source || '')} ${time}${r.partner ? ' · ' + r.partner : ''}
`; }).join(''); } catch (e) { console.error(e); } } function switchDailyDate(offset) { const d = new Date(currentDailyDate); d.setDate(d.getDate() + offset); openDailyDetail(formatLocalDate(d)); } let monthlyDetailYear, monthlyDetailMonth; function openMonthlyDetail(type) { monthlyDetailYear = currentYear; monthlyDetailMonth = currentMonth; loadMonthlyDetail(type); } function switchMonthlyDetail(type, offset) { monthlyDetailMonth += offset; if (monthlyDetailMonth > 12) { monthlyDetailMonth = 1; monthlyDetailYear++; } if (monthlyDetailMonth < 1) { monthlyDetailMonth = 12; monthlyDetailYear--; } loadMonthlyDetail(type); } function openYearlyIncome() { loadYearlyNetIncome(); } async function loadYearlyNetIncome() { document.getElementById('yearlyNetIncomeSummary').innerHTML = '
加载中...
'; document.getElementById('yearlyNetIncomeList').innerHTML = ''; if (!document.getElementById('yearlyNetIncomePage').classList.contains('active')) { showPage('yearlyNetIncomePage'); } try { const res = await fetch(API + '/api/stats/yearly-net-income', { headers: headers() }); if (!res.ok) return; const data = await res.json(); const grandNetIncome = (data.grandTotal.total_income || 0) - (data.grandTotal.total_expense || 0); const grandColor = grandNetIncome >= 0 ? '#27ae60' : '#e74c3c'; document.getElementById('yearlyNetIncomeSummary').innerHTML = `
${grandNetIncome.toFixed(2)}
累计净收入
`; const container = document.getElementById('yearlyNetIncomeList'); const monthNames = ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月']; if (data.yearlyStats.length === 0) { container.innerHTML = '
暂无数据
'; return; } container.innerHTML = data.yearlyStats.map(y => { const year = y.year; const income = y.total_income || 0; const expense = y.total_expense || 0; const net = income - expense; const netColor = net >= 0 ? '#27ae60' : '#e74c3c'; const monthlyData = data.monthlyData[year] || []; const monthlyHtml = monthlyData.map(m => { const mIncome = m.total_income || 0; const mExpense = m.total_expense || 0; const mNet = mIncome - mExpense; const mColor = mNet >= 0 ? '#27ae60' : '#e74c3c'; return `
${monthNames[parseInt(m.month) - 1]} ${mNet.toFixed(2)}
`; }).join(''); return `
${year}年 ${net.toFixed(2)}
收入: ${income.toFixed(2)} | 支出: ${expense.toFixed(2)}
${monthlyHtml}
`; }).join(''); } catch (e) { console.error(e); } } async function loadMonthlyDetail(type) { const pageId = type === 'income' ? 'monthlyIncomeDetailPage' : 'monthlyExpenseDetailPage'; const titleId = type === 'income' ? 'monthlyIncomeTitle' : 'monthlyExpenseTitle'; const navId = type === 'income' ? 'monthlyIncomeNav' : 'monthlyExpenseNav'; const summaryId = type === 'income' ? 'monthlyIncomeSummary' : 'monthlyExpenseSummary'; const listId = type === 'income' ? 'monthlyIncomeList' : 'monthlyExpenseList'; const label = type === 'income' ? '收入' : '支出'; document.getElementById(titleId).textContent = `${monthlyDetailYear}年${monthlyDetailMonth}月${label}`; document.getElementById(navId).textContent = `${monthlyDetailYear}年${monthlyDetailMonth}月`; document.getElementById(summaryId).innerHTML = '
加载中...
'; document.getElementById(listId).innerHTML = ''; if (!document.getElementById(pageId).classList.contains('active')) { showPage(pageId); } try { const res = await fetch(API + '/api/stats/monthly-records?type=' + type + '&year=' + monthlyDetailYear + '&month=' + monthlyDetailMonth, { headers: headers() }); if (!res.ok) return; const data = await res.json(); const color = type === 'income' ? '#27ae60' : '#e74c3c'; document.getElementById(summaryId).innerHTML = `
${data.total.toFixed(2)}
当月总${label}
`; const container = document.getElementById(listId); if (data.records.length === 0) { container.innerHTML = '
当月暂无' + label + '记录
'; return; } const grouped = {}; data.records.forEach(r => { const date = formatLocalDate(r.created_at); if (!grouped[date]) grouped[date] = []; grouped[date].push(r); }); let html = ''; for (const [date, records] of Object.entries(grouped)) { html += `
${date}
`; records.forEach(r => { const time = formatLocalTime(r.created_at); const displayCategory = r.category === '红包收入' ? '红包' : (r.category || '-'); html += `
${displayCategory}${r.boss ? ' · ' + r.boss : r.source ? ' · ' + r.source : r.destination ? ' · ' + r.destination : ''} ${type === 'expense' ? '-' : ''}${(r.amount || 0).toFixed(2)}
${r.quantity ? r.quantity + '单 × ' + (r.category === '派单' ? (r.rebate || r.amount / r.quantity).toFixed(2) + '(单价' + (r.unit_price || 0).toFixed(2) + ')' : (r.unit_price || 0).toFixed(2)) : (r.note || '')} ${time}${r.partner ? ' · ' + r.partner : ''}
`; }); html += '
'; } container.innerHTML = html; } catch (e) { console.error(e); } } async function loadBossRankingPreview() { try { const res = await fetch(API + '/api/stats/boss-ranking/preview?year=' + currentYear + '&month=' + currentMonth, { headers: headers() }); if (!res.ok) return; const rows = await res.json(); renderBossRankingPreview(rows); } catch (e) { console.error(e); } } function renderBossRankingPreview(rows) { const container = document.getElementById('rankingPreviewList'); if (!rows || rows.length === 0) { container.innerHTML = '
暂无数据
'; return; } const max = Math.max(...rows.map(r => r.total_income), 1); container.innerHTML = rows.map((r, i) => { const pct = Math.max((r.total_income / max) * 100, 2); return `
${i + 1}
${r.boss}
${r.total_income.toFixed(2)}
`; }).join(''); } let currentBossName = ''; let bossDetailFrom = 'homePage'; function openBossDetail(boss, from) { currentBossName = boss; bossDetailFrom = from || 'homePage'; loadBossDetail(); } function bossDetailGoBack() { showPage(bossDetailFrom); } async function loadBossDetail() { document.getElementById('bossDetailTitle').textContent = currentBossName + ' 交易记录'; document.getElementById('bossDetailSummary').innerHTML = '
加载中...
'; document.getElementById('bossDetailList').innerHTML = ''; showPage('bossDetailPage'); try { const res = await fetch(API + '/api/stats/boss-records?boss=' + encodeURIComponent(currentBossName), { headers: headers() }); if (!res.ok) return; const data = await res.json(); document.getElementById('bossDetailSummary').innerHTML = `
${data.boss_total_expense.toFixed(2)}
老板总支出
${data.my_income.toFixed(2)}
我的总收入
`; const container = document.getElementById('bossDetailList'); if (data.records.length === 0) { container.innerHTML = '
暂无交易记录
'; return; } const grouped = {}; data.records.forEach(r => { const d = new Date(r.created_at); const key = d.getFullYear() + '-' + String(d.getMonth() + 1).padStart(2, '0'); if (!grouped[key]) grouped[key] = { records: [], total: 0 }; grouped[key].records.push(r); grouped[key].total += r.amount || 0; }); let html = ''; for (const [month, group] of Object.entries(grouped)) { html += `
${month} 收入 ${group.total.toFixed(2)}
`; group.records.forEach(r => { const time = formatLocalDate(r.created_at) + ' ' + formatLocalTime(r.created_at); const displayCategory = r.category === '红包收入' ? '红包' : r.category; html += `
${displayCategory}${r.partner ? ' · ' + r.partner : ''} ${(r.amount || 0).toFixed(2)}
${r.quantity ? r.quantity + '单 × ' + (r.category === '派单' ? (r.rebate || r.amount / r.quantity).toFixed(2) + '(单价' + (r.unit_price || 0).toFixed(2) + ')' : (r.unit_price || 0).toFixed(2)) : (r.note || '')} ${time}
`; }); html += '
'; } container.innerHTML = html; } catch (e) { console.error(e); } } async function loadPartnerRankingPreview() { try { const res = await fetch(API + '/api/stats/partner-ranking/preview?year=' + currentYear + '&month=' + currentMonth, { headers: headers() }); if (!res.ok) return; const rows = await res.json(); renderPartnerRankingPreview(rows); } catch (e) { console.error(e); } } function renderPartnerRankingPreview(rows) { const container = document.getElementById('partnerRankingPreviewList'); if (!rows || rows.length === 0) { container.innerHTML = '
暂无数据
'; return; } const max = Math.max(...rows.map(r => r.dispatch_count), 1); container.innerHTML = rows.map((r, i) => { const pct = Math.max((r.dispatch_count / max) * 100, 2); return `
${i + 1}
${r.partner}
${r.dispatch_count}单
`; }).join(''); } function openPartnerRankingPage() { const now = new Date(); const y = now.getFullYear(); const m = String(now.getMonth() + 1).padStart(2, '0'); document.getElementById('partnerRankStartDate').value = y + '-' + m + '-01'; document.getElementById('partnerRankEndDate').value = y + '-' + m + '-' + String(now.getDate()).padStart(2, '0'); showPage('partnerRankingPage'); loadPartnerRankingDetail(); } async function loadPartnerRankingDetail() { const startDate = document.getElementById('partnerRankStartDate').value; const endDate = document.getElementById('partnerRankEndDate').value; let url = API + '/api/stats/partner-ranking'; const params = []; if (startDate) params.push('startDate=' + startDate); if (endDate) { const d = new Date(endDate); d.setDate(d.getDate() + 1); params.push('endDate=' + formatLocalDate(d)); } if (params.length) url += '?' + params.join('&'); console.log('partner-ranking url:', url); try { const res = await fetch(url, { headers: headers() }); console.log('partner-ranking res.ok:', res.ok); if (!res.ok) return; const data = await res.json(); console.log('partner-ranking data:', data); const rows = data.rows || []; console.log('rows:', rows); const summary = data.summary || { total_partner_income: 0, total_rebate_income: 0, total_milkTea_income: 0 }; // 计算派单总数(从列表) const totalDispatch = rows.reduce((sum, r) => sum + (r.dispatch_count || 0), 0); console.log('totalDispatch:', totalDispatch); // 更新统计卡片 document.getElementById('partnerTotalDispatchCount').textContent = totalDispatch; document.getElementById('totalPartnerIncome').textContent = (summary.total_partner_income || 0).toFixed(2); document.getElementById('totalRebateIncome').textContent = summary.total_rebate_income.toFixed(2); document.getElementById('totalMilkTeaIncome').textContent = (summary.total_milkTea_income || 0).toFixed(2); const container = document.getElementById('partnerRankingDetailList'); if (rows.length === 0) { container.innerHTML = '
暂无数据
'; return; } const max = Math.max(...rows.map(r => r.dispatch_count), 1); container.innerHTML = rows.map((r, i) => { const pct = Math.max((r.dispatch_count / max) * 100, 2); return `
${i + 1}
${r.partner}
${r.dispatch_count}单
`; }).join(''); } catch (e) { console.error(e); } } let currentPartnerName = ''; let partnerDetailFrom = 'homePage'; function openPartnerDetail(partner, from) { currentPartnerName = partner; partnerDetailFrom = from || 'homePage'; loadPartnerDetail(); } function partnerDetailGoBack() { showPage(partnerDetailFrom); } async function loadPartnerDetail() { document.getElementById('partnerDetailTitle').textContent = currentPartnerName + ' 交易记录'; document.getElementById('partnerDetailSummary').innerHTML = '
加载中...
'; document.getElementById('partnerDetailList').innerHTML = ''; showPage('partnerDetailPage'); try { const res = await fetch(API + '/api/stats/partner-records?partner=' + encodeURIComponent(currentPartnerName), { headers: headers() }); if (!res.ok) return; const data = await res.json(); document.getElementById('partnerDetailSummary').innerHTML = `
${data.dispatch_count}
总派单数
${data.spread_income.toFixed(2)}
陪玩总收入
${data.rebate_income.toFixed(2)}
总返点收入
${data.other_income.toFixed(2)}
红包及其他
`; const container = document.getElementById('partnerDetailList'); if (data.records.length === 0) { container.innerHTML = '
暂无交易记录
'; return; } const grouped = {}; data.records.forEach(r => { const d = new Date(r.created_at); const key = d.getFullYear() + '-' + String(d.getMonth() + 1).padStart(2, '0'); if (!grouped[key]) grouped[key] = { records: [], total: 0 }; grouped[key].records.push(r); grouped[key].total += r.amount || 0; }); let html = ''; for (const [month, group] of Object.entries(grouped)) { html += `
${month} 收入 ${group.total.toFixed(2)}
`; group.records.forEach(r => { const time = formatLocalDate(r.created_at) + ' ' + formatLocalTime(r.created_at); const displayCategory = r.category === '红包收入' ? '红包' : r.category; html += `
${displayCategory}${r.boss ? ' · ' + r.boss : ''} ${(r.amount || 0).toFixed(2)}
${r.quantity ? r.quantity + '单 × ' + (r.category === '派单' ? (r.rebate || r.amount / r.quantity).toFixed(2) + '(单价' + (r.unit_price || 0).toFixed(2) + ')' : (r.unit_price || 0).toFixed(2)) : (r.source || '')} ${time}
`; }); html += '
'; } container.innerHTML = html; } catch (e) { console.error(e); } }