import { useState } from 'react'; import { Button, Descriptions, Divider, Drawer, Form, Input, InputNumber, Modal, Select, Space, Table, Tag, Typography, message, } from 'antd'; import { MinusCircleOutlined, PlusOutlined } from '@ant-design/icons'; import type { ColumnsType } from 'antd/es/table'; import { request } from '../lib/api'; import { AROMA_TYPE_LABELS, DETAIL_TEMPLATE_STATUS_LABELS, fmtTime, } from '../lib/constants'; import { useAdminList } from '../lib/useAdminList'; import DetailImageUrlList from '../components/DetailImageUrlList'; import type { ProductDetailTemplateDto } from '../lib/product-detail-templates'; import { TEMPLATE_MAX_DETAIL_IMAGES } from '../lib/product-detail-templates'; type Row = ProductDetailTemplateDto; type TemplateFormValues = { code: string; name: string; description?: string; aromaType?: string | null; storyTitle?: string; storyText?: string; features?: Array<{ icon?: string; title?: string; desc?: string }>; detailImageUrls?: string[]; suggestedDetailImageCount?: number; sortOrder?: number; status?: string; }; function mapToForm(d: Record) { const row = d as Row; return { ...row, detailImageUrls: row.detailImageUrls?.length ? row.detailImageUrls : [''], features: row.features?.length ? row.features : [{ icon: 'star', title: '', desc: '' }], }; } function buildPayload(v: TemplateFormValues) { const detailImageUrls = (v.detailImageUrls ?? []).map((u) => u?.trim()).filter(Boolean); const features = (v.features ?? []) .filter((f) => f?.title?.trim() || f?.desc?.trim()) .map((f) => ({ icon: f.icon?.trim() || 'star', title: f.title?.trim() ?? '', desc: f.desc?.trim() ?? '', })); return { code: v.code.trim(), name: v.name.trim(), description: v.description?.trim() || undefined, aromaType: v.aromaType || null, storyTitle: v.storyTitle?.trim() || undefined, storyText: v.storyText?.trim() || undefined, features, detailImageUrls, suggestedDetailImageCount: detailImageUrls.length || (v.suggestedDetailImageCount ?? 1), sortOrder: v.sortOrder ?? 0, status: v.status ?? 'ACTIVE', }; } function TemplateContentFields() { return ( <> 模板详情长图(套用商品时可逐张修改) 卖点特色 {(fields, { add, remove }) => ( <> {fields.map((field) => ( {fields.length > 1 && ( remove(field.name)} style={{ marginTop: 30 }} /> )} ))} )} ); } export default function ProductDetailTemplatesPage() { const [form] = Form.useForm(); const [editForm] = Form.useForm(); const [createForm] = Form.useForm(); const [filters, setFilters] = useState>({}); const { data, loading, page, pageSize, setPage, setPageSize, reload } = useAdminList( '/admin/product-detail-templates', () => { const qs = new URLSearchParams(); if (filters.name) qs.set('name', filters.name); if (filters.code) qs.set('code', filters.code); if (filters.status) qs.set('status', filters.status); if (filters.aromaType) qs.set('aromaType', filters.aromaType); return qs; }, [filters], ); const [detail, setDetail] = useState | null>(null); const [drawerOpen, setDrawerOpen] = useState(false); const [createOpen, setCreateOpen] = useState(false); const columns: ColumnsType = [ { title: '编码', dataIndex: 'code', width: 120 }, { title: '名称', dataIndex: 'name', width: 120 }, { title: '说明', dataIndex: 'description', width: 200, ellipsis: true }, { title: '香型', dataIndex: 'aromaType', width: 90, render: (v) => (v ? AROMA_TYPE_LABELS[v] || v : '—') }, { title: '详情图', dataIndex: 'detailImageUrls', width: 80, render: (v: string[] | undefined) => v?.length ?? 0 }, { title: '排序', dataIndex: 'sortOrder', width: 60 }, { title: '状态', dataIndex: 'status', width: 80, render: (s) => {DETAIL_TEMPLATE_STATUS_LABELS[s] || s} }, { title: '更新', dataIndex: 'updatedAt', width: 160, render: fmtTime }, { title: '操作', width: 80, render: (_, row) => ( ), }, ]; return (
商品详情模板
{ setFilters(v); setPage(1); }}> ({ value, label }))} />
{ setPage(p); setPageSize(ps); } }} /> setDrawerOpen(false)} extra={detail && ( )}> {detail && ( <> {String(detail.id)} {fmtTime(String(detail.createdAt))}
({ value, label }))} /> )}
setCreateOpen(false)} onOk={async () => { const v = await createForm.validateFields(); const payload = buildPayload(v); await request('/admin/product-detail-templates', { method: 'POST', body: JSON.stringify(payload) }); message.success('已创建'); setCreateOpen(false); createForm.resetFields(); void reload(); }} width={640}>
({ value, label }))} />
); }