From d24ce8f4e0ffaa1c92e129e502fdb4fbaf8f0fed Mon Sep 17 00:00:00 2001 From: R524809 Date: Wed, 23 Sep 2026 17:39:05 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E7=BC=96=E8=BE=91=E9=A1=B5=20SKU=20?= =?UTF-8?q?=E5=9B=BE=E6=A0=87=E9=BB=98=E8=AE=A4=E5=80=BC=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/pages/products/ProductEditPage.tsx | 29 ---- .../components/ProductVariantSection.css | 9 - .../components/ProductVariantSection.tsx | 158 ++++-------------- 3 files changed, 32 insertions(+), 164 deletions(-) diff --git a/apps/web/src/pages/products/ProductEditPage.tsx b/apps/web/src/pages/products/ProductEditPage.tsx index 9a5f403..5b0a970 100644 --- a/apps/web/src/pages/products/ProductEditPage.tsx +++ b/apps/web/src/pages/products/ProductEditPage.tsx @@ -429,7 +429,6 @@ const ProductEditPage = () => { const [loading, setLoading] = useState(true); const [saving, setSaving] = useState(false); const [savingSourceDescription, setSavingSourceDescription] = useState(false); - const [materializingTransferId, setMaterializingTransferId] = useState(null); const [dirty, setDirty] = useState(false); const [moreFeaturesExpanded, setMoreFeaturesExpanded] = useState(false); const [usesVariantPackageWeight, setUsesVariantPackageWeight] = useState(false); @@ -1268,31 +1267,6 @@ const ProductEditPage = () => { const cursor = dictionaryCursors[attributeId]; if (cursor) void loadDictionaryValues(attributeId, query, cursor); }; - /** 把采集素材转存为可引用资产;完成后刷新采集证据,让对应 SKU 的图片立即可选。 */ - const materializeCandidate = async (transferId: string) => { - if (!snapshot) return; - setMaterializingTransferId(transferId); - try { - const queued = await collectionApi.materializeAssets(snapshot.collection_item_id, { - transfer_ids: [transferId], - }); - const completed = await waitForCatalogOperation(queued.operation.id); - const refreshed = await collectionApi.inspection(snapshot.collection_item_id); - setCollectionRecord(refreshed); - if (completed?.status === 'succeeded') { - message.success('素材已转存,可选择并随草稿保存'); - } else if (completed?.status === 'failed') { - message.error(completed.error?.message ?? '素材转存失败,请稍后重试'); - } else { - message.info('素材正在转存,稍后重新展开此 SKU 即可选择'); - } - } catch (error) { - message.error(apiErrorMessage(error)); - } finally { - setMaterializingTransferId(null); - } - }; - if (!currentPlatform) return ; if (loading && !snapshot) return ( @@ -1449,18 +1423,15 @@ const ProductEditPage = () => { form={form} snapshot={snapshot} collectionRecord={collectionRecord} - materializingTransferId={materializingTransferId} activeAttributeSchema={activeAttributeSchema} catalogSyncing={null} dictionaryValues={dictionaryValues} - onMaterialize={materializeCandidate} onLoadDictionaryValues={(dictionaryId, query) => void loadDictionaryValues(dictionaryId, query) } onSyncDictionaryValues={syncDictionaryValues} onOpenDictionaryValues={openDictionaryValues} onLoadMoreDictionaryValues={loadMoreDictionaryValues} - onDirty={() => setDirty(true)} usesVariantPackageWeight={usesVariantPackageWeight} usesVariantPackageDimensions={usesVariantPackageDimensions} usesVariantTags={usesVariantTags} diff --git a/apps/web/src/pages/products/components/ProductVariantSection.css b/apps/web/src/pages/products/components/ProductVariantSection.css index d1abd36..760e95f 100644 --- a/apps/web/src/pages/products/components/ProductVariantSection.css +++ b/apps/web/src/pages/products/components/ProductVariantSection.css @@ -240,15 +240,6 @@ font-size: 11px; line-height: 18px; } -.sku-media-item .ant-btn { - position: absolute; - right: 4px; - bottom: 4px; - z-index: 1; -} -.sku-media-item.selected { - border: 2px solid #7c3aed; -} .sku-media-item .ant-image, .sku-media-item img { width: 100%; diff --git a/apps/web/src/pages/products/components/ProductVariantSection.tsx b/apps/web/src/pages/products/components/ProductVariantSection.tsx index ffa63b5..5c2a886 100644 --- a/apps/web/src/pages/products/components/ProductVariantSection.tsx +++ b/apps/web/src/pages/products/components/ProductVariantSection.tsx @@ -117,16 +117,13 @@ type Props = { form: FormInstance; snapshot: ProductEditorSnapshot; collectionRecord: CollectionItemInspection | null; - materializingTransferId: string | null; activeAttributeSchema: ProductAttributeSchema[]; catalogSyncing: string | null; dictionaryValues: Record; - onMaterialize: (transferId: string) => void; onLoadDictionaryValues: (dictionaryId: string, query: string) => void; onSyncDictionaryValues: (dictionaryId: string, query: string) => void; onOpenDictionaryValues: (dictionaryId: string) => void; onLoadMoreDictionaryValues: (dictionaryId: string, query: string) => void; - onDirty: () => void; usesVariantPackageWeight: boolean; usesVariantPackageDimensions: boolean; usesVariantTags: boolean; @@ -138,25 +135,21 @@ type Props = { /** * 「03 变体设置」区块:SKU 卡片(名称/主图/货号/价格摘要)与展开后的 - * 采集图片选择、SKU 包装覆盖与类目变体属性编辑。 + * 已选图片、SKU 包装覆盖与类目变体属性编辑。 * - * 采集证据(collectionRecord)与素材转存由页面处理;本组件维护卡片 - * 展开状态与图片选择交互。 + * 采集证据仅用于补齐已选图片的预览地址;采集候选图片留待选择弹窗展示。 */ export function ProductVariantSection({ form, snapshot, collectionRecord, - materializingTransferId, activeAttributeSchema, catalogSyncing, dictionaryValues, - onMaterialize, onLoadDictionaryValues, onSyncDictionaryValues, onOpenDictionaryValues, onLoadMoreDictionaryValues, - onDirty, usesVariantPackageWeight, usesVariantPackageDimensions, usesVariantTags, @@ -165,7 +158,7 @@ export function ProductVariantSection({ onAiCopy, onCompareCopy, }: Props) { - // 实时监听变体草稿:驱动主图回显与候选图片的选中态。 + // 实时监听变体草稿,驱动已选图片和主图回显。 const draftVariants = (Form.useWatch('variants', form) ?? []) as VariantValues[]; // 展开状态按 Form.List 的 field.key(而非下标)记录,增删/复制 SKU 后不会错位。 const [expandedVariantKeys, setExpandedVariantKeys] = useState>(() => new Set()); @@ -245,28 +238,19 @@ export function ProductVariantSection({ const selectedAssetIds = draftVariants[field.name]?.media_asset_ids ?? []; const selectedImages = selectedAssetIds - .map( - (assetId) => + .map((assetId) => ({ + assetId, + url: imageCandidates.find( (candidate) => candidate.asset_id === assetId )?.source_url ?? original?.media.find( (media) => media.asset_id === assetId - )?.source_url - ) - .filter((url): url is string => !!url); - // 选中/取消候选图片;setFieldValue 不触发 Form 的 - // onValuesChange,因此需通过 onDirty 手动标记未保存。 - const toggleImage = (assetId: string) => { - const next = selectedAssetIds.includes(assetId) - ? selectedAssetIds.filter((id) => id !== assetId) - : [...selectedAssetIds, assetId]; - form.setFieldValue( - ['variants', field.name, 'media_asset_ids'], - next + )?.source_url, + })) + .filter((image): image is { assetId: string; url: string } => + Boolean(image.url) ); - onDirty(); - }; const copyVariant = () => add({ ...variantValue, @@ -311,7 +295,7 @@ export function ProductVariantSection({ {selectedImages[0] ? ( SKU 主图 ) : ( @@ -441,106 +425,28 @@ export function ProductVariantSection({ SKU 图片 - {imageCandidates.length ? ( -
- {imageCandidates.map( - (candidate, imageIndex) => { - // 仅"转存成功"的候选可直接勾选;待转存图片仅保留预览, - // 避免在此处重复提供后续素材选择流程的入口。 - const selectable = - candidate.status === - 'succeeded' && - !!candidate.asset_id; - const selected = - selectable && - selectedAssetIds.includes( - candidate.asset_id! - ); - return ( -
- {imageIndex === 0 && ( - - 主图 - - )} - 采集候选图片 - {selectable ? ( - - ) : candidate.status === - 'pending_selection' ? null : ( - - )} -
- ); - } - )} - {/* 仅提供素材选择入口的视觉占位,实际选择流程后续接入。 */} - -
- ) : ( -
- {/* 没有采集图片时仍保留选择素材的入口。 */} - -
- )} + {imageIndex === 0 && ( + + 主图 + + )} + 已选 SKU 图片 + + ))} + {/* 图片选择交互将在后续接入。 */} + + {(usesVariantPackageWeight || usesVariantPackageDimensions ||