tiefen_space_h5/app/login/page.js

409 lines
12 KiB
JavaScript
Raw Normal View History

2024-07-03 19:59:39 +08:00
"use client";
2024-07-06 11:05:19 +08:00
import React, { useState, useRef, useEffect } from "react";
import {
Input,
Button,
Swiper,
Tabs,
Divider,
Checkbox,
Toast,
} from "antd-mobile";
2024-07-03 19:59:39 +08:00
import { useRouter } from "next/navigation";
import styles from "./index.module.css";
2024-07-06 11:05:19 +08:00
import { JSEncrypt } from "jsencrypt";
import { handleLogin } from "@/store/actions";
import { saveUserInfo,removeUserInfo } from "@/utils/storeInfo";
import { connect } from "react-redux";
import { cryptoPassword } from "@/utils/crypto";
import require from "@/utils/require";
import {signOut,signIn} from "@/utils/auth";
2024-07-03 19:59:39 +08:00
/*
params格式
{
mid: item.mid,
}
*/
const tabItems = [
{ key: "code", title: "验证码登录" },
{ key: "password", title: "帐号密码登录" },
];
2024-07-06 11:05:19 +08:00
function Login({ handleLogin }) {
2024-07-03 19:59:39 +08:00
const [activeIndex, setActiveIndex] = useState(0);
const [veriCode, setVeriCode] = useState("");
const [isCounting, setIsCounting] = useState(false);
const [seconds, setSeconds] = useState(60);
2024-07-06 11:05:19 +08:00
const [loginInfo, setLoginInfo] = useState({
mobilePhone: "",
regionCode: "86",
password: "",
checked: false,
});
const router = useRouter();
2024-07-03 19:59:39 +08:00
const swiperRef = useRef(null);
2024-07-06 11:05:19 +08:00
useEffect(() => {
handleLogin({ isSignin: false, userToken: null });
signOut()
removeUserInfo();
},[])
useEffect(() => {
let interval;
if (isCounting && seconds > 0) {
interval = setInterval(() => {
setSeconds(seconds - 1);
}, 1000);
} else {
setIsCounting(false);
setSeconds(60);
clearInterval(interval);
}
return () => {
clearInterval(interval);
};
}, [isCounting, seconds]);
const handleSubmit = async (type) => {
const { mobilePhone, password, regionCode, checked } = loginInfo;
//验证数据格式
if (!checked) {
Toast.show({
icon: "fail",
content: "请先阅读并同意《用户协议》和《隐私政策》后登录",
position: "top",
});
return;
}
if (!mobilePhone.match(/^1[3456789]\d{9}$/)) {
Toast.show({
icon: "fail",
content: "手机号码格式错误",
position: "top",
});
return;
}
if (type === "password") {
if (password.length < 8) {
Toast.show({
icon: "fail",
content: "密码不得小于8位",
position: "top",
});
return;
}
if (password.length > 15) {
Toast.show({
icon: "fail",
content: "密码不得大于15位",
position: "top",
});
return;
}
} else {
if (veriCode.length !== 6) {
Toast.show({
icon: "fail",
content: "请输入正确的验证码",
position: "top",
});
return;
}
}
//对手机号进行RSA加密
const encrypt = new JSEncrypt();
encrypt.setPublicKey(process.env.NEXT_PUBLIC_RSA_KEY);
const mobile_phone = encrypt.encrypt(mobilePhone);
//MD5加密password
const encryptedPassword = cryptoPassword(password);
//发送登录请求
let body = {
mobile_phone,
region_code: regionCode,
};
body =
type === "password"
? {
...body,
password: encryptedPassword,
}
: {
...body,
code: veriCode,
};
try {
const data = await require("POST", `/api/login/${
type === "password" ? "login_by_pswd" : "login_by_veri_code"
}`, {
body,
});
if (data.ret === -1) {
Toast.show({
icon: "fail",
content: data.msg,
position: "top",
});
return;
}
//登录
saveUserInfo(data, mobilePhone, regionCode);
signIn(data);
handleLogin({ isSignin: true, userToken: data.data.token });
router.push("/");
} catch (error) {
console.error(error);
}
};
//点击获取验证码
const handleVerification = async () => {
const { mobilePhone, regionCode, checked } = loginInfo;
if (!checked) {
Toast.show({
icon: "fail",
content: "请先阅读并同意《用户协议》和《隐私政策》后登录",
position: "top",
});
return;
}
//手机号校验
if (!mobilePhone.match(/^1[3456789]\d{9}$/)) {
Toast.show({
type: "error",
text1: "手机号码格式错误",
topOffset: 60,
});
return;
}
//开始倒计时
setIsCounting(true);
//对手机号进行RSA加密
const encrypt = new JSEncrypt();
encrypt.setPublicKey(process.env.NEXT_PUBLIC_RSA_KEY);
const mobile_phone = encrypt.encrypt(mobilePhone);
//发送短信验证码
try {
await fetch(`/api/veri_code/send`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
mobile_phone,
region_code: regionCode,
}),
});
} catch (error) {
console.error(error);
}
};
2024-07-03 19:59:39 +08:00
return (
<div className={`${styles.loginBox}`}>
<div className="mt-32 flex justify-between items-center px-2 text-gray-400 sticky top-0 z-10 bg-deepBg">
<Tabs
activeKey={tabItems[activeIndex].key}
onChange={(key) => {
const index = tabItems.findIndex((item) => item.key === key);
setActiveIndex(index);
swiperRef.current?.swipeTo(index);
}}
className={`w-full ${styles.customTabs}`}
>
{tabItems.map((item) => (
<Tabs.Tab
forceRender={false}
title={item.title}
key={item.key}
className="text-left"
/>
))}
</Tabs>
</div>
<Swiper
className="overflow-visible mt-6 "
direction="horizontal"
loop
indicator={() => null}
ref={swiperRef}
defaultIndex={activeIndex}
onIndexChange={(index) => {
setActiveIndex(index);
}}
>
<Swiper.Item className="px-10">
<div className="border-2 border-[#2c2b2f] rounded-2xl p-4">
<div className="flex flex-row flex-nowrap items-center mb-4">
2024-07-06 11:05:19 +08:00
<p className="text-base text-white mr-4">
+{loginInfo.regionCode}
</p>
2024-07-03 19:59:39 +08:00
<Input
2024-07-06 11:05:19 +08:00
clearable
2024-07-03 19:59:39 +08:00
placeholder="请输入手机号"
// disabled={true}
type="number"
maxLength={11}
2024-07-06 11:05:19 +08:00
onChange={(value) =>
setLoginInfo({ ...loginInfo, mobilePhone: value })
}
value={loginInfo.mobilePhone}
style={{ "--color": "#FFFFFF", "--font-size": "16px" }}
/>
</div>
<Divider />
<div className="flex flex-row flex-nowrap items-center">
<p className="text-base text-white mr-4 whitespace-nowrap">
密码
</p>
<Input
clearable
placeholder="请输入密码"
onChange={(value) => setLoginInfo({ ...loginInfo, password: value})}
value={loginInfo.password}
type="password"
2024-07-03 19:59:39 +08:00
style={{ "--color": "#FFFFFF", "--font-size": "16px" }}
/>
</div>
<Divider />
<div className="flex flex-row flex-nowrap items-center">
<p className="text-base text-white mr-4 whitespace-nowrap">
验证码
</p>
<Input
placeholder="请输入验证码"
2024-07-06 11:05:19 +08:00
onChange={(value) => setVeriCode(value)}
2024-07-03 19:59:39 +08:00
value={veriCode}
type="number"
style={{
"--placeholder-color": "#FFFFFF80",
"--font-size": "16px",
}}
/>
<Button
shape="rounded"
size="mini"
disabled={isCounting}
2024-07-06 11:05:19 +08:00
onClick={handleVerification}
2024-07-03 19:59:39 +08:00
style={{ "--background-color": "#FF669E", color: "#FFFFFF" }}
className="whitespace-nowrap"
>
{isCounting ? `(${seconds})重新发送` : "获取验证码"}
</Button>
</div>
</div>
2024-07-06 11:05:19 +08:00
<LoginBtn
loginInfo={loginInfo}
setLoginInfo={setLoginInfo}
handleSubmit={handleSubmit}
type={activeIndex ? "password" : "mobile"}
/>
2024-07-03 19:59:39 +08:00
</Swiper.Item>
<Swiper.Item className="px-10">
<div className="border-2 border-[#2c2b2f] rounded-2xl p-4">
<div className="flex flex-row flex-nowrap items-center mb-4">
2024-07-06 11:05:19 +08:00
<p className="text-base text-white mr-4">
+{loginInfo.regionCode}
</p>
2024-07-03 19:59:39 +08:00
<Input
2024-07-06 11:05:19 +08:00
clearable
2024-07-03 19:59:39 +08:00
placeholder="请输入手机号"
// disabled={true}
type="number"
maxLength={11}
2024-07-06 11:05:19 +08:00
onChange={(value) =>
setLoginInfo({ ...loginInfo, mobilePhone: value })
}
value={loginInfo.mobilePhone}
2024-07-03 19:59:39 +08:00
style={{ "--color": "#FFFFFF", "--font-size": "16px" }}
/>
</div>
<Divider />
<div className="flex flex-row flex-nowrap items-center">
<p className="text-base text-white mr-4 whitespace-nowrap">
密码
</p>
<Input
2024-07-06 11:05:19 +08:00
clearable
2024-07-03 19:59:39 +08:00
placeholder="请输入密码"
2024-07-06 11:05:19 +08:00
onChange={(value) =>
setLoginInfo({ ...loginInfo, password: value })
}
value={loginInfo.password}
type="password"
2024-07-03 19:59:39 +08:00
style={{
"--placeholder-color": "#FFFFFF80",
"--font-size": "16px",
}}
/>
</div>
</div>
2024-07-06 11:05:19 +08:00
<LoginBtn
loginInfo={loginInfo}
setLoginInfo={setLoginInfo}
handleSubmit={handleSubmit}
type={activeIndex ? "password" : "mobile"}
/>
2024-07-03 19:59:39 +08:00
</Swiper.Item>
</Swiper>
</div>
);
}
2024-07-06 11:05:19 +08:00
const LoginBtn = ({ loginInfo, setLoginInfo, type, handleSubmit }) => {
2024-07-03 19:59:39 +08:00
const router = useRouter();
2024-07-06 11:05:19 +08:00
useEffect(() => {
console.log("loginInfo", loginInfo);
}, []);
2024-07-03 19:59:39 +08:00
return (
<div className="mt-16">
<div className="flex items-center">
<Checkbox
2024-07-06 11:05:19 +08:00
value={loginInfo?.checked}
onChange={(value) => setLoginInfo({ ...loginInfo, checked: value })}
2024-07-03 19:59:39 +08:00
style={{
"--icon-size": "14px",
"--font-size": "14px",
"--gap": "6px",
}}
></Checkbox>
<span className="text-[#FFFFFF80] font-medium text-xs ml-2">
我确认已满18周岁并同意
<span
onClick={() =>
router.push(
`${process.env.NEXT_PUBLIC_WEB_URL}/doc/useragreement`
)
}
className="text-[#FF669E] text-xs"
>
用户协议
</span>
<span
onClick={() =>
router.push(
`${process.env.NEXT_PUBLIC_WEB_URL}/doc/useragreement`
)
}
className="text-[#FF669E] text-xs"
>
隐私政策
</span>
</span>
</div>
<Button
shape="rounded"
size="middle"
block
2024-07-06 11:05:19 +08:00
onClick={() => handleSubmit(type)}
2024-07-03 19:59:39 +08:00
style={{ "--background-color": "#FF669E", color: "#FFFFFF" }}
className="mt-2"
>
登录
</Button>
</div>
);
};
2024-07-06 11:05:19 +08:00
const mapDispatchToProps = {
handleLogin,
};
export default connect(null, mapDispatchToProps)(Login);