diff --git a/web/src/components/LoginForm.js b/web/src/components/LoginForm.js index 84a0082c..f10df1a2 100644 --- a/web/src/components/LoginForm.js +++ b/web/src/components/LoginForm.js @@ -28,7 +28,7 @@ import Title from '@douyinfe/semi-ui/lib/es/typography/title'; import Text from '@douyinfe/semi-ui/lib/es/typography/text'; import TelegramLoginButton from 'react-telegram-login'; -import { IconGithubLogo, IconMail } from '@douyinfe/semi-icons'; +import { IconGithubLogo, IconMail, IconLock } from '@douyinfe/semi-icons'; import OIDCIcon from './OIDCIcon.js'; import WeChatIcon from './WeChatIcon'; import { setUserData } from '../helpers/data.js'; @@ -53,7 +53,6 @@ const LoginForm = () => { const [status, setStatus] = useState({}); const [showWeChatLoginModal, setShowWeChatLoginModal] = useState(false); const [showEmailLogin, setShowEmailLogin] = useState(false); - const [showOtherOptions, setShowOtherOptions] = useState(false); const { t } = useTranslation(); const logo = getLogo(); @@ -318,6 +317,7 @@ const LoginForm = () => { size="large" className="!rounded-md" onChange={(value) => handleChange('username', value)} + prefix={} /> { label={t('密码')} placeholder={t('请输入您的密码')} name="password" - type="password" + mode="password" size="large" className="!rounded-md" onChange={(value) => handleChange('password', value)} + prefix={} />
diff --git a/web/src/components/PasswordResetConfirm.js b/web/src/components/PasswordResetConfirm.js index 222c8add..d7a1143e 100644 --- a/web/src/components/PasswordResetConfirm.js +++ b/web/src/components/PasswordResetConfirm.js @@ -1,9 +1,15 @@ import React, { useEffect, useState } from 'react'; -import { Button, Form, Grid, Header, Image, Segment } from 'semantic-ui-react'; -import { API, copy, showError, showNotice } from '../helpers'; -import { useSearchParams } from 'react-router-dom'; +import { API, copy, showError, showNotice, getLogo, getSystemName } from '../helpers'; +import { useSearchParams, Link } from 'react-router-dom'; +import { Button, Card, Form, Typography } from '@douyinfe/semi-ui'; +import { IconMail, IconLock } from '@douyinfe/semi-icons'; +import { useTranslation } from 'react-i18next'; +import Background from '../images/example.png'; + +const { Text, Title } = Typography; const PasswordResetConfirm = () => { + const { t } = useTranslation(); const [inputs, setInputs] = useState({ email: '', token: '', @@ -11,13 +17,15 @@ const PasswordResetConfirm = () => { const { email, token } = inputs; const [loading, setLoading] = useState(false); - const [disableButton, setDisableButton] = useState(false); const [countdown, setCountdown] = useState(30); - const [newPassword, setNewPassword] = useState(''); const [searchParams, setSearchParams] = useSearchParams(); + + const logo = getLogo(); + const systemName = getSystemName(); + useEffect(() => { let token = searchParams.get('token'); let email = searchParams.get('email'); @@ -41,8 +49,8 @@ const PasswordResetConfirm = () => { }, [disableButton, countdown]); async function handleSubmit(e) { + if (!email || !token) return; setDisableButton(true); - if (!email) return; setLoading(true); const res = await API.post(`/api/user/reset`, { email, @@ -53,7 +61,7 @@ const PasswordResetConfirm = () => { let password = res.data.data; setNewPassword(password); await copy(password); - showNotice(`新密码已复制到剪贴板:${password}`); + showNotice(`${t('密码已重置并已复制到剪贴板')}: ${password}`); } else { showError(message); } @@ -61,52 +69,86 @@ const PasswordResetConfirm = () => { } return ( - - -
- 密码重置确认 -
-
- - - {newPassword && ( - { - e.target.select(); - navigator.clipboard.writeText(newPassword); - showNotice(`密码已复制到剪贴板:${newPassword}`); - }} - /> - )} - - -
-
-
+
+ {/* 背景图片容器 - 放大并保持居中 */} +
+ + {/* 半透明遮罩层 */} +
+ +
+
+
+
+ Logo + {systemName} +
+ + +
+ {t('密码重置确认')} +
+
+
+ } + /> + + {newPassword && ( + } + onClick={(e) => { + e.target.select(); + navigator.clipboard.writeText(newPassword); + showNotice(`${t('密码已复制到剪贴板')}: ${newPassword}`); + }} + /> + )} + +
+ +
+ + +
+ {t('返回登录')} +
+
+
+
+
+
+
); }; diff --git a/web/src/components/PasswordResetForm.js b/web/src/components/PasswordResetForm.js index 631d83be..222b4ebe 100644 --- a/web/src/components/PasswordResetForm.js +++ b/web/src/components/PasswordResetForm.js @@ -1,9 +1,16 @@ import React, { useEffect, useState } from 'react'; -import { Button, Form, Grid, Header, Image, Segment } from 'semantic-ui-react'; -import { API, showError, showInfo, showSuccess } from '../helpers'; +import { API, getLogo, showError, showInfo, showSuccess, getSystemName } from '../helpers'; import Turnstile from 'react-turnstile'; +import { Button, Card, Form, Typography } from '@douyinfe/semi-ui'; +import { IconMail } from '@douyinfe/semi-icons'; +import { Link } from 'react-router-dom'; +import { useTranslation } from 'react-i18next'; +import Background from '../images/example.png'; + +const { Text, Title } = Typography; const PasswordResetForm = () => { + const { t } = useTranslation(); const [inputs, setInputs] = useState({ email: '', }); @@ -16,6 +23,20 @@ const PasswordResetForm = () => { const [disableButton, setDisableButton] = useState(false); const [countdown, setCountdown] = useState(30); + const logo = getLogo(); + const systemName = getSystemName(); + + useEffect(() => { + let status = localStorage.getItem('status'); + if (status) { + status = JSON.parse(status); + if (status.turnstile_check) { + setTurnstileEnabled(true); + setTurnstileSiteKey(status.turnstile_site_key); + } + } + }, []); + useEffect(() => { let countdownInterval = null; if (disableButton && countdown > 0) { @@ -29,25 +50,24 @@ const PasswordResetForm = () => { return () => clearInterval(countdownInterval); }, [disableButton, countdown]); - function handleChange(e) { - const { name, value } = e.target; - setInputs((inputs) => ({ ...inputs, [name]: value })); + function handleChange(value) { + setInputs((inputs) => ({ ...inputs, email: value })); } async function handleSubmit(e) { - setDisableButton(true); if (!email) return; if (turnstileEnabled && turnstileToken === '') { - showInfo('请稍后几秒重试,Turnstile 正在检查用户环境!'); + showInfo(t('请稍后几秒重试,Turnstile 正在检查用户环境!')); return; } + setDisableButton(true); setLoading(true); const res = await API.get( `/api/reset_password?email=${email}&turnstile=${turnstileToken}`, ); const { success, message } = res.data; if (success) { - showSuccess('重置邮件发送成功,请检查邮箱!'); + showSuccess(t('重置邮件发送成功,请检查邮箱!')); setInputs({ ...inputs, email: '' }); } else { showError(message); @@ -56,46 +76,80 @@ const PasswordResetForm = () => { } return ( - - -
- 密码重置 -
-
- - - {turnstileEnabled ? ( - { - setTurnstileToken(token); - }} - /> - ) : ( - <> +
+ {/* 背景图片容器 - 放大并保持居中 */} +
+ + {/* 半透明遮罩层 */} +
+ +
+
+
+
+ Logo + {systemName} +
+ + +
+ {t('密码重置')} +
+
+ + } + /> + +
+ +
+ + +
+ {t('想起来了?')} {t('登录')} +
+
+
+ + {turnstileEnabled && ( +
+ { + setTurnstileToken(token); + }} + /> +
)} - - - - - +
+
+
+
); }; diff --git a/web/src/components/RegisterForm.js b/web/src/components/RegisterForm.js index cb85b0d5..df537958 100644 --- a/web/src/components/RegisterForm.js +++ b/web/src/components/RegisterForm.js @@ -21,7 +21,7 @@ import { } from '@douyinfe/semi-ui'; import Title from '@douyinfe/semi-ui/lib/es/typography/title'; import Text from '@douyinfe/semi-ui/lib/es/typography/text'; -import { IconGithubLogo, IconMail } from '@douyinfe/semi-icons'; +import { IconGithubLogo, IconMail, IconUser, IconLock, IconKey } from '@douyinfe/semi-icons'; import { onGitHubOAuthClicked, onLinuxDOOAuthClicked, @@ -334,6 +334,7 @@ const RegisterForm = () => { size="large" className="!rounded-md" onChange={(value) => handleChange('username', value)} + prefix={} /> { label={t('密码')} placeholder={t('输入密码,最短 8 位,最长 20 位')} name="password" - type="password" + mode="password" size="large" className="!rounded-md" onChange={(value) => handleChange('password', value)} + prefix={} /> { label={t('确认密码')} placeholder={t('确认密码')} name="password2" - type="password" + mode="password" size="large" className="!rounded-md" onChange={(value) => handleChange('password2', value)} + prefix={} /> {showEmailVerification && ( @@ -369,6 +372,7 @@ const RegisterForm = () => { size="large" className="!rounded-md" onChange={(value) => handleChange('email', value)} + prefix={} suffix={