Files
assist/src/web/static/js/modules/dashboard-home.js
Jeason 58b3c615ef refactor: dashboard.js 模块化拆分 从7766行拆为13个独立模块
核心 dashboard.js 缩减至266行,只保留:
- TSPDashboard class 定义(constructor、init、bindEvents、switchTab)
- 分页组件、缓存、状态管理、自动刷新、WebSocket、i18n

功能模块拆分到 modules/ 目录:
- chat.js (207行)  智能对话
- agent.js (424行)  Agent管理
- alerts.js (348行)  预警管理
- knowledge.js (699行)  知识库管理
- workorders.js (约500行)  工单管理
- conversations.js (671行)  对话历史
- monitoring.js (455行)  Token/AI监控
- system.js (1388行)  系统优化+设置+数据分析图表
- tenants.js (165行)  租户管理
- utils.js (573行)  工具函数
- dashboard-home.js (286行)  仪表板首页
- feishu-sync.js (698行)  飞书同步管理器

拆分方式:Object.assign(TSPDashboard.prototype, {...})
this 引用完全不会断,所有模块方法互相调用正常
2026-04-02 15:10:23 +08:00

287 lines
11 KiB
JavaScript

// Dashboard Home Module - 仪表板首页相关方法
Object.assign(TSPDashboard.prototype, {
async loadDashboardData() {
try {
const [sessionsResponse, alertsResponse, workordersResponse, knowledgeResponse] = await Promise.all([
fetch('/api/chat/sessions'),
fetch('/api/alerts?per_page=1000'),
fetch('/api/workorders'),
fetch('/api/knowledge/stats')
]);
const sessions = await sessionsResponse.json();
const alerts = await alertsResponse.json();
const workorders = await workordersResponse.json();
const knowledge = await knowledgeResponse.json();
document.getElementById('total-sessions').textContent = sessions.sessions?.length || 0;
document.getElementById('total-alerts').textContent = alerts.alerts?.length || 0;
document.getElementById('total-workorders').textContent = workorders.workorders?.filter(w => w.status === 'open').length || 0;
document.getElementById('knowledge-count').textContent = knowledge.total_entries || 0;
if (alerts.alerts) {
this.updateAlertStatistics(alerts.alerts);
}
document.getElementById('knowledge-total').textContent = knowledge.total_entries || 0;
document.getElementById('knowledge-active').textContent = knowledge.active_entries || 0;
const confidencePercent = Math.round((knowledge.average_confidence || 0) * 100);
document.getElementById('knowledge-confidence-bar').style.width = `${confidencePercent}%`;
document.getElementById('knowledge-confidence-bar').setAttribute('aria-valuenow', confidencePercent);
document.getElementById('knowledge-confidence-bar').textContent = `${confidencePercent}%`;
await this.updatePerformanceChart(sessions, alerts, workorders);
await this.updateSystemHealth();
await this.loadAnalytics();
} catch (error) {
console.error('加载仪表板数据失败:', error);
}
},
initCharts() {
const performanceCtx = document.getElementById('performanceChart');
if (performanceCtx) {
this.charts.performance = new Chart(performanceCtx, {
type: 'line',
data: {
labels: [],
datasets: [{
label: '工单数量',
data: [],
borderColor: '#007bff',
backgroundColor: 'rgba(0, 123, 255, 0.1)',
tension: 0.4
}, {
label: '预警数量',
data: [],
borderColor: '#dc3545',
backgroundColor: 'rgba(220, 53, 69, 0.1)',
tension: 0.4
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
y: {
beginAtZero: true
}
}
}
});
}
const analyticsCtx = document.getElementById('analyticsChart');
if (analyticsCtx) {
this.charts.analytics = new Chart(analyticsCtx, {
type: 'line',
data: {
labels: [],
datasets: [{
label: '满意度',
data: [],
borderColor: '#28a745',
backgroundColor: 'rgba(40, 167, 69, 0.1)',
tension: 0.4
}, {
label: '解决时间(小时)',
data: [],
borderColor: '#ffc107',
backgroundColor: 'rgba(255, 193, 7, 0.1)',
tension: 0.4
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
y: {
beginAtZero: true
}
}
}
});
}
const categoryCtx = document.getElementById('categoryChart');
if (categoryCtx) {
this.charts.category = new Chart(categoryCtx, {
type: 'doughnut',
data: {
labels: [],
datasets: [{
data: [],
backgroundColor: [
'#007bff',
'#28a745',
'#ffc107',
'#dc3545',
'#17a2b8'
]
}]
},
options: {
responsive: true,
maintainAspectRatio: false
}
});
}
},
async updatePerformanceChart(sessions, alerts, workorders) {
if (!this.charts.performance) return;
try {
const response = await fetch('/api/analytics?days=7&dimension=performance');
const analyticsData = await response.json();
if (analyticsData.trend && analyticsData.trend.length > 0) {
const labels = analyticsData.trend.map(item => {
const date = new Date(item.date);
return `${date.getMonth() + 1}/${date.getDate()}`;
});
const workorderData = analyticsData.trend.map(item => item.workorders || 0);
const alertData = analyticsData.trend.map(item => item.alerts || 0);
this.charts.performance.data.labels = labels;
this.charts.performance.data.datasets[0].data = workorderData;
this.charts.performance.data.datasets[1].data = alertData;
this.charts.performance.update();
} else {
this.charts.performance.data.labels = ['暂无数据'];
this.charts.performance.data.datasets[0].data = [0];
this.charts.performance.data.datasets[1].data = [0];
this.charts.performance.update();
}
} catch (error) {
console.error('获取性能趋势数据失败:', error);
this.charts.performance.data.labels = ['数据加载失败'];
this.charts.performance.data.datasets[0].data = [0];
this.charts.performance.data.datasets[1].data = [0];
this.charts.performance.update();
}
},
async updateSystemHealth() {
try {
const response = await fetch('/api/settings');
const settings = await response.json();
const healthScore = Math.max(0, 100 - (settings.memory_usage_percent || 0) - (settings.cpu_usage_percent || 0));
const healthProgress = document.getElementById('health-progress');
const healthDot = document.getElementById('system-health-dot');
const healthText = document.getElementById('system-health-text');
if (healthProgress) {
healthProgress.style.width = `${healthScore}%`;
healthProgress.setAttribute('aria-valuenow', healthScore);
}
if (healthDot) {
healthDot.className = 'health-dot';
if (healthScore >= 80) healthDot.classList.add('excellent');
else if (healthScore >= 60) healthDot.classList.add('good');
else if (healthScore >= 40) healthDot.classList.add('fair');
else if (healthScore >= 20) healthDot.classList.add('poor');
else healthDot.classList.add('critical');
}
if (healthText) {
const statusText = healthScore >= 80 ? '优秀' :
healthScore >= 60 ? '良好' :
healthScore >= 40 ? '一般' :
healthScore >= 20 ? '较差' : '严重';
healthText.textContent = `${statusText} (${healthScore}%)`;
}
const memoryProgress = document.getElementById('memory-progress');
if (memoryProgress && settings.memory_usage_percent !== undefined) {
memoryProgress.style.width = `${settings.memory_usage_percent}%`;
memoryProgress.setAttribute('aria-valuenow', settings.memory_usage_percent);
}
const cpuProgress = document.getElementById('cpu-progress');
if (cpuProgress && settings.cpu_usage_percent !== undefined) {
cpuProgress.style.width = `${settings.cpu_usage_percent}%`;
cpuProgress.setAttribute('aria-valuenow', settings.cpu_usage_percent);
}
} catch (error) {
console.error('更新系统健康状态失败:', error);
}
},
async loadHealth() {
try {
const response = await fetch('/api/health');
const data = await response.json();
this.updateHealthDisplay(data);
} catch (error) {
console.error('加载健康状态失败:', error);
}
},
updateHealthDisplay(health) {
const healthScore = health.health_score || 0;
const healthStatus = health.status || 'unknown';
const healthDot = document.getElementById('health-dot');
const healthStatusText = document.getElementById('health-status');
const systemHealthDot = document.getElementById('system-health-dot');
const systemHealthText = document.getElementById('system-health-text');
const healthProgress = document.getElementById('health-progress');
if (healthDot) {
healthDot.className = `health-dot ${healthStatus}`;
}
if (healthStatusText) {
healthStatusText.textContent = this.getHealthStatusText(healthStatus);
}
if (systemHealthDot) {
systemHealthDot.className = `health-dot ${healthStatus}`;
}
if (systemHealthText) {
systemHealthText.textContent = this.getHealthStatusText(healthStatus);
}
if (healthProgress) {
healthProgress.style.width = `${healthScore * 100}%`;
healthProgress.className = `progress-bar ${this.getHealthColor(healthScore)}`;
}
const memoryUsage = health.memory_usage || 0;
const memoryProgress = document.getElementById('memory-progress');
if (memoryProgress) {
memoryProgress.style.width = `${memoryUsage}%`;
}
const cpuUsage = health.cpu_usage || 0;
const cpuProgress = document.getElementById('cpu-progress');
if (cpuProgress) {
cpuProgress.style.width = `${cpuUsage}%`;
}
},
getHealthStatusText(status) {
const statusMap = {
'excellent': '优秀',
'good': '良好',
'fair': '一般',
'poor': '较差',
'critical': '严重',
'unknown': '未知'
};
return statusMap[status] || status;
},
getHealthColor(score) {
if (score >= 0.8) return 'bg-success';
if (score >= 0.6) return 'bg-info';
if (score >= 0.4) return 'bg-warning';
return 'bg-danger';
}
});