imetting/frontend/src/pages/HomePage.jsx

169 lines
5.5 KiB
JavaScript

import React, { useEffect, useState } from 'react';
import {
Row, Col, Typography, Button,
Form, Input, Space, Tabs, App
} from 'antd';
import {
UserOutlined,
LockOutlined,
ArrowRightOutlined,
} from '@ant-design/icons';
import apiClient from '../utils/apiClient';
import { buildApiUrl, API_ENDPOINTS } from '../config/api';
import menuService from '../services/menuService';
import BrandLogo from '../components/BrandLogo';
import configService, { DEFAULT_BRANDING_CONFIG } from '../utils/configService';
const { Title, Paragraph, Text } = Typography;
const HomePage = ({ onLogin }) => {
const [loading, setLoading] = useState(false);
const [branding, setBranding] = useState(DEFAULT_BRANDING_CONFIG);
const { message } = App.useApp();
useEffect(() => {
configService.getBrandingConfig().then(setBranding).catch(() => {});
}, []);
const handleLogin = async (values) => {
setLoading(true);
try {
const response = await apiClient.post(buildApiUrl(API_ENDPOINTS.AUTH.LOGIN), {
username: values.username,
password: values.password
});
if (response.code === '200') {
message.success('登录成功');
// 关键修复:保存整个 data 对象,因为它包含了 token 和 user 两个部分
const authData = response.data;
localStorage.setItem('iMeetingUser', JSON.stringify(authData));
menuService.clearCache();
// 通知 App 组件更新状态
onLogin(authData);
// 入口页会根据当前用户的首个菜单做动态跳转
window.location.href = '/';
} else {
message.error(response.message || '登录失败');
}
} catch (error) {
console.error('Login error:', error);
message.error(error.response?.data?.message || '账号或密码错误');
} finally {
setLoading(false);
}
};
return (
<div style={{ minHeight: '100vh', display: 'flex', background: '#fff' }}>
<Row style={{ width: '100%' }}>
{/* 左侧:品牌展示区 */}
<Col xs={0} lg={14} style={{
background: '#ebf2ff',
padding: '60px 80px',
display: 'flex',
flexDirection: 'column',
justifyContent: 'center'
}}>
<div style={{ marginBottom: 80 }}>
<BrandLogo title={branding.app_name} size={48} titleSize={24} gap={12} titleColor="#6f42c1" />
</div>
<div style={{ maxWidth: 600 }}>
<Title style={{ fontSize: 56, marginBottom: 24, fontWeight: 800 }}>
<span style={{ color: '#1677ff' }}>{branding.home_headline}</span>
</Title>
<Paragraph style={{ fontSize: 20, color: '#4e5969', lineHeight: 1.6 }}>
{branding.home_tagline}
</Paragraph>
</div>
</Col>
{/* 右侧:登录交互区 */}
<Col xs={24} lg={10} style={{
padding: '40px',
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
background: '#fff'
}}>
<div style={{ width: '100%', maxWidth: 400 }}>
<Tabs
className="console-tabs"
defaultActiveKey="login"
size="large"
style={{ marginBottom: 32 }}
items={[
{ key: 'login', label: '账号登录' },
{ key: 'register', label: '注册账号', disabled: true }
]}
/>
<div style={{ marginBottom: 40 }}>
<Paragraph type="secondary" style={{ fontSize: 16 }}>
{branding.login_welcome}
</Paragraph>
</div>
<Form layout="vertical" onFinish={handleLogin} size="large">
<Form.Item
label={<Text strong>用户名</Text>}
name="username"
rules={[{ required: true, message: '请输入用户名' }]}
>
<Input
prefix={<UserOutlined style={{ color: '#bfbfbf' }} />}
placeholder="请输入用户名"
style={{ borderRadius: 8, height: 50 }}
/>
</Form.Item>
<Form.Item
label={<Text strong>密码</Text>}
name="password"
rules={[{ required: true, message: '请输入密码' }]}
>
<Input.Password
prefix={<LockOutlined style={{ color: '#bfbfbf' }} />}
placeholder="请输入密码"
style={{ borderRadius: 8, height: 50 }}
/>
</Form.Item>
<Form.Item style={{ marginTop: 48 }}>
<Button
type="primary"
icon={<ArrowRightOutlined />}
htmlType="submit"
block
loading={loading}
style={{
height: 50,
fontSize: 16,
borderRadius: 8,
fontWeight: 600
}}
>
立即登录
</Button>
</Form.Item>
</Form>
<div style={{ marginTop: 100, textAlign: 'center' }}>
<Text type="secondary" style={{ fontSize: 13 }}>
{branding.footer_text}
</Text>
</div>
</div>
</Col>
</Row>
</div>
);
};
export default HomePage;