import React from 'react'; import { Card, Collapse, Descriptions, Empty, Space, Table, Tag, Typography } from 'antd'; import type { ColumnsType } from 'antd/es/table'; import { JsonBlock } from './JsonCollapse'; import type { VideoPromptSchemaFieldConfig, VideoPromptSchemaSectionConfig, } from '../../../utils/videoPromptSchema'; import { hasSchemaConfigSnapshot, inferSchemaSections, normalizeSchemaSections, stringifySchemaValue, } from '../../../utils/videoPromptSchema'; const isRecord = (value: unknown): value is Record => !!value && typeof value === 'object' && !Array.isArray(value); const isLongText = (value: unknown): boolean => typeof value === 'string' && value.length > 80; const renderValue = (value: unknown): React.ReactNode => { if (value === null || value === undefined || value === '') return -; if (typeof value === 'boolean') return value ? '是' : '否'; if (typeof value === 'number') return value; if (typeof value === 'string') { return {value}; } return ; }; const tagOfEditable = (editable?: boolean) => editable ? 可编辑 : 只读; const readSectionValue = (schema: Record, key: string): unknown => schema[key]; const renderObjectSection = (schema: Record, section: VideoPromptSchemaSectionConfig): React.ReactNode => { const value = readSectionValue(schema, section.key); if (!isRecord(value)) return ; const fields = section.children.filter((field) => field.enabled); if (!fields.length) return ; return ( {fields.map((field) => ( {field.label}{tagOfEditable(field.editable)}} span={isLongText(value[field.key]) || isRecord(value[field.key]) || Array.isArray(value[field.key]) ? 2 : 1}> {renderValue(value[field.key])} ))} ); }; const buildFlowFields = (section: VideoPromptSchemaSectionConfig, rows: Record[]): VideoPromptSchemaFieldConfig[] => { const configured = section.itemFields.filter((field) => field.enabled); if (configured.length) { return [{ key: '时间段', label: '时间段', enabled: true, editable: false }, ...configured]; } const inferred = Array.from(new Set(rows.flatMap((row) => Object.keys(row)))); return inferred.map((key) => ({ key, label: key, enabled: true, editable: false })); }; const renderFlowSection = (schema: Record, section: VideoPromptSchemaSectionConfig): React.ReactNode => { const value = readSectionValue(schema, section.key); if (!Array.isArray(value) || !value.every(isRecord)) return ; const rows = value as Record[]; const fields = buildFlowFields(section, rows); const columns: ColumnsType> = fields.map((field) => ({ title: {field.label}{tagOfEditable(field.editable)}, dataIndex: field.key, key: field.key, width: isLongText(rows.find((row) => row[field.key])?.[field.key]) ? 320 : 160, render: (cell: unknown) => renderValue(cell), })); return ( `${section.key}-${index}`} columns={columns} dataSource={rows} pagination={false} scroll={{ x: Math.max(900, fields.length * 180) }} tableLayout="fixed" /> ); }; const renderPrimitiveSection = (schema: Record, section: VideoPromptSchemaSectionConfig): React.ReactNode => { const value = readSectionValue(schema, section.key); return renderValue(value); }; interface VideoPromptSchemaViewerProps { schema?: Record | null; finalPrompt?: string | null; schemaConfigSnapshot?: Record | null; schemaConfigSource?: string | null; schemaConfigVersion?: string | null; schemaConfigIsFallback?: boolean | null; } const VideoPromptSchemaViewer: React.FC = ({ schema, finalPrompt, schemaConfigSnapshot, schemaConfigSource, schemaConfigVersion, schemaConfigIsFallback, }) => { const hasSchema = !!schema && Object.keys(schema).length > 0; if (!hasSchema && !finalPrompt) { return ; } const safeSchema = hasSchema ? schema as Record : {}; const hasSnapshot = hasSchemaConfigSnapshot(schemaConfigSnapshot); const sections = hasSnapshot ? normalizeSchemaSections(schemaConfigSnapshot) : inferSchemaSections(safeSchema); const schemaItems = sections .filter((section) => section.key in safeSchema) .map((section) => ({ key: section.key, label: ( {section.label} {tagOfEditable(section.editable)} {!hasSnapshot ? 管理后台兜底展示 : null} ), children: section.type === 'object' ? renderObjectSection(safeSchema, section) : section.type === 'flow' ? renderFlowSection(safeSchema, section) : renderPrimitiveSection(safeSchema, section), })); return ( {schemaConfigSource || schemaConfigSnapshot?.source || (hasSnapshot ? '-' : 'viewer_fallback')} {schemaConfigVersion || schemaConfigSnapshot?.version || '-'} {schemaConfigIsFallback || !hasSnapshot ? : } {finalPrompt ? ( {finalPrompt} ) : null} {schemaItems.length ? ( ) : hasSchema ? ( ) : null} {hasSchema ? ( , }]} /> ) : null} ); }; export default VideoPromptSchemaViewer;