let myChart, trendChart; let isAdmin = false; $(document).ready(function() { // 设置默认日期范围(最近30天) applyQuickSelect('30days'); // 加载统计数据 loadStatistics(); }); // 快捷时间选择 function applyQuickSelect(value) { if (!value) { value = $('#quick-select').val(); } const today = new Date(); let dateFrom, dateTo; switch(value) { case 'today': dateFrom = dateTo = today; break; case 'week': dateFrom = new Date(today); dateFrom.setDate(today.getDate() - today.getDay()); dateTo = today; break; case 'month': dateFrom = new Date(today.getFullYear(), today.getMonth(), 1); dateTo = today; break; case '30days': dateFrom = new Date(today); dateFrom.setDate(today.getDate() - 30); dateTo = today; break; default: return; } $('#date-from').val(dateFrom.toISOString().split('T')[0]); $('#date-to').val(dateTo.toISOString().split('T')[0]); $('#quick-select').val(value); } // 加载统计数据 function loadStatistics() { loadOverview(); loadUserStatistics(); loadLeaderboard(); } // 加载概览数据 function loadOverview() { const dateFrom = $('#date-from').val(); const dateTo = $('#date-to').val(); $.ajax({ url: '/api/statistics/overview', method: 'GET', data: { group_id: 1, date_from: dateFrom, date_to: dateTo }, success: function(data) { isAdmin = data.is_admin; $('#today-count').text(data.today_completed); $('#month-count').text(data.month_completed); $('#pending-count').text(data.status_counts.pending || 0); $('#claimed-count').text(data.status_counts.claimed || 0); // 更新标题和统计数据 if (isAdmin) { $('#stats-title').text('全局完成统计'); $('#trend-title').text('全局完成趋势'); // 管理员使用全局数据 $('#my-total').text(data.total_completed); $('#my-pending').text(data.claimed_pending); // 渲染管理员图表 renderMyChart(data.total_completed, data.claimed_pending); } else { $('#stats-title').text('我的完成统计'); $('#trend-title').text('我的完成趋势'); } // 渲染趋势图 renderTrendChart(data.trend); }, error: handleAjaxError }); } // 加载个人统计 function loadUserStatistics() { const userStr = localStorage.getItem('current_user'); if (isAdmin) { return; } if (!userStr) { console.error('用户信息不存在'); $('#my-total').text('0'); $('#my-pending').text('0'); return; } let user; try { user = JSON.parse(userStr); } catch (e) { console.error('用户信息格式错误', e); $('#my-total').text('0'); $('#my-pending').text('0'); return; } if (!user || !user.id) { console.error('用户ID不存在'); $('#my-total').text('0'); $('#my-pending').text('0'); return; } const dateFrom = $('#date-from').val(); const dateTo = $('#date-to').val(); $.ajax({ url: `/api/statistics/user/${user.id}`, method: 'GET', data: { group_id: 1, date_from: dateFrom, date_to: dateTo }, success: function(data) { $('#my-total').text(data.total_completed); $('#my-pending').text(data.claimed_pending); // 渲染个人图表 renderMyChart(data.total_completed, data.claimed_pending); }, error: handleAjaxError }); } // 加载排行榜 function loadLeaderboard() { $.ajax({ url: '/api/statistics/leaderboard', method: 'GET', data: { group_id: 1, period: 'monthly' }, success: function(data) { renderLeaderboard(data.leaderboard); }, error: handleAjaxError }); } // 渲染个人图表 function renderMyChart(totalCompleted, claimedPending) { const ctx = document.getElementById('myChart'); if (myChart) { myChart.destroy(); } myChart = new Chart(ctx, { type: 'bar', data: { labels: ['总完成数', '待完成数'], datasets: [{ label: '任务数量', data: [totalCompleted, claimedPending], backgroundColor: [ 'rgba(75, 192, 192, 0.5)', 'rgba(255, 159, 64, 0.5)' ], borderColor: [ 'rgba(75, 192, 192, 1)', 'rgba(255, 159, 64, 1)' ], borderWidth: 1 }] }, options: { responsive: true, maintainAspectRatio: true, scales: { y: { beginAtZero: true, ticks: { stepSize: 1 } } } } }); } // 渲染趋势图 function renderTrendChart(trend) { const ctx = document.getElementById('trendChart'); if (trendChart) { trendChart.destroy(); } const labels = trend.map(t => t.date); const data = trend.map(t => t.count); trendChart = new Chart(ctx, { type: 'line', data: { labels: labels, datasets: [{ label: '完成数', data: data, fill: true, backgroundColor: 'rgba(75, 192, 192, 0.2)', borderColor: 'rgba(75, 192, 192, 1)', tension: 0.4 }] }, options: { responsive: true, maintainAspectRatio: true, scales: { y: { beginAtZero: true, ticks: { stepSize: 1 } } } } }); } // 渲染排行榜 function renderLeaderboard(leaderboard) { const tbody = $('#leaderboard'); tbody.empty(); if (leaderboard.length === 0) { tbody.append('暂无数据'); return; } const currentUser = JSON.parse(localStorage.getItem('current_user')); leaderboard.forEach(function(row) { const isCurrentUser = row.user_id === currentUser.id; const rowClass = isCurrentUser ? 'table-primary' : ''; let rankBadge = ''; if (row.rank === 1) { rankBadge = ' '; } else if (row.rank === 2) { rankBadge = ' '; } else if (row.rank === 3) { rankBadge = ' '; } tbody.append(` ${rankBadge}${row.rank} ${row.username}${isCurrentUser ? ' ' : ''} ${row.completed_count} `); }); } // 导出数据 function exportData() { const dateFrom = $('#date-from').val(); const dateTo = $('#date-to').val(); const token = localStorage.getItem('access_token'); let url = '/api/statistics/export?group_id=1'; if (dateFrom) url += `&date_from=${dateFrom}`; if (dateTo) url += `&date_to=${dateTo}`; // 创建隐藏的下载链接 const link = document.createElement('a'); link.href = url; link.download = `statistics_${new Date().toISOString().split('T')[0]}.csv`; // 添加认证头(通过fetch实现) fetch(url, { headers: { 'Authorization': 'Bearer ' + token } }) .then(response => response.blob()) .then(blob => { const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `statistics_${new Date().toISOString().split('T')[0]}.csv`; document.body.appendChild(a); a.click(); window.URL.revokeObjectURL(url); document.body.removeChild(a); showSuccess('数据导出成功!'); }) .catch(error => { showError('导出失败:' + error.message); }); }