console: React 生产级重写(左列表 + 中对话 + 右详情)

旧单页 console.html 换成 Vite + React + TypeScript 单文件构建产物
(309525 字节,sha 90345ec8…,重建字节一致),源码在
cloud/console-react/,改页面只改 src 再 npm run build:console,
产物不手改。布局:左侧列表(模块导航 + 任务列表)、中间标准对话
(实时链路时间线 + 继续会话聊天框,共用 Chat 组件)、右侧详情
(元数据、操作、评审、审批、协调子任务、子代理、线程)。
API 与后端语义未改,key 只存浏览器 localStorage。
6 个 console 标记单测随实现改名更新(意图不变:壳确实调了
这些接口、turn 信息仍在详情里、旧 goal 输入仍不存在);
P1 标记单测未动且通过。
This commit is contained in:
host committed 2026-10-29 06:32:38 +08:00
1 parent 3f4e849a93
commit ebc5624893
57 files changed
+4789 -1746

No files matched your search

@@ -0,0 +1,45 @@
import { useCallback, useMemo, useState } from "react";
import { api, shortId, uploadAttachments } from "../api/client";
import { paths } from "../api/paths";
import type { DispatchBody, Task } from "../api/types";
export function useTaskList() {
const [tasks, setTasks] = useState<Task[]>([]);
const [taskError, setTaskError] = useState("");
const [statusFilter, setStatusFilter] = useState("");
const [executorFilter, setExecutorFilter] = useState("");
const [searchText, setSearchText] = useState("");
const refreshTasks = useCallback(async (pid?: string, currentPid?: string) => {
const id = pid !== undefined ? pid : currentPid;
if (!id) { setTasks([]); return; }
try {
const d = await api<{ tasks: Task[] }>(paths.tasks(id));
setTasks(d.tasks || []);
setTaskError("");
} catch (e: any) { setTaskError("加载失败:" + e.message); }
}, []);
const filteredTasks = useMemo(() => {
const q = searchText.trim().toLowerCase();
return tasks.filter((t) => {
if (statusFilter && t.status !== statusFilter) return false;
if (executorFilter && (t.executor || "") !== executorFilter) return false;
if (q && !((t.id || "") + " " + (t.prompt || "")).toLowerCase().includes(q)) return false;
return true;
});
}, [tasks, statusFilter, executorFilter, searchText]);
const taskCountText = filteredTasks.length + " 个任务(共 " + tasks.length + " 个)";
const dispatch = useCallback(async (body: DispatchBody, atts: Array<{ path: string; file: File }>): Promise<string> => {
const payload: DispatchBody = { ...body };
if (atts.length) {
payload.upload_id = await uploadAttachments(atts);
}
const t = await api<Task>(paths.tasksCreate, "POST", payload);
return "任务已建:" + shortId(t.id);
}, []);
return { tasks, taskError, statusFilter, setStatusFilter, executorFilter, setExecutorFilter, searchText, setSearchText, filteredTasks, taskCountText, refreshTasks, dispatch };
}