tiefen_space_h5/app/login/page.js

666 lines
19 KiB
JavaScript
Raw Normal View History

2024-07-03 19:59:39 +08:00
"use client";
2024-12-13 18:24:36 +08:00
import React, { useState, useRef, useEffect, useMemo } from "react";
2024-07-06 11:05:19 +08:00
import {
2024-10-09 16:59:04 +08:00
// Input,
2024-07-06 11:05:19 +08:00
Button,
Swiper,
Tabs,
Divider,
Checkbox,
Toast,
2024-12-13 18:24:36 +08:00
Dialog,
Popup,
2024-07-06 11:05:19 +08:00
} from "antd-mobile";
2024-07-03 19:59:39 +08:00
import { useRouter } from "next/navigation";
2024-07-22 17:55:52 +08:00
import styles from "./index.module.scss";
2024-07-06 11:05:19 +08:00
import { JSEncrypt } from "jsencrypt";
import { handleLogin } from "@/store/actions";
import { saveUserInfo, get, save } from "@/utils/storeInfo";
2024-07-06 11:05:19 +08:00
import { connect } from "react-redux";
import { cryptoPassword } from "@/utils/crypto";
2024-07-22 16:07:41 +08:00
import requireAPI from "@/utils/requireAPI";
2024-12-24 20:21:53 +08:00
import { signIn, checkAuth } from "@/utils/auth";
2024-10-09 16:59:04 +08:00
import OwnInput from "@/components/OwnInput";
2024-12-24 12:14:28 +08:00
import OwnIcon from "@/components/OwnIcon";
2024-07-03 19:59:39 +08:00
/*
params格式
{
mid: item.mid,
}
*/
const tabItems = [
2024-07-30 22:53:41 +08:00
{ key: "veri_code", title: "验证码登录" },
2024-07-03 19:59:39 +08:00
{ 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);
2024-12-04 14:23:24 +08:00
const [isLoading, setIsLoading] = useState(false);
2024-07-03 19:59:39 +08:00
const [seconds, setSeconds] = useState(60);
2024-08-02 22:12:54 +08:00
const [deviceType, setDeviceType] = useState("");
2024-12-13 18:24:36 +08:00
const [popVisible, setPopVisible] = useState(false);
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-12-13 18:24:36 +08:00
const showMobal = useRef();
const [iframePageUrl, setIframePageUrl] = useState(null);
2024-07-06 11:05:19 +08:00
useEffect(() => {
2024-08-02 22:12:54 +08:00
const userAgent = navigator.userAgent;
//区分设备类型
if (/Android/i.test(userAgent)) {
setDeviceType("Android");
} else if (/iPhone|iPad|iPod/i.test(userAgent)) {
setDeviceType("ios");
} else {
setDeviceType("pc");
}
2024-07-06 11:05:19 +08:00
handleLogin({ isSignin: false, userToken: null });
2024-09-09 15:34:31 +08:00
checkAuth().then((res) => {
const account = get("account");
if (res && account) {
router.replace("/");
2024-08-05 21:10:36 +08:00
}
2024-09-09 15:34:31 +08:00
});
2024-07-17 16:58:27 +08:00
}, []);
2024-07-06 11:05:19 +08:00
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]);
2024-12-13 18:24:36 +08:00
const handleCheck = async (type) => {
const { mobilePhone, password, checked } = loginInfo;
2024-07-06 11:05:19 +08:00
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",
2024-12-13 18:24:36 +08:00
maskClassName: "z-20",
2024-07-06 11:05:19 +08:00
});
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;
}
}
2024-12-13 18:24:36 +08:00
//验证数据格式
if (!checked) {
handleShowDialog(type);
return;
}
handleSubmit(type);
};
const handleSubmit = async (type) => {
const { mobilePhone, password, regionCode, checked } = loginInfo;
2024-07-06 11:05:19 +08:00
//对手机号进行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,
2024-07-30 22:53:41 +08:00
veri_code: veriCode,
2024-07-06 11:05:19 +08:00
};
2024-12-04 14:23:24 +08:00
setIsLoading(true);
2024-07-06 11:05:19 +08:00
try {
2024-07-24 13:53:12 +08:00
const data = await requireAPI(
"POST",
`/api/login/${
type === "password" ? "login_by_pswd" : "login_by_veri_code"
}`,
{
body,
}
);
2024-12-04 14:23:24 +08:00
2024-07-06 11:05:19 +08:00
if (data.ret === -1) {
2024-12-04 14:23:24 +08:00
setIsLoading(false);
2024-08-09 21:02:50 +08:00
Toast.show({
icon: "fail",
content: data.msg,
position: "top",
});
2024-07-06 11:05:19 +08:00
return;
}
//登录
saveUserInfo(data, mobilePhone, regionCode);
signIn(data);
handleLogin({ isSignin: true, userToken: data.data.token });
2024-09-09 15:34:31 +08:00
if (get("firstLogin") == null) {
save("firstLogin", 1);
} else {
save("firstLogin", 0);
}
2024-12-04 14:23:24 +08:00
setIsLoading(false);
2024-07-24 13:53:12 +08:00
router.push(
2024-08-02 22:12:54 +08:00
!data?.data?.is_enabled && type != "password"
2024-07-31 18:16:25 +08:00
? "/my/setting/editPassword?is_enabled=" + data?.data?.is_enabled
: "/"
2024-07-24 13:53:12 +08:00
);
2024-07-06 11:05:19 +08:00
} catch (error) {
2024-12-04 14:23:24 +08:00
setIsLoading(false);
2024-09-09 15:34:31 +08:00
// console.error(error);
2024-07-06 11:05:19 +08:00
}
};
//点击获取验证码
const handleVerification = async () => {
2024-12-13 18:24:36 +08:00
const { mobilePhone, regionCode } = loginInfo;
2024-07-06 11:05:19 +08:00
//手机号校验
if (!mobilePhone.match(/^1[3456789]\d{9}$/)) {
Toast.show({
2024-07-08 20:07:36 +08:00
icon: "fail",
content: "手机号码格式错误",
position: "top",
2024-07-06 11:05:19 +08:00
});
return;
}
//开始倒计时
setIsCounting(true);
//对手机号进行RSA加密
const encrypt = new JSEncrypt();
encrypt.setPublicKey(process.env.NEXT_PUBLIC_RSA_KEY);
const mobile_phone = encrypt.encrypt(mobilePhone);
//发送短信验证码
try {
2024-08-09 21:02:50 +08:00
const data = await fetch(`/api/veri_code/send`, {
2024-07-06 11:05:19 +08:00
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
mobile_phone,
region_code: regionCode,
}),
});
2024-08-09 21:02:50 +08:00
if (data.ret === -1) {
Toast.show({
icon: "fail",
content: data.msg,
position: "top",
});
return;
}
2024-07-06 11:05:19 +08:00
} catch (error) {
2024-09-09 15:34:31 +08:00
// console.error(error);
2024-07-06 11:05:19 +08:00
}
};
2024-12-13 18:24:36 +08:00
const handleShowDialog = (type) => {
showMobal.current = Dialog.show({
title: "登录提示",
content: (
<div>
为了更好保障你的合法权益请阅读和同意
<span
className="text-[#FF669E]"
onClick={() => {
setIframePageUrl(
`/webView/${encodeURIComponent("/doc/useragreement")}`
);
}}
>
用户协议
</span>
<span
className="text-[#FF669E]"
onClick={() => {
setIframePageUrl(
`/webView/${encodeURIComponent("/doc/privatypolicy")}`
);
}}
>
隐私政策
</span>
</div>
),
bodyStyle: {
maxHeight: "none",
width: "80vw",
position: "fixed",
top: "200px",
left: "10vw",
"--text-color": "#fff",
color: "#fff",
},
// cancelText:"确认",
// confirmText:"取消",
style: {
"--text-color": "#fff",
},
closeOnAction: true,
actions: [
[
{
key: "close",
text: "取消",
bold: true,
style: { color: "#ffffff80" },
onClick: () => {
showMobal.current?.close();
},
},
{
key: "submit",
text: "确认",
style: { color: "#fff" },
onClick: () => handleSubmit(type),
},
],
],
});
// if (result) {
// Toast.show({ content: "点击了确认", position: "bottom" });
// }
};
const iframePage = useMemo(() => {
try {
if (!iframePageUrl) return null;
setPopVisible(true);
return (
<iframe className="w-full h-full rounded-t-lg" src={iframePageUrl} />
);
} catch (error) {
setPopVisible(false);
setIframePageUrl(null);
return null;
}
}, [iframePageUrl]);
2024-07-03 19:59:39 +08:00
return (
2024-07-31 18:16:25 +08:00
<div className="lg:flex flex-col items-center ">
2024-08-02 22:12:54 +08:00
<div
className={`lg:max-w-[450px] overflow-hidden pt-20 flex flex-col items-center `}
>
2024-12-24 12:14:28 +08:00
<OwnIcon
src="/images/slogan.png"
2024-07-24 13:53:12 +08:00
alt=""
2024-12-24 12:14:28 +08:00
outClassName="w-[90%]"
className="w-full h-full"
2024-07-24 13:53:12 +08:00
/>
<div className="mt-6 flex justify-between items-center px-2 text-[#ffffff80] 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
2024-07-31 18:16:25 +08:00
allowTouchMove={false}
2024-07-24 13:53:12 +08:00
indicator={() => null}
ref={swiperRef}
defaultIndex={activeIndex}
onIndexChange={(index) => {
2024-07-03 19:59:39 +08:00
setActiveIndex(index);
}}
>
2024-07-25 19:52:30 +08:00
<Swiper.Item className="px-6">
<div className="border-2 border-[#2c2b2f] rounded-2xl p-3">
2024-07-24 13:53:12 +08:00
<div className="flex flex-row flex-nowrap items-center mb-4">
<p className="text-base text-white mr-4">
+{loginInfo.regionCode}
</p>
2024-10-09 16:59:04 +08:00
{/* <Input
2024-07-24 13:53:12 +08:00
clearable
placeholder="请输入手机号"
// disabled={true}
2024-07-31 18:16:25 +08:00
name="phone_number"
2024-07-24 13:53:12 +08:00
type="number"
maxLength={11}
onChange={(value) =>
setLoginInfo({ ...loginInfo, mobilePhone: value })
}
value={loginInfo.mobilePhone}
style={{
"--color": "#FFFFFF",
2024-07-31 18:16:25 +08:00
"--font-size": "16px",
2024-07-24 13:53:12 +08:00
"--placeholder-color": "#FFFFFF80",
}}
2024-10-09 16:59:04 +08:00
/> */}
<OwnInput
clearable={true}
placeholder="请输入手机号"
name="phone_number"
type="number"
maxLength={11}
onChange={(value) => {
setLoginInfo({
...loginInfo,
mobilePhone: value,
});
}}
value={loginInfo.mobilePhone}
2024-07-24 13:53:12 +08:00
/>
</div>
<Divider />
<div className="flex flex-row flex-nowrap items-center">
<p className="text-base text-white mr-4 whitespace-nowrap">
验证码
</p>
2024-10-09 16:59:04 +08:00
{/* <Input
2024-07-24 13:53:12 +08:00
placeholder="请输入验证码"
onChange={(value) => setVeriCode(value)}
value={veriCode}
2024-07-31 18:16:25 +08:00
name="veriCode"
2024-07-24 13:53:12 +08:00
type="number"
style={{
"--placeholder-color": "#FFFFFF80",
2024-07-31 18:16:25 +08:00
"--font-size": "16px",
2024-07-24 13:53:12 +08:00
}}
2024-10-09 16:59:04 +08:00
/> */}
<OwnInput
placeholder="请输入验证码"
name="veriCode"
type="number"
onChange={setVeriCode}
value={veriCode}
2024-07-24 13:53:12 +08:00
/>
<Button
shape="rounded"
size="mini"
disabled={isCounting}
onClick={handleVerification}
style={{ "--background-color": "#FF669E", color: "#FFFFFF" }}
className="whitespace-nowrap"
>
{isCounting ? `(${seconds})重新发送` : "获取验证码"}
</Button>
</div>
2024-07-06 11:05:19 +08:00
</div>
2024-07-03 19:59:39 +08:00
2024-07-24 13:53:12 +08:00
<LoginBtn
loginInfo={loginInfo}
2024-12-04 16:32:25 +08:00
isLoading={isLoading}
2024-07-24 13:53:12 +08:00
setLoginInfo={setLoginInfo}
2024-12-13 18:24:36 +08:00
handleCheck={handleCheck}
setIframePageUrl={setIframePageUrl}
2024-07-24 13:53:12 +08:00
type={activeIndex ? "password" : "mobile"}
/>
</Swiper.Item>
2024-07-31 18:16:25 +08:00
<Swiper.Item className="px-6">
2024-07-25 19:52:30 +08:00
<div className="border-2 border-[#2c2b2f] rounded-2xl p-3">
2024-07-24 13:53:12 +08:00
<div className="flex flex-row flex-nowrap items-center mb-4">
<p className="text-base text-white mr-4">
+{loginInfo.regionCode}
</p>
2024-10-09 16:59:04 +08:00
{/* <Input
2024-07-24 13:53:12 +08:00
clearable
placeholder="请输入手机号"
// disabled={true}
type="number"
2024-07-31 18:16:25 +08:00
name="phone_number"
2024-07-24 13:53:12 +08:00
maxLength={11}
onChange={(value) =>
setLoginInfo({ ...loginInfo, mobilePhone: value })
}
value={loginInfo.mobilePhone}
style={{
"--color": "#FFFFFF",
"--font-size": "16px",
"--placeholder-color": "#FFFFFF80",
}}
2024-10-09 16:59:04 +08:00
/> */}
<OwnInput
clearable={true}
placeholder="请输入手机号"
name="phone_number"
type="number"
maxLength={11}
onChange={(value) => {
setLoginInfo({
...loginInfo,
mobilePhone: value,
});
}}
value={loginInfo.mobilePhone}
2024-07-24 13:53:12 +08:00
/>
</div>
<Divider />
<div className="flex flex-row flex-nowrap items-center">
<p className="text-base text-white mr-4 whitespace-nowrap">
密码
</p>
2024-10-09 16:59:04 +08:00
{/* <Input
2024-07-24 13:53:12 +08:00
clearable
placeholder="请输入密码"
2024-07-31 18:16:25 +08:00
name="password"
2024-07-24 13:53:12 +08:00
onChange={(value) =>
setLoginInfo({ ...loginInfo, password: value })
}
value={loginInfo.password}
type="password"
style={{
"--placeholder-color": "#FFFFFF80",
"--font-size": "16px",
}}
2024-10-09 16:59:04 +08:00
/> */}
<OwnInput
clearable={true}
placeholder="请输入密码"
name="password"
type="password"
2024-11-14 20:04:20 +08:00
maxLength={15}
2024-10-09 16:59:04 +08:00
onChange={(value) => {
setLoginInfo({ ...loginInfo, password: value });
}}
value={loginInfo.password}
2024-07-24 13:53:12 +08:00
/>
</div>
2024-07-03 19:59:39 +08:00
</div>
2024-08-05 18:34:44 +08:00
<div className="flex justify-end">
<span
onClick={() =>
router.push(
`/my/setting/editPassword?forgetPassword=true&phone=${loginInfo.mobilePhone}`
)
2024-08-05 18:34:44 +08:00
}
className="text-[#FF669E] text-xs mt-2 text-right"
>
忘记密码
</span>
2024-07-03 19:59:39 +08:00
</div>
2024-07-24 13:53:12 +08:00
<LoginBtn
2024-12-04 14:23:24 +08:00
isLoading={isLoading}
2024-07-24 13:53:12 +08:00
loginInfo={loginInfo}
setLoginInfo={setLoginInfo}
2024-12-13 18:24:36 +08:00
handleCheck={handleCheck}
setIframePageUrl={setIframePageUrl}
2024-07-24 13:53:12 +08:00
type={activeIndex ? "password" : "mobile"}
/>
</Swiper.Item>
</Swiper>
</div>
2024-08-05 13:10:33 +08:00
{deviceType != "ios" && <BottomBox />}
2024-12-13 18:24:36 +08:00
<Popup
className="z-[9999!important]"
closeOnSwipe={true}
visible={popVisible}
onMaskClick={() => {
setPopVisible(false);
setIframePageUrl(null);
}}
onClose={() => {
setPopVisible(false);
setIframePageUrl(null);
}}
position="bottom"
bodyStyle={{
height: "70vh",
backgroundColor: "#1b1b1c",
padding: "12px",
paddingBottom: 0,
borderTopRightRadius: "15px",
borderTopLeftRadius: "15px",
}}
style={{
"--background-color": "#fff",
}}
>
{iframePage}
</Popup>
2024-07-22 19:43:20 +08:00
</div>
2024-07-03 19:59:39 +08:00
);
}
2024-12-04 14:23:24 +08:00
const LoginBtn = ({
loginInfo,
setLoginInfo,
type,
2024-12-13 18:24:36 +08:00
handleCheck,
2024-12-04 14:23:24 +08:00
isLoading,
2024-12-13 18:24:36 +08:00
setIframePageUrl,
2024-12-04 14:23:24 +08:00
}) => {
2024-07-03 19:59:39 +08:00
const router = useRouter();
2024-10-09 16:59:04 +08:00
useEffect(() => {}, []);
2024-07-03 19:59:39 +08:00
return (
<div className="mt-16">
2024-07-19 14:14:40 +08:00
<div className="flex items-center justify-center">
2024-07-03 19:59:39 +08:00
<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={{
2024-08-05 15:55:20 +08:00
"--icon-size": "18px",
"--font-size": "18px",
2024-07-03 19:59:39 +08:00
"--gap": "6px",
}}
></Checkbox>
<span className="text-[#FFFFFF80] font-medium text-xs ml-2">
2024-07-17 16:58:27 +08:00
我已阅读并同意
2024-07-03 19:59:39 +08:00
<span
2024-12-13 18:24:36 +08:00
onClick={() => {
setIframePageUrl(
2024-08-02 22:12:54 +08:00
`/webView/${encodeURIComponent("/doc/useragreement")}`
2024-12-13 18:24:36 +08:00
);
}}
2024-07-03 19:59:39 +08:00
className="text-[#FF669E] text-xs"
>
用户协议
</span>
<span
2024-12-13 18:24:36 +08:00
onClick={() => {
setIframePageUrl(
2024-08-02 22:12:54 +08:00
`/webView/${encodeURIComponent("/doc/privatypolicy")}`
2024-12-13 18:24:36 +08:00
);
}}
2024-07-03 19:59:39 +08:00
className="text-[#FF669E] text-xs"
>
隐私政策
</span>
</span>
</div>
<Button
shape="rounded"
size="middle"
2024-12-04 14:23:24 +08:00
loading={isLoading}
2024-07-03 19:59:39 +08:00
block
2024-12-13 18:24:36 +08:00
onClick={() => handleCheck(type)}
2024-08-05 18:34:44 +08:00
style={{
"--background-color": "#FF669E",
color: "#FFFFFF",
marginTop: "1rem",
}}
2024-07-24 19:08:22 +08:00
className="mt-4 py-2"
2024-07-03 19:59:39 +08:00
>
登录
</Button>
2024-08-02 22:12:54 +08:00
</div>
);
};
const BottomBox = () => {
const router = useRouter();
return (
2024-08-05 21:10:36 +08:00
<div className="w-full p-6 ">
2024-08-02 22:12:54 +08:00
<div className="p-3 rounded-md flex justify-between items-center bg-[#ffffff17]">
2024-08-05 18:34:44 +08:00
<div>
<p className="">铁粉空间APP可以下载啦</p>
<p className="text-xs text-[#FFFFFF80]">
立即下载APP体验更好的服务
</p>
</div>
<div
className="px-2 py-1 rounded-full bg-[#FF669E]"
onClick={() => router.push("https://tiefen.fun")}
>
下载APP
</div>
2024-08-02 22:12:54 +08:00
</div>
2024-07-03 19:59:39 +08:00
</div>
);
};
2024-07-06 11:05:19 +08:00
const mapDispatchToProps = {
handleLogin,
};
export default connect(null, mapDispatchToProps)(Login);