Harden async task flows and enhance analysis tooling
这个提交包含在:
@@ -37,11 +37,30 @@ function formatStructuredValue(value: unknown) {
|
||||
}
|
||||
}
|
||||
|
||||
function formatTaskTiming(task: {
|
||||
createdAt: string | Date;
|
||||
startedAt?: string | Date | null;
|
||||
completedAt?: string | Date | null;
|
||||
}) {
|
||||
const createdAt = new Date(task.createdAt).getTime();
|
||||
const startedAt = task.startedAt ? new Date(task.startedAt).getTime() : null;
|
||||
const completedAt = task.completedAt ? new Date(task.completedAt).getTime() : null;
|
||||
const durationMs = (completedAt ?? Date.now()) - (startedAt ?? createdAt);
|
||||
const seconds = Math.max(0, Math.round(durationMs / 1000));
|
||||
if (seconds < 60) return `${seconds}s`;
|
||||
const minutes = Math.floor(seconds / 60);
|
||||
const rest = seconds % 60;
|
||||
return `${minutes}m ${rest.toString().padStart(2, "0")}s`;
|
||||
}
|
||||
|
||||
export default function Logs() {
|
||||
const utils = trpc.useUtils();
|
||||
const taskListQuery = trpc.task.list.useQuery(
|
||||
{ limit: 50 },
|
||||
{
|
||||
retry: 3,
|
||||
retryDelay: (attempt) => Math.min(1_000 * 2 ** attempt, 8_000),
|
||||
placeholderData: (previous) => previous,
|
||||
refetchInterval: (query) => {
|
||||
const hasActiveTask = (query.state.data ?? []).some((task) => task.status === "queued" || task.status === "running");
|
||||
return hasActiveTask ? 3_000 : 10_000;
|
||||
@@ -103,6 +122,16 @@ export default function Logs() {
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
|
||||
{taskListQuery.isError ? (
|
||||
<Alert variant="destructive">
|
||||
<AlertTriangle className="h-4 w-4" />
|
||||
<AlertTitle>任务列表刷新失败</AlertTitle>
|
||||
<AlertDescription>
|
||||
当前显示最近一次成功拉取的数据。服务恢复后页面会自动继续刷新。
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
) : null}
|
||||
|
||||
<Tabs defaultValue="tasks" className="space-y-4">
|
||||
<TabsList>
|
||||
<TabsTrigger value="tasks">后台任务</TabsTrigger>
|
||||
@@ -153,7 +182,9 @@ export default function Logs() {
|
||||
) : null}
|
||||
|
||||
<div className="flex items-center justify-between text-xs text-muted-foreground">
|
||||
<span>进度 {task.progress}% · 尝试 {task.attempts}/{task.maxAttempts}</span>
|
||||
<span>
|
||||
进度 {task.progress}% · 尝试 {task.attempts}/{task.maxAttempts} · 耗时 {formatTaskTiming(task)}
|
||||
</span>
|
||||
{task.status === "failed" ? (
|
||||
<Button
|
||||
variant="outline"
|
||||
|
||||
在新工单中引用
屏蔽一个用户