import { type Schedule, type ScheduleArtifact, type ScheduleNode } from "../../services/api"; import { EMPTY_SCHEDULE_FORM, EMPTY_NODE_FORM } from "./constants"; export function formatTime(value: string | null): string { if (!value) return "尚未执行"; return new Intl.DateTimeFormat("zh-CN", { month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", hour12: false, }).format(new Date(value)); } export function shortHash(value: string): string { return value ? `${value.slice(0, 7)}…${value.slice(-5)}` : "—"; } export function formatDuration(value: number | null): string { if (value === null) return "—"; if (value < 1000) return `${value} ms`; if (value < 60_000) return `${(value / 1000).toFixed(1)} s`; return `${Math.floor(value / 60_000)}m ${Math.round((value % 60_000) / 1000)}s`; } export function parseObject(text: string, label: string): Record { let value: unknown; try { value = JSON.parse(text); } catch { throw new Error(`${label}必须是合法 JSON`); } if (!value || Array.isArray(value) || typeof value !== "object") { throw new Error(`${label}必须是 JSON 对象`); } return value as Record; } export function scheduleToForm(schedule: Schedule) { return { scheduleName: schedule.schedule_name, description: schedule.description ?? "", triggerType: schedule.trigger_type, cronExpression: schedule.cron_expression ?? "0 9 * * *", timezone: schedule.timezone, enabled: schedule.enabled, maxConcurrency: String(schedule.max_concurrency), failurePolicy: schedule.failure_policy, }; } export function nodeToForm(node: ScheduleNode) { return { nodeName: node.node_name, timeoutSeconds: String(node.timeout_seconds), retryCount: String(node.retry_count), retryIntervalSec: String(node.retry_interval_sec), argumentsJson: JSON.stringify(node.arguments_json ?? {}, null, 2), envRefsJson: JSON.stringify(node.env_refs_json ?? {}, null, 2), }; } export function artifactNodeKey( artifact: ScheduleArtifact, schedule: Schedule, ): string { const ascii = artifact.script_name .replace(/\.[^.]+$/, "") .replace(/[^A-Za-z0-9_-]+/g, "_") .replace(/^([^A-Za-z])/, "n_$1") .replace(/^_+|_+$/g, "") .slice(0, 48); const base = ascii || `node_${artifact.versions_id.slice(-6).toLowerCase()}`; const existing = new Set(schedule.nodes.map((item) => item.node_key)); if (!existing.has(base)) return base; let index = 2; while (existing.has(`${base}_${index}`)) index += 1; return `${base}_${index}`.slice(0, 64); } export function edgePath( source: ScheduleNode, target: ScheduleNode, ): string { const x1 = source.position_x + 218; const y1 = source.position_y + 52; const x2 = target.position_x; const y2 = target.position_y + 52; const curve = Math.max(70, Math.abs(x2 - x1) * 0.45); return `M ${x1} ${y1} C ${x1 + curve} ${y1}, ${x2 - curve} ${y2}, ${x2} ${y2}`; } export function withSuppressedError(action: () => Promise): void { void action().catch(() => undefined); }