104 lines
2.9 KiB
TypeScript
104 lines
2.9 KiB
TypeScript
|
|
'use client'
|
||
|
|
import {createContext, useContext} from 'react'
|
||
|
|
import {useForm, UseFormReturn} from 'react-hook-form'
|
||
|
|
import Center from '@/components/composites/_client/center'
|
||
|
|
import Right from '@/components/composites/_client/right'
|
||
|
|
import Left from '@/components/composites/_client/left'
|
||
|
|
import {Form} from '@/components/ui/form'
|
||
|
|
import * as z from 'zod'
|
||
|
|
import {zodResolver} from '@hookform/resolvers/zod'
|
||
|
|
import {createResourceByBalance} from '@/actions/resource'
|
||
|
|
import {toast} from 'sonner'
|
||
|
|
import {useRouter} from 'next/navigation'
|
||
|
|
import {AuthContext} from '@/components/providers/AuthProvider'
|
||
|
|
|
||
|
|
// 定义表单验证架构
|
||
|
|
const schema = z.object({
|
||
|
|
type: z.enum(['1', '2']).default('2'),
|
||
|
|
live: z.enum(['3', '5', '10', '20', '30']),
|
||
|
|
quota: z.number().min(10000, '购买数量不能少于10000个'),
|
||
|
|
expire: z.enum(['7', '15', '30', '90', '180', '365']),
|
||
|
|
daily_limit: z.number().min(2000, '每日限额不能少于2000个'),
|
||
|
|
pay_type: z.enum(['wechat', 'alipay', 'balance']),
|
||
|
|
})
|
||
|
|
|
||
|
|
// 从架构中推断类型
|
||
|
|
export type Schema = z.infer<typeof schema>
|
||
|
|
|
||
|
|
type PurchaseFormContextType = {
|
||
|
|
form: UseFormReturn<Schema>
|
||
|
|
}
|
||
|
|
|
||
|
|
export const PurchaseFormContext = createContext<PurchaseFormContextType | undefined>(undefined)
|
||
|
|
|
||
|
|
export type PurchaseFormProps = {}
|
||
|
|
|
||
|
|
export default function PurchaseForm(props: PurchaseFormProps) {
|
||
|
|
console.log('PurchaseForm render')
|
||
|
|
const authCtx = useContext(AuthContext)
|
||
|
|
|
||
|
|
const form = useForm<Schema>({
|
||
|
|
resolver: zodResolver(schema),
|
||
|
|
defaultValues: {
|
||
|
|
type: '2', // 默认为包量套餐
|
||
|
|
live: '3', // 分钟
|
||
|
|
quota: 10_000, // >= 10000
|
||
|
|
expire: '30', // 天
|
||
|
|
daily_limit: 2_000, // >= 2000
|
||
|
|
pay_type: 'balance', // 余额支付
|
||
|
|
},
|
||
|
|
})
|
||
|
|
|
||
|
|
const router = useRouter()
|
||
|
|
|
||
|
|
const toExtract = () => {
|
||
|
|
router.push('/admin/extract')
|
||
|
|
}
|
||
|
|
|
||
|
|
const onSubmit = async (value: Schema) => {
|
||
|
|
try {
|
||
|
|
const resp = await createResourceByBalance({
|
||
|
|
type: Number(value.type),
|
||
|
|
live: Number(value.live) * 60,
|
||
|
|
quota: Number(value.quota),
|
||
|
|
expire: Number(value.expire) * 24 * 3600,
|
||
|
|
daily_limit: Number(value.daily_limit),
|
||
|
|
})
|
||
|
|
|
||
|
|
if (!resp.success) {
|
||
|
|
throw new Error(resp.message)
|
||
|
|
}
|
||
|
|
|
||
|
|
toast.success('购买成功', {
|
||
|
|
duration: 10 * 1000,
|
||
|
|
closeButton: true,
|
||
|
|
action: {
|
||
|
|
label: `去提取`,
|
||
|
|
onClick: toExtract,
|
||
|
|
},
|
||
|
|
})
|
||
|
|
|
||
|
|
await authCtx.refreshProfile()
|
||
|
|
}
|
||
|
|
catch (e) {
|
||
|
|
console.log(e)
|
||
|
|
toast.error('购买失败', {
|
||
|
|
description: (e as Error).message,
|
||
|
|
})
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return (
|
||
|
|
<section role={`tabpanel`} className={`bg-white rounded-lg`}>
|
||
|
|
<Form form={form} onSubmit={onSubmit} className={`flex flex-row`}>
|
||
|
|
<PurchaseFormContext.Provider value={{form}}>
|
||
|
|
<Left/>
|
||
|
|
<Center/>
|
||
|
|
<Right/>
|
||
|
|
</PurchaseFormContext.Provider>
|
||
|
|
</Form>
|
||
|
|
</section>
|
||
|
|
)
|
||
|
|
}
|
||
|
|
|