skyouc
2025-05-23 6883e31331af4633d1b7d74ea7deb5f972afa05d
rsf-admin/src/page/login/Register.jsx
@@ -15,11 +15,13 @@
    useTranslate,
    useLogin,
    useNotify,
    email as validEmail,
} from 'react-admin';
import { useForm, Controller } from 'react-hook-form';
import ProviderChoices from "./ProviderChoices";
import Visibility from '@mui/icons-material/Visibility';
import VisibilityOff from '@mui/icons-material/VisibilityOff';
import { sendEmailCode, register } from '@/api/auth';
const Register = (props) => {
    const translate = useTranslate();
@@ -28,82 +30,116 @@
    const location = useLocation();
    const { systemInfo } = props;
    const { control, watch, handleSubmit, setValue } = useForm();
    const { control, watch, handleSubmit, setValue, setError, clearErrors } = useForm();
    const email = watch('email');
    const username = watch('username');
    const password = watch('password');
    const confirmPassword = watch('confirmPassword');
    const code = watch('code');
    const [loading, setLoading] = useState(false);
    const [codeLoading, setCodeLoading] = useState(false);
    const [showPassword, setShowPassword] = useState(true);
    const [isCounting, setIsCounting] = useState(false);
    const [countdown, setCountdown] = useState(60);
    // 处理验证码按钮点击
    // send code
    const handleSendCode = async () => {
        // 这里假设发送验证码的请求
        const response = await fetch('/api/send-code');
        if (response.ok) {
            setIsCounting(true);
            localStorage.setItem('codeCountdown', 60); // 存储倒计时到本地
        if (!email) {
            setError("email", {
                message: translate('ra.validation.required')
            })
            return;
        }
        const emailError = validEmail()(email);
        if (emailError) {
            setError("email", {
                message: translate("ra.validation.email")
            })
            return;
        }
        clearErrors("email");
        setCodeLoading(true);
        sendEmailCode({ email }).then(res => {
            setCodeLoading(false);
            const { code, msg, data } = res;
            if (code === 200) {
                notify(msg, { type: 'success', messageArgs: { _: msg } });
                const timestamp = Math.floor(Date.now() / 1000);
                const expirationTime = timestamp + 60;
                localStorage.setItem('codeExpirationTime', expirationTime);
                setIsCounting(true);
                setCountdown(60);
            } else if (code === 10005 || code === 10006) {
                setError('email', {
                    message: msg
                })
            } else {
                notify(msg, { type: 'error', messageArgs: { _: msg } });
            }
        }).catch((error) => {
            setCodeLoading(false);
            notify(error.message, { type: 'error', messageArgs: { _: error.message } });
            console.error(error);
        })
    };
    // 倒计时功能
    // countdown
    useEffect(() => {
        const savedCountdown = localStorage.getItem('codeCountdown');
        if (savedCountdown && !isCounting) {
            setCountdown(Number(savedCountdown));
            setIsCounting(true);
        const codeExpirationTime = localStorage.getItem('codeExpirationTime');
        if (codeExpirationTime) {
            const currentTimestamp = Math.floor(Date.now() / 1000);
            const remainingTime = codeExpirationTime - currentTimestamp;
            if (remainingTime > 0) {
                setCountdown(remainingTime);
                setIsCounting(true);
            }
        }
        const interval = setInterval(() => {
            if (isCounting && countdown > 0) {
                setCountdown(prev => prev - 1);
                localStorage.setItem('codeCountdown', countdown - 1);
            } else if (countdown <= 0) {
                clearInterval(interval);
                setIsCounting(false);
                localStorage.removeItem('codeCountdown'); // 重置
                localStorage.removeItem('codeExpirationTime');
            }
        }, 1000);
        return () => clearInterval(interval);
    }, [countdown, isCounting]);
    const onSubmit = (data) => {
        notify("Registration is not open yet");
        return;
    // register
    const onSubmit = (params) => {
        setLoading(true);
        // js native confirm && root
        login(
            data,
            location.state ? (location.state).nextPathname : '/'
        ).catch((error) => {
        register(params).then(res => {
            setLoading(false);
            notify(
                typeof error === 'string'
                    ? error
                    : typeof error === 'undefined' || !error.message
                        ? 'ra.auth.sign_in_error'
                        : error.message,
                {
                    type: 'error',
                    messageArgs: {
                        _:
                            typeof error === 'string'
                                ? error
                                : error && error.message
                                    ? error.message
                                    : undefined,
                    },
                }
            );
        });
            const { code, msg, data } = res;
            if (code === 200) {
                notify(msg, { type: 'success', messageArgs: { _: msg } });
                // to login
                login(
                    params,
                    location.state ? (location.state).nextPathname : '/'
                ).catch(({ code, msg }) => {
                    setLoading(false);
                    notify(msg, { type: 'error', messageArgs: { _: msg } });
                });
            } else if (code === 10002) {
                setError("username", {
                    message: msg
                })
            } else {
                notify(msg, { type: 'error', messageArgs: { _: msg } });
            }
        }).catch((error) => {
            setLoading(false);
            notify(error.message, { type: 'error', messageArgs: { _: error.message } });
            console.error(error);
        })
    };
    return (
@@ -120,7 +156,7 @@
                        control={control}
                        defaultValue=""
                        rules={{ required: true }}
                        render={({ field }) => (
                        render={({ field, fieldState: { error } }) => (
                            <TextField
                                {...field}
                                label={translate("page.login.username")}
@@ -128,6 +164,8 @@
                                disabled={loading}
                                autoFocus
                                autoComplete="off"
                                error={!!error}
                                helperText={error?.message || ""}
                            />
                        )}
                    />
@@ -260,19 +298,22 @@
                        <Button
                            variant="outlined"
                            onClick={handleSendCode}
                            disabled={isCounting || loading}
                            disabled={codeLoading || isCounting}
                            sx={{
                                width: '35%',
                                mt: 1,
                                whiteSpace: 'nowrap',
                            }}
                        >
                            {isCounting ? (
                                <>
                                    <CircularProgress size={20} color="primary" sx={{ marginRight: 1 }} />
                                    {`${countdown}s`}
                                </>
                            ) : (
                                translate('page.login.button.code')
                            )}
                            {codeLoading ? (
                                <CircularProgress size={20} color="primary" sx={{ marginRight: 1 }} />
                            ) :
                                isCounting ? (
                                    `${countdown}s`
                                ) : (
                                    translate('page.login.button.code')
                                )
                            }
                        </Button>
                    </Box>
@@ -281,7 +322,7 @@
                    <Button
                        type="submit"
                        variant="contained"
                        disabled={loading || !(email && username && password && confirmPassword)}
                        disabled={loading || !(email && username && password && confirmPassword && code)}
                        sx={{
                            backgroundColor: "#3D4BA7"
                        }}