登陆注册与忘记密码前后端与jwt配置

Change-Id: Ide4ca3ea34609fdb33ea027e28169852fa41784a
diff --git a/rhj/frontend/src/pages/ForgotPasswordPage/ForgotPasswordPage.css b/rhj/frontend/src/pages/ForgotPasswordPage/ForgotPasswordPage.css
new file mode 100644
index 0000000..6af35e6
--- /dev/null
+++ b/rhj/frontend/src/pages/ForgotPasswordPage/ForgotPasswordPage.css
@@ -0,0 +1,915 @@
+/* 忘记密码页面 - 继承注册页面样式 */
+
+/* 导入注册页面的所有样式 */
+@import url('../RegisterPage/RegisterPage.css');
+
+/* 小红书风格忘记密码卡片 */
+.forgot-password-card {
+  background: #fff;
+  border-radius: 8px;
+  padding: 40px; /* 增加桌面端内边距 */
+  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
+  border: 1px solid #e1e1e1;
+  width: 100%;
+  max-width: 450px; /* 增加桌面端卡片最大宽度 */
+  transition: none;
+}
+
+/* 忘记密码头部 */
+.forgot-password-header {
+  text-align: center;
+  margin-bottom: 40px;
+}
+
+/* Logo样式 */
+.logo-section {
+  margin-bottom: 24px;
+}
+
+.logo-icon {
+  width: 60px;
+  height: 60px;
+  background: #ff2442;
+  border-radius: 12px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  font-size: 28px;
+  margin: 0 auto 16px;
+  box-shadow: 0 4px 12px rgba(255, 36, 66, 0.2);
+}
+
+.forgot-password-title {
+  font-size: 24px;
+  font-weight: 600;
+  color: #333;
+  margin: 0 0 12px 0;
+  text-align: center;
+}
+
+.forgot-password-title::after {
+  display: none;
+}
+
+.forgot-password-subtitle {
+  font-size: 14px;
+  color: #999;
+  margin: 0 0 32px 0;
+  font-weight: 400;
+  text-align: center;
+}
+
+/* 表单样式 */
+.forgot-password-form {
+  display: flex;
+  flex-direction: column;
+  gap: 20px;
+  width: 100%;
+}
+
+.form-group {
+  display: flex;
+  flex-direction: column;
+  gap: 6px;
+  width: 100%;
+  box-sizing: border-box;
+  margin-bottom: 2px;
+  position: relative; /* 为绝对定位的错误提示提供参考点 */
+}
+
+.form-group .input-wrapper {
+  width: 100%;
+  box-sizing: border-box;
+}
+
+.form-label {
+  font-size: 14px;
+  font-weight: 500;
+  color: #333;
+  margin-bottom: 8px;
+}
+
+.input-wrapper {
+  position: relative;
+  display: flex;
+  align-items: center;
+  width: 100%;
+  box-sizing: border-box;
+}
+
+.form-input {
+  width: 100% !important;
+  height: 44px;
+  padding: 12px 16px 12px 48px;
+  border: 1px solid #e1e1e1;
+  border-radius: 6px;
+  font-size: 14px;
+  transition: border-color 0.2s ease;
+  background: #fff;
+  color: #333;
+  box-sizing: border-box !important;
+  flex: 1;
+  min-width: 0;
+}
+
+/* 针对 Antd Input 组件的特定样式 */
+.form-input.ant-input,
+.form-input.ant-input-affix-wrapper {
+  width: 100% !important;
+  height: 44px !important;
+  border: 1px solid #e1e1e1 !important;
+  border-radius: 6px !important;
+  padding: 12px 48px 12px 48px !important;
+  font-size: 14px !important;
+  background: #fff !important;
+  color: #333 !important;
+  box-sizing: border-box !important;
+  flex: 1 !important;
+  min-width: 0 !important;
+  display: flex !important;
+  align-items: center !important;
+}
+
+.form-input.ant-input-affix-wrapper .ant-input {
+  width: 100% !important;
+  height: 100% !important;
+  padding: 0 !important;
+  border: none !important;
+  background: transparent !important;
+  flex: 1 !important;
+  min-width: 0 !important;
+  box-sizing: border-box !important;
+}
+
+.form-input:focus {
+  outline: none;
+  border-color: #ff2442;
+  box-shadow: none;
+  transform: none;
+}
+
+/* Antd Input focus 样式 */
+.form-input.ant-input:focus,
+.form-input.ant-input-affix-wrapper:focus,
+.form-input.ant-input-affix-wrapper-focused {
+  outline: none !important;
+  border-color: #ff2442 !important;
+  box-shadow: none !important;
+  transform: none !important;
+}
+
+.form-input::placeholder {
+  color: #9ca3af;
+}
+
+.input-icon {
+  position: absolute;
+  left: 16px;
+  top: 50%;
+  transform: translateY(-50%);
+  color: #9ca3af;
+  pointer-events: none;
+  transition: color 0.3s ease;
+  z-index: 2;
+}
+
+.form-input:focus + .input-icon {
+  color: #ff2442;
+}
+
+/* 邮箱验证码输入框容器 */
+.email-code-wrapper {
+  display: flex;
+  gap: 8px;
+  width: 100%;
+  box-sizing: border-box;
+  align-items: flex-start;
+}
+
+.email-code-input {
+  flex: 1;
+  min-width: 0;
+}
+
+.send-code-button {
+  height: 44px !important;
+  padding: 0 16px !important;
+  background: #ff2442 !important;
+  border-color: #ff2442 !important;
+  border-radius: 6px !important;
+  font-size: 14px !important;
+  font-weight: 500 !important;
+  white-space: nowrap !important;
+  flex-shrink: 0 !important;
+  min-width: 100px !important;
+  display: flex !important;
+  align-items: center !important;
+  justify-content: center !important;
+  transition: all 0.2s ease !important;
+  box-sizing: border-box !important;
+}
+
+.send-code-button:hover:not(:disabled) {
+  background: #d91e3a !important;
+  border-color: #d91e3a !important;
+  transform: none !important;
+  box-shadow: none !important;
+}
+
+.send-code-button:disabled {
+  background: #f5f5f5 !important;
+  border-color: #d9d9d9 !important;
+  color: #bfbfbf !important;
+  cursor: not-allowed !important;
+}
+
+.send-code-button.ant-btn-loading {
+  background: #ff2442 !important;
+  border-color: #ff2442 !important;
+  color: white !important;
+}
+
+/* 小红书风格忘记密码按钮 */
+.forgot-password-button {
+  width: 100%;
+  height: 48px; /* 固定高度,防止布局变化 */
+  padding: 12px;
+  background: #ff2442;
+  color: white;
+  border: none;
+  border-radius: 6px;
+  font-size: 14px;
+  font-weight: 500;
+  cursor: pointer;
+  transition: background-color 0.2s ease;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  gap: 8px;
+  margin-top: 8px;
+  position: relative; /* 为绝对定位的加载状态做准备 */
+  box-sizing: border-box; /* 确保padding包含在总尺寸内 */
+  min-width: 0; /* 防止flex子元素造成宽度变化 */
+}
+
+.forgot-password-button:hover:not(:disabled) {
+  background: #d91e3a;
+  transform: none;
+  box-shadow: none;
+}
+
+.forgot-password-button:active:not(:disabled) {
+  transform: none;
+}
+
+.forgot-password-button:disabled {
+  background: #ccc;
+  cursor: not-allowed;
+  opacity: 0.8;
+}
+
+.forgot-password-button.loading {
+  background: #ff7b8a;
+  cursor: not-allowed;
+}
+
+.loading-spinner {
+  width: 16px;
+  height: 16px;
+  border: 2px solid rgba(255, 255, 255, 0.3);
+  border-radius: 50%;
+  border-top-color: #fff;
+  animation: spin 1s ease-in-out infinite;
+}
+
+@keyframes spin {
+  to { transform: rotate(360deg); }
+}
+
+/* 加载遮罩层 */
+.loading-overlay {
+  position: fixed;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  background: rgba(0, 0, 0, 0.5);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  z-index: 1000;
+  backdrop-filter: blur(4px);
+}
+
+.loading-content {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  gap: 16px;
+  background: white;
+  padding: 32px;
+  border-radius: 12px;
+  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
+}
+
+.loading-spinner-large {
+  width: 40px;
+  height: 40px;
+  border: 4px solid rgba(255, 36, 66, 0.2);
+  border-radius: 50%;
+  border-top-color: #ff2442;
+  animation: spin 1s ease-in-out infinite;
+}
+
+.loading-text {
+  margin: 0;
+  color: #333;
+  font-size: 16px;
+  font-weight: 500;
+}
+
+/* 登录链接 */
+.login-link {
+  text-align: center;
+  margin-top: 20px;
+  padding-top: 20px;
+  border-top: 1px solid #e5e7eb;
+}
+
+.login-link p {
+  margin: 0 0 8px 0;
+  font-size: 14px;
+  color: #64748b;
+}
+
+.login-link p:last-child {
+  margin-bottom: 0;
+}
+
+.login-link a {
+  color: #ff2442;
+  text-decoration: none;
+  font-weight: 500;
+  transition: color 0.2s ease;
+}
+
+.login-link a:hover {
+  color: #d91e3a;
+  text-decoration: underline;
+}
+
+/* 返回邮箱输入样式 */
+.back-to-email {
+  display: flex;
+  flex-direction: column;
+  gap: 8px;
+  padding: 12px 16px;
+  background: #f8f8f8;
+  border-radius: 6px;
+  border: 1px solid #e1e1e1;
+}
+
+.back-button {
+  background: none;
+  border: none;
+  color: #ff2442;
+  font-size: 14px;
+  cursor: pointer;
+  display: flex;
+  align-items: center;
+  gap: 4px;
+  padding: 0;
+  transition: color 0.2s ease;
+  width: fit-content;
+}
+
+.back-button:hover {
+  color: #d91e3a;
+}
+
+.email-display {
+  font-size: 14px;
+  color: #666;
+  font-weight: 500;
+}
+
+/* 有左侧图标时的内边距调整 */
+.input-wrapper.has-icon .form-input {
+  padding-left: 48px !important;
+}
+
+.input-wrapper.has-icon .form-input.ant-input,
+.input-wrapper.has-icon .form-input.ant-input-affix-wrapper {
+  padding-left: 48px !important;
+}
+
+/* 有右侧切换按钮时的内边距调整 */
+.input-wrapper.has-toggle .form-input {
+  padding-right: 48px !important;
+}
+
+.input-wrapper.has-toggle .form-input.ant-input,
+.input-wrapper.has-toggle .form-input.ant-input-affix-wrapper {
+  padding-right: 48px !important;
+}
+
+/* 没有图标时的内边距调整 */
+.input-wrapper:not(.has-icon) .form-input {
+  padding-left: 16px !important;
+}
+
+.input-wrapper:not(.has-icon) .form-input.ant-input,
+.input-wrapper:not(.has-icon) .form-input.ant-input-affix-wrapper {
+  padding-left: 16px !important;
+}
+
+/* 没有切换按钮时的内边距调整 */
+.input-wrapper:not(.has-toggle) .form-input {
+  padding-right: 16px !important;
+}
+
+.input-wrapper:not(.has-toggle) .form-input.ant-input,
+.input-wrapper:not(.has-toggle) .form-input.ant-input-affix-wrapper {
+  padding-right: 16px !important;
+}
+
+/* 确保输入框内容完全填充 */
+.form-input.ant-input-affix-wrapper .ant-input-suffix {
+  position: absolute !important;
+  right: 12px !important;
+  top: 50% !important;
+  transform: translateY(-50%) !important;
+  margin: 0 !important;
+  padding: 0 !important;
+}
+
+.form-input.ant-input-affix-wrapper .ant-input-prefix {
+  position: absolute !important;
+  left: 16px !important;
+  top: 50% !important;
+  transform: translateY(-50%) !important;
+  margin: 0 !important;
+  padding: 0 !important;
+}
+
+/* 确保所有输入框完全填充其容器 */
+.form-group {
+  display: flex;
+  flex-direction: column;
+  gap: 8px;
+  width: 100%;
+  box-sizing: border-box;
+}
+
+.form-group .input-wrapper {
+  width: 100%;
+  box-sizing: border-box;
+}
+
+/* 防止输入框溢出容器 */
+.form-input,
+.form-input.ant-input,
+.form-input.ant-input-affix-wrapper {
+  max-width: 100% !important;
+  overflow: hidden !important;
+}
+
+/* 确保内部输入元素不会超出边界 */
+.form-input.ant-input-affix-wrapper .ant-input {
+  max-width: 100% !important;
+  overflow: hidden !important;
+  text-overflow: ellipsis !important;
+}
+
+/* 精细间距控制 */
+.forgot-password-header + .forgot-password-form {
+  margin-top: -4px;
+}
+
+.forgot-password-form .form-group:not(:last-child) {
+  margin-bottom: 2px;
+}
+
+.forgot-password-form .form-group:last-of-type {
+  margin-bottom: 6px;
+}
+
+.forgot-password-button + .login-link {
+  margin-top: 14px;
+}
+
+/* 响应式设计 */
+@media (max-width: 768px) {
+  /* 重置body和html确保一致性 */
+  html, body {
+    height: 100%;
+    height: 100dvh;
+    margin: 0;
+    padding: 0;
+    overflow-x: hidden;
+    box-sizing: border-box;
+  }
+  
+  .forgot-password-container {
+    padding: 16px;
+    align-items: center;
+    justify-content: center;
+    min-height: 100vh;
+    min-height: 100dvh; /* 动态视口高度 */
+    /* 强制重置可能影响定位的样式 */
+    margin: 0;
+    box-sizing: border-box;
+    /* 防止内容溢出影响布局 */
+    overflow-x: hidden;
+    overflow-y: auto;
+    /* 确保flexbox在所有移动设备上表现一致 */
+    -webkit-box-align: center;
+    -webkit-box-pack: center;
+    display: flex !important;
+    position: relative;
+  }
+  
+  .forgot-password-content {
+    max-width: 100%;
+    padding: 20px;
+    /* 确保内容区域稳定 */
+    margin: 0 auto;
+    box-sizing: border-box;
+    /* 防止宽度计算问题 */
+    width: calc(100% - 40px);
+    max-width: 480px; /* 增加最大宽度 */
+    position: relative;
+    display: flex;
+    justify-content: center;
+  }
+  
+  .forgot-password-card {
+    padding: 32px 28px; /* 增加内边距 */
+    border-radius: 16px;
+    /* 确保卡片稳定定位 */
+    margin: 0;
+    box-sizing: border-box;
+    width: 100%;
+    max-width: 450px; /* 增加卡片最大宽度 */
+    /* 防止backdrop-filter导致的渲染差异 */
+    will-change: auto;
+    position: relative;
+    /* 防止触摸操作影响布局 */
+    -webkit-touch-callout: none;
+    -webkit-user-select: none;
+    -moz-user-select: none;
+    -ms-user-select: none;
+    user-select: none;
+    -webkit-tap-highlight-color: transparent;
+  }
+  
+  .forgot-password-title {
+    font-size: 24px;
+  }
+  
+  .form-input {
+    width: 100% !important;
+    height: 44px !important;
+    padding: 12px 48px 12px 48px;
+    font-size: 16px; /* 防止iOS Safari缩放 */
+    box-sizing: border-box !important;
+    flex: 1 !important;
+    min-width: 0 !important;
+  }
+  
+  .form-input.ant-input,
+  .form-input.ant-input-affix-wrapper {
+    width: 100% !important;
+    height: 44px !important;
+    padding: 12px 48px 12px 48px !important;
+    font-size: 16px !important;
+    box-sizing: border-box !important;
+    flex: 1 !important;
+    min-width: 0 !important;
+  }
+  
+  .form-input.ant-input-affix-wrapper .ant-input {
+    width: 100% !important;
+    height: 100% !important;
+    padding: 0 !important;
+    border: none !important;
+    background: transparent !important;
+    flex: 1 !important;
+    min-width: 0 !important;
+    box-sizing: border-box !important;
+  }
+}
+
+@media (max-width: 480px) {
+  .forgot-password-container {
+    padding: 16px;
+    align-items: center;
+    justify-content: center;
+    min-height: 100vh;
+    min-height: 100dvh; /* 动态视口高度 */
+    /* 强制重置样式 */
+    margin: 0;
+    box-sizing: border-box;
+    position: relative;
+    /* 确保垂直居中 */
+    display: flex !important;
+  }
+  
+  .forgot-password-content {
+    /* 更严格的尺寸控制 */
+    width: calc(100vw - 32px);
+    max-width: 420px; /* 增加最大宽度 */
+    padding: 16px;
+    margin: 0 auto;
+    box-sizing: border-box;
+    display: flex;
+    justify-content: center;
+  }
+  
+  .forgot-password-card {
+    padding: 28px 24px; /* 增加内边距 */
+    border-radius: 12px;
+    /* 确保卡片完全稳定 */
+    margin: 0;
+    box-sizing: border-box;
+    width: 100%;
+    position: relative;
+    /* 防止变换导致的位置偏移 */
+    transform: none !important;
+    /* 防止触摸操作影响布局 */
+    -webkit-touch-callout: none;
+    -webkit-user-select: none;
+    -khtml-user-select: none;
+    -moz-user-select: none;
+    -ms-user-select: none;
+    user-select: none;
+    /* 防止点击时的高亮效果影响布局 */
+    -webkit-tap-highlight-color: transparent;
+  }
+  
+  .forgot-password-title {
+    font-size: 22px;
+  }
+  
+  .form-input {
+    width: 100% !important;
+    height: 44px !important;
+    padding: 12px 48px 12px 48px;
+    font-size: 16px; /* 防止iOS Safari缩放 */
+    box-sizing: border-box !important;
+    flex: 1 !important;
+    min-width: 0 !important;
+  }
+  
+  .form-input.ant-input,
+  .form-input.ant-input-affix-wrapper {
+    width: 100% !important;
+    height: 44px !important;
+    padding: 12px 48px 12px 48px !important;
+    font-size: 16px !important;
+    box-sizing: border-box !important;
+    flex: 1 !important;
+    min-width: 0 !important;
+  }
+  
+  .form-input.ant-input-affix-wrapper .ant-input {
+    width: 100% !important;
+    height: 100% !important;
+    padding: 0 !important;
+    border: none !important;
+    background: transparent !important;
+    flex: 1 !important;
+    min-width: 0 !important;
+    box-sizing: border-box !important;
+  }
+  
+  /* 移动端优化 */
+  .background-pattern {
+    display: none;
+  }
+  
+  /* 禁用可能影响位置的悬停效果 */
+  .forgot-password-card:hover {
+    transform: none !important;
+  }
+}
+
+/* 高对比度模式支持 */
+@media (prefers-contrast: high) {
+  .forgot-password-card {
+    background: white;
+    border: 2px solid #000;
+  }
+  
+  .form-input {
+    border-color: #000;
+  }
+  
+  .form-input:focus {
+    border-color: #0066cc;
+    box-shadow: 0 0 0 2px #0066cc;
+  }
+}
+
+/* 减少动画模式 */
+@media (prefers-reduced-motion: reduce) {
+  .background-pattern {
+    animation: none;
+  }
+  
+  .forgot-password-card,
+  .form-input,
+  .forgot-password-button {
+    transition: none;
+  }
+}
+
+/* 深色模式支持 */
+@media (prefers-color-scheme: dark) {
+  .forgot-password-background {
+    background: linear-gradient(135deg, #1a202c 0%, #2d3748 100%);
+  }
+  
+  .forgot-password-card {
+    background: rgba(26, 32, 44, 0.95);
+    border-color: rgba(255, 255, 255, 0.1);
+  }
+  
+  .forgot-password-title {
+    color: #f7fafc;
+  }
+  
+  .forgot-password-subtitle {
+    color: #a0aec0;
+  }
+  
+  .form-label {
+    color: #e2e8f0;
+  }
+  
+  .form-input {
+    background: #2d3748;
+    border-color: #4a5568;
+    color: #f7fafc;
+  }
+  
+  .form-input:focus {
+    border-color: #ff2442;
+  }
+  
+  .login-link {
+    border-color: #4a5568;
+  }
+  
+  .login-link p {
+    color: #a0aec0;
+  }
+  
+  /* 深色模式下的错误提示样式 */
+  .error-message {
+    background: rgba(26, 32, 44, 0.95);
+    color: #ff6b6b;
+  }
+  
+  .back-to-email {
+    background: #2d3748;
+    border-color: #4a5568;
+  }
+  
+  .email-display {
+    color: #a0aec0;
+  }
+}
+
+/* 错误提示样式 - 使用绝对定位避免影响布局 */
+.error-message {
+  position: absolute;
+  top: 95%;
+  left: 4px;
+  right: 4px;
+  font-size: 12px;
+  color: #ff4d4f;
+  margin-top: 4px;
+  display: flex;
+  align-items: center;
+  min-height: 16px;
+  animation: fadeInDown 0.3s ease-out;
+  font-weight: 400;
+  line-height: 1.2;
+  background: rgba(255, 255, 255, 0.95);
+  backdrop-filter: blur(4px);
+  padding: 2px 4px;
+  border-radius: 4px;
+  z-index: 10;
+  pointer-events: none; /* 避免干扰用户交互 */
+}
+
+@keyframes fadeInDown {
+  from {
+    opacity: 0;
+    transform: translateY(-8px);
+  }
+  to {
+    opacity: 1;
+    transform: translateY(0);
+  }
+}
+
+/* 输入框错误状态样式 */
+.form-input.input-error,
+.form-input.input-error.ant-input,
+.form-input.input-error.ant-input-affix-wrapper {
+  border-color: #ff4d4f !important;
+  box-shadow: 0 0 0 2px rgba(255, 77, 79, 0.1) !important;
+  transition: all 0.3s ease !important;
+}
+
+.form-input.input-error:focus,
+.form-input.input-error.ant-input:focus,
+.form-input.input-error.ant-input-affix-wrapper:focus,
+.form-input.input-error.ant-input-affix-wrapper-focused {
+  border-color: #ff4d4f !important;
+  box-shadow: 0 0 0 2px rgba(255, 77, 79, 0.2) !important;
+}
+
+/* 错误状态下的图标颜色 */
+.form-input.input-error .anticon {
+  color: #ff4d4f !important;
+}
+
+/* 确保表单组间距一致 */
+.form-group {
+  margin-bottom: 0px;
+}
+
+.form-group:last-of-type {
+  margin-bottom: 0px;
+}
+
+/* 错误弹窗样式 */
+.error-modal .ant-modal-header {
+  background: #fff;
+  border-bottom: 1px solid #f0f0f0;
+  padding: 16px 24px;
+}
+
+.error-modal .ant-modal-title {
+  color: #333;
+  font-weight: 600;
+  font-size: 16px;
+}
+
+.error-modal .ant-modal-body {
+  padding: 16px 24px 24px;
+}
+
+.error-modal .ant-modal-footer {
+  padding: 12px 24px 24px;
+  border-top: none;
+  text-align: center;
+}
+
+.error-modal .ant-btn-primary {
+  background: #ff2442;
+  border-color: #ff2442;
+  font-weight: 500;
+  height: 40px;
+  padding: 0 24px;
+  border-radius: 6px;
+  transition: all 0.2s ease;
+}
+
+.error-modal .ant-btn-primary:hover {
+  background: #d91e3a;
+  border-color: #d91e3a;
+  transform: translateY(-1px);
+  box-shadow: 0 4px 12px rgba(255, 36, 66, 0.3);
+}
+
+.error-modal .ant-modal-content {
+  border-radius: 12px;
+  overflow: hidden;
+  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
+}
+
+/* 错误弹窗遮罩层 */
+.error-modal .ant-modal-mask {
+  background: rgba(0, 0, 0, 0.6);
+  backdrop-filter: blur(4px);
+}
+
+/* 错误弹窗动画 */
+.error-modal .ant-modal {
+  animation: errorModalSlideIn 0.3s ease-out;
+}
+
+@keyframes errorModalSlideIn {
+  from {
+    opacity: 0;
+    transform: translateY(-20px) scale(0.95);
+  }
+  to {
+    opacity: 1;
+    transform: translateY(0) scale(1);
+  }
+}
diff --git a/rhj/frontend/src/pages/ForgotPasswordPage/ForgotPasswordPage.js b/rhj/frontend/src/pages/ForgotPasswordPage/ForgotPasswordPage.js
new file mode 100644
index 0000000..d0437d5
--- /dev/null
+++ b/rhj/frontend/src/pages/ForgotPasswordPage/ForgotPasswordPage.js
@@ -0,0 +1,567 @@
+import React, { useState } from 'react';
+import { Link, useNavigate } from 'react-router-dom';
+import { Input, Button, message, Modal, Alert } from 'antd';
+import { MailOutlined, LockOutlined, SafetyOutlined, ExclamationCircleOutlined, CheckCircleOutlined } from '@ant-design/icons';
+import { hashPassword } from '../../utils/crypto';
+import './ForgotPasswordPage.css';
+
+const baseURL = 'http://10.126.59.25:8082';
+
+const ForgotPasswordPage = () => {
+  const [formData, setFormData] = useState({
+    email: '',
+    emailCode: '',
+    newPassword: '',
+    confirmPassword: ''
+  });
+
+  const [errors, setErrors] = useState({
+    email: '',
+    emailCode: '',
+    newPassword: '',
+    confirmPassword: ''
+  });
+
+  const [emailCodeSent, setEmailCodeSent] = useState(false);
+  const [countdown, setCountdown] = useState(0);
+  const [sendingCode, setSendingCode] = useState(false);
+  const [isLoading, setIsLoading] = useState(false);
+  const [errorModal, setErrorModal] = useState({
+    visible: false,
+    title: '',
+    content: ''
+  });
+  const [successAlert, setSuccessAlert] = useState({
+    visible: false,
+    message: ''
+  });
+  const [emailCodeSuccessAlert, setEmailCodeSuccessAlert] = useState({
+    visible: false,
+    message: ''
+  });
+
+  const navigate = useNavigate();
+
+  // 显示错误弹窗
+  const showErrorModal = (title, content) => {
+    setErrorModal({
+      visible: true,
+      title: title,
+      content: content
+    });
+  };
+
+  // 关闭错误弹窗
+  const closeErrorModal = () => {
+    setErrorModal({
+      visible: false,
+      title: '',
+      content: ''
+    });
+  };
+
+  // 显示成功提示
+  const showSuccessAlert = (message) => {
+    setSuccessAlert({
+      visible: true,
+      message: message
+    });
+    
+    // 3秒后自动隐藏
+    setTimeout(() => {
+      setSuccessAlert({
+        visible: false,
+        message: ''
+      });
+    }, 3000);
+  };
+
+  // 显示邮件验证码发送成功提示
+  const showEmailCodeSuccessAlert = (message) => {
+    setEmailCodeSuccessAlert({
+      visible: true,
+      message: message
+    });
+    
+    // 5秒后自动隐藏
+    setTimeout(() => {
+      setEmailCodeSuccessAlert({
+        visible: false,
+        message: ''
+      });
+    }, 5000);
+  };
+
+  // 倒计时效果
+  React.useEffect(() => {
+    let timer;
+    if (countdown > 0) {
+      timer = setTimeout(() => {
+        setCountdown(countdown - 1);
+      }, 1000);
+    }
+    return () => clearTimeout(timer);
+  }, [countdown]);
+
+  // 发送邮箱验证码
+  const sendEmailCode = async () => {
+    // 验证邮箱格式
+    if (!formData.email || typeof formData.email !== 'string' || !formData.email.trim()) {
+      setErrors(prev => ({
+        ...prev,
+        email: '请先输入邮箱地址'
+      }));
+      return;
+    }
+    
+    if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(formData.email)) {
+      setErrors(prev => ({
+        ...prev,
+        email: '请输入有效的邮箱地址'
+      }));
+      return;
+    }
+
+    setSendingCode(true);
+    
+    try {
+      // 调用后端API发送验证码
+      const response = await fetch(baseURL + '/send-verification-code', {
+        method: 'POST',
+        headers: {
+          'Content-Type': 'application/json',
+        },
+        body: JSON.stringify({
+          email: formData.email,
+          type: 'reset_password'
+        })
+      });
+      
+      if (!response.ok) {
+        throw new Error(`HTTP ${response.status}: ${response.statusText}`);
+      }
+      
+      const result = await response.json();
+      
+      if (result.success) {
+        showEmailCodeSuccessAlert('验证码已发送到您的邮箱');
+        setEmailCodeSent(true);
+        setCountdown(60); // 60秒倒计时
+        
+        // 清除邮箱错误提示
+        setErrors(prev => ({
+          ...prev,
+          email: ''
+        }));
+      } else {
+        // 根据具体错误信息进行处理
+        const errorMessage = result.message || '发送验证码失败,请稍后再试';
+        
+        if (errorMessage.includes('用户不存在') || errorMessage.includes('邮箱未注册')) {
+          setErrors(prev => ({
+            ...prev,
+            email: '该邮箱尚未注册,请检查邮箱地址或先注册账户'
+          }));
+        } else {
+          showErrorModal('发送验证码失败', errorMessage);
+        }
+      }
+      
+    } catch (error) {
+      console.error('发送验证码失败:', error);
+      
+      // 根据错误类型显示不同的错误信息
+      if (error.name === 'TypeError' && error.message.includes('Failed to fetch')) {
+        showErrorModal('网络连接失败', '无法连接到服务器,请检查您的网络连接后重试。');
+      } else if (error.message.includes('HTTP 500')) {
+        showErrorModal('服务器错误', '服务器出现了内部错误,请稍后重试。');
+      } else if (error.message.includes('HTTP 429')) {
+        showErrorModal('发送频率限制', '验证码发送过于频繁,请稍后再试。');
+      } else if (error.message.includes('HTTP 400')) {
+        showErrorModal('请求错误', '邮箱格式错误,请检查邮箱地址是否正确。');
+      } else {
+        showErrorModal('发送失败', '发送验证码失败,请稍后重试。');
+      }
+    } finally {
+      setSendingCode(false);
+    }
+  };
+
+  const handleInputChange = (field) => (e) => {
+    const value = e.target.value;
+    setFormData(prev => ({
+      ...prev,
+      [field]: value
+    }));
+    
+    // 清除对应字段的错误提示
+    if (errors[field]) {
+      setErrors(prev => ({
+        ...prev,
+        [field]: ''
+      }));
+    }
+  };
+
+  const handlePasswordChange = (e) => {
+    const value = e.target.value;
+    setFormData(prev => ({
+      ...prev,
+      newPassword: value
+    }));
+    
+    // 清除密码错误提示
+    if (errors.newPassword) {
+      setErrors(prev => ({
+        ...prev,
+        newPassword: ''
+      }));
+    }
+  };
+
+  const handleConfirmPasswordChange = (e) => {
+    const value = e.target.value;
+    setFormData(prev => ({
+      ...prev,
+      confirmPassword: value
+    }));
+    
+    // 清除确认密码错误提示
+    if (errors.confirmPassword) {
+      setErrors(prev => ({
+        ...prev,
+        confirmPassword: ''
+      }));
+    }
+  };
+
+  const validateForm = () => {
+    const newErrors = {
+      email: '',
+      emailCode: '',
+      newPassword: '',
+      confirmPassword: ''
+    };
+    
+    let hasError = false;
+    
+    // 验证邮箱
+    if (!formData.email || typeof formData.email !== 'string' || !formData.email.trim()) {
+      newErrors.email = '请输入邮箱地址';
+      hasError = true;
+    } else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(formData.email)) {
+      newErrors.email = '请输入有效的邮箱地址';
+      hasError = true;
+    }
+    
+    // 验证邮箱验证码
+    if (!formData.emailCode || typeof formData.emailCode !== 'string' || !formData.emailCode.trim()) {
+      newErrors.emailCode = '请输入邮箱验证码';
+      hasError = true;
+    } else if (formData.emailCode.length !== 6 || !/^\d{6}$/.test(formData.emailCode)) {
+      newErrors.emailCode = '请输入6位数字验证码';
+      hasError = true;
+    }
+    
+    // 验证新密码
+    if (!formData.newPassword || typeof formData.newPassword !== 'string' || !formData.newPassword.trim()) {
+      newErrors.newPassword = '请输入新密码';
+      hasError = true;
+    } else if (formData.newPassword.length < 6) {
+      newErrors.newPassword = '密码长度至少6位';
+      hasError = true;
+    } else if (formData.newPassword.length > 20) {
+      newErrors.newPassword = '密码长度不能超过20位';
+      hasError = true;
+    }
+    
+    // 验证确认密码
+    if (!formData.confirmPassword || typeof formData.confirmPassword !== 'string' || !formData.confirmPassword.trim()) {
+      newErrors.confirmPassword = '请确认新密码';
+      hasError = true;
+    } else if (formData.newPassword !== formData.confirmPassword) {
+      newErrors.confirmPassword = '两次输入的密码不一致';
+      hasError = true;
+    }
+    
+    setErrors(newErrors);
+    return !hasError;
+  };
+
+  const handleSubmit = async (e) => {
+    e.preventDefault();
+    
+    // 验证表单
+    if (!validateForm()) {
+      return;
+    }
+    
+    setIsLoading(true);
+    
+    try {
+      // 验证码验证成功,重置密码
+      const resetResponse = await fetch(baseURL + '/reset-password', {
+        method: 'POST',
+        headers: {
+          'Content-Type': 'application/json',
+        },
+        body: JSON.stringify({
+          email: formData.email,
+          new_password: hashPassword(formData.newPassword), // 前端加密密码
+          verification_code: hashPassword(formData.emailCode) // 前端加密验证码
+        })
+      });
+      
+      if (!resetResponse.ok) {
+        throw new Error(`HTTP ${resetResponse.status}: ${resetResponse.statusText}`);
+      }
+      
+      const resetResult = await resetResponse.json();
+      
+      if (resetResult.success) {
+        showSuccessAlert('密码重置成功!请使用新密码登录,正在跳转到登录页面...');
+        // 清空表单数据
+        setFormData({
+          email: '',
+          emailCode: '',
+          newPassword: '',
+          confirmPassword: ''
+        });
+        setErrors({
+          email: '',
+          emailCode: '',
+          newPassword: '',
+          confirmPassword: ''
+        });
+        // 延迟跳转到登录页面,让用户看到成功提示
+        setTimeout(() => {
+          navigate('/login');
+        }, 2000);
+      } else {
+        // 处理重置密码失败的情况
+        const errorMessage = resetResult.message || '密码重置失败,请稍后再试';
+        showErrorModal('密码重置失败', errorMessage);
+      }
+      
+    } catch (error) {
+      console.error('密码重置失败:', error);
+      
+      // 根据错误类型显示不同的错误信息
+      if (error.name === 'TypeError' && error.message.includes('Failed to fetch')) {
+        showErrorModal('网络连接失败', '无法连接到服务器,请检查您的网络连接后重试。');
+      } else if (error.message.includes('HTTP 500')) {
+        showErrorModal('服务器内部错误', '服务器出现了内部错误,请稍后重试。');
+      } else if (error.message.includes('HTTP 400')) {
+        showErrorModal('请求参数错误', '请求参数有误,请检查您输入的信息是否正确。');
+      } else if (error.message.includes('HTTP 409')) {
+        showErrorModal('操作冲突', '重置操作发生冲突,请稍后重试。');
+      } else {
+        showErrorModal('重置失败', '密码重置失败,请稍后重试。');
+      }
+    } finally {
+      setIsLoading(false);
+    }
+  };
+
+  return (
+    <div className="register-container">
+      <div className="register-background"></div>
+      
+      {isLoading && (
+        <div className="loading-overlay">
+          <div className="loading-content">
+            <div className="loading-spinner-large"></div>
+            <p className="loading-text">正在重置密码...</p>
+          </div>
+        </div>
+      )}
+      
+      <div className="register-content">
+        <div className="register-card">
+          {/* 成功提示 */}
+          {successAlert.visible && (
+            <div style={{ marginBottom: '16px' }}>
+              <Alert
+                message={successAlert.message}
+                type="success"
+                icon={<CheckCircleOutlined />}
+                showIcon
+                closable
+                onClose={() => setSuccessAlert({ visible: false, message: '' })}
+                style={{
+                  borderRadius: '8px',
+                  border: '1px solid #b7eb8f',
+                  backgroundColor: '#f6ffed'
+                }}
+              />
+            </div>
+          )}
+
+          {/* 邮件验证码发送成功提示 */}
+          {emailCodeSuccessAlert.visible && (
+            <div style={{ marginBottom: '16px' }}>
+              <Alert
+                message={emailCodeSuccessAlert.message}
+                type="success"
+                icon={<CheckCircleOutlined />}
+                showIcon
+                closable
+                onClose={() => setEmailCodeSuccessAlert({ visible: false, message: '' })}
+                style={{
+                  borderRadius: '8px',
+                  border: '1px solid #b7eb8f',
+                  backgroundColor: '#f6ffed'
+                }}
+              />
+            </div>
+          )}
+          
+          <div className="register-header">
+            <h1 className="register-title">重置密码</h1>
+            <p className="register-subtitle">请输入邮箱地址和新密码</p>
+          </div>
+
+          <form className="register-form" onSubmit={handleSubmit}>
+            <div className="form-group">
+              <Input
+                type="email"
+                id="email"
+                name="email"
+                className={`form-input ${errors.email ? 'input-error' : ''}`}
+                placeholder="请输入邮箱地址"
+                value={formData.email}
+                onChange={handleInputChange('email')}
+                prefix={<MailOutlined />}
+                size="large"
+                title=""
+                status={errors.email ? 'error' : ''}
+              />
+              {errors.email && (
+                <div className="error-message">
+                  {errors.email}
+                </div>
+              )}
+            </div>
+
+            <div className="form-group">
+              <div className="email-code-wrapper">
+                <Input
+                  type="text"
+                  id="emailCode"
+                  name="emailCode"
+                  className={`form-input email-code-input ${errors.emailCode ? 'input-error' : ''}`}
+                  placeholder="请输入6位验证码"
+                  value={formData.emailCode}
+                  onChange={handleInputChange('emailCode')}
+                  prefix={<SafetyOutlined />}
+                  maxLength={6}
+                  size="large"
+                  title=""
+                  status={errors.emailCode ? 'error' : ''}
+                />
+                <Button
+                  type="primary"
+                  className="send-code-button"
+                  onClick={sendEmailCode}
+                  loading={sendingCode}
+                  disabled={countdown > 0 || !formData.email || sendingCode}
+                  size="large"
+                >
+                  {countdown > 0 ? `${countdown}s后重发` : (emailCodeSent ? '重新发送' : '发送验证码')}
+                </Button>
+              </div>
+              {errors.emailCode && (
+                <div className="error-message">
+                  {errors.emailCode}
+                </div>
+              )}
+            </div>
+
+            <div className="form-group">
+              <Input.Password
+                id="newPassword"
+                name="newPassword"
+                className={`form-input ${errors.newPassword ? 'input-error' : ''}`}
+                placeholder="请输入新密码"
+                value={formData.newPassword}
+                onChange={handlePasswordChange}
+                prefix={<LockOutlined />}
+                size="large"
+                title=""
+                status={errors.newPassword ? 'error' : ''}
+              />
+              {errors.newPassword && (
+                <div className="error-message">
+                  {errors.newPassword}
+                </div>
+              )}
+            </div>
+
+            <div className="form-group">
+              <Input.Password
+                id="confirmPassword"
+                name="confirmPassword"
+                className={`form-input ${errors.confirmPassword ? 'input-error' : ''}`}
+                placeholder="请确认新密码"
+                value={formData.confirmPassword}
+                onChange={handleConfirmPasswordChange}
+                prefix={<LockOutlined />}
+                size="large"
+                title=""
+                status={errors.confirmPassword ? 'error' : ''}
+              />
+              {errors.confirmPassword && (
+                <div className="error-message">
+                  {errors.confirmPassword}
+                </div>
+              )}
+            </div>
+
+            <button
+              type="submit"
+              className={`register-button ${isLoading ? 'loading' : ''}`}
+              disabled={isLoading}
+            >
+              {isLoading ? (
+                <>
+                  <div className="loading-spinner"></div>
+                  重置中...
+                </>
+              ) : (
+                '重置密码'
+              )}
+            </button>
+          </form>
+
+          <div className="login-link">
+            <p>想起密码了? <Link to="/login">立即登录</Link></p>
+            <p>还没有账户? <Link to="/register">立即注册</Link></p>
+          </div>
+        </div>
+      </div>
+
+      {/* 错误弹窗 */}
+      <Modal
+        title={
+          <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
+            <ExclamationCircleOutlined style={{ color: '#ff4d4f', fontSize: '18px' }} />
+            {errorModal.title}
+          </div>
+        }
+        open={errorModal.visible}
+        onOk={closeErrorModal}
+        onCancel={closeErrorModal}
+        okText="我知道了"
+        cancelButtonProps={{ style: { display: 'none' } }}
+        centered
+        className="error-modal"
+      >
+        <div style={{ padding: '16px 0', fontSize: '14px', lineHeight: '1.6' }}>
+          {errorModal.content}
+        </div>
+      </Modal>
+    </div>
+  );
+};
+
+export default ForgotPasswordPage;
diff --git a/rhj/frontend/src/pages/LoginPage/LoginPage.css b/rhj/frontend/src/pages/LoginPage/LoginPage.css
new file mode 100644
index 0000000..ab1e24c
--- /dev/null
+++ b/rhj/frontend/src/pages/LoginPage/LoginPage.css
@@ -0,0 +1,1288 @@
+/* 登录页面容器 */
+.login-container {
+  min-height: 100vh;
+  min-height: 100dvh; /* 动态视口高度,避免移动端地址栏影响 */
+  height: 100vh;
+  height: 100dvh;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  position: relative;
+  overflow: hidden;
+  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
+    'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
+    sans-serif;
+  /* 确保容器稳定定位 */
+  box-sizing: border-box;
+  margin: 0;
+  padding: 0;
+  /* 重置文本对齐 */
+  text-align: initial;
+}
+
+/* 小红书风格背景 */
+.login-background {
+  position: absolute;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  background: #f8f8f8;
+  z-index: -1;
+}
+
+/* 登录内容区域 */
+.login-content {
+  width: 100%;
+  max-width: 500px; /* 增加桌面端最大宽度 */
+  padding: 0;
+  z-index: 1;
+  /* 确保内容稳定定位 */
+  box-sizing: border-box;
+  position: relative;
+  display: flex;
+  justify-content: center;
+}
+
+/* 小红书风格登录卡片 */
+.login-card {
+  background: #fff;
+  border-radius: 8px;
+  padding: 40px; /* 增加桌面端内边距 */
+  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
+  border: 1px solid #e1e1e1;
+  width: 100%;
+  max-width: 450px; /* 增加桌面端卡片最大宽度 */
+  transition: none;
+}
+
+/* 登录头部 */
+.login-header {
+  text-align: center;
+  margin-bottom: 40px;
+}
+
+/* Logo样式 */
+.logo-section {
+  margin-bottom: 24px;
+}
+
+.logo-icon {
+  width: 60px;
+  height: 60px;
+  background: #ff2442;
+  border-radius: 12px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  font-size: 28px;
+  margin: 0 auto 16px;
+  box-shadow: 0 4px 12px rgba(255, 36, 66, 0.2);
+}
+
+.login-title {
+  font-size: 24px;
+  font-weight: 600;
+  color: #333;
+  margin: 0 0 12px 0;
+  text-align: center;
+}
+
+.login-title::after {
+  display: none;
+}
+
+.login-subtitle {
+  font-size: 14px;
+  color: #999;
+  margin: 0 0 32px 0;
+  font-weight: 400;
+  text-align: center;
+}
+
+/* 表单样式 */
+.login-form {
+  display: flex;
+  flex-direction: column;
+  gap: 24px;
+  width: 100%;
+}
+
+.form-group {
+  display: flex;
+  flex-direction: column;
+  gap: 6px;
+  width: 100%;
+  box-sizing: border-box;
+  margin-bottom: 2px;
+  position: relative; /* 为绝对定位的错误提示提供参考点 */
+}
+
+.form-group .input-wrapper {
+  width: 100%;
+  box-sizing: border-box;
+}
+
+.form-label {
+  font-size: 14px;
+  font-weight: 500;
+  color: #333;
+  margin-bottom: 8px;
+}
+
+.input-wrapper {
+  position: relative;
+  display: flex;
+  align-items: center;
+  width: 100%;
+  box-sizing: border-box;
+}
+
+.form-input {
+  width: 100% !important;
+  height: 44px;
+  padding: 12px 16px 12px 48px;
+  border: 1px solid #e1e1e1;
+  border-radius: 6px;
+  font-size: 14px;
+  transition: border-color 0.2s ease;
+  background: #fff;
+  color: #333;
+  box-sizing: border-box !important;
+  flex: 1;
+  min-width: 0;
+}
+
+/* 针对 Antd Input 组件的特定样式 */
+.form-input.ant-input,
+.form-input.ant-input-affix-wrapper {
+  width: 100% !important;
+  height: 44px !important;
+  border: 1px solid #e1e1e1 !important;
+  border-radius: 6px !important;
+  padding: 12px 48px 12px 48px !important;
+  font-size: 14px !important;
+  background: #fff !important;
+  color: #333 !important;
+  box-sizing: border-box !important;
+  flex: 1 !important;
+  min-width: 0 !important;
+  display: flex !important;
+  align-items: center !important;
+}
+
+.form-input.ant-input-affix-wrapper .ant-input {
+  width: 100% !important;
+  height: 100% !important;
+  padding: 0 !important;
+  border: none !important;
+  background: transparent !important;
+  flex: 1 !important;
+  min-width: 0 !important;
+  box-sizing: border-box !important;
+}
+
+.form-input:focus {
+  outline: none;
+  border-color: #ff2442;
+  box-shadow: none;
+  transform: none;
+}
+
+/* Antd Input focus 样式 */
+.form-input.ant-input:focus,
+.form-input.ant-input-affix-wrapper:focus,
+.form-input.ant-input-affix-wrapper-focused {
+  outline: none !important;
+  border-color: #ff2442 !important;
+  box-shadow: none !important;
+  transform: none !important;
+}
+
+.form-input::placeholder {
+  color: #9ca3af;
+}
+
+.input-icon {
+  position: absolute;
+  left: 16px;
+  top: 50%;
+  transform: translateY(-50%);
+  color: #9ca3af;
+  pointer-events: none;
+  transition: color 0.3s ease;
+  z-index: 2;
+}
+
+.form-input:focus + .input-icon {
+  color: #ff2442;
+}
+
+.password-toggle {
+  position: absolute;
+  right: 12px;
+  top: 50%;
+  transform: translateY(-50%);
+  background: none;
+  border: none;
+  color: #9ca3af;
+  cursor: pointer;
+  padding: 4px;
+  border-radius: 4px;
+  transition: all 0.3s ease;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  z-index: 2;
+  width: 24px;
+  height: 24px;
+}
+
+.password-toggle:hover {
+  color: #ff2442;
+  background-color: rgba(255, 36, 66, 0.1);
+}
+
+/* 表单选项 */
+.form-options {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-top: 8px;
+  margin-bottom: 16px;
+  width: 100%;
+  flex-wrap: nowrap; /* 确保不换行 */
+  min-height: 24px;
+  gap: 8px; /* 添加基础间距 */
+}
+
+/* Ant Design Checkbox 样式兼容 */
+.form-options .ant-checkbox-wrapper {
+  flex: 0 0 auto; /* 不伸缩,保持原始大小 */
+  font-size: 14px;
+  color: #64748b;
+  white-space: nowrap; /* 防止文字换行 */
+  overflow: hidden;
+  text-overflow: ellipsis;
+  max-width: 50%; /* 限制最大宽度 */
+}
+
+.form-options .ant-checkbox-wrapper .ant-checkbox {
+  margin-right: 8px;
+}
+
+.form-options .forgot-password {
+  flex: 0 0 auto; /* 不伸缩,保持原始大小 */
+  margin-left: auto;
+  white-space: nowrap;
+  color: #ff2442;
+  text-decoration: none;
+  font-size: 14px;
+  transition: color 0.3s ease;
+  max-width: 45%; /* 限制最大宽度 */
+  overflow: hidden;
+  text-overflow: ellipsis;
+}
+
+.form-options .forgot-password:hover {
+  color: #ff1a3a;
+  text-decoration: underline;
+}
+
+.checkbox-wrapper {
+  display: flex;
+  align-items: center;
+  gap: 8px;
+  cursor: pointer;
+  font-size: 14px;
+  color: #64748b;
+  -webkit-user-select: none;
+  -moz-user-select: none;
+  -ms-user-select: none;
+  user-select: none;
+  flex-shrink: 0;
+}
+
+.checkbox {
+  position: relative;
+  width: 18px;
+  height: 18px;
+  margin: 0;
+  cursor: pointer;
+  opacity: 0;
+}
+
+.checkmark {
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 18px;
+  height: 18px;
+  background-color: #fff;
+  border: 1px solid #e1e1e1;
+  border-radius: 3px;
+  transition: all 0.2s ease;
+}
+
+.checkbox:checked + .checkmark {
+  background-color: #ff2442;
+  border-color: #ff2442;
+}
+
+.checkmark:after {
+  content: "";
+  position: absolute;
+  display: none;
+  left: 5px;
+  top: 2px;
+  width: 4px;
+  height: 8px;
+  border: solid white;
+  border-width: 0 2px 2px 0;
+  transform: rotate(45deg);
+}
+
+.checkbox:checked + .checkmark:after {
+  display: block;
+}
+
+.forgot-password {
+  font-size: 14px;
+  color: #ff2442;
+  text-decoration: none;
+  font-weight: 400;
+  transition: color 0.2s ease;
+  margin-left: auto;
+  flex-shrink: 0;
+  white-space: nowrap;
+}
+
+.forgot-password:hover {
+  color: #d91e3a;
+  text-decoration: underline;
+}
+
+/* 小红书风格登录按钮 */
+.login-button {
+  width: 100%;
+  height: 48px; /* 固定高度,防止布局变化 */
+  padding: 12px;
+  background: #ff2442;
+  color: white;
+  border: none;
+  border-radius: 6px;
+  font-size: 14px;
+  font-weight: 500;
+  cursor: pointer;
+  transition: background-color 0.2s ease;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  gap: 8px;
+  margin-top: 8px;
+  box-sizing: border-box; /* 确保padding包含在总尺寸内 */
+  min-width: 0; /* 防止flex子元素造成宽度变化 */
+}
+
+.login-button:hover:not(:disabled) {
+  background: #d91e3a;
+  transform: none;
+  box-shadow: none;
+}
+
+.login-button:active:not(:disabled) {
+  transform: none;
+}
+
+.login-button:disabled {
+  background: #ccc;
+  cursor: not-allowed;
+  opacity: 0.8;
+}
+
+.login-button.loading {
+  background: #ff7b8a;
+  cursor: not-allowed;
+}
+
+.loading-spinner {
+  width: 16px;
+  height: 16px;
+  border: 2px solid rgba(255, 255, 255, 0.3);
+  border-radius: 50%;
+  border-top-color: #fff;
+  animation: spin 1s ease-in-out infinite;
+}
+
+@keyframes spin {
+  to { transform: rotate(360deg); }
+}
+
+/* 加载遮罩层 */
+.loading-overlay {
+  position: fixed;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  background: rgba(0, 0, 0, 0.5);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  z-index: 1000;
+  backdrop-filter: blur(4px);
+}
+
+.loading-content {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  gap: 16px;
+  background: white;
+  padding: 32px;
+  border-radius: 12px;
+  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
+}
+
+.loading-spinner-large {
+  width: 40px;
+  height: 40px;
+  border: 4px solid rgba(255, 36, 66, 0.2);
+  border-radius: 50%;
+  border-top-color: #ff2442;
+  animation: spin 1s ease-in-out infinite;
+}
+
+.loading-text {
+  margin: 0;
+  color: #333;
+  font-size: 16px;
+  font-weight: 500;
+}
+
+/* 分隔线 */
+.login-divider {
+  position: relative;
+  text-align: center;
+  margin: 32px 0;
+  color: #9ca3af;
+  font-size: 14px;
+}
+
+.login-divider::before {
+  content: '';
+  position: absolute;
+  top: 50%;
+  left: 0;
+  right: 0;
+  height: 1px;
+  background: linear-gradient(to right, transparent, #e5e7eb, transparent);
+}
+
+.login-divider span {
+  background: rgba(255, 255, 255, 0.95);
+  padding: 0 16px;
+  position: relative;
+  z-index: 1;
+}
+
+/* 社交登录 */
+.social-login {
+  display: flex;
+  flex-direction: column;
+  gap: 12px;
+}
+
+.social-button {
+  width: 100%;
+  padding: 12px 16px;
+  border: 1px solid #e1e1e1;
+  border-radius: 6px;
+  background: white;
+  color: #333;
+  font-size: 14px;
+  font-weight: 400;
+  cursor: pointer;
+  transition: border-color 0.2s ease;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  gap: 8px;
+}
+
+.social-button:hover {
+  border-color: #ccc;
+}
+
+.social-button.google:hover {
+  border-color: #4285f4;
+  box-shadow: 0 4px 12px rgba(66, 133, 244, 0.2);
+}
+
+.social-button.github:hover {
+  border-color: #333;
+  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
+}
+
+.social-button.xiaohongshu:hover {
+  border-color: #ff2442;
+  box-shadow: 0 4px 12px rgba(255, 36, 66, 0.2);
+}
+
+/* 注册链接 */
+.signup-link {
+  text-align: center;
+  margin-top: 20px;
+  padding-top: 20px;
+  border-top: 1px solid #e5e7eb;
+}
+
+.signup-link p {
+  margin: 0;
+  font-size: 14px;
+  color: #64748b;
+}
+
+.signup-link a {
+  color: #ff2442;
+  text-decoration: none;
+  font-weight: 500;
+  transition: color 0.2s ease;
+}
+
+.signup-link a:hover {
+  color: #d91e3a;
+  text-decoration: underline;
+}
+
+/* 有左侧图标时的内边距调整 */
+.input-wrapper.has-icon .form-input {
+  padding-left: 48px !important;
+}
+
+.input-wrapper.has-icon .form-input.ant-input,
+.input-wrapper.has-icon .form-input.ant-input-affix-wrapper {
+  padding-left: 48px !important;
+}
+
+/* 有右侧切换按钮时的内边距调整 */
+.input-wrapper.has-toggle .form-input {
+  padding-right: 48px !important;
+}
+
+.input-wrapper.has-toggle .form-input.ant-input,
+.input-wrapper.has-toggle .form-input.ant-input-affix-wrapper {
+  padding-right: 48px !important;
+}
+
+/* 没有图标时的内边距调整 */
+.input-wrapper:not(.has-icon) .form-input {
+  padding-left: 16px !important;
+}
+
+.input-wrapper:not(.has-icon) .form-input.ant-input,
+.input-wrapper:not(.has-icon) .form-input.ant-input-affix-wrapper {
+  padding-left: 16px !important;
+}
+
+/* 没有切换按钮时的内边距调整 */
+.input-wrapper:not(.has-toggle) .form-input {
+  padding-right: 16px !important;
+}
+
+.input-wrapper:not(.has-toggle) .form-input.ant-input,
+.input-wrapper:not(.has-toggle) .form-input.ant-input-affix-wrapper {
+  padding-right: 16px !important;
+}
+
+/* 确保输入框内容完全填充 */
+.form-input.ant-input-affix-wrapper .ant-input-suffix {
+  position: absolute !important;
+  right: 12px !important;
+  top: 50% !important;
+  transform: translateY(-50%) !important;
+  margin: 0 !important;
+  padding: 0 !important;
+}
+
+.form-input.ant-input-affix-wrapper .ant-input-prefix {
+  position: absolute !important;
+  left: 16px !important;
+  top: 50% !important;
+  transform: translateY(-50%) !important;
+  margin: 0 !important;
+  padding: 0 !important;
+}
+
+/* 确保所有输入框完全填充其容器 */
+.form-group {
+  display: flex;
+  flex-direction: column;
+  gap: 8px;
+  width: 100%;
+  box-sizing: border-box;
+}
+
+.form-group .input-wrapper {
+  width: 100%;
+  box-sizing: border-box;
+}
+
+/* 防止输入框溢出容器 */
+.form-input,
+.form-input.ant-input,
+.form-input.ant-input-affix-wrapper {
+  max-width: 100% !important;
+  overflow: hidden !important;
+}
+
+/* 确保内部输入元素不会超出边界 */
+.form-input.ant-input-affix-wrapper .ant-input {
+  max-width: 100% !important;
+  overflow: hidden !important;
+  text-overflow: ellipsis !important;
+}
+
+/* 精细间距控制 */
+.login-header + .login-form {
+  margin-top: -4px;
+}
+
+.login-form .form-group:not(:last-child) {
+  margin-bottom: 2px;
+}
+
+.login-form .form-group:last-of-type {
+  margin-bottom: 6px;
+}
+
+.login-button + .signup-link {
+  margin-top: 14px;
+}
+
+/* 响应式设计 */
+@media (max-width: 768px) {
+  /* 重置body和html确保一致性 */
+  html, body {
+    height: 100%;
+    height: 100dvh;
+    margin: 0;
+    padding: 0;
+    overflow-x: hidden;
+    box-sizing: border-box;
+  }
+  
+  .login-container {
+    padding: 16px;
+    align-items: center;
+    justify-content: center;
+    min-height: 100vh;
+    min-height: 100dvh; /* 动态视口高度 */
+    /* 强制重置可能影响定位的样式 */
+    margin: 0;
+    box-sizing: border-box;
+    /* 防止内容溢出影响布局 */
+    overflow-x: hidden;
+    overflow-y: auto;
+    /* 确保flexbox在所有移动设备上表现一致 */
+    -webkit-box-align: center;
+    -webkit-box-pack: center;
+    display: flex !important;
+    position: relative;
+  }
+  
+  .login-content {
+    max-width: 100%;
+    padding: 20px;
+    /* 确保内容区域稳定 */
+    margin: 0 auto;
+    box-sizing: border-box;
+    /* 防止宽度计算问题 */
+    width: calc(100% - 40px);
+    max-width: 480px; /* 增加最大宽度 */
+    position: relative;
+    display: flex;
+    justify-content: center;
+  }
+  
+  .login-card {
+    padding: 32px 28px; /* 增加内边距 */
+    border-radius: 16px;
+    /* 确保卡片稳定定位 */
+    margin: 0;
+    box-sizing: border-box;
+    width: 100%;
+    max-width: 450px; /* 增加卡片最大宽度 */
+    /* 防止backdrop-filter导致的渲染差异 */
+    will-change: auto;
+    position: relative;
+    /* 防止触摸操作影响布局 */
+    -webkit-touch-callout: none;
+    -webkit-user-select: none;
+    -moz-user-select: none;
+    -ms-user-select: none;
+    user-select: none;
+    -webkit-tap-highlight-color: transparent;
+  }
+  
+  .login-title {
+    font-size: 24px;
+  }
+  
+  .form-input {
+    width: 100% !important;
+    height: 44px !important;
+    padding: 12px 48px 12px 48px;
+    font-size: 16px; /* 防止iOS Safari缩放 */
+    box-sizing: border-box !important;
+    flex: 1 !important;
+    min-width: 0 !important;
+  }
+  
+  .form-input.ant-input,
+  .form-input.ant-input-affix-wrapper {
+    width: 100% !important;
+    height: 44px !important;
+    padding: 12px 48px 12px 48px !important;
+    font-size: 16px !important;
+    box-sizing: border-box !important;
+    flex: 1 !important;
+    min-width: 0 !important;
+  }
+  
+  .form-input.ant-input-affix-wrapper .ant-input {
+    width: 100% !important;
+    height: 100% !important;
+    padding: 0 !important;
+    border: none !important;
+    background: transparent !important;
+    flex: 1 !important;
+    min-width: 0 !important;
+    box-sizing: border-box !important;
+  }
+  
+  .social-login {
+    gap: 10px;
+  }
+  
+  .social-button {
+    padding: 12px 16px;
+    font-size: 14px;
+  }
+  
+  .form-options {
+    display: flex !important;
+    flex-direction: row !important;
+    justify-content: space-between !important;
+    align-items: center !important;
+    gap: 8px !important;
+    width: 100% !important;
+    flex-wrap: nowrap !important;
+    min-height: 22px !important;
+    margin-top: 8px !important;
+    margin-bottom: 16px !important;
+  }
+  
+  .checkbox-wrapper {
+    font-size: 13px;
+    flex: 0 0 auto !important;
+    white-space: nowrap !important;
+    overflow: hidden !important;
+    text-overflow: ellipsis !important;
+    max-width: 48% !important;
+  }
+  
+  .forgot-password {
+    font-size: 13px;
+    margin-left: auto;
+    flex: 0 0 auto !important;
+    white-space: nowrap !important;
+    overflow: hidden !important;
+    text-overflow: ellipsis !important;
+    max-width: 48% !important;
+  }
+  
+  /* Ant Design Checkbox 的特殊处理 */
+  .form-options .ant-checkbox-wrapper {
+    flex: 0 0 auto !important;
+    font-size: 13px !important;
+    white-space: nowrap !important;
+    overflow: hidden !important;
+    text-overflow: ellipsis !important;
+    max-width: 48% !important;
+  }
+}
+
+@media (max-width: 480px) {
+  .login-container {
+    padding: 16px;
+    align-items: center;
+    justify-content: center;
+    min-height: 100vh;
+    min-height: 100dvh; /* 动态视口高度 */
+    /* 强制重置样式 */
+    margin: 0;
+    box-sizing: border-box;
+    position: relative;
+    /* 确保垂直居中 */
+    display: flex !important;
+  }
+  
+  .login-content {
+    /* 更严格的尺寸控制 */
+    width: calc(100vw - 32px);
+    max-width: 420px; /* 增加最大宽度 */
+    padding: 16px;
+    margin: 0 auto;
+    box-sizing: border-box;
+    display: flex;
+    justify-content: center;
+  }
+  
+  .login-card {
+    padding: 28px 24px; /* 增加内边距 */
+    border-radius: 12px;
+    /* 确保卡片完全稳定 */
+    margin: 0;
+    box-sizing: border-box;
+    width: 100%;
+    position: relative;
+    /* 防止变换导致的位置偏移 */
+    transform: none !important;
+    /* 防止触摸操作影响布局 */
+    -webkit-touch-callout: none;
+    -webkit-user-select: none;
+    -khtml-user-select: none;
+    -moz-user-select: none;
+    -ms-user-select: none;
+    user-select: none;
+    /* 防止点击时的高亮效果影响布局 */
+    -webkit-tap-highlight-color: transparent;
+  }
+  
+  .login-title {
+    font-size: 22px;
+  }
+  
+  .form-input {
+    width: 100% !important;
+    height: 44px !important;
+    padding: 12px 48px 12px 48px;
+    font-size: 16px; /* 防止iOS Safari缩放 */
+    box-sizing: border-box !important;
+    flex: 1 !important;
+    min-width: 0 !important;
+  }
+  
+  .form-input.ant-input,
+  .form-input.ant-input-affix-wrapper {
+    width: 100% !important;
+    height: 44px !important;
+    padding: 12px 48px 12px 48px !important;
+    font-size: 16px !important;
+    box-sizing: border-box !important;
+    flex: 1 !important;
+    min-width: 0 !important;
+  }
+  
+  .form-input.ant-input-affix-wrapper .ant-input {
+    width: 100% !important;
+    height: 100% !important;
+    padding: 0 !important;
+    border: none !important;
+    background: transparent !important;
+    flex: 1 !important;
+    min-width: 0 !important;
+    box-sizing: border-box !important;
+  }
+  
+  .social-login {
+    gap: 10px;
+  }
+  
+  .social-button {
+    padding: 12px 16px;
+    font-size: 14px;
+  }
+  
+  .form-options {
+    display: flex !important;
+    flex-direction: row !important;
+    justify-content: space-between !important;
+    align-items: center !important;
+    gap: 6px !important;
+    width: 100% !important;
+    min-height: 20px !important;
+    flex-wrap: nowrap !important;
+    margin-top: 8px !important;
+    margin-bottom: 16px !important;
+  }
+  
+  .checkbox-wrapper {
+    flex: 0 0 auto !important;
+    font-size: 12px !important;
+    white-space: nowrap !important;
+    overflow: hidden !important;
+    text-overflow: ellipsis !important;
+    max-width: 45% !important;
+  }
+  
+  .forgot-password {
+    flex: 0 0 auto !important;
+    font-size: 12px !important;
+    margin-left: auto !important;
+    white-space: nowrap !important;
+    overflow: hidden !important;
+    text-overflow: ellipsis !important;
+    max-width: 45% !important;
+  }
+  
+/* 移动端优化 */
+  .background-pattern {
+    display: none;
+  }
+  
+  /* 禁用可能影响位置的悬停效果 */
+  .login-card:hover {
+    transform: none !important;
+  }
+}
+
+/* 超小屏幕优化(320px及以下) */
+@media (max-width: 320px) {
+  .login-content {
+    padding: 16px;
+  }
+  
+  .login-card {
+    padding: 24px;
+  }
+  
+  .form-options {
+    display: flex !important;
+    flex-direction: row !important;
+    justify-content: space-between !important;
+    align-items: center !important;
+    gap: 4px !important;
+    width: 100% !important;
+    flex-wrap: nowrap !important;
+    min-height: 18px !important;
+    margin-top: 6px !important;
+    margin-bottom: 14px !important;
+  }
+  
+  .checkbox-wrapper {
+    flex: 0 0 auto !important;
+    font-size: 11px !important;
+    white-space: nowrap !important;
+    overflow: hidden !important;
+    text-overflow: ellipsis !important;
+    max-width: 42% !important;
+    line-height: 1.2 !important;
+  }
+  
+  .forgot-password {
+    flex: 0 0 auto !important;
+    font-size: 11px !important;
+    margin-left: auto !important;
+    white-space: nowrap !important;
+    overflow: hidden !important;
+    text-overflow: ellipsis !important;
+    max-width: 42% !important;
+    line-height: 1.2 !important;
+  }
+  
+  /* Ant Design Checkbox 的特殊处理 */
+  .form-options .ant-checkbox-wrapper {
+    flex: 0 0 auto !important;
+    font-size: 11px !important;
+    white-space: nowrap !important;
+    overflow: hidden !important;
+    text-overflow: ellipsis !important;
+    max-width: 42% !important;
+    line-height: 1.2 !important;
+  }
+}
+
+/* 极小屏幕优化(280px及以下) */
+@media (max-width: 280px) {
+  .form-options {
+    display: flex !important;
+    flex-direction: row !important;
+    justify-content: space-between !important;
+    align-items: center !important;
+    gap: 2px !important;
+    width: 100% !important;
+    flex-wrap: nowrap !important;
+    min-height: 16px !important;
+    margin-top: 6px !important;
+    margin-bottom: 14px !important;
+  }
+  
+  .form-options .ant-checkbox-wrapper {
+    flex: 0 0 auto !important;
+    font-size: 10px !important;
+    white-space: nowrap !important;
+    overflow: hidden !important;
+    text-overflow: ellipsis !important;
+    max-width: 40% !important;
+    line-height: 1.1 !important;
+  }
+  
+  .form-options .forgot-password {
+    flex: 0 0 auto !important;
+    font-size: 10px !important;
+    margin-left: auto !important;
+    white-space: nowrap !important;
+    overflow: hidden !important;
+    text-overflow: ellipsis !important;
+    max-width: 40% !important;
+    line-height: 1.1 !important;
+  }
+  
+  .form-options .ant-checkbox-wrapper .ant-checkbox {
+    margin-right: 2px !important;
+    transform: scale(0.8) !important; /* 进一步缩小checkbox */
+  }
+}
+
+/* 高对比度模式支持 */
+@media (prefers-contrast: high) {
+  .login-card {
+    background: white;
+    border: 2px solid #000;
+  }
+  
+  .form-input {
+    border-color: #000;
+  }
+  
+  .form-input:focus {
+    border-color: #0066cc;
+    box-shadow: 0 0 0 2px #0066cc;
+  }
+}
+
+/* 减少动画模式 */
+@media (prefers-reduced-motion: reduce) {
+  .background-pattern {
+    animation: none;
+  }
+  
+  .login-card,
+  .form-input,
+  .login-button,
+  .social-button {
+    transition: none;
+  }
+}
+
+/* 深色模式支持 */
+@media (prefers-color-scheme: dark) {
+  .login-background {
+    background: linear-gradient(135deg, #1a202c 0%, #2d3748 100%);
+  }
+  
+  .login-card {
+    background: rgba(26, 32, 44, 0.95);
+    border-color: rgba(255, 255, 255, 0.1);
+  }
+  
+  .login-title {
+    color: #f7fafc;
+  }
+  
+  .login-subtitle {
+    color: #a0aec0;
+  }
+  
+  .form-label {
+    color: #e2e8f0;
+  }
+  
+  .form-input {
+    background: #2d3748;
+    border-color: #4a5568;
+    color: #f7fafc;
+  }
+  
+  .form-input:focus {
+    border-color: #ff2442;
+  }
+  
+  .social-button {
+    background: #2d3748;
+    border-color: #4a5568;
+    color: #f7fafc;
+  }
+  
+  .signup-link {
+    border-color: #4a5568;
+  }
+  
+  .signup-link p {
+    color: #a0aec0;
+  }
+  
+  /* 深色模式下的错误提示样式 */
+  .error-message {
+    background: rgba(26, 32, 44, 0.95);
+    color: #ff6b6b;
+  }
+  
+  /* 深色模式下的错误弹窗样式 */
+  .error-modal .ant-modal-header {
+    background: #2d3748;
+    border-color: #4a5568;
+  }
+  
+  .error-modal .ant-modal-title {
+    color: #f7fafc;
+  }
+  
+  .error-modal .ant-modal-body {
+    background: #2d3748;
+    color: #f7fafc;
+  }
+  
+  .error-modal .ant-modal-footer {
+    background: #2d3748;
+  }
+  
+  .error-modal .ant-modal-content {
+    background: #2d3748;
+  }
+}
+
+/* 错误提示样式 - 使用绝对定位避免影响布局 */
+.error-message {
+  position: absolute;
+  top: 95%;
+  left: 4px;
+  right: 4px;
+  font-size: 12px;
+  color: #ff4d4f;
+  margin-top: 4px;
+  display: flex;
+  align-items: center;
+  min-height: 16px;
+  animation: fadeInDown 0.3s ease-out;
+  font-weight: 400;
+  line-height: 1.2;
+  background: rgba(255, 255, 255, 0.95);
+  backdrop-filter: blur(4px);
+  padding: 2px 4px;
+  border-radius: 4px;
+  z-index: 10;
+  pointer-events: none; /* 避免干扰用户交互 */
+}
+
+@keyframes fadeInDown {
+  from {
+    opacity: 0;
+    transform: translateY(-8px);
+  }
+  to {
+    opacity: 1;
+    transform: translateY(0);
+  }
+}
+
+/* 输入框错误状态样式 */
+.form-input.input-error,
+.form-input.input-error.ant-input,
+.form-input.input-error.ant-input-affix-wrapper {
+  border-color: #ff4d4f !important;
+  box-shadow: 0 0 0 2px rgba(255, 77, 79, 0.1) !important;
+  transition: all 0.3s ease !important;
+}
+
+.form-input.input-error:focus,
+.form-input.input-error.ant-input:focus,
+.form-input.input-error.ant-input-affix-wrapper:focus,
+.form-input.input-error.ant-input-affix-wrapper-focused {
+  border-color: #ff4d4f !important;
+  box-shadow: 0 0 0 2px rgba(255, 77, 79, 0.2) !important;
+}
+
+/* 错误状态下的图标颜色 */
+.form-input.input-error .anticon {
+  color: #ff4d4f !important;
+}
+
+/* 确保表单组间距一致 */
+.form-group {
+  margin-bottom: 0px;
+}
+
+.form-group:last-of-type {
+  margin-bottom: 0px;
+}
+
+/* 错误弹窗样式 */
+.error-modal .ant-modal-header {
+  background: #fff;
+  border-bottom: 1px solid #f0f0f0;
+  padding: 16px 24px;
+}
+
+.error-modal .ant-modal-title {
+  color: #333;
+  font-weight: 600;
+  font-size: 16px;
+}
+
+.error-modal .ant-modal-body {
+  padding: 16px 24px 24px;
+}
+
+.error-modal .ant-modal-footer {
+  padding: 12px 24px 24px;
+  border-top: none;
+  text-align: center;
+}
+
+.error-modal .ant-btn-primary {
+  background: #ff2442;
+  border-color: #ff2442;
+  font-weight: 500;
+  height: 40px;
+  padding: 0 24px;
+  border-radius: 6px;
+  transition: all 0.2s ease;
+}
+
+.error-modal .ant-btn-primary:hover {
+  background: #d91e3a;
+  border-color: #d91e3a;
+  transform: translateY(-1px);
+  box-shadow: 0 4px 12px rgba(255, 36, 66, 0.3);
+}
+
+.error-modal .ant-modal-content {
+  border-radius: 12px;
+  overflow: hidden;
+  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
+}
+
+/* 错误弹窗遮罩层 */
+.error-modal .ant-modal-mask {
+  background: rgba(0, 0, 0, 0.6);
+  backdrop-filter: blur(4px);
+}
+
+/* 错误弹窗动画 */
+.error-modal .ant-modal {
+  animation: errorModalSlideIn 0.3s ease-out;
+}
+
+@keyframes errorModalSlideIn {
+  from {
+    opacity: 0;
+    transform: translateY(-20px) scale(0.95);
+  }
+  to {
+    opacity: 1;
+    transform: translateY(0) scale(1);
+  }
+}
diff --git a/rhj/frontend/src/pages/LoginPage/LoginPage.js b/rhj/frontend/src/pages/LoginPage/LoginPage.js
new file mode 100644
index 0000000..c315b7d
--- /dev/null
+++ b/rhj/frontend/src/pages/LoginPage/LoginPage.js
@@ -0,0 +1,380 @@
+import React, { useState, useEffect } from 'react';
+import { Link } from 'react-router-dom';
+import { Input, Checkbox, Modal, Alert } from 'antd';
+import { MailOutlined, LockOutlined, ExclamationCircleOutlined, CheckCircleOutlined } from '@ant-design/icons';
+import { 
+  getRememberedLoginInfo, 
+  saveRememberedLoginInfo, 
+  saveAuthInfo, 
+  isLoggedIn 
+} from '../../utils/auth';
+import { hashPassword } from '../../utils/crypto';
+import './LoginPage.css';
+
+const baseURL = 'http://10.126.59.25:8082';
+
+const LoginPage = () => {
+  const [formData, setFormData] = useState({
+    email: '',
+    password: ''
+  });
+
+  const [rememberMe, setRememberMe] = useState(false);
+  const [isLoading, setIsLoading] = useState(false);
+  const [errors, setErrors] = useState({
+    email: '',
+    password: ''
+  });
+  const [errorModal, setErrorModal] = useState({
+    visible: false,
+    title: '',
+    content: ''
+  });
+  const [successAlert, setSuccessAlert] = useState({
+    visible: false,
+    message: ''
+  });
+
+  // 显示错误弹窗
+  const showErrorModal = (title, content) => {
+    setErrorModal({
+      visible: true,
+      title: title,
+      content: content
+    });
+  };
+
+  // 关闭错误弹窗
+  const closeErrorModal = () => {
+    setErrorModal({
+      visible: false,
+      title: '',
+      content: ''
+    });
+  };
+
+  // 显示成功提示
+  const showSuccessAlert = (message) => {
+    setSuccessAlert({
+      visible: true,
+      message: message
+    });
+    
+    // 3秒后自动隐藏
+    setTimeout(() => {
+      setSuccessAlert({
+        visible: false,
+        message: ''
+      });
+    }, 3000);
+  };
+
+  // 页面加载时检查是否有记住的登录信息
+  useEffect(() => {
+    // 检查是否已经登录
+    if (isLoggedIn()) {
+      // 如果已经有token,可以选择直接跳转到主页面
+      // window.location.href = '/test-dashboard';
+      console.log('用户已登录');
+    }
+
+    // 获取记住的登录信息
+    const rememberedInfo = getRememberedLoginInfo();
+    if (rememberedInfo.rememberMe && rememberedInfo.email) {
+      setFormData({
+        email: rememberedInfo.email,
+        password: rememberedInfo.password
+      });
+      setRememberMe(true);
+    }
+  }, []);
+
+  const handleEmailChange = (e) => {
+    const value = e.target.value;
+    setFormData(prev => ({
+      ...prev,
+      email: value
+    }));
+    
+    // 清除邮箱错误提示
+    if (errors.email) {
+      setErrors(prev => ({
+        ...prev,
+        email: ''
+      }));
+    }
+  };
+
+  const handlePasswordChange = (e) => {
+    const value = e.target.value;
+    setFormData(prev => ({
+      ...prev,
+      password: value
+    }));
+    
+    // 清除密码错误提示
+    if (errors.password) {
+      setErrors(prev => ({
+        ...prev,
+        password: ''
+      }));
+    }
+  };
+
+  const handleRememberMeChange = (e) => {
+    const checked = e.target.checked;
+    setRememberMe(checked);
+    
+    // 如果取消记住我,清除已保存的登录信息
+    if (!checked) {
+      saveRememberedLoginInfo('', '', false);
+    }
+  };
+
+  const validateForm = () => {
+    const newErrors = {
+      email: '',
+      password: ''
+    };
+    
+    let hasError = false;
+    
+    // 验证邮箱
+    if (!formData.email || typeof formData.email !== 'string' || !formData.email.trim()) {
+      newErrors.email = '请输入邮箱地址';
+      hasError = true;
+    } else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(formData.email)) {
+      newErrors.email = '请输入有效的邮箱地址';
+      hasError = true;
+    }
+    
+    // 验证密码
+    if (!formData.password || typeof formData.password !== 'string' || !formData.password.trim()) {
+      newErrors.password = '请输入密码';
+      hasError = true;
+    } else if (formData.password.length < 6) {
+      newErrors.password = '密码长度至少6位';
+      hasError = true;
+    }
+    
+    setErrors(newErrors);
+    return !hasError;
+  };
+
+  const handleSubmit = async (e) => {
+    e.preventDefault();
+    
+    // 验证表单
+    if (!validateForm()) {
+      return;
+    }
+    
+    setIsLoading(true);
+    
+    try {
+      // 发送登录请求到后端
+      const response = await fetch(baseURL + '/login', {
+        method: 'POST',
+        headers: {
+          'Content-Type': 'application/json',
+        },
+        body: JSON.stringify({
+          email: formData.email, // 后端支持邮箱登录
+          password: hashPassword(formData.password) // 前端加密密码
+        })
+      });
+      
+      const result = await response.json();
+      
+      if (result.success) {
+        // 显示成功提示
+        showSuccessAlert('登录成功!正在跳转...');
+        
+        // 保存认证信息
+        saveAuthInfo(result.token, result.user, rememberMe);
+        
+        // 保存或清除记住的登录信息
+        saveRememberedLoginInfo(formData.email, formData.password, rememberMe);
+        
+        // 延迟跳转,让用户看到成功提示
+        setTimeout(() => {
+          window.location.href = '/test-dashboard';
+        }, 1500);
+      } else {
+        // 登录失败,显示错误信息
+        let errorTitle = '登录失败';
+        let errorContent = result.message || '登录失败,请检查您的邮箱和密码';
+        
+        // 根据错误类型提供更详细的信息
+        if (result.message) {
+          if (result.message.includes('邮箱') || result.message.includes('email')) {
+            errorTitle = '邮箱验证失败';
+            errorContent = '您输入的邮箱地址不存在或格式不正确,请检查后重试。';
+          } else if (result.message.includes('密码') || result.message.includes('password')) {
+            errorTitle = '密码验证失败';
+            errorContent = '您输入的密码不正确,请检查后重试。如果忘记密码,请点击"忘记密码"进行重置。';
+          } else if (result.message.includes('用户不存在')) {
+            errorTitle = '用户不存在';
+            errorContent = '该邮箱尚未注册,请先注册账户或检查邮箱地址是否正确。';
+          } else if (result.message.includes('账户被锁定') || result.message.includes('locked')) {
+            errorTitle = '账户被锁定';
+            errorContent = '您的账户因安全原因被暂时锁定,请联系客服或稍后重试。';
+          }
+        }
+        
+        showErrorModal(errorTitle, errorContent);
+      }
+    } catch (error) {
+      console.error('登录请求失败:', error);
+      
+      // 根据错误类型显示不同的错误信息
+      if (error.name === 'TypeError' && error.message.includes('fetch')) {
+        showErrorModal('网络连接失败', '无法连接到服务器,请检查您的网络连接后重试。如果问题持续存在,请联系客服。');
+      } else if (error.name === 'AbortError') {
+        showErrorModal('请求超时', '请求超时,请检查网络连接后重试。');
+      } else {
+        showErrorModal('登录失败', '网络连接失败,请检查网络或稍后重试。如果问题持续存在,请联系客服。');
+      }
+    } finally {
+      setIsLoading(false);
+    }
+  };
+
+  return (
+    <div className="login-container">
+      <div className="login-background"></div>
+      
+      {isLoading && (
+        <div className="loading-overlay">
+          <div className="loading-content">
+            <div className="loading-spinner-large"></div>
+            <p className="loading-text">正在登录...</p>
+          </div>
+        </div>
+      )}
+      
+      <div className="login-content">
+        <div className="login-card">
+          {/* 成功提示 */}
+          {successAlert.visible && (
+            <div style={{ marginBottom: '16px' }}>
+              <Alert
+                message={successAlert.message}
+                type="success"
+                icon={<CheckCircleOutlined />}
+                showIcon
+                closable
+                onClose={() => setSuccessAlert({ visible: false, message: '' })}
+                style={{
+                  borderRadius: '8px',
+                  border: '1px solid #b7eb8f',
+                  backgroundColor: '#f6ffed'
+                }}
+              />
+            </div>
+          )}
+          
+          <div className="login-header">
+            <h1 className="login-title">欢迎来到小红书</h1>
+            <p className="login-subtitle">标记我的生活</p>
+          </div>
+
+          <form className="login-form" onSubmit={handleSubmit}>
+            <div className="form-group">
+              <Input
+                type="email"
+                id="email"
+                name="email"
+                className={`form-input ${errors.email ? 'input-error' : ''}`}
+                placeholder="请输入您的邮箱"
+                value={formData.email}
+                onChange={handleEmailChange}
+                prefix={<MailOutlined />}
+                size="large"
+                title=""
+                status={errors.email ? 'error' : ''}
+              />
+              {errors.email && (
+                <div className="error-message">
+                  {errors.email}
+                </div>
+              )}
+            </div>
+
+            <div className="form-group">
+              <Input.Password
+                id="password"
+                name="password"
+                className={`form-input ${errors.password ? 'input-error' : ''}`}
+                placeholder="请输入您的密码"
+                value={formData.password}
+                onChange={handlePasswordChange}
+                prefix={<LockOutlined />}
+                size="large"
+                title=""
+                status={errors.password ? 'error' : ''}
+              />
+              {errors.password && (
+                <div className="error-message">
+                  {errors.password}
+                </div>
+              )}
+            </div>
+
+            <div className="form-options">
+              <Checkbox 
+                checked={rememberMe}
+                onChange={handleRememberMeChange}
+              >
+                记住我
+              </Checkbox>
+              <Link to="/forgot-password" className="forgot-password">忘记密码?</Link>
+            </div>
+
+            <button
+              type="submit"
+              className={`login-button ${isLoading ? 'loading' : ''}`}
+              disabled={isLoading}
+            >
+              {isLoading ? (
+                <>
+                  <div className="loading-spinner"></div>
+                  登录中...
+                </>
+              ) : (
+                '登录'
+              )}
+            </button>
+          </form>
+
+          <div className="signup-link">
+            <p>还没有账户? <Link to="/register">立即注册</Link></p>
+          </div>
+        </div>
+      </div>
+
+      {/* 错误弹窗 */}
+      <Modal
+        title={
+          <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
+            <ExclamationCircleOutlined style={{ color: '#ff4d4f', fontSize: '18px' }} />
+            {errorModal.title}
+          </div>
+        }
+        open={errorModal.visible}
+        onOk={closeErrorModal}
+        onCancel={closeErrorModal}
+        okText="我知道了"
+        cancelButtonProps={{ style: { display: 'none' } }}
+        centered
+        className="error-modal"
+      >
+        <div style={{ padding: '16px 0', fontSize: '14px', lineHeight: '1.6' }}>
+          {errorModal.content}
+        </div>
+      </Modal>
+    </div>
+  );
+};
+
+export default LoginPage;
diff --git a/rhj/frontend/src/pages/RegisterPage/RegisterPage.css b/rhj/frontend/src/pages/RegisterPage/RegisterPage.css
new file mode 100644
index 0000000..fc03361
--- /dev/null
+++ b/rhj/frontend/src/pages/RegisterPage/RegisterPage.css
@@ -0,0 +1,1027 @@
+/* 注册页面容器 */
+.register-container {
+  min-height: 100vh;
+  min-height: 100dvh; /* 动态视口高度,避免移动端地址栏影响 */
+  height: 100vh;
+  height: 100dvh;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  position: relative;
+  overflow: hidden;
+  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
+    'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
+    sans-serif;
+  /* 确保容器稳定定位 */
+  box-sizing: border-box;
+  margin: 0;
+  padding: 0;
+  /* 重置文本对齐 */
+  text-align: initial;
+}
+
+/* 小红书风格背景 */
+.register-background {
+  position: absolute;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  background: #f8f8f8;
+  z-index: -1;
+}
+
+/* 注册内容区域 */
+.register-content {
+  width: 100%;
+  max-width: 500px; /* 增加桌面端最大宽度 */
+  padding: 0;
+  z-index: 1;
+  /* 确保内容稳定定位 */
+  box-sizing: border-box;
+  position: relative;
+  display: flex;
+  justify-content: center;
+}
+
+/* 小红书风格注册卡片 */
+.register-card {
+  background: #fff;
+  border-radius: 8px;
+  padding: 40px; /* 增加桌面端内边距 */
+  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
+  border: 1px solid #e1e1e1;
+  width: 100%;
+  max-width: 450px; /* 增加桌面端卡片最大宽度 */
+  transition: none;
+}
+
+/* 注册头部 */
+.register-header {
+  text-align: center;
+  margin-bottom: 40px;
+}
+
+/* Logo样式 */
+.logo-section {
+  margin-bottom: 24px;
+}
+
+.logo-icon {
+  width: 60px;
+  height: 60px;
+  background: #ff2442;
+  border-radius: 12px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  font-size: 28px;
+  margin: 0 auto 16px;
+  box-shadow: 0 4px 12px rgba(255, 36, 66, 0.2);
+}
+
+.register-title {
+  font-size: 24px;
+  font-weight: 600;
+  color: #333;
+  margin: 0 0 12px 0;
+  text-align: center;
+}
+
+.register-title::after {
+  display: none;
+}
+
+.register-subtitle {
+  font-size: 14px;
+  color: #999;
+  margin: 0 0 32px 0;
+  font-weight: 400;
+  text-align: center;
+}
+
+/* 表单样式 */
+.register-form {
+  display: flex;
+  flex-direction: column;
+  gap: 20px;
+  width: 100%;
+}
+
+.form-group {
+  display: flex;
+  flex-direction: column;
+  gap: 6px;
+  width: 100%;
+  box-sizing: border-box;
+  margin-bottom: 2px;
+  position: relative; /* 为绝对定位的错误提示提供参考点 */
+}
+
+.form-group .input-wrapper {
+  width: 100%;
+  box-sizing: border-box;
+}
+
+.form-label {
+  font-size: 14px;
+  font-weight: 500;
+  color: #333;
+  margin-bottom: 8px;
+}
+
+.input-wrapper {
+  position: relative;
+  display: flex;
+  align-items: center;
+  width: 100%;
+  box-sizing: border-box;
+}
+
+.form-input {
+  width: 100% !important;
+  height: 44px;
+  padding: 12px 16px 12px 48px;
+  border: 1px solid #e1e1e1;
+  border-radius: 6px;
+  font-size: 14px;
+  transition: border-color 0.2s ease;
+  background: #fff;
+  color: #333;
+  box-sizing: border-box !important;
+  flex: 1;
+  min-width: 0;
+}
+
+/* 针对 Antd Input 组件的特定样式 */
+.form-input.ant-input,
+.form-input.ant-input-affix-wrapper {
+  width: 100% !important;
+  height: 44px !important;
+  border: 1px solid #e1e1e1 !important;
+  border-radius: 6px !important;
+  padding: 12px 48px 12px 48px !important;
+  font-size: 14px !important;
+  background: #fff !important;
+  color: #333 !important;
+  box-sizing: border-box !important;
+  flex: 1 !important;
+  min-width: 0 !important;
+  display: flex !important;
+  align-items: center !important;
+}
+
+.form-input.ant-input-affix-wrapper .ant-input {
+  width: 100% !important;
+  height: 100% !important;
+  padding: 0 !important;
+  border: none !important;
+  background: transparent !important;
+  flex: 1 !important;
+  min-width: 0 !important;
+  box-sizing: border-box !important;
+}
+
+.form-input:focus {
+  outline: none;
+  border-color: #ff2442;
+  box-shadow: none;
+  transform: none;
+}
+
+/* Antd Input focus 样式 */
+.form-input.ant-input:focus,
+.form-input.ant-input-affix-wrapper:focus,
+.form-input.ant-input-affix-wrapper-focused {
+  outline: none !important;
+  border-color: #ff2442 !important;
+  box-shadow: none !important;
+  transform: none !important;
+}
+
+.form-input::placeholder {
+  color: #9ca3af;
+}
+
+.input-icon {
+  position: absolute;
+  left: 16px;
+  top: 50%;
+  transform: translateY(-50%);
+  color: #9ca3af;
+  pointer-events: none;
+  transition: color 0.3s ease;
+  z-index: 2;
+}
+
+.form-input:focus + .input-icon {
+  color: #ff2442;
+}
+
+.password-toggle {
+  position: absolute;
+  right: 12px;
+  top: 50%;
+  transform: translateY(-50%);
+  background: none;
+  border: none;
+  color: #9ca3af;
+  cursor: pointer;
+  padding: 4px;
+  border-radius: 4px;
+  transition: all 0.3s ease;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  z-index: 2;
+  width: 24px;
+  height: 24px;
+}
+
+.password-toggle:hover {
+  color: #ff2442;
+  background-color: rgba(255, 36, 66, 0.1);
+}
+
+/* 邮箱验证码输入框容器 */
+.email-code-wrapper {
+  display: flex;
+  gap: 8px;
+  width: 100%;
+  box-sizing: border-box;
+  align-items: flex-start;
+}
+
+.email-code-input {
+  flex: 1;
+  min-width: 0;
+}
+
+.send-code-button {
+  height: 44px !important;
+  padding: 0 16px !important;
+  background: #ff2442 !important;
+  border-color: #ff2442 !important;
+  border-radius: 6px !important;
+  font-size: 14px !important;
+  font-weight: 500 !important;
+  white-space: nowrap !important;
+  flex-shrink: 0 !important;
+  min-width: 100px !important;
+  display: flex !important;
+  align-items: center !important;
+  justify-content: center !important;
+  transition: all 0.2s ease !important;
+  box-sizing: border-box !important;
+}
+
+.send-code-button:hover:not(:disabled) {
+  background: #d91e3a !important;
+  border-color: #d91e3a !important;
+  transform: none !important;
+  box-shadow: none !important;
+}
+
+.send-code-button:disabled {
+  background: #f5f5f5 !important;
+  border-color: #d9d9d9 !important;
+  color: #bfbfbf !important;
+  cursor: not-allowed !important;
+}
+
+.send-code-button.ant-btn-loading {
+  background: #ff2442 !important;
+  border-color: #ff2442 !important;
+  color: white !important;
+}
+
+/* 小红书风格注册按钮 */
+.register-button {
+  width: 100%;
+  height: 48px; /* 固定高度,防止布局变化 */
+  padding: 12px;
+  background: #ff2442;
+  color: white;
+  border: none;
+  border-radius: 6px;
+  font-size: 14px;
+  font-weight: 500;
+  cursor: pointer;
+  transition: background-color 0.2s ease;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  gap: 8px;
+  margin-top: 8px;
+  position: relative; /* 为绝对定位的加载状态做准备 */
+  box-sizing: border-box; /* 确保padding包含在总尺寸内 */
+  min-width: 0; /* 防止flex子元素造成宽度变化 */
+}
+
+.register-button:hover:not(:disabled) {
+  background: #d91e3a;
+  transform: none;
+  box-shadow: none;
+}
+
+.register-button:active:not(:disabled) {
+  transform: none;
+}
+
+.register-button:disabled {
+  background: #ccc;
+  cursor: not-allowed;
+  opacity: 0.8;
+}
+
+.register-button.loading {
+  background: #ff7b8a;
+  cursor: not-allowed;
+}
+
+.loading-spinner {
+  width: 16px;
+  height: 16px;
+  border: 2px solid rgba(255, 255, 255, 0.3);
+  border-radius: 50%;
+  border-top-color: #fff;
+  animation: spin 1s ease-in-out infinite;
+}
+
+@keyframes spin {
+  to { transform: rotate(360deg); }
+}
+
+/* 加载遮罩层 */
+.loading-overlay {
+  position: fixed;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  background: rgba(0, 0, 0, 0.5);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  z-index: 1000;
+  backdrop-filter: blur(4px);
+}
+
+.loading-content {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  gap: 16px;
+  background: white;
+  padding: 32px;
+  border-radius: 12px;
+  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
+}
+
+.loading-spinner-large {
+  width: 40px;
+  height: 40px;
+  border: 4px solid rgba(255, 36, 66, 0.2);
+  border-radius: 50%;
+  border-top-color: #ff2442;
+  animation: spin 1s ease-in-out infinite;
+}
+
+.loading-text {
+  margin: 0;
+  color: #333;
+  font-size: 16px;
+  font-weight: 500;
+}
+
+/* 分隔线 */
+.register-divider {
+  position: relative;
+  text-align: center;
+  margin: 32px 0;
+  color: #9ca3af;
+  font-size: 14px;
+}
+
+.register-divider::before {
+  content: '';
+  position: absolute;
+  top: 50%;
+  left: 0;
+  right: 0;
+  height: 1px;
+  background: linear-gradient(to right, transparent, #e5e7eb, transparent);
+}
+
+.register-divider span {
+  background: rgba(255, 255, 255, 0.95);
+  padding: 0 16px;
+  position: relative;
+  z-index: 1;
+}
+
+/* 社交登录 */
+.social-login {
+  display: flex;
+  flex-direction: column;
+  gap: 12px;
+}
+
+.social-button {
+  width: 100%;
+  padding: 12px 16px;
+  border: 1px solid #e1e1e1;
+  border-radius: 6px;
+  background: white;
+  color: #333;
+  font-size: 14px;
+  font-weight: 400;
+  cursor: pointer;
+  transition: border-color 0.2s ease;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  gap: 8px;
+}
+
+.social-button:hover {
+  border-color: #ccc;
+}
+
+.social-button.google:hover {
+  border-color: #4285f4;
+  box-shadow: 0 4px 12px rgba(66, 133, 244, 0.2);
+}
+
+.social-button.github:hover {
+  border-color: #333;
+  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
+}
+
+.social-button.xiaohongshu:hover {
+  border-color: #ff2442;
+  box-shadow: 0 4px 12px rgba(255, 36, 66, 0.2);
+}
+
+/* 登录链接 */
+.login-link {
+  text-align: center;
+  margin-top: 20px;
+  padding-top: 20px;
+  border-top: 1px solid #e5e7eb;
+}
+
+.login-link p {
+  margin: 0;
+  font-size: 14px;
+  color: #64748b;
+}
+
+.login-link a {
+  color: #ff2442;
+  text-decoration: none;
+  font-weight: 500;
+  transition: color 0.2s ease;
+}
+
+.login-link a:hover {
+  color: #d91e3a;
+  text-decoration: underline;
+}
+
+/* 有左侧图标时的内边距调整 */
+.input-wrapper.has-icon .form-input {
+  padding-left: 48px !important;
+}
+
+.input-wrapper.has-icon .form-input.ant-input,
+.input-wrapper.has-icon .form-input.ant-input-affix-wrapper {
+  padding-left: 48px !important;
+}
+
+/* 有右侧切换按钮时的内边距调整 */
+.input-wrapper.has-toggle .form-input {
+  padding-right: 48px !important;
+}
+
+.input-wrapper.has-toggle .form-input.ant-input,
+.input-wrapper.has-toggle .form-input.ant-input-affix-wrapper {
+  padding-right: 48px !important;
+}
+
+/* 没有图标时的内边距调整 */
+.input-wrapper:not(.has-icon) .form-input {
+  padding-left: 16px !important;
+}
+
+.input-wrapper:not(.has-icon) .form-input.ant-input,
+.input-wrapper:not(.has-icon) .form-input.ant-input-affix-wrapper {
+  padding-left: 16px !important;
+}
+
+/* 没有切换按钮时的内边距调整 */
+.input-wrapper:not(.has-toggle) .form-input {
+  padding-right: 16px !important;
+}
+
+.input-wrapper:not(.has-toggle) .form-input.ant-input,
+.input-wrapper:not(.has-toggle) .form-input.ant-input-affix-wrapper {
+  padding-right: 16px !important;
+}
+
+/* 确保输入框内容完全填充 */
+.form-input.ant-input-affix-wrapper .ant-input-suffix {
+  position: absolute !important;
+  right: 12px !important;
+  top: 50% !important;
+  transform: translateY(-50%) !important;
+  margin: 0 !important;
+  padding: 0 !important;
+}
+
+.form-input.ant-input-affix-wrapper .ant-input-prefix {
+  position: absolute !important;
+  left: 16px !important;
+  top: 50% !important;
+  transform: translateY(-50%) !important;
+  margin: 0 !important;
+  padding: 0 !important;
+}
+
+/* 确保所有输入框完全填充其容器 */
+.form-group {
+  display: flex;
+  flex-direction: column;
+  gap: 8px;
+  width: 100%;
+  box-sizing: border-box;
+}
+
+.form-group .input-wrapper {
+  width: 100%;
+  box-sizing: border-box;
+}
+
+/* 防止输入框溢出容器 */
+.form-input,
+.form-input.ant-input,
+.form-input.ant-input-affix-wrapper {
+  max-width: 100% !important;
+  overflow: hidden !important;
+}
+
+/* 确保内部输入元素不会超出边界 */
+.form-input.ant-input-affix-wrapper .ant-input {
+  max-width: 100% !important;
+  overflow: hidden !important;
+  text-overflow: ellipsis !important;
+}
+
+/* 精细间距控制 */
+.register-header + .register-form {
+  margin-top: -4px;
+}
+
+.register-form .form-group:not(:last-child) {
+  margin-bottom: 2px;
+}
+
+.register-form .form-group:last-of-type {
+  margin-bottom: 6px;
+}
+
+.register-button + .login-link {
+  margin-top: 14px;
+}
+
+/* 响应式设计 */
+@media (max-width: 768px) {
+  /* 重置body和html确保一致性 */
+  html, body {
+    height: 100%;
+    height: 100dvh;
+    margin: 0;
+    padding: 0;
+    overflow-x: hidden;
+    box-sizing: border-box;
+  }
+  
+  .register-container {
+    padding: 16px;
+    align-items: center;
+    justify-content: center;
+    min-height: 100vh;
+    min-height: 100dvh; /* 动态视口高度 */
+    /* 强制重置可能影响定位的样式 */
+    margin: 0;
+    box-sizing: border-box;
+    /* 防止内容溢出影响布局 */
+    overflow-x: hidden;
+    overflow-y: auto;
+    /* 确保flexbox在所有移动设备上表现一致 */
+    -webkit-box-align: center;
+    -webkit-box-pack: center;
+    display: flex !important;
+    position: relative;
+  }
+  
+  .register-content {
+    max-width: 100%;
+    padding: 20px;
+    /* 确保内容区域稳定 */
+    margin: 0 auto;
+    box-sizing: border-box;
+    /* 防止宽度计算问题 */
+    width: calc(100% - 40px);
+    max-width: 480px; /* 增加最大宽度 */
+    position: relative;
+    display: flex;
+    justify-content: center;
+  }
+  
+  .register-card {
+    padding: 32px 28px; /* 增加内边距 */
+    border-radius: 16px;
+    /* 确保卡片稳定定位 */
+    margin: 0;
+    box-sizing: border-box;
+    width: 100%;
+    max-width: 450px; /* 增加卡片最大宽度 */
+    /* 防止backdrop-filter导致的渲染差异 */
+    will-change: auto;
+    position: relative;
+    /* 防止触摸操作影响布局 */
+    -webkit-touch-callout: none;
+    -webkit-user-select: none;
+    -moz-user-select: none;
+    -ms-user-select: none;
+    user-select: none;
+    -webkit-tap-highlight-color: transparent;
+  }
+  
+  .register-title {
+    font-size: 24px;
+  }
+  
+  .form-input {
+    width: 100% !important;
+    height: 44px !important;
+    padding: 12px 48px 12px 48px;
+    font-size: 16px; /* 防止iOS Safari缩放 */
+    box-sizing: border-box !important;
+    flex: 1 !important;
+    min-width: 0 !important;
+  }
+  
+  .form-input.ant-input,
+  .form-input.ant-input-affix-wrapper {
+    width: 100% !important;
+    height: 44px !important;
+    padding: 12px 48px 12px 48px !important;
+    font-size: 16px !important;
+    box-sizing: border-box !important;
+    flex: 1 !important;
+    min-width: 0 !important;
+  }
+  
+  .form-input.ant-input-affix-wrapper .ant-input {
+    width: 100% !important;
+    height: 100% !important;
+    padding: 0 !important;
+    border: none !important;
+    background: transparent !important;
+    flex: 1 !important;
+    min-width: 0 !important;
+    box-sizing: border-box !important;
+  }
+  
+  .social-login {
+    gap: 10px;
+  }
+  
+  .social-button {
+    padding: 12px 16px;
+    font-size: 14px;
+  }
+}
+
+@media (max-width: 480px) {
+  .register-container {
+    padding: 16px;
+    align-items: center;
+    justify-content: center;
+    min-height: 100vh;
+    min-height: 100dvh; /* 动态视口高度 */
+    /* 强制重置样式 */
+    margin: 0;
+    box-sizing: border-box;
+    position: relative;
+    /* 确保垂直居中 */
+    display: flex !important;
+  }
+  
+  .register-content {
+    /* 更严格的尺寸控制 */
+    width: calc(100vw - 32px);
+    max-width: 420px; /* 增加最大宽度 */
+    padding: 16px;
+    margin: 0 auto;
+    box-sizing: border-box;
+    display: flex;
+    justify-content: center;
+  }
+  
+  .register-card {
+    padding: 28px 24px; /* 增加内边距 */
+    border-radius: 12px;
+    /* 确保卡片完全稳定 */
+    margin: 0;
+    box-sizing: border-box;
+    width: 100%;
+    position: relative;
+    /* 防止变换导致的位置偏移 */
+    transform: none !important;
+    /* 防止触摸操作影响布局 */
+    -webkit-touch-callout: none;
+    -webkit-user-select: none;
+    -khtml-user-select: none;
+    -moz-user-select: none;
+    -ms-user-select: none;
+    user-select: none;
+    /* 防止点击时的高亮效果影响布局 */
+    -webkit-tap-highlight-color: transparent;
+  }
+  
+  .register-title {
+    font-size: 22px;
+  }
+  
+  .form-input {
+    width: 100% !important;
+    height: 44px !important;
+    padding: 12px 48px 12px 48px;
+    font-size: 16px; /* 防止iOS Safari缩放 */
+    box-sizing: border-box !important;
+    flex: 1 !important;
+    min-width: 0 !important;
+  }
+  
+  .form-input.ant-input,
+  .form-input.ant-input-affix-wrapper {
+    width: 100% !important;
+    height: 44px !important;
+    padding: 12px 48px 12px 48px !important;
+    font-size: 16px !important;
+    box-sizing: border-box !important;
+    flex: 1 !important;
+    min-width: 0 !important;
+  }
+  
+  .form-input.ant-input-affix-wrapper .ant-input {
+    width: 100% !important;
+    height: 100% !important;
+    padding: 0 !important;
+    border: none !important;
+    background: transparent !important;
+    flex: 1 !important;
+    min-width: 0 !important;
+    box-sizing: border-box !important;
+  }
+  
+  .social-login {
+    gap: 10px;
+  }
+  
+  .social-button {
+    padding: 12px 16px;
+    font-size: 14px;
+  }
+  
+  /* 移动端优化 */
+  .background-pattern {
+    display: none;
+  }
+  
+  /* 禁用可能影响位置的悬停效果 */
+  .register-card:hover {
+    transform: none !important;
+  }
+}
+
+/* 高对比度模式支持 */
+@media (prefers-contrast: high) {
+  .register-card {
+    background: white;
+    border: 2px solid #000;
+  }
+  
+  .form-input {
+    border-color: #000;
+  }
+  
+  .form-input:focus {
+    border-color: #0066cc;
+    box-shadow: 0 0 0 2px #0066cc;
+  }
+}
+
+/* 减少动画模式 */
+@media (prefers-reduced-motion: reduce) {
+  .background-pattern {
+    animation: none;
+  }
+  
+  .register-card,
+  .form-input,
+  .register-button,
+  .social-button {
+    transition: none;
+  }
+}
+
+/* 深色模式支持 */
+@media (prefers-color-scheme: dark) {
+  .register-background {
+    background: linear-gradient(135deg, #1a202c 0%, #2d3748 100%);
+  }
+  
+  .register-card {
+    background: rgba(26, 32, 44, 0.95);
+    border-color: rgba(255, 255, 255, 0.1);
+  }
+  
+  .register-title {
+    color: #f7fafc;
+  }
+  
+  .register-subtitle {
+    color: #a0aec0;
+  }
+  
+  .form-label {
+    color: #e2e8f0;
+  }
+  
+  .form-input {
+    background: #2d3748;
+    border-color: #4a5568;
+    color: #f7fafc;
+  }
+  
+  .form-input:focus {
+    border-color: #ff2442;
+  }
+  
+  .social-button {
+    background: #2d3748;
+    border-color: #4a5568;
+    color: #f7fafc;
+  }
+  
+  .login-link {
+    border-color: #4a5568;
+  }
+  
+  .login-link p {
+    color: #a0aec0;
+  }
+  
+  /* 深色模式下的错误提示样式 */
+  .error-message {
+    background: rgba(26, 32, 44, 0.95);
+    color: #ff6b6b;
+  }
+}
+
+/* 错误提示样式 - 使用绝对定位避免影响布局 */
+.error-message {
+  position: absolute;
+  top: 95%;
+  left: 4px;
+  right: 4px;
+  font-size: 12px;
+  color: #ff4d4f;
+  margin-top: 4px;
+  display: flex;
+  align-items: center;
+  min-height: 16px;
+  animation: fadeInDown 0.3s ease-out;
+  font-weight: 400;
+  line-height: 1.2;
+  background: rgba(255, 255, 255, 0.95);
+  backdrop-filter: blur(4px);
+  padding: 2px 4px;
+  border-radius: 4px;
+  z-index: 10;
+  pointer-events: none; /* 避免干扰用户交互 */
+}
+
+@keyframes fadeInDown {
+  from {
+    opacity: 0;
+    transform: translateY(-8px);
+  }
+  to {
+    opacity: 1;
+    transform: translateY(0);
+  }
+}
+
+/* 输入框错误状态样式 */
+.form-input.input-error,
+.form-input.input-error.ant-input,
+.form-input.input-error.ant-input-affix-wrapper {
+  border-color: #ff4d4f !important;
+  box-shadow: 0 0 0 2px rgba(255, 77, 79, 0.1) !important;
+  transition: all 0.3s ease !important;
+}
+
+.form-input.input-error:focus,
+.form-input.input-error.ant-input:focus,
+.form-input.input-error.ant-input-affix-wrapper:focus,
+.form-input.input-error.ant-input-affix-wrapper-focused {
+  border-color: #ff4d4f !important;
+  box-shadow: 0 0 0 2px rgba(255, 77, 79, 0.2) !important;
+}
+
+/* 错误状态下的图标颜色 */
+.form-input.input-error .anticon {
+  color: #ff4d4f !important;
+}
+
+/* 确保表单组间距一致 */
+.form-group {
+  margin-bottom: 0px;
+}
+
+.form-group:last-of-type {
+  margin-bottom: 0px;
+}
+
+/* 错误弹窗样式 */
+.error-modal .ant-modal-header {
+  background: #fff;
+  border-bottom: 1px solid #f0f0f0;
+  padding: 16px 24px;
+}
+
+.error-modal .ant-modal-title {
+  color: #333;
+  font-weight: 600;
+  font-size: 16px;
+}
+
+.error-modal .ant-modal-body {
+  padding: 16px 24px 24px;
+}
+
+.error-modal .ant-modal-footer {
+  padding: 12px 24px 24px;
+  border-top: none;
+  text-align: center;
+}
+
+.error-modal .ant-btn-primary {
+  background: #ff2442;
+  border-color: #ff2442;
+  font-weight: 500;
+  height: 40px;
+  padding: 0 24px;
+  border-radius: 6px;
+  transition: all 0.2s ease;
+}
+
+.error-modal .ant-btn-primary:hover {
+  background: #d91e3a;
+  border-color: #d91e3a;
+  transform: translateY(-1px);
+  box-shadow: 0 4px 12px rgba(255, 36, 66, 0.3);
+}
+
+.error-modal .ant-modal-content {
+  border-radius: 12px;
+  overflow: hidden;
+  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
+}
+
+/* 错误弹窗遮罩层 */
+.error-modal .ant-modal-mask {
+  background: rgba(0, 0, 0, 0.6);
+  backdrop-filter: blur(4px);
+}
+
+/* 错误弹窗动画 */
+.error-modal .ant-modal {
+  animation: errorModalSlideIn 0.3s ease-out;
+}
+
+@keyframes errorModalSlideIn {
+  from {
+    opacity: 0;
+    transform: translateY(-20px) scale(0.95);
+  }
+  to {
+    opacity: 1;
+    transform: translateY(0) scale(1);
+  }
+}
diff --git a/rhj/frontend/src/pages/RegisterPage/RegisterPage.js b/rhj/frontend/src/pages/RegisterPage/RegisterPage.js
new file mode 100644
index 0000000..836e1cf
--- /dev/null
+++ b/rhj/frontend/src/pages/RegisterPage/RegisterPage.js
@@ -0,0 +1,625 @@
+import React, { useState } from 'react';
+import { Link, useNavigate } from 'react-router-dom';
+import { Input, Button, message, Modal, Alert } from 'antd';
+import { MailOutlined, LockOutlined, UserOutlined, SafetyOutlined, ExclamationCircleOutlined, CheckCircleOutlined } from '@ant-design/icons';
+import { hashPassword } from '../../utils/crypto';
+import './RegisterPage.css';
+
+const baseURL = 'http://10.126.59.25:8082';
+
+const RegisterPage = () => {
+  const [formData, setFormData] = useState({
+    username: '',
+    email: '',
+    emailCode: '',
+    password: '',
+    confirmPassword: ''
+  });
+
+  const [errors, setErrors] = useState({
+    username: '',
+    email: '',
+    emailCode: '',
+    password: '',
+    confirmPassword: ''
+  });
+
+  const [emailCodeSent, setEmailCodeSent] = useState(false);
+  const [countdown, setCountdown] = useState(0);
+  const [sendingCode, setSendingCode] = useState(false);
+  const [isLoading, setIsLoading] = useState(false);
+  const [errorModal, setErrorModal] = useState({
+    visible: false,
+    title: '',
+    content: ''
+  });
+  const [successAlert, setSuccessAlert] = useState({
+    visible: false,
+    message: ''
+  });
+  const [emailCodeSuccessAlert, setEmailCodeSuccessAlert] = useState({
+    visible: false,
+    message: ''
+  });
+
+  const navigate = useNavigate();
+
+  // 显示错误弹窗
+  const showErrorModal = (title, content) => {
+    setErrorModal({
+      visible: true,
+      title: title,
+      content: content
+    });
+  };
+
+  // 关闭错误弹窗
+  const closeErrorModal = () => {
+    setErrorModal({
+      visible: false,
+      title: '',
+      content: ''
+    });
+  };
+
+  // 显示成功提示
+  const showSuccessAlert = (message) => {
+    setSuccessAlert({
+      visible: true,
+      message: message
+    });
+    
+    // 3秒后自动隐藏
+    setTimeout(() => {
+      setSuccessAlert({
+        visible: false,
+        message: ''
+      });
+    }, 3000);
+  };
+
+  // 显示邮件验证码发送成功提示
+  const showEmailCodeSuccessAlert = (message) => {
+    setEmailCodeSuccessAlert({
+      visible: true,
+      message: message
+    });
+    
+    // 5秒后自动隐藏
+    setTimeout(() => {
+      setEmailCodeSuccessAlert({
+        visible: false,
+        message: ''
+      });
+    }, 5000);
+  };
+
+  // 倒计时效果
+  React.useEffect(() => {
+    let timer;
+    if (countdown > 0) {
+      timer = setTimeout(() => {
+        setCountdown(countdown - 1);
+      }, 1000);
+    }
+    return () => clearTimeout(timer);
+  }, [countdown]);
+
+  // 发送邮箱验证码
+  const sendEmailCode = async () => {
+    // 验证邮箱格式
+    if (!formData.email || typeof formData.email !== 'string' || !formData.email.trim()) {
+      setErrors(prev => ({
+        ...prev,
+        email: '请先输入邮箱地址'
+      }));
+      return;
+    }
+    
+    if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(formData.email)) {
+      setErrors(prev => ({
+        ...prev,
+        email: '请输入有效的邮箱地址'
+      }));
+      return;
+    }
+
+    setSendingCode(true);
+    
+    try {
+      // 调用后端API发送验证码
+      const response = await fetch(baseURL + '/send-verification-code', {
+        method: 'POST',
+        headers: {
+          'Content-Type': 'application/json',
+        },
+        body: JSON.stringify({
+          email: formData.email,
+          verification_type: 'register'
+        })
+      });
+      
+      if (!response.ok) {
+        throw new Error(`HTTP ${response.status}: ${response.statusText}`);
+      }
+      
+      const result = await response.json();
+      
+      if (result.success) {
+        showEmailCodeSuccessAlert('验证码已发送到您的邮箱');
+        setEmailCodeSent(true);
+        setCountdown(60); // 60秒倒计时
+        
+        // 清除邮箱错误提示
+        setErrors(prev => ({
+          ...prev,
+          email: ''
+        }));
+      } else {
+        // 根据具体错误信息进行处理
+        const errorMessage = result.message || '发送验证码失败,请稍后再试';
+        
+        if (errorMessage.includes('邮箱') && (errorMessage.includes('已注册') || errorMessage.includes('已存在'))) {
+          setErrors(prev => ({
+            ...prev,
+            email: errorMessage
+          }));
+        } else {
+          showErrorModal('发送验证码失败', errorMessage);
+        }
+      }
+      
+    } catch (error) {
+      console.error('发送验证码失败:', error);
+      
+      // 根据错误类型显示不同的错误信息
+      if (error.name === 'TypeError' && error.message.includes('Failed to fetch')) {
+        showErrorModal('网络连接失败', '无法连接到服务器,请检查您的网络连接后重试。如果问题持续存在,请联系客服。');
+      } else if (error.message.includes('HTTP 500')) {
+        showErrorModal('服务器错误', '服务器出现了内部错误,请稍后重试。如果问题持续存在,请联系客服。');
+      } else if (error.message.includes('HTTP 429')) {
+        showErrorModal('发送频率限制', '验证码发送过于频繁,请稍后再试。为了防止垃圾邮件,系统限制了发送频率。');
+      } else if (error.message.includes('HTTP 400')) {
+        showErrorModal('请求错误', '邮箱格式错误,请检查邮箱地址是否正确。');
+      } else {
+        showErrorModal('发送失败', '发送验证码失败,请稍后重试。如果问题持续存在,请联系客服。');
+      }
+    } finally {
+      setSendingCode(false);
+    }
+  };
+
+  const handleInputChange = (field) => (e) => {
+    const value = e.target.value;
+    setFormData(prev => ({
+      ...prev,
+      [field]: value
+    }));
+    
+    // 清除对应字段的错误提示
+    if (errors[field]) {
+      setErrors(prev => ({
+        ...prev,
+        [field]: ''
+      }));
+    }
+  };
+
+  const handlePasswordChange = (e) => {
+    const value = e.target.value;
+    setFormData(prev => ({
+      ...prev,
+      password: value
+    }));
+    
+    // 清除密码错误提示
+    if (errors.password) {
+      setErrors(prev => ({
+        ...prev,
+        password: ''
+      }));
+    }
+  };
+
+  const handleConfirmPasswordChange = (e) => {
+    const value = e.target.value;
+    setFormData(prev => ({
+      ...prev,
+      confirmPassword: value
+    }));
+    
+    // 清除确认密码错误提示
+    if (errors.confirmPassword) {
+      setErrors(prev => ({
+        ...prev,
+        confirmPassword: ''
+      }));
+    }
+  };
+
+  const validateForm = () => {
+    const newErrors = {
+      username: '',
+      email: '',
+      emailCode: '',
+      password: '',
+      confirmPassword: ''
+    };
+    
+    let hasError = false;
+    
+    // 验证用户名
+    if (!formData.username || typeof formData.username !== 'string' || !formData.username.trim()) {
+      newErrors.username = '请输入用户名';
+      hasError = true;
+    } else if (formData.username.length < 2) {
+      newErrors.username = '用户名至少2个字符';
+      hasError = true;
+    } else if (formData.username.length > 20) {
+      newErrors.username = '用户名不能超过20个字符';
+      hasError = true;
+    }
+    
+    // 验证邮箱
+    if (!formData.email || typeof formData.email !== 'string' || !formData.email.trim()) {
+      newErrors.email = '请输入邮箱地址';
+      hasError = true;
+    } else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(formData.email)) {
+      newErrors.email = '请输入有效的邮箱地址';
+      hasError = true;
+    }
+    
+    // 验证邮箱验证码
+    if (!formData.emailCode || typeof formData.emailCode !== 'string' || !formData.emailCode.trim()) {
+      newErrors.emailCode = '请输入邮箱验证码';
+      hasError = true;
+    } else if (formData.emailCode.length !== 6 || !/^\d{6}$/.test(formData.emailCode)) {
+      newErrors.emailCode = '请输入6位数字验证码';
+      hasError = true;
+    }
+    
+    // 验证密码
+    if (!formData.password || typeof formData.password !== 'string' || !formData.password.trim()) {
+      newErrors.password = '请输入密码';
+      hasError = true;
+    } else if (formData.password.length < 6) {
+      newErrors.password = '密码长度至少6位';
+      hasError = true;
+    } else if (formData.password.length > 20) {
+      newErrors.password = '密码长度不能超过20位';
+      hasError = true;
+    }
+    
+    // 验证确认密码
+    if (!formData.confirmPassword || typeof formData.confirmPassword !== 'string' || !formData.confirmPassword.trim()) {
+      newErrors.confirmPassword = '请确认密码';
+      hasError = true;
+    } else if (formData.password !== formData.confirmPassword) {
+      newErrors.confirmPassword = '两次输入的密码不一致';
+      hasError = true;
+    }
+    
+    setErrors(newErrors);
+    return !hasError;
+  };
+
+  const handleSubmit = async (e) => {
+    e.preventDefault();
+    
+    // 验证表单
+    if (!validateForm()) {
+      return;
+    }
+    
+    setIsLoading(true);
+    
+    try {
+      // 调用后端API进行注册
+      const registerResponse = await fetch(baseURL + '/register', {
+        method: 'POST',
+        headers: {
+          'Content-Type': 'application/json',
+        },
+        body: JSON.stringify({
+          username: formData.username,
+          email: formData.email,
+          password: hashPassword(formData.password), // 前端加密密码
+          verification_code: hashPassword(formData.emailCode) // 前端加密验证码
+        })
+      });
+      
+      if (!registerResponse.ok) {
+        throw new Error(`HTTP ${registerResponse.status}: ${registerResponse.statusText}`);
+      }
+      
+      const registerResult = await registerResponse.json();
+      
+      if (registerResult.success) {
+        showSuccessAlert('注册成功!欢迎加入小红书,正在跳转到登录页面...');
+        // 清空表单数据
+        setFormData({
+          username: '',
+          email: '',
+          emailCode: '',
+          password: '',
+          confirmPassword: ''
+        });
+        setErrors({
+          username: '',
+          email: '',
+          emailCode: '',
+          password: '',
+          confirmPassword: ''
+        });
+        // 延迟跳转到登录页面,让用户看到成功提示
+        setTimeout(() => {
+          navigate('/login');
+        }, 2000);
+      } else {
+        // 处理不同的注册失败情况
+        const errorMessage = registerResult.message || '注册失败,请稍后再试';
+        
+        // 如果是邮箱已存在的错误,将错误显示在邮箱字段下方
+        if (errorMessage.includes('邮箱') && (errorMessage.includes('已存在') || errorMessage.includes('已注册'))) {
+          setErrors(prev => ({
+            ...prev,
+            email: errorMessage
+          }));
+        } 
+        // 如果是用户名已存在的错误,将错误显示在用户名字段下方
+        else if (errorMessage.includes('用户名') && (errorMessage.includes('已存在') || errorMessage.includes('已被使用'))) {
+          setErrors(prev => ({
+            ...prev,
+            username: errorMessage
+          }));
+        } 
+        else {
+          // 其他错误显示在消息框中
+          message.error(errorMessage);
+        }
+      }
+      
+    } catch (error) {
+      console.error('注册失败:', error);
+      
+      // 根据错误类型显示不同的错误信息
+      if (error.name === 'TypeError' && error.message.includes('Failed to fetch')) {
+        showErrorModal('网络连接失败', '无法连接到服务器,请检查您的网络连接后重试。如果问题持续存在,请联系客服。');
+      } else if (error.message.includes('HTTP 500')) {
+        showErrorModal('服务器内部错误', '服务器出现了内部错误,请稍后重试或联系客服。技术团队已收到通知。');
+      } else if (error.message.includes('HTTP 400')) {
+        showErrorModal('请求参数错误', '请求参数有误,请检查您输入的信息是否正确。');
+      } else if (error.message.includes('HTTP 409')) {
+        showErrorModal('用户信息冲突', '您输入的邮箱或用户名可能已被其他用户使用,请尝试使用其他邮箱或用户名。');
+      } else if (error.message.includes('HTTP')) {
+        showErrorModal('请求失败', `请求失败 (${error.message}),请稍后重试。如果问题持续存在,请联系客服。`);
+      } else {
+        showErrorModal('注册失败', '注册过程中发生未知错误,请稍后重试。如果问题持续存在,请联系客服。');
+      }
+    } finally {
+      setIsLoading(false);
+    }
+  };
+
+  return (
+    <div className="register-container">
+      <div className="register-background"></div>
+      
+      {isLoading && (
+        <div className="loading-overlay">
+          <div className="loading-content">
+            <div className="loading-spinner-large"></div>
+            <p className="loading-text">正在注册...</p>
+          </div>
+        </div>
+      )}
+      
+      <div className="register-content">
+        <div className="register-card">
+          {/* 成功提示 */}
+          {successAlert.visible && (
+            <div style={{ marginBottom: '16px' }}>
+              <Alert
+                message={successAlert.message}
+                type="success"
+                icon={<CheckCircleOutlined />}
+                showIcon
+                closable
+                onClose={() => setSuccessAlert({ visible: false, message: '' })}
+                style={{
+                  borderRadius: '8px',
+                  border: '1px solid #b7eb8f',
+                  backgroundColor: '#f6ffed'
+                }}
+              />
+            </div>
+          )}
+
+          {/* 邮件验证码发送成功提示 */}
+          {emailCodeSuccessAlert.visible && (
+            <div style={{ marginBottom: '16px' }}>
+              <Alert
+                message={emailCodeSuccessAlert.message}
+                type="success"
+                icon={<CheckCircleOutlined />}
+                showIcon
+                closable
+                onClose={() => setEmailCodeSuccessAlert({ visible: false, message: '' })}
+                style={{
+                  borderRadius: '8px',
+                  border: '1px solid #b7eb8f',
+                  backgroundColor: '#f6ffed'
+                }}
+              />
+            </div>
+          )}
+          
+          <div className="register-header">
+            <h1 className="register-title">加入小红书</h1>
+            <p className="register-subtitle">发现美好生活,分享精彩瞬间</p>
+          </div>
+
+          <form className="register-form" onSubmit={handleSubmit}>
+            <div className="form-group">
+              <Input
+                type="text"
+                id="username"
+                name="username"
+                className={`form-input ${errors.username ? 'input-error' : ''}`}
+                placeholder="请输入用户名"
+                value={formData.username}
+                onChange={handleInputChange('username')}
+                prefix={<UserOutlined />}
+                size="large"
+                title=""
+                status={errors.username ? 'error' : ''}
+              />
+              {errors.username && (
+                <div className="error-message">
+                  {errors.username}
+                </div>
+              )}
+            </div>
+
+            <div className="form-group">
+              <Input
+                type="email"
+                id="email"
+                name="email"
+                className={`form-input ${errors.email ? 'input-error' : ''}`}
+                placeholder="请输入邮箱地址"
+                value={formData.email}
+                onChange={handleInputChange('email')}
+                prefix={<MailOutlined />}
+                size="large"
+                title=""
+                status={errors.email ? 'error' : ''}
+              />
+              {errors.email && (
+                <div className="error-message">
+                  {errors.email}
+                </div>
+              )}
+            </div>
+
+            <div className="form-group">
+              <div className="email-code-wrapper">
+                <Input
+                  type="text"
+                  id="emailCode"
+                  name="emailCode"
+                  className={`form-input email-code-input ${errors.emailCode ? 'input-error' : ''}`}
+                  placeholder="请输入6位验证码"
+                  value={formData.emailCode}
+                  onChange={handleInputChange('emailCode')}
+                  prefix={<SafetyOutlined />}
+                  maxLength={6}
+                  size="large"
+                  title=""
+                  status={errors.emailCode ? 'error' : ''}
+                />
+                <Button
+                  type="primary"
+                  className="send-code-button"
+                  onClick={sendEmailCode}
+                  loading={sendingCode}
+                  disabled={countdown > 0 || !formData.email || sendingCode}
+                  size="large"
+                >
+                  {countdown > 0 ? `${countdown}s后重发` : (emailCodeSent ? '重新发送' : '发送验证码')}
+                </Button>
+              </div>
+              {errors.emailCode && (
+                <div className="error-message">
+                  {errors.emailCode}
+                </div>
+              )}
+            </div>
+
+            <div className="form-group">
+              <Input.Password
+                id="password"
+                name="password"
+                className={`form-input ${errors.password ? 'input-error' : ''}`}
+                placeholder="请输入密码"
+                value={formData.password}
+                onChange={handlePasswordChange}
+                prefix={<LockOutlined />}
+                size="large"
+                title=""
+                status={errors.password ? 'error' : ''}
+              />
+              {errors.password && (
+                <div className="error-message">
+                  {errors.password}
+                </div>
+              )}
+            </div>
+
+            <div className="form-group">
+              <Input.Password
+                id="confirmPassword"
+                name="confirmPassword"
+                className={`form-input ${errors.confirmPassword ? 'input-error' : ''}`}
+                placeholder="请确认密码"
+                value={formData.confirmPassword}
+                onChange={handleConfirmPasswordChange}
+                prefix={<LockOutlined />}
+                size="large"
+                title=""
+                status={errors.confirmPassword ? 'error' : ''}
+              />
+              {errors.confirmPassword && (
+                <div className="error-message">
+                  {errors.confirmPassword}
+                </div>
+              )}
+            </div>
+
+            <button
+              type="submit"
+              className={`register-button ${isLoading ? 'loading' : ''}`}
+              disabled={isLoading}
+            >
+              {isLoading ? (
+                <>
+                  <div className="loading-spinner"></div>
+                  注册中...
+                </>
+              ) : (
+                '立即注册'
+              )}
+            </button>
+          </form>
+
+          <div className="login-link">
+            <p>已有账户? <Link to="/login">立即登录</Link></p>
+          </div>
+        </div>
+      </div>
+
+      {/* 错误弹窗 */}
+      <Modal
+        title={
+          <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
+            <ExclamationCircleOutlined style={{ color: '#ff4d4f', fontSize: '18px' }} />
+            {errorModal.title}
+          </div>
+        }
+        open={errorModal.visible}
+        onOk={closeErrorModal}
+        onCancel={closeErrorModal}
+        okText="我知道了"
+        cancelButtonProps={{ style: { display: 'none' } }}
+        centered
+        className="error-modal"
+      >
+        <div style={{ padding: '16px 0', fontSize: '14px', lineHeight: '1.6' }}>
+          {errorModal.content}
+        </div>
+      </Modal>
+    </div>
+  );
+};
+
+export default RegisterPage;
diff --git a/rhj/frontend/src/pages/TestDashboard/TestDashboard.css b/rhj/frontend/src/pages/TestDashboard/TestDashboard.css
new file mode 100644
index 0000000..a9e1c80
--- /dev/null
+++ b/rhj/frontend/src/pages/TestDashboard/TestDashboard.css
@@ -0,0 +1,189 @@
+.test-dashboard {
+  min-height: 100vh;
+  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+  padding: 20px;
+}
+
+.dashboard-header {
+  text-align: center;
+  margin-bottom: 30px;
+  color: white;
+}
+
+.dashboard-header h1 {
+  font-size: 2.5rem;
+  margin-bottom: 10px;
+  text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
+}
+
+.dashboard-header p {
+  font-size: 1.1rem;
+  opacity: 0.9;
+}
+
+.dashboard-content {
+  max-width: 1200px;
+  margin: 0 auto;
+  display: flex;
+  flex-direction: column;
+  gap: 20px;
+}
+
+.user-info-card,
+.token-info-card,
+.api-test-card {
+  background: white;
+  border-radius: 12px;
+  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
+  border: none;
+}
+
+.user-info-card .ant-card-head {
+  background: linear-gradient(90deg, #4f46e5 0%, #7c3aed 100%);
+  border-radius: 12px 12px 0 0;
+  border-bottom: none;
+}
+
+.user-info-card .ant-card-head-title {
+  color: white;
+  font-weight: 600;
+}
+
+.user-info-card .ant-card-extra .ant-btn {
+  color: white;
+  border-color: rgba(255, 255, 255, 0.3);
+}
+
+.user-info-card .ant-card-extra .ant-btn:hover {
+  background: rgba(255, 255, 255, 0.1);
+  border-color: rgba(255, 255, 255, 0.5);
+}
+
+.user-info-card .ant-card-extra .ant-btn-danger {
+  background: #ef4444;
+  border-color: #ef4444;
+}
+
+.user-info-card .ant-card-extra .ant-btn-danger:hover {
+  background: #dc2626;
+  border-color: #dc2626;
+}
+
+.token-info-card .ant-card-head {
+  background: linear-gradient(90deg, #059669 0%, #0d9488 100%);
+  border-radius: 12px 12px 0 0;
+  border-bottom: none;
+}
+
+.token-info-card .ant-card-head-title {
+  color: white;
+  font-weight: 600;
+}
+
+.api-test-card .ant-card-head {
+  background: linear-gradient(90deg, #ea580c 0%, #dc2626 100%);
+  border-radius: 12px 12px 0 0;
+  border-bottom: none;
+}
+
+.api-test-card .ant-card-head-title {
+  color: white;
+  font-weight: 600;
+}
+
+.token-display {
+  background: #f8fafc;
+  padding: 20px;
+  border-radius: 8px;
+  border: 1px solid #e2e8f0;
+}
+
+.token-text {
+  background: #1e293b;
+  color: #10b981;
+  padding: 12px;
+  border-radius: 6px;
+  font-family: 'Courier New', monospace;
+  font-size: 14px;
+  word-break: break-all;
+  margin: 10px 0;
+  border: 1px solid #334155;
+}
+
+.token-note {
+  color: #64748b;
+  font-size: 12px;
+  font-style: italic;
+  margin: 10px 0 0 0;
+}
+
+.loading-container {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  height: 100vh;
+  color: white;
+}
+
+.spinner {
+  width: 40px;
+  height: 40px;
+  border: 4px solid rgba(255, 255, 255, 0.3);
+  border-left-color: white;
+  border-radius: 50%;
+  animation: spin 1s linear infinite;
+  margin-bottom: 20px;
+}
+
+@keyframes spin {
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+.loading-container p {
+  font-size: 1.1rem;
+  opacity: 0.9;
+}
+
+/* 响应式设计 */
+@media (max-width: 768px) {
+  .test-dashboard {
+    padding: 10px;
+  }
+  
+  .dashboard-header h1 {
+    font-size: 2rem;
+  }
+  
+  .dashboard-content {
+    gap: 15px;
+  }
+  
+  .user-info-card .ant-card-extra {
+    flex-direction: column;
+    gap: 8px;
+  }
+  
+  .token-text {
+    font-size: 12px;
+  }
+}
+
+/* Ant Design 组件样式覆写 */
+.ant-descriptions-item-label {
+  font-weight: 600;
+  color: #374151;
+  background: #f9fafb;
+}
+
+.ant-descriptions-item-content {
+  color: #111827;
+}
+
+.ant-tag {
+  font-weight: 500;
+  border-radius: 6px;
+  padding: 2px 8px;
+}
diff --git a/rhj/frontend/src/pages/TestDashboard/TestDashboard.js b/rhj/frontend/src/pages/TestDashboard/TestDashboard.js
new file mode 100644
index 0000000..0ecaaf4
--- /dev/null
+++ b/rhj/frontend/src/pages/TestDashboard/TestDashboard.js
@@ -0,0 +1,295 @@
+import React, { useState, useEffect } from 'react';
+import { Card, Button, Descriptions, Avatar, Tag, Space, message } from 'antd';
+import { UserOutlined, LogoutOutlined, ReloadOutlined } from '@ant-design/icons';
+import { getUserInfo, getAuthToken, isLoggedIn, saveAuthInfo, createAuthenticatedRequest } from '../../utils/auth';
+import LogoutButton from '../../components/LogoutButton/LogoutButton';
+import './TestDashboard.css';
+
+const TestDashboard = () => {
+  const [userInfo, setUserInfo] = useState(null);
+  const [token, setToken] = useState(null);
+  const [loading, setLoading] = useState(false);
+  const [jwtTestLoading, setJwtTestLoading] = useState(false);
+
+  useEffect(() => {
+    // 检查用户是否已登录
+    if (!isLoggedIn()) {
+      window.location.href = '/';
+      return;
+    }
+
+    // 获取用户信息和token
+    const authToken = getAuthToken();
+    const authUserInfo = getUserInfo();
+    
+    setToken(authToken);
+    setUserInfo(authUserInfo);
+  }, []);
+
+  const handleRefreshProfile = async () => {
+    if (!token) {
+      message.error('未找到认证token');
+      return;
+    }
+
+    setLoading(true);
+    try {
+      const response = await fetch('http://10.126.59.25:8082/profile', createAuthenticatedRequest());
+
+      const result = await response.json();
+      
+      if (result.success) {
+        setUserInfo(result.user);
+        // 更新存储的用户信息,保持原有的存储方式(localStorage或sessionStorage)
+        const isRemembered = localStorage.getItem('authToken');
+        saveAuthInfo(token, result.user, !!isRemembered);
+        message.success('用户信息刷新成功');
+      } else {
+        message.error(`获取用户信息失败: ${result.message}`);
+      }
+    } catch (error) {
+      console.error('刷新用户信息失败:', error);
+      message.error('网络连接失败');
+    } finally {
+      setLoading(false);
+    }
+  };
+
+  const handleLogout = async () => {
+    if (!token) {
+      // 清除存储并跳转
+      localStorage.removeItem('authToken');
+      localStorage.removeItem('userInfo');
+      sessionStorage.removeItem('authToken');
+      sessionStorage.removeItem('userInfo');
+      window.location.href = '/';
+      return;
+    }
+
+    try {
+      const response = await fetch('http://10.126.59.25:8082/logout', {
+        method: 'POST',
+        headers: {
+          'Authorization': `Bearer ${token}`,
+          'Content-Type': 'application/json',
+        }
+      });
+
+      const result = await response.json();
+      
+      if (result.success) {
+        message.success('退出登录成功');
+      } else {
+        message.warning(`退出登录: ${result.message}`);
+      }
+    } catch (error) {
+      console.error('退出登录请求失败:', error);
+      message.warning('网络请求失败,但将清除本地数据');
+    } finally {
+      // 无论请求成功与否,都清除本地存储并跳转
+      localStorage.removeItem('authToken');
+      localStorage.removeItem('userInfo');
+      sessionStorage.removeItem('authToken');
+      sessionStorage.removeItem('userInfo');
+      window.location.href = '/';
+    }
+  };
+
+  const handleTestJWT = async () => {
+    if (!token) {
+      message.error('未找到认证token');
+      return;
+    }
+
+    setJwtTestLoading(true);
+    try {
+      const response = await fetch('http://10.126.59.25:8082/test-jwt', {
+        method: 'POST',
+        headers: {
+          'Authorization': `Bearer ${token}`,
+          'Content-Type': 'application/json',
+        },
+        body: JSON.stringify({
+          token: token, // 可选:在请求体中也发送token进行额外验证
+          test_purpose: 'frontend_jwt_test'
+        })
+      });
+
+      const result = await response.json();
+      
+      if (result.success) {
+        message.success(`JWT令牌验证成功!用户: ${result.user.username}`);
+        console.log('JWT验证详细结果:', result);
+        
+        // 如果有额外的token验证结果,也显示出来
+        if (result.additional_token_verification) {
+          console.log('额外token验证:', result.additional_token_verification);
+        }
+      } else {
+        message.error(`JWT令牌验证失败: ${result.message}`);
+      }
+    } catch (error) {
+      console.error('JWT令牌验证失败:', error);
+      message.error('网络连接失败');
+    } finally {
+      setJwtTestLoading(false);
+    }
+  };
+
+  const getRoleColor = (role) => {
+    switch (role) {
+      case 'superadmin':
+        return 'red';
+      case 'admin':
+        return 'orange';
+      case 'user':
+      default:
+        return 'blue';
+    }
+  };
+
+  const getStatusColor = (status) => {
+    switch (status) {
+      case 'active':
+        return 'green';
+      case 'banned':
+        return 'red';
+      case 'muted':
+        return 'orange';
+      default:
+        return 'default';
+    }
+  };
+
+  if (!userInfo) {
+    return (
+      <div className="test-dashboard">
+        <div className="loading-container">
+          <div className="spinner"></div>
+          <p>加载用户信息中...</p>
+        </div>
+      </div>
+    );
+  }
+
+  return (
+    <div className="test-dashboard">
+      <div className="dashboard-header">
+        <h1>测试仪表板</h1>
+        <p>登录成功!以下是从后端返回的用户信息:</p>
+      </div>
+
+      <div className="dashboard-content">
+        <Card
+          title={
+            <Space>
+              <Avatar size={40} icon={<UserOutlined />} src={userInfo.avatar} />
+              <span>用户信息</span>
+            </Space>
+          }
+          extra={
+            <Space>
+              <Button 
+                type="primary" 
+                icon={<ReloadOutlined />}
+                loading={loading}
+                onClick={handleRefreshProfile}
+              >
+                刷新信息
+              </Button>
+              <LogoutButton onLogout={() => window.location.href = '/'} />
+            </Space>
+          }
+          className="user-info-card"
+        >
+          <Descriptions column={2} bordered>
+            <Descriptions.Item label="用户ID">{userInfo.id}</Descriptions.Item>
+            <Descriptions.Item label="用户名">{userInfo.username}</Descriptions.Item>
+            <Descriptions.Item label="邮箱">{userInfo.email}</Descriptions.Item>
+            <Descriptions.Item label="角色">
+              <Tag color={getRoleColor(userInfo.role)}>
+                {userInfo.role}
+              </Tag>
+            </Descriptions.Item>
+            <Descriptions.Item label="账号状态">
+              <Tag color={getStatusColor(userInfo.status)}>
+                {userInfo.status}
+              </Tag>
+            </Descriptions.Item>
+            <Descriptions.Item label="个人简介" span={2}>
+              {userInfo.bio || '暂无个人简介'}
+            </Descriptions.Item>
+            <Descriptions.Item label="创建时间">
+              {userInfo.created_at ? new Date(userInfo.created_at).toLocaleString() : '未知'}
+            </Descriptions.Item>
+            <Descriptions.Item label="更新时间">
+              {userInfo.updated_at ? new Date(userInfo.updated_at).toLocaleString() : '未知'}
+            </Descriptions.Item>
+          </Descriptions>
+        </Card>
+
+        <Card title="登录状态信息" className="login-status-card">
+          <div className="login-status-display">
+            <Descriptions column={1} bordered>
+              <Descriptions.Item label="登录方式">
+                <Tag color={localStorage.getItem('authToken') ? 'green' : 'blue'}>
+                  {localStorage.getItem('authToken') ? '记住我登录 (持久化)' : '普通登录 (会话)'}
+                </Tag>
+              </Descriptions.Item>
+              <Descriptions.Item label="Token存储位置">
+                {localStorage.getItem('authToken') ? 'localStorage (浏览器关闭后仍保持登录)' : 'sessionStorage (浏览器关闭后需重新登录)'}
+              </Descriptions.Item>
+              <Descriptions.Item label="记住的登录信息">
+                {localStorage.getItem('rememberMe') === 'true' ? 
+                  `已保存邮箱: ${localStorage.getItem('rememberedEmail') || '无'}` : 
+                  '未保存登录信息'
+                }
+              </Descriptions.Item>
+            </Descriptions>
+          </div>
+        </Card>
+
+        <Card title="Token信息" className="token-info-card">
+          <div className="token-display">
+            <p><strong>认证Token:</strong></p>
+            <div className="token-text">
+              {token ? `${token.substring(0, 50)}...` : '未找到token'}
+            </div>
+            <p className="token-note">
+              * Token已被安全截断显示,完整token存储在浏览器存储中
+            </p>
+          </div>
+        </Card>
+
+        <Card title="API测试" className="api-test-card">
+          <Space direction="vertical" style={{ width: '100%' }}>
+            <p>您可以使用以下按钮测试不同的API接口:</p>
+            <Space wrap>
+              <Button onClick={handleRefreshProfile} loading={loading}>
+                测试 GET /profile
+              </Button>
+              <Button onClick={handleLogout}>
+                测试 POST /logout
+              </Button>
+              <Button 
+                onClick={handleTestJWT} 
+                loading={jwtTestLoading}
+                type="primary"
+              >
+                测试 POST /test-jwt
+              </Button>
+              <Button 
+                type="dashed"
+                onClick={() => window.open('http://10.126.59.25:8082/health', '_blank')}
+              >
+                测试 GET /health
+              </Button>
+            </Space>
+          </Space>
+        </Card>
+      </div>
+    </div>
+  );
+};
+
+export default TestDashboard;