feat: 自动提交 - 周一 2025/09/22 16:28:00.19

This commit is contained in:
赵杰
2025-09-22 16:28:00 +01:00
parent f75176ec69
commit d6c88d87dd
58 changed files with 1197 additions and 11922 deletions

View File

@@ -1373,19 +1373,37 @@ class TSPDashboard {
return;
}
// 添加预警列表的批量操作头部
const headerHtml = `
<div class="d-flex justify-content-between align-items-center mb-3">
<div class="d-flex align-items-center">
<input type="checkbox" id="select-all-alerts" class="form-check-input me-2" onchange="dashboard.toggleSelectAllAlerts()">
<label for="select-all-alerts" class="form-check-label">全选</label>
</div>
<div class="btn-group">
<button class="btn btn-sm btn-danger" id="batch-delete-alerts" onclick="dashboard.batchDeleteAlerts()" disabled>
<i class="fas fa-trash me-1"></i>批量删除
</button>
</div>
</div>
`;
const alertsHtml = alerts.map(alert => `
<div class="alert-item ${alert.level}">
<div class="d-flex justify-content-between align-items-start">
<div class="flex-grow-1">
<div class="d-flex align-items-center mb-2">
<span class="badge bg-${this.getAlertColor(alert.level)} me-2">${this.getLevelText(alert.level)}</span>
<span class="fw-bold">${alert.rule_name || '未知规则'}</span>
<span class="ms-auto text-muted small">${this.formatTime(alert.created_at)}</span>
</div>
<div class="alert-message mb-2">${alert.message}</div>
<div class="alert-meta text-muted small">
类型: ${this.getTypeText(alert.alert_type)} |
级别: ${this.getLevelText(alert.level)}
<div class="d-flex align-items-start">
<input type="checkbox" class="form-check-input me-2 alert-checkbox" value="${alert.id}" onchange="dashboard.updateBatchDeleteAlertsButton()">
<div class="flex-grow-1">
<div class="d-flex align-items-center mb-2">
<span class="badge bg-${this.getAlertColor(alert.level)} me-2">${this.getLevelText(alert.level)}</span>
<span class="fw-bold">${alert.rule_name || '未知规则'}</span>
<span class="ms-auto text-muted small">${this.formatTime(alert.created_at)}</span>
</div>
<div class="alert-message mb-2">${alert.message}</div>
<div class="alert-meta text-muted small">
类型: ${this.getTypeText(alert.alert_type)} |
级别: ${this.getLevelText(alert.level)}
</div>
</div>
</div>
<div class="ms-3">
@@ -1397,7 +1415,7 @@ class TSPDashboard {
</div>
`).join('');
container.innerHTML = alertsHtml;
container.innerHTML = headerHtml + alertsHtml;
}
updateAlertStatistics(alerts) {
@@ -1413,6 +1431,72 @@ class TSPDashboard {
document.getElementById('total-alerts-count').textContent = stats.total || 0;
}
// 预警批量删除功能
toggleSelectAllAlerts() {
const selectAllCheckbox = document.getElementById('select-all-alerts');
const alertCheckboxes = document.querySelectorAll('.alert-checkbox');
alertCheckboxes.forEach(checkbox => {
checkbox.checked = selectAllCheckbox.checked;
});
this.updateBatchDeleteAlertsButton();
}
updateBatchDeleteAlertsButton() {
const selectedCheckboxes = document.querySelectorAll('.alert-checkbox:checked');
const batchDeleteBtn = document.getElementById('batch-delete-alerts');
if (batchDeleteBtn) {
batchDeleteBtn.disabled = selectedCheckboxes.length === 0;
batchDeleteBtn.textContent = selectedCheckboxes.length > 0
? `批量删除 (${selectedCheckboxes.length})`
: '批量删除';
}
}
async batchDeleteAlerts() {
const selectedCheckboxes = document.querySelectorAll('.alert-checkbox:checked');
const selectedIds = Array.from(selectedCheckboxes).map(cb => parseInt(cb.value));
if (selectedIds.length === 0) {
this.showNotification('请选择要删除的预警', 'warning');
return;
}
if (!confirm(`确定要删除选中的 ${selectedIds.length} 个预警吗?此操作不可撤销。`)) {
return;
}
try {
const response = await fetch('/api/batch-delete/alerts', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ ids: selectedIds })
});
const data = await response.json();
if (data.success) {
this.showNotification(data.message, 'success');
// 清除缓存并强制刷新
this.cache.delete('alerts');
await this.loadAlerts();
// 重置批量删除按钮状态
this.updateBatchDeleteAlertsButton();
} else {
this.showNotification(data.error || '批量删除失败', 'error');
}
} catch (error) {
console.error('批量删除预警失败:', error);
this.showNotification('批量删除预警失败', 'error');
}
}
async resolveAlert(alertId) {
try {
const response = await fetch(`/api/alerts/${alertId}/resolve`, { method: 'POST' });
@@ -1456,19 +1540,37 @@ class TSPDashboard {
return;
}
// 添加知识库列表的批量操作头部
const headerHtml = `
<div class="d-flex justify-content-between align-items-center mb-3">
<div class="d-flex align-items-center">
<input type="checkbox" id="select-all-knowledge" class="form-check-input me-2" onchange="dashboard.toggleSelectAllKnowledge()">
<label for="select-all-knowledge" class="form-check-label">全选</label>
</div>
<div class="btn-group">
<button class="btn btn-sm btn-danger" id="batch-delete-knowledge" onclick="dashboard.batchDeleteKnowledge()" disabled>
<i class="fas fa-trash me-1"></i>批量删除
</button>
</div>
</div>
`;
const knowledgeHtml = knowledge.map(item => `
<div class="knowledge-item">
<div class="d-flex justify-content-between align-items-start">
<div class="flex-grow-1">
<h6 class="mb-1">${item.question}</h6>
<p class="text-muted mb-2">${item.answer}</p>
<div class="d-flex gap-3">
<small class="text-muted">分类: ${item.category}</small>
<small class="text-muted">置信度: ${Math.round(item.confidence_score * 100)}%</small>
<small class="text-muted">使用次数: ${item.usage_count || 0}</small>
<span class="badge ${item.is_verified ? 'bg-success' : 'bg-warning'}">
${item.is_verified ? '已验证' : '未验证'}
</span>
<div class="d-flex align-items-start">
<input type="checkbox" class="form-check-input me-2 knowledge-checkbox" value="${item.id}" onchange="dashboard.updateBatchDeleteKnowledgeButton()">
<div class="flex-grow-1">
<h6 class="mb-1">${item.question}</h6>
<p class="text-muted mb-2">${item.answer}</p>
<div class="d-flex gap-3">
<small class="text-muted">分类: ${item.category}</small>
<small class="text-muted">置信度: ${Math.round(item.confidence_score * 100)}%</small>
<small class="text-muted">使用次数: ${item.usage_count || 0}</small>
<span class="badge ${item.is_verified ? 'bg-success' : 'bg-warning'}">
${item.is_verified ? '已验证' : '未验证'}
</span>
</div>
</div>
</div>
<div class="ms-3">
@@ -1490,7 +1592,7 @@ class TSPDashboard {
</div>
`).join('');
container.innerHTML = knowledgeHtml;
container.innerHTML = headerHtml + knowledgeHtml;
}
updateKnowledgePagination(data) {
@@ -1750,24 +1852,115 @@ class TSPDashboard {
}
}
// 工单管理
async loadWorkOrders() {
// 知识库批量删除功能
toggleSelectAllKnowledge() {
const selectAllCheckbox = document.getElementById('select-all-knowledge');
const knowledgeCheckboxes = document.querySelectorAll('.knowledge-checkbox');
knowledgeCheckboxes.forEach(checkbox => {
checkbox.checked = selectAllCheckbox.checked;
});
this.updateBatchDeleteKnowledgeButton();
}
updateBatchDeleteKnowledgeButton() {
const selectedCheckboxes = document.querySelectorAll('.knowledge-checkbox:checked');
const batchDeleteBtn = document.getElementById('batch-delete-knowledge');
if (batchDeleteBtn) {
batchDeleteBtn.disabled = selectedCheckboxes.length === 0;
batchDeleteBtn.textContent = selectedCheckboxes.length > 0
? `批量删除 (${selectedCheckboxes.length})`
: '批量删除';
}
}
async batchDeleteKnowledge() {
const selectedCheckboxes = document.querySelectorAll('.knowledge-checkbox:checked');
const selectedIds = Array.from(selectedCheckboxes).map(cb => parseInt(cb.value));
if (selectedIds.length === 0) {
this.showNotification('请选择要删除的知识库条目', 'warning');
return;
}
if (!confirm(`确定要删除选中的 ${selectedIds.length} 个知识库条目吗?此操作不可撤销。`)) {
return;
}
try {
const statusFilter = document.getElementById('workorder-status-filter').value;
const priorityFilter = document.getElementById('workorder-priority-filter').value;
const response = await fetch('/api/batch-delete/knowledge', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ ids: selectedIds })
});
const data = await response.json();
if (data.success) {
this.showNotification(data.message, 'success');
// 清除缓存并强制刷新
this.cache.delete('knowledge');
await this.loadKnowledge();
// 重置批量删除按钮状态
this.updateBatchDeleteKnowledgeButton();
} else {
this.showNotification(data.error || '批量删除失败', 'error');
}
} catch (error) {
console.error('批量删除知识库条目失败:', error);
this.showNotification('批量删除知识库条目失败', 'error');
}
}
// 工单管理
async loadWorkOrders(forceRefresh = false) {
try {
const statusFilter = document.getElementById('workorder-status-filter')?.value || 'all';
const priorityFilter = document.getElementById('workorder-priority-filter')?.value || 'all';
let url = '/api/workorders';
const params = new URLSearchParams();
if (statusFilter !== 'all') params.append('status', statusFilter);
if (priorityFilter !== 'all') params.append('priority', priorityFilter);
// 添加强制刷新参数
if (forceRefresh) {
params.append('_t', Date.now().toString());
}
if (params.toString()) url += '?' + params.toString();
const response = await fetch(url);
const response = await fetch(url, {
cache: forceRefresh ? 'no-cache' : 'default',
headers: forceRefresh ? {
'Cache-Control': 'no-cache',
'Pragma': 'no-cache'
} : {}
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const workorders = await response.json();
this.updateWorkOrdersDisplay(workorders);
this.updateWorkOrderStatistics(workorders);
// 更新缓存
this.cache.set('workorders', {
data: workorders,
timestamp: Date.now()
});
} catch (error) {
console.error('加载工单失败:', error);
this.showNotification('加载工单失败: ' + error.message, 'error');
}
}
@@ -1779,17 +1972,35 @@ class TSPDashboard {
return;
}
// 添加工单列表的批量操作头部
const headerHtml = `
<div class="d-flex justify-content-between align-items-center mb-3">
<div class="d-flex align-items-center">
<input type="checkbox" id="select-all-workorders" class="form-check-input me-2" onchange="dashboard.toggleSelectAllWorkorders()">
<label for="select-all-workorders" class="form-check-label">全选</label>
</div>
<div class="btn-group">
<button class="btn btn-sm btn-danger" id="batch-delete-workorders" onclick="dashboard.batchDeleteWorkorders()" disabled>
<i class="fas fa-trash me-1"></i>批量删除
</button>
</div>
</div>
`;
const workordersHtml = workorders.map(workorder => `
<div class="work-order-item">
<div class="d-flex justify-content-between align-items-start">
<div class="flex-grow-1">
<h6 class="mb-1">${workorder.title}</h6>
<p class="text-muted mb-2">${workorder.description ? workorder.description.substring(0, 100) + (workorder.description.length > 100 ? '...' : '') : '无处理过程'}</p>
<div class="d-flex gap-3">
<span class="badge bg-${this.getPriorityColor(workorder.priority)}">${this.getPriorityText(workorder.priority)}</span>
<span class="badge bg-${this.getStatusColor(workorder.status)}">${this.getStatusText(workorder.status)}</span>
<small class="text-muted">分类: ${workorder.category}</small>
<small class="text-muted">创建时间: ${new Date(workorder.created_at).toLocaleString()}</small>
<div class="d-flex align-items-start">
<input type="checkbox" class="form-check-input me-2 workorder-checkbox" value="${workorder.id}" onchange="dashboard.updateBatchDeleteButton()">
<div class="flex-grow-1">
<h6 class="mb-1">${workorder.title}</h6>
<p class="text-muted mb-2">${workorder.description ? workorder.description.substring(0, 100) + (workorder.description.length > 100 ? '...' : '') : '无处理过程'}</p>
<div class="d-flex gap-3">
<span class="badge bg-${this.getPriorityColor(workorder.priority)}">${this.getPriorityText(workorder.priority)}</span>
<span class="badge bg-${this.getStatusColor(workorder.status)}">${this.getStatusText(workorder.status)}</span>
<small class="text-muted">分类: ${workorder.category}</small>
<small class="text-muted">创建时间: ${new Date(workorder.created_at).toLocaleString()}</small>
</div>
</div>
</div>
<div class="ms-3">
@@ -1809,7 +2020,7 @@ class TSPDashboard {
</div>
`).join('');
container.innerHTML = workordersHtml;
container.innerHTML = headerHtml + workordersHtml;
}
updateWorkOrderStatistics(workorders) {
@@ -1825,6 +2036,73 @@ class TSPDashboard {
document.getElementById('workorders-resolved').textContent = stats.resolved || 0;
}
// 工单批量删除功能
toggleSelectAllWorkorders() {
const selectAllCheckbox = document.getElementById('select-all-workorders');
const workorderCheckboxes = document.querySelectorAll('.workorder-checkbox');
workorderCheckboxes.forEach(checkbox => {
checkbox.checked = selectAllCheckbox.checked;
});
this.updateBatchDeleteButton();
}
updateBatchDeleteButton() {
const selectedCheckboxes = document.querySelectorAll('.workorder-checkbox:checked');
const batchDeleteBtn = document.getElementById('batch-delete-workorders');
if (batchDeleteBtn) {
batchDeleteBtn.disabled = selectedCheckboxes.length === 0;
batchDeleteBtn.textContent = selectedCheckboxes.length > 0
? `批量删除 (${selectedCheckboxes.length})`
: '批量删除';
}
}
async batchDeleteWorkorders() {
const selectedCheckboxes = document.querySelectorAll('.workorder-checkbox:checked');
const selectedIds = Array.from(selectedCheckboxes).map(cb => parseInt(cb.value));
if (selectedIds.length === 0) {
this.showNotification('请选择要删除的工单', 'warning');
return;
}
if (!confirm(`确定要删除选中的 ${selectedIds.length} 个工单吗?此操作不可撤销。`)) {
return;
}
try {
const response = await fetch('/api/batch-delete/workorders', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ ids: selectedIds })
});
const data = await response.json();
if (data.success) {
this.showNotification(data.message, 'success');
// 清除缓存并强制刷新
this.cache.delete('workorders');
await this.loadWorkOrders(true); // 强制刷新
await this.loadAnalytics();
// 重置批量删除按钮状态
this.updateBatchDeleteButton();
} else {
this.showNotification(data.error || '批量删除失败', 'error');
}
} catch (error) {
console.error('批量删除工单失败:', error);
this.showNotification('批量删除工单失败', 'error');
}
}
async createWorkOrder() {
const title = document.getElementById('wo-title').value.trim();
const description = document.getElementById('wo-description').value.trim();
@@ -3407,6 +3685,7 @@ class TSPDashboard {
// 更新统计卡片
updateStatisticsCards(data) {
// 更新工单统计
const total = data.workorders?.total || 0;
const open = data.workorders?.open || 0;
const resolved = data.workorders?.resolved || 0;
@@ -3417,6 +3696,49 @@ class TSPDashboard {
document.getElementById('resolvedWorkorders').textContent = resolved;
document.getElementById('avgSatisfaction').textContent = avgSatisfaction.toFixed(1);
// 更新预警统计
const alertTotal = data.alerts?.total || 0;
const alertActive = data.alerts?.active || 0;
const alertCritical = data.alerts?.by_level?.critical || 0;
const alertWarning = data.alerts?.by_level?.warning || 0;
const alertError = data.alerts?.by_level?.error || 0;
// 更新预警统计显示
if (document.getElementById('critical-alerts')) {
document.getElementById('critical-alerts').textContent = alertCritical;
}
if (document.getElementById('warning-alerts')) {
document.getElementById('warning-alerts').textContent = alertWarning;
}
if (document.getElementById('error-alerts')) {
document.getElementById('error-alerts').textContent = alertError;
}
if (document.getElementById('total-alerts-count')) {
document.getElementById('total-alerts-count').textContent = alertTotal;
}
// 更新性能统计
const performanceScore = data.performance?.score || 0;
const performanceTrend = data.performance?.trend || 'stable';
if (document.getElementById('performance-score')) {
document.getElementById('performance-score').textContent = performanceScore.toFixed(1);
}
if (document.getElementById('performance-trend')) {
document.getElementById('performance-trend').textContent = this.getPerformanceTrendText(performanceTrend);
}
// 更新满意度统计
const satisfactionAvg = data.satisfaction?.average || 0;
const satisfactionCount = data.satisfaction?.count || 0;
if (document.getElementById('satisfaction-avg')) {
document.getElementById('satisfaction-avg').textContent = satisfactionAvg.toFixed(1);
}
if (document.getElementById('satisfaction-count')) {
document.getElementById('satisfaction-count').textContent = satisfactionCount;
}
// 更新进度条
if (total > 0) {
document.getElementById('openProgress').style.width = `${(open / total) * 100}%`;
@@ -3469,9 +3791,62 @@ class TSPDashboard {
// 更新分布图表
updateDistributionChart(data) {
const categories = data.workorders?.by_category || {};
const labels = Object.keys(categories);
const values = Object.values(categories);
const currentDimension = document.getElementById('dataDimension')?.value || 'workorders';
let labels, values, title, backgroundColor;
if (currentDimension === 'alerts') {
// 预警级别分布
const alertLevels = data.alerts?.by_level || {};
labels = Object.keys(alertLevels);
values = Object.values(alertLevels);
title = '预警级别分布';
backgroundColor = [
'#FF6384', // critical - 红色
'#FFCE56', // warning - 黄色
'#36A2EB', // error - 蓝色
'#4BC0C0', // info - 青色
'#9966FF' // 其他
];
} else if (currentDimension === 'performance') {
// 性能指标分布
const performanceMetrics = data.performance?.by_level || {};
labels = Object.keys(performanceMetrics);
values = Object.values(performanceMetrics);
title = '性能指标分布';
backgroundColor = [
'#28a745', // 优秀 - 绿色
'#ffc107', // 良好 - 黄色
'#fd7e14', // 一般 - 橙色
'#dc3545' // 差 - 红色
];
} else if (currentDimension === 'satisfaction') {
// 满意度分布
const satisfactionLevels = data.satisfaction?.by_level || {};
labels = Object.keys(satisfactionLevels);
values = Object.values(satisfactionLevels);
title = '满意度分布';
backgroundColor = [
'#28a745', // 非常满意 - 绿色
'#ffc107', // 满意 - 黄色
'#fd7e14', // 一般 - 橙色
'#dc3545' // 不满意 - 红色
];
} else {
// 工单分类分布
const categories = data.workorders?.by_category || {};
labels = Object.keys(categories);
values = Object.values(categories);
title = '工单分类分布';
backgroundColor = [
'#FF6384',
'#36A2EB',
'#FFCE56',
'#4BC0C0',
'#9966FF',
'#FF9F40'
];
}
const chartConfig = {
type: 'doughnut',
@@ -3479,14 +3854,7 @@ class TSPDashboard {
labels: labels,
datasets: [{
data: values,
backgroundColor: [
'#FF6384',
'#36A2EB',
'#FFCE56',
'#4BC0C0',
'#9966FF',
'#FF9F40'
]
backgroundColor: backgroundColor
}]
},
options: {
@@ -3495,7 +3863,7 @@ class TSPDashboard {
plugins: {
title: {
display: true,
text: '工单分类分布'
text: title
},
legend: {
display: true,
@@ -3576,23 +3944,72 @@ class TSPDashboard {
this.charts.priorityChart.destroy();
}
const priorities = data.workorders?.by_priority || {};
const labels = Object.keys(priorities).map(p => this.getPriorityText(p));
const values = Object.values(priorities);
const currentDimension = document.getElementById('dataDimension')?.value || 'workorders';
let labels, values, title, backgroundColor, label;
if (currentDimension === 'alerts') {
// 预警严重程度分布
const alertSeverities = data.alerts?.by_severity || {};
labels = Object.keys(alertSeverities).map(s => this.getSeverityText(s));
values = Object.values(alertSeverities);
title = '预警严重程度分布';
label = '预警数量';
backgroundColor = [
'#28a745', // low - 绿色
'#ffc107', // medium - 黄色
'#fd7e14', // high - 橙色
'#dc3545' // critical - 红色
];
} else if (currentDimension === 'performance') {
// 性能指标分布
const performanceMetrics = data.performance?.by_metric || {};
labels = Object.keys(performanceMetrics);
values = Object.values(performanceMetrics);
title = '性能指标分布';
label = '性能值';
backgroundColor = [
'#28a745', // 优秀 - 绿色
'#ffc107', // 良好 - 黄色
'#fd7e14', // 一般 - 橙色
'#dc3545' // 差 - 红色
];
} else if (currentDimension === 'satisfaction') {
// 满意度分布
const satisfactionLevels = data.satisfaction?.by_level || {};
labels = Object.keys(satisfactionLevels).map(s => this.getSatisfactionText(s));
values = Object.values(satisfactionLevels);
title = '满意度分布';
label = '满意度数量';
backgroundColor = [
'#28a745', // 非常满意 - 绿色
'#ffc107', // 满意 - 黄色
'#fd7e14', // 一般 - 橙色
'#dc3545' // 不满意 - 红色
];
} else {
// 工单优先级分布
const priorities = data.workorders?.by_priority || {};
labels = Object.keys(priorities).map(p => this.getPriorityText(p));
values = Object.values(priorities);
title = '工单优先级分布';
label = '工单数量';
backgroundColor = [
'#28a745', // 低 - 绿色
'#ffc107', // 中 - 黄色
'#fd7e14', // 高 - 橙色
'#dc3545' // 紧急 - 红色
];
}
this.charts.priorityChart = new Chart(ctx, {
type: 'bar',
data: {
labels: labels,
datasets: [{
label: '工单数量',
label: label,
data: values,
backgroundColor: [
'#28a745', // 低 - 绿色
'#ffc107', // 中 - 黄色
'#fd7e14', // 高 - 橙色
'#dc3545' // 紧急 - 红色
]
backgroundColor: backgroundColor
}]
},
options: {
@@ -3601,7 +4018,7 @@ class TSPDashboard {
plugins: {
title: {
display: true,
text: '优先级分布'
text: title
}
},
scales: {
@@ -3618,33 +4035,124 @@ class TSPDashboard {
const trendData = data.trend || [];
const labels = trendData.map(item => item.date);
const workorders = trendData.map(item => item.workorders);
const alerts = trendData.map(item => item.alerts);
const performance = trendData.map(item => item.performance || 0);
const satisfaction = trendData.map(item => item.satisfaction || 0);
if (chartType === 'pie' || chartType === 'doughnut') {
const categories = data.workorders?.by_category || {};
return {
labels: Object.keys(categories),
datasets: [{
data: Object.values(categories),
backgroundColor: [
'#FF6384',
'#36A2EB',
'#FFCE56',
'#4BC0C0',
'#9966FF',
'#FF9F40'
]
}]
};
// 根据数据维度选择显示内容
const currentDimension = document.getElementById('dataDimension')?.value || 'workorders';
if (currentDimension === 'alerts') {
const alertLevels = data.alerts?.by_level || {};
return {
labels: Object.keys(alertLevels),
datasets: [{
data: Object.values(alertLevels),
backgroundColor: [
'#FF6384', // critical - 红色
'#FFCE56', // warning - 黄色
'#36A2EB', // error - 蓝色
'#4BC0C0', // info - 青色
'#9966FF' // 其他
]
}]
};
} else if (currentDimension === 'performance') {
// 性能指标分布
const performanceMetrics = data.performance || {};
return {
labels: Object.keys(performanceMetrics),
datasets: [{
data: Object.values(performanceMetrics),
backgroundColor: [
'#28a745', // 优秀 - 绿色
'#ffc107', // 良好 - 黄色
'#fd7e14', // 一般 - 橙色
'#dc3545' // 差 - 红色
]
}]
};
} else if (currentDimension === 'satisfaction') {
// 满意度分布
const satisfactionLevels = data.satisfaction?.by_level || {};
return {
labels: Object.keys(satisfactionLevels),
datasets: [{
data: Object.values(satisfactionLevels),
backgroundColor: [
'#28a745', // 非常满意 - 绿色
'#ffc107', // 满意 - 黄色
'#fd7e14', // 一般 - 橙色
'#dc3545' // 不满意 - 红色
]
}]
};
} else {
const categories = data.workorders?.by_category || {};
return {
labels: Object.keys(categories),
datasets: [{
data: Object.values(categories),
backgroundColor: [
'#FF6384',
'#36A2EB',
'#FFCE56',
'#4BC0C0',
'#9966FF',
'#FF9F40'
]
}]
};
}
} else {
return {
labels: labels,
datasets: [{
// 线图和柱状图根据数据维度显示不同内容
const currentDimension = document.getElementById('dataDimension')?.value || 'workorders';
const datasets = [];
if (currentDimension === 'performance') {
// 性能指标图表
datasets.push({
label: '性能指标',
data: performance,
borderColor: '#28a745',
backgroundColor: 'rgba(40, 167, 69, 0.1)',
tension: chartType === 'line' ? 0.4 : 0
});
} else if (currentDimension === 'satisfaction') {
// 满意度图表
datasets.push({
label: '满意度评分',
data: satisfaction,
borderColor: '#ffc107',
backgroundColor: 'rgba(255, 193, 7, 0.1)',
tension: chartType === 'line' ? 0.4 : 0
});
} else {
// 默认显示工单和预警数据
datasets.push({
label: '工单数量',
data: workorders,
borderColor: '#36A2EB',
backgroundColor: 'rgba(54, 162, 235, 0.1)',
tension: chartType === 'line' ? 0.4 : 0
}]
});
// 如果有预警数据,添加预警数据集
if (alerts.some(alert => alert > 0)) {
datasets.push({
label: '预警数量',
data: alerts,
borderColor: '#FF6384',
backgroundColor: 'rgba(255, 99, 132, 0.1)',
tension: chartType === 'line' ? 0.4 : 0
});
}
}
return {
labels: labels,
datasets: datasets
};
}
}
@@ -4281,6 +4789,35 @@ class TSPDashboard {
return priorityMap[priority] || priority;
}
getSeverityText(severity) {
const severityMap = {
'low': '低',
'medium': '中',
'high': '高',
'critical': '严重'
};
return severityMap[severity] || severity;
}
getSatisfactionText(level) {
const satisfactionMap = {
'very_satisfied': '非常满意',
'satisfied': '满意',
'neutral': '一般',
'dissatisfied': '不满意'
};
return satisfactionMap[level] || level;
}
getPerformanceTrendText(trend) {
const trendMap = {
'up': '上升',
'down': '下降',
'stable': '稳定'
};
return trendMap[trend] || trend;
}
getPriorityColor(priority) {
const colorMap = {
'low': 'secondary',