Browse Source

登录 修改 注册 人机接口加上

main
lk 6 days ago
parent
commit
bb2ad15619
  1. 203
      src/components/captcha/SlideCapt.tsx
  2. 41
      src/pages/use/login/index.tsx
  3. 34
      src/pages/use/password/retrieve.tsx
  4. 30
      src/pages/use/register/index.tsx

203
src/components/captcha/SlideCapt.tsx

@ -1,119 +1,123 @@
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 { 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;
};
reset: () => void
}
const SlideCapt = forwardRef<SlideCaptRef | undefined, SlideCaptProps>((
{
config,
api,
value,
onChange,
}: SlideCaptProps, ref) => {
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 { 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(() => { const fetchCaptcha = useCallback(() => {
return api.getCaptcha().then((res) => {
return api.getCaptcha().then(res => {
if (res.code === 0) { if (res.code === 0) {
const data = res.data;
setKey(data["captcha_key"] || "");
const data = res.data
setKey(data['captcha_key'] || '')
setData({ 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,
});
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) => {
}, [ 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) // console.log(res)
if (res.code === 0 && res.data.is_ok) { if (res.code === 0 && res.data.is_ok) {
message.success(`验证成功`);
message.success(`验证成功`)
//验证成功,onChange通知出去,外部需要key做为校验 //验证成功,onChange通知出去,外部需要key做为校验
onChange?.(innerKey);
setState((prevState) => ({
...prevState,
type: "success",
title: "校验成功",
}));
setOpen(false);
onChange?.(innerKey)
setState(prevState => ({
...prevState, type: 'success', title: '校验成功',
}))
setOpen(false)
} else { } else {
message.error("验证失败");
setState((prevState) => ({
...prevState,
type: "error",
title: "点击进行校验",
}));
message.error('验证失败')
setState(prevState => ({
...prevState, type: 'error', title: '点击进行校验',
}))
} }
setTimeout(() => { setTimeout(() => {
clear();
fetchCaptcha();
}, 1000);
})
.catch(() => {
clear()
fetchCaptcha()
}, 1000)
}).catch(() => {
setTimeout(() => { setTimeout(() => {
clear();
fetchCaptcha();
}, 1000);
});
},
[api.checkCaptcha, setData, state, setState, setOpen, innerKey, onChange, fetchCaptcha],
);
clear()
fetchCaptcha()
}, 1000)
})
}, [ api.checkCaptcha, setData, state, setState, setOpen, innerKey, onChange, fetchCaptcha ])
useImperativeHandle(ref, () => { useImperativeHandle(ref, () => {
return { return {
reset() { reset() {
setState((prevState) => ({
...prevState,
type: "default",
title: "点击进行校验",
}));
setKey(undefined);
onChange?.(undefined);
refresh();
},
};
}, [fetchCaptcha, setState, setKey]);
setState(prevState => ({
...prevState, type: 'default', title: '点击进行校验',
}))
setKey(undefined)
onChange?.(undefined)
refresh()
}
}
}, [ fetchCaptcha, setState, setKey ])
useEffect(() => { useEffect(() => {
if (open) { if (open) {
fetchCaptcha();
fetchCaptcha()
} }
}, [open]);
}, [ open ])
return ( return (
<div className={styles.container}> <div className={styles.container}>
@ -128,33 +132,32 @@ const SlideCapt = forwardRef<SlideCaptRef | undefined, SlideCaptProps>(
horizontalPadding: 5, horizontalPadding: 5,
...config, ...config,
}} }}
style={{ color: "red" }}
style={{ color: 'red' }}
data={data!} data={data!}
events={{ events={{
refresh, refresh,
confirm, confirm,
close: () => { close: () => {
setOpen(false);
},
setOpen(false)
}
}} }}
/> />
} }
open={open} open={open}
onOpenChange={setOpen} onOpenChange={setOpen}
forceRender={true} forceRender={true}
trigger="click"
>
trigger="click">
<GoCaptcha.Button <GoCaptcha.Button
title={"点击进行校验"}
title={'点击进行校验'}
{...state} {...state}
clickEvent={() => {
setOpen(true);
}}
/>
clickEvent={
() => {
setOpen(true)
}
}/>
</Popover> </Popover>
</div> </div>
);
},
);
)
})
export default memo(SlideCapt);
export default memo(SlideCapt)

41
src/pages/use/login/index.tsx

@ -45,7 +45,7 @@ const Login = memo(() => {
const [upform] = Form.useForm(); const [upform] = Form.useForm();
const [emailform] = Form.useForm(); const [emailform] = Form.useForm();
const [telegramform] = Form.useForm(); const [telegramform] = Form.useForm();
const { mutate: upLoginFun } = useAtomValue(upLoginAtom);
const { mutate: upLoginMutate } = useAtomValue(upLoginAtom);
const [emailCodeData, setEmailCodeData] = useState({}); const [emailCodeData, setEmailCodeData] = useState({});
const { mutate: emailLoginMutate } = useAtomValue(emailLoginAtom); const { mutate: emailLoginMutate } = useAtomValue(emailLoginAtom);
const { mutate: telegramLoginMutate } = useAtomValue(telegramLoginAtom); const { mutate: telegramLoginMutate } = useAtomValue(telegramLoginAtom);
@ -54,22 +54,37 @@ const Login = memo(() => {
const uphandleSubmit = (values: any) => { const uphandleSubmit = (values: any) => {
console.log(values); console.log(values);
upLoginFun(values);
upLoginMutate(values);
}; };
const getEmailCode = async () => { const getEmailCode = async () => {
try {
// 验证邮箱和滑动验证码
await emailform.validateFields(["email", "captchaKey"]);
const email = emailform.getFieldValue("email"); const email = emailform.getFieldValue("email");
const result = await systemServ.emailCode({ is_register: false, email });
const captchaKey = emailform.getFieldValue("captchaKey");
const result = await systemServ.emailCode({ is_register: false, email, captchaKey });
setEmailCodeData(result); setEmailCodeData(result);
} catch (error) {
/* empty */
}
}; };
const emailhandleSubmit = (values: any) => { const emailhandleSubmit = (values: any) => {
emailLoginMutate(values); emailLoginMutate(values);
}; };
const getTelegramCode = async () => { const getTelegramCode = async () => {
try {
// 验证邮箱和滑动验证码
await telegramform.validateFields(["telegram", "captchaKey"]);
const telegram = telegramform.getFieldValue("telegram"); const telegram = telegramform.getFieldValue("telegram");
const result = await systemServ.telegramCode({ telegram });
const captchaKey = telegramform.getFieldValue("captchaKey");
const result = await systemServ.telegramCode({ telegram, captchaKey });
setEmailCodeData(result); setEmailCodeData(result);
} catch (error) {
/* empty */
}
}; };
const telegramhandleSubmit = (values: any) => { const telegramhandleSubmit = (values: any) => {
telegramLoginMutate(values); telegramLoginMutate(values);
@ -200,6 +215,15 @@ const Login = memo(() => {
autoComplete="off" autoComplete="off"
/> />
</Form.Item> </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%" }}> <Button type="primary" htmlType="submit" style={{ width: "100%" }}>
{languageSet.} {languageSet.}
</Button> </Button>
@ -227,6 +251,15 @@ const Login = memo(() => {
autoComplete="off" autoComplete="off"
/> />
</Form.Item> </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%" }}> <Button type="primary" htmlType="submit" style={{ width: "100%" }}>
{languageSet.} {languageSet.}
</Button> </Button>

34
src/pages/use/password/retrieve.tsx

@ -1,12 +1,16 @@
import { Layout, Input, Button, Typography, Row, Col, Form, message, Modal } from "antd"; import { Layout, Input, Button, Typography, Row, Col, Form, message, Modal } from "antd";
import { LockOutlined, MailOutlined, SecurityScanOutlined } from "@ant-design/icons"; import { LockOutlined, MailOutlined, SecurityScanOutlined } from "@ant-design/icons";
import { createFileRoute, useNavigate } from "@tanstack/react-router"; 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 { passwordRules } from "@/pages/use/useTools.tsx";
import systemServ from "@/service/system.ts"; import systemServ from "@/service/system.ts";
import { t } from "i18next"; import { t } from "i18next";
import SlideCapt, { SlideCaptRef } from "@/components/captcha/SlideCapt.tsx";
const languageSet = {
const { Title, Text, Link } = Typography;
const PwdRetrieve = memo(() => {
const languageSet = {
向量检索服务免费试用: t("pwdRetrieve.vectorRetrievalServiceFreeTrial", "向量检索服务免费试用"), 向量检索服务免费试用: t("pwdRetrieve.vectorRetrievalServiceFreeTrial", "向量检索服务免费试用"),
免费试用向量检索服务玩转大模型生成式检索: t( 免费试用向量检索服务玩转大模型生成式检索: t(
"pwdRetrieve.freeTrialVectorRetrievalService", "pwdRetrieve.freeTrialVectorRetrievalService",
@ -20,35 +24,42 @@ const languageSet = {
请输入新密码: t("pwdRetrieve.pleaseEnterNewPassword", "请输入新密码"), 请输入新密码: t("pwdRetrieve.pleaseEnterNewPassword", "请输入新密码"),
请确认密码: t("pwdRetrieve.confirmPassword", "请确认密码"), 请确认密码: t("pwdRetrieve.confirmPassword", "请确认密码"),
两次输入的密码不一致: t("pwdRetrieve.passwordsDoNotMatch", "两次输入的密码不一致"), 两次输入的密码不一致: t("pwdRetrieve.passwordsDoNotMatch", "两次输入的密码不一致"),
点击进行校验: t("login.clickToVerify", "点击进行校验"),
找回密码: t("pwdRetrieve.retrievePassword", "找回密码"), 找回密码: t("pwdRetrieve.retrievePassword", "找回密码"),
返回登录: t("pwdRetrieve.backToLogin", "返回登录"), 返回登录: t("pwdRetrieve.backToLogin", "返回登录"),
修改成功: t("pwdRetrieve.changeSuccess", "修改成功"), 修改成功: t("pwdRetrieve.changeSuccess", "修改成功"),
确认: t("pwdRetrieve.confirm", "确认"), 确认: t("pwdRetrieve.confirm", "确认"),
密码修改成功返回登录: t("pwdRetrieve.passwordChangeSuccess", "密码修改成功,返回登录。"), 密码修改成功返回登录: t("pwdRetrieve.passwordChangeSuccess", "密码修改成功,返回登录。"),
};
const { Title, Text, Link } = Typography;
};
const PwdRetrieve = memo(() => {
const navigate = useNavigate(); const navigate = useNavigate();
const [retrieveForm] = Form.useForm(); const [retrieveForm] = Form.useForm();
const [emailCodeData, setEmailCodeData] = useState({}); const [emailCodeData, setEmailCodeData] = useState({});
const [pwdRetrieveData, setPwdRetrieveData] = useState({}); const [pwdRetrieveData, setPwdRetrieveData] = useState({});
const slideCaptRef = useRef<SlideCaptRef>();
const handleRetrieveSubmit = async (values: any) => { const handleRetrieveSubmit = async (values: any) => {
const param = { const param = {
email: values.email, email: values.email,
password: values.password, password: values.password,
code: values.code, code: values.code,
captchaKey: values.captchaKey,
}; };
const result = await systemServ.pwdRetrieve(param); const result = await systemServ.pwdRetrieve(param);
setPwdRetrieveData(result); setPwdRetrieveData(result);
}; };
const handleGetCode = async () => { const handleGetCode = async () => {
try {
// 验证邮箱和滑动验证码
await retrieveForm.validateFields(["email", "captchaKey"]);
const email = retrieveForm.getFieldValue("email"); const email = retrieveForm.getFieldValue("email");
const result = await systemServ.emailCode({ is_register: false, email });
const captchaKey = retrieveForm.getFieldValue("captchaKey");
const result = await systemServ.emailCode({ is_register: false, email, captchaKey });
setEmailCodeData(result); setEmailCodeData(result);
} catch (errorInfo) {
/* empty */
}
}; };
const [countdown, setCountdown] = useState<number>(0); const [countdown, setCountdown] = useState<number>(0);
@ -174,6 +185,15 @@ const PwdRetrieve = memo(() => {
autoComplete="off" autoComplete="off"
/> />
</Form.Item> </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%" }}> <Button type="primary" htmlType="submit" style={{ width: "100%" }}>
{languageSet.} {languageSet.}
</Button> </Button>

30
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 { LockOutlined, MailOutlined, SecurityScanOutlined } from "@ant-design/icons";
import { createFileRoute, useNavigate } from "@tanstack/react-router"; import { createFileRoute, useNavigate } from "@tanstack/react-router";
import { useAtomValue } from "jotai"; 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 { emailRegisterAtom } from "@/store/system/user.ts";
import { passwordRules } from "@/pages/use/useTools"; import { passwordRules } from "@/pages/use/useTools";
import systemServ from "@/service/system.ts"; import systemServ from "@/service/system.ts";
import { t } from "i18next"; import { t } from "i18next";
import SlideCapt, { SlideCaptRef } from "@/components/captcha/SlideCapt.tsx";
const languageSet = { const languageSet = {
向量检索服务免费试用: t("register.vectorRetrievalServiceFreeTrial", "向量检索服务免费试用"), 向量检索服务免费试用: t("register.vectorRetrievalServiceFreeTrial", "向量检索服务免费试用"),
@ -22,6 +23,7 @@ const languageSet = {
请输入密码: t("register.pleaseEnterPassword", "请输入密码"), 请输入密码: t("register.pleaseEnterPassword", "请输入密码"),
请确认密码: t("register.confirmPassword", "请确认密码"), 请确认密码: t("register.confirmPassword", "请确认密码"),
两次输入的密码不一致: t("register.passwordsDoNotMatch", "两次输入的密码不一致"), 两次输入的密码不一致: t("register.passwordsDoNotMatch", "两次输入的密码不一致"),
点击进行校验: t("login.clickToVerify", "点击进行校验"),
注册: t("register.register", "注册"), 注册: t("register.register", "注册"),
登录: t("register.login", "登录"), 登录: t("register.login", "登录"),
返回登录: t("register.backToLogin", "返回登录"), 返回登录: t("register.backToLogin", "返回登录"),
@ -36,15 +38,28 @@ const Register = memo(() => {
const [countdown, setCountdown] = useState(10); const [countdown, setCountdown] = useState(10);
const [emailCodeData, setEmailCodeData] = useState({}); const [emailCodeData, setEmailCodeData] = useState({});
const [isButtonDisabled, setIsButtonDisabled] = useState<boolean>(false); const [isButtonDisabled, setIsButtonDisabled] = useState<boolean>(false);
const slideCaptRef = useRef<SlideCaptRef>();
const getEmailCode = async () => { const getEmailCode = async () => {
try {
// 验证邮箱和滑动验证码
await registerForm.validateFields(["email", "captchaKey"]);
const email = registerForm.getFieldValue("email"); const email = registerForm.getFieldValue("email");
const result = await systemServ.emailCode({ is_register: true, email });
const captchaKey = registerForm.getFieldValue("captchaKey");
const result = await systemServ.emailCode({ is_register: true, email, captchaKey });
setEmailCodeData(result); setEmailCodeData(result);
} catch (errorInfo) {
/* empty */
}
}; };
const emailRegisterSubmit = (values: any) => { 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(() => { useEffect(() => {
@ -150,6 +165,15 @@ const Register = memo(() => {
autoComplete="off" autoComplete="off"
/> />
</Form.Item> </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%" }}> <Button type="primary" htmlType="submit" style={{ width: "100%" }}>
{languageSet.} {languageSet.}
</Button> </Button>

Loading…
Cancel
Save