import { useState } from "react"; import { Button, Empty, Progress, SideSheet, Tag, Toast, } from "@douyinfe/semi-ui-19"; import { api, formatTime, jobLabels, jobStateLabels, post } from "../api"; import type { Job } from "../types"; export function JobPanel({ visible, jobs, timezone, onClose, onChange, onAccount, chatOffset = 0, }: { visible: boolean; jobs: Job[]; timezone?: string; onClose: () => void; onChange: () => void; onAccount: () => void; chatOffset?: number; }) { const [errors, setErrors] = useState< Record >({}); const [busy, setBusy] = useState(""); async function action(job: Job, name: string) { setBusy(job.id); try { await post(`/sync-jobs/${job.id}/${name}`); onChange(); } catch (e) { Toast.error((e as Error).message); } finally { setBusy(""); } } return (

同步进度保存在服务端,关闭此面板不会中断任务。

{!jobs.length && } {jobs.map((job) => (
{jobLabels[job.kind] ?? job.kind} {jobStateLabels[job.status] ?? job.status}
{job.payload?.scope && (

{job.payload.dataset_id || "数据集目录"} ·{" "} {job.payload.scope.region} · {job.payload.scope.universe} · Delay{" "} {job.payload.scope.delay}

)}

{formatTime(job.created_at, timezone)}

{job.payload?.submission && (

{job.payload.submission === "SUBMITTED" ? "已提交" : "待提交"} {job.payload.date_from ? ` · ${job.payload.date_from} 至 ${job.payload.date_to}(UTC)` : " · 全量"}

)} {job.checkpoint?.date && (

同步日期:{job.checkpoint.date} · 已完成{" "} {job.checkpoint.dates_completed} / {job.checkpoint.dates_total} 天

)} {job.kind === "pnl_backfill" && (

{job.total === 0 ? "已提交 Alpha 的 PnL 已齐全,无需补取" : `仅补取缺失的 PnL${job.checkpoint?.alpha_id ? ` · ${job.checkpoint.alpha_id}` : ""}`}

)} {job.kind === "self_correlation" && job.checkpoint?.alpha_id && (

{job.checkpoint.alpha_id} ·{" "} {job.checkpoint.phase === "calculating" ? "计算相关性" : `准备 PnL:${job.checkpoint.references_loaded ?? 0} / ${job.checkpoint.references_total ?? 0} 个基准`}

)}
已处理 {job.processed} 失败 {job.failed} 总数 {job.total ?? "计算中"}
{job.total !== null && job.total > 0 && ( )} {job.error &&

{job.error}

} {job.next_retry_at && (

下次重试:{formatTime(job.next_retry_at, timezone)}

)}
{[ "queued", "running", "waiting_auth", "waiting_connection", ].includes(job.status) && ( )} {["failed", "cancelled", "completed_with_errors"].includes( job.status, ) && ( )} {["waiting_auth", "waiting_connection"].includes(job.status) && ( )} {job.failed > 0 && ( )}
{errors[job.id]?.map((e) => (

{e.alpha_id}:{e.error}

))}
))}
); }