feat(edit): 编辑页样式修改
This commit is contained in:
@@ -35,6 +35,25 @@ import './ProductEditPage.css';
|
||||
type EditorFormValues = SaveProductEditorDraftRequest;
|
||||
type AttributeDraft = NonNullable<EditorFormValues['attributes']>[number];
|
||||
|
||||
/** 规格字段有值时才可据此恢复到对应的 SKU 编辑模式。 */
|
||||
function hasPackageWeight(spec: {
|
||||
length_mm: string | null;
|
||||
width_mm: string | null;
|
||||
height_mm: string | null;
|
||||
shipping_weight_g: string | null;
|
||||
}) {
|
||||
return Boolean(spec.shipping_weight_g);
|
||||
}
|
||||
|
||||
function hasPackageDimensions(spec: {
|
||||
length_mm: string | null;
|
||||
width_mm: string | null;
|
||||
height_mm: string | null;
|
||||
shipping_weight_g: string | null;
|
||||
}) {
|
||||
return Boolean(spec.length_mm && spec.width_mm && spec.height_mm);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按 schema 补齐表单中缺失的属性草稿:aspect(变体维度)属性逐个 SKU 一条,
|
||||
* 其余类目级一条,确保 Form.List 字段与 schema 一一对应、可按定义渲染。
|
||||
@@ -167,11 +186,11 @@ function categoryTree(options: ProductEditorCategoryOption[]) {
|
||||
for (const category of options) {
|
||||
const node = nodes.get(category.id)!;
|
||||
node.isLeaf = !node.children?.length;
|
||||
node.disabled = node.isLeaf && (
|
||||
!category.is_active ||
|
||||
!category.external_type_id ||
|
||||
category.external_type_id === '0'
|
||||
);
|
||||
node.disabled =
|
||||
node.isLeaf &&
|
||||
(!category.is_active ||
|
||||
!category.external_type_id ||
|
||||
category.external_type_id === '0');
|
||||
}
|
||||
for (const category of options) {
|
||||
const path: string[] = [];
|
||||
@@ -404,6 +423,8 @@ const ProductEditPage = () => {
|
||||
const [materializingTransferId, setMaterializingTransferId] = useState<string | null>(null);
|
||||
const [dirty, setDirty] = useState(false);
|
||||
const [moreFeaturesExpanded, setMoreFeaturesExpanded] = useState(false);
|
||||
const [usesVariantPackageWeight, setUsesVariantPackageWeight] = useState(false);
|
||||
const [usesVariantPackageDimensions, setUsesVariantPackageDimensions] = useState(false);
|
||||
const blocker = useBlocker(dirty);
|
||||
const sourceSpecsApplied = useRef(false);
|
||||
const categories = useMemo(() => categoryTree(categoryOptions), [categoryOptions]);
|
||||
@@ -440,6 +461,14 @@ const ProductEditPage = () => {
|
||||
setSourceOverriddenFields(next.source_material_state.overridden_fields);
|
||||
sourceSpecsApplied.current = false;
|
||||
form.setFieldsValue(formValues(next));
|
||||
setUsesVariantPackageWeight(
|
||||
next.variants.length > 0 &&
|
||||
next.variants.every((variant) => hasPackageWeight(variant.package_spec))
|
||||
);
|
||||
setUsesVariantPackageDimensions(
|
||||
next.variants.length > 0 &&
|
||||
next.variants.every((variant) => hasPackageDimensions(variant.package_spec))
|
||||
);
|
||||
setDirty(false);
|
||||
} catch (error) {
|
||||
message.error(apiErrorMessage(error));
|
||||
@@ -601,7 +630,9 @@ const ProductEditPage = () => {
|
||||
Object.fromEntries(
|
||||
results.map(([id, page]) => [
|
||||
id,
|
||||
dictionaryQueries.current[id] ? (current[id] ?? null) : page.next_cursor,
|
||||
dictionaryQueries.current[id]
|
||||
? (current[id] ?? null)
|
||||
: page.next_cursor,
|
||||
])
|
||||
)
|
||||
);
|
||||
@@ -615,13 +646,7 @@ const ProductEditPage = () => {
|
||||
return () => {
|
||||
active = false;
|
||||
};
|
||||
}, [
|
||||
catalogRefresh,
|
||||
currentPlatform,
|
||||
editableAttributeSchema,
|
||||
selectedCategoryId,
|
||||
snapshot,
|
||||
]);
|
||||
}, [catalogRefresh, currentPlatform, editableAttributeSchema, selectedCategoryId, snapshot]);
|
||||
useEffect(() => {
|
||||
if (!snapshot || !currentPlatform) return;
|
||||
let active = true;
|
||||
@@ -703,6 +728,53 @@ const ProductEditPage = () => {
|
||||
}, [blocker, modal]);
|
||||
|
||||
const leave = () => navigate('/collection');
|
||||
/** 将 SPU 共用包装重量复制到每个 SKU,保留默认值作为未填写 SKU 的安全回退。 */
|
||||
const useVariantPackageWeight = () => {
|
||||
const defaultPackageSpec = form.getFieldValue([
|
||||
'common',
|
||||
'default_package_spec',
|
||||
]) as EditorFormValues['common']['default_package_spec'];
|
||||
const variants = form.getFieldValue('variants') as EditorFormValues['variants'];
|
||||
form.setFieldsValue({
|
||||
variants: variants.map((variant) => {
|
||||
const packageSpec = variant.package_spec;
|
||||
return {
|
||||
...variant,
|
||||
package_spec: {
|
||||
...packageSpec,
|
||||
shipping_weight_g:
|
||||
packageSpec.shipping_weight_g ?? defaultPackageSpec.shipping_weight_g,
|
||||
},
|
||||
};
|
||||
}),
|
||||
});
|
||||
setUsesVariantPackageWeight(true);
|
||||
setDirty(true);
|
||||
};
|
||||
/** 将 SPU 共用包装尺寸复制到每个 SKU,保留默认值作为未填写 SKU 的安全回退。 */
|
||||
const useVariantPackageDimensions = () => {
|
||||
const defaultPackageSpec = form.getFieldValue([
|
||||
'common',
|
||||
'default_package_spec',
|
||||
]) as EditorFormValues['common']['default_package_spec'];
|
||||
const variants = form.getFieldValue('variants') as EditorFormValues['variants'];
|
||||
form.setFieldsValue({
|
||||
variants: variants.map((variant) => {
|
||||
const packageSpec = variant.package_spec;
|
||||
return {
|
||||
...variant,
|
||||
package_spec: {
|
||||
...packageSpec,
|
||||
length_mm: packageSpec.length_mm ?? defaultPackageSpec.length_mm,
|
||||
width_mm: packageSpec.width_mm ?? defaultPackageSpec.width_mm,
|
||||
height_mm: packageSpec.height_mm ?? defaultPackageSpec.height_mm,
|
||||
},
|
||||
};
|
||||
}),
|
||||
});
|
||||
setUsesVariantPackageDimensions(true);
|
||||
setDirty(true);
|
||||
};
|
||||
/** 保存草稿:携带快照版本号做乐观锁;来源更新/版本冲突时重新加载合并结果。 */
|
||||
const save = async (values: EditorFormValues) => {
|
||||
if (!productId || !currentPlatform || !snapshot) return;
|
||||
@@ -836,7 +908,8 @@ const ProductEditPage = () => {
|
||||
if (
|
||||
dictionaryContextRef.current !== requestContext ||
|
||||
dictionaryQueries.current[attributeId] !== query
|
||||
) return;
|
||||
)
|
||||
return;
|
||||
setDictionaryValues((current) => ({
|
||||
...current,
|
||||
[attributeId]: cursor
|
||||
@@ -976,6 +1049,10 @@ const ProductEditPage = () => {
|
||||
categoryPaths={categories.paths}
|
||||
categoryNotFoundContent={categoryNotFoundContent}
|
||||
onCategorySearch={setCategorySearch}
|
||||
usesVariantPackageWeight={usesVariantPackageWeight}
|
||||
usesVariantPackageDimensions={usesVariantPackageDimensions}
|
||||
onUseVariantPackageWeight={useVariantPackageWeight}
|
||||
onUseVariantPackageDimensions={useVariantPackageDimensions}
|
||||
/>
|
||||
|
||||
<ProductAttributeSection
|
||||
@@ -1014,6 +1091,8 @@ const ProductEditPage = () => {
|
||||
onOpenDictionaryValues={openDictionaryValues}
|
||||
onLoadMoreDictionaryValues={loadMoreDictionaryValues}
|
||||
onDirty={() => setDirty(true)}
|
||||
usesVariantPackageWeight={usesVariantPackageWeight}
|
||||
usesVariantPackageDimensions={usesVariantPackageDimensions}
|
||||
/>
|
||||
|
||||
<ProductOtherSection
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { Button, Form, Input, Select, Typography } from 'antd';
|
||||
import { Button, Form, Input, InputNumber, Select, Typography } from 'antd';
|
||||
import type { FormInstance } from 'antd';
|
||||
import type {
|
||||
ProductAttributeDictionaryValue,
|
||||
@@ -159,18 +159,18 @@ function DynamicAttributeField({
|
||||
placeholder={`输入后回车添加,最多 ${definition.max_value_count} 项`}
|
||||
/>
|
||||
</Form.Item>
|
||||
) : (
|
||||
) : definition.value_type === 'integer' || definition.value_type === 'decimal' ? (
|
||||
<Form.Item name={scalarValueName} noStyle>
|
||||
<Input
|
||||
type={
|
||||
definition.value_type === 'integer' || definition.value_type === 'decimal'
|
||||
? 'number'
|
||||
: undefined
|
||||
}
|
||||
step={definition.value_type === 'integer' ? '1' : 'any'}
|
||||
<InputNumber<string>
|
||||
step={definition.value_type === 'integer' ? '1' : '0.001'}
|
||||
stringMode
|
||||
placeholder={`填写${definition.name}`}
|
||||
/>
|
||||
</Form.Item>
|
||||
) : (
|
||||
<Form.Item name={scalarValueName} noStyle>
|
||||
<Input placeholder={`填写${definition.name}`} />
|
||||
</Form.Item>
|
||||
);
|
||||
|
||||
return (
|
||||
|
||||
@@ -56,6 +56,7 @@
|
||||
}
|
||||
.dynamic-attribute-control,
|
||||
.dynamic-attribute-control .ant-select,
|
||||
.dynamic-attribute-control .ant-input {
|
||||
.dynamic-attribute-control .ant-input,
|
||||
.dynamic-attribute-control .ant-input-number {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@@ -12,10 +12,9 @@
|
||||
/* 长×宽×高输入组:随容器宽度收缩(压缩到下限后再由窄屏断点改为纵向堆叠) */
|
||||
.package-dimensions-controls {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(64px, 130px) 22px minmax(64px, 130px) 22px minmax(
|
||||
64px,
|
||||
130px
|
||||
) auto;
|
||||
grid-template-columns:
|
||||
minmax(64px, 130px) 22px minmax(64px, 130px) 22px minmax(64px, 130px)
|
||||
auto auto;
|
||||
align-items: center;
|
||||
gap: 7px;
|
||||
max-width: 100%;
|
||||
@@ -30,6 +29,14 @@
|
||||
color: #667085;
|
||||
line-height: 32px;
|
||||
}
|
||||
.package-dimensions-controls .ant-input-number {
|
||||
width: 100%;
|
||||
}
|
||||
.package-weight-control {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
/* 类目下拉弹层(Cascader popup,经 classNames.root 挂载) */
|
||||
.editor-category-popup .ant-cascader-menu {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Card, Cascader, Form, Input, Select } from 'antd';
|
||||
import { Button, Card, Cascader, Form, Input, InputNumber, Select, Tooltip } from 'antd';
|
||||
import type { FormInstance } from 'antd';
|
||||
import { PlusOutlined } from '@ant-design/icons';
|
||||
import type { ProductEditorSnapshot } from '@atlas/contracts';
|
||||
import { SectionTitle } from './SectionTitle';
|
||||
import './ProductMainInfoSection.css';
|
||||
@@ -13,28 +14,68 @@ type CategoryOption = {
|
||||
children?: CategoryOption[];
|
||||
};
|
||||
|
||||
function PackageFields({ name }: { name: NamePath }) {
|
||||
function PackageFields({
|
||||
name,
|
||||
usesVariantPackageWeight,
|
||||
usesVariantPackageDimensions,
|
||||
onUseVariantPackageWeight,
|
||||
onUseVariantPackageDimensions,
|
||||
}: {
|
||||
name: NamePath;
|
||||
usesVariantPackageWeight: boolean;
|
||||
usesVariantPackageDimensions: boolean;
|
||||
onUseVariantPackageWeight: () => void;
|
||||
onUseVariantPackageDimensions: () => void;
|
||||
}) {
|
||||
return (
|
||||
<div className="package-fields">
|
||||
<Form.Item name={[...name, 'shipping_weight_g']} label="包装重量" required>
|
||||
<Input type="number" min="0" step="any" addonAfter="g" style={{ width: 150 }} />
|
||||
</Form.Item>
|
||||
<Form.Item label="包装尺寸" required className="package-dimensions">
|
||||
<div className="package-dimensions-controls">
|
||||
<Form.Item name={[...name, 'length_mm']} noStyle>
|
||||
<Input type="number" min="0" step="any" placeholder="长" />
|
||||
</Form.Item>
|
||||
<span className="package-dimension-separator">×</span>
|
||||
<Form.Item name={[...name, 'width_mm']} noStyle>
|
||||
<Input type="number" min="0" step="any" placeholder="宽" />
|
||||
</Form.Item>
|
||||
<span className="package-dimension-separator">×</span>
|
||||
<Form.Item name={[...name, 'height_mm']} noStyle>
|
||||
<Input type="number" min="0" step="any" placeholder="高" />
|
||||
</Form.Item>
|
||||
<span className="package-dimension-unit">mm</span>
|
||||
</div>
|
||||
</Form.Item>
|
||||
{!usesVariantPackageWeight && (
|
||||
<Form.Item name={[...name, 'shipping_weight_g']} label="包装重量" required>
|
||||
<div className="package-weight-control">
|
||||
<InputNumber<string>
|
||||
min="0"
|
||||
step="0.001"
|
||||
stringMode
|
||||
addonAfter="g"
|
||||
style={{ width: 150 }}
|
||||
/>
|
||||
<Tooltip title="按 SKU 分别填写包装重量">
|
||||
<Button
|
||||
type="text"
|
||||
icon={<PlusOutlined />}
|
||||
aria-label="按 SKU 分别填写包装重量"
|
||||
onClick={onUseVariantPackageWeight}
|
||||
/>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</Form.Item>
|
||||
)}
|
||||
{!usesVariantPackageDimensions && (
|
||||
<Form.Item label="包装尺寸" required className="package-dimensions">
|
||||
<div className="package-dimensions-controls">
|
||||
<Form.Item name={[...name, 'length_mm']} noStyle>
|
||||
<InputNumber<string> min="0" step="0.001" stringMode placeholder="长" />
|
||||
</Form.Item>
|
||||
<span className="package-dimension-separator">×</span>
|
||||
<Form.Item name={[...name, 'width_mm']} noStyle>
|
||||
<InputNumber<string> min="0" step="0.001" stringMode placeholder="宽" />
|
||||
</Form.Item>
|
||||
<span className="package-dimension-separator">×</span>
|
||||
<Form.Item name={[...name, 'height_mm']} noStyle>
|
||||
<InputNumber<string> min="0" step="0.001" stringMode placeholder="高" />
|
||||
</Form.Item>
|
||||
<span className="package-dimension-unit">mm</span>
|
||||
<Tooltip title="按 SKU 分别填写包装尺寸">
|
||||
<Button
|
||||
type="text"
|
||||
icon={<PlusOutlined />}
|
||||
aria-label="按 SKU 分别填写包装尺寸"
|
||||
onClick={onUseVariantPackageDimensions}
|
||||
/>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</Form.Item>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -47,6 +88,10 @@ type Props = {
|
||||
categoryPaths: Map<string, string[]>;
|
||||
categoryNotFoundContent: string;
|
||||
onCategorySearch: (query: string) => void;
|
||||
usesVariantPackageWeight: boolean;
|
||||
usesVariantPackageDimensions: boolean;
|
||||
onUseVariantPackageWeight: () => void;
|
||||
onUseVariantPackageDimensions: () => void;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -63,6 +108,10 @@ export function ProductMainInfoSection({
|
||||
categoryPaths,
|
||||
categoryNotFoundContent,
|
||||
onCategorySearch,
|
||||
usesVariantPackageWeight,
|
||||
usesVariantPackageDimensions,
|
||||
onUseVariantPackageWeight,
|
||||
onUseVariantPackageDimensions,
|
||||
}: Props) {
|
||||
return (
|
||||
<Card className="editor-section editor-horizontal-section" bordered={false}>
|
||||
@@ -139,7 +188,15 @@ export function ProductMainInfoSection({
|
||||
<Input className="editor-short-input" placeholder="无品牌请填写“无品牌”" />
|
||||
</Form.Item>
|
||||
</div>
|
||||
<PackageFields name={['common', 'default_package_spec']} />
|
||||
{(!usesVariantPackageWeight || !usesVariantPackageDimensions) && (
|
||||
<PackageFields
|
||||
name={['common', 'default_package_spec']}
|
||||
usesVariantPackageWeight={usesVariantPackageWeight}
|
||||
usesVariantPackageDimensions={usesVariantPackageDimensions}
|
||||
onUseVariantPackageWeight={onUseVariantPackageWeight}
|
||||
onUseVariantPackageDimensions={onUseVariantPackageDimensions}
|
||||
/>
|
||||
)}
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,10 @@
|
||||
.sku-section .ant-input {
|
||||
border-radius: 8px;
|
||||
}
|
||||
.sku-section .ant-input-number {
|
||||
width: 100%;
|
||||
border-radius: 8px;
|
||||
}
|
||||
.sku-section textarea.ant-input {
|
||||
resize: none;
|
||||
}
|
||||
@@ -13,6 +17,9 @@
|
||||
.sku-section .ant-input-group .ant-input {
|
||||
border-radius: 8px 0 0 8px;
|
||||
}
|
||||
.sku-section .ant-input-number-group .ant-input-number {
|
||||
border-radius: 8px 0 0 8px;
|
||||
}
|
||||
|
||||
/* 卡片列表与卡片骨架 */
|
||||
.sku-card-list {
|
||||
@@ -83,7 +90,8 @@
|
||||
width: 100%;
|
||||
}
|
||||
.sku-card-summary .ant-input,
|
||||
.sku-card-summary textarea.ant-input {
|
||||
.sku-card-summary textarea.ant-input,
|
||||
.sku-card-summary .ant-input-number {
|
||||
width: 100%;
|
||||
}
|
||||
.sku-card-field,
|
||||
@@ -310,7 +318,9 @@
|
||||
min-width: 0;
|
||||
}
|
||||
/* 独立的重量输入(非"长×宽×高"行内组)限制宽度 */
|
||||
.sku-spec-panel > .ant-form-item:not(:has(.sku-inline-dimensions)) .ant-input-group-wrapper {
|
||||
.sku-spec-panel
|
||||
> .ant-form-item:not(:has(.sku-inline-dimensions))
|
||||
:is(.ant-input-group-wrapper, .ant-input-number-group-wrapper) {
|
||||
max-width: 220px;
|
||||
}
|
||||
.sku-inline-dimensions {
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
import { useState } from 'react';
|
||||
import { Button, Card, Form, Image, Input, Popconfirm, Space, Tag, Typography } from 'antd';
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
Form,
|
||||
Image,
|
||||
Input,
|
||||
InputNumber,
|
||||
Popconfirm,
|
||||
Space,
|
||||
Tag,
|
||||
Typography,
|
||||
} from 'antd';
|
||||
import type { FormInstance } from 'antd';
|
||||
import { CopyOutlined, DeleteOutlined, DownOutlined, PlusOutlined } from '@ant-design/icons';
|
||||
import type {
|
||||
@@ -65,15 +76,15 @@ function InlineDimensions({ name }: { name: NamePath }) {
|
||||
return (
|
||||
<div className="sku-inline-dimensions">
|
||||
<Form.Item name={[...name, 'length_mm']} noStyle>
|
||||
<Input type="number" min="0" step="any" placeholder="长" />
|
||||
<InputNumber<string> min="0" step="0.001" stringMode placeholder="长" />
|
||||
</Form.Item>
|
||||
<span className="sku-dimension-separator">×</span>
|
||||
<Form.Item name={[...name, 'width_mm']} noStyle>
|
||||
<Input type="number" min="0" step="any" placeholder="宽" />
|
||||
<InputNumber<string> min="0" step="0.001" stringMode placeholder="宽" />
|
||||
</Form.Item>
|
||||
<span className="sku-dimension-separator">×</span>
|
||||
<Form.Item name={[...name, 'height_mm']} noStyle>
|
||||
<Input type="number" min="0" step="any" placeholder="高" />
|
||||
<InputNumber<string> min="0" step="0.001" stringMode placeholder="高" />
|
||||
</Form.Item>
|
||||
<span className="sku-dimension-unit">mm</span>
|
||||
</div>
|
||||
@@ -94,6 +105,8 @@ type Props = {
|
||||
onOpenDictionaryValues: (dictionaryId: string) => void;
|
||||
onLoadMoreDictionaryValues: (dictionaryId: string, query: string) => void;
|
||||
onDirty: () => void;
|
||||
usesVariantPackageWeight: boolean;
|
||||
usesVariantPackageDimensions: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -117,6 +130,8 @@ export function ProductVariantSection({
|
||||
onOpenDictionaryValues,
|
||||
onLoadMoreDictionaryValues,
|
||||
onDirty,
|
||||
usesVariantPackageWeight,
|
||||
usesVariantPackageDimensions,
|
||||
}: Props) {
|
||||
// 实时监听变体草稿:驱动主图回显与候选图片的选中态。
|
||||
const draftVariants = (Form.useWatch('variants', form) ?? []) as VariantValues[];
|
||||
@@ -140,7 +155,11 @@ export function ProductVariantSection({
|
||||
{(fields, { add, remove }) => {
|
||||
// 新建变体默认值:id 为 null 表示服务端尚不存在,
|
||||
// client_key 作为保存前的临时标识。
|
||||
const addVariant = () =>
|
||||
const addVariant = () => {
|
||||
const defaultPackageSpec = form.getFieldValue([
|
||||
'common',
|
||||
'default_package_spec',
|
||||
]) as EditorFormValues['common']['default_package_spec'];
|
||||
add({
|
||||
id: null,
|
||||
client_key: crypto.randomUUID(),
|
||||
@@ -157,15 +176,24 @@ export function ProductVariantSection({
|
||||
status: null,
|
||||
},
|
||||
package_spec: {
|
||||
length_mm: null,
|
||||
width_mm: null,
|
||||
height_mm: null,
|
||||
shipping_weight_g: null,
|
||||
length_mm: usesVariantPackageDimensions
|
||||
? defaultPackageSpec.length_mm
|
||||
: null,
|
||||
width_mm: usesVariantPackageDimensions
|
||||
? defaultPackageSpec.width_mm
|
||||
: null,
|
||||
height_mm: usesVariantPackageDimensions
|
||||
? defaultPackageSpec.height_mm
|
||||
: null,
|
||||
shipping_weight_g: usesVariantPackageWeight
|
||||
? defaultPackageSpec.shipping_weight_g
|
||||
: null,
|
||||
status: null,
|
||||
},
|
||||
offer_id: null,
|
||||
media_asset_ids: [],
|
||||
} satisfies VariantValues);
|
||||
};
|
||||
return (
|
||||
<div className="sku-card-list">
|
||||
{fields.map((field, index) => {
|
||||
@@ -331,7 +359,12 @@ export function ProductVariantSection({
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Input placeholder="—" />
|
||||
<InputNumber<string>
|
||||
min="0"
|
||||
step="0.0001"
|
||||
stringMode
|
||||
placeholder="—"
|
||||
/>
|
||||
</Form.Item>
|
||||
</div>
|
||||
<div className="sku-card-field sku-price-field">
|
||||
@@ -340,13 +373,15 @@ export function ProductVariantSection({
|
||||
{original?.listing.currency_code ?? '₽'}
|
||||
)
|
||||
</span>
|
||||
<Input
|
||||
<InputNumber<string>
|
||||
value={
|
||||
original?.listing.selling_price ??
|
||||
''
|
||||
}
|
||||
placeholder="—"
|
||||
readOnly
|
||||
controls={false}
|
||||
stringMode
|
||||
/>
|
||||
</div>
|
||||
<div className="sku-card-value">
|
||||
@@ -542,26 +577,30 @@ export function ProductVariantSection({
|
||||
<Typography.Title level={5}>
|
||||
SKU 规格
|
||||
</Typography.Title>
|
||||
<Form.Item
|
||||
name={[
|
||||
field.name,
|
||||
'package_spec',
|
||||
'shipping_weight_g',
|
||||
]}
|
||||
label="包装重量"
|
||||
>
|
||||
<Input
|
||||
type="number"
|
||||
min="0"
|
||||
step="any"
|
||||
addonAfter="g"
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item label="包装尺寸">
|
||||
<InlineDimensions
|
||||
name={[field.name, 'package_spec']}
|
||||
/>
|
||||
</Form.Item>
|
||||
{usesVariantPackageWeight && (
|
||||
<Form.Item
|
||||
name={[
|
||||
field.name,
|
||||
'package_spec',
|
||||
'shipping_weight_g',
|
||||
]}
|
||||
label="包装重量"
|
||||
>
|
||||
<InputNumber<string>
|
||||
min="0"
|
||||
step="0.001"
|
||||
stringMode
|
||||
addonAfter="g"
|
||||
/>
|
||||
</Form.Item>
|
||||
)}
|
||||
{usesVariantPackageDimensions && (
|
||||
<Form.Item label="包装尺寸">
|
||||
<InlineDimensions
|
||||
name={[field.name, 'package_spec']}
|
||||
/>
|
||||
</Form.Item>
|
||||
)}
|
||||
<Form.Item
|
||||
name={[
|
||||
field.name,
|
||||
@@ -570,10 +609,10 @@ export function ProductVariantSection({
|
||||
]}
|
||||
label="商品重量"
|
||||
>
|
||||
<Input
|
||||
type="number"
|
||||
<InputNumber<string>
|
||||
min="0"
|
||||
step="any"
|
||||
step="0.001"
|
||||
stringMode
|
||||
addonAfter="g"
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
Reference in New Issue
Block a user