feat(edit): 编辑上报细节优化

This commit is contained in:
2026-10-06 18:30:05 +08:00
parent e20cd7547f
commit 79b310efe7
92 changed files with 2764 additions and 368 deletions
+16 -5
View File
@@ -2,6 +2,8 @@ import type {
CreateMediaUploadIntentRequest,
MediaAccessUrl,
MediaAsset,
DeleteProductImageRequest,
ProductImageDeletion,
MediaUploadIntent,
ProductUploadImage,
ProductImportedImage,
@@ -21,6 +23,13 @@ export const WATERMARK_IMAGE_MAX_BYTES = 5 * 1024 * 1024;
/** 异步操作查询,契约见 docs/api/conventions.md §5(GET /api/operations/{operation_id}) */
export const mediaApi = {
listPendingImageDeletions: (productId: string) => api.get<ProductImageDeletion[]>(`/products/${productId}/image-deletions`),
deleteProductImage: (productId: string, payload: DeleteProductImageRequest) =>
api.post<ProductImageDeletion>(`/products/${productId}/image-deletions`, payload,
{ headers: { 'Idempotency-Key': crypto.randomUUID() } }),
readImageDeletion: (productId: string, id: string) => api.get<ProductImageDeletion>(`/products/${productId}/image-deletions/${id}`),
retryImageDeletion: (productId: string, id: string) => api.post<ProductImageDeletion>(`/products/${productId}/image-deletions/${id}/retry`, {},
{ headers: { 'Idempotency-Key': crypto.randomUUID() } }),
createAiEdit: (assetId: string, payload: CreateMediaAiEditRequest) =>
api.post<MediaAiEdit>(`/media-assets/${assetId}/ai-edits`, payload,
{ headers: { 'Idempotency-Key': crypto.randomUUID() } }),
@@ -47,8 +56,8 @@ export const mediaApi = {
{ headers: { 'Idempotency-Key': crypto.randomUUID() } }),
readWatermarkDerivative: (derivativeId: string) =>
api.get<WatermarkDerivative>(`/media-watermark-derivatives/${derivativeId}`),
listProductUploads: () => api.get<ProductUploadImage[]>('/media-assets/product-uploads'),
listProductImports: () => api.get<ProductImportedImage[]>('/media-assets/product-imports'),
listProductUploads: (productId: string) => api.get<ProductUploadImage[]>(`/media-assets/product-uploads?product_id=${encodeURIComponent(productId)}`),
listProductImports: (productId: string) => api.get<ProductImportedImage[]>(`/media-assets/product-imports?product_id=${encodeURIComponent(productId)}`),
importProductImage: (payload: ImportProductImageRequest) =>
api.post<ProductImportedImage>('/media-assets/product-imports', payload, {
headers: { 'Idempotency-Key': crypto.randomUUID() },
@@ -165,17 +174,19 @@ export async function uploadWatermarkImage(file: File): Promise<MediaAsset> {
}
/** 商品图片沿用素材直传协议,完成服务端校验后才可写入 SKU 草稿。 */
export async function uploadProductImage(file: File): Promise<MediaAsset> {
return uploadImage(file, 'product_image');
export async function uploadProductImage(file: File, productId: string): Promise<MediaAsset> {
return uploadImage(file, 'product_image', productId);
}
async function uploadImage(
file: File,
purpose: CreateMediaUploadIntentRequest['purpose']
purpose: CreateMediaUploadIntentRequest['purpose'],
productId?: string
): Promise<MediaAsset> {
const checksumSha256 = await sha256Hex(file);
const intent = await mediaApi.createUploadIntent({
purpose,
...(productId ? { product_id: productId } : {}),
filename: file.name,
content_type: file.type as CreateMediaUploadIntentRequest['content_type'],
byte_size: file.size,
+17 -5
View File
@@ -6,6 +6,7 @@ import type {
ProductEditorContext,
ProductEditorSnapshot,
ProductAiTask,
RequestProductAiTask,
ProductEditorValidation,
ProductPublishPreflight,
ProductPublishJob,
@@ -29,10 +30,21 @@ export const productEditorApi = {
},
}
),
read: (productId: string, platformId: string) =>
api.get<ProductEditorSnapshot>(`/products/${productId}/editor`, {
read: async (
productId: string,
platformId: string,
collectionItemId?: string | null
): Promise<ProductEditorSnapshot> => {
// 插件首次进入时尚无平台配置,沿用采集箱的初始化流程并校验商品归属。
if (collectionItemId) {
const context = await productEditorApi.enter(collectionItemId, platformId);
if (context.product_id !== productId)
throw new Error('采集记录与商品不匹配,请从采集箱重新进入编辑页');
}
return api.get<ProductEditorSnapshot>(`/products/${productId}/editor`, {
headers: { 'X-Atlas-Platform-Id': platformId },
}),
});
},
aiAutofill: (profileId: string, platformId: string) =>
api.post<{ ai_task_id: string; status: 'queued' }>(
`/product-platform-profiles/${profileId}/ai/autofills`,
@@ -44,10 +56,10 @@ export const productEditorApi = {
},
}
),
aiSkuCopy: (profileId: string, variantId: string, platformId: string) =>
aiSkuCopy: (profileId: string, variantId: string, platformId: string, input: RequestProductAiTask = {}) =>
api.post<{ ai_task_id: string; status: 'queued' }>(
`/product-platform-profiles/${profileId}/variants/${variantId}/ai/copy`,
{},
input,
{
headers: {
'X-Atlas-Platform-Id': platformId,