306 lines
9.4 KiB
JavaScript
306 lines
9.4 KiB
JavaScript
import { View, Text, TextInput } from "react-native";
|
|
import React, { useState, useEffect, useContext } from "react";
|
|
import { useTailwind } from "tailwind-rn";
|
|
import { Button, CheckBox } from "@rneui/themed";
|
|
import { useNavigation } from "@react-navigation/native";
|
|
import Toast from "react-native-toast-message";
|
|
import { AuthContext } from "../../../App";
|
|
import { JSEncrypt } from "jsencrypt";
|
|
import MyDivider from "../../../components/MyDivider";
|
|
import baseRequest from "../../../utils/baseRequest";
|
|
import { get, save, storeAppInfo } from "../../../utils/storeInfo";
|
|
import { generateSignature } from "../../../utils/crypto";
|
|
|
|
export default function PhoneNumLogin() {
|
|
const { signIn, inviterCode, checked, setChecked } = useContext(AuthContext);
|
|
const navigation = useNavigation();
|
|
const tailwind = useTailwind();
|
|
//设置checkbox
|
|
const toggleCheckbox = () => setChecked(!checked);
|
|
//重新获取验证码的计时器
|
|
const [isCounting, setIsCounting] = useState(false);
|
|
const [seconds, setSeconds] = useState(60);
|
|
const [isLoading, setIsLoading] = useState(false);
|
|
//保存区号、手机号、验证码
|
|
const [regionCode, setRegionCode] = useState("86");
|
|
const [mobilePhone, setMobilePhone] = useState("");
|
|
const [veriCode, setVeriCode] = useState("");
|
|
|
|
//获取之前缓存的用户的手机号
|
|
useEffect(() => {
|
|
async function getMobilePhone() {
|
|
const mobile_phone = await get("mobile_phone");
|
|
const region_code = await get("region_code");
|
|
if (mobile_phone && region_code) {
|
|
setMobilePhone(mobile_phone);
|
|
setRegionCode(region_code);
|
|
}
|
|
}
|
|
getMobilePhone();
|
|
}, []);
|
|
|
|
//获取环境变量
|
|
const apiUrl = process.env.EXPO_PUBLIC_API_URL;
|
|
|
|
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({
|
|
type: "error",
|
|
text1: "手机号码格式错误",
|
|
topOffset: 60,
|
|
});
|
|
return;
|
|
}
|
|
//开始倒计时
|
|
setIsCounting(true);
|
|
//对手机号进行RSA加密
|
|
const encrypt = new JSEncrypt();
|
|
encrypt.setPublicKey(process.env.EXPO_PUBLIC_RSA_KEY);
|
|
const mobile_phone = encrypt.encrypt(mobilePhone);
|
|
//发送短信验证码
|
|
const base = await baseRequest();
|
|
const signature = await generateSignature({
|
|
mobile_phone: mobile_phone,
|
|
region_code: regionCode,
|
|
...base,
|
|
});
|
|
try {
|
|
await fetch(`${apiUrl}/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);
|
|
}
|
|
};
|
|
|
|
//点击登录
|
|
const handleSubmit = async () => {
|
|
if (!checked) {
|
|
Toast.show({
|
|
type: "error",
|
|
text1: "请先阅读并同意《用户协议》和《隐私政策》后登录",
|
|
topOffset: 60,
|
|
});
|
|
return;
|
|
}
|
|
if (!mobilePhone.match(/^1[3456789]\d{9}$/)) {
|
|
Toast.show({
|
|
type: "error",
|
|
text1: "手机号码格式错误",
|
|
topOffset: 60,
|
|
});
|
|
return;
|
|
}
|
|
if (!veriCode) {
|
|
Toast.show({
|
|
type: "error",
|
|
text1: "请输入验证码",
|
|
topOffset: 60,
|
|
});
|
|
return;
|
|
}
|
|
//重新获取设备和app信息
|
|
await storeAppInfo();
|
|
//对手机号进行RSA加密
|
|
const encrypt = new JSEncrypt();
|
|
encrypt.setPublicKey(process.env.EXPO_PUBLIC_RSA_KEY);
|
|
const mobile_phone = encrypt.encrypt(mobilePhone);
|
|
//发送登录请求
|
|
const base = await baseRequest();
|
|
const signature = await generateSignature({
|
|
mobile_phone: mobile_phone,
|
|
region_code: regionCode,
|
|
veri_code: veriCode,
|
|
inviter: inviterCode,
|
|
...base,
|
|
});
|
|
setIsLoading(true);
|
|
try {
|
|
const response = await fetch(
|
|
`${apiUrl}/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: veriCode,
|
|
inviter: inviterCode,
|
|
...base,
|
|
}),
|
|
}
|
|
);
|
|
const data = await response.json();
|
|
if (data.ret === -1) {
|
|
setIsLoading(false);
|
|
Toast.show({
|
|
type: "error",
|
|
text1: data.msg,
|
|
topOffset: 60,
|
|
});
|
|
return;
|
|
}
|
|
//保存账号信息,用于切换账号
|
|
await save(`account_list_${data.data.account.user_id}`, {
|
|
mobile_phone_origion: mobilePhone,
|
|
mobile_phone: mobile_phone,
|
|
region_code: regionCode,
|
|
account: data.data.account,
|
|
login_time: new Date().getTime(),
|
|
});
|
|
//若已经设置了密码则直接登录
|
|
if (data.data.is_enabled) {
|
|
setIsLoading(false);
|
|
signIn(data, mobilePhone, regionCode);
|
|
return;
|
|
}
|
|
//若没设置密码则前往设置密码
|
|
await save("token", data.data.token);
|
|
await save("account", data.data.account);
|
|
await save("mobile_phone", mobile_phone);
|
|
await save("region_code", regionCode);
|
|
setIsLoading(false);
|
|
navigation.navigate("SetPassword", {
|
|
data: data,
|
|
mobile_phone: mobile_phone,
|
|
region_code: regionCode,
|
|
mobilePhone: mobilePhone,
|
|
});
|
|
} catch (error) {
|
|
setIsLoading(false);
|
|
console.error(error);
|
|
}
|
|
};
|
|
return (
|
|
<View style={tailwind("mt-14 flex-1 flex-col")}>
|
|
<View style={tailwind("flex px-10 justify-center")}>
|
|
<View style={tailwind("border-2 border-[#2c2b2f] rounded-2xl p-4")}>
|
|
<View style={tailwind("flex flex-row flex-nowrap items-center")}>
|
|
<Text style={tailwind("text-base text-white font-medium mr-4")}>
|
|
+{regionCode}
|
|
</Text>
|
|
<TextInput
|
|
placeholder="请输入手机号"
|
|
placeholderTextColor="#FFFFFF80"
|
|
underlineColorAndroid="transparent"
|
|
keyboardType="numeric"
|
|
onChangeText={(value) => setMobilePhone(value)}
|
|
value={mobilePhone}
|
|
style={tailwind("flex-1 text-white")}
|
|
/>
|
|
</View>
|
|
<View style={tailwind("my-4")}>
|
|
<MyDivider />
|
|
</View>
|
|
<View style={tailwind("flex flex-row flex-nowrap items-center")}>
|
|
<Text style={tailwind("text-base text-white font-medium mr-4")}>
|
|
验证码
|
|
</Text>
|
|
<TextInput
|
|
placeholder="请输入验证码"
|
|
placeholderTextColor="#FFFFFF80"
|
|
underlineColorAndroid="transparent"
|
|
keyboardType="numeric"
|
|
onChangeText={(value) => setVeriCode(value)}
|
|
value={veriCode}
|
|
style={tailwind("flex-1 text-white")}
|
|
/>
|
|
<Button
|
|
color="#FF669E"
|
|
radius="999"
|
|
size="sm"
|
|
disabled={isCounting}
|
|
disabledStyle={tailwind("bg-[#FFFFFF1A]")}
|
|
titleStyle={tailwind("text-xs mx-1")}
|
|
onPress={handleVerification}
|
|
>
|
|
{isCounting ? `(${seconds})重新发送` : "获取验证码"}
|
|
</Button>
|
|
</View>
|
|
</View>
|
|
<View
|
|
style={tailwind(
|
|
"flex flex-row flex-nowrap justify-center items-center mt-16"
|
|
)}
|
|
>
|
|
<CheckBox
|
|
checked={checked}
|
|
onPress={toggleCheckbox}
|
|
iconType="material-community"
|
|
checkedIcon="checkbox-marked"
|
|
uncheckedIcon="checkbox-blank-outline"
|
|
checkedColor="#FF669E"
|
|
containerStyle={tailwind("p-0 m-0 bg-transparent")}
|
|
size={18}
|
|
/>
|
|
<Text style={tailwind("text-[#FFFFFF80] font-medium text-xs")}>
|
|
我已阅读并同意
|
|
<Text
|
|
onPress={() =>
|
|
navigation.navigate("WebWithHeader", {
|
|
title: "用户协议",
|
|
uri: `${process.env.EXPO_PUBLIC_WEB_URL}/doc/useragreement`,
|
|
})
|
|
}
|
|
style={tailwind("text-[#FF669E] text-xs")}
|
|
>
|
|
《用户协议》
|
|
</Text>
|
|
、
|
|
<Text
|
|
onPress={() =>
|
|
navigation.navigate("WebWithHeader", {
|
|
title: "隐私政策",
|
|
uri: `${process.env.EXPO_PUBLIC_WEB_URL}/doc/privatypolicy`,
|
|
})
|
|
}
|
|
style={tailwind("text-[#FF669E] text-xs")}
|
|
>
|
|
《隐私政策》
|
|
</Text>
|
|
</Text>
|
|
</View>
|
|
<Button
|
|
color="#FF669E"
|
|
radius="999"
|
|
size="md"
|
|
loading={isLoading}
|
|
onPress={handleSubmit}
|
|
titleStyle={tailwind("text-base font-medium")}
|
|
containerStyle={tailwind("mt-2")}
|
|
>
|
|
登录
|
|
</Button>
|
|
</View>
|
|
</View>
|
|
);
|
|
}
|