314 lines
9.5 KiB
React
314 lines
9.5 KiB
React
|
import {
|
||
|
View,
|
||
|
Text,
|
||
|
TextInput,
|
||
|
TouchableWithoutFeedback,
|
||
|
Keyboard,
|
||
|
ScrollView,
|
||
|
} from "react-native";
|
||
|
import React, { useState, useEffect, useContext } from "react";
|
||
|
import { useTailwind } from "tailwind-rn";
|
||
|
import { Button } from "@rneui/themed";
|
||
|
import Toast from "react-native-toast-message";
|
||
|
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
||
|
import { get } from "../../../utils/storeInfo";
|
||
|
import { JSEncrypt } from "jsencrypt";
|
||
|
import { cryptoPassword, generateSignature } from "../../../utils/crypto";
|
||
|
import { AuthContext } from "../../../App";
|
||
|
import MyDivider from "../../../components/MyDivider";
|
||
|
import baseRequest from "../../../utils/baseRequest";
|
||
|
|
||
|
export default function EditPassword({ navigation }) {
|
||
|
const { signOut } = useContext(AuthContext);
|
||
|
const insets = useSafeAreaInsets();
|
||
|
const tailwind = useTailwind();
|
||
|
|
||
|
//获取环境变量
|
||
|
const apiUrl = process.env.EXPO_PUBLIC_API_URL;
|
||
|
|
||
|
//保存区号、手机号、验证码、旧密码、新密码
|
||
|
const [regionCode, setRegionCode] = useState("");
|
||
|
const [mobilePhone, setMobilePhone] = useState("");
|
||
|
const [veriCode, setVeriCode] = useState("");
|
||
|
const [newPassword, setNewPassword] = useState("");
|
||
|
const [confirmPassword, setConfirmPassword] = useState("");
|
||
|
|
||
|
//获取当前用户的手机号
|
||
|
useEffect(() => {
|
||
|
async function getMobilePhone() {
|
||
|
setMobilePhone(await get("mobile_phone"));
|
||
|
setRegionCode(await get("region_code"));
|
||
|
}
|
||
|
getMobilePhone();
|
||
|
}, []);
|
||
|
|
||
|
//重新获取验证码的计时器
|
||
|
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({
|
||
|
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 handleUpdatePassword = async () => {
|
||
|
//验证数据格式
|
||
|
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;
|
||
|
}
|
||
|
if (!confirmPassword) {
|
||
|
Toast.show({
|
||
|
type: "error",
|
||
|
text1: "请再次输入您的密码",
|
||
|
topOffset: 60,
|
||
|
});
|
||
|
return;
|
||
|
}
|
||
|
if (newPassword != confirmPassword) {
|
||
|
Toast.show({
|
||
|
type: "error",
|
||
|
text1: "两次输入密码不一致",
|
||
|
topOffset: 60,
|
||
|
});
|
||
|
return;
|
||
|
}
|
||
|
if (newPassword.length < 8) {
|
||
|
Toast.show({
|
||
|
type: "error",
|
||
|
text1: "新密码不得小于8位",
|
||
|
topOffset: 60,
|
||
|
});
|
||
|
return;
|
||
|
}
|
||
|
if (newPassword.length > 15) {
|
||
|
Toast.show({
|
||
|
type: "error",
|
||
|
text1: "新密码不得大于15位",
|
||
|
topOffset: 60,
|
||
|
});
|
||
|
return;
|
||
|
}
|
||
|
//对手机号进行RSA加密
|
||
|
const encrypt = new JSEncrypt();
|
||
|
encrypt.setPublicKey(process.env.EXPO_PUBLIC_RSA_KEY);
|
||
|
const mobile_phone = encrypt.encrypt(mobilePhone);
|
||
|
//MD5加密新旧密码
|
||
|
const encryptedNewPassword = await cryptoPassword(newPassword);
|
||
|
//发送修改密码请求
|
||
|
const base = await baseRequest();
|
||
|
const signature = await generateSignature({
|
||
|
mobile_phone: mobile_phone,
|
||
|
region_code: regionCode,
|
||
|
veri_code: veriCode,
|
||
|
new_password: encryptedNewPassword,
|
||
|
...base,
|
||
|
});
|
||
|
try {
|
||
|
const response = await fetch(
|
||
|
`${apiUrl}/api/login/reset_password?signature=${signature}`,
|
||
|
{
|
||
|
method: "POST",
|
||
|
headers: {
|
||
|
"Content-Type": "application/json",
|
||
|
},
|
||
|
body: JSON.stringify({
|
||
|
mobile_phone: mobile_phone,
|
||
|
region_code: regionCode,
|
||
|
veri_code: veriCode,
|
||
|
new_password: encryptedNewPassword,
|
||
|
...base,
|
||
|
}),
|
||
|
}
|
||
|
);
|
||
|
const data = await response.json();
|
||
|
if (data.ret === -1) {
|
||
|
Toast.show({
|
||
|
type: "error",
|
||
|
text1: data.msg,
|
||
|
topOffset: 60,
|
||
|
});
|
||
|
return;
|
||
|
}
|
||
|
Toast.show({
|
||
|
type: "success",
|
||
|
text1: "修改成功,请重新登录",
|
||
|
topOffset: 60,
|
||
|
});
|
||
|
signOut();
|
||
|
} catch (error) {
|
||
|
console.error(error);
|
||
|
}
|
||
|
};
|
||
|
return (
|
||
|
<TouchableWithoutFeedback onPress={() => Keyboard.dismiss()}>
|
||
|
<ScrollView
|
||
|
style={{
|
||
|
paddingTop: insets.top,
|
||
|
paddingBottom: insets.bottom,
|
||
|
paddingLeft: insets.left,
|
||
|
paddingRight: insets.right,
|
||
|
...tailwind("flex-1 flex-col"),
|
||
|
}}
|
||
|
>
|
||
|
<View style={tailwind("flex px-4 mt-32 justify-center")}>
|
||
|
<Text style={tailwind("text-3xl text-white font-medium")}>
|
||
|
修改密码
|
||
|
</Text>
|
||
|
<Text style={tailwind("text-base text-white mb-10")}>请牢记密码</Text>
|
||
|
<View style={tailwind("border-2 border-[#2c2b2f] rounded-2xl p-4")}>
|
||
|
<View
|
||
|
style={tailwind("flex flex-row flex-nowrap items-center mb-4")}
|
||
|
>
|
||
|
<Text style={tailwind("text-base text-white mr-4")}>
|
||
|
+{regionCode}
|
||
|
</Text>
|
||
|
<TextInput
|
||
|
placeholder="未获取到手机号,请重新登录"
|
||
|
placeholderTextColor="#FFFFFF80"
|
||
|
underlineColorAndroid="transparent"
|
||
|
keyboardType="numeric"
|
||
|
editable={false}
|
||
|
onChangeText={(value) => setMobilePhone(value)}
|
||
|
value={mobilePhone}
|
||
|
style={tailwind("flex-1 text-white")}
|
||
|
/>
|
||
|
</View>
|
||
|
<MyDivider />
|
||
|
<View
|
||
|
style={tailwind("flex flex-row flex-nowrap items-center my-4")}
|
||
|
>
|
||
|
<Text style={tailwind("text-base text-white 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-sm font-medium mx-2")}
|
||
|
onPress={handleVerification}
|
||
|
>
|
||
|
{isCounting ? `(${seconds})重新发送` : "获取验证码"}
|
||
|
</Button>
|
||
|
</View>
|
||
|
<MyDivider />
|
||
|
<View
|
||
|
style={tailwind("flex flex-row flex-nowrap items-center my-4")}
|
||
|
>
|
||
|
<Text style={tailwind("text-base text-white mr-4")}>新密码</Text>
|
||
|
<TextInput
|
||
|
placeholder="请输入8-15位新密码"
|
||
|
placeholderTextColor="#FFFFFF80"
|
||
|
underlineColorAndroid="transparent"
|
||
|
secureTextEntry={true}
|
||
|
onChangeText={(value) => setNewPassword(value)}
|
||
|
value={newPassword}
|
||
|
style={tailwind("flex-1 text-white")}
|
||
|
/>
|
||
|
</View>
|
||
|
<MyDivider />
|
||
|
<View
|
||
|
style={tailwind("flex flex-row flex-nowrap items-center mt-4")}
|
||
|
>
|
||
|
<Text style={tailwind("text-base text-white mr-4")}>
|
||
|
确认密码
|
||
|
</Text>
|
||
|
<TextInput
|
||
|
placeholder="请再次输入新密码"
|
||
|
placeholderTextColor="#FFFFFF80"
|
||
|
underlineColorAndroid="transparent"
|
||
|
secureTextEntry={true}
|
||
|
onChangeText={(value) => setConfirmPassword(value)}
|
||
|
value={confirmPassword}
|
||
|
style={tailwind("flex-1 text-white")}
|
||
|
/>
|
||
|
</View>
|
||
|
</View>
|
||
|
<Button
|
||
|
color="#FF669E"
|
||
|
radius="999"
|
||
|
size="md"
|
||
|
onPress={handleUpdatePassword}
|
||
|
titleStyle={tailwind("text-base font-medium")}
|
||
|
containerStyle={tailwind("mt-16")}
|
||
|
>
|
||
|
确认修改
|
||
|
</Button>
|
||
|
</View>
|
||
|
</ScrollView>
|
||
|
</TouchableWithoutFeedback>
|
||
|
);
|
||
|
}
|