From ecbce54e70e9dcc303c42144d3a70411b4cdf3d6 Mon Sep 17 00:00:00 2001 From: marco Date: Wed, 17 Jun 2026 21:32:12 +0800 Subject: [PATCH] =?UTF-8?q?feat(cps):=20=E6=96=B0=E5=BB=BA=E6=B7=98?= =?UTF-8?q?=E5=AE=9D=E6=B4=BB=E5=8A=A8=E6=94=AF=E6=8C=81=E4=B8=8A=E4=BC=A0?= =?UTF-8?q?/=E9=80=89=E6=8B=A9=E8=90=BD=E5=9C=B0=E9=A1=B5=E5=9B=BE=20+=20?= =?UTF-8?q?=E5=88=97=E8=A1=A8=E7=BC=A9=E7=95=A5=E5=9B=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ActivityFormModal 淘宝分支加 ImagePicker(上传新图 / 选已有 / 预览),必填 - 活动列表加落地页图缩略图列 - types: CpsActivity.image_url Co-Authored-By: Claude Opus 4.8 --- src/app/(main)/cps/page.tsx | 110 +++++++++++++++++++++++++++++++++--- src/lib/types.ts | 1 + 2 files changed, 103 insertions(+), 8 deletions(-) diff --git a/src/app/(main)/cps/page.tsx b/src/app/(main)/cps/page.tsx index fa3901e..87e18e0 100644 --- a/src/app/(main)/cps/page.tsx +++ b/src/app/(main)/cps/page.tsx @@ -19,6 +19,7 @@ import { Tabs, Tag, Typography, + Upload, message, } from 'antd'; import { api, errMsg } from '@/lib/api'; @@ -556,6 +557,17 @@ function ActivitiesTab() { ellipsis: true, render: (v: string | null) => v || '-', }, + { + title: '落地页图', + dataIndex: 'image_url', + width: 80, + render: (v: string | null) => + v ? ( + + ) : ( + '-' + ), + }, { title: '状态', dataIndex: 'status', @@ -587,13 +599,86 @@ function ActivitiesTab() { showTotal: (t) => `共 ${t} 个活动`, onChange, }} - scroll={{ x: 1000 }} + scroll={{ x: 1080 }} /> setCreateOpen(false)} onDone={reload} /> ); } +// 淘宝活动落地页图选择器:上传新图 或 点选已有图。受控组件(value = image_url 绝对 URL)。 +function ImagePicker({ value, onChange }: { value?: string | null; onChange?: (v: string) => void }) { + const [existing, setExisting] = useState([]); + const [uploading, setUploading] = useState(false); + + useEffect(() => { + api + .get<{ images: string[] }>('/admin/api/cps/activity-images') + .then((r) => setExisting(r.data.images || [])) + .catch(() => {}); + }, []); + + const upload = async (file: File) => { + setUploading(true); + try { + const fd = new FormData(); + fd.append('file', file); + const r = await api.post<{ url: string }>('/admin/api/cps/upload-image', fd); + onChange?.(r.data.url); + setExisting((prev) => (prev.includes(r.data.url) ? prev : [r.data.url, ...prev])); + message.success('图片已上传'); + } catch (e) { + message.error(errMsg(e, '上传失败')); + } finally { + setUploading(false); + } + }; + + const thumb = (u: string, w: number, selected: boolean) => ( + 落地页图 onChange?.(u)} + style={{ + width: w, + height: Math.round(w * 1.27), + objectFit: 'cover', + borderRadius: 6, + cursor: 'pointer', + border: selected ? '2px solid #ff4d4f' : '2px solid #f0f0f0', + }} + /> + ); + + return ( +
+ { + upload(file); + return false; // 阻止 antd 默认上传,走我们自己的端点 + }} + > + + + {value && ( +
+ 当前: + {thumb(value, 90, true)} +
+ )} + {existing.length > 0 && ( +
+
或选择已有图:
+ {existing.map((u) => thumb(u, 56, u === value))} +
+ )} +
+ ); +} + function ActivityFormModal({ open, onClose, @@ -655,13 +740,22 @@ function ActivityFormModal({ )} {platform === 'taobao' && ( - - - + <> + + + + + + + )} {platform === 'jd' && (