import { useRouter } from "expo-router"; import React, { useEffect, useRef, useState } from "react"; import { Alert, ImageBackground, KeyboardAvoidingView, Platform, ScrollView, StatusBar, StyleSheet, Text, TextInput, TouchableOpacity, View, } from "react-native"; import { useSafeAreaInsets } from "react-native-safe-area-context"; import { Images } from "@/constants/images"; import { login, sendVerifyCode } from "@/services/user"; export default function LoginScreen() { const router = useRouter(); const insets = useSafeAreaInsets(); const [phone, setPhone] = useState(""); const [verifyCode, setVerifyCode] = useState(""); const [agreeFlag, setAgreeFlag] = useState(false); const [countdown, setCountdown] = useState(0); const [disabled, setDisabled] = useState(false); const [loading, setLoading] = useState(false); const [tips, setTips] = useState("获取验证码"); const timerRef = useRef | null>(null); useEffect(() => { return () => { if (timerRef.current) { clearInterval(timerRef.current); } }; }, []); // 验证手机号 const isChinesePhoneNumber = (phoneNumber: string) => { const phoneNumberPattern = /^1[3-9]\d{9}$/; return phoneNumberPattern.test(phoneNumber); }; // 开始倒计时 const startCountdown = () => { setDisabled(true); let count = 60; setTips(`${count}s后重新获取`); timerRef.current = setInterval(() => { count--; if (count > 0) { setTips(`${count}s后重新获取`); } else { resetCountdown(); } }, 1000); }; // 重置倒计时 const resetCountdown = () => { setDisabled(false); setTips("获取验证码"); if (timerRef.current) { clearInterval(timerRef.current); timerRef.current = null; } }; // 获取验证码 const handleGetVerifyCode = async () => { if (disabled) return; if (phone && isChinesePhoneNumber(phone)) { try { const res = await sendVerifyCode(phone, "LOGIN"); if (res) { Alert.alert("提示", "验证码已发送"); startCountdown(); } } catch (error) { Alert.alert("错误", "获取验证码失败,请重试"); } } else { Alert.alert("提示", "请输入正确的手机号"); } }; // 登录 const handleLogin = async () => { if (!agreeFlag) { Alert.alert("提示", "请您先阅读并同意用户协议和隐私政策"); return; } if (phone && isChinesePhoneNumber(phone) && verifyCode) { setLoading(true); try { const result = await login({ loginWay: "MOBILE", mobile: phone, verifycode: verifyCode, }); if (result.success) { // TODO: 如果 needInfo 为 true,跳转到完善信息页面 // if (result.needInfo) { // router.replace('/user-info'); // return; // } router.back(); } else { Alert.alert("错误", "登录失败,请检查验证码"); } } catch (error) { Alert.alert("错误", "登录失败"); } setLoading(false); } else { Alert.alert("提示", "请输入手机号和验证码"); } }; const goBack = () => { router.back(); }; return ( {/* 底部表单区域 */} {/* 表单 */} {/* 手机号输入 */} 手机号 {/* 验证码输入 */} 验证码 {tips} {/* 协议勾选 */} setAgreeFlag(!agreeFlag)} activeOpacity={0.8} > {agreeFlag && } 我已阅读并同意 router.push({ pathname: "/agreement", params: { type: "user.html" }, }) } > 《用户协议》 router.push({ pathname: "/agreement", params: { type: "privacy.html" }, }) } > 《隐私政策》 {/* 按钮区域 */} {loading ? "登录中..." : "登录"} 返回 ); } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: "#1a1a2e", }, background: { flex: 1, }, keyboardView: { flex: 1, }, scrollContent: { flexGrow: 1, justifyContent: "flex-end", }, bottom: { width: "100%", }, form: { paddingHorizontal: 25, }, formItem: { flexDirection: "row", alignItems: "center", paddingVertical: 12, }, label: { color: "#fff", fontSize: 14, width: 50, }, input: { flex: 1, color: "#fff", fontSize: 14, paddingVertical: 8, outlineStyle: "none", } as any, codeInput: { flex: 1, }, divider: { height: 1, backgroundColor: "rgba(255,255,255,0.2)", }, verifyBtn: { backgroundColor: "#000", borderRadius: 4, paddingHorizontal: 10, paddingVertical: 5, minWidth: 80, alignItems: "center", }, verifyBtnDisabled: { backgroundColor: "#ccc", }, verifyBtnText: { color: "#fff", fontSize: 12, }, verifyBtnTextDisabled: { color: "#666", }, agreeCheckboxArea: { flexDirection: "row", alignItems: "center", }, agree: { flexDirection: "row", alignItems: "center", justifyContent: "center", marginTop: 25, paddingHorizontal: 25, }, radio: { width: 16, height: 16, borderRadius: 8, borderWidth: 1, borderColor: "rgba(255,255,255,0.5)", marginRight: 6, justifyContent: "center", alignItems: "center", }, radioChecked: { borderColor: "#8b3dff", backgroundColor: "#8b3dff", }, radioInner: { width: 6, height: 6, borderRadius: 3, backgroundColor: "#fff", }, agreeText: { color: "#fff", fontSize: 12, }, linkText: { color: "#8b3dff", }, btnArea: { paddingTop: 15, alignItems: "center", }, btn: { width: 234, height: 45, overflow: "hidden", }, loginBtnBg: { width: "100%", height: "100%", justifyContent: "center", alignItems: "center", }, btnDisabled: { opacity: 0.6, }, btnText: { color: "#fff", fontSize: 14, fontWeight: "600", }, btnBack: { width: 234, height: 35, backgroundColor: "#fff", borderRadius: 25, justifyContent: "center", alignItems: "center", marginTop: 10, borderWidth: 1, borderColor: "#fff", }, btnBackText: { color: "#888", fontSize: 12, }, });