const API = ''; let token = localStorage.getItem('token'); let username = localStorage.getItem('username'); let currentType = 'income'; let currentCategory = '接单'; let currentYear = new Date().getFullYear(); let currentMonth = new Date().getMonth() + 1; let currentNav = 'stats'; function headers() { return { 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + token }; } function formatLocalTime(isoStr) { if (!isoStr) return ''; const d = new Date(isoStr); const h = String(d.getHours()).padStart(2, '0'); const m = String(d.getMinutes()).padStart(2, '0'); return h + ':' + m; } function formatLocalDate(input) { if (!input) return '未知日期'; const d = input instanceof Date ? input : new Date(input); const y = d.getFullYear(); const m = String(d.getMonth() + 1).padStart(2, '0'); const day = String(d.getDate()).padStart(2, '0'); return y + '-' + m + '-' + day; } async function loadTotalStats() { try { const res = await fetch(API + '/api/stats/total', { headers: headers() }); if (!res.ok) return; const s = await res.json(); document.getElementById('totalTakeCount').textContent = s.take_count; document.getElementById('totalDispatchCount').textContent = s.dispatch_count; document.getElementById('totalNetIncome').textContent = '' + s.net_income.toFixed(2); } catch (e) { console.error(e); } } function renderHorizontalChart(containerId, rows, clickHandler, fromPage) { const container = document.getElementById(containerId); if (rows.length === 0) { container.innerHTML = '
暂无数据
'; return; } const max = Math.max(...rows.map(r => r.count), 1); container.innerHTML = rows.map((r, i) => { const pct = Math.max((r.count / max) * 100, 2); const onclick = clickHandler ? ` onclick="${clickHandler}('${r.name.replace(/'/g, "\\'")}', '${fromPage}')"` : ''; return `
${i + 1}
${r.name}
${r.count}单
`; }).join(''); } async function openTakeRanking() { showPage('takeRankingPage'); try { const res = await fetch(API + '/api/stats/take-ranking', { headers: headers() }); if (!res.ok) return; const data = await res.json(); const rows = data.rows || []; // 显示统计卡片 const summaryContainer = document.getElementById('takeRankingSummary'); summaryContainer.innerHTML = `
接单总数
${data.total_take_count || 0}
接单总收入
${(data.total_take_income || 0).toFixed(2)}
红包收入
${(data.total_redEnvelope_income || 0).toFixed(2)}
`; renderHorizontalChart('takeRankingChart', rows, 'openBossDetail', 'takeRankingPage'); } catch (e) { console.error(e); } } async function openDispatchRanking() { showPage('dispatchRankingPage'); try { const res = await fetch(API + '/api/stats/dispatch-ranking', { headers: headers() }); if (!res.ok) return; const data = await res.json(); const rows = data.rows || []; // 计算总计 const totalDispatch = data.total_dispatch_count !== undefined ? data.total_dispatch_count : (rows.reduce((sum, r) => sum + (r.dispatch_count || 0), 0)); const totalPartnerIncome = rows.reduce((sum, r) => sum + (r.partner_income || 0), 0); const totalRebateIncome = rows.reduce((sum, r) => sum + (r.rebate_income || 0), 0); const totalMilkTeaIncome = data.total_milkTea_income || 0; // 显示4个卡片 const summaryContainer = document.getElementById('dispatchRankingSummary'); summaryContainer.innerHTML = `
派单总数
${totalDispatch}
陪玩总收入
${totalPartnerIncome.toFixed(2)}
返点总收入
${totalRebateIncome.toFixed(2)}
奶茶收入
${totalMilkTeaIncome.toFixed(2)}
`; // 显示排行列表 const max = Math.max(...rows.map(r => r.dispatch_count || 0), 1); const container = document.getElementById('dispatchRankingChart'); container.innerHTML = rows.map((r, i) => { const pct = Math.max(((r.dispatch_count || 0) / max) * 100, 2); return `
${i + 1}
${r.name}
${r.dispatch_count}单
`; }).join(''); } catch (e) { console.error(e); } } function showToast(msg) { const t = document.getElementById('toast'); t.textContent = msg; t.classList.add('show'); setTimeout(() => t.classList.remove('show'), 2000); } function showPage(pageId) { document.querySelectorAll('.page').forEach(p => p.classList.remove('active')); document.getElementById(pageId).classList.add('active'); window.scrollTo(0, 0); if (pageId === 'homePage') { updateMonthDisplay(); loadStats(); document.getElementById('profileName').textContent = username; document.getElementById('avatarText').textContent = username.charAt(0).toUpperCase(); switchNav(currentNav); } if (pageId === 'recordPage') { currentType = 'income'; currentCategory = '接单'; document.querySelectorAll('.type-btn').forEach((b, i) => b.classList.toggle('active', i === 0)); document.getElementById('incomeCats').style.display = 'grid'; document.getElementById('expenseCats').style.display = 'none'; selectCategory(document.querySelector('#incomeCats .category-item'), '接单'); } if (pageId === 'rankingPage') { const startDate = `${currentYear}-${String(currentMonth).padStart(2, '0')}-01`; const now = new Date(); const endDay = (currentYear === now.getFullYear() && currentMonth === now.getMonth() + 1) ? formatLocalDate(now) : `${currentYear}-${String(currentMonth).padStart(2, '0')}-28`; document.getElementById('rankStartDate').value = startDate; document.getElementById('rankEndDate').value = endDay; currentSort = 'total_income'; document.querySelectorAll('.sort-btn').forEach((b, i) => b.classList.toggle('active', i === 0)); loadRankingDetail(); } if (pageId === 'orderListPage') { document.getElementById('orderListTitle').textContent = `${currentYear}年${currentMonth}月接单列表`; orderPage = 1; orderHasMore = true; document.getElementById('orderList').innerHTML = ''; loadOrders(); } if (pageId === 'otherIncomeListPage') { document.getElementById('otherIncomeListTitle').textContent = `${currentYear}年${currentMonth}月红包及其他收入`; otherIncomePage = 1; otherIncomeHasMore = true; document.getElementById('otherIncomeList').innerHTML = ''; loadOtherIncome(); } if (pageId === 'dispatchListPage') { document.getElementById('dispatchListTitle').textContent = `${currentYear}年${currentMonth}月派单列表`; dispatchPage = 1; dispatchHasMore = true; document.getElementById('dispatchList').innerHTML = ''; loadDispatches(); } if (pageId === 'redEnvelopeListPage') { redEnvelopePage = 1; redEnvelopeHasMore = true; document.getElementById('redEnvelopeList').innerHTML = ''; loadRedEnvelope(); } if (pageId === 'milkTeaListPage') { milkTeaPage = 1; milkTeaHasMore = true; document.getElementById('milkTeaList').innerHTML = ''; loadMilkTea(); } } function switchNav(nav) { currentNav = nav; document.querySelectorAll('.tab-panel').forEach(p => p.classList.remove('active')); document.getElementById('navStats').classList.toggle('active', nav === 'stats'); document.getElementById('navMine').classList.toggle('active', nav === 'mine'); if (nav === 'stats') { document.getElementById('statsPanel').classList.add('active'); } else { document.getElementById('minePanel').classList.add('active'); loadTotalStats(); } } function updateMonthDisplay() { document.getElementById('monthDisplay').textContent = `${currentYear}年${currentMonth}月`; } // 头像连续点击5次显示隐藏按钮 let avatarTapCount = 0; let avatarTapTimer = null; function onAvatarTap() { avatarTapCount++; clearTimeout(avatarTapTimer); avatarTapTimer = setTimeout(() => { avatarTapCount = 0; }, 1500); if (avatarTapCount >= 5) { avatarTapCount = 0; const el = document.getElementById('secretBtns'); const visible = el.style.display !== 'none'; el.style.display = visible ? 'none' : 'block'; showToast(visible ? '已隐藏' : '已解锁'); } } // 下拉刷新 (function() { let startY = 0, pulling = false, triggered = false; const threshold = 60; function getPanel() { return document.getElementById('statsPanel'); } function getIndicator() { return document.getElementById('pullIndicator'); } document.addEventListener('touchstart', function(e) { const panel = getPanel(); if (!panel || !panel.classList.contains('active')) return; if (currentNav !== 'stats') return; if (window.scrollY > 0) return; startY = e.touches[0].clientY; pulling = true; triggered = false; }, { passive: true }); document.addEventListener('touchmove', function(e) { if (!pulling) return; const panel = getPanel(); if (!panel || !panel.classList.contains('active')) { pulling = false; return; } if (window.scrollY > 0) { pulling = false; return; } const dy = e.touches[0].clientY - startY; if (dy < 0) return; const indicator = getIndicator(); const arrow = document.getElementById('pullArrow'); const text = document.getElementById('pullText'); if (dy > 10) { indicator.classList.add('visible'); if (dy >= threshold) { arrow.classList.add('flipped'); text.textContent = '松手刷新'; triggered = true; } else { arrow.classList.remove('flipped'); text.textContent = '下拉刷新'; triggered = false; } } }, { passive: true }); document.addEventListener('touchend', function() { if (!pulling) return; pulling = false; const indicator = getIndicator(); const arrow = document.getElementById('pullArrow'); const text = document.getElementById('pullText'); if (triggered) { text.textContent = '刷新中...'; arrow.classList.remove('flipped'); indicator.classList.add('refreshing'); loadStats().then(() => { setTimeout(() => { indicator.classList.remove('visible', 'refreshing'); showToast('已刷新'); }, 500); }); } else { indicator.classList.remove('visible'); } }, { passive: true }); })(); document.addEventListener('DOMContentLoaded', function() { if (token && username) { showPage('homePage'); } renderForm(); });