diff --git a/src/features/ecommerce/EcommercePage.tsx b/src/features/ecommerce/EcommercePage.tsx index ab4a3bc..d1bf1d3 100644 --- a/src/features/ecommerce/EcommercePage.tsx +++ b/src/features/ecommerce/EcommercePage.tsx @@ -367,310 +367,310 @@ const platformSpecOptions: Array<{ }> = [ { label: "淘宝/天猫", - ratios: ["淘宝主图 / SKU 鍥?800脳800px", "详情页宽 750px", "详情页宽 790px"], - defaultRatio: "淘宝主图 / SKU 鍥?800脳800px", + ratios: ["淘宝主图 / SKU 图 800×800px", "详情页宽 750px", "详情页宽 790px"], + defaultRatio: "淘宝主图 / SKU 图 800×800px", ratioGroups: { set: { - ratios: ["1000脳1000px\u00a0\u00a0\u00a01锛?", "800脳800px\u00a0\u00a0\u00a01锛?"], - defaultRatio: "1000脳1000px\u00a0\u00a0\u00a01锛?", + ratios: ["1000×1000px\u00a0\u00a0\u00a01:1", "800×800px\u00a0\u00a0\u00a01:1"], + defaultRatio: "1000×1000px\u00a0\u00a0\u00a01:1", }, detail: { ratios: [ - "750脳1000px\u00a0\u00a0\u00a03锛?", - "790脳1053px\u00a0\u00a0\u00a03锛?", - "750脳1125px\u00a0\u00a0\u00a02锛?", - "790脳1185px\u00a0\u00a0\u00a02锛?", + "750×1000px\u00a0\u00a0\u00a03:4", + "790×1053px\u00a0\u00a0\u00a03:4", + "750×1125px\u00a0\u00a0\u00a02:3", + "790×1185px\u00a0\u00a0\u00a02:3", ], - defaultRatio: "750脳1000px\u00a0\u00a0\u00a03锛?", + defaultRatio: "750×1000px\u00a0\u00a0\u00a03:4", }, model: { - ratios: ["750脳1000px\u00a0\u00a0\u00a03锛?"], - defaultRatio: "750脳1000px\u00a0\u00a0\u00a03锛?", + ratios: ["750×1000px\u00a0\u00a0\u00a03:4"], + defaultRatio: "750×1000px\u00a0\u00a0\u00a03:4", }, video: { - ratios: ["1080脳1920px\u00a0\u00a0\u00a09锛?6", "1080脳1440px\u00a0\u00a0\u00a03锛?", "1080脳1080px\u00a0\u00a0\u00a01锛?"], - defaultRatio: "1080脳1920px\u00a0\u00a0\u00a09锛?6", + ratios: ["1080×1920px\u00a0\u00a0\u00a09:16", "1080×1440px\u00a0\u00a0\u00a03:4", "1080×1080px\u00a0\u00a0\u00a01:1"], + defaultRatio: "1080×1920px\u00a0\u00a0\u00a09:16", }, hot: { - ratios: ["800脳800px\u00a0\u00a0\u00a01锛?"], - defaultRatio: "800脳800px\u00a0\u00a0\u00a01锛?", + ratios: ["800×800px\u00a0\u00a0\u00a01:1"], + defaultRatio: "800×800px\u00a0\u00a0\u00a01:1", }, }, - specs: ["主图 / SKU 鍥?800脳800px锛屸墹3MB", "详情页宽 750px 或?790px锛屽崟寮犻珮鈮?546px"], - tip: "建议主图 200-400KB JPG锛岃秴杩?500KB 浼氬奖鍝嶅姞杞介€熷害銆?", + specs: ["主图 / SKU 图 800×800px,≤3MB", "详情页宽 750px 或 790px,单张高度≤1546px"], + tip: "建议主图 200-400KB JPG,超过 500KB 会影响加载速度。", }, { label: "京东", - ratios: ["京东主图 / SKU 鍥?800脳800px", "详情页宽 750px", "首图主体占比 鈮?0%"], - defaultRatio: "京东主图 / SKU 鍥?800脳800px", + ratios: ["京东主图 / SKU 图 800×800px", "详情页宽 750px", "首图主体占比 ≥80%"], + defaultRatio: "京东主图 / SKU 图 800×800px", ratioGroups: { set: { - ratios: ["1000脳1000px\u00a0\u00a0\u00a01锛?"], - defaultRatio: "1000脳1000px\u00a0\u00a0\u00a01锛?", + ratios: ["1000×1000px\u00a0\u00a0\u00a01:1"], + defaultRatio: "1000×1000px\u00a0\u00a0\u00a01:1", }, detail: { ratios: [ - "750脳1000px\u00a0\u00a0\u00a03锛?", - "990脳1320px\u00a0\u00a0\u00a03锛?", - "750脳1125px\u00a0\u00a0\u00a02锛?", - "990脳1485px\u00a0\u00a0\u00a02锛?", + "750×1000px\u00a0\u00a0\u00a03:4", + "990×1320px\u00a0\u00a0\u00a03:4", + "750×1125px\u00a0\u00a0\u00a02:3", + "990×1485px\u00a0\u00a0\u00a02:3", ], - defaultRatio: "750脳1000px\u00a0\u00a0\u00a03锛?", + defaultRatio: "750×1000px\u00a0\u00a0\u00a03:4", }, model: { - ratios: ["750脳1125px\u00a0\u00a0\u00a02锛?", "990脳1485px\u00a0\u00a0\u00a02锛?"], - defaultRatio: "750脳1125px\u00a0\u00a0\u00a02锛?", + ratios: ["750×1125px\u00a0\u00a0\u00a02:3", "990×1485px\u00a0\u00a0\u00a02:3"], + defaultRatio: "750×1125px\u00a0\u00a0\u00a02:3", }, video: { - ratios: ["1080脳1920px\u00a0\u00a0\u00a09锛?6", "1920脳1080px\u00a0\u00a0\u00a016锛?"], - defaultRatio: "1080脳1920px\u00a0\u00a0\u00a09锛?6", + ratios: ["1080×1920px\u00a0\u00a0\u00a09:16", "1920×1080px\u00a0\u00a0\u00a016:9"], + defaultRatio: "1080×1920px\u00a0\u00a0\u00a09:16", }, hot: { - ratios: ["800脳800px\u00a0\u00a0\u00a01锛?"], - defaultRatio: "800脳800px\u00a0\u00a0\u00a01锛?", + ratios: ["800×800px\u00a0\u00a0\u00a01:1"], + defaultRatio: "800×800px\u00a0\u00a0\u00a01:1", }, }, - specs: ["主图 / SKU 鍥?800脳800px锛岀櫧搴曪紝鈮?MB", "详情页宽 750px锛岄鍥句富浣撳崰姣?鈮?0%"], + specs: ["主图 / SKU 图 800×800px,白底,≤3MB", "详情页宽 750px,首图主体占比 ≥80%"], }, { label: "拼多多", - ratios: ["主图 750脳352px", "主图 800脳800px", "详情页宽 750px"], - defaultRatio: "主图 750脳352px", + ratios: ["主图 750×352px", "主图 800×800px", "详情页宽 750px"], + defaultRatio: "主图 750×352px", ratioGroups: { set: { - ratios: ["800脳800px\u00a0\u00a0\u00a01锛?", "750脳1000px\u00a0\u00a0\u00a03锛?"], - defaultRatio: "800脳800px\u00a0\u00a0\u00a01锛?", + ratios: ["800×800px\u00a0\u00a0\u00a01:1", "750×1000px\u00a0\u00a0\u00a03:4"], + defaultRatio: "800×800px\u00a0\u00a0\u00a01:1", }, detail: { - ratios: ["750脳1000px\u00a0\u00a0\u00a03锛?", "750脳1125px\u00a0\u00a0\u00a02锛?"], - defaultRatio: "750脳1000px\u00a0\u00a0\u00a03锛?", + ratios: ["750×1000px\u00a0\u00a0\u00a03:4", "750×1125px\u00a0\u00a0\u00a02:3"], + defaultRatio: "750×1000px\u00a0\u00a0\u00a03:4", }, model: { - ratios: ["750脳1000px\u00a0\u00a0\u00a03锛?"], - defaultRatio: "750脳1000px\u00a0\u00a0\u00a03锛?", + ratios: ["750×1000px\u00a0\u00a0\u00a03:4"], + defaultRatio: "750×1000px\u00a0\u00a0\u00a03:4", }, video: { - ratios: ["1080脳1920px\u00a0\u00a0\u00a09锛?6"], - defaultRatio: "1080脳1920px\u00a0\u00a0\u00a09锛?6", + ratios: ["1080×1920px\u00a0\u00a0\u00a09:16"], + defaultRatio: "1080×1920px\u00a0\u00a0\u00a09:16", }, hot: { - ratios: ["800脳800px\u00a0\u00a0\u00a01锛?"], - defaultRatio: "800脳800px\u00a0\u00a0\u00a01锛?", + ratios: ["800×800px\u00a0\u00a0\u00a01:1"], + defaultRatio: "800×800px\u00a0\u00a0\u00a01:1", }, }, - specs: ["主图 750脳352px 或?800脳800px锛屸墹1MB", "详情页宽 750px,要求纯白底、无水印、无拼接"], + specs: ["主图 750×352px 或 800×800px,≤1MB", "详情页宽 750px,要求纯白底、无水印、无拼接"], }, { label: "抖音电商", - ratios: ["鐭棰?1080脳1920px"], - defaultRatio: "鐭棰?1080脳1920px", + ratios: ["短视频1080×1920px"], + defaultRatio: "短视频1080×1920px", ratioGroups: { video: { - ratios: ["1080脳1920px\u00a0\u00a0\u00a09锛?6"], - defaultRatio: "1080脳1920px\u00a0\u00a0\u00a09锛?6", + ratios: ["1080×1920px\u00a0\u00a0\u00a09:16"], + defaultRatio: "1080×1920px\u00a0\u00a0\u00a09:16", }, hot: { - ratios: ["800脳800px\u00a0\u00a0\u00a01锛?"], - defaultRatio: "800脳800px\u00a0\u00a0\u00a01锛?", + ratios: ["800×800px\u00a0\u00a0\u00a01:1"], + defaultRatio: "800×800px\u00a0\u00a0\u00a01:1", }, }, - specs: ["鐭棰?1080脳1920px锛?:16", "30s 图呮渶浣?"], + specs: ["短视频 1080×1920px,9:16", "30s 内最佳"], }, { label: "亚马逊 Amazon", - ratios: ["主图 鈮?600脳1600px", "建议 2000脳2000px+", "鏈€灏?500脳500px"], - defaultRatio: "主图 鈮?600脳1600px", + ratios: ["主图 ≥1600×1600px", "建议 2000×2000px+", "最小 500×500px"], + defaultRatio: "主图 ≥1600×1600px", ratioGroups: { set: { - ratios: ["1600脳1600px\u00a0\u00a0\u00a01锛?"], - defaultRatio: "1600脳1600px\u00a0\u00a0\u00a01锛?", + ratios: ["1600×1600px\u00a0\u00a0\u00a01:1"], + defaultRatio: "1600×1600px\u00a0\u00a0\u00a01:1", }, detail: { - ratios: ["1600脳1600px\u00a0\u00a0\u00a01锛?", "1200脳1800px\u00a0\u00a0\u00a02锛?", "1200脳1600px\u00a0\u00a0\u00a03锛?"], - defaultRatio: "1200脳1800px\u00a0\u00a0\u00a02锛?", + ratios: ["1600×1600px\u00a0\u00a0\u00a01:1", "1200×1800px\u00a0\u00a0\u00a02:3", "1200×1600px\u00a0\u00a0\u00a03:4"], + defaultRatio: "1200×1800px\u00a0\u00a0\u00a02:3", }, model: { - ratios: ["1200脳1800px\u00a0\u00a0\u00a02锛?"], - defaultRatio: "1200脳1800px\u00a0\u00a0\u00a02锛?", + ratios: ["1200×1800px\u00a0\u00a0\u00a02:3"], + defaultRatio: "1200×1800px\u00a0\u00a0\u00a02:3", }, video: { - ratios: ["1920脳1080px\u00a0\u00a0\u00a016锛?"], - defaultRatio: "1920脳1080px\u00a0\u00a0\u00a016锛?", + ratios: ["1920×1080px\u00a0\u00a0\u00a016:9"], + defaultRatio: "1920×1080px\u00a0\u00a0\u00a016:9", }, hot: { - ratios: ["1600脳1600px\u00a0\u00a0\u00a01锛?"], - defaultRatio: "1600脳1600px\u00a0\u00a0\u00a01锛?", + ratios: ["1600×1600px\u00a0\u00a0\u00a01:1"], + defaultRatio: "1600×1600px\u00a0\u00a0\u00a01:1", }, }, - specs: ["主图 1600脳1600px+,纯白底,≤10MB", "鏈€灏?500脳500px锛屽缓璁?2000px+ 浠ユ敮鎸佺缉鏀?"], - aliases: ["浜氶┈閫?"], + specs: ["主图 1600×1600px+,纯白底,≤10MB", "最小 500×500px,建议 2000px+ 以支持缩放"], + aliases: ["亚马逊"], }, { label: "Shopee", - ratios: ["商品主图 1024脳1024px", "基础主图 800脳800px"], - defaultRatio: "商品主图 1024脳1024px", + ratios: ["商品主图 1024×1024px", "基础主图 800×800px"], + defaultRatio: "商品主图 1024×1024px", ratioGroups: { set: { - ratios: ["800脳800px\u00a0\u00a0\u00a01锛?"], - defaultRatio: "800脳800px\u00a0\u00a0\u00a01锛?", + ratios: ["800×800px\u00a0\u00a0\u00a01:1"], + defaultRatio: "800×800px\u00a0\u00a0\u00a01:1", }, detail: { - ratios: ["750脳1000px\u00a0\u00a0\u00a03锛?", "750脳1125px\u00a0\u00a0\u00a02锛?"], - defaultRatio: "750脳1000px\u00a0\u00a0\u00a03锛?", + ratios: ["750×1000px\u00a0\u00a0\u00a03:4", "750×1125px\u00a0\u00a0\u00a02:3"], + defaultRatio: "750×1000px\u00a0\u00a0\u00a03:4", }, model: { - ratios: ["750脳1000px\u00a0\u00a0\u00a03锛?"], - defaultRatio: "750脳1000px\u00a0\u00a0\u00a03锛?", + ratios: ["750×1000px\u00a0\u00a0\u00a03:4"], + defaultRatio: "750×1000px\u00a0\u00a0\u00a03:4", }, video: { - ratios: ["1080脳1920px\u00a0\u00a0\u00a09锛?6"], - defaultRatio: "1080脳1920px\u00a0\u00a0\u00a09锛?6", + ratios: ["1080×1920px\u00a0\u00a0\u00a09:16"], + defaultRatio: "1080×1920px\u00a0\u00a0\u00a09:16", }, hot: { - ratios: ["800脳800px\u00a0\u00a0\u00a01锛?"], - defaultRatio: "800脳800px\u00a0\u00a0\u00a01锛?", + ratios: ["800×800px\u00a0\u00a0\u00a01:1"], + defaultRatio: "800×800px\u00a0\u00a0\u00a01:1", }, }, - specs: ["商品主图推荐 1024脳1024px,基础 800脳800px", "鈮?MB锛岀櫧搴曟垨娴呰壊搴?"], + specs: ["商品主图推荐 1024×1024px,基础 800×800px", "≤2MB,白底或浅色底"], aliases: ["虾皮 Shopee/Lazada", "虾皮"], }, { label: "Lazada", - ratios: ["商品主图 800脳800px"], - defaultRatio: "商品主图 800脳800px", + ratios: ["商品主图 800×800px"], + defaultRatio: "商品主图 800×800px", ratioGroups: { set: { - ratios: ["800脳800px\u00a0\u00a0\u00a01锛?"], - defaultRatio: "800脳800px\u00a0\u00a0\u00a01锛?", + ratios: ["800×800px\u00a0\u00a0\u00a01:1"], + defaultRatio: "800×800px\u00a0\u00a0\u00a01:1", }, detail: { - ratios: ["750脳1000px\u00a0\u00a0\u00a03锛?", "750脳1125px\u00a0\u00a0\u00a02锛?"], - defaultRatio: "750脳1000px\u00a0\u00a0\u00a03锛?", + ratios: ["750×1000px\u00a0\u00a0\u00a03:4", "750×1125px\u00a0\u00a0\u00a02:3"], + defaultRatio: "750×1000px\u00a0\u00a0\u00a03:4", }, model: { - ratios: ["750脳1000px\u00a0\u00a0\u00a03锛?"], - defaultRatio: "750脳1000px\u00a0\u00a0\u00a03锛?", + ratios: ["750×1000px\u00a0\u00a0\u00a03:4"], + defaultRatio: "750×1000px\u00a0\u00a0\u00a03:4", }, video: { - ratios: ["1080脳1920px\u00a0\u00a0\u00a09锛?6"], - defaultRatio: "1080脳1920px\u00a0\u00a0\u00a09锛?6", + ratios: ["1080×1920px\u00a0\u00a0\u00a09:16"], + defaultRatio: "1080×1920px\u00a0\u00a0\u00a09:16", }, hot: { - ratios: ["800脳800px\u00a0\u00a0\u00a01锛?"], - defaultRatio: "800脳800px\u00a0\u00a0\u00a01锛?", + ratios: ["800×800px\u00a0\u00a0\u00a01:1"], + defaultRatio: "800×800px\u00a0\u00a0\u00a01:1", }, }, - specs: ["商品主图 800脳800px锛?:1"], + specs: ["商品主图 800×800px,1:1"], }, { label: "Instagram", - ratios: ["帖子 1080脳1350px", "帖子 1080脳1080px", "Stories / Reels 1080脳1920px", "头像 320脳320px"], - defaultRatio: "帖子 1080脳1350px", + ratios: ["帖子 1080×1350px", "帖子 1080×1080px", "Stories / Reels 1080×1920px", "头像 320×320px"], + defaultRatio: "帖子 1080×1350px", ratioGroups: { set: { - ratios: ["1080脳1080px\u00a0\u00a0\u00a01锛?", "1080脳1350px\u00a0\u00a0\u00a04锛?"], - defaultRatio: "1080脳1080px\u00a0\u00a0\u00a01锛?", + ratios: ["1080×1080px\u00a0\u00a0\u00a01:1", "1080×1350px\u00a0\u00a0\u00a04:5"], + defaultRatio: "1080×1080px\u00a0\u00a0\u00a01:1", }, detail: { - ratios: ["1080脳1350px\u00a0\u00a0\u00a04锛?"], - defaultRatio: "1080脳1350px\u00a0\u00a0\u00a04锛?", + ratios: ["1080×1350px\u00a0\u00a0\u00a04:5"], + defaultRatio: "1080×1350px\u00a0\u00a0\u00a04:5", }, model: { - ratios: ["1080脳1350px\u00a0\u00a0\u00a04锛?"], - defaultRatio: "1080脳1350px\u00a0\u00a0\u00a04锛?", + ratios: ["1080×1350px\u00a0\u00a0\u00a04:5"], + defaultRatio: "1080×1350px\u00a0\u00a0\u00a04:5", }, video: { - ratios: ["1080脳1920px\u00a0\u00a0\u00a09锛?6", "1080脳1350px\u00a0\u00a0\u00a04锛?"], - defaultRatio: "1080脳1920px\u00a0\u00a0\u00a09锛?6", + ratios: ["1080×1920px\u00a0\u00a0\u00a09:16", "1080×1350px\u00a0\u00a0\u00a04:5"], + defaultRatio: "1080×1920px\u00a0\u00a0\u00a09:16", }, }, - specs: ["帖子 1080脳1350px 或?1080脳1080px", "Stories / Reels 封面 1080脳1920px锛屽ご鍍?320脳320px"], - tip: "建议 鈮?MB JPG銆?", + specs: ["帖子 1080×1350px 或 1080×1080px", "Stories / Reels 封面 1080×1920px,头像 320×320px"], + tip: "建议 ≤8MB JPG。", aliases: ["Instagram Reels"], }, { label: "速卖通", - ratios: ["主图 800脳800px", "主图 1000脳1000px+"], - defaultRatio: "主图 800脳800px", + ratios: ["主图 800×800px", "主图 1000×1000px+"], + defaultRatio: "主图 800×800px", ratioGroups: { set: { - ratios: ["1000脳1000px\u00a0\u00a0\u00a01锛?"], - defaultRatio: "1000脳1000px\u00a0\u00a0\u00a01锛?", + ratios: ["1000×1000px\u00a0\u00a0\u00a01:1"], + defaultRatio: "1000×1000px\u00a0\u00a0\u00a01:1", }, detail: { - ratios: ["750脳1125px\u00a0\u00a0\u00a02锛?", "750脳1000px\u00a0\u00a0\u00a03锛?"], - defaultRatio: "750脳1125px\u00a0\u00a0\u00a02锛?", + ratios: ["750×1125px\u00a0\u00a0\u00a02:3", "750×1000px\u00a0\u00a0\u00a03:4"], + defaultRatio: "750×1125px\u00a0\u00a0\u00a02:3", }, model: { - ratios: ["750脳1125px\u00a0\u00a0\u00a02锛?"], - defaultRatio: "750脳1125px\u00a0\u00a0\u00a02锛?", + ratios: ["750×1125px\u00a0\u00a0\u00a02:3"], + defaultRatio: "750×1125px\u00a0\u00a0\u00a02:3", }, video: { - ratios: ["1080脳1920px\u00a0\u00a0\u00a09锛?6", "1920脳1080px\u00a0\u00a0\u00a016锛?"], - defaultRatio: "1080脳1920px\u00a0\u00a0\u00a09锛?6", + ratios: ["1080×1920px\u00a0\u00a0\u00a09:16", "1920×1080px\u00a0\u00a0\u00a016:9"], + defaultRatio: "1080×1920px\u00a0\u00a0\u00a09:16", }, hot: { - ratios: ["800脳800px\u00a0\u00a0\u00a01锛?"], - defaultRatio: "800脳800px\u00a0\u00a0\u00a01锛?", + ratios: ["800×800px\u00a0\u00a0\u00a01:1"], + defaultRatio: "800×800px\u00a0\u00a0\u00a01:1", }, }, - specs: ["主图建议 800脳800px 或更高,1:1", "适合跨境电商主图、SKU 鍥惧拰鍦烘櫙鍥?"], + specs: ["主图建议 800×800px 或更高,1:1", "适合跨境电商主图、SKU 图和场景图"], }, { label: "eBay", - ratios: ["鍟嗗搧鍥?1:1", "白底多角度展示图 1:1"], - defaultRatio: "鍟嗗搧鍥?1:1", + ratios: ["商品图1:1", "白底多角度展示图 1:1"], + defaultRatio: "商品图1:1", ratioGroups: { set: { - ratios: ["1600脳1600px\u00a0\u00a0\u00a01锛?"], - defaultRatio: "1600脳1600px\u00a0\u00a0\u00a01锛?", + ratios: ["1600×1600px\u00a0\u00a0\u00a01:1"], + defaultRatio: "1600×1600px\u00a0\u00a0\u00a01:1", }, detail: { - ratios: ["1000脳1500px\u00a0\u00a0\u00a02锛?", "1200脳1600px\u00a0\u00a0\u00a03锛?"], - defaultRatio: "1000脳1500px\u00a0\u00a0\u00a02锛?", + ratios: ["1000×1500px\u00a0\u00a0\u00a02:3", "1200×1600px\u00a0\u00a0\u00a03:4"], + defaultRatio: "1000×1500px\u00a0\u00a0\u00a02:3", }, model: { - ratios: ["1000脳1500px\u00a0\u00a0\u00a02锛?"], - defaultRatio: "1000脳1500px\u00a0\u00a0\u00a02锛?", + ratios: ["1000×1500px\u00a0\u00a0\u00a02:3"], + defaultRatio: "1000×1500px\u00a0\u00a0\u00a02:3", }, video: { - ratios: ["1920脳1080px\u00a0\u00a0\u00a016锛?", "1080脳1920px\u00a0\u00a0\u00a09锛?6"], - defaultRatio: "1920脳1080px\u00a0\u00a0\u00a016锛?", + ratios: ["1920×1080px\u00a0\u00a0\u00a016:9", "1080×1920px\u00a0\u00a0\u00a09:16"], + defaultRatio: "1920×1080px\u00a0\u00a0\u00a016:9", }, hot: { - ratios: ["1600脳1600px\u00a0\u00a0\u00a01锛?"], - defaultRatio: "1600脳1600px\u00a0\u00a0\u00a01锛?", + ratios: ["1600×1600px\u00a0\u00a0\u00a01:1"], + defaultRatio: "1600×1600px\u00a0\u00a0\u00a01:1", }, }, - specs: ["鍟嗗搧鍥惧缓璁?1:1锛屼富浣撴竻鏅板眳涓?", "閫傚悎白底主图鍜屽瑙掑害灞曠ず鍥?"], + specs: ["商品图建议 1:1,主体清晰居中", "适合白底主图和多角度展示图"], }, { label: "TikTok Shop", - ratios: ["商品主图 1:1", "鐭棰?/ 竖版封面 9:16"], + ratios: ["商品主图 1:1", "短视频/ 竖版封面 9:16"], defaultRatio: "商品主图 1:1", ratioGroups: { set: { - ratios: ["1280脳1280px\u00a0\u00a0\u00a01锛?"], - defaultRatio: "1280脳1280px\u00a0\u00a0\u00a01锛?", + ratios: ["1280×1280px\u00a0\u00a0\u00a01:1"], + defaultRatio: "1280×1280px\u00a0\u00a0\u00a01:1", }, detail: { - ratios: ["1080脳1350px\u00a0\u00a0\u00a04锛?"], - defaultRatio: "1080脳1350px\u00a0\u00a0\u00a04锛?", + ratios: ["1080×1350px\u00a0\u00a0\u00a04:5"], + defaultRatio: "1080×1350px\u00a0\u00a0\u00a04:5", }, model: { - ratios: ["1080脳1350px\u00a0\u00a0\u00a04锛?"], - defaultRatio: "1080脳1350px\u00a0\u00a0\u00a04锛?", + ratios: ["1080×1350px\u00a0\u00a0\u00a04:5"], + defaultRatio: "1080×1350px\u00a0\u00a0\u00a04:5", }, video: { - ratios: ["1080脳1920px\u00a0\u00a0\u00a09锛?6"], - defaultRatio: "1080脳1920px\u00a0\u00a0\u00a09锛?6", + ratios: ["1080×1920px\u00a0\u00a0\u00a09:16"], + defaultRatio: "1080×1920px\u00a0\u00a0\u00a09:16", }, hot: { - ratios: ["800脳800px\u00a0\u00a0\u00a01锛?"], - defaultRatio: "800脳800px\u00a0\u00a0\u00a01锛?", + ratios: ["800×800px\u00a0\u00a0\u00a01:1"], + defaultRatio: "800×800px\u00a0\u00a0\u00a01:1", }, }, - specs: ["商品主图建议 1:1", "鐭棰?竖版封面建议 9:16"], + specs: ["商品主图建议 1:1", "短视频竖版封面建议 9:16"], }, ]; const platformOptions = platformSpecOptions.map((option) => option.label); @@ -684,7 +684,7 @@ const getPlatformLogoSources = (value: string) => { if (normalized.includes("shopee")) return [shopeeLogo]; if (normalized.includes("lazada")) return [lazadaLogo]; if (normalized.includes("instagram")) return [instagramLogo]; - if (value.includes("速卖通") || value.includes("閫熷崠閫")) return [aliexpressLogo]; + if (value.includes("速卖通")) return [aliexpressLogo]; if (normalized.includes("ebay")) return [ebayLogo]; if (normalized.includes("tiktok")) return [tiktokShopLogo]; return []; @@ -744,7 +744,7 @@ const languageAliases: Record = { "西班牙语": "西班牙语", "葡文": "葡萄牙语", "葡萄牙语": "葡萄牙语", - "鍗板凹璇?": "印度尼西亚语", + "印尼语": "印度尼西亚语", "印度尼西亚语": "印度尼西亚语", "菲律宾语": "菲律宾语(他加禄语)", "菲律宾语(他加禄语)": "菲律宾语(他加禄语)", @@ -755,10 +755,10 @@ const getPlatformSpec = (value: string) => const legacyPlatformAliases: Record = { "淘宝/天猫": "淘宝/天猫", "京东": "京东", - "鎷煎澶?": "拼多多", + "拼多多": "拼多多", "抖音电商": "抖音电商", - "浜氶┈閫?Amazon": "亚马逊 Amazon", - "閫熷崠閫?": "速卖通", + "亚马逊Amazon": "亚马逊 Amazon", + "速卖通": "速卖通", }; const normalizePlatform = (value: string) => getPlatformSpec(legacyPlatformAliases[value] ?? value).label; const domesticPlatformLabels = new Set(["淘宝/天猫", "京东", "拼多多", "抖音电商"]); @@ -811,13 +811,13 @@ const formatRatioDisplayValue = (value: string) => { return `${width}×${height}px\u00a0\u00a0\u00a0${formatAspectRatio(width, height)}`; } return normalizedValue - .replace("淘宝主图 / SKU 鍥?", "淘宝主图 / SKU 图 ") - .replace("京东主图 / SKU 鍥?", "京东主图 / SKU 图 ") + .replace("淘宝主图 / SKU 图 ", "淘宝主图 / SKU 图 ") + .replace("京东主图 / SKU 图 ", "京东主图 / SKU 图 ") .replace("详情页宽", "详情页宽") - .replace("鐭棰?", "短视频") + .replace("短视频", "短视频") .replace("主图", "主图") .replace("商品主图", "商品主图") - .replace("鍟嗗搧鍥?", "商品图"); + .replace("商品图", "商品图"); }; /** Extract CSS aspect-ratio from a ratio string like "1000x1000px 1:1" -> "1 / 1" */ const parseRatioToAspectCss = (ratioStr: string): string => { @@ -825,7 +825,7 @@ const parseRatioToAspectCss = (ratioStr: string): string => { if (!match) return "1 / 1"; return `${match[1]} / ${match[2]}`; }; -/** Normalize ratio display string ("1000脳1000px 1锛?") to API format ("1:1") */ +/** Normalize ratio display string ("1000×1000px 1:1") to API format ("1:1") */ const normalizeRatioForApi = (ratioStr: string): string => { const match = ratioStr.match(/(\d+)\D+(\d+)/u); if (!match) return "1:1"; @@ -938,7 +938,7 @@ const productSetAssets = ossAssets.ecommerce.productSet; const productSetPreviewCards = [ { id: "main", label: "01 主图 (白底/合规)", src: productSetAssets.main }, { id: "scene", label: "02 场景展示", src: productSetAssets.scene }, - { id: "model", label: "03 妯$壒鍦烘櫙鍥?", src: productSetAssets.model }, + { id: "model", label: "03 模特场景图", src: productSetAssets.model }, { id: "detail", label: "04 细节说明", src: productSetAssets.detail }, { id: "selling", label: "05 卖点详解", src: productSetAssets.selling }, ]; @@ -998,6 +998,22 @@ function getImageFileFormat(file: File) { return file.name.split(".").pop()?.toUpperCase() ?? ""; } +function getRemoteImageFormat(mimeType: string, imageUrl: string) { + const mimeFormat = mimeType.split("/")[1]?.replace("jpeg", "jpg").toUpperCase(); + if (mimeFormat) return mimeFormat; + return imageUrl.split("?")[0].split(".").pop()?.toUpperCase() ?? "IMAGE"; +} + +function getRemoteImageName(imageUrl: string, fallback: string) { + try { + const parsed = new URL(imageUrl); + const filename = decodeURIComponent(parsed.pathname.split("/").filter(Boolean).pop() || ""); + return filename || fallback; + } catch { + return fallback; + } +} + function readImageDimensions(src: string): Promise<{ width: number; height: number }> { return new Promise((resolve, reject) => { const image = new Image(); @@ -1219,7 +1235,9 @@ function ProductClonePage(_props: ProductClonePageProps = {}) { const cloneReferenceInputRef = useRef(null); const smartCutoutInputRef = useRef(null); const imageWorkbenchInputRef = useRef(null); + const imageWorkbenchUrlInputRef = useRef(null); const watermarkInputRef = useRef(null); + const watermarkUrlInputRef = useRef(null); const watermarkProcessTimeoutRef = useRef(null); const smartCutoutTransitionTimeoutRef = useRef(null); const smartCutoutPendingUrlsRef = useRef([]); @@ -1698,7 +1716,7 @@ function ProductClonePage(_props: ProductClonePageProps = {}) { }); setProductSetStatus("ready"); } catch (err) { - toast.error(err instanceof Error ? err.message : "鍟嗗搧鍥句笂浼犲け璐?"); + toast.error(err instanceof Error ? err.message : "商品图上传失败"); } }; @@ -1793,6 +1811,49 @@ function ProductClonePage(_props: ProductClonePageProps = {}) { setIsCloneSettingsCollapsed(false); }; + const loadRemoteImageFromInput = async (input: HTMLInputElement | null, fallbackName: string) => { + const rawValue = input?.value.trim() ?? ""; + if (!rawValue) { + toast.info("请先粘贴图片 URL"); + return null; + } + + let imageUrl: string; + try { + const parsed = new URL(rawValue, window.location.href); + if (parsed.protocol !== "http:" && parsed.protocol !== "https:") { + throw new Error("仅支持 http 或 https 图片链接"); + } + imageUrl = parsed.toString(); + } catch (error) { + toast.error(error instanceof Error ? error.message : "图片 URL 不正确"); + return null; + } + + try { + const response = await fetch(imageUrl); + if (!response.ok) throw new Error(`图片读取失败(${response.status})`); + const blob = await response.blob(); + if (!blob.type.startsWith("image/")) throw new Error("链接内容不是图片"); + const src = URL.createObjectURL(blob); + try { + await readImageDimensions(src); + } catch { + URL.revokeObjectURL(src); + throw new Error("图片无法预览,请换一个链接"); + } + if (input) input.value = ""; + return { + src, + name: getRemoteImageName(imageUrl, fallbackName), + format: getRemoteImageFormat(blob.type, imageUrl), + }; + } catch (error) { + toast.error(error instanceof Error ? error.message : "图片导入失败"); + return null; + } + }; + const closeWatermarkRemovalPage = () => { if (watermarkProcessTimeoutRef.current !== null) { window.clearTimeout(watermarkProcessTimeoutRef.current); @@ -1846,6 +1907,18 @@ function ProductClonePage(_props: ProductClonePageProps = {}) { if (file) addWatermarkImage(file); }; + const handleWatermarkUrlImport = async () => { + const nextImage = await loadRemoteImageFromInput(watermarkUrlInputRef.current, "watermark-source"); + if (!nextImage) return; + setWatermarkImage((current) => { + if (current?.src) URL.revokeObjectURL(current.src); + return nextImage; + }); + setWatermarkStatus("idle"); + setActiveQuickTool("watermark"); + toast.success("图片已导入"); + }; + const handleWatermarkGenerate = () => { if (!watermarkImage || watermarkStatus === "processing") return; if (watermarkProcessTimeoutRef.current !== null) window.clearTimeout(watermarkProcessTimeoutRef.current); @@ -1943,6 +2016,22 @@ function ProductClonePage(_props: ProductClonePageProps = {}) { if (file) addImageWorkbenchImage(file); }; + const handleImageWorkbenchUrlImport = async () => { + const nextImage = await loadRemoteImageFromInput(imageWorkbenchUrlInputRef.current, "image-workbench-source"); + if (!nextImage) return; + setImageWorkbenchImage((current) => { + if (current?.src) URL.revokeObjectURL(current.src); + return nextImage; + }); + setImageWorkbenchStatus("idle"); + setImageWorkbenchMaskStrokes([]); + setImageWorkbenchBrushCursor(null); + clearImageWorkbenchMaskCanvas(); + imageWorkbenchActiveStrokeIdRef.current = null; + setActiveQuickTool("image-edit"); + toast.success("图片已导入"); + }; + const handleImageWorkbenchGenerate = () => { if (!imageWorkbenchImage) { toast.info("请先上传图片"); @@ -2444,7 +2533,7 @@ function ProductClonePage(_props: ProductClonePageProps = {}) { setStatus("ready"); setResults([]); } catch (err) { - toast.error(err instanceof Error ? err.message : "鍟嗗搧鍥句笂浼犲け璐?"); + toast.error(err instanceof Error ? err.message : "商品图上传失败"); } }; @@ -2961,7 +3050,7 @@ function ProductClonePage(_props: ProductClonePageProps = {}) { setGarmentImages((current) => [...current, ...nextImages].slice(0, 5)); setTryOnStatus("ready"); } catch (err) { - toast.error(err instanceof Error ? err.message : "鏈嶉グ鍥句笂浼犲け璐?"); + toast.error(err instanceof Error ? err.message : "服饰图上传失败"); } })(); event.target.value = ""; @@ -3011,7 +3100,7 @@ function ProductClonePage(_props: ProductClonePageProps = {}) { setDetailStatus("ready"); setDetailResultUrl(null); } catch (err) { - toast.error(err instanceof Error ? err.message : "璇︽儏鍥句笂浼犲け璐?"); + toast.error(err instanceof Error ? err.message : "详情图上传失败"); } }; @@ -3040,9 +3129,9 @@ function ProductClonePage(_props: ProductClonePageProps = {}) { const IMAGE_MODEL = "gpt-image-2"; const setCountLabels: Record = { - selling: { label: "鍗栫偣鍥?", promptDesc: "selling-point infographic image highlighting core product advantages and detail close-ups" }, - white: { label: "白底鍥?", promptDesc: "clean white-background product photo showing the item from its best angle, studio lighting, no props" }, - scene: { label: "鍦烘櫙鍥?", promptDesc: "lifestyle scene image showing the product in a realistic usage environment with natural surroundings" }, + selling: { label: "卖点图", promptDesc: "selling-point infographic image highlighting core product advantages and detail close-ups" }, + white: { label: "白底图", promptDesc: "clean white-background product photo showing the item from its best angle, studio lighting, no props" }, + scene: { label: "场景图", promptDesc: "lifestyle scene image showing the product in a realistic usage environment with natural surroundings" }, }; const buildDetailModulePrompt = (moduleIds: string[]): string => { @@ -3182,7 +3271,7 @@ function ProductClonePage(_props: ProductClonePageProps = {}) { imageGen.updateTask(storeId, { status: "completed", progress: 100, resultUrl: persistedUrl }); } else { generatedUrls.push(""); - imageGen.updateTask(storeId, { status: "failed", error: "生成鏈繑鍥炵粨鏋?" }); + imageGen.updateTask(storeId, { status: "failed", error: "生成未返回结果" }); } } } @@ -3270,7 +3359,7 @@ function ProductClonePage(_props: ProductClonePageProps = {}) { imageGen.updateTask(storeId, { status: "completed", progress: 100, resultUrl: persistedUrl }); } else { statusFn?.("idle"); - imageGen.updateTask(storeId, { status: "failed", error: "生成鏈繑鍥炵粨鏋?" }); + imageGen.updateTask(storeId, { status: "failed", error: "生成未返回结果" }); } } catch (err) { if (imageAbortRef.current.current) { @@ -3467,7 +3556,7 @@ function ProductClonePage(_props: ProductClonePageProps = {}) { const handleDetailAiWrite = () => { setDetailRequirement( - "1.产品名称:无线降噪蓝牙耳机\n2.鏍稿績鍗栫偣锛氫富鍔ㄩ檷鍣€?4H续航、低延迟连接、舒适佩戴\n3.适用人群:通勤、办公、运动和旅行用户\n4.期望场景:地铁通勤、居家办公、户外运动\n5.鍏蜂綋参数锛氳摑鐗?.3銆両PX4闃叉按銆佸揩鍏?0分钟使用2小时", + "1.产品名称:无线降噪蓝牙耳机\n2.核心卖点:主动降噪、24H续航、低延迟连接、舒适佩戴\n3.适用人群:通勤、办公、运动和旅行用户\n4.期望场景:地铁通勤、居家办公、户外运动\n5.具体参数:蓝牙5.3、IPX4防水、快充10分钟使用2小时", ); }; @@ -3547,19 +3636,19 @@ function ProductClonePage(_props: ProductClonePageProps = {}) { const isWatermarkTool = isCloneTool && activeQuickTool === "watermark"; const isImageEditTool = isCloneTool && activeQuickTool === "image-edit"; const isHotVideoTool = isCloneTool && activeQuickTool === "hot-video"; - const pageLabel = isSetTool ? "商品套图" : isDetail ? "A+/璇︽儏椤?" : isTryOn ? "AI服饰穿戴" : activeToolMeta?.label || "商品工具"; + const pageLabel = isSetTool ? "商品套图" : isDetail ? "A+/详情页" : isTryOn ? "AI服饰穿戴" : activeToolMeta?.label || "商品工具"; const setPrimaryLabel = setImages.length === 0 ? "请先上传商品原图" : productSetStatus === "generating" - ? "生成涓?.." + ? "生成中..." : "生成" + selectedProductSetOutput.label; const tryOnPrimaryLabel = - garmentImages.length === 0 ? "请先上传服装图片" : tryOnStatus === "generating" ? "生成涓?.." : "生成服饰穿戴鍥?"; + garmentImages.length === 0 ? "请先上传服装图片" : tryOnStatus === "generating" ? "生成中..." : "生成服饰穿戴图"; const detailPrimaryLabel = - detailProductImages.length === 0 ? "请上传产品图" : detailStatus === "generating" ? "生成涓?.." : "生成A+璇︽儏椤?"; + detailProductImages.length === 0 ? "请上传产品图" : detailStatus === "generating" ? "生成中..." : "生成A+详情页"; const clonePrimaryLabel = - productImages.length === 0 ? "请先上传商品原图" : status === "generating" ? "生成涓?.." : "生成" + selectedCloneOutput.label; + productImages.length === 0 ? "请先上传商品原图" : status === "generating" ? "生成中..." : "生成" + selectedCloneOutput.label; const setPreviewCards: CloneResult[] = []; let setIndex = 0; for (const countKey of cloneSetCountKeys) { @@ -3693,7 +3782,7 @@ function ProductClonePage(_props: ProductClonePageProps = {}) { if (historyRefreshLockRef.current) return; historyRefreshLockRef.current = true; setIsHistoryRefreshing(true); - setHistoryRefreshMessage("鍒锋柊涓?.."); + setHistoryRefreshMessage("刷新中..."); setHistoryRefreshStamp(Date.now()); window.setTimeout(() => { @@ -4023,7 +4112,7 @@ function ProductClonePage(_props: ProductClonePageProps = {}) { value={productSetRequirement} onChange={(event) => setProductSetRequirement(event.target.value)} maxLength={500} - placeholder="建议鍖呭惈浠ヤ笅淇℃伅锛氫骇鍝佸悕绉般€佹牳蹇冨崠鐐广€佹湡鏈涘満鏅€佸叿浣撳弬鏁?" + placeholder="建议包含以下信息:产品名称、核心卖点、期望场景、具体参数" /> {productImages.length || videoOutfitVideoFile ? ( -
+
{productImages.map((image) => (
{image.name @@ -4675,7 +4764,7 @@ function ProductClonePage(_props: ProductClonePageProps = {}) { ); const smartCutoutPreview = ( -
+
+
- - + { + if (event.key === "Enter") void handleImageWorkbenchUrlImport(); + }} + /> +
@@ -5155,7 +5251,7 @@ function ProductClonePage(_props: ProductClonePageProps = {}) { ); const watermarkPreview = ( -
+
- - + { + if (event.key === "Enter") void handleWatermarkUrlImport(); + }} + /> +
@@ -5350,7 +5453,7 @@ function ProductClonePage(_props: ProductClonePageProps = {}) { ); const hotVideoPreview = ( -
+