import { useEffect, useMemo, useState } from 'react'; import { useParams } from 'react-router-dom'; import { Alert, Card, Collapse, Descriptions, Image, Spin, Table, Tag, Typography } from 'antd'; import type { CollectionItemInspection } from '@atlas/contracts'; import { collectionApi } from '@/services/collection'; import { apiErrorMessage } from '@/services/api'; import { mediaApi } from '@/services/media'; /** Temporary parser inspection surface. This is deliberately read-only: it lets * product and parser work be checked before these values become editor fields. */ export default function CollectionInspectionPage() { const { id } = useParams<{ id: string }>(); const [record, setRecord] = useState(); const [error, setError] = useState(); const [previewUrls, setPreviewUrls] = useState>({}); useEffect(() => { if (!id) return; void collectionApi .inspection(id) .then(setRecord) .catch((reason) => setError(apiErrorMessage(reason))); }, [id]); const assetIds = useMemo( () => [ ...new Set( (record?.asset_transfers ?? []) .filter((transfer) => transfer.status === 'succeeded' && !!transfer.asset_id) .map((transfer) => transfer.asset_id as string) ), ], [record] ); useEffect(() => { let disposed = false; setPreviewUrls({}); if (!assetIds.length) return; void loadPreviewUrls(assetIds).then((urls) => { if (!disposed) setPreviewUrls(urls); }); return () => { disposed = true; }; }, [assetIds]); const variantsById = useMemo( () => new Map((record?.variants ?? []).map((variant) => [variant.id, variant])), [record] ); if (error) return ; if (!record) return (
); return ( 只读测试}> SKU 草稿 value ?? '默认 SKU(待确认)', }, { title: '来源货号', dataIndex: 'source_sku', render: (value) => value ?? '—', }, { title: '名称', dataIndex: 'display_name', render: (value) => value ?? '—', }, ]} /> 素材转存任务
{ const url = transfer.asset_id ? previewUrls[transfer.asset_id] : undefined; if (url) return ( ); return ( {transfer.status === 'succeeded' ? '预览加载中…' : '待转存'} ); }, }, { title: '类型', dataIndex: 'role' }, { title: '关联 SKU', render: (_, transfer) => { const variant = transfer.source_variant_id ? variantsById.get(transfer.source_variant_id) : undefined; return variant?.source_sku ?? variant?.source_variant_key ?? '商品级'; }, }, { title: '状态', dataIndex: 'status' }, { title: '来源 URL', dataIndex: 'source_url', ellipsis: true, render: (value) => ( 查看来源 ), }, { title: '错误', dataIndex: 'error_payload', render: (value) => value ? ( {JSON.stringify(value)} ) : ( '—' ), }, ]} /> , }, { key: 'evidence', label: '原始证据(raw_evidence)', children: , }, ]} /> ); } async function loadPreviewUrls(assetIds: string[]) { const urls: Record = {}; let cursor = 0; const worker = async () => { while (cursor < assetIds.length) { const assetId = assetIds[cursor++]; try { urls[assetId] = (await mediaApi.createPreviewUrl(assetId)).url; } catch { // The task row remains inspectable through its source URL and error state. } } }; await Promise.all(Array.from({ length: Math.min(4, assetIds.length) }, () => worker())); return urls; } function Json({ value }: { value: unknown }) { return (
            {JSON.stringify(value, null, 2)}
        
); }