92 lines
3.5 KiB
JavaScript
92 lines
3.5 KiB
JavaScript
// 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' }
|
||
}
|
||
});
|
||
}
|