This commit is contained in:
2026-06-16 17:09:24 +08:00
parent 3b5477cc2a
commit 75a7724f8d
2 changed files with 135 additions and 24 deletions
+116 -22
View File
@@ -1,13 +1,39 @@
import { useState } from 'react'; import { useState, useEffect } from 'react';
import { Button, Card, Form, Input, message, Typography, Checkbox } from 'antd'; import { Button, Card, Form, Input, message, Typography, Checkbox } from 'antd';
import { UserOutlined, LockOutlined, ThunderboltOutlined } from '@ant-design/icons'; import { UserOutlined, LockOutlined, ThunderboltOutlined } from '@ant-design/icons';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { useAdminStore } from '../store'; import { useAdminStore } from '../store';
import { getSiteInfo } from '../api';
const AdminLoginPage = () => { const AdminLoginPage = () => {
const navigate = useNavigate(); const navigate = useNavigate();
const { login } = useAdminStore(); const { login } = useAdminStore();
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const getInitialSiteInfo = () => {
try {
const cached = localStorage.getItem('siteInfo');
if (cached) {
const info = JSON.parse(cached);
return {
siteName: info.siteName || 'VideoGen.AI',
siteLogo: info.siteLogo || '',
};
}
} catch { }
return { siteName: 'VideoGen.AI', siteLogo: '' };
};
const initialInfo = getInitialSiteInfo();
const [siteName, setSiteName] = useState(initialInfo.siteName);
const [siteLogo, setSiteLogo] = useState(initialInfo.siteLogo);
useEffect(() => {
getSiteInfo().then(info => {
setSiteName(info.siteName);
setSiteLogo(info.siteLogo);
}).catch(() => {});
}, []);
const handleLogin = async (values: { username: string; password: string; rememberMe?: boolean }) => { const handleLogin = async (values: { username: string; password: string; rememberMe?: boolean }) => {
setLoading(true); setLoading(true);
@@ -24,45 +50,113 @@ const AdminLoginPage = () => {
return ( return (
<div style={{ <div style={{
minHeight: '100vh', display: 'flex', alignItems: 'center', justifyContent: 'center', minHeight: '100vh',
background: 'linear-gradient(135deg, #0f0f23 0%, #1a1a35 50%, #0f0f23 100%)', display: 'flex',
alignItems: 'center',
justifyContent: 'center',
background: 'linear-gradient(135deg, #f0f4ff 0%, #e8ecf8 40%, #f0f0ff 70%, #f8f9ff 100%)',
position: 'relative',
overflow: 'hidden',
}}> }}>
<div style={{
position: 'absolute',
width: 500, height: 500, borderRadius: '50%',
background: 'radial-gradient(circle, rgba(99,102,241,0.08) 0%, transparent 70%)',
top: -150, right: -100, filter: 'blur(40px)',
}} />
<div style={{
position: 'absolute',
width: 400, height: 400, borderRadius: '50%',
background: 'radial-gradient(circle, rgba(139,92,246,0.06) 0%, transparent 70%)',
bottom: -100, left: -80, filter: 'blur(50px)',
}} />
<Card bordered={false} style={{ <Card bordered={false} style={{
width: 420, borderRadius: 16, boxShadow: '0 20px 60px rgba(0,0,0,0.3)', width: 440,
}}> borderRadius: 20,
{/* Logo */} boxShadow: '0 20px 60px rgba(0,0,0,0.08)',
<div style={{ textAlign: 'center', marginBottom: 32 }}> border: '1px solid #e2e8f0',
background: '#fff',
zIndex: 1,
}} styles={{ body: { padding: '36px 28px' } }}>
<div style={{ textAlign: 'center', marginBottom: 28 }}>
<div style={{ <div style={{
width: 56, height: 56, borderRadius: 14, margin: '0 auto 16px', width: 52,
background: 'linear-gradient(135deg, #6366f1, #8b5cf6)', height: 52,
display: 'flex', alignItems: 'center', justifyContent: 'center', borderRadius: 14,
boxShadow: '0 8px 24px rgba(99,102,241,0.3)', margin: '0 auto 16px',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
background: siteLogo
? 'transparent'
: 'linear-gradient(135deg, #6366f1, #8b5cf6)',
boxShadow: siteLogo ? 'none' : '0 8px 24px rgba(99,102,241,0.25)',
}}> }}>
<ThunderboltOutlined style={{ fontSize: 26, color: '#fff' }} /> {siteLogo ? (
<img src={siteLogo} alt="logo" style={{ width: '100%', height: '100%', borderRadius: 14, objectFit: 'contain' }} />
) : (
<ThunderboltOutlined style={{ fontSize: 26, color: '#fff' }} />
)}
</div> </div>
<Typography.Title level={3} style={{ margin: 0 }}> <Typography.Title level={3} style={{ margin: 0, color: '#1e293b', fontWeight: 700 }}>
VideoGen<span style={{ color: '#6366f1' }}>.AI</span> {siteName}
<span style={{ color: '#6366f1' }}>.AI</span>
</Typography.Title> </Typography.Title>
<Typography.Text type="secondary"></Typography.Text> <Typography.Text type="secondary" style={{ fontSize: 14, color: '#94a3b8' }}></Typography.Text>
</div> </div>
<Form onFinish={handleLogin} layout="vertical"> <Form onFinish={handleLogin} layout="vertical">
<Form.Item name="username" rules={[{ required: true, message: '请输入用户名' }]}> <Form.Item name="username" rules={[{ required: true, message: '请输入用户名' }]}>
<Input placeholder="用户名" size="large" prefix={<UserOutlined style={{ color: '#94a3b8', marginRight: 8 }} />} /> <Input
placeholder="用户名"
size="large"
prefix={<UserOutlined style={{ color: '#94a3b8', marginRight: 8 }} />}
style={{
background: '#fff',
border: '1.5px solid #e2e8f0',
color: '#1e293b',
height: 48,
borderRadius: 10,
fontSize: 14,
}}
/>
</Form.Item> </Form.Item>
<Form.Item name="password" rules={[{ required: true, message: '请输入密码' }]}> <Form.Item name="password" rules={[{ required: true, message: '请输入密码' }]}>
<Input.Password placeholder="密码" size="large" prefix={<LockOutlined style={{ color: '#94a3b8', marginRight: 8 }} />} /> <Input.Password
placeholder="密码"
size="large"
prefix={<LockOutlined style={{ color: '#94a3b8', marginRight: 8 }} />}
style={{
background: '#fff',
border: '1.5px solid #e2e8f0',
color: '#1e293b',
height: 48,
borderRadius: 10,
fontSize: 14,
}}
/>
</Form.Item> </Form.Item>
<Form.Item name="rememberMe" valuePropName="checked"> <Form.Item name="rememberMe" valuePropName="checked" style={{ marginBottom: 12 }}>
<Checkbox></Checkbox> <Checkbox></Checkbox>
</Form.Item> </Form.Item>
<Form.Item style={{ marginBottom: 8 }}> <Form.Item style={{ marginBottom: 8 }}>
<Button type="primary" htmlType="submit" loading={loading} block size="large" <Button
type="primary"
htmlType="submit"
loading={loading}
block
size="large"
style={{ style={{
borderRadius: 10, fontWeight: 600, height: 44, height: 48,
background: 'linear-gradient(135deg, #6366f1, #8b5cf6)', borderRadius: 10,
fontSize: 16,
fontWeight: 600,
background: 'linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%)',
border: 'none', border: 'none',
}}> boxShadow: '0 8px 24px rgba(99,102,241,0.25)',
}}
>
</Button> </Button>
</Form.Item> </Form.Item>
+19 -2
View File
@@ -25,10 +25,27 @@ const LoginPage: React.FC = () => {
const [sliderKey, setSliderKey] = useState(0); const [sliderKey, setSliderKey] = useState(0);
const [showResend, setShowResend] = useState(false); const [showResend, setShowResend] = useState(false);
const [loginShowResend, setLoginShowResend] = useState(false); const [loginShowResend, setLoginShowResend] = useState(false);
const [siteName, setSiteName] = useState('VideoGen.AI');
const [siteLogo, setSiteLogo] = useState(''); const getInitialSiteInfo = () => {
try {
const cached = localStorage.getItem('siteInfo');
if (cached) {
const info = JSON.parse(cached);
return {
siteName: info.siteName || 'VideoGen.AI',
siteLogo: info.siteLogo || '',
};
}
} catch { }
return { siteName: 'VideoGen.AI', siteLogo: '' };
};
const initialInfo = getInitialSiteInfo();
const [siteName, setSiteName] = useState(initialInfo.siteName);
const [siteLogo, setSiteLogo] = useState(initialInfo.siteLogo);
const [agreementUrl, setAgreementUrl] = useState(''); const [agreementUrl, setAgreementUrl] = useState('');
const [policyUrl, setPolicyUrl] = useState(''); const [policyUrl, setPolicyUrl] = useState('');
const navigate = useNavigate(); const navigate = useNavigate();
const { login } = useAuthStore(); const { login } = useAuthStore();
const [pwdForm] = Form.useForm(); const [pwdForm] = Form.useForm();