引入 husky,并全局重新格式化
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
|
||||
import { ReactNode } from 'react'
|
||||
import { Metadata } from 'next'
|
||||
import {ReactNode} from 'react'
|
||||
import {Metadata} from 'next'
|
||||
|
||||
export async function generateMetadata(): Promise<Metadata> {
|
||||
return {
|
||||
@@ -9,9 +8,9 @@ export async function generateMetadata(): Promise<Metadata> {
|
||||
}
|
||||
|
||||
export type ProfileLayoutProps = {
|
||||
children: ReactNode
|
||||
children: ReactNode
|
||||
}
|
||||
|
||||
export default async function ProfileLayout(props: ProfileLayoutProps) {
|
||||
return props.children
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,6 @@ import {useRouter} from 'next/navigation'
|
||||
export type ProfilePageProps = {}
|
||||
|
||||
export default function ProfilePage(props: ProfilePageProps) {
|
||||
|
||||
const router = useRouter()
|
||||
const profile = useProfileStore(store => store.profile)
|
||||
|
||||
@@ -42,9 +41,9 @@ export default function ProfilePage(props: ProfilePageProps) {
|
||||
if (!profile) {
|
||||
return (
|
||||
<Page>
|
||||
<div className={`flex flex-col gap-4`}>
|
||||
<h3 className={`text-lg font-bold`}>加载中...</h3>
|
||||
<p className={`text-sm text-gray-600`}>请稍等片刻</p>
|
||||
<div className="flex flex-col gap-4">
|
||||
<h3 className="text-lg font-bold">加载中...</h3>
|
||||
<p className="text-sm text-gray-600">请稍等片刻</p>
|
||||
</div>
|
||||
</Page>
|
||||
)
|
||||
@@ -52,59 +51,63 @@ export default function ProfilePage(props: ProfilePageProps) {
|
||||
|
||||
return (
|
||||
<Page className="flex-row items-start">
|
||||
<div className={`flex-3/4 flex flex-col gap-4`}>
|
||||
<div className="flex-3/4 flex flex-col gap-4">
|
||||
{/* banner */}
|
||||
<section className={`flex-none basis-40 relative rounded-lg overflow-hidden flex flex-col gap-4 pl-8 justify-center`}>
|
||||
<Image src={banner} alt={`背景图`} aria-hidden className={`absolute inset-0 w-full h-full object-cover`}/>
|
||||
<h3 className={`text-lg font-bold z-10 relative`}>蓝狐HTTP邀请您参与【先测后买】服务</h3>
|
||||
<p className={`text-sm text-gray-600 z-10 relative`}>为了保障您的账户安全,请先完成实名认证,即可获取福利套餐测试资格</p>
|
||||
<section className="flex-none basis-40 relative rounded-lg overflow-hidden flex flex-col gap-4 pl-8 justify-center">
|
||||
<Image src={banner} alt="背景图" aria-hidden className="absolute inset-0 w-full h-full object-cover"/>
|
||||
<h3 className="text-lg font-bold z-10 relative">蓝狐HTTP邀请您参与【先测后买】服务</h3>
|
||||
<p className="text-sm text-gray-600 z-10 relative">为了保障您的账户安全,请先完成实名认证,即可获取福利套餐测试资格</p>
|
||||
</section>
|
||||
|
||||
{/* 块信息 */}
|
||||
<div className={`flex-none basis-40 flex gap-4`}>
|
||||
<div className="flex-none basis-40 flex gap-4">
|
||||
|
||||
<Card className={`flex-1`}>
|
||||
<Card className="flex-1">
|
||||
<CardHeader>
|
||||
<CardTitle className={`font-normal`}>帐号余额(元)</CardTitle>
|
||||
<CardTitle className="font-normal">帐号余额(元)</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className={`flex-auto flex justify-between items-center px-8`}>
|
||||
<p className={`text-xl`}>{profile?.balance}</p>
|
||||
<CardContent className="flex-auto flex justify-between items-center px-8">
|
||||
<p className="text-xl">{profile?.balance}</p>
|
||||
<RechargeModal classNames={{
|
||||
trigger: `h-10 px-6`,
|
||||
}}/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card className={`flex-1`}>
|
||||
<Card className="flex-1">
|
||||
<CardHeader>
|
||||
<CardTitle className={`font-normal`}>实名认证</CardTitle>
|
||||
<CardTitle className="font-normal">实名认证</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className={`flex-auto flex justify-between items-center px-8`}>
|
||||
<CardContent className="flex-auto flex justify-between items-center px-8">
|
||||
{!profile?.id_token
|
||||
? <>
|
||||
<p className={`text-sm`}>为了保障您的账户安全和正常使用服务,请您尽快完成实名认证</p>
|
||||
<Button theme={`outline`} className={`mx-16 w-24`} onClick={() => router.push('/admin/identify')}>去认证</Button>
|
||||
</>
|
||||
: <>
|
||||
<p className={`flex flex-col gap-1`}>
|
||||
<span>{profile.name}</span>
|
||||
<span className={`text-sm`}>{profile.id_no}</span>
|
||||
</p>
|
||||
<p className={`flex gap-1 items-center`}>
|
||||
<CheckCircle className={`text-done`} size={18}/>
|
||||
<span>已认证</span>
|
||||
</p>
|
||||
</>}
|
||||
? (
|
||||
<>
|
||||
<p className="text-sm">为了保障您的账户安全和正常使用服务,请您尽快完成实名认证</p>
|
||||
<Button theme="outline" className="mx-16 w-24" onClick={() => router.push('/admin/identify')}>去认证</Button>
|
||||
</>
|
||||
)
|
||||
: (
|
||||
<>
|
||||
<p className="flex flex-col gap-1">
|
||||
<span>{profile.name}</span>
|
||||
<span className="text-sm">{profile.id_no}</span>
|
||||
</p>
|
||||
<p className="flex gap-1 items-center">
|
||||
<CheckCircle className="text-done" size={18}/>
|
||||
<span>已认证</span>
|
||||
</p>
|
||||
</>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
<div className={`flex-auto shrink-0 basis-80 rounded-lg bg-white p-4 flex flex-col gap-8`}>
|
||||
<div className="flex-auto shrink-0 basis-80 rounded-lg bg-white p-4 flex flex-col gap-8">
|
||||
|
||||
{/* 安全信息 */}
|
||||
<div className={`flex flex-col gap-4`}>
|
||||
<h3 className={`font-normal`}>安全信息</h3>
|
||||
<div className={`flex gap-4 items-center`}>
|
||||
<div className="flex flex-col gap-4">
|
||||
<h3 className="font-normal">安全信息</h3>
|
||||
<div className="flex gap-4 items-center">
|
||||
<p>{profile.phone}</p>
|
||||
<PasswordForm profile={profile}/>
|
||||
</div>
|
||||
@@ -133,7 +136,7 @@ function Aftersale(props: {
|
||||
qrcode.toCanvas(canvasRef.current, String(admin), {
|
||||
width: 180,
|
||||
margin: 0,
|
||||
}).catch(err => {
|
||||
}).catch((err) => {
|
||||
console.error(err)
|
||||
})
|
||||
}
|
||||
@@ -143,32 +146,36 @@ function Aftersale(props: {
|
||||
<Card className="flex-none basis-80">
|
||||
<CardHeader>
|
||||
<CardTitle>
|
||||
<QrCodeIcon size={18}/> 关于售后
|
||||
<QrCodeIcon size={18}/>
|
||||
{' '}
|
||||
关于售后
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className={`flex flex-col gap-8`}>
|
||||
<CardContent className="flex flex-col gap-8">
|
||||
|
||||
<div className={`flex flex-col gap-4`}>
|
||||
<p className={`text-weak text-sm`}>
|
||||
<div className="flex flex-col gap-4">
|
||||
<p className="text-weak text-sm">
|
||||
1.全国100万+动态IP代理资源免费测试,先测后买让您安心使用。
|
||||
</p>
|
||||
|
||||
<p className={`text-weak text-sm`}>
|
||||
<p className="text-weak text-sm">
|
||||
2.注册即享新人福利,专业的客户经理,多维度为您提供在线代理相关答疑
|
||||
</p>
|
||||
|
||||
<p className={`text-weak text-sm`}>
|
||||
<p className="text-weak text-sm">
|
||||
3.1V1专属售后答疑,技术团队7*24小时在线支持提供专属解决方案
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className={`flex flex-col gap-4 items-center`}>
|
||||
<div className="flex flex-col gap-4 items-center">
|
||||
<p>您的专属客服经理</p>
|
||||
<div>
|
||||
<canvas ref={canvasRef} width="180" height="180" className={`mx-auto bg-muted`}/>
|
||||
<canvas ref={canvasRef} width="180" height="180" className="mx-auto bg-muted"/>
|
||||
</div>
|
||||
<p className="text-xs text-weak">
|
||||
扫描上方二维码添加客服经理微信<br/>获取更多帮助与支持
|
||||
扫描上方二维码添加客服经理微信
|
||||
<br/>
|
||||
获取更多帮助与支持
|
||||
</p>
|
||||
</div>
|
||||
</CardContent>
|
||||
@@ -179,7 +186,6 @@ function Aftersale(props: {
|
||||
function BasicForm(props: {
|
||||
profile: User
|
||||
}) {
|
||||
|
||||
const schema = z.object({
|
||||
username: z.string(),
|
||||
email: z.string().email('请输入正确的邮箱'),
|
||||
@@ -196,7 +202,7 @@ function BasicForm(props: {
|
||||
contact_wechat: props.profile.contact_wechat || '',
|
||||
},
|
||||
})
|
||||
const handler = form.handleSubmit(async value => {
|
||||
const handler = form.handleSubmit(async (value) => {
|
||||
try {
|
||||
const resp = await update(value)
|
||||
if (!resp.success) {
|
||||
@@ -217,8 +223,8 @@ function BasicForm(props: {
|
||||
const refreshProfile = useProfileStore(store => store.refreshProfile)
|
||||
|
||||
return (
|
||||
<div className={`flex flex-col gap-4`}>
|
||||
<h3 className={`font-normal`}>基本信息</h3>
|
||||
<div className="flex flex-col gap-4">
|
||||
<h3 className="font-normal">基本信息</h3>
|
||||
<Form
|
||||
form={form}
|
||||
handler={handler}
|
||||
@@ -227,60 +233,65 @@ function BasicForm(props: {
|
||||
)}
|
||||
>
|
||||
<FormField<Schema>
|
||||
name={`username`}
|
||||
label={<span className={`w-full flex justify-end`}>用户名</span>}
|
||||
className={`grid grid-cols-[48px_1fr] grid-rows-[auto_auto] gap-x-4`}
|
||||
name="username"
|
||||
label={<span className="w-full flex justify-end">用户名</span>}
|
||||
className="grid grid-cols-[48px_1fr] grid-rows-[auto_auto] gap-x-4"
|
||||
classNames={{
|
||||
message: `col-start-2`,
|
||||
}}
|
||||
>
|
||||
{({field}) => (
|
||||
<Input {...field} placeholder={`请输入用户名`} className={`w-52`}/>
|
||||
<Input {...field} placeholder="请输入用户名" className="w-52"/>
|
||||
)}
|
||||
</FormField>
|
||||
<FormField<Schema>
|
||||
name={`email`}
|
||||
label={<span className={`w-full flex justify-end`}>邮箱</span>}
|
||||
className={`grid grid-cols-[48px_1fr] grid-rows-[auto_auto] gap-x-4`}
|
||||
name="email"
|
||||
label={<span className="w-full flex justify-end">邮箱</span>}
|
||||
className="grid grid-cols-[48px_1fr] grid-rows-[auto_auto] gap-x-4"
|
||||
classNames={{
|
||||
message: `col-start-2`,
|
||||
}}
|
||||
>
|
||||
{({field}) => (
|
||||
<Input {...field} placeholder={`请输入邮箱`} className={`w-52`}/>
|
||||
<Input {...field} placeholder="请输入邮箱" className="w-52"/>
|
||||
)}
|
||||
</FormField>
|
||||
<FormField<Schema>
|
||||
name={`contact_qq`}
|
||||
label={<span className={`w-full flex justify-end`}>QQ</span>}
|
||||
className={`grid grid-cols-[48px_1fr] grid-rows-[auto_auto] gap-x-4`}
|
||||
name="contact_qq"
|
||||
label={<span className="w-full flex justify-end">QQ</span>}
|
||||
className="grid grid-cols-[48px_1fr] grid-rows-[auto_auto] gap-x-4"
|
||||
classNames={{
|
||||
message: `col-start-2`,
|
||||
}}
|
||||
>
|
||||
{({field}) => (
|
||||
<Input {...field} placeholder={`请输入QQ号`} className={`w-52`}/>
|
||||
<Input {...field} placeholder="请输入QQ号" className="w-52"/>
|
||||
)}
|
||||
</FormField>
|
||||
<FormField<Schema>
|
||||
name={`contact_wechat`}
|
||||
label={<span className={`w-full flex justify-end`}>微信</span>}
|
||||
className={`grid grid-cols-[48px_1fr] grid-rows-[auto_auto] gap-x-4`}
|
||||
name="contact_wechat"
|
||||
label={<span className="w-full flex justify-end">微信</span>}
|
||||
className="grid grid-cols-[48px_1fr] grid-rows-[auto_auto] gap-x-4"
|
||||
classNames={{
|
||||
message: `col-start-2`,
|
||||
}}
|
||||
>
|
||||
{({field}) => (
|
||||
<Input {...field} placeholder={`请输入微信号`} className={`w-52`}/>
|
||||
<Input {...field} placeholder="请输入微信号" className="w-52"/>
|
||||
)}
|
||||
</FormField>
|
||||
<div className={`flex justify-end gap-4 col-span-2 justify-self-stretch`}>
|
||||
<Button theme={`outline`} type={`button`} onClick={() => form.reset({
|
||||
username: props.profile.username || '',
|
||||
email: props.profile.email || '',
|
||||
contact_qq: props.profile.contact_qq || '',
|
||||
contact_wechat: props.profile.contact_wechat || '',
|
||||
})}>撤销</Button>
|
||||
<div className="flex justify-end gap-4 col-span-2 justify-self-stretch">
|
||||
<Button
|
||||
theme="outline"
|
||||
type="button"
|
||||
onClick={() => form.reset({
|
||||
username: props.profile.username || '',
|
||||
email: props.profile.email || '',
|
||||
contact_qq: props.profile.contact_qq || '',
|
||||
contact_wechat: props.profile.contact_wechat || '',
|
||||
})}>
|
||||
撤销
|
||||
</Button>
|
||||
<Button>保存</Button>
|
||||
</div>
|
||||
</Form>
|
||||
@@ -291,7 +302,6 @@ function BasicForm(props: {
|
||||
function PasswordForm(props: {
|
||||
profile: User
|
||||
}) {
|
||||
|
||||
// ======================
|
||||
// open
|
||||
// ======================
|
||||
@@ -324,7 +334,7 @@ function PasswordForm(props: {
|
||||
confirm_password: '',
|
||||
},
|
||||
})
|
||||
const handler = form.handleSubmit(async value => {
|
||||
const handler = form.handleSubmit(async (value) => {
|
||||
try {
|
||||
const resp = await updatePassword({
|
||||
phone: value.phone,
|
||||
@@ -374,7 +384,7 @@ function PasswordForm(props: {
|
||||
|
||||
setCaptchaWait(60)
|
||||
interval.current = setInterval(() => {
|
||||
setCaptchaWait(wait => {
|
||||
setCaptchaWait((wait) => {
|
||||
if (wait <= 1) {
|
||||
clearInterval(interval.current!)
|
||||
return 0
|
||||
@@ -393,38 +403,38 @@ function PasswordForm(props: {
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={setOpen}>
|
||||
<DialogTrigger asChild>
|
||||
<Button theme={`outline`} className={`w-24 h-9`}>修改密码</Button>
|
||||
<Button theme="outline" className="w-24 h-9">修改密码</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>修改密码</DialogTitle>
|
||||
</DialogHeader>
|
||||
<Form form={form} handler={handler} className={`flex flex-col gap-4 mt-4`}>
|
||||
<Form form={form} handler={handler} className="flex flex-col gap-4 mt-4">
|
||||
|
||||
{/* 手机号 */}
|
||||
<FormField<Schema> name={`phone`} label={`手机号`} className={`flex-auto`}>
|
||||
<FormField<Schema> name="phone" label="手机号" className="flex-auto">
|
||||
{({field}) => (
|
||||
<Input {...field} placeholder={`请输入手机号`} autoComplete={`tel-national`}/>
|
||||
<Input {...field} placeholder="请输入手机号" autoComplete="tel-national"/>
|
||||
)}
|
||||
</FormField>
|
||||
|
||||
<FormField<Schema> name={`captcha`} label={`验证码`}>
|
||||
<FormField<Schema> name="captcha" label="验证码">
|
||||
{({field}) => (
|
||||
<div className={`flex gap-4`}>
|
||||
<Input {...field} placeholder={`请输入验证码`} autoComplete={`one-time-code`}/>
|
||||
<Button className={`p-0 bg-transparent`} onClick={refreshCaptcha} type={`button`}>
|
||||
<img src={captchaUrl} alt={`验证码`} className={`h-10`}/>
|
||||
<div className="flex gap-4">
|
||||
<Input {...field} placeholder="请输入验证码" autoComplete="one-time-code"/>
|
||||
<Button className="p-0 bg-transparent" onClick={refreshCaptcha} type="button">
|
||||
<img src={captchaUrl} alt="验证码" className="h-10"/>
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</FormField>
|
||||
|
||||
{/* 短信令牌 */}
|
||||
<FormField<Schema> name={`code`} label={`短信令牌`} className={`flex-auto`}>
|
||||
<FormField<Schema> name="code" label="短信令牌" className="flex-auto">
|
||||
{({field}) => (
|
||||
<div className={`flex gap-4`}>
|
||||
<Input {...field} placeholder={`请输入验证码`} autoComplete={`one-time-code`}/>
|
||||
<Button theme={`outline`} type={`button`} className={`w-36`} onClick={() => sendVerifier()}>
|
||||
<div className="flex gap-4">
|
||||
<Input {...field} placeholder="请输入验证码" autoComplete="one-time-code"/>
|
||||
<Button theme="outline" type="button" className="w-36" onClick={() => sendVerifier()}>
|
||||
{captchaWait > 0
|
||||
? `重新发送(${captchaWait})`
|
||||
: `获取短信令牌`
|
||||
@@ -435,29 +445,35 @@ function PasswordForm(props: {
|
||||
</FormField>
|
||||
|
||||
{/* 新密码 */}
|
||||
<FormField<Schema> name={`password`} label={`新密码`} className={`flex-auto`}>
|
||||
<FormField<Schema> name="password" label="新密码" className="flex-auto">
|
||||
{({field}) => (
|
||||
<Input {...field} placeholder={`请输入新密码`} type={`password`} autoComplete={`new-password`}/>
|
||||
<Input {...field} placeholder="请输入新密码" type="password" autoComplete="new-password"/>
|
||||
)}
|
||||
</FormField>
|
||||
|
||||
{/* 确认密码 */}
|
||||
<FormField<Schema> name={`confirm_password`} label={`确认密码`} className={`flex-auto`}>
|
||||
<FormField<Schema> name="confirm_password" label="确认密码" className="flex-auto">
|
||||
{({field}) => (
|
||||
<Input {...field} placeholder={`请再次输入新密码`} type={`password`} autoComplete={`new-password`}/>
|
||||
<Input {...field} placeholder="请再次输入新密码" type="password" autoComplete="new-password"/>
|
||||
)}
|
||||
</FormField>
|
||||
</Form>
|
||||
|
||||
<DialogFooter>
|
||||
<Button theme={`outline`} type={`button`} onClick={() => {
|
||||
setOpen(false)
|
||||
form.reset()
|
||||
}}>关闭</Button>
|
||||
<Button onClick={async e => {
|
||||
<Button
|
||||
theme="outline"
|
||||
type="button"
|
||||
onClick={() => {
|
||||
setOpen(false)
|
||||
form.reset()
|
||||
}}>
|
||||
关闭
|
||||
</Button>
|
||||
<Button onClick={async (e) => {
|
||||
const result = await handler(e)
|
||||
|
||||
}}>保存</Button>
|
||||
}}>
|
||||
保存
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
||||
Reference in New Issue
Block a user