TaskPulse/backend/app/api/executions.py
Steven b04c0ce321 feat: agent avatars, task tags, search, edit/delete agents, cron readability, timezone fix
- Agent avatars: first-letter + deterministic color avatar in all views
- Agent management: edit (name/description) and delete with confirmation
- Execution API: validates agent existence, returns 410 if deleted
- Task tags: JSON array field, editable with tag pills UI
- Task search: by name (?q=) and by tags (?tags=) and by status
- Task edit: simplified to name/tags/description only (not agent params)
- Cron display: human-readable Chinese (e.g. '每5分钟', '每天 09:00')
- Timezone fix: UTC→local via dayjs.utc().local() across all pages
- Content area: full width (removed max-width:1200px constraints)
- Login page: standalone layout without sidebar
2026-06-15 23:33:28 +08:00

79 lines
2.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""API router — TaskExecution (reporting + query)."""
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.ext.asyncio import AsyncSession
from app.database import get_db
from app.schemas import ExecutionOut, ExecutionReport
from app.services import ExecutionService, TaskService, AgentService
router = APIRouter(prefix="/api/tasks/{task_id}/executions", tags=["executions"])
@router.post("", response_model=ExecutionOut, status_code=201)
async def report_execution(task_id: int, body: ExecutionReport,
db: AsyncSession = Depends(get_db)):
"""Agent reports execution result for a task."""
# Verify task exists
task_svc = TaskService(db)
task = await task_svc.get(task_id)
if not task:
raise HTTPException(404, "Task not found")
# Verify agent exists and is active
agent_svc = AgentService(db)
agent = await agent_svc.get(task.agent_id)
if not agent:
raise HTTPException(410, "Agent已被删除请重新注册")
if agent.status != "active":
raise HTTPException(403, "Agent已停用无法汇报")
exec_svc = ExecutionService(db)
record = await exec_svc.report_result(
task_id=task_id,
agent_id=task.agent_id,
status=body.status,
finished_at=body.finished_at,
duration_ms=body.duration_ms,
result=body.result,
log=body.log,
error_message=body.error_message,
)
# Update task's last_run info
await task_svc.mark_run(task_id, success=(body.status == "success"))
await db.commit()
return ExecutionOut(**record.__dict__)
@router.get("", response_model=list[ExecutionOut])
async def list_executions(
task_id: int,
limit: int = Query(50, ge=1, le=200),
offset: int = Query(0, ge=0),
db: AsyncSession = Depends(get_db),
):
exec_svc = ExecutionService(db)
records = await exec_svc.get_executions(task_id, limit=limit, offset=offset)
return [ExecutionOut(**r.__dict__) for r in records]
@router.get("/recent", response_model=list[ExecutionOut])
async def recent_executions(
limit: int = Query(100, ge=1, le=500),
db: AsyncSession = Depends(get_db),
):
"""Get recent executions across all tasks (for dashboard)."""
exec_svc = ExecutionService(db)
records = await exec_svc.get_recent_executions(limit=limit)
return [ExecutionOut(**r.__dict__) for r in records]
@router.get("/{execution_id}", response_model=ExecutionOut)
async def get_execution(execution_id: int, db: AsyncSession = Depends(get_db)):
exec_svc = ExecutionService(db)
record = await exec_svc.get_execution(execution_id)
if not record:
raise HTTPException(404, "Execution not found")
return ExecutionOut(**record.__dict__)