diff --git a/apps/web/src/components/DrawerForm.tsx b/apps/web/src/components/DrawerForm.tsx index d07db5f..9ca1635 100644 --- a/apps/web/src/components/DrawerForm.tsx +++ b/apps/web/src/components/DrawerForm.tsx @@ -19,6 +19,7 @@ interface DrawerFormProps { sections?: FormSection[]; children?: React.ReactNode; columns?: 1 | 2; + form?: ReturnType[0]; } export function DrawerForm({ @@ -32,8 +33,10 @@ export function DrawerForm({ sections, children, columns = 2, + form: externalForm, }: DrawerFormProps) { - const [form] = Form.useForm(); + const [internalForm] = Form.useForm(); + const form = externalForm ?? internalForm; const isDark = useThemeMode(); React.useEffect(() => { diff --git a/apps/web/src/pages/health/PointsProductList.tsx b/apps/web/src/pages/health/PointsProductList.tsx index 8d80f2f..c9330b0 100644 --- a/apps/web/src/pages/health/PointsProductList.tsx +++ b/apps/web/src/pages/health/PointsProductList.tsx @@ -11,12 +11,15 @@ import { Tag, Badge, Switch, + Upload, message, } from 'antd'; import { PlusOutlined, EditOutlined, DeleteOutlined, + PictureOutlined, + UploadOutlined, } from '@ant-design/icons'; import { pointsApi, @@ -26,8 +29,11 @@ import { import { AuthButton } from '../../components/AuthButton'; import { DrawerForm } from '../../components/DrawerForm'; import type { FormSection } from '../../components/DrawerForm'; +import MediaPicker from '../../components/MediaPicker'; import { PageContainer } from '../../components/PageContainer'; +import { uploadFile } from '../../api/upload'; import { usePaginatedData } from '../../hooks/usePaginatedData'; +import { useThemeMode } from '../../hooks/useThemeMode'; import { formatDateTime } from '../../utils/format'; /** 商品类型映射 */ @@ -59,6 +65,9 @@ interface ProductFilters { export default function PointsProductList() { const [modalOpen, setModalOpen] = useState(false); const [editing, setEditing] = useState(null); + const [mediaPickerOpen, setMediaPickerOpen] = useState(false); + const [form] = Form.useForm(); + const isDark = useThemeMode(); const fetchProducts = useCallback( async (page: number, pageSize: number, filters: ProductFilters) => { @@ -309,8 +318,53 @@ export default function PointsProductList() { title: '展示设置', fields: ( <> - - + + + + + { + try { + const result = await uploadFile(file); + form.setFieldValue('image_url', result.url); + message.success('图片上传成功'); + } catch { + message.error('图片上传失败'); + } + return false; + }} + > + + + + + prev.image_url !== cur.image_url}> + {({ getFieldValue }) => { + const url: string | undefined = getFieldValue('image_url'); + if (!url) return null; + return ( +
+ 商品图片预览 { (e.target as HTMLImageElement).style.display = 'none'; }} + /> +
+ ); + }}
@@ -402,6 +456,16 @@ export default function PointsProductList() { width={600} columns={2} sections={formSections} + form={form} + /> + + setMediaPickerOpen(false)} + onSelect={(url) => { + form.setFieldValue('image_url', url); + message.success('已选择图片'); + }} /> );