refactor: 清理不需要的代码文件,添加.gitignore,优化项目结构
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -13,6 +13,65 @@ class TSPDashboard {
|
||||
this.restorePageState();
|
||||
}
|
||||
|
||||
async generateAISuggestion(workorderId) {
|
||||
try {
|
||||
const resp = await fetch(`/api/workorders/${workorderId}/ai-suggestion`, { method: 'POST' });
|
||||
const data = await resp.json();
|
||||
if (data.success) {
|
||||
const ta = document.getElementById(`aiSuggestion_${workorderId}`);
|
||||
if (ta) ta.value = data.ai_suggestion || '';
|
||||
this.showNotification('AI建议已生成', 'success');
|
||||
} else {
|
||||
throw new Error(data.error || '生成失败');
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('生成AI建议失败:', e);
|
||||
this.showNotification('生成AI建议失败: ' + e.message, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
async saveHumanResolution(workorderId) {
|
||||
try {
|
||||
const text = document.getElementById(`humanResolution_${workorderId}`).value.trim();
|
||||
if (!text) { this.showNotification('请输入人工描述', 'warning'); return; }
|
||||
const resp = await fetch(`/api/workorders/${workorderId}/human-resolution`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ human_resolution: text })
|
||||
});
|
||||
const data = await resp.json();
|
||||
if (data.success) {
|
||||
const simEl = document.getElementById(`aiSim_${workorderId}`);
|
||||
const apprEl = document.getElementById(`aiApproved_${workorderId}`);
|
||||
const approveBtn = document.getElementById(`approveBtn_${workorderId}`);
|
||||
const percent = Math.round((data.similarity || 0) * 100);
|
||||
if (simEl) { simEl.textContent = `相似度: ${percent}%`; simEl.className = `badge ${percent>=95?'bg-success':percent>=70?'bg-warning':'bg-secondary'}`; }
|
||||
if (apprEl) { apprEl.textContent = data.approved ? '已自动审批' : '未审批'; apprEl.className = `badge ${data.approved?'bg-success':'bg-secondary'}`; }
|
||||
if (approveBtn) approveBtn.disabled = !data.approved;
|
||||
this.showNotification('人工描述已保存并评估完成', 'success');
|
||||
} else {
|
||||
throw new Error(data.error || '保存失败');
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('保存人工描述失败:', e);
|
||||
this.showNotification('保存人工描述失败: ' + e.message, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
async approveToKnowledge(workorderId) {
|
||||
try {
|
||||
const resp = await fetch(`/api/workorders/${workorderId}/approve-to-knowledge`, { method: 'POST' });
|
||||
const data = await resp.json();
|
||||
if (data.success) {
|
||||
this.showNotification('已入库为知识条目', 'success');
|
||||
} else {
|
||||
throw new Error(data.error || '入库失败');
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('入库失败:', e);
|
||||
this.showNotification('入库失败: ' + e.message, 'error');
|
||||
}
|
||||
}
|
||||
init() {
|
||||
this.bindEvents();
|
||||
this.loadInitialData();
|
||||
@@ -99,6 +158,27 @@ class TSPDashboard {
|
||||
e.preventDefault();
|
||||
this.saveSystemSettings();
|
||||
});
|
||||
|
||||
// API测试按钮事件
|
||||
const testApiBtn = document.getElementById('test-api-connection');
|
||||
if (testApiBtn) {
|
||||
testApiBtn.addEventListener('click', () => this.testApiConnection());
|
||||
}
|
||||
|
||||
const testModelBtn = document.getElementById('test-model-response');
|
||||
if (testModelBtn) {
|
||||
testModelBtn.addEventListener('click', () => this.testModelResponse());
|
||||
}
|
||||
|
||||
// 重启服务按钮事件
|
||||
const restartBtn = document.getElementById('restart-service');
|
||||
if (restartBtn) {
|
||||
restartBtn.addEventListener('click', () => {
|
||||
if (confirm('确定要重启服务吗?这将中断当前连接。')) {
|
||||
this.showNotification('重启服务功能待实现', 'info');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
switchTab(tabName) {
|
||||
@@ -180,10 +260,10 @@ class TSPDashboard {
|
||||
}
|
||||
|
||||
startAutoRefresh() {
|
||||
// 每5秒刷新健康状态
|
||||
// 每15秒刷新健康状态(减少 /api/health 日志)
|
||||
this.refreshIntervals.health = setInterval(() => {
|
||||
this.loadHealth();
|
||||
}, 5000);
|
||||
}, 15000);
|
||||
|
||||
// 每10秒刷新当前标签页数据
|
||||
this.refreshIntervals.currentTab = setInterval(() => {
|
||||
@@ -305,7 +385,10 @@ class TSPDashboard {
|
||||
document.getElementById('knowledge-confidence').textContent = `${confidencePercent}%`;
|
||||
|
||||
// 更新性能图表
|
||||
this.updatePerformanceChart(sessions, alerts, workorders);
|
||||
await this.updatePerformanceChart(sessions, alerts, workorders);
|
||||
|
||||
// 更新系统健康状态
|
||||
await this.updateSystemHealth();
|
||||
|
||||
} catch (error) {
|
||||
console.error('加载仪表板数据失败:', error);
|
||||
@@ -323,13 +406,13 @@ class TSPDashboard {
|
||||
data: {
|
||||
labels: [],
|
||||
datasets: [{
|
||||
label: '活跃会话',
|
||||
label: '工单数量',
|
||||
data: [],
|
||||
borderColor: '#007bff',
|
||||
backgroundColor: 'rgba(0, 123, 255, 0.1)',
|
||||
tension: 0.4
|
||||
}, {
|
||||
label: '活跃预警',
|
||||
label: '预警数量',
|
||||
data: [],
|
||||
borderColor: '#dc3545',
|
||||
backgroundColor: 'rgba(220, 53, 69, 0.1)',
|
||||
@@ -407,26 +490,96 @@ class TSPDashboard {
|
||||
}
|
||||
}
|
||||
|
||||
updatePerformanceChart(sessions, alerts, workorders) {
|
||||
async updatePerformanceChart(sessions, alerts, workorders) {
|
||||
if (!this.charts.performance) return;
|
||||
|
||||
const now = new Date();
|
||||
const labels = [];
|
||||
const sessionData = [];
|
||||
const alertData = [];
|
||||
|
||||
// 生成过去24小时的数据点
|
||||
for (let i = 23; i >= 0; i--) {
|
||||
const time = new Date(now.getTime() - i * 60 * 60 * 1000);
|
||||
labels.push(time.getHours() + ':00');
|
||||
sessionData.push(Math.floor(Math.random() * 10) + 5); // 模拟数据
|
||||
alertData.push(Math.floor(Math.random() * 5)); // 模拟数据
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
this.charts.performance.data.labels = labels;
|
||||
this.charts.performance.data.datasets[0].data = sessionData;
|
||||
this.charts.performance.data.datasets[1].data = alertData;
|
||||
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);
|
||||
}
|
||||
|
||||
// 更新CPU使用
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
// 对话功能
|
||||
@@ -506,6 +659,9 @@ class TSPDashboard {
|
||||
this.addMessage('user', message);
|
||||
messageInput.value = '';
|
||||
|
||||
// 显示占位提示:小奇正在查询中
|
||||
const typingId = this.showTypingIndicator();
|
||||
|
||||
// 发送消息到服务器
|
||||
try {
|
||||
const response = await fetch('/api/chat/message', {
|
||||
@@ -521,16 +677,70 @@ class TSPDashboard {
|
||||
|
||||
const data = await response.json();
|
||||
if (data.success) {
|
||||
this.addMessage('assistant', data.response, data.knowledge_used);
|
||||
this.updateTypingIndicator(typingId, data.response, data.knowledge_used);
|
||||
} else {
|
||||
this.addMessage('assistant', '抱歉,处理您的消息时出现了错误。', null, true);
|
||||
this.updateTypingIndicator(typingId, '抱歉,处理您的消息时出现了错误。', null, true);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('发送消息失败:', error);
|
||||
this.addMessage('assistant', '网络连接错误,请稍后重试。', null, true);
|
||||
this.updateTypingIndicator(typingId, '网络连接错误,请稍后重试。', null, true);
|
||||
}
|
||||
}
|
||||
|
||||
showTypingIndicator() {
|
||||
const messagesContainer = document.getElementById('chat-messages');
|
||||
const id = `typing-${Date.now()}`;
|
||||
const messageDiv = document.createElement('div');
|
||||
messageDiv.className = 'message assistant';
|
||||
messageDiv.id = id;
|
||||
const avatar = document.createElement('div');
|
||||
avatar.className = 'message-avatar';
|
||||
avatar.innerHTML = '<i class="fas fa-robot"></i>';
|
||||
const contentDiv = document.createElement('div');
|
||||
contentDiv.className = 'message-content';
|
||||
contentDiv.innerHTML = `
|
||||
<div>小奇正在查询中,请稍后…</div>
|
||||
<div class="message-time">${new Date().toLocaleTimeString()}</div>
|
||||
`;
|
||||
messageDiv.appendChild(avatar);
|
||||
messageDiv.appendChild(contentDiv);
|
||||
messagesContainer.appendChild(messageDiv);
|
||||
messagesContainer.scrollTop = messagesContainer.scrollHeight;
|
||||
return id;
|
||||
}
|
||||
|
||||
updateTypingIndicator(typingId, content, knowledgeUsed = null, isError = false) {
|
||||
const node = document.getElementById(typingId);
|
||||
if (!node) {
|
||||
// 回退:若占位不存在则直接追加
|
||||
this.addMessage('assistant', content, knowledgeUsed, isError);
|
||||
return;
|
||||
}
|
||||
const contentDiv = node.querySelector('.message-content');
|
||||
if (contentDiv) {
|
||||
contentDiv.innerHTML = `
|
||||
<div>${content}</div>
|
||||
<div class="message-time">${new Date().toLocaleTimeString()}</div>
|
||||
`;
|
||||
if (knowledgeUsed && knowledgeUsed.length > 0) {
|
||||
const knowledgeDiv = document.createElement('div');
|
||||
knowledgeDiv.className = 'knowledge-info';
|
||||
knowledgeDiv.innerHTML = `
|
||||
<i class="fas fa-lightbulb me-1"></i>
|
||||
使用了知识库: ${knowledgeUsed.map(k => k.question || k.source || '实时数据').join(', ')}
|
||||
`;
|
||||
contentDiv.appendChild(knowledgeDiv);
|
||||
}
|
||||
if (isError) {
|
||||
contentDiv.style.borderLeft = '4px solid #dc3545';
|
||||
} else {
|
||||
contentDiv.style.borderLeft = '';
|
||||
}
|
||||
}
|
||||
const messagesContainer = document.getElementById('chat-messages');
|
||||
messagesContainer.scrollTop = messagesContainer.scrollHeight;
|
||||
}
|
||||
|
||||
addMessage(role, content, knowledgeUsed = null, isError = false) {
|
||||
const messagesContainer = document.getElementById('chat-messages');
|
||||
|
||||
@@ -603,16 +813,21 @@ class TSPDashboard {
|
||||
|
||||
async loadAgentData() {
|
||||
try {
|
||||
const response = await fetch('/api/agent/status');
|
||||
const data = await response.json();
|
||||
const [statusResp, toolsResp] = await Promise.all([
|
||||
fetch('/api/agent/status'),
|
||||
fetch('/api/agent/tools/stats')
|
||||
]);
|
||||
const data = await statusResp.json();
|
||||
const toolsData = await toolsResp.json();
|
||||
|
||||
if (data.success) {
|
||||
document.getElementById('agent-current-state').textContent = data.status || '未知';
|
||||
document.getElementById('agent-active-goals').textContent = data.active_goals || 0;
|
||||
document.getElementById('agent-available-tools').textContent = data.available_tools || 0;
|
||||
const tools = (toolsData.success ? toolsData.tools : (data.tools || [])) || [];
|
||||
document.getElementById('agent-available-tools').textContent = tools.length || 0;
|
||||
|
||||
// 更新工具列表
|
||||
this.updateToolsList(data.tools || []);
|
||||
// 更新工具列表(使用真实统计)
|
||||
this.updateToolsList(tools);
|
||||
|
||||
// 更新执行历史
|
||||
this.updateAgentExecutionHistory(data.execution_history || []);
|
||||
@@ -624,27 +839,64 @@ class TSPDashboard {
|
||||
|
||||
updateToolsList(tools) {
|
||||
const toolsList = document.getElementById('tools-list');
|
||||
if (tools.length === 0) {
|
||||
if (!tools || tools.length === 0) {
|
||||
toolsList.innerHTML = '<div class="empty-state"><i class="fas fa-tools"></i><p>暂无工具</p></div>';
|
||||
return;
|
||||
}
|
||||
|
||||
const toolsHtml = tools.map(tool => `
|
||||
<div class="d-flex justify-content-between align-items-center mb-2">
|
||||
<div>
|
||||
<strong>${tool.name}</strong>
|
||||
<br>
|
||||
<small class="text-muted">使用次数: ${tool.usage_count || 0}</small>
|
||||
const toolsHtml = tools.map(tool => {
|
||||
const usage = tool.usage_count || 0;
|
||||
const success = Math.round((tool.success_rate || 0) * 100);
|
||||
const meta = tool.metadata || {};
|
||||
return `
|
||||
<div class="d-flex justify-content-between align-items-center mb-2">
|
||||
<div>
|
||||
<strong>${tool.name}</strong>
|
||||
${meta.description ? `<div class="text-muted small">${meta.description}</div>` : ''}
|
||||
<small class="text-muted">使用次数: ${usage}</small>
|
||||
</div>
|
||||
<div>
|
||||
<span class="badge ${success >= 80 ? 'bg-success' : success >= 50 ? 'bg-warning' : 'bg-secondary'}">${success}%</span>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<span class="badge ${tool.success_rate >= 0.8 ? 'bg-success' : 'bg-warning'}">
|
||||
${Math.round((tool.success_rate || 0) * 100)}%
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
`).join('');
|
||||
`;
|
||||
}).join('');
|
||||
|
||||
toolsList.innerHTML = toolsHtml;
|
||||
|
||||
// 追加自定义工具注册入口
|
||||
const addDiv = document.createElement('div');
|
||||
addDiv.className = 'mt-3';
|
||||
addDiv.innerHTML = `
|
||||
<div class="input-group input-group-sm">
|
||||
<input type="text" id="custom-tool-name" class="form-control" placeholder="自定义工具名称">
|
||||
<input type="text" id="custom-tool-desc" class="form-control" placeholder="描述(可选)">
|
||||
<button class="btn btn-outline-primary" id="register-tool-btn">注册</button>
|
||||
</div>
|
||||
`;
|
||||
toolsList.appendChild(addDiv);
|
||||
document.getElementById('register-tool-btn').addEventListener('click', async () => {
|
||||
const name = document.getElementById('custom-tool-name').value.trim();
|
||||
const description = document.getElementById('custom-tool-desc').value.trim();
|
||||
if (!name) { this.showNotification('请输入工具名称', 'warning'); return; }
|
||||
try {
|
||||
const resp = await fetch('/api/agent/tools/register', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ name, description })
|
||||
});
|
||||
const res = await resp.json();
|
||||
if (res.success) {
|
||||
this.showNotification('工具注册成功', 'success');
|
||||
this.loadAgentData();
|
||||
} else {
|
||||
this.showNotification(res.error || '工具注册失败', 'error');
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('注册工具失败:', e);
|
||||
this.showNotification('注册工具失败', 'error');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
updateExecutionHistory(history) {
|
||||
@@ -1349,6 +1601,32 @@ class TSPDashboard {
|
||||
<small class="text-muted">${workorder.satisfaction_score}/5.0</small>
|
||||
</div>
|
||||
` : ''}
|
||||
<h6 class="mt-3">AI建议与人工描述</h6>
|
||||
<div class="border p-3 rounded">
|
||||
<div class="mb-2">
|
||||
<button class="btn btn-sm btn-outline-primary" onclick="dashboard.generateAISuggestion(${workorder.id})">
|
||||
<i class="fas fa-magic me-1"></i>生成AI建议
|
||||
</button>
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<label class="form-label">AI建议</label>
|
||||
<textarea id="aiSuggestion_${workorder.id}" class="form-control" rows="4" placeholder="点击上方按钮生成..." readonly></textarea>
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<label class="form-label">人工描述</label>
|
||||
<textarea id="humanResolution_${workorder.id}" class="form-control" rows="3" placeholder="请填写人工处理描述..."></textarea>
|
||||
</div>
|
||||
<div class="d-flex align-items-center gap-2 mb-2">
|
||||
<button class="btn btn-sm btn-outline-success" onclick="dashboard.saveHumanResolution(${workorder.id})">
|
||||
<i class="fas fa-save me-1"></i>保存人工描述并评估
|
||||
</button>
|
||||
<span id="aiSim_${workorder.id}" class="badge bg-secondary">相似度: --</span>
|
||||
<span id="aiApproved_${workorder.id}" class="badge bg-secondary">未审批</span>
|
||||
<button id="approveBtn_${workorder.id}" class="btn btn-sm btn-outline-primary" onclick="dashboard.approveToKnowledge(${workorder.id})" disabled>
|
||||
<i class="fas fa-check me-1"></i>入库
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1582,22 +1860,19 @@ class TSPDashboard {
|
||||
|
||||
async downloadTemplate() {
|
||||
try {
|
||||
const response = await fetch('/api/workorders/import/template');
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
// 创建下载链接
|
||||
const link = document.createElement('a');
|
||||
link.href = result.template_url;
|
||||
link.download = '工单导入模板.xlsx';
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
|
||||
this.showNotification('模板下载成功', 'success');
|
||||
} else {
|
||||
throw new Error(result.error || '下载模板失败');
|
||||
}
|
||||
// 直接请求文件接口,避免浏览器跨源/权限限制
|
||||
const resp = await fetch('/api/workorders/import/template/file');
|
||||
if (!resp.ok) throw new Error('下载接口返回错误');
|
||||
const blob = await resp.blob();
|
||||
const blobUrl = window.URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.href = blobUrl;
|
||||
a.download = '工单导入模板.xlsx';
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
window.URL.revokeObjectURL(blobUrl);
|
||||
this.showNotification('模板下载成功', 'success');
|
||||
} catch (error) {
|
||||
console.error('下载模板失败:', error);
|
||||
this.showNotification('下载模板失败: ' + error.message, 'error');
|
||||
@@ -2348,11 +2623,40 @@ class TSPDashboard {
|
||||
}
|
||||
|
||||
updateSettingsDisplay(settings) {
|
||||
if (settings.api_timeout) document.getElementById('api-timeout').value = settings.api_timeout;
|
||||
if (settings.max_history) document.getElementById('max-history').value = settings.max_history;
|
||||
if (settings.refresh_interval) document.getElementById('refresh-interval').value = settings.refresh_interval;
|
||||
if (settings.api_timeout !== undefined) document.getElementById('api-timeout').value = settings.api_timeout;
|
||||
if (settings.max_history !== undefined) document.getElementById('max-history').value = settings.max_history;
|
||||
if (settings.refresh_interval !== undefined) document.getElementById('refresh-interval').value = settings.refresh_interval;
|
||||
if (settings.auto_monitoring !== undefined) document.getElementById('auto-monitoring').checked = settings.auto_monitoring;
|
||||
if (settings.agent_mode !== undefined) document.getElementById('agent-mode').checked = settings.agent_mode;
|
||||
// 新增:API与模型、端口、日志级别(如页面存在对应输入框则填充)
|
||||
const map = [
|
||||
['api-provider','api_provider'],
|
||||
['api-base-url','api_base_url'],
|
||||
['api-key','api_key'],
|
||||
['model-name','model_name'],
|
||||
['model-temperature','model_temperature'],
|
||||
['model-max-tokens','model_max_tokens'],
|
||||
['server-port','server_port'],
|
||||
['websocket-port','websocket_port'],
|
||||
['log-level','log_level']
|
||||
];
|
||||
map.forEach(([id, key]) => {
|
||||
const el = document.getElementById(id);
|
||||
if (el && settings[key] !== undefined) el.value = settings[key];
|
||||
});
|
||||
|
||||
// 更新温度滑块显示值
|
||||
const tempSlider = document.getElementById('model-temperature');
|
||||
const tempValue = document.getElementById('temperature-value');
|
||||
if (tempSlider && tempValue) {
|
||||
tempSlider.addEventListener('input', function() {
|
||||
tempValue.textContent = this.value;
|
||||
});
|
||||
tempValue.textContent = tempSlider.value;
|
||||
}
|
||||
|
||||
// 更新服务状态显示
|
||||
this.updateServiceStatus(settings);
|
||||
}
|
||||
|
||||
async saveSystemSettings() {
|
||||
@@ -2361,7 +2665,16 @@ class TSPDashboard {
|
||||
max_history: parseInt(document.getElementById('max-history').value),
|
||||
refresh_interval: parseInt(document.getElementById('refresh-interval').value),
|
||||
auto_monitoring: document.getElementById('auto-monitoring').checked,
|
||||
agent_mode: document.getElementById('agent-mode').checked
|
||||
agent_mode: document.getElementById('agent-mode').checked,
|
||||
api_provider: document.getElementById('api-provider')?.value || '',
|
||||
api_base_url: document.getElementById('api-base-url')?.value || '',
|
||||
api_key: document.getElementById('api-key')?.value || '',
|
||||
model_name: document.getElementById('model-name')?.value || '',
|
||||
model_temperature: parseFloat(document.getElementById('model-temperature')?.value || 0.7),
|
||||
model_max_tokens: parseInt(document.getElementById('model-max-tokens')?.value || 1000),
|
||||
server_port: parseInt(document.getElementById('server-port')?.value || 5000),
|
||||
websocket_port: parseInt(document.getElementById('websocket-port')?.value || 8765),
|
||||
log_level: document.getElementById('log-level')?.value || 'INFO'
|
||||
};
|
||||
|
||||
try {
|
||||
@@ -2385,6 +2698,113 @@ class TSPDashboard {
|
||||
}
|
||||
}
|
||||
|
||||
// 更新服务状态显示
|
||||
updateServiceStatus(settings) {
|
||||
// 更新仪表板服务状态卡片
|
||||
if (settings.current_server_port !== undefined) {
|
||||
const webPortEl = document.getElementById('web-port-status');
|
||||
if (webPortEl) webPortEl.textContent = settings.current_server_port;
|
||||
}
|
||||
if (settings.current_websocket_port !== undefined) {
|
||||
const wsPortEl = document.getElementById('ws-port-status');
|
||||
if (wsPortEl) wsPortEl.textContent = settings.current_websocket_port;
|
||||
}
|
||||
if (settings.log_level !== undefined) {
|
||||
const logLevelEl = document.getElementById('log-level-status');
|
||||
if (logLevelEl) logLevelEl.textContent = settings.log_level;
|
||||
}
|
||||
if (settings.uptime_seconds !== undefined) {
|
||||
const uptimeEl = document.getElementById('uptime-status');
|
||||
if (uptimeEl) {
|
||||
const hours = Math.floor(settings.uptime_seconds / 3600);
|
||||
const minutes = Math.floor((settings.uptime_seconds % 3600) / 60);
|
||||
uptimeEl.textContent = `${hours}小时${minutes}分钟`;
|
||||
}
|
||||
}
|
||||
|
||||
// 更新系统设置页面的当前端口显示
|
||||
const currentPortEl = document.getElementById('current-server-port');
|
||||
if (currentPortEl && settings.current_server_port !== undefined) {
|
||||
currentPortEl.textContent = settings.current_server_port;
|
||||
}
|
||||
}
|
||||
|
||||
// 刷新服务状态
|
||||
async refreshServiceStatus() {
|
||||
try {
|
||||
const response = await fetch('/api/settings');
|
||||
const settings = await response.json();
|
||||
this.updateServiceStatus(settings);
|
||||
this.showNotification('服务状态已刷新', 'success');
|
||||
} catch (error) {
|
||||
console.error('刷新服务状态失败:', error);
|
||||
this.showNotification('刷新服务状态失败', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// 测试API连接
|
||||
async testApiConnection() {
|
||||
try {
|
||||
const apiProvider = document.getElementById('api-provider').value;
|
||||
const apiBaseUrl = document.getElementById('api-base-url').value;
|
||||
const apiKey = document.getElementById('api-key').value;
|
||||
const modelName = document.getElementById('model-name').value;
|
||||
|
||||
const response = await fetch('/api/test/connection', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
api_provider: apiProvider,
|
||||
api_base_url: apiBaseUrl,
|
||||
api_key: apiKey,
|
||||
model_name: modelName
|
||||
})
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
if (result.success) {
|
||||
this.showNotification(`API连接测试成功: ${result.message}`, 'success');
|
||||
} else {
|
||||
this.showNotification(`API连接测试失败: ${result.error}`, 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('API连接测试失败:', error);
|
||||
this.showNotification('API连接测试失败', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// 测试模型回答
|
||||
async testModelResponse() {
|
||||
try {
|
||||
const testMessage = prompt('请输入测试消息:', '你好,请简单介绍一下你自己');
|
||||
if (!testMessage) return;
|
||||
|
||||
const response = await fetch('/api/test/model', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
test_message: testMessage
|
||||
})
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
if (result.success) {
|
||||
const message = `模型回答测试成功:\n\n问题: ${result.test_message}\n\n回答: ${result.response}\n\n响应时间: ${result.response_time}`;
|
||||
alert(message);
|
||||
this.showNotification('模型回答测试成功', 'success');
|
||||
} else {
|
||||
this.showNotification(`模型回答测试失败: ${result.error}`, 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('模型回答测试失败:', error);
|
||||
this.showNotification('模型回答测试失败', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
async loadSystemInfo() {
|
||||
try {
|
||||
const response = await fetch('/api/system/info');
|
||||
|
||||
Reference in New Issue
Block a user