Files
ozon-seller-kit/studio/src/pages/product/ProductAttributesPanel.tsx
T

162 lines
7.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { useState } from 'react';
import { Col, Divider, Input, Row, Tag, Typography } from 'antd';
import { ProductDetail } from '@/services/product';
import CopyPanel from './CopyPanel';
const { Text } = Typography;
interface Props {
product: ProductDetail;
onSave: (p: Partial<ProductDetail>) => Promise<void> | void;
}
/** 产品属性:采集参数只读展示 / 条形码 / 品牌 / 简介 / AI 文案 */
export default function ProductAttributesPanel({ product, onSave }: Props) {
const raw = (product.raw ?? {}) as Record<string, unknown>;
const params = raw.params as Array<{ key: string; value: string }> | undefined;
const [descExpanded, setDescExpanded] = useState(false);
const updateRaw = (patch: Record<string, unknown>) => {
onSave({ raw: { ...raw, ...patch } });
};
const sellingPoints = typeof raw.sellingPoints === 'string' ? raw.sellingPoints : '';
const desc = typeof raw.desc === 'string' ? raw.desc : '';
return (
<div>
{/* 基础字段:品牌 + 条形码 */}
<Row gutter={16} style={{ marginBottom: 12 }}>
<Col span={8}>
<Text style={{ fontSize: 12, color: '#666', display: 'block', marginBottom: 4 }}>
品牌(Brand
</Text>
<Input
value={(raw.brand as string) ?? ''}
onChange={(e) => updateRaw({ brand: e.target.value })}
placeholder="采集到的品牌名"
/>
</Col>
<Col span={8}>
<Text style={{ fontSize: 12, color: '#666', display: 'block', marginBottom: 4 }}>
条形码(Barcode
</Text>
<Input
value={product.barcode ?? ''}
onChange={(e) => onSave({ barcode: e.target.value })}
placeholder="EAN / UPC / 留空"
/>
</Col>
<Col span={8}>
<Text style={{ fontSize: 12, color: '#666', display: 'block', marginBottom: 4 }}>
主题标签(内部备注)
</Text>
<Input
value={(raw.tags as string) ?? ''}
onChange={(e) => updateRaw({ tags: e.target.value })}
placeholder="逗号分隔,内部用"
/>
</Col>
</Row>
{/* 俄文简介(来自 AI 生成或手动) */}
<div style={{ marginBottom: 12 }}>
<Text style={{ fontSize: 12, color: '#666', display: 'block', marginBottom: 4 }}>
俄文简介(description
</Text>
<Input.TextArea
autoSize={{ minRows: 3, maxRows: 8 }}
value={product.description ?? ''}
onChange={(e) => onSave({ description: e.target.value })}
placeholder="Описание товара на русском — можно сгенерировать через AI ниже"
/>
</div>
{/* 采集参数展示(只读,参考用) */}
{Array.isArray(params) && params.length > 0 && (
<div style={{ marginBottom: 12, padding: '12px 16px', background: '#fafafa', borderRadius: 8 }}>
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 8 }}>
<Text style={{ fontSize: 12, color: '#666', fontWeight: 500 }}>
采集参数({params.length} 项,只读参考)
</Text>
{params.length > 8 && (
<a style={{ fontSize: 12 }} onClick={() => setDescExpanded(!descExpanded)}>
{descExpanded ? '收起' : `展开全部 ${params.length} 项`}
</a>
)}
</div>
<Row gutter={[8, 4]}>
{(descExpanded ? params : params.slice(0, 8)).map((p, i) => (
<Col key={i} span={12}>
<div style={{ display: 'flex', gap: 6, alignItems: 'baseline' }}>
<Tag
style={{
fontSize: 11,
maxWidth: 120,
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
flexShrink: 0,
}}
>
{p.key}
</Tag>
<Text style={{ fontSize: 12 }} ellipsis={{ tooltip: p.value }}>
{p.value}
</Text>
</div>
</Col>
))}
</Row>
{!descExpanded && params.length > 8 && (
<Text type="secondary" style={{ fontSize: 11, marginTop: 4, display: 'block' }}>
还有 {params.length - 8} 项未显示
</Text>
)}
</div>
)}
{/* 采集卖点 / 描述(只读参考) */}
{(sellingPoints || desc) && (
<div style={{ marginBottom: 12, padding: '12px 16px', background: '#fafafa', borderRadius: 8 }}>
{sellingPoints && (
<>
<Text style={{ fontSize: 12, color: '#666', fontWeight: 500, display: 'block', marginBottom: 4 }}>
采集卖点(参考)
</Text>
<Text style={{ fontSize: 12, whiteSpace: 'pre-wrap' }}>
{sellingPoints}
</Text>
</>
)}
{desc && (
<>
<Text
style={{
fontSize: 12,
color: '#666',
fontWeight: 500,
display: 'block',
marginTop: sellingPoints ? 8 : 0,
marginBottom: 4,
}}
>
采集描述(参考)
</Text>
<Text style={{ fontSize: 12, whiteSpace: 'pre-wrap' }}>
{desc.slice(0, 300)}
{desc.length > 300 && '…'}
</Text>
</>
)}
</div>
)}
<Divider style={{ margin: '16px 0' }} />
<CopyPanel product={product} onSave={onSave} />
</div>
);
}