feat:1.历史记录重构UI重构2.置顶功能实现

This commit is contained in:
liailing1026
2026-02-27 11:39:20 +08:00
parent dad1ac2e51
commit c009db12a6
6 changed files with 376 additions and 149 deletions

View File

@@ -66,10 +66,10 @@ class MultiAgentTaskCRUD:
def get_recent(
db: Session, limit: int = 20, offset: int = 0
) -> List[MultiAgentTask]:
"""获取最近的任务记录"""
"""获取最近的任务记录,置顶的排在最前面"""
return (
db.query(MultiAgentTask)
.order_by(MultiAgentTask.created_at.desc())
.order_by(MultiAgentTask.is_pinned.desc(), MultiAgentTask.created_at.desc())
.offset(offset)
.limit(limit)
.all()
@@ -184,6 +184,18 @@ class MultiAgentTaskCRUD:
db.refresh(task)
return task
@staticmethod
def update_is_pinned(
db: Session, task_id: str, is_pinned: bool
) -> Optional[MultiAgentTask]:
"""更新任务置顶状态"""
task = db.query(MultiAgentTask).filter(MultiAgentTask.task_id == task_id).first()
if task:
task.is_pinned = is_pinned
db.commit()
db.refresh(task)
return task
@staticmethod
def append_rehearsal_log(
db: Session, task_id: str, log_entry: dict

View File

@@ -6,7 +6,7 @@ SQLAlchemy ORM 数据模型
import uuid
from datetime import datetime, timezone
from enum import Enum as PyEnum
from sqlalchemy import Column, String, Text, DateTime, Integer, Enum, Index, ForeignKey
from sqlalchemy import Column, String, Text, DateTime, Integer, Enum, Index, ForeignKey, Boolean
from sqlalchemy.dialects.postgresql import JSONB
from sqlalchemy.orm import relationship
@@ -48,6 +48,7 @@ class MultiAgentTask(Base):
execution_id = Column(String(64))
rehearsal_log = Column(JSONB)
branches = Column(JSONB) # 任务大纲探索分支数据
is_pinned = Column(Boolean, default=False, nullable=False) # 置顶标志
created_at = Column(DateTime(timezone=True), default=utc_now)
updated_at = Column(DateTime(timezone=True), default=utc_now, onupdate=utc_now)
@@ -74,6 +75,7 @@ class MultiAgentTask(Base):
"execution_id": self.execution_id,
"rehearsal_log": self.rehearsal_log,
"branches": self.branches,
"is_pinned": self.is_pinned,
"created_at": self.created_at.isoformat() if self.created_at else None,
"updated_at": self.updated_at.isoformat() if self.updated_at else None,
}

View File

@@ -331,10 +331,11 @@ def handle_execute_plan_optimized_ws(data):
MultiAgentTaskCRUD.update_status(db, task_id, TaskStatus.STOPPED)
print(f"[execute_plan_optimized] 用户停止执行,跳过保存执行数据,已完成 {completed_steps_count}/{plan_steps_count} 步骤task_id={task_id}")
# 任务大纲(用户可能编辑了)仍然保存
if plan:
MultiAgentTaskCRUD.update_task_outline(db, task_id, plan)
print(f"[execute_plan_optimized] 已保存 task_outline 到数据库,task_id={task_id}")
# # 任务大纲(用户可能编辑了)仍然保存
# # 注释原因:执行任务时不保存 task_outline避免覆盖导致步骤 ID 变化与 agent_scores 不匹配
# if plan:
# MultiAgentTaskCRUD.update_task_outline(db, task_id, plan)
# print(f"[execute_plan_optimized] 已保存 task_outline 到数据库task_id={task_id}")
# # 保存 assigned_agents每个步骤使用的 agent
# # 注释原因assigned_agents 只在生成阶段由用户手动选择写入,执行时不覆盖
@@ -1849,6 +1850,7 @@ def handle_get_plans(data):
"status": task.status.value if task.status else 'unknown',
"execution_count": task.execution_count or 0,
"created_at": task.created_at.isoformat() if task.created_at else None,
"is_pinned": task.is_pinned or False, # 置顶标志
# 完整数据用于恢复
"task_outline": task.task_outline,
"assigned_agents": task.assigned_agents,
@@ -2060,6 +2062,54 @@ def handle_delete_plan(data):
})
@socketio.on('pin_plan')
def handle_pin_plan(data):
"""
WebSocket版本置顶/取消置顶历史任务
"""
# socketio 包装: data = { id: 'pin_plan-xxx', action: 'pin_plan', data: { id: 'ws_req_xxx', data: {...} } }
request_id = data.get('id') # socketio 包装的 id
incoming_data = data.get('data', {}).get('data', {}) # 真正的请求数据
plan_id = incoming_data.get('plan_id')
is_pinned = incoming_data.get('is_pinned', True) # 默认为置顶
if not plan_id:
emit('response', {
'id': request_id,
'status': 'error',
'error': '缺少 plan_idtask_id'
})
return
try:
with get_db_context() as db:
task = MultiAgentTaskCRUD.update_is_pinned(db, plan_id, is_pinned)
if not task:
emit('response', {
'id': request_id,
'status': 'error',
'error': f'任务不存在: {plan_id}'
})
return
# 通知所有客户端刷新历史列表
socketio.emit('history_updated', {'task_id': plan_id})
emit('response', {
'id': request_id,
'status': 'success',
'data': {"message": "置顶成功" if is_pinned else "取消置顶成功"}
})
except Exception as e:
emit('response', {
'id': request_id,
'status': 'error',
'error': str(e)
})
@socketio.on('save_branches')
def handle_save_branches(data):
"""