feat: 手机号登录/重置密码

This commit is contained in:
landaiqing
2024-06-09 13:23:08 +08:00
parent 82b791428b
commit 0cba84266a
4 changed files with 176 additions and 24 deletions

View File

@@ -50,7 +50,7 @@ export const register = (data: API.PhoneRegisterRequest) => {
}; };
/** /**
* 注册 * 登录
* @param data * @param data
*/ */
export const login = (data: API.LoginRequest) => { export const login = (data: API.LoginRequest) => {
@@ -60,3 +60,26 @@ export const login = (data: API.LoginRequest) => {
data: data, data: data,
}); });
}; };
/**
* 手机号登录
* @param data
*/
export const loginByPhone = (data: API.LoginByPhoneRequest) => {
return web.request({
url: "/auth/user/loginByPhone",
method: "post",
data: data,
});
};
/**
* 找回密码
* @param data
*/
export const findPassword = (data: API.findPasswordRequest) => {
return web.request({
url: "/auth/user/findPassword",
method: "post",
data: data,
});
};

View File

@@ -15,6 +15,20 @@ declare namespace API {
token: string; token: string;
deg: number; deg: number;
}; };
type LoginByPhoneRequest = {
phone?: string;
activeCode?: string;
token: string;
deg: number;
};
type findPasswordRequest = {
phone?: string;
password?: string;
confirmPassword?: string;
activeCode?: string;
token: string;
deg: number;
};
// type ApiResponse<T> = { // type ApiResponse<T> = {
// success?: boolean; // success?: boolean;
// code?: number; // code?: number;

View File

@@ -11,13 +11,17 @@ import qrCode from "@/assets/images/login_qrcode-landaiqing.jpg";
import styles from "./index.module.less"; import styles from "./index.module.less";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import FooterComponent from "@/components/Footer"; import FooterComponent from "@/components/Footer";
import { getSms, register } from "@/api/user"; import { findPassword, getSms } from "@/api/user";
import RotateCaptcha, { CaptchaInstance, type TicketInfoType } from "react-rotate-captcha";
import { get, load } from "@/api/captcha";
// import useStore from '@/utils/store/useStore.tsx' // import useStore from '@/utils/store/useStore.tsx'
type LoginType = "phone"; type LoginType = "phone";
export default observer(() => { export default observer(() => {
const [form] = Form.useForm(); const [form] = Form.useForm();
const captchaRef = useRef<CaptFieldRef | null | undefined>(); const captchaRef = useRef<CaptFieldRef | null | undefined>();
const smsCaptcha = useRef<CaptchaInstance>(null);
const findPasswordCaptcha = useRef<CaptchaInstance>(null);
const [loginType, setLoginType] = useState<LoginType>("phone"); const [loginType, setLoginType] = useState<LoginType>("phone");
const colors = ["#fc6076", "#ff9a44", "#ef9d43", "#e75516"]; const colors = ["#fc6076", "#ff9a44", "#ef9d43", "#e75516"];
const getHoverColors = (colors: string[]) => const getHoverColors = (colors: string[]) =>
@@ -25,6 +29,69 @@ export default observer(() => {
const getActiveColors = (colors: string[]) => const getActiveColors = (colors: string[]) =>
colors.map((color) => new TinyColor(color).darken(5).toString()); colors.map((color) => new TinyColor(color).darken(5).toString());
async function smsVerify(token: string, deg: number): Promise<TicketInfoType> {
const phone = form.getFieldValue("phone");
const data: any = {
token: token,
deg: deg,
phone: phone,
};
const res: any = await getSms(data);
if (res && res.code === 0) {
message.open({
content: res.data,
type: "success",
duration: 5,
});
} else {
message.open({
content: res.data,
type: "warning",
duration: 5,
});
}
return res;
}
async function findPasswordVerify(token: string, deg: number): Promise<TicketInfoType> {
const mobile = form.getFieldValue("phone");
const captcha = form.getFieldValue("activeCode");
const password = form.getFieldValue("password");
const confirmPassword = form.getFieldValue("confirmPassword");
const data: API.findPasswordRequest = {
token: token,
deg: deg,
phone: mobile,
activeCode: captcha,
password: password,
confirmPassword: confirmPassword,
};
const res: any = await findPassword(data);
if (res && res.success && res.code === 0) {
message.open({
content: res.data,
type: "success",
duration: 5,
});
} else if (res.code === 0 && !res.success) {
message.open({
content: res.data,
type: "error",
duration: 5,
});
}
return res;
}
async function openSmsCaptcha() {
smsCaptcha.current!.open();
}
async function fopenFindPasswordCaptcha() {
findPasswordCaptcha.current!.open();
}
const items = [ const items = [
{ {
key: "phone", key: "phone",
@@ -37,16 +104,16 @@ export default observer(() => {
}, },
]; ];
const onSubmit = async (formData: object) => {
const res: any = await register(formData);
if (res && res.success) {
message.success(res.data);
} else {
message.error(res.data);
}
};
return ( return (
<div className={styles.container}> <div className={styles.container}>
<RotateCaptcha get={get} load={load} verify={smsVerify} limit={2} ref={smsCaptcha} />
<RotateCaptcha
get={get}
load={load}
verify={findPasswordVerify}
limit={2}
ref={findPasswordCaptcha}
/>
<div className={styles.content}> <div className={styles.content}>
<Space> <Space>
<Space className={styles.login_content}> <Space className={styles.login_content}>
@@ -152,13 +219,8 @@ export default observer(() => {
}, },
]} ]}
fieldRef={captchaRef} fieldRef={captchaRef}
onGetCaptcha={async (phone: string) => { onGetCaptcha={async () => {
const res: any = await getSms(phone); await openSmsCaptcha();
if (res && res.success) {
message.success(res.data, 3);
} else {
message.warning(res.data, 3);
}
}} }}
/> />
@@ -233,8 +295,8 @@ export default observer(() => {
]; ];
await form await form
.validateFields(validateFields) .validateFields(validateFields)
.then(async (values) => { .then(async () => {
await onSubmit(values as API.PhoneRegisterRequest); await fopenFindPasswordCaptcha();
}) })
.catch((error) => { .catch((error) => {
console.error(error); console.error(error);

View File

@@ -37,7 +37,7 @@ import useStore from "@/utils/store/useStore.tsx";
import FooterComponent from "@/components/Footer"; import FooterComponent from "@/components/Footer";
import RotateCaptcha, { CaptchaInstance, type TicketInfoType } from "react-rotate-captcha"; import RotateCaptcha, { CaptchaInstance, type TicketInfoType } from "react-rotate-captcha";
import { get, load } from "@/api/captcha/index.ts"; import { get, load } from "@/api/captcha/index.ts";
import { getSms, login, oauthLogin } from "@/api/user"; import { getSms, login, loginByPhone, oauthLogin } from "@/api/user";
import { TinyColor } from "@ctrl/tinycolor"; import { TinyColor } from "@ctrl/tinycolor";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import { setStorage } from "@/utils/localStorage/config.ts"; import { setStorage } from "@/utils/localStorage/config.ts";
@@ -55,6 +55,7 @@ export default observer(() => {
const [form] = Form.useForm(); const [form] = Form.useForm();
const smsCaptcha = useRef<CaptchaInstance>(null); const smsCaptcha = useRef<CaptchaInstance>(null);
const loginCaptcha = useRef<CaptchaInstance>(null); const loginCaptcha = useRef<CaptchaInstance>(null);
const loginByPhoneCaptcha = useRef<CaptchaInstance>(null);
const captchaRef = useRef<CaptFieldRef | null | undefined>(); const captchaRef = useRef<CaptFieldRef | null | undefined>();
const navigate = useNavigate(); const navigate = useNavigate();
const store = useStore("user"); const store = useStore("user");
@@ -91,7 +92,7 @@ export default observer(() => {
async function loginVerify(token: string, deg: number): Promise<TicketInfoType> { async function loginVerify(token: string, deg: number): Promise<TicketInfoType> {
const userName = form.getFieldValue("username"); const userName = form.getFieldValue("username");
const password = form.getFieldValue("password"); const password = form.getFieldValue("password");
const data: any = { const data: API.LoginRequest = {
token: token, token: token,
deg: deg, deg: deg,
userName: userName, userName: userName,
@@ -122,6 +123,40 @@ export default observer(() => {
return res; return res;
} }
async function loginByPhoneVerify(token: string, deg: number): Promise<TicketInfoType> {
const mobile = form.getFieldValue("mobile");
const captcha = form.getFieldValue("captcha");
const data: API.LoginByPhoneRequest = {
token: token,
deg: deg,
phone: mobile,
activeCode: captcha,
};
const res: any = await loginByPhone(data);
if (res && res.success && res.code === 0) {
store.setToken(res.data.token);
store.setUserId(res.data.user.id);
setStorage("token", res.data.token, 24 * 60 * 30);
if (store.getToken() !== null || store.getUserId() !== null) {
setTimeout(() => {
navigate("/main");
}, 3000);
}
message.open({
content: "登录成功!",
type: "success",
duration: 5,
});
} else if (res.code === 0 && !res.success) {
message.open({
content: "登录失败!",
type: "error",
duration: 5,
});
}
return res;
}
const items = [ const items = [
{ {
label: ( label: (
@@ -158,10 +193,27 @@ export default observer(() => {
loginCaptcha.current!.open(); loginCaptcha.current!.open();
} }
async function openLoginByPhoneCaptcha() {
loginByPhoneCaptcha.current!.open();
}
return ( return (
<div className={styles.container}> <div className={styles.container}>
<RotateCaptcha get={get} load={load} verify={smsVerify} limit={2} ref={smsCaptcha} /> <RotateCaptcha get={get} load={load} verify={smsVerify} limit={2} ref={smsCaptcha} />
<RotateCaptcha get={get} load={load} verify={loginVerify} ref={loginCaptcha} /> <RotateCaptcha
get={get}
load={load}
verify={loginVerify}
limit={2}
ref={loginCaptcha}
/>
<RotateCaptcha
get={get}
load={load}
limit={2}
verify={loginByPhoneVerify}
ref={loginByPhoneCaptcha}
/>
<div className={styles.content}> <div className={styles.content}>
<Space className={styles.content_content}> <Space className={styles.content_content}>
<Space className={styles.login_content}> <Space className={styles.login_content}>
@@ -206,7 +258,7 @@ export default observer(() => {
<img <img
alt="logo" alt="logo"
src={logo} src={logo}
style={{ width: "44px", height: "44px"}} style={{ width: "44px", height: "44px" }}
/> />
<span></span> <span></span>
</Space> </Space>
@@ -346,9 +398,10 @@ export default observer(() => {
await form await form
.validateFields(validateFields) .validateFields(validateFields)
.then(async () => { .then(async () => {
// await onSubmit(values);
if (loginType === "account") { if (loginType === "account") {
await openLoginCaptcha(); await openLoginCaptcha();
} else {
await openLoginByPhoneCaptcha();
} }
}) })
.catch((error) => { .catch((error) => {