feat: 完成 SKU 图片选择及素材导入后端

This commit is contained in:
R524809
2026-09-24 17:46:34 +08:00
parent d24ce8f4e0
commit e670d06ca6
26 changed files with 2287 additions and 119 deletions
+22 -1
View File
@@ -3,6 +3,9 @@ import type {
MediaAccessUrl,
MediaAsset,
MediaUploadIntent,
ProductUploadImage,
ProductImportedImage,
ImportProductImageRequest,
} from '@atlas/contracts';
import { api } from '@/services/api';
@@ -12,6 +15,12 @@ export const WATERMARK_IMAGE_MAX_BYTES = 5 * 1024 * 1024;
/** 异步操作查询,契约见 docs/api/conventions.md §5(GET /api/operations/{operation_id}) */
export const mediaApi = {
listProductUploads: () => api.get<ProductUploadImage[]>('/media-assets/product-uploads'),
listProductImports: () => api.get<ProductImportedImage[]>('/media-assets/product-imports'),
importProductImage: (payload: ImportProductImageRequest) =>
api.post<ProductImportedImage>('/media-assets/product-imports', payload, {
headers: { 'Idempotency-Key': crypto.randomUUID() },
}),
createUploadIntent: (payload: CreateMediaUploadIntentRequest) =>
api.post<MediaUploadIntent>('/media/upload-intents', payload, {
headers: { 'Idempotency-Key': crypto.randomUUID() },
@@ -47,9 +56,21 @@ export async function sha256Hex(file: File): Promise<string> {
* 返回已通过校验的素材,可直接用于图片水印模板的 image_asset_id。
*/
export async function uploadWatermarkImage(file: File): Promise<MediaAsset> {
return uploadImage(file, 'watermark_image');
}
/** 商品图片沿用素材直传协议,完成服务端校验后才可写入 SKU 草稿。 */
export async function uploadProductImage(file: File): Promise<MediaAsset> {
return uploadImage(file, 'product_image');
}
async function uploadImage(
file: File,
purpose: CreateMediaUploadIntentRequest['purpose']
): Promise<MediaAsset> {
const checksumSha256 = await sha256Hex(file);
const intent = await mediaApi.createUploadIntent({
purpose: 'watermark_image',
purpose,
filename: file.name,
content_type: file.type as CreateMediaUploadIntentRequest['content_type'],
byte_size: file.size,