// Filename: public/static/js/dashboard-chart.js (V2.0 - 兼容全局授权版) // export default function initializeDashboardChart() { // ========================================================================= // // Dashboard Chart Module // // ========================================================================= // /** @type {import('chart.js').Chart | null} 专属的图表实例 */ let historicalChartInstance = null; // 使用 DOMContentLoaded 确保页面结构加载完毕后再执行 document.addEventListener('DOMContentLoaded', main); function main() { setupChartEventListeners(); fetchChartData(); // [新增] 监听来自主程序的刷新命令 window.addEventListener('refresh-chart', () => fetchChartData(document.getElementById('chartGroupFilter')?.value)); } function setupChartEventListeners() { const chartGroupFilter = document.getElementById('chartGroupFilter'); if (chartGroupFilter) { chartGroupFilter.addEventListener('change', (e) => fetchChartData(e.target.value)); } } function handleFilterChange(groupId) { fetchChartData(groupId); } async function fetchChartData(groupId = '') { const url = groupId ? `/admin/dashboard/chart?group_id=${groupId}` : '/admin/dashboard/chart'; try { const response = await apiFetch(url, { noCache: true }); // 图表数据总是获取最新的 if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`); const chartData = await response.json(); renderHistoricalChart(chartData); } catch (error) { if (error.message !== 'Unauthorized') { console.error('Failed to fetch chart data:', error); renderHistoricalChart(null); } } } function renderHistoricalChart(chartData) { const canvas = document.getElementById('historicalChart'); if (!canvas) return; // [关键] 我们不再需要 setTimeout 检查! // 因为HTML的加载顺序保证了,当这个脚本执行时,`Chart` 对象必然存在。 const ctx = canvas.getContext('2d'); if (historicalChartInstance) { historicalChartInstance.destroy(); } if (!chartData || !chartData.labels || chartData.labels.length === 0) { ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.font = "16px Inter, sans-serif"; ctx.fillStyle = "#9ca3af"; ctx.textAlign = "center"; ctx.fillText("暂无图表数据", canvas.width / 2, canvas.height / 2); return; } // 创建新图表 historicalChartInstance = new Chart(ctx, { type: 'line', data: { labels: chartData.labels, datasets: chartData.datasets.map(dataset => ({ label: dataset.label, data: dataset.data, borderColor: dataset.color, backgroundColor: `${dataset.color}33`, pointBackgroundColor: dataset.color, pointBorderColor: '#fff', pointHoverBackgroundColor: '#fff', pointHoverBorderColor: dataset.color, fill: true, tension: 0.4 })) }, options: { responsive: true, maintainAspectRatio: false, scales: { y: { beginAtZero: true, grid: { color: 'rgba(0, 0, 0, 0.05)' } }, x: { grid: { display: false } } }, plugins: { legend: { position: 'top', align: 'end', labels: { usePointStyle: true, boxWidth: 8, padding: 20 } } }, interaction: { intersect: false, mode: 'index' } } }); }