9f4a32d6c0
- Replace error message div with Semi UI Banner component for better UX - Add rounded corners to Banner component with !rounded-lg class - Fix Form.Input not displaying values by implementing proper formApi usage - Use getFormApi callback to obtain form API instance - Replace manual value props with formApi.setValues() for dynamic updates - Set proper initValues for form initialization - Remove unused Input import and console.log statements - Clean up debugging code and optimize form state management This change enhances the visual consistency with Semi Design system and resolves the issue where email field was not showing URL parameter values.
177 lines
6.1 KiB
JavaScript
177 lines
6.1 KiB
JavaScript
import React, { useEffect, useState } from 'react';
|
|
import { API, copy, showError, showNotice, getLogo, getSystemName } from '../../helpers';
|
|
import { useSearchParams, Link } from 'react-router-dom';
|
|
import { Button, Card, Form, Typography, Banner } from '@douyinfe/semi-ui';
|
|
import { IconMail, IconLock } from '@douyinfe/semi-icons';
|
|
import { useTranslation } from 'react-i18next';
|
|
import Background from '/example.png';
|
|
|
|
const { Text, Title } = Typography;
|
|
|
|
const PasswordResetConfirm = () => {
|
|
const { t } = useTranslation();
|
|
const [inputs, setInputs] = useState({
|
|
email: '',
|
|
token: '',
|
|
});
|
|
const { email, token } = inputs;
|
|
const isValidResetLink = email && token;
|
|
|
|
const [loading, setLoading] = useState(false);
|
|
const [disableButton, setDisableButton] = useState(false);
|
|
const [countdown, setCountdown] = useState(30);
|
|
const [newPassword, setNewPassword] = useState('');
|
|
const [searchParams, setSearchParams] = useSearchParams();
|
|
const [formApi, setFormApi] = useState(null);
|
|
|
|
const logo = getLogo();
|
|
const systemName = getSystemName();
|
|
|
|
useEffect(() => {
|
|
let token = searchParams.get('token');
|
|
let email = searchParams.get('email');
|
|
setInputs({
|
|
token: token || '',
|
|
email: email || '',
|
|
});
|
|
if (formApi) {
|
|
formApi.setValues({
|
|
email: email || '',
|
|
newPassword: newPassword || ''
|
|
});
|
|
}
|
|
}, [searchParams, newPassword, formApi]);
|
|
|
|
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]);
|
|
|
|
async function handleSubmit(e) {
|
|
if (!email || !token) {
|
|
showError(t('无效的重置链接,请重新发起密码重置请求'));
|
|
return;
|
|
}
|
|
setDisableButton(true);
|
|
setLoading(true);
|
|
const res = await API.post(`/api/user/reset`, {
|
|
email,
|
|
token,
|
|
});
|
|
const { success, message } = res.data;
|
|
if (success) {
|
|
let password = res.data.data;
|
|
setNewPassword(password);
|
|
await copy(password);
|
|
showNotice(`${t('密码已重置并已复制到剪贴板')}: ${password}`);
|
|
} else {
|
|
showError(message);
|
|
}
|
|
setLoading(false);
|
|
}
|
|
|
|
return (
|
|
<div className="min-h-screen relative flex items-center justify-center py-12 px-4 sm:px-6 lg:px-8 overflow-hidden">
|
|
{/* 背景图片容器 - 放大并保持居中 */}
|
|
<div
|
|
className="absolute inset-0 z-0 bg-cover bg-center scale-125 opacity-100"
|
|
style={{
|
|
backgroundImage: `url(${Background})`
|
|
}}
|
|
></div>
|
|
|
|
{/* 半透明遮罩层 */}
|
|
<div className="absolute inset-0 bg-gradient-to-br from-teal-500/30 via-blue-500/30 to-purple-500/30 backdrop-blur-sm z-0"></div>
|
|
|
|
<div className="w-full max-w-sm relative z-10">
|
|
<div className="flex flex-col items-center">
|
|
<div className="w-full max-w-md">
|
|
<div className="flex items-center justify-center mb-6 gap-2">
|
|
<img src={logo} alt="Logo" className="h-10 rounded-full" />
|
|
<Title heading={3} className='!text-white'>{systemName}</Title>
|
|
</div>
|
|
|
|
<Card className="shadow-xl border-0 !rounded-2xl overflow-hidden">
|
|
<div className="flex justify-center pt-6 pb-2">
|
|
<Title heading={3} className="text-gray-800 dark:text-gray-200">{t('密码重置确认')}</Title>
|
|
</div>
|
|
<div className="px-2 py-8">
|
|
{!isValidResetLink && (
|
|
<Banner
|
|
type="danger"
|
|
description={t('无效的重置链接,请重新发起密码重置请求')}
|
|
className="mb-4 !rounded-lg"
|
|
closeIcon={null}
|
|
/>
|
|
)}
|
|
<Form
|
|
getFormApi={(api) => setFormApi(api)}
|
|
initValues={{ email: email || '', newPassword: newPassword || '' }}
|
|
className="space-y-4"
|
|
>
|
|
<Form.Input
|
|
field="email"
|
|
label={t('邮箱')}
|
|
name="email"
|
|
size="large"
|
|
className="!rounded-md"
|
|
disabled={true}
|
|
prefix={<IconMail />}
|
|
placeholder={email ? '' : t('等待获取邮箱信息...')}
|
|
/>
|
|
|
|
{newPassword && (
|
|
<Form.Input
|
|
field="newPassword"
|
|
label={t('新密码')}
|
|
name="newPassword"
|
|
size="large"
|
|
className="!rounded-md"
|
|
disabled={true}
|
|
prefix={<IconLock />}
|
|
onClick={(e) => {
|
|
e.target.select();
|
|
navigator.clipboard.writeText(newPassword);
|
|
showNotice(`${t('密码已复制到剪贴板')}: ${newPassword}`);
|
|
}}
|
|
/>
|
|
)}
|
|
|
|
<div className="space-y-2 pt-2">
|
|
<Button
|
|
theme="solid"
|
|
className="w-full !rounded-full"
|
|
type="primary"
|
|
htmlType="submit"
|
|
size="large"
|
|
onClick={handleSubmit}
|
|
loading={loading}
|
|
disabled={disableButton || newPassword || !isValidResetLink}
|
|
>
|
|
{newPassword ? t('密码重置完成') : t('确认重置密码')}
|
|
</Button>
|
|
</div>
|
|
</Form>
|
|
|
|
<div className="mt-6 text-center text-sm">
|
|
<Text><Link to="/login" className="text-blue-600 hover:text-blue-800 font-medium">{t('返回登录')}</Link></Text>
|
|
</div>
|
|
</div>
|
|
</Card>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default PasswordResetConfirm;
|