3 Commits
f62a3aa63a
...
4db01f13ae
Author | SHA1 | Message | Date |
---|---|---|---|
lk | 4db01f13ae |
登录 修改 注册 本地化全部加上
|
2 months ago |
lk | 6623046824 |
Merge remote-tracking branch 'origin/main'
# Conflicts: # src/pages/use/login/index.tsx |
2 months ago |
lk | 28cd4e28ed |
登录 修改 注册 本地化接口已写
|
2 months ago |
4 changed files with 586 additions and 513 deletions
-
307src/components/captcha/SlideCapt.tsx
-
454src/pages/use/login/index.tsx
-
98src/pages/use/password/retrieve.tsx
-
240src/pages/use/register/index.tsx
@ -1,163 +1,160 @@ |
|||||
import React, { forwardRef, memo, useCallback, useEffect, useState, useImperativeHandle } from 'react' |
|
||||
import { Popover, message } from 'antd' |
|
||||
import GoCaptcha from 'go-captcha-react' |
|
||||
import { SlideCaptchaCheckData } from './types.ts' |
|
||||
import { SlideData, SlidePoint } from 'go-captcha-react/dist/components/Slide/meta/data' |
|
||||
import { SlideConfig } from 'go-captcha-react/dist/components/Slide/meta/config' |
|
||||
import { Props } from 'go-captcha-react/dist/components/Button' |
|
||||
import { useStyle } from './style.ts' |
|
||||
|
import React, { forwardRef, memo, useCallback, useEffect, useState, useImperativeHandle } from "react"; |
||||
|
import { Popover, message } from "antd"; |
||||
|
import GoCaptcha from "go-captcha-react"; |
||||
|
import { SlideCaptchaCheckData } from "./types.ts"; |
||||
|
import { SlideData, SlidePoint } from "go-captcha-react/dist/components/Slide/meta/data"; |
||||
|
import { SlideConfig } from "go-captcha-react/dist/components/Slide/meta/config"; |
||||
|
import { Props } from "go-captcha-react/dist/components/Button"; |
||||
|
import { useStyle } from "./style.ts"; |
||||
|
|
||||
export interface SlideCaptProps { |
export interface SlideCaptProps { |
||||
api: { |
api: { |
||||
getCaptcha: () => Promise<any>, |
|
||||
checkCaptcha: (params: SlideCaptchaCheckData) => Promise<any>, |
|
||||
}, |
|
||||
config?: SlideConfig |
|
||||
value?: string |
|
||||
onChange?: (value?: string) => void |
|
||||
|
getCaptcha: () => Promise<any>; |
||||
|
checkCaptcha: (params: SlideCaptchaCheckData) => Promise<any>; |
||||
|
}; |
||||
|
config?: SlideConfig; |
||||
|
value?: string; |
||||
|
onChange?: (value?: string) => void; |
||||
} |
} |
||||
|
|
||||
export type SlideCaptRef = { |
export type SlideCaptRef = { |
||||
reset: () => void |
|
||||
} |
|
||||
|
|
||||
|
|
||||
const SlideCapt = forwardRef<SlideCaptRef | undefined, SlideCaptProps>(( |
|
||||
{ |
|
||||
config, |
|
||||
api, |
|
||||
value, |
|
||||
onChange, |
|
||||
}: SlideCaptProps, ref) => { |
|
||||
|
|
||||
const { styles } = useStyle() |
|
||||
const [ open, setOpen ] = useState(false) |
|
||||
const [ state, setState ] = useState<Props>({}) |
|
||||
const [ data, setData ] = useState<SlideData>() |
|
||||
const [ innerKey, setKey ] = useState(value) |
|
||||
|
|
||||
const fetchCaptcha = useCallback(() => { |
|
||||
|
|
||||
return api.getCaptcha().then(res => { |
|
||||
if (res.code === 0) { |
|
||||
const data = res.data |
|
||||
setKey(data['captcha_key'] || '') |
|
||||
setData({ |
|
||||
image: data['image_base64'] || '', |
|
||||
thumb: data['tile_base64'] || '', |
|
||||
thumbX: data['tile_x'] || 0, |
|
||||
thumbY: data['tile_y'] || 0, |
|
||||
thumbWidth: data['tile_width'] || 0, |
|
||||
thumbHeight: data['tile_height'] || 0, |
|
||||
}) |
|
||||
|
reset: () => void; |
||||
|
}; |
||||
|
|
||||
|
const SlideCapt = forwardRef<SlideCaptRef | undefined, SlideCaptProps>( |
||||
|
({ config, api, value, onChange }: SlideCaptProps, ref) => { |
||||
|
const { styles } = useStyle(); |
||||
|
const [open, setOpen] = useState(false); |
||||
|
const [state, setState] = useState<Props>({}); |
||||
|
const [data, setData] = useState<SlideData>(); |
||||
|
const [innerKey, setKey] = useState(value); |
||||
|
|
||||
|
const fetchCaptcha = useCallback(() => { |
||||
|
return api.getCaptcha().then((res) => { |
||||
|
if (res.code === 0) { |
||||
|
const data = res.data; |
||||
|
setKey(data["captcha_key"] || ""); |
||||
|
setData({ |
||||
|
image: data["image_base64"] || "", |
||||
|
thumb: data["tile_base64"] || "", |
||||
|
thumbX: data["tile_x"] || 0, |
||||
|
thumbY: data["tile_y"] || 0, |
||||
|
thumbWidth: data["tile_width"] || 0, |
||||
|
thumbHeight: data["tile_height"] || 0, |
||||
|
}); |
||||
|
} |
||||
|
}); |
||||
|
}, [api.getCaptcha, setData]); |
||||
|
|
||||
|
const refresh = useCallback(() => { |
||||
|
fetchCaptcha(); |
||||
|
}, [fetchCaptcha]); |
||||
|
|
||||
|
const confirm = useCallback( |
||||
|
(point: SlidePoint, clear: (fn?: any) => void) => { |
||||
|
api |
||||
|
.checkCaptcha({ |
||||
|
point: [point.x, point.y].join(","), |
||||
|
key: innerKey!, |
||||
|
}) |
||||
|
.then((res) => { |
||||
|
// console.log(res)
|
||||
|
if (res.code === 0 && res.data.is_ok) { |
||||
|
message.success(`验证成功`); |
||||
|
|
||||
|
//验证成功,onChange通知出去,外部需要key做为校验
|
||||
|
onChange?.(innerKey); |
||||
|
|
||||
|
setState((prevState) => ({ |
||||
|
...prevState, |
||||
|
type: "success", |
||||
|
title: "校验成功", |
||||
|
})); |
||||
|
setOpen(false); |
||||
|
} else { |
||||
|
message.error("验证失败"); |
||||
|
setState((prevState) => ({ |
||||
|
...prevState, |
||||
|
type: "error", |
||||
|
title: "点击进行校验", |
||||
|
})); |
||||
|
} |
||||
|
setTimeout(() => { |
||||
|
clear(); |
||||
|
fetchCaptcha(); |
||||
|
}, 1000); |
||||
|
}) |
||||
|
.catch(() => { |
||||
|
setTimeout(() => { |
||||
|
clear(); |
||||
|
fetchCaptcha(); |
||||
|
}, 1000); |
||||
|
}); |
||||
|
}, |
||||
|
[api.checkCaptcha, setData, state, setState, setOpen, innerKey, onChange, fetchCaptcha], |
||||
|
); |
||||
|
|
||||
|
useImperativeHandle(ref, () => { |
||||
|
return { |
||||
|
reset() { |
||||
|
setState((prevState) => ({ |
||||
|
...prevState, |
||||
|
type: "default", |
||||
|
title: "点击进行校验", |
||||
|
})); |
||||
|
setKey(undefined); |
||||
|
onChange?.(undefined); |
||||
|
refresh(); |
||||
|
}, |
||||
|
}; |
||||
|
}, [fetchCaptcha, setState, setKey]); |
||||
|
|
||||
|
useEffect(() => { |
||||
|
if (open) { |
||||
|
fetchCaptcha(); |
||||
} |
} |
||||
|
}, [open]); |
||||
|
|
||||
|
return ( |
||||
|
<div className={styles.container}> |
||||
|
<Popover |
||||
|
content={ |
||||
|
<GoCaptcha.Slide |
||||
|
config={{ |
||||
|
width: 300, |
||||
|
height: 217, |
||||
|
showTheme: false, |
||||
|
verticalPadding: 5, |
||||
|
horizontalPadding: 5, |
||||
|
...config, |
||||
|
}} |
||||
|
style={{ color: "red" }} |
||||
|
data={data!} |
||||
|
events={{ |
||||
|
refresh, |
||||
|
confirm, |
||||
|
close: () => { |
||||
|
setOpen(false); |
||||
|
}, |
||||
|
}} |
||||
|
/> |
||||
|
} |
||||
|
open={open} |
||||
|
onOpenChange={setOpen} |
||||
|
forceRender={true} |
||||
|
trigger="click" |
||||
|
> |
||||
|
<GoCaptcha.Button |
||||
|
title={"点击进行校验"} |
||||
|
{...state} |
||||
|
clickEvent={() => { |
||||
|
setOpen(true); |
||||
|
}} |
||||
|
/> |
||||
|
</Popover> |
||||
|
</div> |
||||
|
); |
||||
|
}, |
||||
|
); |
||||
|
|
||||
}) |
|
||||
|
|
||||
|
|
||||
}, [ api.getCaptcha, setData ]) |
|
||||
|
|
||||
const refresh = useCallback(() => { |
|
||||
fetchCaptcha() |
|
||||
}, [ fetchCaptcha ]) |
|
||||
|
|
||||
const confirm = useCallback((point: SlidePoint, clear: (fn?: any) => void) => { |
|
||||
|
|
||||
api.checkCaptcha({ |
|
||||
point: [ point.x, point.y ].join(','), |
|
||||
key: innerKey! |
|
||||
}).then(res => { |
|
||||
// console.log(res)
|
|
||||
if (res.code === 0 && res.data.is_ok) { |
|
||||
message.success(`验证成功`) |
|
||||
|
|
||||
//验证成功,onChange通知出去,外部需要key做为校验
|
|
||||
onChange?.(innerKey) |
|
||||
|
|
||||
setState(prevState => ({ |
|
||||
...prevState, type: 'success', title: '校验成功', |
|
||||
})) |
|
||||
setOpen(false) |
|
||||
} else { |
|
||||
message.error('验证失败') |
|
||||
setState(prevState => ({ |
|
||||
...prevState, type: 'error', title: '点击进行校验', |
|
||||
})) |
|
||||
} |
|
||||
setTimeout(() => { |
|
||||
clear() |
|
||||
fetchCaptcha() |
|
||||
}, 1000) |
|
||||
|
|
||||
}).catch(() => { |
|
||||
setTimeout(() => { |
|
||||
clear() |
|
||||
fetchCaptcha() |
|
||||
}, 1000) |
|
||||
}) |
|
||||
|
|
||||
}, [ api.checkCaptcha, setData, state, setState, setOpen, innerKey, onChange, fetchCaptcha ]) |
|
||||
|
|
||||
useImperativeHandle(ref, () => { |
|
||||
return { |
|
||||
reset() { |
|
||||
setState(prevState => ({ |
|
||||
...prevState, type: 'default', title: '点击进行校验', |
|
||||
})) |
|
||||
setKey(undefined) |
|
||||
onChange?.(undefined) |
|
||||
refresh() |
|
||||
} |
|
||||
} |
|
||||
}, [ fetchCaptcha, setState, setKey ]) |
|
||||
|
|
||||
useEffect(() => { |
|
||||
|
|
||||
if (open) { |
|
||||
fetchCaptcha() |
|
||||
} |
|
||||
|
|
||||
}, [ open ]) |
|
||||
|
|
||||
return ( |
|
||||
<div className={styles.container}> |
|
||||
<Popover |
|
||||
content={ |
|
||||
<GoCaptcha.Slide |
|
||||
config={{ |
|
||||
width: 300, |
|
||||
height: 217, |
|
||||
showTheme: false, |
|
||||
verticalPadding: 5, |
|
||||
horizontalPadding: 5, |
|
||||
...config, |
|
||||
}} |
|
||||
style={{ color: 'red' }} |
|
||||
data={data!} |
|
||||
events={{ |
|
||||
refresh, |
|
||||
confirm, |
|
||||
close: () => { |
|
||||
setOpen(false) |
|
||||
} |
|
||||
}} |
|
||||
/> |
|
||||
} |
|
||||
open={open} |
|
||||
onOpenChange={setOpen} |
|
||||
forceRender={true} |
|
||||
trigger="click"> |
|
||||
<GoCaptcha.Button |
|
||||
title={'点击进行校验'} |
|
||||
{...state} |
|
||||
clickEvent={ |
|
||||
() => { |
|
||||
setOpen(true) |
|
||||
} |
|
||||
}/> |
|
||||
</Popover> |
|
||||
</div> |
|
||||
) |
|
||||
}) |
|
||||
|
|
||||
export default memo(SlideCapt) |
|
||||
|
export default memo(SlideCapt); |
@ -1,261 +1,281 @@ |
|||||
import { Layout, Tabs, Input, Button, Typography, Row, Col, Form } from 'antd' |
|
||||
import { QrcodeOutlined, UserOutlined, LockOutlined } from '@ant-design/icons' |
|
||||
import SelectLang from '@/components/select-lang' |
|
||||
import { createFileRoute, useNavigate } from '@tanstack/react-router' |
|
||||
import { useAtom, useAtomValue } from 'jotai' |
|
||||
import { useTranslation } from '@/i18n.ts' |
|
||||
|
import { Layout, Tabs, Input, Button, Typography, Row, Col, Form } from "antd"; |
||||
|
import { QrcodeOutlined, UserOutlined, LockOutlined } from "@ant-design/icons"; |
||||
|
import SelectLang from "@/components/select-lang"; |
||||
|
import { createFileRoute, useNavigate } from "@tanstack/react-router"; |
||||
|
import { useAtom, useAtomValue } from "jotai"; |
||||
|
import { useTranslation } from "@/i18n.ts"; |
||||
import { |
import { |
||||
emailCodeAtom, |
emailCodeAtom, |
||||
emailLoginAtom, |
emailLoginAtom, |
||||
telegramCodeAtom, |
telegramCodeAtom, |
||||
telegramLoginAtom, |
telegramLoginAtom, |
||||
upLoginAtom, |
upLoginAtom, |
||||
} from '@/store/system/user.ts' |
|
||||
import React, { memo, useEffect, useLayoutEffect, useRef, useState } from 'react' |
|
||||
import systemServ from '@/service/system.ts' |
|
||||
import SlideCapt, { SlideCaptRef } from '@/components/captcha/SlideCapt.tsx' |
|
||||
|
} from "@/store/system/user.ts"; |
||||
|
import React, { memo, useEffect, useLayoutEffect, useRef, useState } from "react"; |
||||
|
import systemServ from "@/service/system.ts"; |
||||
|
import SlideCapt, { SlideCaptRef } from "@/components/captcha/SlideCapt.tsx"; |
||||
|
import { t } from "i18next"; |
||||
|
|
||||
const { Title, Text, Link } = Typography |
|
||||
const { TabPane } = Tabs |
|
||||
|
const { Title, Text, Link } = Typography; |
||||
|
const { TabPane } = Tabs; |
||||
|
|
||||
const Login = memo(() => { |
const Login = memo(() => { |
||||
const navigate = useNavigate() |
|
||||
const [ upform ] = Form.useForm() |
|
||||
const [ emailform ] = Form.useForm() |
|
||||
const [ telegramform ] = Form.useForm() |
|
||||
const { mutate: upLoginFun } = useAtomValue(upLoginAtom) |
|
||||
const [ emailCodeData, setEmailCodeData ] = useState({}) |
|
||||
const { mutate: emailLoginMutate } = useAtomValue(emailLoginAtom) |
|
||||
const { mutate: telegramLoginMutate } = useAtomValue(telegramLoginAtom) |
|
||||
|
const languageSet = { |
||||
|
向量检索服务免费试用: t("login.vectorRetrievalServiceFreeTrial", "向量检索服务免费试用"), |
||||
|
免费试用向量检索服务玩转大模型生成式检索: t( |
||||
|
"login.freeTrialVectorRetrievalService", |
||||
|
"免费试用向量检索服务,玩转大模型生成式检索", |
||||
|
), |
||||
|
查看详情: t("login.viewDetails", "查看详情 >"), |
||||
|
请输入邮箱: t("login.pleaseEnterEmail", "请输入邮箱"), |
||||
|
获得验证码: t("login.getVerificationCode", "获得验证码"), |
||||
|
秒后重试: t("login.retryAfterSeconds", "秒后重试"), |
||||
|
请输入验证码: t("login.pleaseEnterVerificationCode", "请输入验证码"), |
||||
|
请输入登录密码: t("login.pleaseEnterPassword", "请输入登录密码"), |
||||
|
点击进行校验: t("login.clickToVerify", "点击进行校验"), |
||||
|
登录: t("login.login", "登录"), |
||||
|
注册: t("login.register", "注册"), |
||||
|
忘记密码: t("login.forgotPassword", "忘记密码"), |
||||
|
邮箱密码登录: t("login.emailPasswordLogin", "邮箱密码登录"), |
||||
|
邮箱验证登录: t("login.emailVerificationLogin", "邮箱验证登录"), |
||||
|
飞机验证登录: t("login.telegramVerificationLogin", "飞机验证登录"), |
||||
|
}; |
||||
|
|
||||
const slideCaptRef = useRef<SlideCaptRef>() |
|
||||
|
const navigate = useNavigate(); |
||||
|
const [upform] = Form.useForm(); |
||||
|
const [emailform] = Form.useForm(); |
||||
|
const [telegramform] = Form.useForm(); |
||||
|
const { mutate: upLoginFun } = useAtomValue(upLoginAtom); |
||||
|
const [emailCodeData, setEmailCodeData] = useState({}); |
||||
|
const { mutate: emailLoginMutate } = useAtomValue(emailLoginAtom); |
||||
|
const { mutate: telegramLoginMutate } = useAtomValue(telegramLoginAtom); |
||||
|
|
||||
|
const slideCaptRef = useRef<SlideCaptRef>(); |
||||
|
|
||||
const uphandleSubmit = (values: any) => { |
const uphandleSubmit = (values: any) => { |
||||
console.log(values) |
|
||||
upLoginFun(values) |
|
||||
} |
|
||||
|
console.log(values); |
||||
|
upLoginFun(values); |
||||
|
}; |
||||
|
|
||||
const getEmailCode = async () => { |
const getEmailCode = async () => { |
||||
const email = emailform.getFieldValue('email') |
|
||||
const result = await systemServ.emailCode({ is_register: false, email }) |
|
||||
setEmailCodeData(result) |
|
||||
} |
|
||||
|
const email = emailform.getFieldValue("email"); |
||||
|
const result = await systemServ.emailCode({ is_register: false, email }); |
||||
|
setEmailCodeData(result); |
||||
|
}; |
||||
const emailhandleSubmit = (values: any) => { |
const emailhandleSubmit = (values: any) => { |
||||
emailLoginMutate(values) |
|
||||
} |
|
||||
|
emailLoginMutate(values); |
||||
|
}; |
||||
|
|
||||
const getTelegramCode = async () => { |
const getTelegramCode = async () => { |
||||
const telegram = telegramform.getFieldValue('telegram') |
|
||||
const result = await systemServ.telegramCode({ telegram }) |
|
||||
setEmailCodeData(result) |
|
||||
} |
|
||||
|
const telegram = telegramform.getFieldValue("telegram"); |
||||
|
const result = await systemServ.telegramCode({ telegram }); |
||||
|
setEmailCodeData(result); |
||||
|
}; |
||||
const telegramhandleSubmit = (values: any) => { |
const telegramhandleSubmit = (values: any) => { |
||||
telegramLoginMutate(values) |
|
||||
} |
|
||||
|
telegramLoginMutate(values); |
||||
|
}; |
||||
|
|
||||
const [ countdown, setCountdown ] = useState<number>(() => { |
|
||||
const savedCountdown = localStorage.getItem('countdown') |
|
||||
return savedCountdown !== null ? Number(savedCountdown) : 0 |
|
||||
}) |
|
||||
|
const [countdown, setCountdown] = useState<number>(() => { |
||||
|
const savedCountdown = localStorage.getItem("countdown"); |
||||
|
return savedCountdown !== null ? Number(savedCountdown) : 0; |
||||
|
}); |
||||
|
|
||||
const [ isButtonDisabled, setIsButtonDisabled ] = useState<boolean>(() => { |
|
||||
const savedIsButtonDisabled = localStorage.getItem('isButtonDisabled') |
|
||||
return savedIsButtonDisabled !== null ? JSON.parse(savedIsButtonDisabled) : false |
|
||||
}) |
|
||||
|
const [isButtonDisabled, setIsButtonDisabled] = useState<boolean>(() => { |
||||
|
const savedIsButtonDisabled = localStorage.getItem("isButtonDisabled"); |
||||
|
return savedIsButtonDisabled !== null ? JSON.parse(savedIsButtonDisabled) : false; |
||||
|
}); |
||||
|
|
||||
useEffect(() => { |
useEffect(() => { |
||||
localStorage.setItem('isButtonDisabled', JSON.stringify(isButtonDisabled)) |
|
||||
}, [ isButtonDisabled ]) |
|
||||
|
localStorage.setItem("isButtonDisabled", JSON.stringify(isButtonDisabled)); |
||||
|
}, [isButtonDisabled]); |
||||
|
|
||||
useEffect(() => { |
useEffect(() => { |
||||
if ((emailCodeData as any)?.code === 0) { |
if ((emailCodeData as any)?.code === 0) { |
||||
setCountdown(10) |
|
||||
setIsButtonDisabled(true) |
|
||||
|
setCountdown(10); |
||||
|
setIsButtonDisabled(true); |
||||
} |
} |
||||
}, [ emailCodeData ]) |
|
||||
|
}, [emailCodeData]); |
||||
|
|
||||
useEffect(() => { |
useEffect(() => { |
||||
let timer: number |
|
||||
|
let timer: number; |
||||
if (countdown > 0) { |
if (countdown > 0) { |
||||
timer = setTimeout(() => setCountdown(countdown - 1), 1000) |
|
||||
|
timer = setTimeout(() => setCountdown(countdown - 1), 1000); |
||||
} else { |
} else { |
||||
setIsButtonDisabled(false) |
|
||||
|
setIsButtonDisabled(false); |
||||
} |
} |
||||
localStorage.setItem('countdown', String(countdown)) |
|
||||
return () => clearTimeout(timer) |
|
||||
}, [ countdown ]) |
|
||||
|
localStorage.setItem("countdown", String(countdown)); |
||||
|
return () => clearTimeout(timer); |
||||
|
}, [countdown]); |
||||
|
|
||||
useLayoutEffect(() => { |
useLayoutEffect(() => { |
||||
document.body.className = 'login' |
|
||||
|
document.body.className = "login"; |
||||
return () => { |
return () => { |
||||
document.body.className = document.body.className.replace('login', '') |
|
||||
} |
|
||||
}, []) |
|
||||
|
document.body.className = document.body.className.replace("login", ""); |
||||
|
}; |
||||
|
}, []); |
||||
|
|
||||
return ( |
return ( |
||||
<Layout |
|
||||
style={{ |
|
||||
height: '100vh', |
|
||||
background: 'url(\'https://placehold.co/1920x1080\') no-repeat center center', |
|
||||
backgroundSize: 'cover', |
|
||||
}} |
|
||||
> |
|
||||
<Row justify="center" align="middle" style={{ height: '100%' }}> |
|
||||
<Col> |
|
||||
<Row> |
|
||||
<Col span={12} style={{ padding: '20px' }}> |
|
||||
<Title level={3}>向量检索服务免费试用</Title> |
|
||||
<Text>免费试用向量检索服务,玩转大模型生成式检索</Text> |
|
||||
<br/> |
|
||||
<Link href="#">查看详情 ></Link> |
|
||||
</Col> |
|
||||
<Col |
|
||||
span={12} |
|
||||
style={{ |
|
||||
padding: '20px', |
|
||||
background: '#fff', |
|
||||
borderRadius: '8px', |
|
||||
position: 'relative', |
|
||||
width: '500px', |
|
||||
height: '400px', |
|
||||
}} |
|
||||
> |
|
||||
<Tabs defaultActiveKey="1" |
|
||||
onChange={(key) => { |
|
||||
if (key === '1') { |
|
||||
slideCaptRef.current?.reset() |
|
||||
} |
|
||||
}} |
|
||||
style={{ marginTop: '50px' }}> |
|
||||
<TabPane tab="邮箱密码登录" key="1"> |
|
||||
<Form form={upform} onFinish={uphandleSubmit}> |
|
||||
<Form.Item name="username" rules={[ { required: true, message: '请输入邮箱' } ]}> |
|
||||
<Input size="large" placeholder="请输入邮箱" prefix={<UserOutlined/>}/> |
|
||||
</Form.Item> |
|
||||
<Form.Item name="password" rules={[ { required: true, message: '请输入登录密码' } ]}> |
|
||||
<Input.Password |
|
||||
size="large" |
|
||||
placeholder="请输入登录密码" |
|
||||
prefix={<LockOutlined/>} |
|
||||
autoComplete="off" |
|
||||
/> |
|
||||
</Form.Item> |
|
||||
<Form.Item name={'captchaKey'} |
|
||||
rules={[ { required: true, message: '点击进行校验' } ]}> |
|
||||
|
|
||||
<SlideCapt |
|
||||
ref={slideCaptRef} |
|
||||
api={{ |
|
||||
getCaptcha: systemServ.captcha, |
|
||||
checkCaptcha: systemServ.captchaCheck |
|
||||
}}/> |
|
||||
</Form.Item> |
|
||||
{/*<Form.Item name="code" rules={[{ required: true, message: "请输入验证码" }]}>*/} |
|
||||
{/* <Input.Password size="large" placeholder="验证码" prefix={<LockOutlined />} />*/} |
|
||||
{/*</Form.Item>*/} |
|
||||
<Button type="primary" htmlType="submit" style={{ width: '100%' }}> |
|
||||
登录 |
|
||||
</Button> |
|
||||
</Form> |
|
||||
</TabPane> |
|
||||
<TabPane tab="邮箱验证登录" key="2"> |
|
||||
<Form form={emailform} onFinish={emailhandleSubmit}> |
|
||||
<Form.Item name="email" rules={[ { required: true, message: '请输入邮箱' } ]}> |
|
||||
<Input |
|
||||
size="large" |
|
||||
placeholder="请输入邮箱" |
|
||||
prefix={<UserOutlined/>} |
|
||||
addonAfter={ |
|
||||
<Button onClick={getEmailCode} disabled={isButtonDisabled}> |
|
||||
{isButtonDisabled ? `${countdown}秒后重试` : '获得验证码'} |
|
||||
</Button> |
|
||||
} |
|
||||
/> |
|
||||
</Form.Item> |
|
||||
<Form.Item name="code" rules={[ { required: true, message: '请输入验证码' } ]}> |
|
||||
<Input.Password |
|
||||
size="large" |
|
||||
placeholder="请输入验证码" |
|
||||
prefix={<LockOutlined/>} |
|
||||
autoComplete="off" |
|
||||
/> |
|
||||
</Form.Item> |
|
||||
<Button type="primary" htmlType="submit" style={{ width: '100%' }}> |
|
||||
登录 |
|
||||
|
<Layout |
||||
|
style={{ |
||||
|
height: "100vh", |
||||
|
background: "url('https://placehold.co/1920x1080') no-repeat center center", |
||||
|
backgroundSize: "cover", |
||||
|
}} |
||||
|
> |
||||
|
<Row justify="center" align="middle" style={{ height: "100%" }}> |
||||
|
<Col> |
||||
|
<Row> |
||||
|
<Col span={12} style={{ padding: "20px" }}> |
||||
|
<Title level={3}>{languageSet.向量检索服务免费试用}</Title> |
||||
|
<Text>{languageSet.免费试用向量检索服务玩转大模型生成式检索}</Text> |
||||
|
<br /> |
||||
|
<Link href="#">{languageSet.查看详情}</Link> |
||||
|
</Col> |
||||
|
<Col |
||||
|
span={12} |
||||
|
style={{ |
||||
|
padding: "20px", |
||||
|
background: "#fff", |
||||
|
borderRadius: "8px", |
||||
|
position: "relative", |
||||
|
width: "500px", |
||||
|
height: "400px", |
||||
|
}} |
||||
|
> |
||||
|
<Tabs |
||||
|
defaultActiveKey="1" |
||||
|
onChange={(key) => { |
||||
|
if (key === "1") { |
||||
|
slideCaptRef.current?.reset(); |
||||
|
} |
||||
|
}} |
||||
|
style={{ marginTop: "50px" }} |
||||
|
> |
||||
|
<TabPane tab={languageSet.邮箱密码登录} key="1"> |
||||
|
<Form form={upform} onFinish={uphandleSubmit}> |
||||
|
<Form.Item name="username" rules={[{ required: true, message: languageSet.请输入邮箱 }]}> |
||||
|
<Input size="large" placeholder={languageSet.请输入邮箱} prefix={<UserOutlined />} /> |
||||
|
</Form.Item> |
||||
|
<Form.Item name="password" rules={[{ required: true, message: languageSet.请输入登录密码 }]}> |
||||
|
<Input.Password |
||||
|
size="large" |
||||
|
placeholder={languageSet.请输入登录密码} |
||||
|
prefix={<LockOutlined />} |
||||
|
autoComplete="off" |
||||
|
/> |
||||
|
</Form.Item> |
||||
|
<Form.Item name={"captchaKey"} rules={[{ required: true, message: languageSet.点击进行校验 }]}> |
||||
|
<SlideCapt |
||||
|
ref={slideCaptRef} |
||||
|
api={{ |
||||
|
getCaptcha: systemServ.captcha, |
||||
|
checkCaptcha: systemServ.captchaCheck, |
||||
|
}} |
||||
|
/> |
||||
|
</Form.Item> |
||||
|
<Button type="primary" htmlType="submit" style={{ width: "100%" }}> |
||||
|
{languageSet.登录} |
||||
|
</Button> |
||||
|
</Form> |
||||
|
</TabPane> |
||||
|
<TabPane tab={languageSet.邮箱验证登录} key="2"> |
||||
|
<Form form={emailform} onFinish={emailhandleSubmit}> |
||||
|
<Form.Item name="email" rules={[{ required: true, message: languageSet.请输入邮箱 }]}> |
||||
|
<Input |
||||
|
size="large" |
||||
|
placeholder={languageSet.请输入邮箱} |
||||
|
prefix={<UserOutlined />} |
||||
|
addonAfter={ |
||||
|
<Button onClick={getEmailCode} disabled={isButtonDisabled}> |
||||
|
{isButtonDisabled ? `${countdown}${languageSet.秒后重试}` : languageSet.获得验证码} |
||||
</Button> |
</Button> |
||||
</Form> |
|
||||
</TabPane> |
|
||||
<TabPane tab="飞机验证登录" key="3"> |
|
||||
<Form form={telegramform} onFinish={telegramhandleSubmit}> |
|
||||
<Form.Item name="telegram" rules={[ { required: true, message: '请输入邮箱' } ]}> |
|
||||
<Input |
|
||||
size="large" |
|
||||
placeholder="请输入邮箱" |
|
||||
prefix={<UserOutlined/>} |
|
||||
addonAfter={ |
|
||||
<Button onClick={getTelegramCode} disabled={isButtonDisabled}> |
|
||||
{isButtonDisabled ? `${countdown}秒后重试` : '获得飞机验证码'} |
|
||||
</Button> |
|
||||
} |
|
||||
/> |
|
||||
</Form.Item> |
|
||||
<Form.Item name="code" rules={[ { required: true, message: '请输入飞机验证码' } ]}> |
|
||||
<Input.Password |
|
||||
size="large" |
|
||||
placeholder="请输入飞机验证码" |
|
||||
prefix={<LockOutlined/>} |
|
||||
autoComplete="off" |
|
||||
/> |
|
||||
</Form.Item> |
|
||||
<Button type="primary" htmlType="submit" style={{ width: '100%' }}> |
|
||||
登录 |
|
||||
|
} |
||||
|
/> |
||||
|
</Form.Item> |
||||
|
<Form.Item name="code" rules={[{ required: true, message: languageSet.请输入验证码 }]}> |
||||
|
<Input.Password |
||||
|
size="large" |
||||
|
placeholder={languageSet.请输入验证码} |
||||
|
prefix={<LockOutlined />} |
||||
|
autoComplete="off" |
||||
|
/> |
||||
|
</Form.Item> |
||||
|
<Button type="primary" htmlType="submit" style={{ width: "100%" }}> |
||||
|
{languageSet.登录} |
||||
|
</Button> |
||||
|
</Form> |
||||
|
</TabPane> |
||||
|
<TabPane tab={languageSet.飞机验证登录} key="3"> |
||||
|
<Form form={telegramform} onFinish={telegramhandleSubmit}> |
||||
|
<Form.Item name="telegram" rules={[{ required: true, message: languageSet.请输入邮箱 }]}> |
||||
|
<Input |
||||
|
size="large" |
||||
|
placeholder={languageSet.请输入邮箱} |
||||
|
prefix={<UserOutlined />} |
||||
|
addonAfter={ |
||||
|
<Button onClick={getTelegramCode} disabled={isButtonDisabled}> |
||||
|
{isButtonDisabled ? `${countdown}${languageSet.秒后重试}` : languageSet.获得验证码} |
||||
</Button> |
</Button> |
||||
</Form> |
|
||||
</TabPane> |
|
||||
</Tabs> |
|
||||
<div |
|
||||
style={{ |
|
||||
position: 'absolute', |
|
||||
top: 0, |
|
||||
right: 0, |
|
||||
width: 0, |
|
||||
height: 0, |
|
||||
borderLeft: '80px solid transparent', |
|
||||
borderTop: '80px solid #ff9800', |
|
||||
textAlign: 'center', |
|
||||
}} |
|
||||
> |
|
||||
|
} |
||||
|
/> |
||||
|
</Form.Item> |
||||
|
<Form.Item name="code" rules={[{ required: true, message: languageSet.请输入验证码 }]}> |
||||
|
<Input.Password |
||||
|
size="large" |
||||
|
placeholder={languageSet.请输入验证码} |
||||
|
prefix={<LockOutlined />} |
||||
|
autoComplete="off" |
||||
|
/> |
||||
|
</Form.Item> |
||||
|
<Button type="primary" htmlType="submit" style={{ width: "100%" }}> |
||||
|
{languageSet.登录} |
||||
|
</Button> |
||||
|
</Form> |
||||
|
</TabPane> |
||||
|
</Tabs> |
||||
|
<div |
||||
|
style={{ |
||||
|
position: "absolute", |
||||
|
top: 0, |
||||
|
right: 0, |
||||
|
width: 0, |
||||
|
height: 0, |
||||
|
borderLeft: "80px solid transparent", |
||||
|
borderTop: "80px solid #ff9800", |
||||
|
textAlign: "center", |
||||
|
}} |
||||
|
> |
||||
<span |
<span |
||||
style={{ |
|
||||
position: 'absolute', |
|
||||
top: '-70px', |
|
||||
right: '0px', |
|
||||
color: '#fff', |
|
||||
fontSize: '16px', |
|
||||
transform: 'rotate(0deg)', |
|
||||
textAlign: 'center', |
|
||||
width: '60px', |
|
||||
display: 'block', |
|
||||
cursor: 'pointer', // 设置手型光标
|
|
||||
}} |
|
||||
onClick={() => navigate({ to: '/register' })} |
|
||||
|
style={{ |
||||
|
position: "absolute", |
||||
|
top: "-70px", |
||||
|
right: "0px", |
||||
|
color: "#fff", |
||||
|
fontSize: "16px", |
||||
|
transform: "rotate(0deg)", |
||||
|
textAlign: "center", |
||||
|
width: "60px", |
||||
|
display: "block", |
||||
|
cursor: "pointer", // 设置手型光标
|
||||
|
}} |
||||
|
onClick={() => navigate({ to: "/register" })} |
||||
> |
> |
||||
注册 |
|
||||
|
{languageSet.注册} |
||||
</span> |
</span> |
||||
</div> |
|
||||
<Row justify="space-between" style={{ marginTop: '10px' }}> |
|
||||
<Link onClick={() => navigate({ to: '/pwdRetrieve' })}>忘记密码</Link> |
|
||||
</Row> |
|
||||
</Col> |
|
||||
</Row> |
|
||||
</Col> |
|
||||
</Row> |
|
||||
</Layout> |
|
||||
) |
|
||||
}) |
|
||||
|
</div> |
||||
|
<Row justify="space-between" style={{ marginTop: "10px" }}> |
||||
|
<Link onClick={() => navigate({ to: "/pwdRetrieve" })}>{languageSet.忘记密码}</Link> |
||||
|
</Row> |
||||
|
</Col> |
||||
|
</Row> |
||||
|
</Col> |
||||
|
</Row> |
||||
|
</Layout> |
||||
|
); |
||||
|
}); |
||||
|
|
||||
export const Route = createFileRoute('/login')({ |
|
||||
|
export const Route = createFileRoute("/login")({ |
||||
component: Login, |
component: Login, |
||||
}) |
|
||||
|
}); |
||||
|
|
||||
export default Login |
|
||||
|
export default Login; |
Write
Preview
Loading…
Cancel
Save
Reference in new issue