import { reactive } from 'vue' import type { ProductionIssueCode, ProductionSession, ShotKeyframe, ShotVideo } from './types' /** 按项目隔离生产回执,切换页面后仍能查看上一次批量操作结果。 */ const sessions = reactive>({}) /** 取得项目的生产页会话容器。 */ export function getProductionSession(projectId: string): ProductionSession { return (sessions[projectId] ??= { receipt: null }) } /** 生成规格尺寸必须成对留空或成对填写正整数。 */ export function validOptionalSize(width: number | '', height: number | ''): boolean { if (width === '' && height === '') return true return ( Number.isSafeInteger(width) && Number.isSafeInteger(height) && typeof width === 'number' && typeof height === 'number' && width > 0 && height > 0 ) } /** 返回当前成功主首帧;异常的重复主图只取最新列表中的第一条。 */ export function primaryKeyframe(items: ShotKeyframe[]): ShotKeyframe | undefined { return items.find(item => item.isPrimary && item.status === 'completed' && item.imageUrl) } /** 返回当前成功主视频。 */ export function primaryVideo(items: ShotVideo[]): ShotVideo | undefined { return items.find(item => item.isPrimary && item.status === 'completed' && item.videoUrl) } /** 活动视频状态与后端重复任务保护保持一致。 */ export function isActiveVideo(item: ShotVideo): boolean { return ['pending', 'queued', 'running'].includes(item.status) } /** 就绪问题转为短标签,后端详细 reason 仍在页面原样显示。 */ export function issueLabel(code: ProductionIssueCode): string { const labels: Record = { invalid_generation_spec: '生成规格不完整', missing_visual_style: '缺少视觉风格', missing_reference: '缺少主体参考图', missing_identity: '缺少角色身份', missing_identity_anchor: '缺少演员母版', identity_unlocked: '演员身份未锁定', missing_prompt: '缺少视频提示词', missing_keyframe: '缺少主首帧', stale_keyframe: '主首帧已过期' } return labels[code] } /** 生产状态中文标签,未知值由状态组件回退显示原文。 */ export function productionStatusLabel(status: string): string { const labels: Record = { ready: '已就绪', skipped: '已有结果', in_progress: '任务进行中', blocked: '前置条件不足', pending: '等待提交', queued: '排队中', running: '生成中', completed: '已完成', failed: '失败', cancelled: '已取消', not_started: '未开始' } return labels[status] ?? status }