主要更新: - 统一规约管理视图(全局/项目规约共享表格) - 项目树形导航(看板/项目规约子菜单) - 智能高亮与状态持久化 - 移动端响应式支持(汉堡菜单) - 规约类型更新为7个专业分类 - 文件清理(85→15文件,减少82%) 修复问题: - 修复创建项目功能(JavaScript语法错误) - 修复协作规约错误高亮 - 修复看板需要点击2次才高亮 - 修复项目树自动收起问题 新增工具: - debug.html(项目创建测试) - test.html(移动端测试) - status.html(系统诊断) 技术改进: - 上下文状态管理(currentRuleContext) - 展开状态持久化(projectExpandedState) - 触摸事件支持 - 移除console.log提升兼容性
360 lines
11 KiB
JavaScript
360 lines
11 KiB
JavaScript
const express = require('express');
|
|
const sqlite3 = require('sqlite3').verbose();
|
|
const path = require('path');
|
|
|
|
const app = express();
|
|
const PORT = 3000;
|
|
|
|
// 中间件
|
|
app.use(express.json());
|
|
app.use(express.static('public'));
|
|
|
|
// 数据库连接
|
|
const db = new sqlite3.Database('./tasks.db', (err) => {
|
|
if (err) {
|
|
console.error('❌ 数据库连接失败:', err.message);
|
|
process.exit(1);
|
|
}
|
|
console.log('✅ 已连接到 SQLite 数据库');
|
|
});
|
|
|
|
// 初始化数据库表
|
|
db.serialize(() => {
|
|
// 项目表
|
|
db.run(`CREATE TABLE IF NOT EXISTS projects (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
name TEXT NOT NULL,
|
|
description TEXT,
|
|
status TEXT DEFAULT 'active',
|
|
created_by TEXT DEFAULT 'human',
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
)`);
|
|
|
|
// 任务表
|
|
db.run(`CREATE TABLE IF NOT EXISTS tasks (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
project_id INTEGER NOT NULL,
|
|
parent_id INTEGER,
|
|
title TEXT NOT NULL,
|
|
description TEXT,
|
|
type TEXT DEFAULT 'development',
|
|
priority TEXT DEFAULT 'normal',
|
|
status TEXT DEFAULT 'initial',
|
|
assigned_to TEXT,
|
|
created_by TEXT DEFAULT 'human',
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
FOREIGN KEY (project_id) REFERENCES projects(id),
|
|
FOREIGN KEY (parent_id) REFERENCES tasks(id)
|
|
)`);
|
|
|
|
// 智能体表
|
|
db.run(`CREATE TABLE IF NOT EXISTS agents (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
name TEXT UNIQUE NOT NULL,
|
|
type TEXT,
|
|
capabilities TEXT,
|
|
status TEXT DEFAULT 'idle',
|
|
current_task TEXT,
|
|
completed_tasks INTEGER DEFAULT 0,
|
|
last_heartbeat DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
)`);
|
|
|
|
// 附件表
|
|
db.run(`CREATE TABLE IF NOT EXISTS attachments (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
task_id INTEGER NOT NULL,
|
|
filename TEXT NOT NULL,
|
|
filepath TEXT NOT NULL,
|
|
size INTEGER,
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
FOREIGN KEY (task_id) REFERENCES tasks(id)
|
|
)`);
|
|
|
|
// 规约表 (支持全局和项目级别)
|
|
db.run(`CREATE TABLE IF NOT EXISTS rules (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
project_id INTEGER,
|
|
rule_no TEXT NOT NULL,
|
|
rule_type TEXT NOT NULL,
|
|
description TEXT NOT NULL,
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
FOREIGN KEY (project_id) REFERENCES projects(id)
|
|
)`);
|
|
|
|
console.log('✅ 数据库表已初始化');
|
|
});
|
|
|
|
// ==================== API 路由 ====================
|
|
|
|
// 统计信息
|
|
app.get('/api/stats', (req, res) => {
|
|
const stats = {};
|
|
|
|
db.get('SELECT COUNT(*) as count FROM projects', (err, row) => {
|
|
stats.projects = row ? row.count : 0;
|
|
|
|
db.get('SELECT COUNT(*) as count FROM tasks', (err, row) => {
|
|
stats.tasks = row ? row.count : 0;
|
|
|
|
db.get('SELECT COUNT(*) as count FROM tasks WHERE status = "in_progress"', (err, row) => {
|
|
stats.in_progress_tasks = row ? row.count : 0;
|
|
|
|
db.get('SELECT COUNT(*) as count FROM tasks WHERE status = "completed"', (err, row) => {
|
|
stats.completed_tasks = row ? row.count : 0;
|
|
|
|
db.get('SELECT COUNT(*) as count FROM agents', (err, row) => {
|
|
stats.total_agents = row ? row.count : 0;
|
|
|
|
db.get('SELECT COUNT(*) as count FROM agents WHERE status = "busy"', (err, row) => {
|
|
stats.active_agents = row ? row.count : 0;
|
|
res.json(stats);
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
// 项目管理
|
|
app.get('/api/projects', (req, res) => {
|
|
db.all('SELECT * FROM projects ORDER BY created_at DESC', (err, rows) => {
|
|
if (err) return res.status(500).json({ error: err.message });
|
|
res.json(rows || []);
|
|
});
|
|
});
|
|
|
|
app.post('/api/projects', (req, res) => {
|
|
const { name, description, created_by = 'human' } = req.body;
|
|
|
|
db.run(
|
|
'INSERT INTO projects (name, description, created_by) VALUES (?, ?, ?)',
|
|
[name, description, created_by],
|
|
function(err) {
|
|
if (err) return res.status(500).json({ error: err.message });
|
|
res.json({ id: this.lastID, name, description, created_by });
|
|
}
|
|
);
|
|
});
|
|
|
|
app.get('/api/projects/:id', (req, res) => {
|
|
db.get('SELECT * FROM projects WHERE id = ?', [req.params.id], (err, row) => {
|
|
if (err) return res.status(500).json({ error: err.message });
|
|
if (!row) return res.status(404).json({ error: 'Project not found' });
|
|
res.json(row);
|
|
});
|
|
});
|
|
|
|
app.delete('/api/projects/:id', (req, res) => {
|
|
// 先删除项目下的所有任务
|
|
db.run('DELETE FROM tasks WHERE project_id = ?', [req.params.id], (err) => {
|
|
if (err) return res.status(500).json({ error: err.message });
|
|
|
|
// 然后删除项目
|
|
db.run('DELETE FROM projects WHERE id = ?', [req.params.id], function(err) {
|
|
if (err) return res.status(500).json({ error: err.message });
|
|
if (this.changes === 0) return res.status(404).json({ error: 'Project not found' });
|
|
res.json({ success: true });
|
|
});
|
|
});
|
|
});
|
|
|
|
// 任务管理
|
|
app.get('/api/tasks', (req, res) => {
|
|
const { project_id } = req.query;
|
|
let query = 'SELECT t.*, (SELECT COUNT(*) FROM tasks WHERE parent_id = t.id) as subtask_count, (SELECT COUNT(*) FROM attachments WHERE task_id = t.id) as attachment_count FROM tasks t';
|
|
let params = [];
|
|
|
|
if (project_id) {
|
|
query += ' WHERE t.project_id = ?';
|
|
params.push(project_id);
|
|
}
|
|
|
|
query += ' ORDER BY t.created_at DESC';
|
|
|
|
db.all(query, params, (err, rows) => {
|
|
if (err) return res.status(500).json({ error: err.message });
|
|
res.json(rows || []);
|
|
});
|
|
});
|
|
|
|
app.post('/api/tasks', (req, res) => {
|
|
const { project_id, parent_id, title, description, type = 'development', priority = 'normal', status = 'initial', assigned_to, created_by = 'human' } = req.body;
|
|
|
|
db.run(
|
|
'INSERT INTO tasks (project_id, parent_id, title, description, type, priority, status, assigned_to, created_by) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)',
|
|
[project_id, parent_id || null, title, description, type, priority, status, assigned_to || null, created_by],
|
|
function(err) {
|
|
if (err) return res.status(500).json({ error: err.message });
|
|
res.json({ id: this.lastID, project_id, title, type, priority, status });
|
|
}
|
|
);
|
|
});
|
|
|
|
app.get('/api/tasks/:id', (req, res) => {
|
|
db.get('SELECT * FROM tasks WHERE id = ?', [req.params.id], (err, task) => {
|
|
if (err) return res.status(500).json({ error: err.message });
|
|
if (!task) return res.status(404).json({ error: 'Task not found' });
|
|
|
|
// 获取附件
|
|
db.all('SELECT * FROM attachments WHERE task_id = ?', [req.params.id], (err, attachments) => {
|
|
task.attachments = attachments || [];
|
|
|
|
// 获取子任务
|
|
db.all('SELECT * FROM tasks WHERE parent_id = ?', [req.params.id], (err, subtasks) => {
|
|
task.subtasks = subtasks || [];
|
|
res.json(task);
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
app.put('/api/tasks/:id', (req, res) => {
|
|
const updates = [];
|
|
const values = [];
|
|
|
|
['status', 'type', 'priority', 'assigned_to', 'title', 'description'].forEach(field => {
|
|
if (req.body[field] !== undefined) {
|
|
updates.push(`${field} = ?`);
|
|
values.push(req.body[field]);
|
|
}
|
|
});
|
|
|
|
if (updates.length === 0) {
|
|
return res.status(400).json({ error: 'No fields to update' });
|
|
}
|
|
|
|
values.push(req.params.id);
|
|
|
|
db.run(
|
|
`UPDATE tasks SET ${updates.join(', ')} WHERE id = ?`,
|
|
values,
|
|
function(err) {
|
|
if (err) return res.status(500).json({ error: err.message });
|
|
if (this.changes === 0) return res.status(404).json({ error: 'Task not found' });
|
|
res.json({ success: true });
|
|
}
|
|
);
|
|
});
|
|
|
|
app.delete('/api/tasks/:id', (req, res) => {
|
|
db.run('DELETE FROM tasks WHERE id = ?', [req.params.id], function(err) {
|
|
if (err) return res.status(500).json({ error: err.message });
|
|
res.json({ success: true });
|
|
});
|
|
});
|
|
|
|
// 智能体管理
|
|
app.get('/api/agents', (req, res) => {
|
|
db.all('SELECT * FROM agents ORDER BY name', (err, rows) => {
|
|
if (err) return res.status(500).json({ error: err.message });
|
|
res.json(rows || []);
|
|
});
|
|
});
|
|
|
|
app.post('/api/agents', (req, res) => {
|
|
const { name, type, capabilities } = req.body;
|
|
|
|
db.run(
|
|
'INSERT INTO agents (name, type, capabilities) VALUES (?, ?, ?)',
|
|
[name, type, JSON.stringify(capabilities)],
|
|
function(err) {
|
|
if (err) return res.status(500).json({ error: err.message });
|
|
res.json({ id: this.lastID, name, type, capabilities });
|
|
}
|
|
);
|
|
});
|
|
|
|
// 规约管理 (支持多条目)
|
|
// 获取全局规约列表
|
|
app.get('/api/rules/global', (req, res) => {
|
|
db.all('SELECT * FROM rules WHERE project_id IS NULL ORDER BY rule_no', (err, rows) => {
|
|
if (err) return res.status(500).json({ error: err.message });
|
|
res.json(rows || []);
|
|
});
|
|
});
|
|
|
|
// 获取项目规约列表
|
|
app.get('/api/rules/project/:projectId', (req, res) => {
|
|
db.all('SELECT * FROM rules WHERE project_id = ? ORDER BY rule_no', [req.params.projectId], (err, rows) => {
|
|
if (err) return res.status(500).json({ error: err.message });
|
|
res.json(rows || []);
|
|
});
|
|
});
|
|
|
|
// 获取单个规约
|
|
app.get('/api/rules/:id', (req, res) => {
|
|
db.get('SELECT * FROM rules WHERE id = ?', [req.params.id], (err, row) => {
|
|
if (err) return res.status(500).json({ error: err.message });
|
|
if (!row) return res.status(404).json({ error: 'Rule not found' });
|
|
res.json(row);
|
|
});
|
|
});
|
|
|
|
// 创建规约
|
|
app.post('/api/rules', (req, res) => {
|
|
const { project_id, rule_no, rule_type, description } = req.body;
|
|
|
|
db.run(
|
|
'INSERT INTO rules (project_id, rule_no, rule_type, description) VALUES (?, ?, ?, ?)',
|
|
[project_id || null, rule_no, rule_type, description],
|
|
function(err) {
|
|
if (err) return res.status(500).json({ error: err.message });
|
|
res.json({ id: this.lastID, project_id, rule_no, rule_type, description });
|
|
}
|
|
);
|
|
});
|
|
|
|
// 更新规约
|
|
app.put('/api/rules/:id', (req, res) => {
|
|
const { rule_no, rule_type, description } = req.body;
|
|
const updates = [];
|
|
const values = [];
|
|
|
|
if (rule_no !== undefined) { updates.push('rule_no = ?'); values.push(rule_no); }
|
|
if (rule_type !== undefined) { updates.push('rule_type = ?'); values.push(rule_type); }
|
|
if (description !== undefined) { updates.push('description = ?'); values.push(description); }
|
|
updates.push('updated_at = CURRENT_TIMESTAMP');
|
|
|
|
if (values.length === 0) {
|
|
return res.status(400).json({ error: 'No fields to update' });
|
|
}
|
|
|
|
values.push(req.params.id);
|
|
|
|
db.run(
|
|
`UPDATE rules SET ${updates.join(', ')} WHERE id = ?`,
|
|
values,
|
|
function(err) {
|
|
if (err) return res.status(500).json({ error: err.message });
|
|
res.json({ success: true });
|
|
}
|
|
);
|
|
});
|
|
|
|
// 删除规约
|
|
app.delete('/api/rules/:id', (req, res) => {
|
|
db.run('DELETE FROM rules WHERE id = ?', [req.params.id], function(err) {
|
|
if (err) return res.status(500).json({ error: err.message });
|
|
res.json({ success: true });
|
|
});
|
|
});
|
|
|
|
|
|
// 启动服务器
|
|
app.listen(PORT, () => {
|
|
console.log(`🚀 多智能体任务管理系统已启动`);
|
|
console.log(` 本地访问: http://localhost:${PORT}`);
|
|
console.log(` 远程访问: http://10.0.6.5:${PORT}`);
|
|
});
|
|
|
|
// 优雅关闭
|
|
process.on('SIGINT', () => {
|
|
db.close((err) => {
|
|
if (err) console.error(err);
|
|
console.log('\n👋 服务器已关闭');
|
|
process.exit(0);
|
|
});
|
|
});
|