190 lines
5.9 KiB
JavaScript
190 lines
5.9 KiB
JavaScript
// HoloLake 数据统计面板 · 交互脚本 v2(含导出 + 环形图)
|
||
|
||
window.addEventListener('load', function() {
|
||
// 条形图动画
|
||
setTimeout(function() {
|
||
var bars = document.querySelectorAll('.bar-fill');
|
||
bars.forEach(function(bar) {
|
||
var percent = bar.getAttribute('data-percent');
|
||
bar.style.width = percent + '%';
|
||
});
|
||
}, 300);
|
||
|
||
// 柱状图动画
|
||
setTimeout(function() {
|
||
var trendBars = document.querySelectorAll('.trend-bar');
|
||
trendBars.forEach(function(bar) {
|
||
var height = bar.getAttribute('data-height');
|
||
var fill = bar.querySelector('.trend-fill');
|
||
fill.style.height = height + '%';
|
||
});
|
||
}, 600);
|
||
|
||
// 环形图绘制函数
|
||
function drawDonut(percentages) {
|
||
var segments = document.querySelectorAll('.donut-segment');
|
||
var total = 377; // 2 * Math.PI * 60 ≈ 377
|
||
var cumulative = 0;
|
||
segments.forEach(function(seg, i) {
|
||
var value = percentages[i] || 0;
|
||
var dashArray = (value / 100 * total) + ' ' + total;
|
||
seg.setAttribute('stroke-dasharray', dashArray);
|
||
seg.setAttribute('stroke-dashoffset', 0);
|
||
});
|
||
}
|
||
|
||
// 当前选中的时间范围
|
||
var currentRange = 'today';
|
||
|
||
// 模拟数据
|
||
var mockData = {
|
||
today: {
|
||
users: '128', chats: '1,024', personas: '6', api: '3,892',
|
||
bars: [72,15,8,3,2],
|
||
trends: [45,62,38,78,55,90,85],
|
||
donut: [72,15,8,3,2],
|
||
apiTotal: '3,892'
|
||
},
|
||
week: {
|
||
users: '128', chats: '6,847', personas: '6', api: '24,103',
|
||
bars: [68,18,9,3,2],
|
||
trends: [320,415,380,450,290,520,480],
|
||
donut: [68,18,9,3,2],
|
||
apiTotal: '24,103'
|
||
},
|
||
month: {
|
||
users: '128', chats: '28,392', personas: '6', api: '98,741',
|
||
bars: [65,20,10,3,2],
|
||
trends: [1200,1450,1100,1680,1320,1890,1750],
|
||
donut: [65,20,10,3,2],
|
||
apiTotal: '98,741'
|
||
}
|
||
};
|
||
|
||
// 更新所有图表和数字
|
||
function updateStats(range) {
|
||
currentRange = range;
|
||
var data = mockData[range];
|
||
|
||
// 更新统计卡片
|
||
var values = document.querySelectorAll('.stat-value');
|
||
values[0].textContent = data.users;
|
||
values[1].textContent = data.chats;
|
||
values[2].textContent = data.personas;
|
||
values[3].textContent = data.api;
|
||
|
||
// 更新条形图
|
||
var bars = document.querySelectorAll('.bar-fill');
|
||
bars.forEach(function(bar, i) {
|
||
bar.style.width = '0%';
|
||
setTimeout(function() {
|
||
bar.style.width = data.bars[i] + '%';
|
||
}, 100);
|
||
});
|
||
|
||
// 更新百分比文字
|
||
var barValues = document.querySelectorAll('.bar-value');
|
||
data.bars.forEach(function(v, i) {
|
||
barValues[i].textContent = v + '%';
|
||
});
|
||
|
||
// 更新柱状图
|
||
var maxTrend = Math.max.apply(null, data.trends);
|
||
var trendBars = document.querySelectorAll('.trend-bar');
|
||
trendBars.forEach(function(bar, i) {
|
||
var fill = bar.querySelector('.trend-fill');
|
||
fill.style.height = '0%';
|
||
setTimeout(function() {
|
||
fill.style.height = Math.round(data.trends[i] / maxTrend * 90) + '%';
|
||
}, 100);
|
||
});
|
||
|
||
// 更新环形图
|
||
drawDonut(data.donut);
|
||
document.querySelector('.donut-center-value').textContent = data.apiTotal;
|
||
|
||
// 更新图例百分比
|
||
var legendPercents = document.querySelectorAll('.legend-percent');
|
||
data.donut.forEach(function(v, i) {
|
||
legendPercents[i].textContent = v + '%';
|
||
});
|
||
}
|
||
|
||
// 时间选择器切换
|
||
var timeButtons = document.querySelectorAll('.time-btn');
|
||
timeButtons.forEach(function(btn) {
|
||
btn.addEventListener('click', function() {
|
||
timeButtons.forEach(function(b) { b.classList.remove('active'); });
|
||
btn.classList.add('active');
|
||
var range = btn.getAttribute('data-range');
|
||
updateStats(range);
|
||
});
|
||
});
|
||
|
||
// 初始化环形图(今日数据)
|
||
drawDonut(mockData.today.donut);
|
||
|
||
// 卡片点击高亮
|
||
var cards = document.querySelectorAll('.stat-card');
|
||
cards.forEach(function(card) {
|
||
card.addEventListener('click', function() {
|
||
cards.forEach(function(c) { c.style.borderColor = 'rgba(255,255,255,0.06)'; });
|
||
card.style.borderColor = 'rgba(79, 195, 247, 0.5)';
|
||
});
|
||
});
|
||
|
||
// CSV 导出功能
|
||
var exportBtn = document.getElementById('exportBtn');
|
||
var toast = document.getElementById('exportToast');
|
||
|
||
exportBtn.addEventListener('click', function() {
|
||
var data = mockData[currentRange];
|
||
var models = ['DeepSeek', '通义千问', 'Kimi', '豆包', 'GPT/Claude'];
|
||
var days = ['周一', '周二', '周三', '周四', '周五', '周六', '周日'];
|
||
|
||
var csv = '\uFEFF'; // BOM for Chinese support
|
||
csv += 'HoloLake 数据统计报表\n';
|
||
csv += '时间范围,' + currentRange + '\n';
|
||
csv += '导出时间,' + new Date().toLocaleString('zh-CN') + '\n\n';
|
||
|
||
csv += '【统计概览】\n';
|
||
csv += '指标,数值,变化\n';
|
||
csv += '总用户,' + data.users + ',↑12%\n';
|
||
csv += '今日对话,' + data.chats + ',↑8%\n';
|
||
csv += '活跃人格体,' + data.personas + ',—\n';
|
||
csv += 'API调用,' + data.api + ',↓3%\n\n';
|
||
|
||
csv += '【模型调用分布】\n';
|
||
csv += '模型,占比\n';
|
||
models.forEach(function(m, i) {
|
||
csv += m + ',' + data.donut[i] + '%\n';
|
||
});
|
||
csv += '\n';
|
||
|
||
csv += '【每日对话趋势】\n';
|
||
csv += '日期,对话次数\n';
|
||
days.forEach(function(d, i) {
|
||
csv += d + ',' + data.trends[i] + '\n';
|
||
});
|
||
|
||
// 创建下载链接
|
||
var blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
|
||
var link = document.createElement('a');
|
||
var url = URL.createObjectURL(blob);
|
||
link.href = url;
|
||
link.setAttribute('download', 'hololake_stats_' + currentRange + '.csv');
|
||
document.body.appendChild(link);
|
||
link.click();
|
||
document.body.removeChild(link);
|
||
URL.revokeObjectURL(url);
|
||
|
||
// 显示提示
|
||
toast.classList.add('show');
|
||
setTimeout(function() {
|
||
toast.classList.remove('show');
|
||
}, 2000);
|
||
});
|
||
|
||
console.log('HoloLake Analytics v2 · 交互已加载');
|
||
});
|