import type { JsonObject, JsonValue, WorkflowListItemDto, WorkflowStatusResponseDto, } from "@/lib/types/backend"; import { getOrderStatusMeta, getStepStatusMeta, getWorkflowStepMeta, } from "@/lib/types/status"; import { businessEmptyState, READY_STATE, type WorkflowDetailVM, type WorkflowLookupItemVM, type WorkflowStepVM, } from "@/lib/types/view-models"; type WorkflowAssetUriField = | "asset_uri" | "candidate_uri" | "preview_uri" | "result_uri" | "source_uri"; const WORKFLOW_ASSET_URI_FIELDS = new Set([ "asset_uri", "candidate_uri", "preview_uri", "result_uri", "source_uri", ]); function collectKnownAssetUris( value: JsonValue | undefined, results: string[] = [], ): string[] { if (!value || typeof value !== "object") { return results; } if (Array.isArray(value)) { for (const item of value) { collectKnownAssetUris(item, results); } return results; } for (const [key, nestedValue] of Object.entries(value)) { if ( WORKFLOW_ASSET_URI_FIELDS.has(key as WorkflowAssetUriField) && typeof nestedValue === "string" && nestedValue.startsWith("mock://") ) { results.push(nestedValue); continue; } collectKnownAssetUris(nestedValue, results); } return results; } function uniqueMockUris(...payloads: Array): string[] { return [...new Set(payloads.flatMap((payload) => collectKnownAssetUris(payload)))]; } function adaptWorkflowStep( currentStep: WorkflowStatusResponseDto["current_step"], step: WorkflowStatusResponseDto["steps"][number], ): WorkflowStepVM { const stepMeta = getWorkflowStepMeta(step.step_name); const mockAssetUris = uniqueMockUris(step.input_json, step.output_json); return { id: step.id, workflowRunId: step.workflow_run_id, name: step.step_name, label: stepMeta.label, status: step.step_status, statusMeta: getStepStatusMeta(step.step_status), input: step.input_json, output: step.output_json, errorMessage: step.error_message, startedAt: step.started_at, endedAt: step.ended_at, containsMockAssets: mockAssetUris.length > 0, mockAssetUris, isCurrent: currentStep === step.step_name, isFailed: step.step_status === "failed", }; } export function adaptWorkflowLookupItem( workflow: Pick< WorkflowStatusResponseDto | WorkflowListItemDto, | "order_id" | "workflow_id" | "workflow_type" | "workflow_status" | "current_step" | "failure_count" | "review_task_status" | "revision_count" | "pending_manual_confirm" | "updated_at" >, ): WorkflowLookupItemVM { return { orderId: workflow.order_id, workflowId: workflow.workflow_id, workflowType: workflow.workflow_type, status: workflow.workflow_status, statusMeta: getOrderStatusMeta(workflow.workflow_status), currentStep: workflow.current_step, currentStepLabel: getWorkflowStepMeta(workflow.current_step).label, failureCount: workflow.failure_count, reviewTaskStatus: workflow.review_task_status, revisionCount: workflow.revision_count, pendingManualConfirm: workflow.pending_manual_confirm, updatedAt: workflow.updated_at, }; } export function adaptWorkflowDetail( workflow: WorkflowStatusResponseDto, ): WorkflowDetailVM { const steps = workflow.steps.map((step) => adaptWorkflowStep(workflow.current_step, step), ); return { orderId: workflow.order_id, workflowId: workflow.workflow_id, workflowType: workflow.workflow_type, status: workflow.workflow_status, statusMeta: getOrderStatusMeta(workflow.workflow_status), currentStep: workflow.current_step, currentStepLabel: getWorkflowStepMeta(workflow.current_step).label, currentRevisionAssetId: workflow.current_revision_asset_id, currentRevisionVersion: workflow.current_revision_version, latestRevisionAssetId: workflow.latest_revision_asset_id, latestRevisionVersion: workflow.latest_revision_version, revisionCount: workflow.revision_count, reviewTaskStatus: workflow.review_task_status, pendingManualConfirm: workflow.pending_manual_confirm, createdAt: workflow.created_at, updatedAt: workflow.updated_at, steps, stepTimelineState: steps.length ? READY_STATE : businessEmptyState( "暂无流程记录", "当前工作流还没有可展示的步骤执行记录。", ), failureCount: steps.filter((step) => step.isFailed).length, hasMockAssets: steps.some((step) => step.containsMockAssets), }; }