From 6dd2a107fd3c1c9e1d7b5c2bc5eef59670462d78 Mon Sep 17 00:00:00 2001
From: ludan <251918489@qq.com>
Date: Wed, 17 Jun 2026 17:02:10 +0800
Subject: [PATCH 1/2] =?UTF-8?q?feat:=20=E7=94=B5=E5=95=86=E5=88=9B?=
=?UTF-8?q?=E4=BD=9C=E5=9C=BA=E6=99=AF=E6=94=AF=E6=8C=81=E5=B8=A6=E8=B4=A7?=
=?UTF-8?q?=E8=A7=86=E9=A2=91=E6=97=B6=E9=95=BF=E3=80=81=E7=A7=BB=E5=8A=A8?=
=?UTF-8?q?=E7=AB=AF=E9=9A=90=E8=97=8F=E8=AE=BE=E7=BD=AE=E6=8C=89=E9=92=AE?=
=?UTF-8?q?=E3=80=81=E4=BC=98=E5=8C=96=E5=B9=B3=E5=8F=B0=E9=80=89=E6=8B=A9?=
=?UTF-8?q?=E5=99=A8=E6=A0=B7=E5=BC=8F?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 新增带货视频时长选项(5/10/15秒)及时长选择 popover
- 创作标签在移动端(<=640px)隐藏平台/语种/比例/设置/时长按钮行,仅保留文本输入框
- 重构平台选择器为单列滚动列表,移除平台 logo,统一比例/语种/平台 active 高亮样式
- 优化 composer 整体布局节奏(素材紧凑、工具栏底部固定、响应式高度)
- 调整 AI 帮写提交按钮为青色系渐变样式
---
src/features/ecommerce/EcommercePage.tsx | 54 ++-
src/styles/ecommerce-standalone.css | 425 ++++++++++++++++++++---
src/styles/pages/ecommerce.css | 187 +++++++++-
src/styles/standalone/overrides.css | 54 +--
4 files changed, 617 insertions(+), 103 deletions(-)
diff --git a/src/features/ecommerce/EcommercePage.tsx b/src/features/ecommerce/EcommercePage.tsx
index 81d5cc7..e703ea0 100644
--- a/src/features/ecommerce/EcommercePage.tsx
+++ b/src/features/ecommerce/EcommercePage.tsx
@@ -1429,6 +1429,7 @@ const maxCloneProductImages = 20;
const maxCloneReferenceImages = 20;
const cloneVideoDurationMin = 5;
const cloneVideoDurationMax = 45;
+const composerDurationOptions = [5, 10, 15];
const defaultEcommercePlatform = "淘宝/天猫";
const defaultProductSetOutput: ProductSetOutputKey = "set";
const defaultCloneOutput: CloneOutputKey = "set";
@@ -2411,13 +2412,13 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
const cloneRatioOptions = baseCloneRatioOptions;
const composerRatioOptions = useMemo(
() => [
- "1000×1000px 1:1",
- "800×1200px 2:3",
- "1200×800px 3:2",
- "1200×900px 4:3",
- "900×1200px 3:4",
- "1080×1920px 9:16",
- "1920×1080px 16:9",
+ "1000×1000px\u00a0\u00a0\u00a01:1",
+ "800×1200px\u00a0\u00a0\u00a02:3",
+ "1200×800px\u00a0\u00a0\u00a03:2",
+ "1200×900px\u00a0\u00a0\u00a04:3",
+ "900×1200px\u00a0\u00a0\u00a03:4",
+ "1080×1920px\u00a0\u00a0\u00a09:16",
+ "1920×1080px\u00a0\u00a0\u00a016:9",
],
[],
);
@@ -5975,11 +5976,10 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
}
if (menuToRender === "platform") {
return (
-
{cloneOutput === "set" ? (
@@ -6599,14 +6610,18 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
) : null}
{shouldShowScenarioSettings ? (
-
-
+ {activeCommerceScenario !== "salesVideo" && activeCommerceScenario !== "poster" ? (
+
+ ) : null}
+ {activeCommerceScenario !== "salesVideo" ? (
+
+ ) : null}
diff --git a/src/styles/ecommerce-standalone.css b/src/styles/ecommerce-standalone.css
index ddb620b..46f6904 100644
--- a/src/styles/ecommerce-standalone.css
+++ b/src/styles/ecommerce-standalone.css
@@ -14328,9 +14328,8 @@ html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[d
row-gap: 10px !important;
}
- html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-option-row.ecom-command-option-row--settings button {
- flex: 1 1 calc(50% - 5px) !important;
- justify-content: flex-start !important;
+ html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-option-row.ecom-command-option-row--settings {
+ display: none !important;
}
html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-toolbar {
@@ -14339,40 +14338,6 @@ html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[d
}
@media (max-width: 420px) {
- html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-option-row.ecom-command-option-row--settings {
- display: flex !important;
- flex-wrap: nowrap !important;
- gap: 7px !important;
- justify-content: stretch !important;
- overflow: visible !important;
- }
-
- html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-option-row.ecom-command-option-row--settings button {
- display: inline-flex !important;
- flex: 1 1 0 !important;
- width: auto !important;
- min-width: 0 !important;
- max-width: none !important;
- height: 42px !important;
- min-height: 42px !important;
- padding: 0 !important;
- justify-content: center !important;
- font-size: 0 !important;
- }
-
- html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-option-row.ecom-command-option-row--settings button > span:not(.ecom-command-option-icon) {
- display: none !important;
- }
-
- html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-option-row.ecom-command-option-row--settings .ecom-command-option-icon {
- display: inline-grid !important;
- width: 22px !important;
- height: 22px !important;
- min-width: 22px !important;
- margin: 0 !important;
- font-size: 14px !important;
- }
-
html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-toolbar {
flex-direction: row !important;
align-items: center !important;
@@ -19482,9 +19447,16 @@ html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[d
border: 0 !important;
border-radius: 14px !important;
color: #ffffff !important;
- background: #181b1f !important;
- box-shadow: 0 12px 28px rgba(16, 32, 44, 0.14) !important;
+ background: linear-gradient(135deg, #1ebddb 0%, #0f829b 100%) !important;
+ box-shadow: 0 12px 28px rgba(15, 130, 155, 0.22) !important;
text-align: center !important;
+ transition: transform 160ms ease, box-shadow 160ms ease !important;
+}
+
+html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-ai-submit:hover {
+ background: linear-gradient(135deg, #21c8e3 0%, #1194ad 100%) !important;
+ box-shadow: 0 14px 32px rgba(15, 130, 155, 0.28) !important;
+ transform: translateY(-1px) !important;
}
@media (max-width: 640px) {
@@ -20125,3 +20097,378 @@ html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[d
color: #0f7895 !important;
font-weight: 600 !important;
}
+
+
+/* Platform picker: single-column scrollable list without logos, matching language/ratio style. */
+html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .clone-ai-input-wrapper.ecom-command-composer > .ecom-command-popover.ecom-command-popover--platforms.ecom-command-popover--platforms {
+ display: flex !important;
+ flex-direction: column !important;
+ flex-wrap: nowrap !important;
+ gap: 2px !important;
+ width: fit-content !important;
+ min-width: 0 !important;
+ max-width: calc(100vw - 48px) !important;
+ max-height: min(320px, calc(100dvh - 180px)) !important;
+ padding: 5px !important;
+ border: 1px solid rgba(16, 115, 204, 0.1) !important;
+ border-radius: 12px !important;
+ background: #ffffff !important;
+ box-shadow: 0 12px 32px rgba(16, 115, 204, 0.1) !important;
+ overflow-x: hidden !important;
+ overflow-y: auto !important;
+ scrollbar-width: thin !important;
+ scrollbar-color: rgba(16, 115, 204, 0.28) transparent !important;
+ animation: none !important;
+}
+
+html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-popover--platforms.ecom-command-popover--platforms button {
+ display: flex !important;
+ flex: 0 0 auto !important;
+ align-items: center !important;
+ justify-content: center !important;
+ width: 100% !important;
+ height: 36px !important;
+ min-height: 36px !important;
+ padding: 0 16px !important;
+ border: 0 !important;
+ border-radius: 8px !important;
+ color: rgba(16, 32, 44, 0.78) !important;
+ background: transparent !important;
+ font-size: 14px !important;
+ font-weight: 500 !important;
+ white-space: nowrap !important;
+ animation: none !important;
+ transition: background 120ms ease, color 120ms ease !important;
+}
+
+html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-popover--platforms.ecom-command-popover--platforms button:hover {
+ background: rgba(30, 189, 219, 0.08) !important;
+ color: #0f7895 !important;
+ transform: none !important;
+}
+
+html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-popover--platforms.ecom-command-popover--platforms button.is-active {
+ background: rgba(30, 189, 219, 0.12) !important;
+ color: #0f7895 !important;
+ font-weight: 600 !important;
+}
+
+html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .clone-ai-input-wrapper.ecom-command-composer > .ecom-command-popover.ecom-command-popover--platforms.ecom-command-popover--platforms::-webkit-scrollbar {
+ width: 5px !important;
+}
+
+html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .clone-ai-input-wrapper.ecom-command-composer > .ecom-command-popover.ecom-command-popover--platforms.ecom-command-popover--platforms::-webkit-scrollbar-thumb {
+ background: rgba(16, 115, 204, 0.28) !important;
+ border-radius: 999px !important;
+}
+
+
+/* Ratio & Language pickers: stronger active state so the selected option is clearly visible. */
+html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-popover--ratio-picker.ecom-command-popover--ratio-picker button.is-active,
+html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-popover--languages.ecom-command-popover--languages button.is-active {
+ background: rgba(30, 189, 219, 0.2) !important;
+ color: #0f7895 !important;
+ font-weight: 700 !important;
+}
+
+html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-popover--ratio-picker.ecom-command-popover--ratio-picker button.is-active::before,
+html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-popover--languages.ecom-command-popover--languages button.is-active::before {
+ position: absolute !important;
+ left: 8px !important;
+ top: 50% !important;
+ width: 5px !important;
+ height: 5px !important;
+ border-radius: 999px !important;
+ background: #1ebddb !important;
+ transform: translateY(-50%) scale(1) !important;
+ opacity: 1 !important;
+ content: "" !important;
+}
+
+html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-popover--ratio-picker.ecom-command-popover--ratio-picker button.is-active,
+html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-popover--languages.ecom-command-popover--languages button.is-active {
+ position: relative !important;
+ padding-left: 22px !important;
+}
+
+
+/* Platform picker: stronger active state with a visible dot indicator. */
+html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-popover--platforms.ecom-command-popover--platforms button.is-active {
+ position: relative !important;
+ padding-left: 22px !important;
+ background: rgba(30, 189, 219, 0.2) !important;
+ color: #0f7895 !important;
+ font-weight: 700 !important;
+}
+
+html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-popover--platforms.ecom-command-popover--platforms button.is-active::before {
+ position: absolute !important;
+ left: 8px !important;
+ top: 50% !important;
+ width: 5px !important;
+ height: 5px !important;
+ border-radius: 999px !important;
+ background: #1ebddb !important;
+ transform: translateY(-50%) scale(1) !important;
+ opacity: 1 !important;
+ content: "" !important;
+}
+
+
+/* Ratio/Language/Platform pickers: clean active state without dot indicator, keep color highlight only. */
+html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-popover--ratio-picker.ecom-command-popover--ratio-picker button.is-active,
+html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-popover--languages.ecom-command-popover--languages button.is-active,
+html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-popover--platforms.ecom-command-popover--platforms button.is-active {
+ position: static !important;
+ padding-left: 16px !important;
+ padding-right: 16px !important;
+ background: rgba(30, 189, 219, 0.2) !important;
+ color: #0f7895 !important;
+ font-weight: 700 !important;
+}
+
+html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-popover--ratio-picker.ecom-command-popover--ratio-picker button.is-active::before,
+html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-popover--languages.ecom-command-popover--languages button.is-active::before,
+html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-popover--platforms.ecom-command-popover--platforms button.is-active::before {
+ content: none !important;
+}
+
+
+/* Duration picker: single-column scrollable list for video duration, matching ratio/language style. */
+html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .clone-ai-input-wrapper.ecom-command-composer > .ecom-command-popover.ecom-command-popover--duration.ecom-command-popover--duration {
+ display: flex !important;
+ flex-direction: column !important;
+ flex-wrap: nowrap !important;
+ gap: 2px !important;
+ width: fit-content !important;
+ min-width: 0 !important;
+ max-width: calc(100vw - 48px) !important;
+ max-height: min(320px, calc(100dvh - 180px)) !important;
+ padding: 5px !important;
+ border: 1px solid rgba(16, 115, 204, 0.1) !important;
+ border-radius: 12px !important;
+ background: #ffffff !important;
+ box-shadow: 0 12px 32px rgba(16, 115, 204, 0.1) !important;
+ overflow-x: hidden !important;
+ overflow-y: auto !important;
+ scrollbar-width: thin !important;
+ scrollbar-color: rgba(16, 115, 204, 0.28) transparent !important;
+ animation: none !important;
+}
+
+html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-popover--duration.ecom-command-popover--duration button {
+ display: flex !important;
+ flex: 0 0 auto !important;
+ align-items: center !important;
+ justify-content: center !important;
+ width: 100% !important;
+ height: 36px !important;
+ min-height: 36px !important;
+ padding: 0 16px !important;
+ border: 0 !important;
+ border-radius: 8px !important;
+ color: rgba(16, 32, 44, 0.78) !important;
+ background: transparent !important;
+ font-size: 14px !important;
+ font-weight: 500 !important;
+ white-space: nowrap !important;
+ animation: none !important;
+ transition: background 120ms ease, color 120ms ease !important;
+}
+
+html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-popover--duration.ecom-command-popover--duration button:hover {
+ background: rgba(30, 189, 219, 0.08) !important;
+ color: #0f7895 !important;
+ transform: none !important;
+}
+
+html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-popover--duration.ecom-command-popover--duration button.is-active {
+ background: rgba(30, 189, 219, 0.2) !important;
+ color: #0f7895 !important;
+ font-weight: 700 !important;
+}
+
+html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .clone-ai-input-wrapper.ecom-command-composer > .ecom-command-popover.ecom-command-popover--duration.ecom-command-popover--duration::-webkit-scrollbar {
+ width: 5px !important;
+}
+
+html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .clone-ai-input-wrapper.ecom-command-composer > .ecom-command-popover.ecom-command-popover--duration.ecom-command-popover--duration::-webkit-scrollbar-thumb {
+ background: rgba(16, 115, 204, 0.28) !important;
+ border-radius: 999px !important;
+}
+
+/* Final composer rhythm: keep attachments compact and pin the toolbelt to the card bottom. */
+html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .clone-ai-input-wrapper.ecom-command-composer {
+ display: flex !important;
+ flex-direction: column !important;
+ justify-content: flex-start !important;
+ align-items: stretch !important;
+ gap: clamp(12px, 1.6vw, 18px) !important;
+ min-height: clamp(250px, 31vh, 316px) !important;
+ padding: clamp(18px, 2.05vw, 24px) clamp(18px, 2.3vw, 26px) clamp(16px, 1.9vw, 22px) !important;
+}
+
+html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .clone-ai-input-wrapper.ecom-command-composer:has(.ecom-command-asset-popover) {
+ min-height: clamp(286px, 35vh, 340px) !important;
+}
+
+html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .clone-ai-input-wrapper.ecom-command-composer > .ecom-command-asset-popover,
+html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-composer-wrap:not(.has-generated.is-compact) .clone-ai-input-wrapper.ecom-command-composer:has(.ecom-command-asset-popover) .ecom-command-asset-popover {
+ display: flex !important;
+ flex-wrap: nowrap !important;
+ align-items: center !important;
+ align-self: start !important;
+ gap: 12px !important;
+ width: 100% !important;
+ max-width: 100% !important;
+ min-height: 64px !important;
+ margin: 0 !important;
+ padding: 0 2px 2px !important;
+ border: 0 !important;
+ background: transparent !important;
+ box-shadow: none !important;
+ overflow-x: auto !important;
+ overflow-y: hidden !important;
+ scrollbar-width: none !important;
+}
+
+html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-asset-popover::-webkit-scrollbar {
+ display: none !important;
+}
+
+html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-asset-add,
+html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-composer-wrap:not(.has-generated.is-compact) .clone-ai-input-wrapper.ecom-command-composer:has(.ecom-command-asset-popover) .ecom-command-asset-add {
+ flex: 0 0 64px !important;
+ width: 64px !important;
+ height: 64px !important;
+ min-height: 64px !important;
+ padding: 0 !important;
+ border: 0 !important;
+ border-radius: 15px !important;
+ background: rgba(30, 189, 219, 0.1) !important;
+ color: #0b8fb2 !important;
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.78) !important;
+}
+
+html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-asset-add span {
+ font-size: 24px !important;
+ line-height: 1 !important;
+}
+
+html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-asset-add small {
+ margin-top: 4px !important;
+ color: #0f7f9e !important;
+ font-size: 14px !important;
+ font-weight: 600 !important;
+}
+
+html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-asset-thumb,
+html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-composer-wrap:not(.has-generated.is-compact) .clone-ai-input-wrapper.ecom-command-composer:has(.ecom-command-asset-popover) .ecom-command-asset-thumb {
+ flex: 0 0 64px !important;
+ width: 64px !important;
+ height: 64px !important;
+ min-height: 64px !important;
+ border-radius: 15px !important;
+ box-shadow: 0 12px 28px rgba(16, 115, 204, 0.12) !important;
+}
+
+html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .clone-ai-input-wrapper.ecom-command-composer > .ecom-command-option-row--settings {
+ align-self: start !important;
+ margin: 0 !important;
+}
+
+html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .clone-ai-input-wrapper.ecom-command-composer > textarea {
+ flex: 1 1 auto !important;
+ align-self: stretch !important;
+ width: 100% !important;
+ min-height: 86px !important;
+ height: auto !important;
+ margin: 0 !important;
+ padding: 0 !important;
+ line-height: 1.58 !important;
+}
+
+html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .clone-ai-input-wrapper.ecom-command-composer:has(.ecom-command-asset-popover) > textarea {
+ min-height: 78px !important;
+}
+
+html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-toolbar {
+ flex: 0 0 auto !important;
+ align-self: end !important;
+ width: 100% !important;
+ margin: auto 0 0 !important;
+ padding-top: clamp(12px, 1.45vw, 16px) !important;
+ border-top: 1px solid rgba(30, 189, 219, 0.12) !important;
+}
+
+html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-composer-actions {
+ min-width: 0 !important;
+}
+
+@media (max-width: 640px) {
+ html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .clone-ai-input-wrapper.ecom-command-composer {
+ gap: 12px !important;
+ min-height: 318px !important;
+ padding: 18px 16px 16px !important;
+ }
+
+ html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .clone-ai-input-wrapper.ecom-command-composer:has(.ecom-command-asset-popover) {
+ min-height: 336px !important;
+ }
+
+ html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .clone-ai-input-wrapper.ecom-command-composer > .ecom-command-asset-popover,
+ html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-composer-wrap:not(.has-generated.is-compact) .clone-ai-input-wrapper.ecom-command-composer:has(.ecom-command-asset-popover) .ecom-command-asset-popover {
+ gap: 10px !important;
+ min-height: 58px !important;
+ }
+
+ html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-asset-add,
+ html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-asset-thumb,
+ html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-composer-wrap:not(.has-generated.is-compact) .clone-ai-input-wrapper.ecom-command-composer:has(.ecom-command-asset-popover) .ecom-command-asset-add,
+ html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-composer-wrap:not(.has-generated.is-compact) .clone-ai-input-wrapper.ecom-command-composer:has(.ecom-command-asset-popover) .ecom-command-asset-thumb {
+ flex-basis: 58px !important;
+ width: 58px !important;
+ height: 58px !important;
+ min-height: 58px !important;
+ border-radius: 14px !important;
+ }
+
+ html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-asset-add span {
+ font-size: 22px !important;
+ }
+
+ html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-asset-add small {
+ font-size: 13px !important;
+ }
+
+ html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .clone-ai-input-wrapper.ecom-command-composer > textarea,
+ html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .clone-ai-input-wrapper.ecom-command-composer:has(.ecom-command-asset-popover) > textarea {
+ min-height: 96px !important;
+ }
+
+ html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-toolbar {
+ min-height: 58px !important;
+ padding-top: 12px !important;
+ }
+}
+
+@media (max-width: 390px) {
+ html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .clone-ai-input-wrapper.ecom-command-composer {
+ min-height: 306px !important;
+ padding-inline: 14px !important;
+ }
+
+ html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .clone-ai-input-wrapper.ecom-command-composer:has(.ecom-command-asset-popover) {
+ min-height: 326px !important;
+ }
+
+ html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-asset-add,
+ html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-asset-thumb,
+ html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-composer-wrap:not(.has-generated.is-compact) .clone-ai-input-wrapper.ecom-command-composer:has(.ecom-command-asset-popover) .ecom-command-asset-add,
+ html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-composer-wrap:not(.has-generated.is-compact) .clone-ai-input-wrapper.ecom-command-composer:has(.ecom-command-asset-popover) .ecom-command-asset-thumb {
+ flex-basis: 54px !important;
+ width: 54px !important;
+ height: 54px !important;
+ min-height: 54px !important;
+ }
+}
diff --git a/src/styles/pages/ecommerce.css b/src/styles/pages/ecommerce.css
index 08875be..2302139 100644
--- a/src/styles/pages/ecommerce.css
+++ b/src/styles/pages/ecommerce.css
@@ -12522,9 +12522,16 @@ html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[d
border: 0 !important;
border-radius: 14px !important;
color: #ffffff !important;
- background: #181b1f !important;
- box-shadow: 0 12px 28px rgba(16, 32, 44, 0.14) !important;
+ background: linear-gradient(135deg, #1ebddb 0%, #0f829b 100%) !important;
+ box-shadow: 0 12px 28px rgba(15, 130, 155, 0.22) !important;
text-align: center !important;
+ transition: transform 160ms ease, box-shadow 160ms ease !important;
+}
+
+html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-ai-submit:hover {
+ background: linear-gradient(135deg, #21c8e3 0%, #1194ad 100%) !important;
+ box-shadow: 0 14px 32px rgba(15, 130, 155, 0.28) !important;
+ transform: translateY(-1px) !important;
}
@media (max-width: 640px) {
@@ -12639,3 +12646,179 @@ html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[d
overflow-y: auto !important;
}
}
+
+/* Final composer rhythm: keep attachments compact and pin the toolbelt to the card bottom. */
+html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .clone-ai-input-wrapper.ecom-command-composer {
+ display: flex !important;
+ flex-direction: column !important;
+ justify-content: flex-start !important;
+ align-items: stretch !important;
+ gap: clamp(12px, 1.6vw, 18px) !important;
+ min-height: clamp(250px, 31vh, 316px) !important;
+ padding: clamp(18px, 2.05vw, 24px) clamp(18px, 2.3vw, 26px) clamp(16px, 1.9vw, 22px) !important;
+}
+
+html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .clone-ai-input-wrapper.ecom-command-composer:has(.ecom-command-asset-popover) {
+ min-height: clamp(286px, 35vh, 340px) !important;
+}
+
+html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .clone-ai-input-wrapper.ecom-command-composer > .ecom-command-asset-popover,
+html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-composer-wrap:not(.has-generated.is-compact) .clone-ai-input-wrapper.ecom-command-composer:has(.ecom-command-asset-popover) .ecom-command-asset-popover {
+ display: flex !important;
+ flex-wrap: nowrap !important;
+ align-items: center !important;
+ align-self: start !important;
+ gap: 12px !important;
+ width: 100% !important;
+ max-width: 100% !important;
+ min-height: 64px !important;
+ margin: 0 !important;
+ padding: 0 2px 2px !important;
+ border: 0 !important;
+ background: transparent !important;
+ box-shadow: none !important;
+ overflow-x: auto !important;
+ overflow-y: hidden !important;
+ scrollbar-width: none !important;
+}
+
+html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-asset-popover::-webkit-scrollbar {
+ display: none !important;
+}
+
+html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-asset-add,
+html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-composer-wrap:not(.has-generated.is-compact) .clone-ai-input-wrapper.ecom-command-composer:has(.ecom-command-asset-popover) .ecom-command-asset-add {
+ flex: 0 0 64px !important;
+ width: 64px !important;
+ height: 64px !important;
+ min-height: 64px !important;
+ padding: 0 !important;
+ border: 0 !important;
+ border-radius: 15px !important;
+ background: rgba(30, 189, 219, 0.1) !important;
+ color: #0b8fb2 !important;
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.78) !important;
+}
+
+html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-asset-add span {
+ font-size: 24px !important;
+ line-height: 1 !important;
+}
+
+html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-asset-add small {
+ margin-top: 4px !important;
+ color: #0f7f9e !important;
+ font-size: 14px !important;
+ font-weight: 600 !important;
+}
+
+html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-asset-thumb,
+html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-composer-wrap:not(.has-generated.is-compact) .clone-ai-input-wrapper.ecom-command-composer:has(.ecom-command-asset-popover) .ecom-command-asset-thumb {
+ flex: 0 0 64px !important;
+ width: 64px !important;
+ height: 64px !important;
+ min-height: 64px !important;
+ border-radius: 15px !important;
+ box-shadow: 0 12px 28px rgba(16, 115, 204, 0.12) !important;
+}
+
+html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .clone-ai-input-wrapper.ecom-command-composer > .ecom-command-option-row--settings {
+ align-self: start !important;
+ margin: 0 !important;
+}
+
+html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .clone-ai-input-wrapper.ecom-command-composer > textarea {
+ flex: 1 1 auto !important;
+ align-self: stretch !important;
+ width: 100% !important;
+ min-height: 86px !important;
+ height: auto !important;
+ margin: 0 !important;
+ padding: 0 !important;
+ line-height: 1.58 !important;
+}
+
+html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .clone-ai-input-wrapper.ecom-command-composer:has(.ecom-command-asset-popover) > textarea {
+ min-height: 78px !important;
+}
+
+html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-toolbar {
+ flex: 0 0 auto !important;
+ align-self: end !important;
+ width: 100% !important;
+ margin: auto 0 0 !important;
+ padding-top: clamp(12px, 1.45vw, 16px) !important;
+ border-top: 1px solid rgba(30, 189, 219, 0.12) !important;
+}
+
+html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-composer-actions {
+ min-width: 0 !important;
+}
+
+@media (max-width: 640px) {
+ html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .clone-ai-input-wrapper.ecom-command-composer {
+ gap: 12px !important;
+ min-height: 318px !important;
+ padding: 18px 16px 16px !important;
+ }
+
+ html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .clone-ai-input-wrapper.ecom-command-composer:has(.ecom-command-asset-popover) {
+ min-height: 336px !important;
+ }
+
+ html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .clone-ai-input-wrapper.ecom-command-composer > .ecom-command-asset-popover,
+ html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-composer-wrap:not(.has-generated.is-compact) .clone-ai-input-wrapper.ecom-command-composer:has(.ecom-command-asset-popover) .ecom-command-asset-popover {
+ gap: 10px !important;
+ min-height: 58px !important;
+ }
+
+ html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-asset-add,
+ html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-asset-thumb,
+ html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-composer-wrap:not(.has-generated.is-compact) .clone-ai-input-wrapper.ecom-command-composer:has(.ecom-command-asset-popover) .ecom-command-asset-add,
+ html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-composer-wrap:not(.has-generated.is-compact) .clone-ai-input-wrapper.ecom-command-composer:has(.ecom-command-asset-popover) .ecom-command-asset-thumb {
+ flex-basis: 58px !important;
+ width: 58px !important;
+ height: 58px !important;
+ min-height: 58px !important;
+ border-radius: 14px !important;
+ }
+
+ html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-asset-add span {
+ font-size: 22px !important;
+ }
+
+ html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-asset-add small {
+ font-size: 13px !important;
+ }
+
+ html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .clone-ai-input-wrapper.ecom-command-composer > textarea,
+ html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .clone-ai-input-wrapper.ecom-command-composer:has(.ecom-command-asset-popover) > textarea {
+ min-height: 96px !important;
+ }
+
+ html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-toolbar {
+ min-height: 58px !important;
+ padding-top: 12px !important;
+ }
+}
+
+@media (max-width: 390px) {
+ html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .clone-ai-input-wrapper.ecom-command-composer {
+ min-height: 306px !important;
+ padding-inline: 14px !important;
+ }
+
+ html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .clone-ai-input-wrapper.ecom-command-composer:has(.ecom-command-asset-popover) {
+ min-height: 326px !important;
+ }
+
+ html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-asset-add,
+ html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-asset-thumb,
+ html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-composer-wrap:not(.has-generated.is-compact) .clone-ai-input-wrapper.ecom-command-composer:has(.ecom-command-asset-popover) .ecom-command-asset-add,
+ html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-composer-wrap:not(.has-generated.is-compact) .clone-ai-input-wrapper.ecom-command-composer:has(.ecom-command-asset-popover) .ecom-command-asset-thumb {
+ flex-basis: 54px !important;
+ width: 54px !important;
+ height: 54px !important;
+ min-height: 54px !important;
+ }
+}
diff --git a/src/styles/standalone/overrides.css b/src/styles/standalone/overrides.css
index 272f22b..d4817c3 100644
--- a/src/styles/standalone/overrides.css
+++ b/src/styles/standalone/overrides.css
@@ -3461,9 +3461,8 @@ html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[d
row-gap: 10px !important;
}
- html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-option-row.ecom-command-option-row--settings button {
- flex: 1 1 calc(50% - 5px) !important;
- justify-content: flex-start !important;
+ html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-option-row.ecom-command-option-row--settings {
+ display: none !important;
}
html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-toolbar {
@@ -3472,40 +3471,6 @@ html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[d
}
@media (max-width: 420px) {
- html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-option-row.ecom-command-option-row--settings {
- display: flex !important;
- flex-wrap: nowrap !important;
- gap: 7px !important;
- justify-content: stretch !important;
- overflow: visible !important;
- }
-
- html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-option-row.ecom-command-option-row--settings button {
- display: inline-flex !important;
- flex: 1 1 0 !important;
- width: auto !important;
- min-width: 0 !important;
- max-width: none !important;
- height: 42px !important;
- min-height: 42px !important;
- padding: 0 !important;
- justify-content: center !important;
- font-size: 0 !important;
- }
-
- html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-option-row.ecom-command-option-row--settings button > span:not(.ecom-command-option-icon) {
- display: none !important;
- }
-
- html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-option-row.ecom-command-option-row--settings .ecom-command-option-icon {
- display: inline-grid !important;
- width: 22px !important;
- height: 22px !important;
- min-width: 22px !important;
- margin: 0 !important;
- font-size: 14px !important;
- }
-
html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .ecom-command-toolbar {
flex-direction: row !important;
align-items: center !important;
@@ -3560,15 +3525,18 @@ html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[d
z-index: 160 !important;
}
-html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .clone-ai-input-wrapper.ecom-command-composer > .ecom-command-popover.ecom-command-popover--platform {
- width: min(360px, calc(100% - var(--composer-popover-left, 0px))) !important;
- max-width: min(360px, calc(100% - var(--composer-popover-left, 0px))) !important;
+html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .clone-ai-input-wrapper.ecom-command-composer > .ecom-command-popover.ecom-command-popover--platforms {
+ width: fit-content !important;
+ min-width: 0 !important;
+ max-width: min(320px, calc(100% - var(--composer-popover-left, 0px))) !important;
}
html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .clone-ai-input-wrapper.ecom-command-composer > .ecom-command-popover.ecom-command-popover--languages,
-html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .clone-ai-input-wrapper.ecom-command-composer > .ecom-command-popover.ecom-command-popover--ratio-picker {
- width: min(420px, calc(100% - var(--composer-popover-left, 0px))) !important;
- max-width: min(420px, calc(100% - var(--composer-popover-left, 0px))) !important;
+html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .clone-ai-input-wrapper.ecom-command-composer > .ecom-command-popover.ecom-command-popover--ratio-picker,
+html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .clone-ai-input-wrapper.ecom-command-composer > .ecom-command-popover.ecom-command-popover--duration {
+ width: fit-content !important;
+ min-width: 0 !important;
+ max-width: min(320px, calc(100% - var(--composer-popover-left, 0px))) !important;
}
html body #root .ecommerce-standalone.ecommerce-standalone .product-clone-page[data-tool="clone"][data-tool="clone"] .clone-ai-input-wrapper.ecom-command-composer > .ecom-command-popover.ecom-command-popover--settings {
From 3d72e166edf0f045635ea305e8c9c2ff77630a4e Mon Sep 17 00:00:00 2001
From: ludan <251918489@qq.com>
Date: Wed, 17 Jun 2026 18:47:10 +0800
Subject: [PATCH 2/2] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E7=94=B5?=
=?UTF-8?q?=E5=95=86=E5=85=A8=E5=9C=BA=E6=99=AF=E7=B4=A0=E6=9D=90=E4=B8=8A?=
=?UTF-8?q?=E4=BC=A0=E4=BD=93=E9=AA=8C=EF=BC=8C=E5=85=88=E6=9C=AC=E5=9C=B0?=
=?UTF-8?q?=E9=A2=84=E8=A7=88=E5=86=8D=E5=90=8E=E5=8F=B0=E4=B8=8A=E4=BC=A0?=
=?UTF-8?q?=20OSS?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 新增 createLocalImageItems 同步创建本地 blob 预览项
- 新增 uploadImageItem 后台异步上传 OSS 并读取图片尺寸
- 改造商品主图、套图、参考图、服饰图、详情图 5 个上传入口
- 选择文件后立即渲染缩略图,OSS 上传在后台并行进行
- 上传完成后按 id 替换为 OSS URL,释放本地 blob URL
---
src/features/ecommerce/EcommercePage.tsx | 209 ++++++++++++++++-------
1 file changed, 150 insertions(+), 59 deletions(-)
diff --git a/src/features/ecommerce/EcommercePage.tsx b/src/features/ecommerce/EcommercePage.tsx
index e703ea0..e7dafd2 100644
--- a/src/features/ecommerce/EcommercePage.tsx
+++ b/src/features/ecommerce/EcommercePage.tsx
@@ -1559,6 +1559,42 @@ const blobToDataUrl = (blob: Blob): Promise
=>
reader.readAsDataURL(blob);
});
+function createLocalImageItems(files: File[], limit: number, prefix: string): CloneImageItem[] {
+ const selectedFiles = Array.from(files).slice(0, limit);
+ const stamp = Date.now();
+ return selectedFiles.map((file, index) => {
+ const localPreviewUrl = URL.createObjectURL(file);
+ const mimeType = normalizeEcommerceImageMime(file.type);
+ return {
+ id: `${prefix}-${stamp}-${index}`,
+ src: localPreviewUrl,
+ name: file.name,
+ file,
+ format: getImageFileFormat(file),
+ mimeType,
+ };
+ });
+}
+
+async function uploadImageItem(item: CloneImageItem): Promise<{ src?: string; ossKey?: string; width?: number; height?: number }> {
+ if (!item.file) return {};
+ const mimeType = normalizeEcommerceImageMime(item.file.type);
+ try {
+ const uploadBlob = item.file.type === mimeType ? item.file : new Blob([item.file], { type: mimeType });
+ const [uploaded, dimensions] = await Promise.all([
+ aiGenerationClient.uploadAssetBinary(uploadBlob, {
+ name: item.file.name,
+ mimeType,
+ scope: ecommerceOssScopes.productSource,
+ }),
+ readImageDimensions(item.src).catch(() => ({})),
+ ]);
+ return { src: uploaded.url, ossKey: uploaded.ossKey, ...dimensions };
+ } catch {
+ return {};
+ }
+}
+
async function createUploadedImageItems(files: File[], limit: number, prefix: string): Promise {
const selectedFiles = Array.from(files).slice(0, limit);
const stamp = Date.now();
@@ -2553,20 +2589,30 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
});
};
- const addSetImages = async (files: File[]) => {
+ const addSetImages = (files: File[]) => {
if (setImages.length >= 3) return;
const imageFiles = notifyRejectedImages(files);
if (!imageFiles.length) return;
- try {
- const nextImages = await createUploadedImageItems(imageFiles, 3 - setImages.length, "set");
- setSetImages((current) => {
- if (current.length >= 3) return current;
- return nextImages.length ? [...current, ...nextImages].slice(0, 3) : current;
- });
- setProductSetStatus("ready");
- } catch (err) {
- toast.error(err instanceof Error ? err.message : "商品图上传失败");
- }
+ const remainingSlots = 3 - setImages.length;
+ if (remainingSlots <= 0) return;
+
+ const localItems = createLocalImageItems(imageFiles, remainingSlots, "set");
+ setSetImages((current) => [...current, ...localItems].slice(0, 3));
+ setProductSetStatus("ready");
+
+ Promise.all(localItems.map(async (item) => {
+ const uploaded = await uploadImageItem(item);
+ if (uploaded.src) URL.revokeObjectURL(item.src);
+ return { id: item.id, uploaded };
+ })).then((results) => {
+ const updateMap = new Map(results.map((result) => [result.id, result.uploaded]));
+ setSetImages((current) => current.map((item) => {
+ const update = updateMap.get(item.id);
+ return update ? { ...item, ...update } : item;
+ }));
+ }).catch(() => {
+ toast.error("套图后台上传失败,请检查网络后重试");
+ });
};
const handleSetUpload = (event: ChangeEvent) => {
@@ -3651,20 +3697,33 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
});
};
- const addProductImages = async (files: File[]) => {
+ const addProductImages = (files: File[]) => {
const imageFiles = notifyRejectedImages(files);
if (!imageFiles.length) return;
- try {
- const nextImages = await createUploadedImageItems(imageFiles, maxCloneProductImages - productImages.length, "product");
- setProductImages((current) => {
- if (current.length >= maxCloneProductImages) return current;
- return nextImages.length ? [...current, ...nextImages].slice(0, maxCloneProductImages) : current;
- });
- setStatus("ready");
- setResults([]);
- } catch (err) {
- toast.error(err instanceof Error ? err.message : "商品图上传失败");
- }
+ const remainingSlots = maxCloneProductImages - productImages.length;
+ if (remainingSlots <= 0) return;
+
+ const localItems = createLocalImageItems(imageFiles, remainingSlots, "product");
+ setProductImages((current) => [...current, ...localItems].slice(0, maxCloneProductImages));
+ setStatus("ready");
+ setResults([]);
+
+ Promise.all(localItems.map(async (item) => {
+ const uploaded = await uploadImageItem(item);
+ if (uploaded.src) {
+ URL.revokeObjectURL(item.src);
+ }
+ return { id: item.id, uploaded };
+ })).then((results) => {
+ const updateMap = new Map(results.map((result) => [result.id, result.uploaded]));
+ setProductImages((current) => current.map((item) => {
+ const update = updateMap.get(item.id);
+ if (!update) return item;
+ return { ...item, ...update };
+ }));
+ }).catch(() => {
+ toast.error("商品图后台上传失败,请检查网络后重试");
+ });
};
const handleProductUpload = (event: ChangeEvent) => {
@@ -3718,22 +3777,29 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
});
};
- const addCloneReferenceImages = async (files: File[]) => {
+ const addCloneReferenceImages = (files: File[]) => {
const imageFiles = notifyRejectedImages(files);
if (!imageFiles.length) return;
const remainingSlots = maxCloneReferenceImages - cloneReferenceImages.length;
if (remainingSlots <= 0) return;
- try {
- const nextImages = await createUploadedImageItems(imageFiles, remainingSlots, "reference");
- if (!nextImages.length) return;
- setCloneReferenceImages((current) => {
- if (current.length >= maxCloneReferenceImages) return current;
- return nextImages.length ? [...current, ...nextImages].slice(0, maxCloneReferenceImages) : current;
- });
- hydrateCloneReferenceImageMeta(nextImages);
- } catch (err) {
- toast.error(err instanceof Error ? err.message : "参考图上传失败");
- }
+
+ const localItems = createLocalImageItems(imageFiles, remainingSlots, "reference");
+ setCloneReferenceImages((current) => [...current, ...localItems].slice(0, maxCloneReferenceImages));
+ hydrateCloneReferenceImageMeta(localItems);
+
+ Promise.all(localItems.map(async (item) => {
+ const uploaded = await uploadImageItem(item);
+ if (uploaded.src) URL.revokeObjectURL(item.src);
+ return { id: item.id, uploaded };
+ })).then((results) => {
+ const updateMap = new Map(results.map((result) => [result.id, result.uploaded]));
+ setCloneReferenceImages((current) => current.map((item) => {
+ const update = updateMap.get(item.id);
+ return update ? { ...item, ...update } : item;
+ }));
+ }).catch(() => {
+ toast.error("参考图后台上传失败,请检查网络后重试");
+ });
};
const removeCloneReferenceImage = (imageId: string) => {
@@ -4189,23 +4255,38 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
};
}, [openCloneModelSelect]);
+ const addGarmentImages = (files: File[]) => {
+ const uploadedFiles = notifyRejectedImages(files);
+ if (!uploadedFiles.length) return;
+ const remainingSlots = 5 - garmentImages.length;
+ if (remainingSlots <= 0) return;
+
+ const localItems = createLocalImageItems(uploadedFiles, remainingSlots, "garment");
+ setGarmentImages((current) => [...current, ...localItems].slice(0, 5));
+ setTryOnStatus("ready");
+
+ Promise.all(localItems.map(async (item) => {
+ const uploaded = await uploadImageItem(item);
+ if (uploaded.src) URL.revokeObjectURL(item.src);
+ return { id: item.id, uploaded };
+ })).then((results) => {
+ const updateMap = new Map(results.map((result) => [result.id, result.uploaded]));
+ setGarmentImages((current) => current.map((item) => {
+ const update = updateMap.get(item.id);
+ return update ? { ...item, ...update } : item;
+ }));
+ }).catch(() => {
+ toast.error("服饰图后台上传失败,请检查网络后重试");
+ });
+ };
+
const handleGarmentUpload = (event: ChangeEvent) => {
const files = event.target.files;
- if (!files?.length) return;
- const uploadedFiles = notifyRejectedImages(Array.from(files));
- if (!uploadedFiles.length) {
+ if (!files?.length) {
event.target.value = "";
return;
}
- void (async () => {
- try {
- const nextImages = await createUploadedImageItems(uploadedFiles, 5 - garmentImages.length, "garment");
- setGarmentImages((current) => [...current, ...nextImages].slice(0, 5));
- setTryOnStatus("ready");
- } catch (err) {
- toast.error(err instanceof Error ? err.message : "服饰图上传失败");
- }
- })();
+ addGarmentImages(Array.from(files));
event.target.value = "";
};
@@ -4241,20 +4322,30 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
reader.readAsDataURL(blob);
});
- const addDetailImages = async (files: File[]) => {
+ const addDetailImages = (files: File[]) => {
const uploadedFiles = notifyRejectedImages(files);
if (!uploadedFiles.length) return;
- try {
- const nextImages = await createUploadedImageItems(uploadedFiles, 3 - detailProductImages.length, "detail");
- setDetailProductImages((current) => {
- if (current.length >= 3) return current;
- return nextImages.length ? [...current, ...nextImages].slice(0, 3) : current;
- });
- setDetailStatus("ready");
- setDetailResultUrl(null);
- } catch (err) {
- toast.error(err instanceof Error ? err.message : "详情图上传失败");
- }
+ const remainingSlots = 3 - detailProductImages.length;
+ if (remainingSlots <= 0) return;
+
+ const localItems = createLocalImageItems(uploadedFiles, remainingSlots, "detail");
+ setDetailProductImages((current) => [...current, ...localItems].slice(0, 3));
+ setDetailStatus("ready");
+ setDetailResultUrl(null);
+
+ Promise.all(localItems.map(async (item) => {
+ const uploaded = await uploadImageItem(item);
+ if (uploaded.src) URL.revokeObjectURL(item.src);
+ return { id: item.id, uploaded };
+ })).then((results) => {
+ const updateMap = new Map(results.map((result) => [result.id, result.uploaded]));
+ setDetailProductImages((current) => current.map((item) => {
+ const update = updateMap.get(item.id);
+ return update ? { ...item, ...update } : item;
+ }));
+ }).catch(() => {
+ toast.error("详情图后台上传失败,请检查网络后重试");
+ });
};
const uploadCloneImages = async (images: CloneImageItem[]): Promise => {