暂无可用套餐时取消加载中 & 登录页加返回首页 & 加联系专属客服 & 修改白名单上限10个

This commit is contained in:
Eamon-meng
2026-04-21 16:42:37 +08:00
parent a0b0956677
commit eb4c2d2d5f
9 changed files with 146 additions and 132 deletions

View File

@@ -6,7 +6,7 @@ import {Card, CardContent} from '@/components/ui/card'
import {Form, FormField} from '@/components/ui/form'
import {Label} from '@/components/ui/label'
import {Tabs, TabsList, TabsTrigger} from '@/components/ui/tabs'
import {EyeClosedIcon, EyeIcon} from 'lucide-react'
import {EyeClosedIcon, EyeIcon, HomeIcon} from 'lucide-react'
import {useState, ReactNode, useEffect, Suspense} from 'react'
import zod from 'zod'
import {useForm, useFormContext, useWatch} from 'react-hook-form'
@@ -16,6 +16,7 @@ import {useRouter} from 'next/navigation'
import {login, LoginMode} from '@/actions/auth'
import {useProfileStore} from '@/components/stores/profile'
import dynamic from 'next/dynamic'
import Link from 'next/link'
const smsSchema = zod.object({
username: zod.string().length(11, '请输入正确的手机号码'),
@@ -88,111 +89,122 @@ export default function LoginCard() {
const [showPwd, setShowPwd] = useState(false)
return (
<Card className="w-96 mx-4 shadow-lg relative z-20 py-8">
<CardContent className="px-8">
{/* 登录方式切换 */}
<Tabs
value={mode}
onValueChange={(val) => {
setMode(val as LoginMode)
form.reset({username: '', password: '', remember: false})
form.clearErrors()
}}
className="mb-6">
<TabsList className="w-full p-0 bg-white">
<Tab value="password"></Tab>
<Tab value="phone_code">/</Tab>
</TabsList>
</Tabs>
<Form<LoginSchema> className="space-y-6" form={form} handler={handler}>
<FormField name="username" label={mode === 'phone_code' ? '手机号' : '用户名'}>
{({id, field}) => (
<Input
{...field}
id={id}
type="tel"
placeholder={mode === 'phone_code' ? '请输入手机号' : '请输入用户名/手机号/邮箱'}
autoComplete="tel-national"
/>
)}
</FormField>
<FormField name="password" label={mode === 'phone_code' ? '验证码' : '密码'}>
{({id, field}) =>
mode === 'phone_code' ? (
<div className="flex space-x-4">
<Input
{...field}
id={id}
className="h-10"
placeholder="请输入验证码"
autoComplete="one-time-code"
disabled={submitting}
/>
<SendMsgByUsername/>
</div>
) : (
<div className="relative">
<Input
{...field}
id={id}
type={showPwd ? 'text' : 'password'}
className="h-10 pr-10"
placeholder="至少6位密码需包含字母和数字"
autoComplete="current-password"
minLength={6}
disabled={submitting}
/>
<button
type="button"
tabIndex={-1}
className="absolute right-2 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600 cursor-pointer"
onClick={() => setShowPwd(v => !v)}
aria-label={showPwd ? '隐藏密码' : '显示密码'}
>
{showPwd ? (
<EyeIcon size={20}/>
) : (
<EyeClosedIcon size={20}/>
)}
</button>
</div>
)
}
</FormField>
<FormField name="remember">
{({id, field}) => (
<div className="flex flex-row items-start space-x-2 space-y-0">
<Checkbox
<div className="relative flex flex-col items-center">
<div className="relative w-96 mx-4">
<Link
href="/"
className="absolute -top-8 right-0 inline-flex items-center text-sm transition-colors"
>
<HomeIcon size={18} className="mr-1"/>
</Link>
</div>
<Card className="w-96 mx-4 shadow-lg relative z-20 py-8">
<CardContent className="px-8">
{/* 登录方式切换 */}
<Tabs
value={mode}
onValueChange={(val) => {
setMode(val as LoginMode)
form.reset({username: '', password: '', remember: false})
form.clearErrors()
}}
className="mb-6">
<TabsList className="w-full p-0 bg-white">
<Tab value="password"></Tab>
<Tab value="phone_code">/</Tab>
</TabsList>
</Tabs>
<Form<LoginSchema> className="space-y-6" form={form} handler={handler}>
<FormField name="username" label={mode === 'phone_code' ? '手机号' : '用户名'}>
{({id, field}) => (
<Input
{...field}
id={id}
checked={field.value}
onCheckedChange={field.onChange}
disabled={submitting}
type="tel"
placeholder={mode === 'phone_code' ? '请输入手机号' : '请输入用户名/手机号/邮箱'}
autoComplete="tel-national"
/>
<div className="space-y-1 leading-none">
<Label></Label>
)}
</FormField>
<FormField name="password" label={mode === 'phone_code' ? '验证码' : '密码'}>
{({id, field}) =>
mode === 'phone_code' ? (
<div className="flex space-x-4">
<Input
{...field}
id={id}
className="h-10"
placeholder="请输入验证码"
autoComplete="one-time-code"
disabled={submitting}
/>
<SendMsgByUsername/>
</div>
) : (
<div className="relative">
<Input
{...field}
id={id}
type={showPwd ? 'text' : 'password'}
className="h-10 pr-10"
placeholder="至少6位密码需包含字母和数字"
autoComplete="current-password"
minLength={6}
disabled={submitting}
/>
<button
type="button"
tabIndex={-1}
className="absolute right-2 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600 cursor-pointer"
onClick={() => setShowPwd(v => !v)}
aria-label={showPwd ? '隐藏密码' : '显示密码'}
>
{showPwd ? (
<EyeIcon size={20}/>
) : (
<EyeClosedIcon size={20}/>
)}
</button>
</div>
)
}
</FormField>
<FormField name="remember">
{({id, field}) => (
<div className="flex flex-row items-start space-x-2 space-y-0">
<Checkbox
id={id}
checked={field.value}
onCheckedChange={field.onChange}
disabled={submitting}
/>
<div className="space-y-1 leading-none">
<Label></Label>
</div>
</div>
</div>
)}
</FormField>
<div className="flex flex-col gap-3">
<Button
className="w-full h-12 text-lg"
type="submit"
theme="gradient"
disabled={submitting}
>
{submitting ? '登录中...' : (mode === 'phone_code' ? '首次登录即注册' : '立即登录')}
</Button>
<p className="text-xs text-center text-gray-500">
<a href="/userAgreement" className="text-blue-600 hover:text-blue-500"></a>
<a href="/privacyPolicy" className="text-blue-600 hover:text-blue-500"></a>
</p>
</div>
</Form>
</CardContent>
</Card>
)}
</FormField>
<div className="flex flex-col gap-3">
<Button
className="w-full h-12 text-lg"
type="submit"
theme="gradient"
disabled={submitting}
>
{submitting ? '登录中...' : (mode === 'phone_code' ? '首次登录即注册' : '立即登录')}
</Button>
<p className="text-xs text-center text-gray-500">
<a href="/userAgreement" className="text-blue-600 hover:text-blue-500"></a>
<a href="/privacyPolicy" className="text-blue-600 hover:text-blue-500"></a>
</p>
</div>
</Form>
</CardContent>
</Card>
</div>
)
}