浏览代码

♻️ refactor(wechat-coupon): 重构代金券批次管理表单

- 分离创建和编辑表单为独立渲染组件,优化代码结构
- 移除未使用的zod导入和FormDescription组件
- 删除未使用的wechatPayConfigClient和configData相关代码
- 为创建表单添加默认重置值,提升用户体验
- 编辑表单新增可用数量字段和状态选择器
- 添加表单提交状态加载提示,优化用户体验
- 优化表单布局和字段标签,提升可读性
yourname 3 月之前
父节点
当前提交
af5ae6b661
共有 1 个文件被更改,包括 300 次插入159 次删除
  1. 300 159
      src/client/admin-shadcn/pages/WechatCouponStocks.tsx

+ 300 - 159
src/client/admin-shadcn/pages/WechatCouponStocks.tsx

@@ -16,13 +16,11 @@ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/cli
 import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/client/components/ui/table'
 import { Badge } from '@/client/components/ui/badge'
 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 { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@/client/components/ui/form'
 import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/client/components/ui/select'
 import { Textarea } from '@/client/components/ui/textarea'
 import { DataTablePagination } from '@/client/admin-shadcn/components/DataTablePagination'
-import { wechatPayConfigClient } from '@/client/api'
 import { WechatPayConfigSelector } from '@/client/admin-shadcn/components/WechatPayConfigSelector'
-import { z } from 'zod'
 
 type CreateRequest = InferRequestType<typeof wechatCouponStockClient.$post>['json']
 type UpdateRequest = InferRequestType<typeof wechatCouponStockClient[':id']['$put']>['json']
@@ -39,16 +37,6 @@ export const WechatCouponStocksPage = () => {
   const [editingData, setEditingData] = useState<StockResponse | null>(null)
   const [isCreateForm, setIsCreateForm] = useState(true)
 
-  // 获取微信支付配置列表
-  const { data: configData } = useQuery({
-    queryKey: ['wechat-pay-configs'],
-    queryFn: async () => {
-      const res = await wechatPayConfigClient.$get()
-      if (res.status !== 200) throw new Error('获取配置失败')
-      return await res.json()
-    },
-  })
-
   // 获取代金券批次列表
   const { data, isLoading, refetch } = useQuery({
     queryKey: ['wechat-coupon-stocks', searchParams],
@@ -66,7 +54,7 @@ export const WechatCouponStocksPage = () => {
     },
   })
 
-  // 表单实例
+  // 表单实例 - 创建/编辑分离模式
   const createForm = useForm<CreateRequest>({
     resolver: zodResolver(CreateWechatCouponStockDto),
     defaultValues: {
@@ -92,7 +80,18 @@ export const WechatCouponStocksPage = () => {
   const handleCreate = () => {
     setEditingData(null)
     setIsCreateForm(true)
-    createForm.reset()
+    createForm.reset({
+      stockName: '',
+      stockCreatorMchid: '',
+      couponType: 'NORMAL',
+      couponUseRule: {},
+      stockSendRule: {},
+      couponAmount: 100,
+      couponQuantity: 100,
+      startTime: new Date(),
+      endTime: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000),
+      configId: 0,
+    })
     setIsModalOpen(true)
   }
 
@@ -312,93 +311,221 @@ export const WechatCouponStocksPage = () => {
             </DialogDescription>
           </DialogHeader>
 
-          <Form {...(isCreateForm ? createForm : updateForm)}>
-            <form
-              onSubmit={(isCreateForm ? createForm : updateForm).handleSubmit(
-                isCreateForm ? handleCreateSubmit : handleUpdateSubmit
-              )}
-              className="space-y-4"
-            >
-              <FormField
-                control={(isCreateForm ? createForm : updateForm).control}
-                name="stockName"
-                render={({ field }) => (
-                  <FormItem>
-                    <FormLabel className="flex items-center">
-                      批次名称
-                      <span className="text-red-500 ml-1">*</span>
-                    </FormLabel>
-                    <FormControl>
-                      <Input placeholder="请输入批次名称" {...field} />
-                    </FormControl>
-                    <FormMessage />
-                  </FormItem>
-                )}
-              />
+          {isCreateForm ? (
+            // 创建表单(独立渲染)
+            <Form {...createForm}>
+              <form
+                onSubmit={createForm.handleSubmit(handleCreateSubmit)}
+                className="space-y-4"
+              >
+                <FormField
+                  control={createForm.control}
+                  name="stockName"
+                  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="stockCreatorMchid"
-                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={createForm.control}
+                  name="stockCreatorMchid"
+                  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={createForm.control}
+                  name="configId"
+                  render={({ field }) => (
+                    <WechatPayConfigSelector
+                      value={field.value}
+                      onChange={field.onChange}
+                      required
+                      label="支付配置"
+                      placeholder="请选择微信支付配置"
+                    />
+                  )}
+                />
+
+                <FormField
+                  control={createForm.control}
+                  name="couponType"
+                  render={({ field }) => (
+                    <FormItem>
+                      <FormLabel>代金券类型</FormLabel>
+                      <Select onValueChange={field.onChange} value={field.value}>
+                        <FormControl>
+                          <SelectTrigger>
+                            <SelectValue placeholder="请选择代金券类型" />
+                          </SelectTrigger>
+                        </FormControl>
+                        <SelectContent>
+                          <SelectItem value="NORMAL">满减券</SelectItem>
+                          <SelectItem value="CUT_TO">减至券</SelectItem>
+                        </SelectContent>
+                      </Select>
+                      <FormMessage />
+                    </FormItem>
+                  )}
+                />
 
-              <FormField
-                control={(isCreateForm ? createForm : updateForm).control}
-                name="configId"
-                render={({ field }) => (
-                  <WechatPayConfigSelector
-                    value={field.value}
-                    onChange={field.onChange}
-                    required
-                    label="支付配置"
-                    placeholder="请选择微信支付配置"
+                <div className="grid grid-cols-2 gap-4">
+                  <FormField
+                    control={createForm.control}
+                    name="couponAmount"
+                    render={({ field }) => (
+                      <FormItem>
+                        <FormLabel className="flex items-center">
+                          代金券面额(分)
+                          <span className="text-red-500 ml-1">*</span>
+                        </FormLabel>
+                        <FormControl>
+                          <Input
+                            type="number"
+                            placeholder="请输入面额"
+                            {...field}
+                            onChange={(e) => field.onChange(Number(e.target.value))}
+                          />
+                        </FormControl>
+                        <FormMessage />
+                      </FormItem>
+                    )}
                   />
-                )}
-              />
 
-              <FormField
-                control={(isCreateForm ? createForm : updateForm).control}
-                name="couponType"
-                render={({ field }) => (
-                  <FormItem>
-                    <FormLabel>代金券类型</FormLabel>
-                    <Select onValueChange={field.onChange} value={field.value}>
+                  <FormField
+                    control={createForm.control}
+                    name="couponQuantity"
+                    render={({ field }) => (
+                      <FormItem>
+                        <FormLabel className="flex items-center">
+                          代金券数量
+                          <span className="text-red-500 ml-1">*</span>
+                        </FormLabel>
+                        <FormControl>
+                          <Input
+                            type="number"
+                            placeholder="请输入数量"
+                            {...field}
+                            onChange={(e) => field.onChange(Number(e.target.value))}
+                          />
+                        </FormControl>
+                        <FormMessage />
+                      </FormItem>
+                    )}
+                  />
+                </div>
+
+                <FormField
+                  control={createForm.control}
+                  name="couponUseRule"
+                  render={({ field }) => (
+                    <FormItem>
+                      <FormLabel>代金券使用规则</FormLabel>
+                      <FormControl>
+                        <Textarea
+                          placeholder='{"coupon_minimum": 100}'
+                          rows={3}
+                          {...field}
+                          value={typeof field.value === 'string' ? field.value : JSON.stringify(field.value, null, 2)}
+                          onChange={(e) => {
+                            try {
+                              field.onChange(JSON.parse(e.target.value))
+                            } catch {
+                              field.onChange(e.target.value)
+                            }
+                          }}
+                        />
+                      </FormControl>
+                      <FormMessage />
+                    </FormItem>
+                  )}
+                />
+
+                <FormField
+                  control={createForm.control}
+                  name="stockSendRule"
+                  render={({ field }) => (
+                    <FormItem>
+                      <FormLabel>批次发放规则</FormLabel>
                       <FormControl>
-                        <SelectTrigger>
-                          <SelectValue placeholder="请选择代金券类型" />
-                        </SelectTrigger>
+                        <Textarea
+                          placeholder='{"max_coupons": 100}'
+                          rows={3}
+                          {...field}
+                          value={typeof field.value === 'string' ? field.value : JSON.stringify(field.value, null, 2)}
+                          onChange={(e) => {
+                            try {
+                              field.onChange(JSON.parse(e.target.value))
+                            } catch {
+                              field.onChange(e.target.value)
+                            }
+                          }}
+                        />
                       </FormControl>
-                      <SelectContent>
-                        <SelectItem value="NORMAL">满减券</SelectItem>
-                        <SelectItem value="CUT_TO">减至券</SelectItem>
-                      </SelectContent>
-                    </Select>
-                    <FormMessage />
-                  </FormItem>
-                )}
-              />
+                      <FormMessage />
+                    </FormItem>
+                  )}
+                />
 
-              <div className="grid grid-cols-2 gap-4">
+                <DialogFooter>
+                  <Button type="button" variant="outline" onClick={() => setIsModalOpen(false)}>
+                    取消
+                  </Button>
+                  <Button type="submit" disabled={createForm.formState.isSubmitting}>
+                    {createForm.formState.isSubmitting ? '创建中...' : '创建'}
+                  </Button>
+                </DialogFooter>
+              </form>
+            </Form>
+          ) : (
+            // 编辑表单(独立渲染)
+            <Form {...updateForm}>
+              <form
+                onSubmit={updateForm.handleSubmit(handleUpdateSubmit)}
+                className="space-y-4"
+              >
                 <FormField
-                  control={(isCreateForm ? createForm : updateForm).control}
-                  name="couponAmount"
+                  control={updateForm.control}
+                  name="stockName"
                   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={updateForm.control}
+                  name="couponAmount"
+                  render={({ field }) => (
+                    <FormItem>
+                      <FormLabel>代金券面额(分)</FormLabel>
                       <FormControl>
                         <Input
                           type="number"
@@ -413,14 +540,11 @@ export const WechatCouponStocksPage = () => {
                 />
 
                 <FormField
-                  control={(isCreateForm ? createForm : updateForm).control}
+                  control={updateForm.control}
                   name="couponQuantity"
                   render={({ field }) => (
                     <FormItem>
-                      <FormLabel className="flex items-center">
-                        代金券数量
-                        <span className="text-red-500 ml-1">*</span>
-                      </FormLabel>
+                      <FormLabel>代金券数量</FormLabel>
                       <FormControl>
                         <Input
                           type="number"
@@ -433,11 +557,28 @@ export const WechatCouponStocksPage = () => {
                     </FormItem>
                   )}
                 />
-              </div>
 
-              {!isCreateForm && (
                 <FormField
-                  control={(isCreateForm ? createForm : updateForm).control}
+                  control={updateForm.control}
+                  name="availableQuantity"
+                  render={({ field }) => (
+                    <FormItem>
+                      <FormLabel>可用数量</FormLabel>
+                      <FormControl>
+                        <Input
+                          type="number"
+                          placeholder="请输入可用数量"
+                          {...field}
+                          onChange={(e) => field.onChange(Number(e.target.value))}
+                        />
+                      </FormControl>
+                      <FormMessage />
+                    </FormItem>
+                  )}
+                />
+
+                <FormField
+                  control={updateForm.control}
                   name="status"
                   render={({ field }) => (
                     <FormItem>
@@ -461,70 +602,70 @@ export const WechatCouponStocksPage = () => {
                     </FormItem>
                   )}
                 />
-              )}
-
-              <FormField
-                control={(isCreateForm ? createForm : updateForm).control}
-                name="couponUseRule"
-                render={({ field }) => (
-                  <FormItem>
-                    <FormLabel>代金券使用规则</FormLabel>
-                    <FormControl>
-                      <Textarea
-                        placeholder='{"coupon_minimum": 100}'
-                        rows={3}
-                        {...field}
-                        value={typeof field.value === 'string' ? field.value : JSON.stringify(field.value, null, 2)}
-                        onChange={(e) => {
-                          try {
-                            field.onChange(JSON.parse(e.target.value))
-                          } catch {
-                            field.onChange(e.target.value)
-                          }
-                        }}
-                      />
-                    </FormControl>
-                    <FormMessage />
-                  </FormItem>
-                )}
-              />
 
-              <FormField
-                control={(isCreateForm ? createForm : updateForm).control}
-                name="stockSendRule"
-                render={({ field }) => (
-                  <FormItem>
-                    <FormLabel>批次发放规则</FormLabel>
-                    <FormControl>
-                      <Textarea
-                        placeholder='{"max_coupons": 100}'
-                        rows={3}
-                        {...field}
-                        value={typeof field.value === 'string' ? field.value : JSON.stringify(field.value, null, 2)}
-                        onChange={(e) => {
-                          try {
-                            field.onChange(JSON.parse(e.target.value))
-                          } catch {
-                            field.onChange(e.target.value)
-                          }
-                        }}
-                      />
-                    </FormControl>
-                    <FormMessage />
-                  </FormItem>
-                )}
-              />
+                <FormField
+                  control={updateForm.control}
+                  name="couponUseRule"
+                  render={({ field }) => (
+                    <FormItem>
+                      <FormLabel>代金券使用规则</FormLabel>
+                      <FormControl>
+                        <Textarea
+                          placeholder='{"coupon_minimum": 100}'
+                          rows={3}
+                          {...field}
+                          value={typeof field.value === 'string' ? field.value : JSON.stringify(field.value, null, 2)}
+                          onChange={(e) => {
+                            try {
+                              field.onChange(JSON.parse(e.target.value))
+                            } catch {
+                              field.onChange(e.target.value)
+                            }
+                          }}
+                        />
+                      </FormControl>
+                      <FormMessage />
+                    </FormItem>
+                  )}
+                />
 
-              <DialogFooter>
-                <Button type="button" variant="outline" onClick={() => setIsModalOpen(false)}>
-                  取消
-                </Button>
-                <Button type="submit">
-                  {isCreateForm ? '创建' : '更新'}
-                </Button>
-              </DialogFooter>
-            </form>
-          </Form>
+                <FormField
+                  control={updateForm.control}
+                  name="stockSendRule"
+                  render={({ field }) => (
+                    <FormItem>
+                      <FormLabel>批次发放规则</FormLabel>
+                      <FormControl>
+                        <Textarea
+                          placeholder='{"max_coupons": 100}'
+                          rows={3}
+                          {...field}
+                          value={typeof field.value === 'string' ? field.value : JSON.stringify(field.value, null, 2)}
+                          onChange={(e) => {
+                            try {
+                              field.onChange(JSON.parse(e.target.value))
+                            } catch {
+                              field.onChange(e.target.value)
+                            }
+                          }}
+                        />
+                      </FormControl>
+                      <FormMessage />
+                    </FormItem>
+                  )}
+                />
+
+                <DialogFooter>
+                  <Button type="button" variant="outline" onClick={() => setIsModalOpen(false)}>
+                    取消
+                  </Button>
+                  <Button type="submit" disabled={updateForm.formState.isSubmitting}>
+                    {updateForm.formState.isSubmitting ? '更新中...' : '更新'}
+                  </Button>
+                </DialogFooter>
+              </form>
+            </Form>
+          )}
         </DialogContent>
       </Dialog>
     </div>