Files
auto-virtual-tryon-frontend/src/lib/adapters/workflows.ts
2026-03-28 00:28:51 +08:00

163 lines
4.5 KiB
TypeScript

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<WorkflowAssetUriField>([
"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<JsonObject | null>): 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),
};
}