修复表单响应性问题 & 更新套餐管理接口字段
This commit is contained in:
@@ -1,5 +1,9 @@
|
||||
## TODO
|
||||
|
||||
### 禁止直接依赖 form
|
||||
|
||||
`\[(.*,)?form(,.*)?\]`
|
||||
|
||||
业务场景页面优化实现
|
||||
|
||||
业务定制页面优化实现
|
||||
|
||||
@@ -1,8 +1,23 @@
|
||||
'use server'
|
||||
|
||||
import {callByUser} from '@/actions/base'
|
||||
import {callByDevice, callByUser} from '@/actions/base'
|
||||
import {Resource} from '@/lib/models'
|
||||
import {ExtraReq, PageRecord} from '@/lib/api'
|
||||
import {PageRecord} from '@/lib/api'
|
||||
|
||||
export type CreateResourceReq = {
|
||||
type: number
|
||||
short?: {
|
||||
live: number
|
||||
mode: number
|
||||
quota: number
|
||||
expire?: number
|
||||
}
|
||||
long?: {
|
||||
live: number
|
||||
mode: number
|
||||
quota: number
|
||||
expire?: number
|
||||
}
|
||||
}
|
||||
|
||||
export async function listResourceShort(props: {
|
||||
page: number
|
||||
@@ -34,45 +49,14 @@ export async function allResource() {
|
||||
return callByUser<Resource<1 | 2>[]>('/api/resource/all')
|
||||
}
|
||||
|
||||
export async function createResource(props: {
|
||||
type: number
|
||||
short?: {
|
||||
live: number
|
||||
mode: number
|
||||
quota: number
|
||||
expire_at: number
|
||||
daily_limit: number
|
||||
}
|
||||
long?: {
|
||||
live: number
|
||||
mode: number
|
||||
quota: number
|
||||
expire_at: number
|
||||
daily_limit: number
|
||||
}
|
||||
}) {
|
||||
export async function createResource(props: CreateResourceReq) {
|
||||
return await callByUser('/api/resource/create', props)
|
||||
}
|
||||
|
||||
export async function prepareResource(props: {
|
||||
type: number
|
||||
short?: {
|
||||
live: number
|
||||
mode: number
|
||||
quota: number
|
||||
expire_at: number
|
||||
daily_limit: number
|
||||
}
|
||||
long?: {
|
||||
live: number
|
||||
mode: number
|
||||
quota: number
|
||||
expire_at: number
|
||||
daily_limit: number
|
||||
}
|
||||
payment_method: number
|
||||
payment_platform: number
|
||||
}) {
|
||||
} & CreateResourceReq) {
|
||||
return await callByUser<{
|
||||
trade_no: string
|
||||
pay_url: string
|
||||
@@ -101,3 +85,7 @@ export async function payClose(props: {
|
||||
}) {
|
||||
return callByUser('/api/trade/cancel', props)
|
||||
}
|
||||
|
||||
export async function getPrice(props: CreateResourceReq) {
|
||||
return callByDevice<{price: string}>('/api/resource/price', props)
|
||||
}
|
||||
|
||||
@@ -207,7 +207,7 @@ function Tab(props: {
|
||||
}
|
||||
|
||||
function SendMsgByUsername() {
|
||||
const form = useFormContext<LoginSchema>()
|
||||
const phone = form.watch('username')
|
||||
const {control} = useFormContext<LoginSchema>()
|
||||
const phone = useWatch({control, name: 'username'})
|
||||
return <SendMsg phone={phone}/>
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import {Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle, DialogTr
|
||||
import {Button} from '@/components/ui/button'
|
||||
import {Form, FormField} from '@/components/ui/form'
|
||||
import {Input} from '@/components/ui/input'
|
||||
import {useForm, useFormContext} from 'react-hook-form'
|
||||
import {useForm, useFormContext, useWatch} from 'react-hook-form'
|
||||
import {zodResolver} from '@hookform/resolvers/zod'
|
||||
import * as z from 'zod'
|
||||
import {toast} from 'sonner'
|
||||
@@ -154,7 +154,7 @@ export function ChangePasswordDialog({
|
||||
}
|
||||
|
||||
function SendMsgByPhone() {
|
||||
const form = useFormContext<Schema>()
|
||||
const phone = form.watch('phone')
|
||||
const {control} = useFormContext<Schema>()
|
||||
const phone = useWatch({control, name: 'phone'})
|
||||
return <SendMsg phone={phone}/>
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import {RadioGroup, RadioGroupItem} from '@/components/ui/radio-group'
|
||||
import {Input} from '@/components/ui/input'
|
||||
import {Select, SelectContent, SelectItem, SelectSeparator, SelectTrigger, SelectValue} from '@/components/ui/select'
|
||||
import {Button} from '@/components/ui/button'
|
||||
import {useForm, useFormContext} from 'react-hook-form'
|
||||
import {useForm, useFormContext, useWatch} from 'react-hook-form'
|
||||
import {Alert, AlertTitle} from '@/components/ui/alert'
|
||||
import {ArrowRight, Box, CircleAlert, CopyIcon, ExternalLinkIcon, LinkIcon, Loader, Plus, Timer} from 'lucide-react'
|
||||
import {memo, ReactNode, useEffect, useRef, useState} from 'react'
|
||||
@@ -487,10 +487,10 @@ function SelectResource() {
|
||||
}
|
||||
|
||||
function SelectRegion() {
|
||||
const form = useFormContext<Schema>()
|
||||
const regionType = form.watch('regionType')
|
||||
const prov = form.watch('prov')
|
||||
const city = form.watch('city')
|
||||
const {control, setValue} = useFormContext<Schema>()
|
||||
const regionType = useWatch({control, name: 'regionType'})
|
||||
const prov = useWatch({control, name: 'prov'})
|
||||
const city = useWatch({control, name: 'city'})
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-4 md:max-w-[calc(160px*2+1rem)]">
|
||||
@@ -500,8 +500,8 @@ function SelectRegion() {
|
||||
onValueChange={(e) => {
|
||||
field.onChange(e)
|
||||
if (e === 'unlimited') {
|
||||
form.setValue('prov', '')
|
||||
form.setValue('city', '')
|
||||
setValue('prov', '')
|
||||
setValue('city', '')
|
||||
}
|
||||
}}
|
||||
defaultValue={field.value}
|
||||
@@ -525,8 +525,8 @@ function SelectRegion() {
|
||||
options={cities.options}
|
||||
value={[prov || '', city || '']}
|
||||
onChange={(value) => {
|
||||
form.setValue('prov', value[0])
|
||||
form.setValue('city', value[1])
|
||||
setValue('prov', value[0])
|
||||
setValue('city', value[1])
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
@@ -536,7 +536,7 @@ function SelectRegion() {
|
||||
|
||||
function ApplyLink() {
|
||||
const form = useFormContext<Schema>()
|
||||
const values = form.watch()
|
||||
useWatch()
|
||||
|
||||
// let type: 'open' | 'copy' = 'open'
|
||||
const type = useRef<'open' | 'copy'>('open')
|
||||
@@ -613,7 +613,7 @@ function ApplyLink() {
|
||||
|
||||
{/* 展示链接地址 */}
|
||||
<div className="bg-secondary p-4 rounded-md break-all">
|
||||
{link(values)}
|
||||
{link(form.getValues())}
|
||||
</div>
|
||||
|
||||
{/* 操作 */}
|
||||
|
||||
@@ -8,12 +8,12 @@ import FormOption from '@/components/composites/purchase/option'
|
||||
import Image from 'next/image'
|
||||
import check from '../_assets/check.svg'
|
||||
import {Schema} from '@/components/composites/purchase/long/form'
|
||||
import {useFormContext} from 'react-hook-form'
|
||||
import {useFormContext, useWatch} from 'react-hook-form'
|
||||
import {Card} from '@/components/ui/card'
|
||||
|
||||
export default function Center() {
|
||||
const form = useFormContext<Schema>()
|
||||
const type = form.watch('type')
|
||||
const type = useWatch({name: 'type'})
|
||||
|
||||
return (
|
||||
<Card className="flex-auto p-6 flex flex-col gap-6 relative">
|
||||
|
||||
@@ -14,20 +14,18 @@ import Pay from '@/components/composites/purchase/pay'
|
||||
import {buttonVariants} from '@/components/ui/button'
|
||||
import Link from 'next/link'
|
||||
import {merge} from '@/lib/utils'
|
||||
import {useFormContext} from 'react-hook-form'
|
||||
import {useFormContext, useWatch} from 'react-hook-form'
|
||||
import {Schema} from '@/components/composites/purchase/long/form'
|
||||
import {Card} from '@/components/ui/card'
|
||||
|
||||
export default function Right() {
|
||||
const profile = useProfileStore(store => store.profile)
|
||||
const form = useFormContext<Schema>()
|
||||
|
||||
const method = form.watch('pay_type')
|
||||
const mode = form.watch('type')
|
||||
const live = form.watch('live')
|
||||
const quota = form.watch('quota')
|
||||
const expire = form.watch('expire')
|
||||
const dailyLimit = form.watch('daily_limit')
|
||||
const {control} = useFormContext<Schema>()
|
||||
const method = useWatch({control, name: 'pay_type'})
|
||||
const mode = useWatch({control, name: 'type'})
|
||||
const live = useWatch({control, name: 'live'})
|
||||
const quota = useWatch({control, name: 'quota'})
|
||||
const expire = useWatch({control, name: 'expire'})
|
||||
const dailyLimit = useWatch({control, name: 'daily_limit'})
|
||||
|
||||
const price = useMemo(() => {
|
||||
const base = {
|
||||
@@ -173,9 +171,8 @@ function BalanceOrLogin(props: {
|
||||
long: {
|
||||
mode: Number(props.mode),
|
||||
live: Number(props.live),
|
||||
daily_limit: props.dailyLimit,
|
||||
expire_at: Number(props.expire),
|
||||
quota: props.quota,
|
||||
expire: Number(props.expire),
|
||||
quota: props.mode === '1' ? props.dailyLimit : props.quota,
|
||||
},
|
||||
}}/>
|
||||
</>
|
||||
|
||||
@@ -8,7 +8,7 @@ import {useProfileStore} from '@/components/stores/profile'
|
||||
import {Alert, AlertTitle} from '@/components/ui/alert'
|
||||
import {toast} from 'sonner'
|
||||
import {useRouter} from 'next/navigation'
|
||||
import {completeResource, createResource, prepareResource} from '@/actions/resource'
|
||||
import {completeResource, createResource, CreateResourceReq, prepareResource} from '@/actions/resource'
|
||||
import {
|
||||
TradeMethod,
|
||||
TradeMethodDecoration,
|
||||
@@ -19,7 +19,7 @@ import {usePlatformType} from '@/lib/hooks'
|
||||
|
||||
export type PayProps = {
|
||||
amount: string
|
||||
resource: Parameters<typeof createResource>[0]
|
||||
resource: CreateResourceReq
|
||||
} & ({
|
||||
method: 'alipay' | 'wechat'
|
||||
} | {
|
||||
|
||||
@@ -7,13 +7,13 @@ import {Minus, Plus} from 'lucide-react'
|
||||
import FormOption from '@/components/composites/purchase/option'
|
||||
import Image from 'next/image'
|
||||
import check from '../_assets/check.svg'
|
||||
import {useFormContext} from 'react-hook-form'
|
||||
import {useFormContext, useWatch} from 'react-hook-form'
|
||||
import {Schema} from '@/components/composites/purchase/short/form'
|
||||
import {Card} from '@/components/ui/card'
|
||||
|
||||
export default function Center() {
|
||||
const form = useFormContext<Schema>()
|
||||
const type = form.watch('type')
|
||||
const type = useWatch({name: 'type'})
|
||||
|
||||
return (
|
||||
<Card className="flex-auto p-6 flex flex-col gap-6 relative">
|
||||
@@ -82,8 +82,8 @@ export default function Center() {
|
||||
theme="outline"
|
||||
type="button"
|
||||
className="h-10 w-10 border border-gray-200 rounded-sm flex items-center justify-center text-lg"
|
||||
onClick={() => form.setValue('quota', Math.max(10_000, Number(field.value) - 5_000))}
|
||||
disabled={Number(field.value) === 10_000}>
|
||||
onClick={() => form.setValue('quota', Math.max(10000, Number(field.value) - 5000))}
|
||||
disabled={Number(field.value) === 10000}>
|
||||
<Minus/>
|
||||
</Button>
|
||||
<Input
|
||||
@@ -91,14 +91,13 @@ export default function Center() {
|
||||
id={id}
|
||||
type="number"
|
||||
className="w-40 h-10 border border-gray-200 rounded-sm text-center"
|
||||
min={10_000}
|
||||
step={5_000}
|
||||
/>
|
||||
min={10000}
|
||||
step={5000}/>
|
||||
<Button
|
||||
theme="outline"
|
||||
type="button"
|
||||
className="h-10 w-10 border border-gray-200 rounded-sm flex items-center justify-center text-lg"
|
||||
onClick={() => form.setValue('quota', Number(field.value) + 5_000)}>
|
||||
onClick={() => form.setValue('quota', Number(field.value) + 5000)}>
|
||||
<Plus/>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -14,18 +14,17 @@ import {buttonVariants} from '@/components/ui/button'
|
||||
import Link from 'next/link'
|
||||
import {merge} from '@/lib/utils'
|
||||
import Pay from '@/components/composites/purchase/pay'
|
||||
import {useFormContext} from 'react-hook-form'
|
||||
import {useFormContext, useWatch} from 'react-hook-form'
|
||||
import {Card} from '@/components/ui/card'
|
||||
|
||||
export default function Right() {
|
||||
const form = useFormContext<Schema>()
|
||||
|
||||
const method = form.watch('pay_type')
|
||||
const live = form.watch('live')
|
||||
const mode = form.watch('type')
|
||||
const dailyLimit = form.watch('daily_limit')
|
||||
const expire = form.watch('expire')
|
||||
const quota = form.watch('quota')
|
||||
const {control} = useFormContext<Schema>()
|
||||
const method = useWatch({control, name: 'pay_type'})
|
||||
const live = useWatch({control, name: 'live'})
|
||||
const mode = useWatch({control, name: 'type'})
|
||||
const dailyLimit = useWatch({control, name: 'daily_limit'})
|
||||
const expire = useWatch({control, name: 'expire'})
|
||||
const quota = useWatch({control, name: 'quota'})
|
||||
|
||||
const price = useMemo(() => {
|
||||
const base = live === '180' ? 150 : Number(live)
|
||||
@@ -165,9 +164,8 @@ function BalanceOrLogin(props: {
|
||||
short: {
|
||||
mode: Number(props.mode),
|
||||
live: Number(props.live),
|
||||
quota: props.quota,
|
||||
expire_at: Number(props.expire),
|
||||
daily_limit: props.dailyLimit,
|
||||
expire: Number(props.expire),
|
||||
quota: props.mode === '1' ? props.dailyLimit : props.quota,
|
||||
},
|
||||
}}/>
|
||||
</>
|
||||
|
||||
@@ -17,20 +17,13 @@ import React, {ComponentProps, createContext, ReactNode, useContext, useId} from
|
||||
|
||||
type FormProps<T extends FieldValues> = {
|
||||
form: UseFormReturn<T>
|
||||
onSubmit?: SubmitHandler<T>
|
||||
onError?: SubmitErrorHandler<T>
|
||||
handler?: (e?: React.BaseSyntheticEvent) => Promise<void>
|
||||
} & Omit<ComponentProps<'form'>, 'onSubmit' | 'onError'>
|
||||
|
||||
function Form<T extends FieldValues>(rawProps: FormProps<T>) {
|
||||
const {children, onSubmit, onError, handler, ...props} = rawProps
|
||||
const {children, handler, ...props} = rawProps
|
||||
const form = props.form
|
||||
|
||||
const handle = handler || form.handleSubmit(
|
||||
onSubmit || ((_) => {}),
|
||||
onError,
|
||||
)
|
||||
|
||||
return (
|
||||
<FormProvider {...form}>
|
||||
<form
|
||||
@@ -38,7 +31,7 @@ function Form<T extends FieldValues>(rawProps: FormProps<T>) {
|
||||
onSubmit={async (event) => {
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
await handle(event)
|
||||
await handler?.(event)
|
||||
}}>
|
||||
{children}
|
||||
</form>
|
||||
|
||||
Reference in New Issue
Block a user