| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264 |
- import { Button, Toast } from '@ant-design/react-native';
- import { Ionicons } from '@expo/vector-icons';
- import { router } from 'expo-router';
- import React, { useRef, useState } from 'react';
- import {
- KeyboardAvoidingView,
- Platform,
- Pressable,
- ScrollView,
- StyleSheet,
- Text,
- TextInput,
- View,
- } from 'react-native';
- import { SafeAreaView } from 'react-native-safe-area-context';
- function FieldLabel({ children }: { children: React.ReactNode }) {
- return (
- <Text className="mb-2 ml-1 text-xs font-bold uppercase tracking-widest text-outline">
- {children}
- </Text>
- );
- }
- export default function SignUpScreen() {
- const [mobile, setMobile] = useState('');
- const [password, setPassword] = useState('');
- const [email, setEmail] = useState('');
- const [name, setName] = useState('');
- const [organization, setOrganization] = useState('');
- const [agreed, setAgreed] = useState(false);
- const [flushAgree, setFlushAgree] = useState(false);
- const [loading, setLoading] = useState(false);
- const scrollView = useRef<ScrollView>(null);
- const handleRegister = async () => {
- setFlushAgree(false);
- if (mobile.trim().length !== 11) {
- Toast.fail('请输入正确的手机号');
- return;
- }
- if (password.trim().length < 6) {
- Toast.fail('请输入不少于 6 位的登录密码');
- return;
- }
- if (!email.includes('@')) {
- Toast.fail('请输入正确的邮箱');
- return;
- }
- if (!name.trim()) {
- Toast.fail('请输入姓名');
- return;
- }
- if (!organization.trim()) {
- Toast.fail('请输入所属机构');
- return;
- }
- if (!agreed) {
- Toast.fail('请先阅读并同意协议');
- setFlushAgree(true);
- scrollView.current?.scrollToEnd({ animated: true });
- return;
- }
- setLoading(true);
- const toastKey = Toast.loading('正在创建账号...');
- try {
- await new Promise((resolve) => setTimeout(resolve, 600));
- Toast.success('注册成功,请登录');
- router.replace('/sign-in');
- } catch (error) {
- console.error('注册失败:', error);
- Toast.fail('注册失败,请稍后重试');
- } finally {
- setLoading(false);
- Toast.remove(toastKey);
- }
- };
- return (
- <SafeAreaView className="flex-1 bg-surface">
- <KeyboardAvoidingView
- className="flex-1"
- behavior={Platform.OS === 'ios' ? 'padding' : undefined}
- >
- <ScrollView
- ref={scrollView}
- className="flex-1"
- contentContainerClassName="px-8 pt-12 pb-10"
- contentContainerStyle={{ flexGrow: 1 }}
- keyboardShouldPersistTaps="handled"
- showsVerticalScrollIndicator={false}
- >
- <View className="absolute -top-24 -right-24 h-96 w-96 rounded-full bg-primary-container/10" />
- <View className="absolute top-32 -left-20 h-64 w-64 rounded-full bg-secondary-container/20" />
- <View className="absolute -bottom-16 right-0 h-48 w-48 rounded-full bg-primary-fixed/50" />
- <View className="flex-1 justify-between">
- <View>
- <View className="mb-12">
- <View className="mb-6 h-16 w-16 items-center justify-center rounded-2xl bg-primary-container shadow-lg">
- <Ionicons name="sparkles" size={30} color="#ffffff" />
- </View>
- <Text className="mb-2 text-4xl font-extrabold tracking-tight text-on-surface">
- 创建账号
- </Text>
- <Text className="text-base font-medium leading-7 text-on-surface-variant">
- 完善基础信息,开启您的智能借贷助手工作台
- </Text>
- </View>
- <View className="mb-8 rounded-2xl bg-surface-container-lowest p-3 shadow-sm">
- <View className="px-2 pb-2">
- <FieldLabel>手机号码</FieldLabel>
- <View className="mb-5 flex-row items-center rounded-2xl bg-surface-container-low px-5 py-4">
- <Text className="text-2xl font-bold text-on-surface">+86</Text>
- <View
- className="mx-4 h-5 bg-outline-variant/40"
- style={{ width: StyleSheet.hairlineWidth }}
- />
- <TextInput
- value={mobile}
- onChangeText={setMobile}
- editable={!loading}
- keyboardType="phone-pad"
- maxLength={11}
- placeholder="请输入手机号"
- placeholderTextColor="#9ca3af"
- className="flex-1 p-0 text-xl font-medium text-on-surface"
- />
- <Ionicons
- name="phone-portrait-outline"
- size={22}
- color="#c3c6d7"
- />
- </View>
- <FieldLabel>登录密码</FieldLabel>
- <View className="mb-5 flex-row items-center rounded-2xl bg-surface-container-low px-5 py-4">
- <TextInput
- value={password}
- onChangeText={setPassword}
- editable={!loading}
- secureTextEntry
- maxLength={20}
- placeholder="请输入不少于 6 位的密码"
- placeholderTextColor="#9ca3af"
- className="flex-1 p-0 text-xl font-medium text-on-surface"
- />
- <Ionicons name="lock-closed-outline" size={22} color="#c3c6d7" />
- </View>
- <FieldLabel>邮箱</FieldLabel>
- <View className="mb-5 flex-row items-center rounded-2xl bg-surface-container-low px-5 py-4">
- <TextInput
- value={email}
- onChangeText={setEmail}
- editable={!loading}
- keyboardType="email-address"
- autoCapitalize="none"
- placeholder="请输入常用邮箱"
- placeholderTextColor="#9ca3af"
- className="flex-1 p-0 text-xl font-medium text-on-surface"
- />
- <Ionicons name="mail-outline" size={22} color="#c3c6d7" />
- </View>
- <FieldLabel>姓名</FieldLabel>
- <View className="mb-5 flex-row items-center rounded-2xl bg-surface-container-low px-5 py-4">
- <TextInput
- value={name}
- onChangeText={setName}
- editable={!loading}
- placeholder="请输入姓名"
- placeholderTextColor="#9ca3af"
- className="flex-1 p-0 text-xl font-medium text-on-surface"
- />
- <Ionicons name="person-outline" size={22} color="#c3c6d7" />
- </View>
- <FieldLabel>所属机构</FieldLabel>
- <View className="flex-row items-center rounded-2xl bg-surface-container-low px-5 py-4">
- <TextInput
- value={organization}
- onChangeText={setOrganization}
- editable={!loading}
- placeholder="请输入所属机构"
- placeholderTextColor="#9ca3af"
- className="flex-1 p-0 text-xl font-medium text-on-surface"
- />
- <Ionicons name="business-outline" size={22} color="#c3c6d7" />
- </View>
- </View>
- </View>
- <View className="mb-8 gap-4">
- <Button type="primary" loading={loading} onPress={handleRegister}>
- 注册账号
- </Button>
- <View className="flex-row items-center justify-between px-3">
- <Pressable hitSlop={8} onPress={() => router.back()}>
- <Text className="text-lg font-medium text-on-surface-variant">
- 返回登录
- </Text>
- </Pressable>
- <Pressable hitSlop={8}>
- <Text className="text-lg font-medium text-on-surface-variant">
- 遇到问题?
- </Text>
- </Pressable>
- </View>
- </View>
- </View>
- <View className="pt-4">
- <View
- className={`flex-row items-start gap-3 rounded-md border-2 border-transparent px-2 transition delay-300 ${
- flushAgree ? 'border-primary/50' : ''
- }`}
- >
- <Pressable
- onPress={() => setAgreed((value) => !value)}
- hitSlop={8}
- className="pt-1"
- >
- <View
- className={`h-6 w-6 items-center justify-center rounded-full ${
- agreed
- ? 'border-primary bg-primary'
- : 'border-outline-variant bg-surface-container-low'
- }`}
- >
- {agreed ? (
- <Ionicons name="checkmark" size={14} color="#ffffff" />
- ) : null}
- </View>
- </Pressable>
- <Text className="flex-1 text-sm leading-7 text-on-surface-variant">
- 注册即代表您已阅读并同意
- <Text className="cursor-pointer font-semibold text-primary">
- 《用户服务协议》
- </Text>
- 、
- <Text className="cursor-pointer font-semibold text-primary">
- 《隐私政策》
- </Text>
- ,并授权该应用用于账户创建与服务通知。
- </Text>
- </View>
- </View>
- </View>
- </ScrollView>
- </KeyboardAvoidingView>
- </SafeAreaView>
- );
- }
|