mirror of
https://github.com/songquanpeng/one-api.git
synced 2025-09-17 09:16:36 +08:00
chore: update default theme style
This commit is contained in:
parent
9b83d63896
commit
c64b7c891f
@ -3,12 +3,13 @@ package controller
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/songquanpeng/one-api/common"
|
"github.com/songquanpeng/one-api/common"
|
||||||
"github.com/songquanpeng/one-api/common/config"
|
"github.com/songquanpeng/one-api/common/config"
|
||||||
"github.com/songquanpeng/one-api/common/message"
|
"github.com/songquanpeng/one-api/common/message"
|
||||||
"github.com/songquanpeng/one-api/model"
|
"github.com/songquanpeng/one-api/model"
|
||||||
"net/http"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
@ -120,6 +121,7 @@ func SendEmailVerification(c *gin.Context) {
|
|||||||
"<p>验证码 %d 分钟内有效,如果不是本人操作,请忽略。</p>", config.SystemName, code, common.VerificationValidMinutes)
|
"<p>验证码 %d 分钟内有效,如果不是本人操作,请忽略。</p>", config.SystemName, code, common.VerificationValidMinutes)
|
||||||
err := message.SendEmail(subject, email, content)
|
err := message.SendEmail(subject, email, content)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
||||||
c.JSON(http.StatusOK, gin.H{
|
c.JSON(http.StatusOK, gin.H{
|
||||||
"success": false,
|
"success": false,
|
||||||
"message": err.Error(),
|
"message": err.Error(),
|
||||||
|
@ -571,7 +571,9 @@
|
|||||||
"qrcode_placeholder": "Enter an image URL",
|
"qrcode_placeholder": "Enter an image URL",
|
||||||
"buttons": {
|
"buttons": {
|
||||||
"save": "Save WeChat Server Settings"
|
"save": "Save WeChat Server Settings"
|
||||||
}
|
},
|
||||||
|
"scan_tip": "Scan QR code to follow WeChat Official Account, enter 'code' to get verification code (valid for 3 minutes)",
|
||||||
|
"code_placeholder": "Verification code"
|
||||||
},
|
},
|
||||||
"turnstile": {
|
"turnstile": {
|
||||||
"title": "Turnstile Configuration",
|
"title": "Turnstile Configuration",
|
||||||
@ -754,5 +756,72 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"loading_failed": "Failed to load homepage content..."
|
"loading_failed": "Failed to load homepage content..."
|
||||||
|
},
|
||||||
|
"auth": {
|
||||||
|
"login": {
|
||||||
|
"title": "User Login",
|
||||||
|
"username": "Username / Email",
|
||||||
|
"password": "Password",
|
||||||
|
"button": "Login",
|
||||||
|
"forgot_password": "Forgot password?",
|
||||||
|
"reset_password": "Reset",
|
||||||
|
"no_account": "No account?",
|
||||||
|
"register": "Register",
|
||||||
|
"other_methods": "Other login methods",
|
||||||
|
"wechat": {
|
||||||
|
"scan_tip": "Scan QR code to follow WeChat Official Account, enter 'code' to get verification code (valid for 3 minutes)",
|
||||||
|
"code_placeholder": "Verification code"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"register": {
|
||||||
|
"title": "New User Registration",
|
||||||
|
"username": "Username (max 12 characters)",
|
||||||
|
"password": "Password (8-20 characters)",
|
||||||
|
"confirm_password": "Confirm password",
|
||||||
|
"email": "Email address",
|
||||||
|
"verification_code": "Verification code",
|
||||||
|
"get_code": "Get code",
|
||||||
|
"get_code_retry": "Retry ({{countdown}})",
|
||||||
|
"button": "Register",
|
||||||
|
"has_account": "Have an account?",
|
||||||
|
"login": "Login"
|
||||||
|
},
|
||||||
|
"reset": {
|
||||||
|
"title": "Password Reset",
|
||||||
|
"email": "Email address",
|
||||||
|
"button": "Submit",
|
||||||
|
"notice": "The system will send an email containing a reset link to your mailbox. Please check your email.",
|
||||||
|
"confirm": {
|
||||||
|
"title": "Password Reset Confirmation",
|
||||||
|
"new_password": "New password",
|
||||||
|
"button": "Submit",
|
||||||
|
"button_disabled": "Password reset completed",
|
||||||
|
"notice": "New password has been generated, please click the password field or button above to copy. Please login and change your password as soon as possible!"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"about": {
|
||||||
|
"title": "About",
|
||||||
|
"description": "One API is an open-source API management and proxy platform.",
|
||||||
|
"repository": "Repository: ",
|
||||||
|
"loading_failed": "Loading failed"
|
||||||
|
},
|
||||||
|
"messages": {
|
||||||
|
"success": {
|
||||||
|
"login": "Login successful!",
|
||||||
|
"register": "Registration successful!",
|
||||||
|
"verification_code": "Verification code sent, please check your email!",
|
||||||
|
"password_reset": "Reset email sent, please check your inbox!"
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"login_expired": "Not logged in or session expired, please login again!",
|
||||||
|
"password_length": "Password must be at least 8 characters!",
|
||||||
|
"password_mismatch": "Passwords do not match",
|
||||||
|
"turnstile_wait": "Please wait a few seconds, Turnstile is checking the environment!",
|
||||||
|
"root_password": "Please change the default password immediately!"
|
||||||
|
},
|
||||||
|
"notice": {
|
||||||
|
"password_copied": "New password copied to clipboard: {{password}}"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -720,10 +720,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"about": {
|
"about": {
|
||||||
"title": "关于系统",
|
"title": "关于",
|
||||||
"description": "可在设置页面设置关于内容,支持 HTML & Markdown",
|
"description": "One API 是一个开源的接口管理和代理平台。",
|
||||||
"repository": "项目仓库地址:",
|
"repository": "项目地址:",
|
||||||
"loading_failed": "加载关于内容失败..."
|
"loading_failed": "加载失败"
|
||||||
},
|
},
|
||||||
"footer": {
|
"footer": {
|
||||||
"built_by": "由",
|
"built_by": "由",
|
||||||
@ -758,5 +758,66 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"loading_failed": "加载首页内容失败..."
|
"loading_failed": "加载首页内容失败..."
|
||||||
|
},
|
||||||
|
"auth": {
|
||||||
|
"login": {
|
||||||
|
"title": "用户登录",
|
||||||
|
"username": "用户名 / 邮箱地址",
|
||||||
|
"password": "密码",
|
||||||
|
"button": "登录",
|
||||||
|
"forgot_password": "忘记密码?",
|
||||||
|
"reset_password": "点击重置",
|
||||||
|
"no_account": "没有账户?",
|
||||||
|
"register": "点击注册",
|
||||||
|
"other_methods": "使用其他方式登录",
|
||||||
|
"wechat": {
|
||||||
|
"scan_tip": "微信扫码关注公众号,输入「验证码」获取验证码(三分钟内有效)",
|
||||||
|
"code_placeholder": "验证码"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"register": {
|
||||||
|
"title": "新用户注册",
|
||||||
|
"username": "输入用户名,最长 12 位",
|
||||||
|
"password": "输入密码,最短 8 位,最长 20 位",
|
||||||
|
"confirm_password": "再次输入密码",
|
||||||
|
"email": "输入邮箱地址",
|
||||||
|
"verification_code": "输入验证码",
|
||||||
|
"get_code": "获取验证码",
|
||||||
|
"get_code_retry": "重试 ({{countdown}})",
|
||||||
|
"button": "注册",
|
||||||
|
"has_account": "已有账户?",
|
||||||
|
"login": "点击登录"
|
||||||
|
},
|
||||||
|
"reset": {
|
||||||
|
"title": "密码重置",
|
||||||
|
"email": "邮箱地址",
|
||||||
|
"button": "提交",
|
||||||
|
"notice": "系统将向您的邮箱发送一封包含重置链接的邮件,请注意查收。",
|
||||||
|
"confirm": {
|
||||||
|
"title": "密码重置确认",
|
||||||
|
"new_password": "新密码",
|
||||||
|
"button": "提交",
|
||||||
|
"button_disabled": "密码重置完成",
|
||||||
|
"notice": "新密码已生成,请点击密码框或上方按钮复制。请及时登录并修改密码!"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"messages": {
|
||||||
|
"success": {
|
||||||
|
"login": "登录成功!",
|
||||||
|
"register": "注册成功!",
|
||||||
|
"verification_code": "验证码发送成功,请检查你的邮箱!",
|
||||||
|
"password_reset": "重置邮件发送成功,请检查邮箱!"
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"login_expired": "未登录或登录已过期,请重新登录!",
|
||||||
|
"password_length": "密码长度不得小于 8 位!",
|
||||||
|
"password_mismatch": "两次输入的密码不一致",
|
||||||
|
"turnstile_wait": "请稍后几秒重试,Turnstile 正在检查用户环境!",
|
||||||
|
"root_password": "请立刻修改默认密码!"
|
||||||
|
},
|
||||||
|
"notice": {
|
||||||
|
"password_copied": "新密码已复制到剪贴板:{{password}}"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,12 +12,14 @@ import {
|
|||||||
Card,
|
Card,
|
||||||
} from 'semantic-ui-react';
|
} from 'semantic-ui-react';
|
||||||
import { Link, useNavigate, useSearchParams } from 'react-router-dom';
|
import { Link, useNavigate, useSearchParams } from 'react-router-dom';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { UserContext } from '../context/User';
|
import { UserContext } from '../context/User';
|
||||||
import { API, getLogo, showError, showSuccess, showWarning } from '../helpers';
|
import { API, getLogo, showError, showSuccess, showWarning } from '../helpers';
|
||||||
import { onGitHubOAuthClicked, onLarkOAuthClicked } from './utils';
|
import { onGitHubOAuthClicked, onLarkOAuthClicked } from './utils';
|
||||||
import larkIcon from '../images/lark.svg';
|
import larkIcon from '../images/lark.svg';
|
||||||
|
|
||||||
const LoginForm = () => {
|
const LoginForm = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
const [inputs, setInputs] = useState({
|
const [inputs, setInputs] = useState({
|
||||||
username: '',
|
username: '',
|
||||||
password: '',
|
password: '',
|
||||||
@ -33,7 +35,7 @@ const LoginForm = () => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (searchParams.get('expired')) {
|
if (searchParams.get('expired')) {
|
||||||
showError('未登录或登录已过期,请重新登录!');
|
showError(t('messages.error.login_expired'));
|
||||||
}
|
}
|
||||||
let status = localStorage.getItem('status');
|
let status = localStorage.getItem('status');
|
||||||
if (status) {
|
if (status) {
|
||||||
@ -57,7 +59,7 @@ const LoginForm = () => {
|
|||||||
userDispatch({ type: 'login', payload: data });
|
userDispatch({ type: 'login', payload: data });
|
||||||
localStorage.setItem('user', JSON.stringify(data));
|
localStorage.setItem('user', JSON.stringify(data));
|
||||||
navigate('/');
|
navigate('/');
|
||||||
showSuccess('登录成功!');
|
showSuccess(t('messages.success.login'));
|
||||||
setShowWeChatLoginModal(false);
|
setShowWeChatLoginModal(false);
|
||||||
} else {
|
} else {
|
||||||
showError(message);
|
showError(message);
|
||||||
@ -82,11 +84,11 @@ const LoginForm = () => {
|
|||||||
localStorage.setItem('user', JSON.stringify(data));
|
localStorage.setItem('user', JSON.stringify(data));
|
||||||
if (username === 'root' && password === '123456') {
|
if (username === 'root' && password === '123456') {
|
||||||
navigate('/user/edit');
|
navigate('/user/edit');
|
||||||
showSuccess('登录成功!');
|
showSuccess(t('messages.success.login'));
|
||||||
showWarning('请立刻修改默认密码!');
|
showWarning(t('messages.error.root_password'));
|
||||||
} else {
|
} else {
|
||||||
navigate('/token');
|
navigate('/token');
|
||||||
showSuccess('登录成功!');
|
showSuccess(t('messages.success.login'));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
showError(message);
|
showError(message);
|
||||||
@ -110,7 +112,7 @@ const LoginForm = () => {
|
|||||||
style={{ marginBottom: '1.5em' }}
|
style={{ marginBottom: '1.5em' }}
|
||||||
>
|
>
|
||||||
<Image src={logo} style={{ marginBottom: '10px' }} />
|
<Image src={logo} style={{ marginBottom: '10px' }} />
|
||||||
<Header.Content>用户登录</Header.Content>
|
<Header.Content>{t('auth.login.title')}</Header.Content>
|
||||||
</Header>
|
</Header>
|
||||||
</Card.Header>
|
</Card.Header>
|
||||||
<Form size='large'>
|
<Form size='large'>
|
||||||
@ -118,7 +120,7 @@ const LoginForm = () => {
|
|||||||
fluid
|
fluid
|
||||||
icon='user'
|
icon='user'
|
||||||
iconPosition='left'
|
iconPosition='left'
|
||||||
placeholder='用户名 / 邮箱地址'
|
placeholder={t('auth.login.username')}
|
||||||
name='username'
|
name='username'
|
||||||
value={username}
|
value={username}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
@ -128,7 +130,7 @@ const LoginForm = () => {
|
|||||||
fluid
|
fluid
|
||||||
icon='lock'
|
icon='lock'
|
||||||
iconPosition='left'
|
iconPosition='left'
|
||||||
placeholder='密码'
|
placeholder={t('auth.login.password')}
|
||||||
name='password'
|
name='password'
|
||||||
type='password'
|
type='password'
|
||||||
value={password}
|
value={password}
|
||||||
@ -145,7 +147,7 @@ const LoginForm = () => {
|
|||||||
}}
|
}}
|
||||||
onClick={handleSubmit}
|
onClick={handleSubmit}
|
||||||
>
|
>
|
||||||
登录
|
{t('auth.login.button')}
|
||||||
</Button>
|
</Button>
|
||||||
</Form>
|
</Form>
|
||||||
|
|
||||||
@ -160,15 +162,15 @@ const LoginForm = () => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
忘记密码?
|
{t('auth.login.forgot_password')}
|
||||||
<Link to='/reset' style={{ color: '#2185d0' }}>
|
<Link to='/reset' style={{ color: '#2185d0' }}>
|
||||||
点击重置
|
{t('auth.login.reset_password')}
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
没有账户?
|
{t('auth.login.no_account')}
|
||||||
<Link to='/register' style={{ color: '#2185d0' }}>
|
<Link to='/register' style={{ color: '#2185d0' }}>
|
||||||
点击注册
|
{t('auth.login.register')}
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -182,7 +184,7 @@ const LoginForm = () => {
|
|||||||
horizontal
|
horizontal
|
||||||
style={{ color: '#666', fontSize: '0.9em' }}
|
style={{ color: '#666', fontSize: '0.9em' }}
|
||||||
>
|
>
|
||||||
使用其他方式登录
|
{t('auth.login.other_methods')}
|
||||||
</Divider>
|
</Divider>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
@ -250,14 +252,12 @@ const LoginForm = () => {
|
|||||||
<Modal.Description>
|
<Modal.Description>
|
||||||
<Image src={status.wechat_qrcode} fluid />
|
<Image src={status.wechat_qrcode} fluid />
|
||||||
<div style={{ textAlign: 'center' }}>
|
<div style={{ textAlign: 'center' }}>
|
||||||
<p>
|
<p>{t('auth.login.wechat.scan_tip')}</p>
|
||||||
微信扫码关注公众号,输入「验证码」获取验证码(三分钟内有效)
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
<Form size='large'>
|
<Form size='large'>
|
||||||
<Form.Input
|
<Form.Input
|
||||||
fluid
|
fluid
|
||||||
placeholder='验证码'
|
placeholder={t('auth.login.wechat.code_placeholder')}
|
||||||
name='wechat_verification_code'
|
name='wechat_verification_code'
|
||||||
value={inputs.wechat_verification_code}
|
value={inputs.wechat_verification_code}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
@ -266,13 +266,13 @@ const LoginForm = () => {
|
|||||||
fluid
|
fluid
|
||||||
size='large'
|
size='large'
|
||||||
style={{
|
style={{
|
||||||
background: '#2F73FF', // 使用更现代的蓝色
|
background: '#2F73FF',
|
||||||
color: 'white',
|
color: 'white',
|
||||||
marginBottom: '1.5em',
|
marginBottom: '1.5em',
|
||||||
}}
|
}}
|
||||||
onClick={onSubmitWeChatVerificationCode}
|
onClick={onSubmitWeChatVerificationCode}
|
||||||
>
|
>
|
||||||
登录
|
{t('auth.login.button')}
|
||||||
</Button>
|
</Button>
|
||||||
</Form>
|
</Form>
|
||||||
</Modal.Description>
|
</Modal.Description>
|
||||||
|
@ -8,29 +8,23 @@ import {
|
|||||||
Card,
|
Card,
|
||||||
Message,
|
Message,
|
||||||
} from 'semantic-ui-react';
|
} from 'semantic-ui-react';
|
||||||
import {
|
import { useTranslation } from 'react-i18next';
|
||||||
API,
|
import { API, copy, getLogo, showError, showNotice } from '../helpers';
|
||||||
copy,
|
|
||||||
showError,
|
|
||||||
showInfo,
|
|
||||||
showNotice,
|
|
||||||
showSuccess,
|
|
||||||
} from '../helpers';
|
|
||||||
import { useSearchParams } from 'react-router-dom';
|
import { useSearchParams } from 'react-router-dom';
|
||||||
|
|
||||||
const PasswordResetConfirm = () => {
|
const PasswordResetConfirm = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
const [inputs, setInputs] = useState({
|
const [inputs, setInputs] = useState({
|
||||||
email: '',
|
email: '',
|
||||||
token: '',
|
token: '',
|
||||||
});
|
});
|
||||||
const { email, token } = inputs;
|
const { email, token } = inputs;
|
||||||
|
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
const [disableButton, setDisableButton] = useState(false);
|
const [disableButton, setDisableButton] = useState(false);
|
||||||
const [countdown, setCountdown] = useState(30);
|
|
||||||
|
|
||||||
const [newPassword, setNewPassword] = useState('');
|
const [newPassword, setNewPassword] = useState('');
|
||||||
|
const logo = getLogo();
|
||||||
|
|
||||||
|
const [countdown, setCountdown] = useState(30);
|
||||||
|
|
||||||
const [searchParams, setSearchParams] = useSearchParams();
|
const [searchParams, setSearchParams] = useSearchParams();
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -68,7 +62,7 @@ const PasswordResetConfirm = () => {
|
|||||||
let password = res.data.data;
|
let password = res.data.data;
|
||||||
setNewPassword(password);
|
setNewPassword(password);
|
||||||
await copy(password);
|
await copy(password);
|
||||||
showNotice(`新密码已复制到剪贴板:${password}`);
|
showNotice(t('messages.notice.password_copied', { password }));
|
||||||
} else {
|
} else {
|
||||||
showError(message);
|
showError(message);
|
||||||
}
|
}
|
||||||
@ -90,8 +84,8 @@ const PasswordResetConfirm = () => {
|
|||||||
textAlign='center'
|
textAlign='center'
|
||||||
style={{ marginBottom: '1.5em' }}
|
style={{ marginBottom: '1.5em' }}
|
||||||
>
|
>
|
||||||
<Image src='/logo.png' style={{ marginBottom: '10px' }} />
|
<Image src={logo} style={{ marginBottom: '10px' }} />
|
||||||
<Header.Content>密码重置确认</Header.Content>
|
<Header.Content>{t('auth.reset.confirm.title')}</Header.Content>
|
||||||
</Header>
|
</Header>
|
||||||
</Card.Header>
|
</Card.Header>
|
||||||
<Form size='large'>
|
<Form size='large'>
|
||||||
@ -99,7 +93,7 @@ const PasswordResetConfirm = () => {
|
|||||||
fluid
|
fluid
|
||||||
icon='mail'
|
icon='mail'
|
||||||
iconPosition='left'
|
iconPosition='left'
|
||||||
placeholder='邮箱地址'
|
placeholder={t('auth.reset.email')}
|
||||||
name='email'
|
name='email'
|
||||||
value={email}
|
value={email}
|
||||||
readOnly
|
readOnly
|
||||||
@ -110,7 +104,7 @@ const PasswordResetConfirm = () => {
|
|||||||
fluid
|
fluid
|
||||||
icon='lock'
|
icon='lock'
|
||||||
iconPosition='left'
|
iconPosition='left'
|
||||||
placeholder='新密码'
|
placeholder={t('auth.reset.confirm.new_password')}
|
||||||
name='newPassword'
|
name='newPassword'
|
||||||
value={newPassword}
|
value={newPassword}
|
||||||
readOnly
|
readOnly
|
||||||
@ -122,30 +116,29 @@ const PasswordResetConfirm = () => {
|
|||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.target.select();
|
e.target.select();
|
||||||
navigator.clipboard.writeText(newPassword);
|
navigator.clipboard.writeText(newPassword);
|
||||||
showNotice(`密码已复制到剪贴板:${newPassword}`);
|
showNotice(t('auth.reset.confirm.notice'));
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<Button
|
<Button
|
||||||
color='blue'
|
|
||||||
fluid
|
fluid
|
||||||
size='large'
|
size='large'
|
||||||
onClick={handleSubmit}
|
onClick={handleSubmit}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
disabled={disableButton}
|
disabled={disableButton}
|
||||||
style={{
|
style={{
|
||||||
background: '#2F73FF', // 使用更现代的蓝色
|
background: '#2F73FF',
|
||||||
color: 'white',
|
color: 'white',
|
||||||
marginBottom: '1.5em',
|
marginBottom: '1.5em',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{disableButton ? '密码重置完成' : '提交'}
|
{disableButton ? t('auth.reset.confirm.button_disabled') : t('auth.reset.confirm.button')}
|
||||||
</Button>
|
</Button>
|
||||||
</Form>
|
</Form>
|
||||||
{newPassword && (
|
{newPassword && (
|
||||||
<Message style={{ background: 'transparent', boxShadow: 'none' }}>
|
<Message style={{ background: 'transparent', boxShadow: 'none' }}>
|
||||||
<p style={{ fontSize: '0.9em', color: '#666' }}>
|
<p style={{ fontSize: '0.9em', color: '#666' }}>
|
||||||
新密码已生成,请点击密码框或上方按钮复制。请及时登录并修改密码!
|
{t('auth.reset.confirm.notice')}
|
||||||
</p>
|
</p>
|
||||||
</Message>
|
</Message>
|
||||||
)}
|
)}
|
||||||
|
@ -8,21 +8,23 @@ import {
|
|||||||
Card,
|
Card,
|
||||||
Message,
|
Message,
|
||||||
} from 'semantic-ui-react';
|
} from 'semantic-ui-react';
|
||||||
import { API, showError, showInfo, showSuccess } from '../helpers';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { API, getLogo, showError, showInfo, showSuccess } from '../helpers';
|
||||||
import Turnstile from 'react-turnstile';
|
import Turnstile from 'react-turnstile';
|
||||||
|
|
||||||
const PasswordResetForm = () => {
|
const PasswordResetForm = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
const [inputs, setInputs] = useState({
|
const [inputs, setInputs] = useState({
|
||||||
email: '',
|
email: '',
|
||||||
});
|
});
|
||||||
const { email } = inputs;
|
const { email } = inputs;
|
||||||
|
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [turnstileEnabled, setTurnstileEnabled] = useState(false);
|
const [turnstileEnabled, setTurnstileEnabled] = useState(false);
|
||||||
const [turnstileSiteKey, setTurnstileSiteKey] = useState('');
|
const [turnstileSiteKey, setTurnstileSiteKey] = useState('');
|
||||||
const [turnstileToken, setTurnstileToken] = useState('');
|
const [turnstileToken, setTurnstileToken] = useState('');
|
||||||
const [disableButton, setDisableButton] = useState(false);
|
const [disableButton, setDisableButton] = useState(false);
|
||||||
const [countdown, setCountdown] = useState(30);
|
const [countdown, setCountdown] = useState(30);
|
||||||
|
const logo = getLogo();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let status = localStorage.getItem('status');
|
let status = localStorage.getItem('status');
|
||||||
@ -66,10 +68,12 @@ const PasswordResetForm = () => {
|
|||||||
);
|
);
|
||||||
const { success, message } = res.data;
|
const { success, message } = res.data;
|
||||||
if (success) {
|
if (success) {
|
||||||
showSuccess('重置邮件发送成功,请检查邮箱!');
|
showSuccess(t('auth.reset.notice'));
|
||||||
setInputs({ ...inputs, email: '' });
|
setInputs({ ...inputs, email: '' });
|
||||||
} else {
|
} else {
|
||||||
showError(message);
|
showError(message);
|
||||||
|
setDisableButton(false);
|
||||||
|
setCountdown(30);
|
||||||
}
|
}
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
@ -89,8 +93,8 @@ const PasswordResetForm = () => {
|
|||||||
textAlign='center'
|
textAlign='center'
|
||||||
style={{ marginBottom: '1.5em' }}
|
style={{ marginBottom: '1.5em' }}
|
||||||
>
|
>
|
||||||
<Image src='/logo.png' style={{ marginBottom: '10px' }} />
|
<Image src={logo} style={{ marginBottom: '10px' }} />
|
||||||
<Header.Content>密码重置</Header.Content>
|
<Header.Content>{t('auth.reset.title')}</Header.Content>
|
||||||
</Header>
|
</Header>
|
||||||
</Card.Header>
|
</Card.Header>
|
||||||
<Form size='large'>
|
<Form size='large'>
|
||||||
@ -98,7 +102,7 @@ const PasswordResetForm = () => {
|
|||||||
fluid
|
fluid
|
||||||
icon='mail'
|
icon='mail'
|
||||||
iconPosition='left'
|
iconPosition='left'
|
||||||
placeholder='邮箱地址'
|
placeholder={t('auth.reset.email')}
|
||||||
name='email'
|
name='email'
|
||||||
value={email}
|
value={email}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
@ -133,12 +137,12 @@ const PasswordResetForm = () => {
|
|||||||
marginBottom: '1.5em',
|
marginBottom: '1.5em',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{disableButton ? `重试 (${countdown})` : '提交'}
|
{disableButton ? t('auth.register.get_code_retry', { countdown }) : t('auth.reset.button')}
|
||||||
</Button>
|
</Button>
|
||||||
</Form>
|
</Form>
|
||||||
<Message style={{ background: 'transparent', boxShadow: 'none' }}>
|
<Message style={{ background: 'transparent', boxShadow: 'none' }}>
|
||||||
<p style={{ fontSize: '0.9em', color: '#666' }}>
|
<p style={{ fontSize: '0.9em', color: '#666' }}>
|
||||||
系统将向您的邮箱发送一封包含重置链接的邮件,请注意查收。
|
{t('auth.reset.notice')}
|
||||||
</p>
|
</p>
|
||||||
</Message>
|
</Message>
|
||||||
</Card.Content>
|
</Card.Content>
|
||||||
|
@ -6,15 +6,16 @@ import {
|
|||||||
Header,
|
Header,
|
||||||
Image,
|
Image,
|
||||||
Message,
|
Message,
|
||||||
Segment,
|
|
||||||
Card,
|
Card,
|
||||||
Divider,
|
Divider,
|
||||||
} from 'semantic-ui-react';
|
} from 'semantic-ui-react';
|
||||||
import { Link, useNavigate } from 'react-router-dom';
|
import { Link, useNavigate } from 'react-router-dom';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { API, getLogo, showError, showInfo, showSuccess } from '../helpers';
|
import { API, getLogo, showError, showInfo, showSuccess } from '../helpers';
|
||||||
import Turnstile from 'react-turnstile';
|
import Turnstile from 'react-turnstile';
|
||||||
|
|
||||||
const RegisterForm = () => {
|
const RegisterForm = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
const [inputs, setInputs] = useState({
|
const [inputs, setInputs] = useState({
|
||||||
username: '',
|
username: '',
|
||||||
password: '',
|
password: '',
|
||||||
@ -28,6 +29,8 @@ const RegisterForm = () => {
|
|||||||
const [turnstileSiteKey, setTurnstileSiteKey] = useState('');
|
const [turnstileSiteKey, setTurnstileSiteKey] = useState('');
|
||||||
const [turnstileToken, setTurnstileToken] = useState('');
|
const [turnstileToken, setTurnstileToken] = useState('');
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [disableButton, setDisableButton] = useState(false);
|
||||||
|
const [countdown, setCountdown] = useState(30);
|
||||||
const logo = getLogo();
|
const logo = getLogo();
|
||||||
let affCode = new URLSearchParams(window.location.search).get('aff');
|
let affCode = new URLSearchParams(window.location.search).get('aff');
|
||||||
if (affCode) {
|
if (affCode) {
|
||||||
@ -46,6 +49,19 @@ const RegisterForm = () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
let countdownInterval = null;
|
||||||
|
if (disableButton && countdown > 0) {
|
||||||
|
countdownInterval = setInterval(() => {
|
||||||
|
setCountdown(countdown - 1);
|
||||||
|
}, 1000);
|
||||||
|
} else if (countdown === 0) {
|
||||||
|
setDisableButton(false);
|
||||||
|
setCountdown(30);
|
||||||
|
}
|
||||||
|
return () => clearInterval(countdownInterval);
|
||||||
|
}, [disableButton, countdown]);
|
||||||
|
|
||||||
let navigate = useNavigate();
|
let navigate = useNavigate();
|
||||||
|
|
||||||
function handleChange(e) {
|
function handleChange(e) {
|
||||||
@ -56,16 +72,16 @@ const RegisterForm = () => {
|
|||||||
|
|
||||||
async function handleSubmit(e) {
|
async function handleSubmit(e) {
|
||||||
if (password.length < 8) {
|
if (password.length < 8) {
|
||||||
showInfo('密码长度不得小于 8 位!');
|
showInfo(t('messages.error.password_length'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (password !== password2) {
|
if (password !== password2) {
|
||||||
showInfo('两次输入的密码不一致');
|
showInfo(t('messages.error.password_mismatch'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (username && password) {
|
if (username && password) {
|
||||||
if (turnstileEnabled && turnstileToken === '') {
|
if (turnstileEnabled && turnstileToken === '') {
|
||||||
showInfo('请稍后几秒重试,Turnstile 正在检查用户环境!');
|
showInfo(t('messages.error.turnstile_wait'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
@ -80,7 +96,7 @@ const RegisterForm = () => {
|
|||||||
const { success, message } = res.data;
|
const { success, message } = res.data;
|
||||||
if (success) {
|
if (success) {
|
||||||
navigate('/login');
|
navigate('/login');
|
||||||
showSuccess('注册成功!');
|
showSuccess(t('messages.success.register'));
|
||||||
} else {
|
} else {
|
||||||
showError(message);
|
showError(message);
|
||||||
}
|
}
|
||||||
@ -91,18 +107,21 @@ const RegisterForm = () => {
|
|||||||
const sendVerificationCode = async () => {
|
const sendVerificationCode = async () => {
|
||||||
if (inputs.email === '') return;
|
if (inputs.email === '') return;
|
||||||
if (turnstileEnabled && turnstileToken === '') {
|
if (turnstileEnabled && turnstileToken === '') {
|
||||||
showInfo('请稍后几秒重试,Turnstile 正在检查用户环境!');
|
showInfo(t('messages.error.turnstile_wait'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
setDisableButton(true);
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
const res = await API.get(
|
const res = await API.get(
|
||||||
`/api/verification?email=${inputs.email}&turnstile=${turnstileToken}`
|
`/api/verification?email=${inputs.email}&turnstile=${turnstileToken}`
|
||||||
);
|
);
|
||||||
const { success, message } = res.data;
|
const { success, message } = res.data;
|
||||||
if (success) {
|
if (success) {
|
||||||
showSuccess('验证码发送成功,请检查你的邮箱!');
|
showSuccess(t('messages.success.verification_code'));
|
||||||
} else {
|
} else {
|
||||||
showError(message);
|
showError(message);
|
||||||
|
setDisableButton(false);
|
||||||
|
setCountdown(30);
|
||||||
}
|
}
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
};
|
};
|
||||||
@ -123,7 +142,7 @@ const RegisterForm = () => {
|
|||||||
style={{ marginBottom: '1.5em' }}
|
style={{ marginBottom: '1.5em' }}
|
||||||
>
|
>
|
||||||
<Image src={logo} style={{ marginBottom: '10px' }} />
|
<Image src={logo} style={{ marginBottom: '10px' }} />
|
||||||
<Header.Content>新用户注册</Header.Content>
|
<Header.Content>{t('auth.register.title')}</Header.Content>
|
||||||
</Header>
|
</Header>
|
||||||
</Card.Header>
|
</Card.Header>
|
||||||
<Form size='large'>
|
<Form size='large'>
|
||||||
@ -131,7 +150,7 @@ const RegisterForm = () => {
|
|||||||
fluid
|
fluid
|
||||||
icon='user'
|
icon='user'
|
||||||
iconPosition='left'
|
iconPosition='left'
|
||||||
placeholder='输入用户名,最长 12 位'
|
placeholder={t('auth.register.username')}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
name='username'
|
name='username'
|
||||||
style={{ marginBottom: '1em' }}
|
style={{ marginBottom: '1em' }}
|
||||||
@ -140,7 +159,7 @@ const RegisterForm = () => {
|
|||||||
fluid
|
fluid
|
||||||
icon='lock'
|
icon='lock'
|
||||||
iconPosition='left'
|
iconPosition='left'
|
||||||
placeholder='输入密码,最短 8 位,最长 20 位'
|
placeholder={t('auth.register.password')}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
name='password'
|
name='password'
|
||||||
type='password'
|
type='password'
|
||||||
@ -150,7 +169,7 @@ const RegisterForm = () => {
|
|||||||
fluid
|
fluid
|
||||||
icon='lock'
|
icon='lock'
|
||||||
iconPosition='left'
|
iconPosition='left'
|
||||||
placeholder='再次输入密码'
|
placeholder={t('auth.register.confirm_password')}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
name='password2'
|
name='password2'
|
||||||
type='password'
|
type='password'
|
||||||
@ -163,7 +182,7 @@ const RegisterForm = () => {
|
|||||||
fluid
|
fluid
|
||||||
icon='mail'
|
icon='mail'
|
||||||
iconPosition='left'
|
iconPosition='left'
|
||||||
placeholder='输入邮箱地址'
|
placeholder={t('auth.register.email')}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
name='email'
|
name='email'
|
||||||
type='email'
|
type='email'
|
||||||
@ -171,9 +190,10 @@ const RegisterForm = () => {
|
|||||||
<Button
|
<Button
|
||||||
onClick={sendVerificationCode}
|
onClick={sendVerificationCode}
|
||||||
disabled={loading}
|
disabled={loading}
|
||||||
// style={{ backgroundColor: '#2F73FF', color: 'white' }}
|
|
||||||
>
|
>
|
||||||
获取验证码
|
{disableButton
|
||||||
|
? t('auth.register.get_code_retry', { countdown })
|
||||||
|
: t('auth.register.get_code')}
|
||||||
</Button>
|
</Button>
|
||||||
}
|
}
|
||||||
style={{ marginBottom: '1em' }}
|
style={{ marginBottom: '1em' }}
|
||||||
@ -182,7 +202,7 @@ const RegisterForm = () => {
|
|||||||
fluid
|
fluid
|
||||||
icon='lock'
|
icon='lock'
|
||||||
iconPosition='left'
|
iconPosition='left'
|
||||||
placeholder='输入验证码'
|
placeholder={t('auth.register.verification_code')}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
name='verification_code'
|
name='verification_code'
|
||||||
style={{ marginBottom: '1em' }}
|
style={{ marginBottom: '1em' }}
|
||||||
@ -218,7 +238,7 @@ const RegisterForm = () => {
|
|||||||
}}
|
}}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
>
|
>
|
||||||
注册
|
{t('auth.register.button')}
|
||||||
</Button>
|
</Button>
|
||||||
</Form>
|
</Form>
|
||||||
|
|
||||||
@ -231,9 +251,9 @@ const RegisterForm = () => {
|
|||||||
color: '#666',
|
color: '#666',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
已有账户?
|
{t('auth.register.has_account')}
|
||||||
<Link to='/login' style={{ color: '#2185d0' }}>
|
<Link to='/login' style={{ color: '#2185d0' }}>
|
||||||
点击登录
|
{t('auth.register.login')}
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</Message>
|
</Message>
|
||||||
|
Loading…
Reference in New Issue
Block a user