新增 v2.0 Web 管理界面

新界面功能:
 项目管理 - 创建、查看、选择项目
 项目详情 - 任务统计、规约查看、共享笔记
 任务列表 - 按项目/状态过滤,支持 Markdown 渲染
 智能体列表 - 查看状态和心跳
 全局规约 - 编辑和查看全局协作规约
 项目规约 - 每个项目单独设置规约
 信息共享清单 - 添加和查看项目笔记
 实时统计 - 6个统计卡片展示

特性:
- 4个标签页:项目、任务、智能体、规约
- Markdown 实时渲染(使用 marked.js)
- 模态框表单(创建项目/任务,编辑规约)
- 自动刷新(每30秒)
- 响应式设计

旧界面保留为 index-v1.html
This commit is contained in:
work-1
2026-02-15 21:51:05 +08:00
parent 62e280a9dd
commit f229b0cd97
2 changed files with 1098 additions and 214 deletions
+459
View File
@@ -0,0 +1,459 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>多智能体任务管理系统</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
padding: 20px;
}
.container {
max-width: 1400px;
margin: 0 auto;
}
header {
text-align: center;
color: white;
margin-bottom: 30px;
}
h1 {
font-size: 2.5em;
margin-bottom: 10px;
}
.stats {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 15px;
margin-bottom: 30px;
}
.stat-card {
background: white;
padding: 20px;
border-radius: 10px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
text-align: center;
}
.stat-card h3 {
color: #666;
font-size: 0.9em;
margin-bottom: 10px;
}
.stat-card .number {
font-size: 2em;
font-weight: bold;
color: #667eea;
}
.main-content {
display: grid;
grid-template-columns: 1fr 2fr;
gap: 20px;
}
.panel {
background: white;
border-radius: 10px;
padding: 20px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
.panel h2 {
color: #333;
margin-bottom: 20px;
padding-bottom: 10px;
border-bottom: 2px solid #667eea;
}
.agent-item, .task-item {
padding: 15px;
margin-bottom: 10px;
border-radius: 8px;
background: #f8f9fa;
border-left: 4px solid #667eea;
}
.agent-item.busy {
border-left-color: #f39c12;
background: #fff9e6;
}
.agent-item.offline {
border-left-color: #95a5a6;
background: #ecf0f1;
}
.task-item.pending {
border-left-color: #3498db;
}
.task-item.in_progress {
border-left-color: #f39c12;
background: #fff9e6;
}
.task-item.completed {
border-left-color: #27ae60;
background: #e8f8f5;
}
.badge {
display: inline-block;
padding: 4px 12px;
border-radius: 20px;
font-size: 0.85em;
font-weight: bold;
margin-left: 10px;
}
.badge.idle {
background: #3498db;
color: white;
}
.badge.busy {
background: #f39c12;
color: white;
}
.badge.pending {
background: #3498db;
color: white;
}
.badge.in_progress {
background: #f39c12;
color: white;
}
.badge.completed {
background: #27ae60;
color: white;
}
.badge.high {
background: #e74c3c;
color: white;
}
.badge.normal {
background: #3498db;
color: white;
}
.badge.low {
background: #95a5a6;
color: white;
}
button {
padding: 10px 20px;
border: none;
border-radius: 5px;
background: #667eea;
color: white;
font-weight: bold;
cursor: pointer;
transition: all 0.3s;
}
button:hover {
background: #764ba2;
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
}
.form-group {
margin-bottom: 15px;
}
.form-group label {
display: block;
margin-bottom: 5px;
color: #333;
font-weight: bold;
}
.form-group input, .form-group textarea, .form-group select {
width: 100%;
padding: 10px;
border: 1px solid #ddd;
border-radius: 5px;
font-size: 1em;
}
.form-group textarea {
resize: vertical;
min-height: 80px;
}
.task-meta {
font-size: 0.85em;
color: #666;
margin-top: 8px;
}
.empty-state {
text-align: center;
color: #999;
padding: 40px;
}
#createTaskForm {
margin-top: 20px;
}
.refresh-btn {
float: right;
padding: 5px 15px;
font-size: 0.9em;
}
</style>
</head>
<body>
<div class="container">
<header>
<h1>🤖 多智能体任务管理系统</h1>
<p>Multi-Agent Task Management System</p>
</header>
<div class="stats" id="stats">
<!-- 统计数据将动态加载 -->
</div>
<div class="main-content">
<div class="panel">
<h2>
智能体列表
<button class="refresh-btn" onclick="loadAgents()">刷新</button>
</h2>
<div id="agentList">
<div class="empty-state">加载中...</div>
</div>
</div>
<div class="panel">
<h2>
任务列表
<button class="refresh-btn" onclick="loadTasks()">刷新</button>
</h2>
<div id="taskList">
<div class="empty-state">加载中...</div>
</div>
<form id="createTaskForm">
<h3 style="margin-top: 30px; margin-bottom: 15px;">创建新任务</h3>
<div class="form-group">
<label>任务标题 *</label>
<input type="text" id="taskTitle" required placeholder="输入任务标题">
</div>
<div class="form-group">
<label>任务描述</label>
<textarea id="taskDescription" placeholder="详细描述任务内容"></textarea>
</div>
<div class="form-group">
<label>优先级</label>
<select id="taskPriority">
<option value="low"></option>
<option value="normal" selected>普通</option>
<option value="high"></option>
</select>
</div>
<button type="submit">创建任务</button>
</form>
</div>
</div>
</div>
<script>
const API_BASE = '';
// 加载统计数据
async function loadStats() {
try {
const response = await fetch(`${API_BASE}/api/stats`);
const stats = await response.json();
document.getElementById('stats').innerHTML = `
<div class="stat-card">
<h3>智能体总数</h3>
<div class="number">${stats.total_agents || 0}</div>
</div>
<div class="stat-card">
<h3>活跃智能体</h3>
<div class="number">${stats.active_agents || 0}</div>
</div>
<div class="stat-card">
<h3>待处理任务</h3>
<div class="number">${stats.pending_tasks || 0}</div>
</div>
<div class="stat-card">
<h3>进行中任务</h3>
<div class="number">${stats.in_progress_tasks || 0}</div>
</div>
<div class="stat-card">
<h3>已完成任务</h3>
<div class="number">${stats.completed_tasks || 0}</div>
</div>
<div class="stat-card">
<h3>任务总数</h3>
<div class="number">${stats.total_tasks || 0}</div>
</div>
`;
} catch (error) {
console.error('加载统计数据失败:', error);
}
}
// 加载智能体列表
async function loadAgents() {
try {
const response = await fetch(`${API_BASE}/api/agents`);
const agents = await response.json();
const agentList = document.getElementById('agentList');
if (agents.length === 0) {
agentList.innerHTML = '<div class="empty-state">暂无智能体注册</div>';
return;
}
agentList.innerHTML = agents.map(agent => {
const statusClass = agent.status === 'busy' ? 'busy' : 'idle';
const lastHeartbeat = new Date(agent.last_heartbeat).toLocaleString('zh-CN');
return `
<div class="agent-item ${statusClass}">
<strong>${agent.name}</strong>
<span class="badge ${agent.status}">${agent.status === 'idle' ? '空闲' : '忙碌'}</span>
<div class="task-meta">
类型: ${agent.type || '通用'} |
注册时间: ${new Date(agent.registered_at).toLocaleString('zh-CN')} |
最后心跳: ${lastHeartbeat}
</div>
</div>
`;
}).join('');
} catch (error) {
console.error('加载智能体列表失败:', error);
document.getElementById('agentList').innerHTML =
'<div class="empty-state">加载失败</div>';
}
}
// 加载任务列表
async function loadTasks() {
try {
const response = await fetch(`${API_BASE}/api/tasks`);
const tasks = await response.json();
const taskList = document.getElementById('taskList');
if (tasks.length === 0) {
taskList.innerHTML = '<div class="empty-state">暂无任务</div>';
return;
}
taskList.innerHTML = tasks.map(task => {
const statusText = {
'pending': '待处理',
'in_progress': '进行中',
'completed': '已完成'
}[task.status] || task.status;
const priorityText = {
'low': '低',
'normal': '普通',
'high': '高'
}[task.priority] || task.priority;
return `
<div class="task-item ${task.status}">
<strong>${task.title}</strong>
<span class="badge ${task.status}">${statusText}</span>
<span class="badge ${task.priority}">${priorityText}</span>
${task.description ? `<div style="margin-top: 8px; color: #666;">${task.description}</div>` : ''}
<div class="task-meta">
创建时间: ${new Date(task.created_at).toLocaleString('zh-CN')} |
${task.assigned_to ? `执行者: ${task.assigned_to}` : '未分配'} |
${task.completed_at ? `完成时间: ${new Date(task.completed_at).toLocaleString('zh-CN')}` : ''}
</div>
${task.result ? `<div style="margin-top: 8px; padding: 8px; background: #e8f4f8; border-radius: 4px;"><strong>结果:</strong> ${task.result}</div>` : ''}
</div>
`;
}).join('');
} catch (error) {
console.error('加载任务列表失败:', error);
document.getElementById('taskList').innerHTML =
'<div class="empty-state">加载失败</div>';
}
}
// 创建任务表单提交
document.getElementById('createTaskForm').addEventListener('submit', async (e) => {
e.preventDefault();
const title = document.getElementById('taskTitle').value;
const description = document.getElementById('taskDescription').value;
const priority = document.getElementById('taskPriority').value;
try {
const response = await fetch(`${API_BASE}/api/tasks`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
title,
description,
priority,
created_by: 'human'
})
});
const result = await response.json();
if (response.ok) {
alert('✅ 任务创建成功!');
document.getElementById('createTaskForm').reset();
loadTasks();
loadStats();
} else {
alert('❌ 创建失败: ' + result.error);
}
} catch (error) {
alert('❌ 创建失败: ' + error.message);
}
});
// 初始加载
loadStats();
loadAgents();
loadTasks();
// 自动刷新(每10秒)
setInterval(() => {
loadStats();
loadAgents();
loadTasks();
}, 10000);
</script>
</body>
</html>
+622 -197
View File
File diff suppressed because it is too large Load Diff