feat: 手机号登录/重置密码
This commit is contained in:
@@ -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,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
14
src/types/user/user.d.ts
vendored
14
src/types/user/user.d.ts
vendored
@@ -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;
|
||||||
|
@@ -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);
|
||||||
|
@@ -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}>
|
||||||
@@ -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) => {
|
||||||
|
Reference in New Issue
Block a user