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
+26 -3
View File
@@ -5,17 +5,21 @@ const checksum = z
.regex(/^[a-f0-9]{64}$/, '必须是 SHA-256 十六进制摘要');
export const createMediaUploadIntentRequestSchema = z
.object({
purpose: z.literal('watermark_image'),
purpose: z.enum(['watermark_image', 'product_image']),
filename: z.string().trim().min(1).max(255),
content_type: z.enum(['image/png', 'image/jpeg', 'image/webp']),
byte_size: z
.number()
.int()
.min(1)
.max(5 * 1024 * 1024),
.max(20 * 1024 * 1024),
checksum_sha256: checksum,
})
.strict();
.strict()
.refine(
(value) => value.purpose !== 'watermark_image' || value.byte_size <= 5 * 1024 * 1024,
{ path: ['byte_size'], message: '水印图片不能超过 5 MiB' },
);
export const completeMediaUploadIntentRequestSchema = z
.object({
checksum_sha256: checksum,
@@ -26,6 +30,18 @@ export const createMediaAccessUrlRequestSchema = z
purpose: z.literal('preview'),
})
.strict();
export const importProductImageRequestSchema = z.object({
url: z.url().max(2048).refine((value) => {
try {
const url = new URL(value);
return url.protocol === 'https:' && !url.username && !url.password && !url.port
&& /\.(?:jpe?g|png)$/i.test(url.pathname);
} catch {
return false;
}
}, '仅支持 HTTPS 的 JPG 或 PNG 图片链接'),
}).strict();
export type ImportProductImageRequest = z.infer<typeof importProductImageRequestSchema>;
export type CreateMediaUploadIntentRequest = z.infer<
typeof createMediaUploadIntentRequestSchema
@@ -60,6 +76,13 @@ export type MediaAsset = {
created_at: string;
};
/** 工作空间已上传的商品图片,预览地址过期后需重新读取。 */
export type ProductUploadImage = MediaAsset & {
preview_url: string;
preview_url_expires_at: string;
};
export type ProductImportedImage = ProductUploadImage & { source_url: string };
/** POST /api/media-assets/{asset_id}/access-urls 响应(短时预览 URL) */
export type MediaAccessUrl = {
url: string;
+1 -1
View File
@@ -552,7 +552,7 @@ export const saveProductEditorDraftRequestSchema = z
offer_id: nullableText(500),
media_asset_ids: z
.array(uuid)
.max(15)
.max(30)
.refine(
(ids) => new Set(ids).size === ids.length,
'SKU 图片不能重复',