ソースを参照

✨ feat(advertisement): 重构广告管理功能并提取独立表单组件

- 创建 CreateAdvertisementForm 组件处理广告创建功能
- 创建 EditAdvertisementForm 组件处理广告编辑功能
- 重构 Advertisements 页面移除冗余表单逻辑
- 优化组件结构提升代码可维护性
- 修复删除广告状态码验证从200改为204
yourname 4 ヶ月 前
コミット
b3b16ed613

+ 241 - 0
src/client/admin-shadcn/components/CreateAdvertisementForm.tsx

@@ -0,0 +1,241 @@
+import React from 'react';
+import { useForm } from 'react-hook-form';
+import { zodResolver } from '@hookform/resolvers/zod';
+import { toast } from 'sonner';
+
+import { Button } from '@/client/components/ui/button';
+import { Input } from '@/client/components/ui/input';
+import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from '@/client/components/ui/dialog';
+import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from '@/client/components/ui/form';
+import { Textarea } from '@/client/components/ui/textarea';
+import { Switch } from '@/client/components/ui/switch';
+
+import { useMutation, useQueryClient } from '@tanstack/react-query';
+import { advertisementClient } from '@/client/api';
+import type { InferRequestType } from 'hono/client';
+import { CreateAdvertisementDto } from '@/server/modules/advertisements/advertisement.schema';
+import AvatarSelector from './AvatarSelector';
+
+// 类型定义
+type CreateRequest = InferRequestType<typeof advertisementClient.$post>['json'];
+
+interface CreateAdvertisementFormProps {
+  open: boolean;
+  onOpenChange: (open: boolean) => void;
+  onSuccess?: () => void;
+}
+
+const CreateAdvertisementForm: React.FC<CreateAdvertisementFormProps> = ({
+  open,
+  onOpenChange,
+  onSuccess
+}) => {
+  const queryClient = useQueryClient();
+
+  // 创建广告
+  const createMutation = useMutation({
+    mutationFn: async (data: CreateRequest) => {
+      const response = await advertisementClient.$post({ json: data });
+      if (response.status !== 201) throw new Error('创建广告失败');
+      return response.json();
+    },
+    onSuccess: () => {
+      queryClient.invalidateQueries({ queryKey: ['advertisements'] });
+      toast.success('广告创建成功');
+      onSuccess?.();
+    },
+    onError: (error) => {
+      toast.error(`创建失败:${error.message}`);
+    }
+  });
+
+  // 表单实例
+  const form = useForm<CreateRequest>({
+    resolver: zodResolver(CreateAdvertisementDto),
+    defaultValues: {
+      title: '',
+      linkUrl: '',
+      imageFileId: undefined,
+      positionId: 1,
+      sortOrder: 0,
+      isEnabled: 1,
+      description: '',
+      startTime: undefined,
+      endTime: undefined
+    }
+  });
+
+  // 处理表单提交
+  const handleSubmit = (data: CreateRequest) => {
+    createMutation.mutate(data);
+  };
+
+  return (
+    <Dialog open={open} onOpenChange={onOpenChange}>
+      <DialogContent className="sm:max-w-[600px] max-h-[90vh] overflow-y-auto">
+        <DialogHeader>
+          <DialogTitle>创建广告</DialogTitle>
+          <DialogDescription>
+            创建新的广告内容
+          </DialogDescription>
+        </DialogHeader>
+        
+        <Form {...form}>
+          <form onSubmit={form.handleSubmit(handleSubmit)} className="space-y-4">
+            <FormField
+              control={form.control}
+              name="title"
+              render={({ field }) => (
+                <FormItem>
+                  <FormLabel className="flex items-center">
+                    广告标题
+                    <span className="text-red-500 ml-1">*</span>
+                  </FormLabel>
+                  <FormControl>
+                    <Input placeholder="请输入广告标题" {...field} />
+                  </FormControl>
+                  <FormMessage />
+                </FormItem>
+              )}
+            />
+
+            <FormField
+              control={form.control}
+              name="linkUrl"
+              render={({ field }) => (
+                <FormItem>
+                  <FormLabel className="flex items-center">
+                    链接地址
+                    <span className="text-red-500 ml-1">*</span>
+                  </FormLabel>
+                  <FormControl>
+                    <Input placeholder="请输入链接地址" {...field} />
+                  </FormControl>
+                  <FormMessage />
+                </FormItem>
+              )}
+            />
+
+            <FormField
+              control={form.control}
+              name="imageFileId"
+              render={({ field }) => (
+                <FormItem>
+                  <FormLabel>
+                    图片文件
+                  </FormLabel>
+                  <FormControl>
+                    <AvatarSelector
+                      value={field.value || undefined}
+                      onChange={(value) => field.onChange(value ? Number(value) : undefined)}
+                      maxSize={2}
+                      uploadPath="/advertisements"
+                      uploadButtonText="上传图片"
+                      previewSize="medium"
+                      placeholder="选择广告图片"
+                    />
+                  </FormControl>
+                  <FormMessage />
+                </FormItem>
+              )}
+            />
+
+            <div className="grid grid-cols-2 gap-4">
+              <FormField
+                control={form.control}
+                name="positionId"
+                render={({ field }) => (
+                  <FormItem>
+                    <FormLabel className="flex items-center">
+                      广告位ID
+                      <span className="text-red-500 ml-1">*</span>
+                    </FormLabel>
+                    <FormControl>
+                      <Input
+                        type="number"
+                        placeholder="请输入广告位ID"
+                        {...field}
+                        onChange={(e) => field.onChange(Number(e.target.value))}
+                      />
+                    </FormControl>
+                    <FormMessage />
+                  </FormItem>
+                )}
+              />
+
+              <FormField
+                control={form.control}
+                name="sortOrder"
+                render={({ field }) => (
+                  <FormItem>
+                    <FormLabel>排序值</FormLabel>
+                    <FormControl>
+                      <Input
+                        type="number"
+                        placeholder="排序值"
+                        {...field}
+                        onChange={(e) => field.onChange(Number(e.target.value))}
+                      />
+                    </FormControl>
+                    <FormMessage />
+                  </FormItem>
+                )}
+              />
+            </div>
+
+            <FormField
+              control={form.control}
+              name="isEnabled"
+              render={({ field }) => (
+                <FormItem className="flex flex-row items-center justify-between rounded-lg border p-4">
+                  <div className="space-y-0.5">
+                    <FormLabel className="text-base">启用状态</FormLabel>
+                    <FormDescription>
+                      是否在前台显示该广告
+                    </FormDescription>
+                  </div>
+                  <FormControl>
+                    <Switch
+                      checked={field.value === 1}
+                      onCheckedChange={(checked) => field.onChange(checked ? 1 : 0)}
+                    />
+                  </FormControl>
+                </FormItem>
+              )}
+            />
+
+            <FormField
+              control={form.control}
+              name="description"
+              render={({ field }) => (
+                <FormItem>
+                  <FormLabel>广告描述</FormLabel>
+                  <FormControl>
+                    <Textarea
+                      placeholder="请输入广告描述"
+                      className="resize-none"
+                      {...field}
+                      value={field.value || ''}
+                    />
+                  </FormControl>
+                  <FormMessage />
+                </FormItem>
+              )}
+            />
+
+            <DialogFooter>
+              <Button type="button" variant="outline" onClick={() => onOpenChange(false)}>
+                取消
+              </Button>
+              <Button type="submit" disabled={createMutation.isPending}>
+                创建
+              </Button>
+            </DialogFooter>
+          </form>
+        </Form>
+      </DialogContent>
+    </Dialog>
+  );
+};
+
+export default CreateAdvertisementForm;

+ 258 - 0
src/client/admin-shadcn/components/EditAdvertisementForm.tsx

@@ -0,0 +1,258 @@
+import React from 'react';
+import { useForm } from 'react-hook-form';
+import { zodResolver } from '@hookform/resolvers/zod';
+import { toast } from 'sonner';
+
+import { Button } from '@/client/components/ui/button';
+import { Input } from '@/client/components/ui/input';
+import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from '@/client/components/ui/dialog';
+import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from '@/client/components/ui/form';
+import { Textarea } from '@/client/components/ui/textarea';
+import { Switch } from '@/client/components/ui/switch';
+
+import { useMutation, useQueryClient } from '@tanstack/react-query';
+import { advertisementClient } from '@/client/api';
+import type { InferRequestType, InferResponseType } from 'hono/client';
+import { UpdateAdvertisementDto } from '@/server/modules/advertisements/advertisement.schema';
+import AvatarSelector from './AvatarSelector';
+
+// 类型定义
+type UpdateRequest = InferRequestType<typeof advertisementClient[':id']['$put']>['json'];
+type AdvertisementItem = InferResponseType<typeof advertisementClient.$get, 200>['data'][0];
+
+interface EditAdvertisementFormProps {
+  open: boolean;
+  onOpenChange: (open: boolean) => void;
+  advertisement: AdvertisementItem | null;
+  onSuccess?: () => void;
+}
+
+const EditAdvertisementForm: React.FC<EditAdvertisementFormProps> = ({
+  open,
+  onOpenChange,
+  advertisement,
+  onSuccess
+}) => {
+  const queryClient = useQueryClient();
+
+  // 更新广告
+  const updateMutation = useMutation({
+    mutationFn: async ({ id, data }: { id: number; data: UpdateRequest }) => {
+      const response = await advertisementClient[':id']['$put']({
+        param: { id: id.toString() },
+        json: data
+      });
+      if (response.status !== 200) throw new Error('更新广告失败');
+      return response.json();
+    },
+    onSuccess: () => {
+      queryClient.invalidateQueries({ queryKey: ['advertisements'] });
+      toast.success('广告更新成功');
+      onSuccess?.();
+    },
+    onError: (error) => {
+      toast.error(`更新失败:${error.message}`);
+    }
+  });
+
+  // 表单实例
+  const form = useForm<UpdateRequest>({
+    resolver: zodResolver(UpdateAdvertisementDto),
+    defaultValues: {}
+  });
+
+  // 重置表单数据
+  React.useEffect(() => {
+    if (advertisement) {
+      form.reset({
+        title: advertisement.title,
+        linkUrl: advertisement.linkUrl,
+        imageFileId: advertisement.imageFileId || undefined,
+        positionId: advertisement.positionId,
+        sortOrder: advertisement.sortOrder,
+        isEnabled: advertisement.isEnabled,
+        description: advertisement.description || undefined,
+        startTime: advertisement.startTime || undefined,
+        endTime: advertisement.endTime || undefined
+      });
+    }
+  }, [advertisement, form]);
+
+  // 处理表单提交
+  const handleSubmit = (data: UpdateRequest) => {
+    if (advertisement) {
+      updateMutation.mutate({ id: advertisement.id, data });
+    }
+  };
+
+  if (!advertisement) return null;
+
+  return (
+    <Dialog open={open} onOpenChange={onOpenChange}>
+      <DialogContent className="sm:max-w-[600px] max-h-[90vh] overflow-y-auto">
+        <DialogHeader>
+          <DialogTitle>编辑广告</DialogTitle>
+          <DialogDescription>
+            编辑现有广告信息
+          </DialogDescription>
+        </DialogHeader>
+        
+        <Form {...form}>
+          <form onSubmit={form.handleSubmit(handleSubmit)} className="space-y-4">
+            <FormField
+              control={form.control}
+              name="title"
+              render={({ field }) => (
+                <FormItem>
+                  <FormLabel className="flex items-center">
+                    广告标题
+                    <span className="text-red-500 ml-1">*</span>
+                  </FormLabel>
+                  <FormControl>
+                    <Input placeholder="请输入广告标题" {...field} />
+                  </FormControl>
+                  <FormMessage />
+                </FormItem>
+              )}
+            />
+
+            <FormField
+              control={form.control}
+              name="linkUrl"
+              render={({ field }) => (
+                <FormItem>
+                  <FormLabel className="flex items-center">
+                    链接地址
+                    <span className="text-red-500 ml-1">*</span>
+                  </FormLabel>
+                  <FormControl>
+                    <Input placeholder="请输入链接地址" {...field} />
+                  </FormControl>
+                  <FormMessage />
+                </FormItem>
+              )}
+            />
+
+            <FormField
+              control={form.control}
+              name="imageFileId"
+              render={({ field }) => (
+                <FormItem>
+                  <FormLabel>
+                    图片文件
+                  </FormLabel>
+                  <FormControl>
+                    <AvatarSelector
+                      value={field.value || undefined}
+                      onChange={(value) => field.onChange(value ? Number(value) : undefined)}
+                      maxSize={2}
+                      uploadPath="/advertisements"
+                      uploadButtonText="上传图片"
+                      previewSize="medium"
+                      placeholder="选择广告图片"
+                    />
+                  </FormControl>
+                  <FormMessage />
+                </FormItem>
+              )}
+            />
+
+            <div className="grid grid-cols-2 gap-4">
+              <FormField
+                control={form.control}
+                name="positionId"
+                render={({ field }) => (
+                  <FormItem>
+                    <FormLabel className="flex items-center">
+                      广告位ID
+                      <span className="text-red-500 ml-1">*</span>
+                    </FormLabel>
+                    <FormControl>
+                      <Input
+                        type="number"
+                        placeholder="请输入广告位ID"
+                        {...field}
+                        onChange={(e) => field.onChange(Number(e.target.value))}
+                      />
+                    </FormControl>
+                    <FormMessage />
+                  </FormItem>
+                )}
+              />
+
+              <FormField
+                control={form.control}
+                name="sortOrder"
+                render={({ field }) => (
+                  <FormItem>
+                    <FormLabel>排序值</FormLabel>
+                    <FormControl>
+                      <Input
+                        type="number"
+                        placeholder="排序值"
+                        {...field}
+                        onChange={(e) => field.onChange(Number(e.target.value))}
+                      />
+                    </FormControl>
+                    <FormMessage />
+                  </FormItem>
+                )}
+              />
+            </div>
+
+            <FormField
+              control={form.control}
+              name="isEnabled"
+              render={({ field }) => (
+                <FormItem className="flex flex-row items-center justify-between rounded-lg border p-4">
+                  <div className="space-y-0.5">
+                    <FormLabel className="text-base">启用状态</FormLabel>
+                    <FormDescription>
+                      是否在前台显示该广告
+                    </FormDescription>
+                  </div>
+                  <FormControl>
+                    <Switch
+                      checked={field.value === 1}
+                      onCheckedChange={(checked) => field.onChange(checked ? 1 : 0)}
+                    />
+                  </FormControl>
+                </FormItem>
+              )}
+            />
+
+            <FormField
+              control={form.control}
+              name="description"
+              render={({ field }) => (
+                <FormItem>
+                  <FormLabel>广告描述</FormLabel>
+                  <FormControl>
+                    <Textarea
+                      placeholder="请输入广告描述"
+                      className="resize-none"
+                      {...field}
+                      value={field.value || ''}
+                    />
+                  </FormControl>
+                  <FormMessage />
+                </FormItem>
+              )}
+            />
+
+            <DialogFooter>
+              <Button type="button" variant="outline" onClick={() => onOpenChange(false)}>
+                取消
+              </Button>
+              <Button type="submit" disabled={updateMutation.isPending}>
+                更新
+              </Button>
+            </DialogFooter>
+          </form>
+        </Form>
+      </DialogContent>
+    </Dialog>
+  );
+};
+
+export default EditAdvertisementForm;

+ 29 - 253
src/client/admin-shadcn/pages/Advertisements.tsx

@@ -1,30 +1,22 @@
-import React, { useState, useEffect } from 'react';
-import { useForm } from 'react-hook-form';
-import { zodResolver } from '@hookform/resolvers/zod';
+import React, { useState } from 'react';
 import { Plus, Edit, Trash2 } from 'lucide-react';
 import { toast } from 'sonner';
 
 import { Button } from '@/client/components/ui/button';
 import { Input } from '@/client/components/ui/input';
 import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/client/components/ui/table';
-import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from '@/client/components/ui/dialog';
-import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from '@/client/components/ui/form';
-import { Textarea } from '@/client/components/ui/textarea';
-import { Switch } from '@/client/components/ui/switch';
 import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/client/components/ui/card';
 import { Badge } from '@/client/components/ui/badge';
-import AvatarSelector from '@/client/admin-shadcn/components/AvatarSelector';
 
 import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
 import { advertisementClient } from '@/client/api';
-import type { InferResponseType, InferRequestType } from 'hono/client';
-import { CreateAdvertisementDto, UpdateAdvertisementDto } from '@/server/modules/advertisements/advertisement.schema';
+import type { InferResponseType } from 'hono/client';
+import CreateAdvertisementForm from '@/client/admin-shadcn/components/CreateAdvertisementForm';
+import EditAdvertisementForm from '@/client/admin-shadcn/components/EditAdvertisementForm';
 
 // 类型定义
 type AdvertisementResponse = InferResponseType<typeof advertisementClient.$get, 200>;
 type AdvertisementItem = AdvertisementResponse['data'][0];
-type CreateRequest = InferRequestType<typeof advertisementClient.$post>['json'];
-type UpdateRequest = InferRequestType<typeof advertisementClient[':id']['$put']>['json'];
 
 const Advertisements: React.FC = () => {
   const queryClient = useQueryClient();
@@ -49,42 +41,6 @@ const Advertisements: React.FC = () => {
     }
   });
 
-  // 创建广告
-  const createMutation = useMutation({
-    mutationFn: async (data: CreateRequest) => {
-      const response = await advertisementClient.$post({ json: data });
-      if (response.status !== 200) throw new Error('创建广告失败');
-      return response.json();
-    },
-    onSuccess: () => {
-      queryClient.invalidateQueries({ queryKey: ['advertisements'] });
-      toast.success('广告创建成功');
-      setIsModalOpen(false);
-    },
-    onError: (error) => {
-      toast.error(`创建失败:${error.message}`);
-    }
-  });
-
-  // 更新广告
-  const updateMutation = useMutation({
-    mutationFn: async ({ id, data }: { id: number; data: UpdateRequest }) => {
-      const response = await advertisementClient[':id']['$put']({
-        param: { id: id.toString() },
-        json: data
-      });
-      if (response.status !== 200) throw new Error('更新广告失败');
-      return response.json();
-    },
-    onSuccess: () => {
-      queryClient.invalidateQueries({ queryKey: ['advertisements'] });
-      toast.success('广告更新成功');
-      setIsModalOpen(false);
-    },
-    onError: (error) => {
-      toast.error(`更新失败:${error.message}`);
-    }
-  });
 
   // 删除广告
   const deleteMutation = useMutation({
@@ -92,7 +48,7 @@ const Advertisements: React.FC = () => {
       const response = await advertisementClient[':id']['$delete']({
         param: { id: id.toString() }
       });
-      if (response.status !== 200) throw new Error('删除广告失败');
+      if (response.status !== 204) throw new Error('删除广告失败');
       return response.json();
     },
     onSuccess: () => {
@@ -104,32 +60,10 @@ const Advertisements: React.FC = () => {
     }
   });
 
-  // 表单实例
-  const createForm = useForm<CreateRequest>({
-    resolver: zodResolver(CreateAdvertisementDto),
-    defaultValues: {
-      title: '',
-      linkUrl: '',
-      imageFileId: undefined,
-      positionId: 1,
-      sortOrder: 0,
-      isEnabled: 1,
-      description: '',
-      startTime: undefined,
-      endTime: undefined
-    }
-  });
-
-  const updateForm = useForm<UpdateRequest>({
-    resolver: zodResolver(UpdateAdvertisementDto),
-    defaultValues: {}
-  });
-
   // 打开创建表单
   const handleCreate = () => {
     setEditingData(null);
     setIsCreateForm(true);
-    createForm.reset();
     setIsModalOpen(true);
   };
 
@@ -137,27 +71,19 @@ const Advertisements: React.FC = () => {
   const handleEdit = (data: AdvertisementItem) => {
     setEditingData(data);
     setIsCreateForm(false);
-    updateForm.reset({
-      title: data.title,
-      linkUrl: data.linkUrl,
-      imageFileId: data.imageFileId || undefined,
-      positionId: data.positionId,
-      sortOrder: data.sortOrder,
-      isEnabled: data.isEnabled,
-      description: data.description || undefined,
-      startTime: data.startTime || undefined,
-      endTime: data.endTime || undefined
-    });
     setIsModalOpen(true);
   };
 
-  // 处理表单提交
-  const handleSubmit = (data: CreateRequest | UpdateRequest) => {
-    if (isCreateForm) {
-      createMutation.mutate(data as CreateRequest);
-    } else if (editingData) {
-      updateMutation.mutate({ id: editingData.id, data: data as UpdateRequest });
-    }
+  // 处理创建成功
+  const handleCreateSuccess = () => {
+    setIsModalOpen(false);
+    queryClient.invalidateQueries({ queryKey: ['advertisements'] });
+  };
+
+  // 处理更新成功
+  const handleUpdateSuccess = () => {
+    setIsModalOpen(false);
+    queryClient.invalidateQueries({ queryKey: ['advertisements'] });
   };
 
   // 处理删除
@@ -275,170 +201,20 @@ const Advertisements: React.FC = () => {
       </Card>
 
       {/* 创建/编辑对话框 */}
-      <Dialog open={isModalOpen} onOpenChange={setIsModalOpen}>
-        <DialogContent className="sm:max-w-[600px] max-h-[90vh] overflow-y-auto">
-          <DialogHeader>
-            <DialogTitle>{isCreateForm ? '创建广告' : '编辑广告'}</DialogTitle>
-            <DialogDescription>
-              {isCreateForm ? '创建新的广告内容' : '编辑现有广告信息'}
-            </DialogDescription>
-          </DialogHeader>
-          
-          <Form {...(isCreateForm ? createForm : updateForm)}>
-            <form onSubmit={(isCreateForm ? createForm : updateForm).handleSubmit(handleSubmit)} className="space-y-4">
-              <FormField
-                control={(isCreateForm ? createForm : updateForm).control}
-                name="title"
-                render={({ field }) => (
-                  <FormItem>
-                    <FormLabel className="flex items-center">
-                      广告标题
-                      <span className="text-red-500 ml-1">*</span>
-                    </FormLabel>
-                    <FormControl>
-                      <Input placeholder="请输入广告标题" {...field} />
-                    </FormControl>
-                    <FormMessage />
-                  </FormItem>
-                )}
-              />
-
-              <FormField
-                control={(isCreateForm ? createForm : updateForm).control}
-                name="linkUrl"
-                render={({ field }) => (
-                  <FormItem>
-                    <FormLabel className="flex items-center">
-                      链接地址
-                      <span className="text-red-500 ml-1">*</span>
-                    </FormLabel>
-                    <FormControl>
-                      <Input placeholder="请输入链接地址" {...field} />
-                    </FormControl>
-                    <FormMessage />
-                  </FormItem>
-                )}
-              />
-
-              <FormField
-                control={(isCreateForm ? createForm : updateForm).control}
-                name="imageFileId"
-                render={({ field }) => (
-                  <FormItem>
-                    <FormLabel>
-                      图片文件
-                    </FormLabel>
-                    <FormControl>
-                      <AvatarSelector
-                        value={field.value || undefined}
-                        onChange={(value) => field.onChange(value ? Number(value) : undefined)}
-                        maxSize={2}
-                        uploadPath="/advertisements"
-                        uploadButtonText="上传图片"
-                        previewSize="medium"
-                        placeholder="选择广告图片"
-                      />
-                    </FormControl>
-                    <FormMessage />
-                  </FormItem>
-                )}
-              />
-
-              <div className="grid grid-cols-2 gap-4">
-                <FormField
-                  control={(isCreateForm ? createForm : updateForm).control}
-                  name="positionId"
-                  render={({ field }) => (
-                    <FormItem>
-                      <FormLabel className="flex items-center">
-                        广告位ID
-                        <span className="text-red-500 ml-1">*</span>
-                      </FormLabel>
-                      <FormControl>
-                        <Input
-                          type="number"
-                          placeholder="请输入广告位ID"
-                          {...field}
-                          onChange={(e) => field.onChange(Number(e.target.value))}
-                        />
-                      </FormControl>
-                      <FormMessage />
-                    </FormItem>
-                  )}
-                />
-
-                <FormField
-                  control={(isCreateForm ? createForm : updateForm).control}
-                  name="sortOrder"
-                  render={({ field }) => (
-                    <FormItem>
-                      <FormLabel>排序值</FormLabel>
-                      <FormControl>
-                        <Input
-                          type="number"
-                          placeholder="排序值"
-                          {...field}
-                          onChange={(e) => field.onChange(Number(e.target.value))}
-                        />
-                      </FormControl>
-                      <FormMessage />
-                    </FormItem>
-                  )}
-                />
-              </div>
-
-              <FormField
-                control={(isCreateForm ? createForm : updateForm).control}
-                name="isEnabled"
-                render={({ field }) => (
-                  <FormItem className="flex flex-row items-center justify-between rounded-lg border p-4">
-                    <div className="space-y-0.5">
-                      <FormLabel className="text-base">启用状态</FormLabel>
-                      <FormDescription>
-                        是否在前台显示该广告
-                      </FormDescription>
-                    </div>
-                    <FormControl>
-                      <Switch
-                        checked={field.value === 1}
-                        onCheckedChange={(checked) => field.onChange(checked ? 1 : 0)}
-                      />
-                    </FormControl>
-                  </FormItem>
-                )}
-              />
-
-              <FormField
-                control={(isCreateForm ? createForm : updateForm).control}
-                name="description"
-                render={({ field }) => (
-                  <FormItem>
-                    <FormLabel>广告描述</FormLabel>
-                    <FormControl>
-                      <Textarea
-                        placeholder="请输入广告描述"
-                        className="resize-none"
-                        {...field}
-                        value={field.value || ''}
-                      />
-                    </FormControl>
-                    <FormMessage />
-                  </FormItem>
-                )}
-              />
-
-              <DialogFooter>
-                <Button type="button" variant="outline" onClick={() => setIsModalOpen(false)}>
-                  取消
-                </Button>
-                <Button type="submit" disabled={createMutation.isPending || updateMutation.isPending}>
-                  {isCreateForm ? '创建' : '更新'}
-                </Button>
-              </DialogFooter>
-            </form>
-          </Form>
-        </DialogContent>
-      </Dialog>
+      {isCreateForm ? (
+        <CreateAdvertisementForm
+          open={isModalOpen}
+          onOpenChange={setIsModalOpen}
+          onSuccess={handleCreateSuccess}
+        />
+      ) : (
+        <EditAdvertisementForm
+          open={isModalOpen}
+          onOpenChange={setIsModalOpen}
+          advertisement={editingData}
+          onSuccess={handleUpdateSuccess}
+        />
+      )}
     </div>
   );
 };