From 1f9b6bb044add2f1b2f4c0a499d57b00608098e5 Mon Sep 17 00:00:00 2001 From: luorijun Date: Tue, 16 Dec 2025 17:10:30 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=A1=A8=E5=8D=95=E5=93=8D?= =?UTF-8?q?=E5=BA=94=E6=80=A7=E9=97=AE=E9=A2=98=20&=20=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E5=A5=97=E9=A4=90=E7=AE=A1=E7=90=86=E6=8E=A5=E5=8F=A3=E5=AD=97?= =?UTF-8?q?=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 ++ src/actions/resource.ts | 60 ++++++++----------- src/app/(auth)/login/login-card.tsx | 4 +- .../dialogs/change-password-dialog.tsx | 6 +- src/components/composites/extract/index.tsx | 22 +++---- .../composites/purchase/long/center.tsx | 4 +- .../composites/purchase/long/right.tsx | 23 ++++--- src/components/composites/purchase/pay.tsx | 4 +- .../composites/purchase/short/center.tsx | 15 +++-- .../composites/purchase/short/right.tsx | 22 ++++--- src/components/ui/form.tsx | 11 +--- 11 files changed, 77 insertions(+), 98 deletions(-) diff --git a/README.md b/README.md index c73ca36..f79249d 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,9 @@ ## TODO +### 禁止直接依赖 form + +`\[(.*,)?form(,.*)?\]` + 业务场景页面优化实现 业务定制页面优化实现 diff --git a/src/actions/resource.ts b/src/actions/resource.ts index 6b7c10e..5245223 100644 --- a/src/actions/resource.ts +++ b/src/actions/resource.ts @@ -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[]>('/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) +} diff --git a/src/app/(auth)/login/login-card.tsx b/src/app/(auth)/login/login-card.tsx index bd15a0a..c2b7d4d 100644 --- a/src/app/(auth)/login/login-card.tsx +++ b/src/app/(auth)/login/login-card.tsx @@ -207,7 +207,7 @@ function Tab(props: { } function SendMsgByUsername() { - const form = useFormContext() - const phone = form.watch('username') + const {control} = useFormContext() + const phone = useWatch({control, name: 'username'}) return } diff --git a/src/components/composites/dialogs/change-password-dialog.tsx b/src/components/composites/dialogs/change-password-dialog.tsx index 604ef84..f1cd92f 100644 --- a/src/components/composites/dialogs/change-password-dialog.tsx +++ b/src/components/composites/dialogs/change-password-dialog.tsx @@ -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() - const phone = form.watch('phone') + const {control} = useFormContext() + const phone = useWatch({control, name: 'phone'}) return } diff --git a/src/components/composites/extract/index.tsx b/src/components/composites/extract/index.tsx index b434868..3131637 100644 --- a/src/components/composites/extract/index.tsx +++ b/src/components/composites/extract/index.tsx @@ -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() - const regionType = form.watch('regionType') - const prov = form.watch('prov') - const city = form.watch('city') + const {control, setValue} = useFormContext() + const regionType = useWatch({control, name: 'regionType'}) + const prov = useWatch({control, name: 'prov'}) + const city = useWatch({control, name: 'city'}) return (
@@ -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() - const values = form.watch() + useWatch() // let type: 'open' | 'copy' = 'open' const type = useRef<'open' | 'copy'>('open') @@ -613,7 +613,7 @@ function ApplyLink() { {/* 展示链接地址 */}
- {link(values)} + {link(form.getValues())}
{/* 操作 */} diff --git a/src/components/composites/purchase/long/center.tsx b/src/components/composites/purchase/long/center.tsx index 2c5caaa..45bd821 100644 --- a/src/components/composites/purchase/long/center.tsx +++ b/src/components/composites/purchase/long/center.tsx @@ -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() - const type = form.watch('type') + const type = useWatch({name: 'type'}) return ( diff --git a/src/components/composites/purchase/long/right.tsx b/src/components/composites/purchase/long/right.tsx index db74a7e..13c4d9c 100644 --- a/src/components/composites/purchase/long/right.tsx +++ b/src/components/composites/purchase/long/right.tsx @@ -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() - - 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() + 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, }, }}/> diff --git a/src/components/composites/purchase/pay.tsx b/src/components/composites/purchase/pay.tsx index ebe2aea..c6b237b 100644 --- a/src/components/composites/purchase/pay.tsx +++ b/src/components/composites/purchase/pay.tsx @@ -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[0] + resource: CreateResourceReq } & ({ method: 'alipay' | 'wechat' } | { diff --git a/src/components/composites/purchase/short/center.tsx b/src/components/composites/purchase/short/center.tsx index 590ab72..3229c9c 100644 --- a/src/components/composites/purchase/short/center.tsx +++ b/src/components/composites/purchase/short/center.tsx @@ -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() - const type = form.watch('type') + const type = useWatch({name: 'type'}) return ( @@ -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}> + min={10000} + step={5000}/>
diff --git a/src/components/composites/purchase/short/right.tsx b/src/components/composites/purchase/short/right.tsx index a3dde70..1a78031 100644 --- a/src/components/composites/purchase/short/right.tsx +++ b/src/components/composites/purchase/short/right.tsx @@ -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() - - 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() + 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, }, }}/> diff --git a/src/components/ui/form.tsx b/src/components/ui/form.tsx index 09fd6c6..299be80 100644 --- a/src/components/ui/form.tsx +++ b/src/components/ui/form.tsx @@ -17,20 +17,13 @@ import React, {ComponentProps, createContext, ReactNode, useContext, useId} from type FormProps = { form: UseFormReturn - onSubmit?: SubmitHandler - onError?: SubmitErrorHandler handler?: (e?: React.BaseSyntheticEvent) => Promise } & Omit, 'onSubmit' | 'onError'> function Form(rawProps: FormProps) { - const {children, onSubmit, onError, handler, ...props} = rawProps + const {children, handler, ...props} = rawProps const form = props.form - const handle = handler || form.handleSubmit( - onSubmit || ((_) => {}), - onError, - ) - return (
(rawProps: FormProps) { onSubmit={async (event) => { event.preventDefault() event.stopPropagation() - await handle(event) + await handler?.(event) }}> {children}