Update seller store experience
This commit is contained in:
@@ -49,6 +49,7 @@ export default function CollectionInspectionPage() {
|
||||
() => new Map((record?.variants ?? []).map((variant) => [variant.id, variant])),
|
||||
[record]
|
||||
);
|
||||
const payload = normalisedPayload(record?.normalized_payload);
|
||||
|
||||
if (error)
|
||||
return <Alert type="error" message="无法读取采集数据" description={error} showIcon />;
|
||||
@@ -65,7 +66,7 @@ export default function CollectionInspectionPage() {
|
||||
type="info"
|
||||
showIcon
|
||||
style={{ marginBottom: 16 }}
|
||||
message="这里展示扩展实际提交、服务端实际保存的数据,不代表已确认的商品编辑字段。"
|
||||
message="这里展示扩展实际提交、服务端实际保存的数据;未转存图片或视频直接使用采集来源预览,不代表已确认的商品编辑字段。"
|
||||
/>
|
||||
<Descriptions
|
||||
bordered
|
||||
@@ -81,9 +82,71 @@ export default function CollectionInspectionPage() {
|
||||
{ key: 'status', label: '采集状态', children: record.collection_status },
|
||||
{ key: 'parser', label: '解析器版本', children: record.parser_version ?? '—' },
|
||||
{ key: 'sku', label: '已创建 SKU', children: record.variants.length },
|
||||
{ key: 'assets', label: '素材任务', children: record.asset_transfers.length },
|
||||
{ key: 'assets', label: '素材候选', children: record.asset_transfers.length },
|
||||
{ key: 'attributes', label: '已采集特征', children: payload.attributes.length },
|
||||
{ key: 'categories', label: '已采集类目', children: payload.categories.length },
|
||||
]}
|
||||
/>
|
||||
<Typography.Title level={5} style={{ marginTop: 24 }}>
|
||||
商品描述
|
||||
</Typography.Title>
|
||||
<Card size="small">
|
||||
{payload.description ? (
|
||||
<Typography.Paragraph style={{ whiteSpace: 'pre-wrap', marginBottom: 0 }}>
|
||||
{payload.description}
|
||||
</Typography.Paragraph>
|
||||
) : (
|
||||
<Typography.Text type="secondary">本次采集未取得商品描述。</Typography.Text>
|
||||
)}
|
||||
</Card>
|
||||
<Typography.Title level={5} style={{ marginTop: 24 }}>
|
||||
类目与特征
|
||||
</Typography.Title>
|
||||
<Descriptions
|
||||
bordered
|
||||
size="small"
|
||||
column={1}
|
||||
items={[
|
||||
{
|
||||
key: 'category-path',
|
||||
label: '类目路径',
|
||||
children: payload.categories.length
|
||||
? payload.categories.map((category) => category.name).join(' › ')
|
||||
: '未采集',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
<Table
|
||||
size="small"
|
||||
pagination={false}
|
||||
rowKey={(attribute) => `${attribute.key}:${attribute.value}`}
|
||||
dataSource={payload.attributes}
|
||||
style={{ marginTop: 12 }}
|
||||
columns={[
|
||||
{ title: '特征', dataIndex: 'name' },
|
||||
{ title: '值', dataIndex: 'value' },
|
||||
{ title: '来源键', dataIndex: 'key', ellipsis: true },
|
||||
]}
|
||||
locale={{ emptyText: '本次采集未取得商品特征。' }}
|
||||
/>
|
||||
<Typography.Title level={5} style={{ marginTop: 24 }}>
|
||||
规格轴
|
||||
</Typography.Title>
|
||||
<Table
|
||||
size="small"
|
||||
pagination={false}
|
||||
rowKey="key"
|
||||
dataSource={payload.variantAxes}
|
||||
columns={[
|
||||
{ title: '规格名称', dataIndex: 'name' },
|
||||
{ title: '来源键', dataIndex: 'key', ellipsis: true },
|
||||
{
|
||||
title: '规格值',
|
||||
render: (_, axis) => axis.values.map((value) => value.name).join(' / ') || '—',
|
||||
},
|
||||
]}
|
||||
locale={{ emptyText: '本次采集未取得规格轴。' }}
|
||||
/>
|
||||
<Typography.Title level={5} style={{ marginTop: 24 }}>
|
||||
SKU 草稿
|
||||
</Typography.Title>
|
||||
@@ -111,7 +174,7 @@ export default function CollectionInspectionPage() {
|
||||
]}
|
||||
/>
|
||||
<Typography.Title level={5} style={{ marginTop: 24 }}>
|
||||
素材转存任务
|
||||
素材候选与转存状态
|
||||
</Typography.Title>
|
||||
<Table
|
||||
size="small"
|
||||
@@ -124,26 +187,50 @@ export default function CollectionInspectionPage() {
|
||||
width: 108,
|
||||
render: (_, transfer) => {
|
||||
const url = transfer.asset_id
|
||||
? previewUrls[transfer.asset_id]
|
||||
: undefined;
|
||||
? previewUrls[transfer.asset_id] ?? transfer.source_url
|
||||
: transfer.source_url;
|
||||
if (transfer.media_type === 'video')
|
||||
return url ? (
|
||||
<video
|
||||
controls
|
||||
preload="none"
|
||||
poster={transfer.poster_url ?? undefined}
|
||||
src={url}
|
||||
style={{ width: 96, height: 72, objectFit: 'cover', background: '#000' }}
|
||||
>
|
||||
当前浏览器不支持视频预览。
|
||||
</video>
|
||||
) : (
|
||||
<Typography.Text type="secondary">
|
||||
暂无来源视频
|
||||
</Typography.Text>
|
||||
);
|
||||
if (url)
|
||||
return (
|
||||
<Image
|
||||
width={72}
|
||||
height={72}
|
||||
src={url}
|
||||
alt="已转存采集素材"
|
||||
alt={
|
||||
transfer.asset_id
|
||||
? '已转存采集素材'
|
||||
: '采集来源图片'
|
||||
}
|
||||
style={{ objectFit: 'cover' }}
|
||||
/>
|
||||
);
|
||||
return (
|
||||
<Typography.Text type="secondary">
|
||||
{transfer.status === 'succeeded' ? '预览加载中…' : '待转存'}
|
||||
暂无来源图片
|
||||
</Typography.Text>
|
||||
);
|
||||
},
|
||||
},
|
||||
{ title: '类型', dataIndex: 'role' },
|
||||
{
|
||||
title: '类型',
|
||||
render: (_, transfer) =>
|
||||
`${transfer.media_type === 'video' ? '视频' : '图片'} · ${transfer.role}`,
|
||||
},
|
||||
{
|
||||
title: '关联 SKU',
|
||||
render: (_, transfer) => {
|
||||
@@ -153,7 +240,20 @@ export default function CollectionInspectionPage() {
|
||||
return variant?.source_sku ?? variant?.source_variant_key ?? '商品级';
|
||||
},
|
||||
},
|
||||
{ title: '状态', dataIndex: 'status' },
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'status',
|
||||
render: (status) => {
|
||||
if (status === 'pending_selection')
|
||||
return <Tag color="default">候选,未转存</Tag>;
|
||||
if (status === 'queued') return <Tag color="processing">等待转存</Tag>;
|
||||
if (status === 'running') return <Tag color="processing">转存中</Tag>;
|
||||
if (status === 'succeeded') return <Tag color="success">已转存</Tag>;
|
||||
if (status === 'failed') return <Tag color="error">转存失败</Tag>;
|
||||
if (status === 'cancelled') return <Tag>已取消</Tag>;
|
||||
return status;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '来源 URL',
|
||||
dataIndex: 'source_url',
|
||||
@@ -229,3 +329,52 @@ function Json({ value }: { value: unknown }) {
|
||||
</pre>
|
||||
);
|
||||
}
|
||||
|
||||
type InspectionAttribute = { key: string; name: string; value: string };
|
||||
type InspectionCategory = { key: string; name: string };
|
||||
type InspectionAxis = { key: string; name: string; values: Array<{ key: string; name: string }> };
|
||||
|
||||
function normalisedPayload(value: unknown): {
|
||||
description: string | null;
|
||||
attributes: InspectionAttribute[];
|
||||
categories: InspectionCategory[];
|
||||
variantAxes: InspectionAxis[];
|
||||
} {
|
||||
if (!value || typeof value !== 'object' || Array.isArray(value))
|
||||
return { description: null, attributes: [], categories: [], variantAxes: [] };
|
||||
const root = value as Record<string, unknown>;
|
||||
const common = record(root.common);
|
||||
const description = record(common?.description)?.value;
|
||||
return {
|
||||
description: typeof description === 'string' ? description : null,
|
||||
attributes: records(common?.attributes).flatMap((item) =>
|
||||
typeof item.key === 'string' && typeof item.name === 'string' && typeof item.value === 'string'
|
||||
? [{ key: item.key, name: item.name, value: item.value }]
|
||||
: []),
|
||||
categories: records(common?.categories).flatMap((item) =>
|
||||
typeof item.key === 'string' && typeof item.name === 'string'
|
||||
? [{ key: item.key, name: item.name }]
|
||||
: []),
|
||||
variantAxes: records(root.variantAxes).flatMap((item) => {
|
||||
if (typeof item.key !== 'string' || typeof item.name !== 'string') return [];
|
||||
return [{
|
||||
key: item.key,
|
||||
name: item.name,
|
||||
values: records(item.values).flatMap((option) =>
|
||||
typeof option.key === 'string' && typeof option.name === 'string'
|
||||
? [{ key: option.key, name: option.name }]
|
||||
: []),
|
||||
}];
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
function record(value: unknown): Record<string, unknown> | undefined {
|
||||
return value && typeof value === 'object' && !Array.isArray(value)
|
||||
? value as Record<string, unknown>
|
||||
: undefined;
|
||||
}
|
||||
|
||||
function records(value: unknown): Record<string, unknown>[] {
|
||||
return Array.isArray(value) ? value.filter((item): item is Record<string, unknown> => !!record(item)) : [];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user