import { useEffect, useState } from 'react'; import { Alert, Button, Card, Popconfirm, Select, Space, Spin, Typography, message } from 'antd'; import type { FormInstance } from 'antd/es/form'; import { request, type Paginated } from '../lib/api'; import { getProductDetailTemplate, mapDtoToProductDetailTemplate, type ProductDetailTemplate, type ProductDetailTemplateDto, } from '../lib/product-detail-templates'; type Props = { form: FormInstance; /** 当前商品香型,用于推荐匹配模板 */ aromaType?: string; }; function hasDetailContent(form: FormInstance) { const storyTitle = form.getFieldValue('storyTitle') as string | undefined; const storyText = form.getFieldValue('storyText') as string | undefined; const features = form.getFieldValue('features') as Array<{ title?: string; desc?: string }> | undefined; const detailImageUrls = form.getFieldValue('detailImageUrls') as string[] | undefined; const hasFeatures = (features ?? []).some((f) => f?.title?.trim() || f?.desc?.trim()); const hasImages = (detailImageUrls ?? []).some((u) => u?.trim()); return Boolean(storyTitle?.trim() || storyText?.trim() || hasFeatures || hasImages); } function applyTemplate(form: FormInstance, template: ProductDetailTemplate) { const { content } = template; const detailImageUrls = content.detailImageUrls?.length ? [...content.detailImageUrls] : ['']; form.setFieldsValue({ storyTitle: content.storyTitle ?? '', storyText: content.storyText ?? '', detailImageUrls, features: content.features && content.features.length > 0 ? content.features.map((f) => ({ ...f })) : [{ icon: 'star', title: '', desc: '' }], }); const imageHint = detailImageUrls.filter(Boolean).length; message.success( imageHint > 0 ? `已应用模板「${template.label}」(含 ${imageHint} 张详情图,可逐张修改)` : `已应用模板「${template.label}」`, ); } export default function ProductDetailTemplatePicker({ form, aromaType }: Props) { const [templates, setTemplates] = useState([]); const [loading, setLoading] = useState(true); const [selectedId, setSelectedId] = useState(); useEffect(() => { let cancelled = false; setLoading(true); request>( '/admin/product-detail-templates?status=ACTIVE&pageSize=100', ) .then((res) => { if (cancelled) return; const mapped = res.items.map(mapDtoToProductDetailTemplate); setTemplates(mapped); const defaultId = (aromaType && mapped.find((t) => t.aromaType === aromaType)?.id) || mapped.find((t) => t.code === 'dukang-classic')?.id || mapped[0]?.id; setSelectedId(defaultId); }) .catch(() => { if (!cancelled) message.error('加载详情模板失败'); }) .finally(() => { if (!cancelled) setLoading(false); }); return () => { cancelled = true; }; }, [aromaType]); const selected = getProductDetailTemplate(templates, selectedId ?? ''); function doApply() { if (!selected) return; applyTemplate(form, selected); } function handleApply() { if (!selected) return; if (hasDetailContent(form)) { return; } doApply(); } if (loading) { return ( ); } if (templates.length === 0) { return ( 暂无可用模板,请先在「详情模板」菜单中创建。 ); } return ( 选择模板可一键填充详情长图、故事与卖点;套用后可在下方逐张替换图片。