diff --git a/apps/web/src/layouts/MainLayout.css b/apps/web/src/layouts/MainLayout.css index 42efc44..d6e2f17 100644 --- a/apps/web/src/layouts/MainLayout.css +++ b/apps/web/src/layouts/MainLayout.css @@ -2,6 +2,11 @@ min-height: 100vh; } +/* 除左侧菜单外的完整内容区域,供页面按实际可用宽度响应。 */ +.main-content-layout { + container-type: inline-size; +} + .main-sider { background: var(--sider-bg) !important; display: flex; diff --git a/apps/web/src/pages/products/ProductEditPage.css b/apps/web/src/pages/products/ProductEditPage.css index 3ef0fa5..bf96d20 100644 --- a/apps/web/src/pages/products/ProductEditPage.css +++ b/apps/web/src/pages/products/ProductEditPage.css @@ -55,6 +55,16 @@ gap: 16px; } +/* + * 主内容区不足 1360px 时,采集面板移至编辑卡片下方;大于等于该宽度时 + * 保持两列。断点依据除菜单栏外的实际内容宽度,不依赖浏览器窗口宽度。 + */ +@container (max-width: 1199px) { + .editor-workspace { + grid-template-columns: 1fr; + } +} + /* 区块卡片公共外框 */ .editor-section.ant-card { border: 1px solid #e9e7ef; @@ -69,6 +79,52 @@ font-weight: 600; } +/* + * 01 / 02 / 04 共用的横向表单:Label 与控件列作为最大 780px 的整体居中。 + * 宽度充足时控件不超过 680px;卡片变窄时先吃掉两侧留白,再收缩控件列。 + * 容器查询以卡片实际宽度为准,不受左侧菜单或采集面板布局的间接影响。 + */ +.editor-horizontal-section.ant-card { + container-type: inline-size; +} +.editor-horizontal-section .ant-form-item-row { + justify-content: center; + min-width: 0; +} +.editor-horizontal-section .ant-form-item-label { + flex: 0 0 100px !important; + max-width: 100px !important; +} +.editor-horizontal-section .ant-form-item-control { + flex: 0 1 min(680px, calc(100% - 100px)) !important; + width: auto; + max-width: min(680px, calc(100% - 100px)) !important; + min-width: 0; +} + +/* + * 100px 标签列与包装尺寸输入组在 480px 以下已没有足够可读空间;此时才 + * 切换为纵向表单。该断点读取卡片宽度,非浏览器窗口宽度。 + */ +@container (max-width: 479px) { + .editor-horizontal-section .ant-form-item-row { + flex-direction: column; + row-gap: 4px; + } + .editor-horizontal-section .ant-form-item-row > .ant-form-item-label { + flex: 0 0 auto !important; + max-width: 100% !important; + padding: 0; + text-align: left; + } + .editor-horizontal-section .ant-form-item-row > .ant-form-item-control { + flex: 1 1 auto !important; + width: 100%; + max-width: 100% !important; + min-width: 0; + } +} + /* 表单栅格(主要信息与其它区块使用) */ .editor-form-grid { display: grid; @@ -123,12 +179,6 @@ display: flex; } -@media (max-width: 1180px) { - /* 窄屏:采集面板移到主编辑列下方 */ - .editor-workspace { - grid-template-columns: 1fr; - } -} /* * ≤700px:整张表单切换为纵向布局(标签在上、控件在下)。 * 更宽时保持"标签 | 控件"同行,随宽度缩小优先压缩控件长度 @@ -136,17 +186,23 @@ * labelCol/wrapperCol 以内联样式注入 flex,故此处需要 !important 覆盖。 */ @media (max-width: 700px) { - .product-editor .ant-form-item-row { + .product-editor .editor-section:not(.editor-horizontal-section) .ant-form-item-row { flex-direction: column; row-gap: 4px; } - .product-editor .ant-form-item-row > .ant-form-item-label { + .product-editor + .editor-section:not(.editor-horizontal-section) + .ant-form-item-row + > .ant-form-item-label { flex: 0 0 auto !important; max-width: 100% !important; padding: 0; text-align: left; } - .product-editor .ant-form-item-row > .ant-form-item-control { + .product-editor + .editor-section:not(.editor-horizontal-section) + .ant-form-item-row + > .ant-form-item-control { flex: 1 1 auto !important; width: 100%; max-width: 100% !important; diff --git a/apps/web/src/pages/products/ProductEditPage.tsx b/apps/web/src/pages/products/ProductEditPage.tsx index 7ba8444..f36492b 100644 --- a/apps/web/src/pages/products/ProductEditPage.tsx +++ b/apps/web/src/pages/products/ProductEditPage.tsx @@ -889,7 +889,7 @@ const ProductEditPage = () => { form={form} layout="horizontal" labelAlign="right" - labelCol={{ flex: '190px' }} + labelCol={{ flex: '0 0 100px' }} wrapperCol={{ flex: '0 1 680px' }} onFinish={save} requiredMark diff --git a/apps/web/src/pages/products/components/CollectedProductInfoPanel.css b/apps/web/src/pages/products/components/CollectedProductInfoPanel.css index b310457..1ef837e 100644 --- a/apps/web/src/pages/products/components/CollectedProductInfoPanel.css +++ b/apps/web/src/pages/products/components/CollectedProductInfoPanel.css @@ -171,8 +171,8 @@ aspect-ratio: 3 / 4; object-fit: cover; } -@media (max-width: 1180px) { - /* 窄屏下面板退化为工作区下方整行,不再固定高度 */ +@container (max-width: 1199px) { + /* 主内容区不足 1360px 时,面板退化为工作区下方整行,不再固定高度。 */ .editor-aside { position: static; } diff --git a/apps/web/src/pages/products/components/ProductAttributeSection.tsx b/apps/web/src/pages/products/components/ProductAttributeSection.tsx index 830c144..2bbcf55 100644 --- a/apps/web/src/pages/products/components/ProductAttributeSection.tsx +++ b/apps/web/src/pages/products/components/ProductAttributeSection.tsx @@ -69,7 +69,7 @@ export function ProductAttributeSection({ setDictionarySearches({}); }, [selectedCategoryId]); return ( - + + +
diff --git a/apps/web/src/pages/products/components/ProductVariantSection.css b/apps/web/src/pages/products/components/ProductVariantSection.css index ba56e2b..163308b 100644 --- a/apps/web/src/pages/products/components/ProductVariantSection.css +++ b/apps/web/src/pages/products/components/ProductVariantSection.css @@ -98,10 +98,12 @@ font-weight: 500; } .sku-card-field { - flex: 1 1 120px; + /* 三个可编辑字段在同一行时,输入框允许收缩至 100px 后才换行。 */ + flex: 1 1 100px; + min-width: 100px; } .sku-price-field { - flex: 1 1 130px; + flex: 1 1 100px; } .sku-card-field > span, .sku-card-value > span { @@ -157,34 +159,59 @@ margin-left: auto; } -/* 展开区:左侧采集图片、右侧规格面板 */ +/* 展开区:图片与规格使用同层级面板,宽度不足时再改为上下排列。 */ .sku-card-expanded { display: grid; - grid-template-columns: minmax(0, 1.08fr) minmax(390px, 0.92fr); - gap: 32px; + grid-template-columns: minmax(0, 1fr) minmax(360px, 1fr); + gap: 20px; margin-top: 16px; padding-top: 16px; border-top: 1px solid #f0edf3; } +.sku-media-panel, +.sku-spec-panel { + padding: 18px; + border: 1px solid #eeeaf3; + border-radius: 10px; + background: #fcfbfd; +} .sku-media-panel h5.ant-typography, .sku-spec-panel h5.ant-typography { margin: 0 0 12px; } .sku-media-grid { display: grid; - grid-template-columns: repeat(2, minmax(0, 1fr)); + grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 10px; align-items: start; } .sku-media-item { position: relative; min-width: 0; + /* 每张图片框固定为 3:4;实际图片使用 contain,完整居中展示。 */ aspect-ratio: 3 / 4; + align-self: start; overflow: hidden; border: 1px solid #ece8f0; border-radius: 8px; background: #f5f3f7; } +.sku-media-item--main { + grid-column: span 2; + grid-row: span 2; +} +.sku-media-main-badge { + position: absolute; + top: 6px; + left: 6px; + z-index: 1; + padding: 2px 6px; + border-radius: 4px; + background: rgb(64 57 79 / 72%); + color: #fff; + font-size: 11px; + line-height: 18px; +} .sku-media-item .ant-btn { position: absolute; right: 6px; @@ -200,24 +227,28 @@ height: 100%; } .sku-media-item img { + display: block; object-fit: contain; + object-position: center; } -.sku-media-empty { +.sku-media-picker.ant-btn { display: flex; - grid-column: 1 / -1; - min-height: 190px; + width: 100%; + height: 100%; + aspect-ratio: 3 / 4; + align-self: start; align-items: center; justify-content: center; - border: 1px dashed #d9d4df; border-radius: 8px; color: #90889c; font-size: 13px; } +.sku-media-picker--empty { + grid-column: span 2; + grid-row: span 2; +} .sku-spec-panel { - padding: 18px 18px 6px; - border: 1px solid #eeeaf3; - border-radius: 10px; - background: #fcfbfd; + padding-bottom: 6px; } .sku-spec-panel .ant-form-item { margin-bottom: 16px; diff --git a/apps/web/src/pages/products/components/ProductVariantSection.tsx b/apps/web/src/pages/products/components/ProductVariantSection.tsx index 5c6940c..39e8eea 100644 --- a/apps/web/src/pages/products/components/ProductVariantSection.tsx +++ b/apps/web/src/pages/products/components/ProductVariantSection.tsx @@ -354,7 +354,7 @@ export function ProductVariantSection({ {imageCandidates.length ? (
- {imageCandidates.map((candidate) => { + {imageCandidates.map((candidate, imageIndex) => { // 仅"转存成功"的候选可直接勾选; // 其余按转存状态展示对应按钮。 const selectable = @@ -368,9 +368,14 @@ export function ProductVariantSection({ ); return (
+ {imageIndex === 0 && ( + + 主图 + + )} ); })} + {/* 仅提供素材选择入口的视觉占位,实际选择流程后续接入。 */} +
) : ( -
- 暂无采集图片 +
+ {/* 没有采集图片时仍保留选择素材的入口。 */} +
)}