فهرست منبع

✨feat(ui): Add loading states to all authentication buttons

Add loading indicators to improve user experience during authentication processes:
- Implement loading states for all login and registration buttons
- Add try/catch/finally structure to properly handle async operations
- Create wrapper functions for OAuth redirect operations
- Set loading state for verification code submission
- Update modal confirmation buttons with loading state
- Add proper error handling with user feedback
- Split generic loading state into specific state variables

This change enhances user experience by providing clear visual feedback
during authentication actions.
Apple\Apple 7 ماه پیش
والد
کامیت
0f3216564d
2فایلهای تغییر یافته به همراه293 افزوده شده و 125 حذف شده
  1. 152 60
      web/src/components/LoginForm.js
  2. 141 65
      web/src/components/RegisterForm.js

+ 152 - 60
web/src/components/LoginForm.js

@@ -53,6 +53,15 @@ const LoginForm = () => {
   const [status, setStatus] = useState({});
   const [status, setStatus] = useState({});
   const [showWeChatLoginModal, setShowWeChatLoginModal] = useState(false);
   const [showWeChatLoginModal, setShowWeChatLoginModal] = useState(false);
   const [showEmailLogin, setShowEmailLogin] = useState(false);
   const [showEmailLogin, setShowEmailLogin] = useState(false);
+  const [wechatLoading, setWechatLoading] = useState(false);
+  const [githubLoading, setGithubLoading] = useState(false);
+  const [oidcLoading, setOidcLoading] = useState(false);
+  const [linuxdoLoading, setLinuxdoLoading] = useState(false);
+  const [emailLoginLoading, setEmailLoginLoading] = useState(false);
+  const [loginLoading, setLoginLoading] = useState(false);
+  const [resetPasswordLoading, setResetPasswordLoading] = useState(false);
+  const [otherLoginOptionsLoading, setOtherLoginOptionsLoading] = useState(false);
+  const [wechatCodeSubmitLoading, setWechatCodeSubmitLoading] = useState(false);
   const { t } = useTranslation();
   const { t } = useTranslation();
 
 
   const logo = getLogo();
   const logo = getLogo();
@@ -79,7 +88,9 @@ const LoginForm = () => {
   }, []);
   }, []);
 
 
   const onWeChatLoginClicked = () => {
   const onWeChatLoginClicked = () => {
+    setWechatLoading(true);
     setShowWeChatLoginModal(true);
     setShowWeChatLoginModal(true);
+    setWechatLoading(false);
   };
   };
 
 
   const onSubmitWeChatVerificationCode = async () => {
   const onSubmitWeChatVerificationCode = async () => {
@@ -87,20 +98,27 @@ const LoginForm = () => {
       showInfo('请稍后几秒重试,Turnstile 正在检查用户环境!');
       showInfo('请稍后几秒重试,Turnstile 正在检查用户环境!');
       return;
       return;
     }
     }
-    const res = await API.get(
-      `/api/oauth/wechat?code=${inputs.wechat_verification_code}`,
-    );
-    const { success, message, data } = res.data;
-    if (success) {
-      userDispatch({ type: 'login', payload: data });
-      localStorage.setItem('user', JSON.stringify(data));
-      setUserData(data);
-      updateAPI();
-      navigate('/');
-      showSuccess('登录成功!');
-      setShowWeChatLoginModal(false);
-    } else {
-      showError(message);
+    setWechatCodeSubmitLoading(true);
+    try {
+      const res = await API.get(
+        `/api/oauth/wechat?code=${inputs.wechat_verification_code}`,
+      );
+      const { success, message, data } = res.data;
+      if (success) {
+        userDispatch({ type: 'login', payload: data });
+        localStorage.setItem('user', JSON.stringify(data));
+        setUserData(data);
+        updateAPI();
+        navigate('/');
+        showSuccess('登录成功!');
+        setShowWeChatLoginModal(false);
+      } else {
+        showError(message);
+      }
+    } catch (error) {
+      showError('登录失败,请重试');
+    } finally {
+      setWechatCodeSubmitLoading(false);
     }
     }
   };
   };
 
 
@@ -114,33 +132,40 @@ const LoginForm = () => {
       return;
       return;
     }
     }
     setSubmitted(true);
     setSubmitted(true);
-    if (username && password) {
-      const res = await API.post(
-        `/api/user/login?turnstile=${turnstileToken}`,
-        {
-          username,
-          password,
-        },
-      );
-      const { success, message, data } = res.data;
-      if (success) {
-        userDispatch({ type: 'login', payload: data });
-        setUserData(data);
-        updateAPI();
-        showSuccess('登录成功!');
-        if (username === 'root' && password === '123456') {
-          Modal.error({
-            title: '您正在使用默认密码!',
-            content: '请立刻修改默认密码!',
-            centered: true,
-          });
+    setLoginLoading(true);
+    try {
+      if (username && password) {
+        const res = await API.post(
+          `/api/user/login?turnstile=${turnstileToken}`,
+          {
+            username,
+            password,
+          },
+        );
+        const { success, message, data } = res.data;
+        if (success) {
+          userDispatch({ type: 'login', payload: data });
+          setUserData(data);
+          updateAPI();
+          showSuccess('登录成功!');
+          if (username === 'root' && password === '123456') {
+            Modal.error({
+              title: '您正在使用默认密码!',
+              content: '请立刻修改默认密码!',
+              centered: true,
+            });
+          }
+          navigate('/console');
+        } else {
+          showError(message);
         }
         }
-        navigate('/console');
       } else {
       } else {
-        showError(message);
+        showError('请输入用户名和密码!');
       }
       }
-    } else {
-      showError('请输入用户名和密码!');
+    } catch (error) {
+      showError('登录失败,请重试');
+    } finally {
+      setLoginLoading(false);
     }
     }
   }
   }
 
 
@@ -162,20 +187,81 @@ const LoginForm = () => {
         params[field] = response[field];
         params[field] = response[field];
       }
       }
     });
     });
-    const res = await API.get(`/api/oauth/telegram/login`, { params });
-    const { success, message, data } = res.data;
-    if (success) {
-      userDispatch({ type: 'login', payload: data });
-      localStorage.setItem('user', JSON.stringify(data));
-      showSuccess('登录成功!');
-      setUserData(data);
-      updateAPI();
-      navigate('/');
-    } else {
-      showError(message);
+    try {
+      const res = await API.get(`/api/oauth/telegram/login`, { params });
+      const { success, message, data } = res.data;
+      if (success) {
+        userDispatch({ type: 'login', payload: data });
+        localStorage.setItem('user', JSON.stringify(data));
+        showSuccess('登录成功!');
+        setUserData(data);
+        updateAPI();
+        navigate('/');
+      } else {
+        showError(message);
+      }
+    } catch (error) {
+      showError('登录失败,请重试');
+    }
+  };
+
+  // 包装的GitHub登录点击处理
+  const handleGitHubClick = () => {
+    setGithubLoading(true);
+    try {
+      onGitHubOAuthClicked(status.github_client_id);
+    } finally {
+      // 由于重定向,这里不会执行到,但为了完整性添加
+      setTimeout(() => setGithubLoading(false), 3000);
+    }
+  };
+
+  // 包装的OIDC登录点击处理
+  const handleOIDCClick = () => {
+    setOidcLoading(true);
+    try {
+      onOIDCClicked(
+        status.oidc_authorization_endpoint,
+        status.oidc_client_id
+      );
+    } finally {
+      // 由于重定向,这里不会执行到,但为了完整性添加
+      setTimeout(() => setOidcLoading(false), 3000);
+    }
+  };
+
+  // 包装的LinuxDO登录点击处理
+  const handleLinuxDOClick = () => {
+    setLinuxdoLoading(true);
+    try {
+      onLinuxDOOAuthClicked(status.linuxdo_client_id);
+    } finally {
+      // 由于重定向,这里不会执行到,但为了完整性添加
+      setTimeout(() => setLinuxdoLoading(false), 3000);
     }
     }
   };
   };
 
 
+  // 包装的邮箱登录选项点击处理
+  const handleEmailLoginClick = () => {
+    setEmailLoginLoading(true);
+    setShowEmailLogin(true);
+    setEmailLoginLoading(false);
+  };
+
+  // 包装的重置密码点击处理
+  const handleResetPasswordClick = () => {
+    setResetPasswordLoading(true);
+    navigate('/reset');
+    setResetPasswordLoading(false);
+  };
+
+  // 包装的其他登录选项点击处理
+  const handleOtherLoginOptionsClick = () => {
+    setOtherLoginOptionsLoading(true);
+    setShowEmailLogin(false);
+    setOtherLoginOptionsLoading(false);
+  };
+
   const renderOAuthOptions = () => {
   const renderOAuthOptions = () => {
     return (
     return (
       <div className="flex flex-col items-center">
       <div className="flex flex-col items-center">
@@ -199,6 +285,7 @@ const LoginForm = () => {
                     icon={<Icon svg={<WeChatIcon />} style={{ color: '#07C160' }} />}
                     icon={<Icon svg={<WeChatIcon />} style={{ color: '#07C160' }} />}
                     size="large"
                     size="large"
                     onClick={onWeChatLoginClicked}
                     onClick={onWeChatLoginClicked}
+                    loading={wechatLoading}
                   >
                   >
                     <span className="ml-3">{t('使用 微信 继续')}</span>
                     <span className="ml-3">{t('使用 微信 继续')}</span>
                   </Button>
                   </Button>
@@ -211,7 +298,8 @@ const LoginForm = () => {
                     type="tertiary"
                     type="tertiary"
                     icon={<IconGithubLogo size="large" style={{ color: '#24292e' }} />}
                     icon={<IconGithubLogo size="large" style={{ color: '#24292e' }} />}
                     size="large"
                     size="large"
-                    onClick={() => onGitHubOAuthClicked(status.github_client_id)}
+                    onClick={handleGitHubClick}
+                    loading={githubLoading}
                   >
                   >
                     <span className="ml-3">{t('使用 GitHub 继续')}</span>
                     <span className="ml-3">{t('使用 GitHub 继续')}</span>
                   </Button>
                   </Button>
@@ -224,12 +312,8 @@ const LoginForm = () => {
                     type="tertiary"
                     type="tertiary"
                     icon={<OIDCIcon style={{ color: '#1877F2' }} />}
                     icon={<OIDCIcon style={{ color: '#1877F2' }} />}
                     size="large"
                     size="large"
-                    onClick={() =>
-                      onOIDCClicked(
-                        status.oidc_authorization_endpoint,
-                        status.oidc_client_id
-                      )
-                    }
+                    onClick={handleOIDCClick}
+                    loading={oidcLoading}
                   >
                   >
                     <span className="ml-3">{t('使用 OIDC 继续')}</span>
                     <span className="ml-3">{t('使用 OIDC 继续')}</span>
                   </Button>
                   </Button>
@@ -242,7 +326,8 @@ const LoginForm = () => {
                     type="tertiary"
                     type="tertiary"
                     icon={<LinuxDoIcon style={{ color: '#E95420', width: '20px', height: '20px' }} />}
                     icon={<LinuxDoIcon style={{ color: '#E95420', width: '20px', height: '20px' }} />}
                     size="large"
                     size="large"
-                    onClick={() => onLinuxDOOAuthClicked(status.linuxdo_client_id)}
+                    onClick={handleLinuxDOClick}
+                    loading={linuxdoLoading}
                   >
                   >
                     <span className="ml-3">{t('使用 LinuxDO 继续')}</span>
                     <span className="ml-3">{t('使用 LinuxDO 继续')}</span>
                   </Button>
                   </Button>
@@ -267,7 +352,8 @@ const LoginForm = () => {
                   className="w-full h-12 flex items-center justify-center bg-black text-white !rounded-full hover:bg-gray-800 transition-colors"
                   className="w-full h-12 flex items-center justify-center bg-black text-white !rounded-full hover:bg-gray-800 transition-colors"
                   icon={<IconMail size="large" />}
                   icon={<IconMail size="large" />}
                   size="large"
                   size="large"
-                  onClick={() => setShowEmailLogin(true)}
+                  onClick={handleEmailLoginClick}
+                  loading={emailLoginLoading}
                 >
                 >
                   <span className="ml-3">{t('使用 邮箱 登录')}</span>
                   <span className="ml-3">{t('使用 邮箱 登录')}</span>
                 </Button>
                 </Button>
@@ -340,6 +426,7 @@ const LoginForm = () => {
                     htmlType="submit"
                     htmlType="submit"
                     size="large"
                     size="large"
                     onClick={handleSubmit}
                     onClick={handleSubmit}
+                    loading={loginLoading}
                   >
                   >
                     {t('继续')}
                     {t('继续')}
                   </Button>
                   </Button>
@@ -349,7 +436,8 @@ const LoginForm = () => {
                     type='tertiary'
                     type='tertiary'
                     className="w-full !rounded-full"
                     className="w-full !rounded-full"
                     size="large"
                     size="large"
-                    onClick={() => navigate('/reset')}
+                    onClick={handleResetPasswordClick}
+                    loading={resetPasswordLoading}
                   >
                   >
                     {t('忘记密码?')}
                     {t('忘记密码?')}
                   </Button>
                   </Button>
@@ -366,7 +454,8 @@ const LoginForm = () => {
                   type="tertiary"
                   type="tertiary"
                   className="w-full !rounded-full"
                   className="w-full !rounded-full"
                   size="large"
                   size="large"
-                  onClick={() => setShowEmailLogin(false)}
+                  onClick={handleOtherLoginOptionsClick}
+                  loading={otherLoginOptionsLoading}
                 >
                 >
                   {t('其他登录选项')}
                   {t('其他登录选项')}
                 </Button>
                 </Button>
@@ -390,6 +479,9 @@ const LoginForm = () => {
         okText={t('登录')}
         okText={t('登录')}
         size="small"
         size="small"
         centered={true}
         centered={true}
+        okButtonProps={{
+          loading: wechatCodeSubmitLoading,
+        }}
       >
       >
         <div className="flex flex-col items-center">
         <div className="flex flex-col items-center">
           <img src={status.wechat_qrcode} alt="微信二维码" className="mb-4" />
           <img src={status.wechat_qrcode} alt="微信二维码" className="mb-4" />

+ 141 - 65
web/src/components/RegisterForm.js

@@ -55,6 +55,15 @@ const RegisterForm = () => {
   const [showWeChatLoginModal, setShowWeChatLoginModal] = useState(false);
   const [showWeChatLoginModal, setShowWeChatLoginModal] = useState(false);
   const [showEmailRegister, setShowEmailRegister] = useState(false);
   const [showEmailRegister, setShowEmailRegister] = useState(false);
   const [status, setStatus] = useState({});
   const [status, setStatus] = useState({});
+  const [wechatLoading, setWechatLoading] = useState(false);
+  const [githubLoading, setGithubLoading] = useState(false);
+  const [oidcLoading, setOidcLoading] = useState(false);
+  const [linuxdoLoading, setLinuxdoLoading] = useState(false);
+  const [emailRegisterLoading, setEmailRegisterLoading] = useState(false);
+  const [registerLoading, setRegisterLoading] = useState(false);
+  const [verificationCodeLoading, setVerificationCodeLoading] = useState(false);
+  const [otherRegisterOptionsLoading, setOtherRegisterOptionsLoading] = useState(false);
+  const [wechatCodeSubmitLoading, setWechatCodeSubmitLoading] = useState(false);
   let navigate = useNavigate();
   let navigate = useNavigate();
 
 
   const logo = getLogo();
   const logo = getLogo();
@@ -79,7 +88,9 @@ const RegisterForm = () => {
   }, []);
   }, []);
 
 
   const onWeChatLoginClicked = () => {
   const onWeChatLoginClicked = () => {
+    setWechatLoading(true);
     setShowWeChatLoginModal(true);
     setShowWeChatLoginModal(true);
+    setWechatLoading(false);
   };
   };
 
 
   const onSubmitWeChatVerificationCode = async () => {
   const onSubmitWeChatVerificationCode = async () => {
@@ -87,20 +98,27 @@ const RegisterForm = () => {
       showInfo('请稍后几秒重试,Turnstile 正在检查用户环境!');
       showInfo('请稍后几秒重试,Turnstile 正在检查用户环境!');
       return;
       return;
     }
     }
-    const res = await API.get(
-      `/api/oauth/wechat?code=${inputs.wechat_verification_code}`,
-    );
-    const { success, message, data } = res.data;
-    if (success) {
-      userDispatch({ type: 'login', payload: data });
-      localStorage.setItem('user', JSON.stringify(data));
-      setUserData(data);
-      updateAPI();
-      navigate('/');
-      showSuccess('登录成功!');
-      setShowWeChatLoginModal(false);
-    } else {
-      showError(message);
+    setWechatCodeSubmitLoading(true);
+    try {
+      const res = await API.get(
+        `/api/oauth/wechat?code=${inputs.wechat_verification_code}`,
+      );
+      const { success, message, data } = res.data;
+      if (success) {
+        userDispatch({ type: 'login', payload: data });
+        localStorage.setItem('user', JSON.stringify(data));
+        setUserData(data);
+        updateAPI();
+        navigate('/');
+        showSuccess('登录成功!');
+        setShowWeChatLoginModal(false);
+      } else {
+        showError(message);
+      }
+    } catch (error) {
+      showError('登录失败,请重试');
+    } finally {
+      setWechatCodeSubmitLoading(false);
     }
     }
   };
   };
 
 
@@ -122,23 +140,28 @@ const RegisterForm = () => {
         showInfo('请稍后几秒重试,Turnstile 正在检查用户环境!');
         showInfo('请稍后几秒重试,Turnstile 正在检查用户环境!');
         return;
         return;
       }
       }
-      setLoading(true);
-      if (!affCode) {
-        affCode = localStorage.getItem('aff');
+      setRegisterLoading(true);
+      try {
+        if (!affCode) {
+          affCode = localStorage.getItem('aff');
+        }
+        inputs.aff_code = affCode;
+        const res = await API.post(
+          `/api/user/register?turnstile=${turnstileToken}`,
+          inputs,
+        );
+        const { success, message } = res.data;
+        if (success) {
+          navigate('/login');
+          showSuccess('注册成功!');
+        } else {
+          showError(message);
+        }
+      } catch (error) {
+        showError('注册失败,请重试');
+      } finally {
+        setRegisterLoading(false);
       }
       }
-      inputs.aff_code = affCode;
-      const res = await API.post(
-        `/api/user/register?turnstile=${turnstileToken}`,
-        inputs,
-      );
-      const { success, message } = res.data;
-      if (success) {
-        navigate('/login');
-        showSuccess('注册成功!');
-      } else {
-        showError(message);
-      }
-      setLoading(false);
     }
     }
   }
   }
 
 
@@ -148,17 +171,64 @@ const RegisterForm = () => {
       showInfo('请稍后几秒重试,Turnstile 正在检查用户环境!');
       showInfo('请稍后几秒重试,Turnstile 正在检查用户环境!');
       return;
       return;
     }
     }
-    setLoading(true);
-    const res = await API.get(
-      `/api/verification?email=${inputs.email}&turnstile=${turnstileToken}`,
-    );
-    const { success, message } = res.data;
-    if (success) {
-      showSuccess('验证码发送成功,请检查你的邮箱!');
-    } else {
-      showError(message);
+    setVerificationCodeLoading(true);
+    try {
+      const res = await API.get(
+        `/api/verification?email=${inputs.email}&turnstile=${turnstileToken}`,
+      );
+      const { success, message } = res.data;
+      if (success) {
+        showSuccess('验证码发送成功,请检查你的邮箱!');
+      } else {
+        showError(message);
+      }
+    } catch (error) {
+      showError('发送验证码失败,请重试');
+    } finally {
+      setVerificationCodeLoading(false);
     }
     }
-    setLoading(false);
+  };
+
+  const handleGitHubClick = () => {
+    setGithubLoading(true);
+    try {
+      onGitHubOAuthClicked(status.github_client_id);
+    } finally {
+      setTimeout(() => setGithubLoading(false), 3000);
+    }
+  };
+
+  const handleOIDCClick = () => {
+    setOidcLoading(true);
+    try {
+      onOIDCClicked(
+        status.oidc_authorization_endpoint,
+        status.oidc_client_id
+      );
+    } finally {
+      setTimeout(() => setOidcLoading(false), 3000);
+    }
+  };
+
+  const handleLinuxDOClick = () => {
+    setLinuxdoLoading(true);
+    try {
+      onLinuxDOOAuthClicked(status.linuxdo_client_id);
+    } finally {
+      setTimeout(() => setLinuxdoLoading(false), 3000);
+    }
+  };
+
+  const handleEmailRegisterClick = () => {
+    setEmailRegisterLoading(true);
+    setShowEmailRegister(true);
+    setEmailRegisterLoading(false);
+  };
+
+  const handleOtherRegisterOptionsClick = () => {
+    setOtherRegisterOptionsLoading(true);
+    setShowEmailRegister(false);
+    setOtherRegisterOptionsLoading(false);
   };
   };
 
 
   const onTelegramLoginClicked = async (response) => {
   const onTelegramLoginClicked = async (response) => {
@@ -178,17 +248,21 @@ const RegisterForm = () => {
         params[field] = response[field];
         params[field] = response[field];
       }
       }
     });
     });
-    const res = await API.get(`/api/oauth/telegram/login`, { params });
-    const { success, message, data } = res.data;
-    if (success) {
-      userDispatch({ type: 'login', payload: data });
-      localStorage.setItem('user', JSON.stringify(data));
-      showSuccess('登录成功!');
-      setUserData(data);
-      updateAPI();
-      navigate('/');
-    } else {
-      showError(message);
+    try {
+      const res = await API.get(`/api/oauth/telegram/login`, { params });
+      const { success, message, data } = res.data;
+      if (success) {
+        userDispatch({ type: 'login', payload: data });
+        localStorage.setItem('user', JSON.stringify(data));
+        showSuccess('登录成功!');
+        setUserData(data);
+        updateAPI();
+        navigate('/');
+      } else {
+        showError(message);
+      }
+    } catch (error) {
+      showError('登录失败,请重试');
     }
     }
   };
   };
 
 
@@ -215,6 +289,7 @@ const RegisterForm = () => {
                     icon={<Icon svg={<WeChatIcon />} style={{ color: '#07C160' }} />}
                     icon={<Icon svg={<WeChatIcon />} style={{ color: '#07C160' }} />}
                     size="large"
                     size="large"
                     onClick={onWeChatLoginClicked}
                     onClick={onWeChatLoginClicked}
+                    loading={wechatLoading}
                   >
                   >
                     <span className="ml-3">{t('使用 微信 继续')}</span>
                     <span className="ml-3">{t('使用 微信 继续')}</span>
                   </Button>
                   </Button>
@@ -227,7 +302,8 @@ const RegisterForm = () => {
                     type="tertiary"
                     type="tertiary"
                     icon={<IconGithubLogo size="large" style={{ color: '#24292e' }} />}
                     icon={<IconGithubLogo size="large" style={{ color: '#24292e' }} />}
                     size="large"
                     size="large"
-                    onClick={() => onGitHubOAuthClicked(status.github_client_id)}
+                    onClick={handleGitHubClick}
+                    loading={githubLoading}
                   >
                   >
                     <span className="ml-3">{t('使用 GitHub 继续')}</span>
                     <span className="ml-3">{t('使用 GitHub 继续')}</span>
                   </Button>
                   </Button>
@@ -240,12 +316,8 @@ const RegisterForm = () => {
                     type="tertiary"
                     type="tertiary"
                     icon={<OIDCIcon style={{ color: '#1877F2' }} />}
                     icon={<OIDCIcon style={{ color: '#1877F2' }} />}
                     size="large"
                     size="large"
-                    onClick={() =>
-                      onOIDCClicked(
-                        status.oidc_authorization_endpoint,
-                        status.oidc_client_id
-                      )
-                    }
+                    onClick={handleOIDCClick}
+                    loading={oidcLoading}
                   >
                   >
                     <span className="ml-3">{t('使用 OIDC 继续')}</span>
                     <span className="ml-3">{t('使用 OIDC 继续')}</span>
                   </Button>
                   </Button>
@@ -258,7 +330,8 @@ const RegisterForm = () => {
                     type="tertiary"
                     type="tertiary"
                     icon={<LinuxDoIcon style={{ color: '#E95420', width: '20px', height: '20px' }} />}
                     icon={<LinuxDoIcon style={{ color: '#E95420', width: '20px', height: '20px' }} />}
                     size="large"
                     size="large"
-                    onClick={() => onLinuxDOOAuthClicked(status.linuxdo_client_id)}
+                    onClick={handleLinuxDOClick}
+                    loading={linuxdoLoading}
                   >
                   >
                     <span className="ml-3">{t('使用 LinuxDO 继续')}</span>
                     <span className="ml-3">{t('使用 LinuxDO 继续')}</span>
                   </Button>
                   </Button>
@@ -283,7 +356,8 @@ const RegisterForm = () => {
                   className="w-full h-12 flex items-center justify-center bg-black text-white !rounded-full hover:bg-gray-800 transition-colors"
                   className="w-full h-12 flex items-center justify-center bg-black text-white !rounded-full hover:bg-gray-800 transition-colors"
                   icon={<IconMail size="large" />}
                   icon={<IconMail size="large" />}
                   size="large"
                   size="large"
-                  onClick={() => setShowEmailRegister(true)}
+                  onClick={handleEmailRegisterClick}
+                  loading={emailRegisterLoading}
                 >
                 >
                   <span className="ml-3">{t('使用 邮箱 注册')}</span>
                   <span className="ml-3">{t('使用 邮箱 注册')}</span>
                 </Button>
                 </Button>
@@ -375,7 +449,7 @@ const RegisterForm = () => {
                       suffix={
                       suffix={
                         <Button
                         <Button
                           onClick={sendVerificationCode}
                           onClick={sendVerificationCode}
-                          disabled={loading}
+                          loading={verificationCodeLoading}
                           size="small"
                           size="small"
                           className="!rounded-md mr-2"
                           className="!rounded-md mr-2"
                         >
                         >
@@ -404,6 +478,7 @@ const RegisterForm = () => {
                     htmlType="submit"
                     htmlType="submit"
                     size="large"
                     size="large"
                     onClick={handleSubmit}
                     onClick={handleSubmit}
+                    loading={registerLoading}
                   >
                   >
                     {t('注册')}
                     {t('注册')}
                   </Button>
                   </Button>
@@ -420,7 +495,8 @@ const RegisterForm = () => {
                   type="tertiary"
                   type="tertiary"
                   className="w-full !rounded-full"
                   className="w-full !rounded-full"
                   size="large"
                   size="large"
-                  onClick={() => setShowEmailRegister(false)}
+                  onClick={handleOtherRegisterOptionsClick}
+                  loading={otherRegisterOptionsLoading}
                 >
                 >
                   {t('其他注册选项')}
                   {t('其他注册选项')}
                 </Button>
                 </Button>
@@ -436,7 +512,6 @@ const RegisterForm = () => {
     );
     );
   };
   };
 
 
-  // 微信登录模态框
   const renderWeChatLoginModal = () => {
   const renderWeChatLoginModal = () => {
     return (
     return (
       <Modal
       <Modal
@@ -448,6 +523,9 @@ const RegisterForm = () => {
         okText={t('登录')}
         okText={t('登录')}
         size="small"
         size="small"
         centered={true}
         centered={true}
+        okButtonProps={{
+          loading: wechatCodeSubmitLoading,
+        }}
       >
       >
         <div className="flex flex-col items-center">
         <div className="flex flex-col items-center">
           <img src={status.wechat_qrcode} alt="微信二维码" className="mb-4" />
           <img src={status.wechat_qrcode} alt="微信二维码" className="mb-4" />
@@ -472,7 +550,6 @@ const RegisterForm = () => {
 
 
   return (
   return (
     <div className="min-h-screen relative flex items-center justify-center py-12 px-4 sm:px-6 lg:px-8 overflow-hidden">
     <div className="min-h-screen relative flex items-center justify-center py-12 px-4 sm:px-6 lg:px-8 overflow-hidden">
-      {/* 背景图片容器 - 放大并保持居中 */}
       <div
       <div
         className="absolute inset-0 z-0 bg-cover bg-center scale-125 opacity-100"
         className="absolute inset-0 z-0 bg-cover bg-center scale-125 opacity-100"
         style={{
         style={{
@@ -480,7 +557,6 @@ const RegisterForm = () => {
         }}
         }}
       ></div>
       ></div>
 
 
-      {/* 半透明遮罩层 */}
       <div className="absolute inset-0 bg-gradient-to-br from-teal-500/30 via-blue-500/30 to-purple-500/30 backdrop-blur-sm z-0"></div>
       <div className="absolute inset-0 bg-gradient-to-br from-teal-500/30 via-blue-500/30 to-purple-500/30 backdrop-blur-sm z-0"></div>
 
 
       <div className="w-full max-w-md relative z-10">
       <div className="w-full max-w-md relative z-10">