From bb2ad15619f6b03350c87ede97b04107bb01c870 Mon Sep 17 00:00:00 2001 From: lk Date: Sat, 14 Sep 2024 15:34:52 +0800 Subject: [PATCH] =?UTF-8?q?=E7=99=BB=E5=BD=95=20=E4=BF=AE=E6=94=B9=20=20?= =?UTF-8?q?=E6=B3=A8=E5=86=8C=20=20=20=E4=BA=BA=E6=9C=BA=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E5=8A=A0=E4=B8=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/captcha/SlideCapt.tsx | 307 ++++++++++++++++++----------------- src/pages/use/login/index.tsx | 49 +++++- src/pages/use/password/retrieve.tsx | 70 +++++--- src/pages/use/register/index.tsx | 34 +++- 4 files changed, 270 insertions(+), 190 deletions(-) diff --git a/src/components/captcha/SlideCapt.tsx b/src/components/captcha/SlideCapt.tsx index d77e149..086fb58 100644 --- a/src/components/captcha/SlideCapt.tsx +++ b/src/components/captcha/SlideCapt.tsx @@ -1,160 +1,163 @@ -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 { useStyle } from './style.ts' +import {Props} from "@/global"; export interface SlideCaptProps { api: { - getCaptcha: () => Promise; - checkCaptcha: (params: SlideCaptchaCheckData) => Promise; - }; - config?: SlideConfig; - value?: string; - onChange?: (value?: string) => void; + getCaptcha: () => Promise, + checkCaptcha: (params: SlideCaptchaCheckData) => Promise, + }, + config?: SlideConfig + value?: string + onChange?: (value?: string) => void } export type SlideCaptRef = { - reset: () => void; -}; - -const SlideCapt = forwardRef( - ({ config, api, value, onChange }: SlideCaptProps, ref) => { - const { styles } = useStyle(); - const [open, setOpen] = useState(false); - const [state, setState] = useState({}); - const [data, setData] = useState(); - 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(); + reset: () => void +} + + +const SlideCapt = forwardRef(( + { + config, + api, + value, + onChange, + }: SlideCaptProps, ref) => { + + const { styles } = useStyle() + const [ open, setOpen ] = useState(false) + const [ state, setState ] = useState({}) + const [ data, setData ] = useState() + 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, + }) } - }, [open]); - - return ( -
- { - setOpen(false); - }, - }} - /> - } - open={open} - onOpenChange={setOpen} - forceRender={true} - trigger="click" - > - { - setOpen(true); - }} - /> - -
- ); - }, -); -export default memo(SlideCapt); + }) + + + }, [ 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 ( +
+ { + setOpen(false) + } + }} + /> + } + open={open} + onOpenChange={setOpen} + forceRender={true} + trigger="click"> + { + setOpen(true) + } + }/> + +
+ ) +}) + +export default memo(SlideCapt) \ No newline at end of file diff --git a/src/pages/use/login/index.tsx b/src/pages/use/login/index.tsx index f48b2c2..cb06b6c 100644 --- a/src/pages/use/login/index.tsx +++ b/src/pages/use/login/index.tsx @@ -45,7 +45,7 @@ const Login = memo(() => { const [upform] = Form.useForm(); const [emailform] = Form.useForm(); const [telegramform] = Form.useForm(); - const { mutate: upLoginFun } = useAtomValue(upLoginAtom); + const { mutate: upLoginMutate } = useAtomValue(upLoginAtom); const [emailCodeData, setEmailCodeData] = useState({}); const { mutate: emailLoginMutate } = useAtomValue(emailLoginAtom); const { mutate: telegramLoginMutate } = useAtomValue(telegramLoginAtom); @@ -54,22 +54,37 @@ const Login = memo(() => { const uphandleSubmit = (values: any) => { console.log(values); - upLoginFun(values); + upLoginMutate(values); }; const getEmailCode = async () => { - const email = emailform.getFieldValue("email"); - const result = await systemServ.emailCode({ is_register: false, email }); - setEmailCodeData(result); + try { + // 验证邮箱和滑动验证码 + await emailform.validateFields(["email", "captchaKey"]); + + const email = emailform.getFieldValue("email"); + const captchaKey = emailform.getFieldValue("captchaKey"); + const result = await systemServ.emailCode({ is_register: false, email, captchaKey }); + setEmailCodeData(result); + } catch (error) { + /* empty */ + } }; const emailhandleSubmit = (values: any) => { emailLoginMutate(values); }; const getTelegramCode = async () => { - const telegram = telegramform.getFieldValue("telegram"); - const result = await systemServ.telegramCode({ telegram }); - setEmailCodeData(result); + try { + // 验证邮箱和滑动验证码 + await telegramform.validateFields(["telegram", "captchaKey"]); + const telegram = telegramform.getFieldValue("telegram"); + const captchaKey = telegramform.getFieldValue("captchaKey"); + const result = await systemServ.telegramCode({ telegram, captchaKey }); + setEmailCodeData(result); + } catch (error) { + /* empty */ + } }; const telegramhandleSubmit = (values: any) => { telegramLoginMutate(values); @@ -200,6 +215,15 @@ const Login = memo(() => { autoComplete="off" /> + + + @@ -227,6 +251,15 @@ const Login = memo(() => { autoComplete="off" /> + + + diff --git a/src/pages/use/password/retrieve.tsx b/src/pages/use/password/retrieve.tsx index aa424f4..550b3de 100644 --- a/src/pages/use/password/retrieve.tsx +++ b/src/pages/use/password/retrieve.tsx @@ -1,54 +1,65 @@ import { Layout, Input, Button, Typography, Row, Col, Form, message, Modal } from "antd"; import { LockOutlined, MailOutlined, SecurityScanOutlined } from "@ant-design/icons"; import { createFileRoute, useNavigate } from "@tanstack/react-router"; -import React, { memo, useEffect, useState } from "react"; +import React, { memo, useEffect, useRef, useState } from "react"; import { passwordRules } from "@/pages/use/useTools.tsx"; import systemServ from "@/service/system.ts"; import { t } from "i18next"; - -const languageSet = { - 向量检索服务免费试用: t("pwdRetrieve.vectorRetrievalServiceFreeTrial", "向量检索服务免费试用"), - 免费试用向量检索服务玩转大模型生成式检索: t( - "pwdRetrieve.freeTrialVectorRetrievalService", - "免费试用向量检索服务,玩转大模型生成式检索", - ), - 查看详情: t("pwdRetrieve.viewDetails", "查看详情 >"), - 请输入邮箱: t("pwdRetrieve.pleaseEnterEmail", "请输入邮箱"), - 获得验证码: t("pwdRetrieve.getVerificationCode", "获得验证码"), - 秒后重试: t("pwdRetrieve.retryAfterSeconds", "秒后重试"), - 请输入验证码: t("pwdRetrieve.pleaseEnterVerificationCode", "请输入验证码"), - 请输入新密码: t("pwdRetrieve.pleaseEnterNewPassword", "请输入新密码"), - 请确认密码: t("pwdRetrieve.confirmPassword", "请确认密码"), - 两次输入的密码不一致: t("pwdRetrieve.passwordsDoNotMatch", "两次输入的密码不一致"), - 找回密码: t("pwdRetrieve.retrievePassword", "找回密码"), - 返回登录: t("pwdRetrieve.backToLogin", "返回登录"), - 修改成功: t("pwdRetrieve.changeSuccess", "修改成功"), - 确认: t("pwdRetrieve.confirm", "确认"), - 密码修改成功返回登录: t("pwdRetrieve.passwordChangeSuccess", "密码修改成功,返回登录。"), -}; +import SlideCapt, { SlideCaptRef } from "@/components/captcha/SlideCapt.tsx"; const { Title, Text, Link } = Typography; const PwdRetrieve = memo(() => { + const languageSet = { + 向量检索服务免费试用: t("pwdRetrieve.vectorRetrievalServiceFreeTrial", "向量检索服务免费试用"), + 免费试用向量检索服务玩转大模型生成式检索: t( + "pwdRetrieve.freeTrialVectorRetrievalService", + "免费试用向量检索服务,玩转大模型生成式检索", + ), + 查看详情: t("pwdRetrieve.viewDetails", "查看详情 >"), + 请输入邮箱: t("pwdRetrieve.pleaseEnterEmail", "请输入邮箱"), + 获得验证码: t("pwdRetrieve.getVerificationCode", "获得验证码"), + 秒后重试: t("pwdRetrieve.retryAfterSeconds", "秒后重试"), + 请输入验证码: t("pwdRetrieve.pleaseEnterVerificationCode", "请输入验证码"), + 请输入新密码: t("pwdRetrieve.pleaseEnterNewPassword", "请输入新密码"), + 请确认密码: t("pwdRetrieve.confirmPassword", "请确认密码"), + 两次输入的密码不一致: t("pwdRetrieve.passwordsDoNotMatch", "两次输入的密码不一致"), + 点击进行校验: t("login.clickToVerify", "点击进行校验"), + 找回密码: t("pwdRetrieve.retrievePassword", "找回密码"), + 返回登录: t("pwdRetrieve.backToLogin", "返回登录"), + 修改成功: t("pwdRetrieve.changeSuccess", "修改成功"), + 确认: t("pwdRetrieve.confirm", "确认"), + 密码修改成功返回登录: t("pwdRetrieve.passwordChangeSuccess", "密码修改成功,返回登录。"), + }; + const navigate = useNavigate(); const [retrieveForm] = Form.useForm(); const [emailCodeData, setEmailCodeData] = useState({}); const [pwdRetrieveData, setPwdRetrieveData] = useState({}); + const slideCaptRef = useRef(); const handleRetrieveSubmit = async (values: any) => { const param = { email: values.email, password: values.password, code: values.code, + captchaKey: values.captchaKey, }; const result = await systemServ.pwdRetrieve(param); setPwdRetrieveData(result); }; const handleGetCode = async () => { - const email = retrieveForm.getFieldValue("email"); - const result = await systemServ.emailCode({ is_register: false, email }); - setEmailCodeData(result); + try { + // 验证邮箱和滑动验证码 + await retrieveForm.validateFields(["email", "captchaKey"]); + const email = retrieveForm.getFieldValue("email"); + const captchaKey = retrieveForm.getFieldValue("captchaKey"); + const result = await systemServ.emailCode({ is_register: false, email, captchaKey }); + setEmailCodeData(result); + } catch (errorInfo) { + /* empty */ + } }; const [countdown, setCountdown] = useState(0); @@ -174,6 +185,15 @@ const PwdRetrieve = memo(() => { autoComplete="off" /> + + + diff --git a/src/pages/use/register/index.tsx b/src/pages/use/register/index.tsx index 45690f7..5018999 100644 --- a/src/pages/use/register/index.tsx +++ b/src/pages/use/register/index.tsx @@ -2,11 +2,12 @@ import { Layout, Input, Button, Typography, Row, Col, Form } from "antd"; import { LockOutlined, MailOutlined, SecurityScanOutlined } from "@ant-design/icons"; import { createFileRoute, useNavigate } from "@tanstack/react-router"; import { useAtomValue } from "jotai"; -import React, { memo, useEffect, useState } from "react"; +import React, { memo, useEffect, useRef, useState } from "react"; import { emailRegisterAtom } from "@/store/system/user.ts"; import { passwordRules } from "@/pages/use/useTools"; import systemServ from "@/service/system.ts"; import { t } from "i18next"; +import SlideCapt, { SlideCaptRef } from "@/components/captcha/SlideCapt.tsx"; const languageSet = { 向量检索服务免费试用: t("register.vectorRetrievalServiceFreeTrial", "向量检索服务免费试用"), @@ -22,6 +23,7 @@ const languageSet = { 请输入密码: t("register.pleaseEnterPassword", "请输入密码"), 请确认密码: t("register.confirmPassword", "请确认密码"), 两次输入的密码不一致: t("register.passwordsDoNotMatch", "两次输入的密码不一致"), + 点击进行校验: t("login.clickToVerify", "点击进行校验"), 注册: t("register.register", "注册"), 登录: t("register.login", "登录"), 返回登录: t("register.backToLogin", "返回登录"), @@ -36,15 +38,28 @@ const Register = memo(() => { const [countdown, setCountdown] = useState(10); const [emailCodeData, setEmailCodeData] = useState({}); const [isButtonDisabled, setIsButtonDisabled] = useState(false); + const slideCaptRef = useRef(); const getEmailCode = async () => { - const email = registerForm.getFieldValue("email"); - const result = await systemServ.emailCode({ is_register: true, email }); - setEmailCodeData(result); + try { + // 验证邮箱和滑动验证码 + await registerForm.validateFields(["email", "captchaKey"]); + const email = registerForm.getFieldValue("email"); + const captchaKey = registerForm.getFieldValue("captchaKey"); + const result = await systemServ.emailCode({ is_register: true, email, captchaKey }); + setEmailCodeData(result); + } catch (errorInfo) { + /* empty */ + } }; const emailRegisterSubmit = (values: any) => { - emailRegisterMutate({ email: values.email, password: values.password, code: values.code }); + emailRegisterMutate({ + email: values.email, + password: values.password, + code: values.code, + captchaKey: values.captchaKey, + }); }; useEffect(() => { @@ -150,6 +165,15 @@ const Register = memo(() => { autoComplete="off" /> + + +