244 lines
7.1 KiB
JavaScript
244 lines
7.1 KiB
JavaScript
"use client";
|
|
|
|
import React, { useState, useEffect } from "react";
|
|
import { Form, Input, Toast, Checkbox } from "antd-mobile";
|
|
import { JSEncrypt } from "jsencrypt";
|
|
import { useRouter } from "next/navigation";
|
|
import { signIn } from "@/utils/auth";
|
|
import Link from "next/link";
|
|
import baseRequest from "@/utils/baseRequest";
|
|
import { generateSignature } from "@/utils/crypto";
|
|
import { getCookie } from "cookies-next";
|
|
|
|
export default function PhonenumLogin() {
|
|
const router = useRouter();
|
|
|
|
//保存区号、手机号、验证码
|
|
const [regionCode, setRegionCode] = useState("86");
|
|
const [mobilePhone, setMobilePhone] = useState("");
|
|
|
|
//重新获取验证码的计时器
|
|
const [isCounting, setIsCounting] = useState(false);
|
|
const [seconds, setSeconds] = useState(60);
|
|
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 handleVerification = async () => {
|
|
//手机号校验
|
|
if (!mobilePhone.match(/^1[3456789]\d{9}$/)) {
|
|
Toast.show({
|
|
content: "手机号码格式错误",
|
|
});
|
|
return;
|
|
}
|
|
//开始倒计时
|
|
setIsCounting(true);
|
|
//对手机号进行RSA加密
|
|
const encrypt = new JSEncrypt();
|
|
encrypt.setPublicKey(process.env.NEXT_PUBLIC_RSA_KEY);
|
|
const mobile_phone = encrypt.encrypt(mobilePhone);
|
|
const base = baseRequest();
|
|
const signature = generateSignature({
|
|
mobile_phone: mobile_phone,
|
|
region_code: regionCode,
|
|
...base,
|
|
});
|
|
//发送短信验证码
|
|
try {
|
|
await fetch(`/api/veri_code/send?signature=${signature}`, {
|
|
method: "POST",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
},
|
|
body: JSON.stringify({
|
|
mobile_phone: mobile_phone,
|
|
region_code: regionCode,
|
|
...base,
|
|
}),
|
|
});
|
|
} catch (error) {
|
|
console.error(error);
|
|
}
|
|
};
|
|
|
|
//设置checkbox
|
|
const [checked, setChecked] = useState(false);
|
|
|
|
//点击登录
|
|
const handleSubmit = async (value) => {
|
|
if (!checked) {
|
|
Toast.show({
|
|
content: "请先勾选同意《用户协议》与《隐私政策》",
|
|
});
|
|
return;
|
|
}
|
|
if (!value.mobile_phone) {
|
|
Toast.show({
|
|
content: "请填写手机号",
|
|
});
|
|
return;
|
|
}
|
|
if (!value.mobile_phone.match(/^1[3456789]\d{9}$/)) {
|
|
Toast.show({
|
|
content: "手机号码格式错误",
|
|
});
|
|
return;
|
|
}
|
|
if (!value.veri_code) {
|
|
Toast.show({
|
|
content: "请先输入正确的验证码",
|
|
});
|
|
return;
|
|
}
|
|
|
|
//读取邀请人
|
|
const inviter = getCookie("inviter");
|
|
|
|
//对手机号进行RSA加密
|
|
const encrypt = new JSEncrypt();
|
|
encrypt.setPublicKey(process.env.NEXT_PUBLIC_RSA_KEY);
|
|
const mobile_phone = encrypt.encrypt(value.mobile_phone);
|
|
const base = baseRequest();
|
|
const signature = generateSignature({
|
|
mobile_phone: mobile_phone,
|
|
region_code: regionCode,
|
|
veri_code: value.veri_code,
|
|
inviter: parseInt(inviter, 10),
|
|
...base,
|
|
});
|
|
//发送登录请求
|
|
try {
|
|
const response = await fetch(
|
|
`/api/login/login_by_veri_code?signature=${signature}`,
|
|
{
|
|
method: "POST",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
},
|
|
body: JSON.stringify({
|
|
mobile_phone: mobile_phone,
|
|
region_code: regionCode,
|
|
veri_code: value.veri_code,
|
|
inviter: parseInt(inviter, 10),
|
|
...base,
|
|
}),
|
|
}
|
|
);
|
|
const data = await response.json();
|
|
if (data.ret === -1) {
|
|
Toast.show({
|
|
content: data.msg,
|
|
});
|
|
return;
|
|
}
|
|
//若已经设置了密码则直接登录
|
|
if (data.data.is_enabled) {
|
|
signIn(data);
|
|
router.back();
|
|
return;
|
|
}
|
|
//若没设置密码则前往设置密码
|
|
signIn(data);
|
|
const replacedString = mobile_phone.replace(/\+/g, "%2B");
|
|
router.replace(
|
|
`../setpassword?mobile_phone=${replacedString}®ion_code=${regionCode}`
|
|
);
|
|
} catch (error) {
|
|
console.error(error);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<section className="flex flex-1 flex-col">
|
|
<div className="flex flex-row justify-center">
|
|
<Form
|
|
style={{
|
|
"--border-top": "0",
|
|
"--border-bottom": "0",
|
|
"--border-inner": "0",
|
|
}}
|
|
layout="horizontal"
|
|
onFinish={handleSubmit}
|
|
>
|
|
<div className="w-96 p-4 bg-[#07050A]">
|
|
<div className="rounded-2xl overflow-hidden border-neutral border">
|
|
<Form.Item name="mobile_phone">
|
|
<div className="flex flex-row">
|
|
<p className="mr-4 text-white">+{regionCode}</p>
|
|
<Input
|
|
placeholder="请输入手机号"
|
|
clearable
|
|
type="number"
|
|
value={mobilePhone}
|
|
onChange={(value) => setMobilePhone(value)}
|
|
/>
|
|
</div>
|
|
</Form.Item>
|
|
<hr className="mx-4 border-neutral" />
|
|
<Form.Item
|
|
name="veri_code"
|
|
extra={
|
|
<button disabled={isCounting} onClick={handleVerification}>
|
|
<p className={isCounting ? "" : "text-primary"}>
|
|
{isCounting ? `(${seconds})重新发送` : "获取验证码"}
|
|
</p>
|
|
</button>
|
|
}
|
|
>
|
|
<div className="flex flex-row">
|
|
<p className="mr-4 text-white whitespace-nowrap">验证码</p>
|
|
<Input placeholder="请输入验证码" clearable type="number" />
|
|
</div>
|
|
</Form.Item>
|
|
</div>
|
|
<div className="flex justify-center mt-8 mb-4">
|
|
<Checkbox
|
|
style={{
|
|
"--icon-size": "18px",
|
|
"--font-size": "14px",
|
|
"--gap": "6px",
|
|
}}
|
|
checked={checked}
|
|
onChange={() => setChecked(!checked)}
|
|
>
|
|
<p className="text-gray-400 text-sm">
|
|
同意
|
|
<Link className="link text-primary" href="/doc/useragreement">
|
|
《用户协议》
|
|
</Link>
|
|
、
|
|
<Link className="link text-primary" href="/doc/privatypolicy">
|
|
《隐私政策》
|
|
</Link>
|
|
</p>
|
|
</Checkbox>
|
|
</div>
|
|
<div className="flex justify-center">
|
|
<button
|
|
type="submit"
|
|
className="btn btn-primary w-full text-base text-white font-medium"
|
|
>
|
|
登录
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</Form>
|
|
</div>
|
|
</section>
|
|
);
|
|
}
|