feat(web): 任务详情页新增探索链路播报板
按创建时间分页平铺展示探索节点,作为探索链路图的时间轴视图, 复用同一份 exploration_nodes 数据,不影响链路图。 - 后端 NodesPage/NodesByIDs/EdgesTouching:分页下推 SQL, 支持 kind/state 过滤、payload/origin 搜索、正倒序, 并补出当页节点的相邻边与对端节点 - 新增 GET /api/exploration/nodes(仅本任务节点,不含继承) - 播报板:时间轴分行、按天分组、类型快筛、搜索防抖、 自动刷新、直播位未读提示、展开看上下游与 payload - 补 mock,NEXT_PUBLIC_MOCK=1 下可无后端预览
This commit is contained in:
1 parent
13ce2ea6e3
commit
c03e008d7b
7 files changed
+1053
-37
No files matched your search
+34
-8
@@ -31,6 +31,8 @@ import type {
|
||||
DeleteTaskResult,
|
||||
Edge,
|
||||
EvidenceBodyPreview,
|
||||
ExplorationNodePage,
|
||||
ExplorationNodeQuery,
|
||||
Finding,
|
||||
FindingAssetTree,
|
||||
FindingDeepenResponse,
|
||||
@@ -655,6 +657,25 @@ export const api = {
|
||||
.then(arr)
|
||||
.catch(() => [] as ConvTokenSummary[]),
|
||||
explorationGraph: (task?: string) => get<{ nodes: TaskNode[]; edges: Edge[] }>(`/exploration/graph${tq(task)}`),
|
||||
// 播报板:服务端按创建顺序分页的探索节点(默认最新在前)。
|
||||
explorationNodes: (task: string, query: ExplorationNodeQuery = {}) => {
|
||||
const q = new URLSearchParams();
|
||||
if (task) q.set("task", task);
|
||||
q.set("page", String(query.page ?? 1));
|
||||
q.set("size", String(query.size ?? 20));
|
||||
if (query.kinds?.length) q.set("kind", query.kinds.join(","));
|
||||
if (query.states?.length) q.set("state", query.states.join(","));
|
||||
if (query.q?.trim()) q.set("q", query.q.trim());
|
||||
if (query.order === "asc") q.set("order", "asc");
|
||||
return get<ExplorationNodePage>(`/exploration/nodes?${q.toString()}`).then((r) => ({
|
||||
items: arr(r.items),
|
||||
total: r.total ?? 0,
|
||||
page: r.page ?? 1,
|
||||
size: r.size ?? query.size ?? 20,
|
||||
edges: arr(r.edges),
|
||||
refs: r.refs ?? {},
|
||||
}));
|
||||
},
|
||||
activity: (task?: string, opts?: { intent?: string; since?: number; limit?: number }) => {
|
||||
const q = new URLSearchParams();
|
||||
if (task) q.set("task", task);
|
||||
@@ -742,7 +763,10 @@ export const api = {
|
||||
return r.text();
|
||||
},
|
||||
chatMentions: (kind: string, query: string, signal?: AbortSignal, cursor = "") =>
|
||||
http<{ items: ChatMention[]; next_cursor?: string }>(`/chat/mentions?${new URLSearchParams({ kind, q: query, cursor })}`, { signal }),
|
||||
http<{ items: ChatMention[]; next_cursor?: string }>(
|
||||
`/chat/mentions?${new URLSearchParams({ kind, q: query, cursor })}`,
|
||||
{ signal },
|
||||
),
|
||||
chat: (message: string, task?: string, attachments?: ChatAttachment[], seg?: number) =>
|
||||
post<{ reply: string; mode: string }>(`/chat${tq(task)}`, { message, attachments, seg }),
|
||||
chatStatus: (taskId: string) => get<{ running: boolean }>(`/tasks/${taskId}/chat/status`),
|
||||
@@ -1073,16 +1097,18 @@ export const api = {
|
||||
interceptDecide: (id: number, decision: "allowed" | "denied") =>
|
||||
post<{ ok: boolean }>(`/intercept/pending/${id}/decide`, { decision }),
|
||||
interceptExecution: (id: number, conversationId?: number) =>
|
||||
get<import("@/lib/types").InterceptExecution>(`/intercept/history/${id}/execution${conversationId ? `?conversation=${conversationId}` : ""}`),
|
||||
get<import("@/lib/types").InterceptExecution>(
|
||||
`/intercept/history/${id}/execution${conversationId ? `?conversation=${conversationId}` : ""}`,
|
||||
),
|
||||
interceptDetail: (id: number) => get<InterceptDetail>(`/intercept/history/${id}`),
|
||||
interceptHistory: () => get<{ items: InterceptApprovalRow[] }>("/intercept/history").then((r) => arr(r.items)),
|
||||
interceptHistoryPage: (page = 1, size = 20, filter: InterceptApprovalFilter = {}) =>
|
||||
get<{ items: InterceptApprovalRow[]; total?: number }>(`/intercept/history?${interceptPageQuery(page, size, filter)}`).then(
|
||||
(r) => ({
|
||||
items: arr(r.items),
|
||||
total: r.total ?? r.items?.length ?? 0,
|
||||
}),
|
||||
),
|
||||
get<{ items: InterceptApprovalRow[]; total?: number }>(
|
||||
`/intercept/history?${interceptPageQuery(page, size, filter)}`,
|
||||
).then((r) => ({
|
||||
items: arr(r.items),
|
||||
total: r.total ?? r.items?.length ?? 0,
|
||||
})),
|
||||
interceptTask: (taskId: string) =>
|
||||
get<{ items: InterceptApprovalRow[] }>(`/intercept/task/${taskId}`).then((r) => arr(r.items)),
|
||||
interceptTaskPage: (taskId: string, page = 1, size = 20, filter: InterceptApprovalFilter = {}) =>
|
||||
|
||||
Reference in new issue
Block a user