|
|
@@ -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>
|