diff --git a/web/src/components/settings/TwoFASetting.js b/web/src/components/settings/TwoFASetting.js
index af0896ad..148284dd 100644
--- a/web/src/components/settings/TwoFASetting.js
+++ b/web/src/components/settings/TwoFASetting.js
@@ -17,7 +17,13 @@ along with this program. If not, see .
For commercial licensing, please contact support@quantumnous.com
*/
import { API, showError, showSuccess, showWarning } from '../../helpers';
-import { Banner, Button, Card, Checkbox, Divider, Form, Input, Modal, Tag, Typography } from '@douyinfe/semi-ui';
+import { Banner, Button, Card, Checkbox, Divider, Input, Modal, Tag, Typography, Steps, Space, Badge } from '@douyinfe/semi-ui';
+import {
+ IconShield,
+ IconAlertTriangle,
+ IconRefresh,
+ IconCopy
+} from '@douyinfe/semi-icons';
import React, { useEffect, useState } from 'react';
import { QRCodeSVG } from 'qrcode.react';
@@ -43,6 +49,7 @@ const TwoFASetting = () => {
const [verificationCode, setVerificationCode] = useState('');
const [backupCodes, setBackupCodes] = useState([]);
const [confirmDisable, setConfirmDisable] = useState(false);
+ const [currentStep, setCurrentStep] = useState(0);
// 获取2FA状态
const fetchStatus = async () => {
@@ -68,6 +75,7 @@ const TwoFASetting = () => {
if (res.data.success) {
setSetupData(res.data.data);
setSetupModalVisible(true);
+ setCurrentStep(0);
} else {
showError(res.data.message);
}
@@ -95,6 +103,7 @@ const TwoFASetting = () => {
setEnableModalVisible(false);
setSetupModalVisible(false);
setVerificationCode('');
+ setCurrentStep(0);
fetchStatus();
} else {
showError(res.data.message);
@@ -166,75 +175,250 @@ const TwoFASetting = () => {
}
};
- const copyBackupCodes = () => {
- const codesText = backupCodes.join('\n');
- navigator.clipboard.writeText(codesText).then(() => {
- showSuccess('备用码已复制到剪贴板');
+ // 通用复制函数
+ const copyTextToClipboard = (text, successMessage = '已复制到剪贴板') => {
+ navigator.clipboard.writeText(text).then(() => {
+ showSuccess(successMessage);
}).catch(() => {
showError('复制失败,请手动复制');
});
};
- return (
-
+ const copyBackupCodes = () => {
+ const codesText = backupCodes.join('\n');
+ copyTextToClipboard(codesText, '备用码已复制到剪贴板');
+ };
+
+ // 备用码展示组件
+ const BackupCodesDisplay = ({ codes, title, onCopy }) => {
+ return (
+
+
+
+ {title}
+
+
+
+
+ {codes.map((code, index) => (
+
+
+
+ {code}
+
+
+ #{(index + 1).toString().padStart(2, '0')}
+
+
+
+ ))}
+
+
+
+
}
+ onClick={onCopy}
+ className="!rounded-lg !bg-slate-600 hover:!bg-slate-700 w-full"
+ >
+ 复制所有代码
+
+
+
+ );
+ };
+
+ // 渲染设置模态框footer
+ const renderSetupModalFooter = () => {
+ return (
+ <>
+ {currentStep > 0 && (
+
+ )}
+ {currentStep < 2 ? (
+
+ ) : (
+
+ )}
+ >
+ );
+ };
+
+ // 渲染禁用模态框footer
+ const renderDisableModalFooter = () => {
+ return (
+ <>
+
+
+ >
+ );
+ };
+
+ // 渲染重新生成模态框footer
+ const renderRegenerateModalFooter = () => {
+ if (backupCodes.length > 0) {
+ return (
+
+ );
+ }
+
+ return (
+ <>
+
+
+ >
+ );
+ };
+
+ return (
+ <>
+
-
-
-
-
+
+
+
+
-
-
两步验证设置
-
- 两步验证(2FA)为您的账户提供额外的安全保护。启用后,登录时需要输入密码和验证器应用生成的验证码。
-
-
-
当前状态:
+
+
+
+ 两步验证设置
+
{status.enabled ? (
- 已启用
+ 已启用
) : (
- 未启用
+ 未启用
)}
{status.locked && (
- 账户已锁定
+ 账户已锁定
)}
+
+ 两步验证(2FA)为您的账户提供额外的安全保护。启用后,登录时需要输入密码和验证器应用生成的验证码。
+
{status.enabled && (
-
+
剩余备用码:{status.backup_codes_remaining || 0} 个
)}
-
+
{!status.enabled ? (
}
>
- 启用两步验证
+ 启用验证
) : (
@@ -248,11 +432,7 @@ const TwoFASetting = () => {
-
+
设置两步验证
}
@@ -260,101 +440,66 @@ const TwoFASetting = () => {
onCancel={() => {
setSetupModalVisible(false);
setSetupData(null);
+ setCurrentStep(0);
+ setVerificationCode('');
}}
- footer={null}
+ footer={renderSetupModalFooter()}
width={650}
style={{ maxWidth: '90vw' }}
>
{setupData && (
- {/* 步骤 1:扫描二维码 */}
-
-
-
- 使用认证器应用(如 Google Authenticator、Microsoft Authenticator)扫描下方二维码:
-
-
-
-
- 或手动输入密钥:{setupData.secret}
-
-
-
+ {/* 步骤进度 */}
+
+
+
+
+
- {/* 步骤 2:保存备用码 */}
-
-
-
- 请将以下备用码保存在安全的地方。如果丢失手机,可以使用这些备用码登录:
-
-
-
- {setupData.backup_codes.map((code, index) => (
-
-
{code}
+ {/* 步骤内容 */}
+
+ {currentStep === 0 && (
+
+
+ 使用认证器应用(如 Google Authenticator、Microsoft Authenticator)扫描下方二维码:
+
+
+
+
+ 或手动输入密钥:{setupData.secret}
+
+
-
-
-
+ )}
- {/* 步骤 3:验证设置 */}
-
-
-
- 3
+ {currentStep === 1 && (
+
+ {/* 备用码展示 */}
+ {
+ const codesText = setupData.backup_codes.join('\n');
+ copyTextToClipboard(codesText, '备用码已复制到剪贴板');
+ }}
+ />
-
验证设置
-
-
- 输入认证器应用显示的6位数字验证码:
-
-
-
-
+ )}
)}
@@ -364,11 +509,7 @@ const TwoFASetting = () => {
-
+
禁用两步验证
}
@@ -378,58 +519,73 @@ const TwoFASetting = () => {
setVerificationCode('');
setConfirmDisable(false);
}}
- footer={null}
+ footer={renderDisableModalFooter()}
width={550}
+ style={{ maxWidth: '90vw' }}
>
-
-
- 警告:禁用两步验证将会:
-
- - 降低您账户的安全性
- - 永久删除您的两步验证设置
- - 永久删除所有备用码(包括未使用的)
- - 需要重新完整设置才能再次启用
-
-
- 此操作不可撤销,请谨慎操作!
-
-
- }
- className="rounded-lg"
- />
-
+ {/* 警告提示 */}
+
+
-
- setConfirmDisable(e.target.checked)}
- className="text-sm"
- >
- 我已了解禁用两步验证将永久删除所有相关设置和备用码,此操作不可撤销
-
+
+
+ {/* 内容区域 */}
+
+
+
+ 禁用后的影响:
+
+
+ -
+
+ 降低您账户的安全性
+
+ -
+
+ 需要重新完整设置才能再次启用
+
+ -
+
+ 永久删除您的两步验证设置
+
+ -
+
+ 永久删除所有备用码(包括未使用的)
+
+
-
-
+
+
+
+
+
+
+ 验证身份
+
+
+
+
+
+ setConfirmDisable(e.target.checked)}
+ className="text-sm"
+ >
+ 我已了解禁用两步验证将永久删除所有相关设置和备用码,此操作不可撤销
+
+
+
+
@@ -437,11 +593,7 @@ const TwoFASetting = () => {
-
+
重新生成备用码
}
@@ -451,73 +603,64 @@ const TwoFASetting = () => {
setVerificationCode('');
setBackupCodes([]);
}}
- footer={null}
+ footer={renderRegenerateModalFooter()}
width={500}
+ style={{ maxWidth: '90vw' }}
>
-
+
{backupCodes.length === 0 ? (
<>
-
-
+
-
-
+
+
+ {/* 验证区域 */}
+
>
) : (
<>
-
-
-
+ {/* 成功提示 */}
+
+
+
+
+ 新的备用码已生成
+
- 新的备用码已生成
-
- 请将以下备用码保存在安全的地方:
-
-
-
-
- {backupCodes.map((code, index) => (
-
- {code}
-
- ))}
-
-
-
+
+ 旧的备用码已失效,请保存新的备用码
+
+
+ {/* 备用码展示 */}
+
+
>
)}
-
+ >
);
};