'use client' import {useState} from 'react' import {Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle, DialogTrigger} from '@/components/ui/dialog' import {Button} from '@/components/ui/button' import {Form, FormField} from '@/components/ui/form' import {Input} from '@/components/ui/input' import {useForm, useFormContext, useWatch} from 'react-hook-form' import {zodResolver} from '@hookform/resolvers/zod' import * as z from 'zod' import {toast} from 'sonner' import {useRouter} from 'next/navigation' import {updatePassword} from '@/actions/user' import dynamic from 'next/dynamic' // 表单验证规则 const schema = z.object({ phone: z.string().regex(/^1\d{10}$/, `请输入正确的手机号`), captcha: z.string().nonempty('请输入验证码'), code: z.string().regex(/^\d{6}$/, `请输入正确的验证码`), password: z.string().min(6, `密码至少6位`), confirm_password: z.string(), }).refine(data => data.password === data.confirm_password, { message: '两次输入的密码不一致', path: ['confirm_password'], }) type Schema = z.infer interface ChangePasswordDialogProps { triggerClassName?: string open?: boolean defaultOpen?: boolean onOpenChange?: (open: boolean) => void onSuccess?: () => void } export function ChangePasswordDialog({ triggerClassName, open, defaultOpen, onOpenChange, onSuccess, }: ChangePasswordDialogProps) { const [internalOpen, setInternalOpen] = useState(defaultOpen || false) const router = useRouter() const actualOpen = open !== undefined ? open : internalOpen const actualOnOpenChange = onOpenChange || setInternalOpen // 表单初始化 const form = useForm({ resolver: zodResolver( schema.refine( data => /^(?=.*[a-zA-Z])(?=.*\d).{6,}$/.test(data.password), { message: '密码需包含字母和数字,且不少于6位', path: ['password'], }, ), ), defaultValues: { phone: '', captcha: '', code: '', password: '', confirm_password: '', }, }) // 提交处理 const handler = async (value: Schema) => { try { const resp = await updatePassword({ phone: value.phone, code: value.code, password: value.password, }) if (!resp.success) { throw new Error(resp.message) } toast.success(`保存成功,请重新登录`) onSuccess?.() actualOnOpenChange(false) router.replace('/login') } catch (e) { console.error(e) toast.error(`保存失败`, { description: e instanceof Error ? e.message : String(e), }) } } return (
{ const data = form.getValues() await handler(data) }} className="flex flex-col gap-4 mt-4"> 修改密码 {/* 手机号输入 */} name="phone" label="手机号" className="flex-auto"> {({field}) => ( )} {/* 短信验证码 */}
name="code" label="验证码" className="flex-auto"> {({field}) => ( )}
{/* 新密码 */} name="password" label="新密码" className="flex-auto"> {({field}) => ( )} {/* 确认密码 */} name="confirm_password" label="确认密码" className="flex-auto"> {({field}) => ( )}
) } function SendMsgByPhone() { const {control} = useFormContext() const phone = useWatch({control, name: 'phone'}) return } const SendMsg = dynamic(() => import('@/components/send-msg'), {ssr: false})