282 lines
8.4 KiB
JavaScript
282 lines
8.4 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 httpService from '../services/httpService';
|
|
import { buildApiUrl, API_ENDPOINTS } from '../config/api';
|
|
import menuService from '../services/menuService';
|
|
import BrandLogo from '../components/BrandLogo';
|
|
import configService from '../utils/configService';
|
|
|
|
const { Title, Paragraph, Text } = Typography;
|
|
|
|
const BRAND_HIGHLIGHTS = [
|
|
'智能转录与结构化总结',
|
|
'时间轴回看与全文检索',
|
|
'沉淀可追踪的会议资产',
|
|
];
|
|
const HOME_TAGLINE = '让每一次谈话都产生价值';
|
|
|
|
const HomePage = ({ onLogin }) => {
|
|
const [loading, setLoading] = useState(false);
|
|
const [branding, setBranding] = useState(() => configService.getCachedBrandingConfig());
|
|
const { message } = App.useApp();
|
|
|
|
useEffect(() => {
|
|
if (branding) {
|
|
return;
|
|
}
|
|
|
|
let active = true;
|
|
configService.getBrandingConfig().then((nextBranding) => {
|
|
if (active) {
|
|
setBranding(nextBranding);
|
|
}
|
|
}).catch((error) => {
|
|
console.error('Load branding config failed:', error);
|
|
});
|
|
|
|
return () => {
|
|
active = false;
|
|
};
|
|
}, [branding]);
|
|
|
|
if (!branding) {
|
|
return null;
|
|
}
|
|
|
|
const handleLogin = async (values) => {
|
|
setLoading(true);
|
|
try {
|
|
const response = await httpService.post(buildApiUrl(API_ENDPOINTS.AUTH.LOGIN), {
|
|
username: values.username,
|
|
password: values.password
|
|
});
|
|
|
|
if (response.code === '200') {
|
|
message.success('登录成功');
|
|
menuService.clearCache();
|
|
|
|
onLogin(response.data);
|
|
} 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={{ maxWidth: 640 }}>
|
|
<div style={{ marginBottom: 64 }}>
|
|
<BrandLogo title={branding.app_name} size={48} titleSize={24} gap={12} titleColor="#6f42c1" />
|
|
</div>
|
|
|
|
<div
|
|
style={{
|
|
display: 'inline-flex',
|
|
alignItems: 'center',
|
|
padding: '8px 16px',
|
|
borderRadius: 999,
|
|
marginBottom: 24,
|
|
border: '1px solid rgba(37, 99, 235, 0.14)',
|
|
background: 'rgba(255, 255, 255, 0.55)',
|
|
boxShadow: 'inset 0 1px 0 rgba(255,255,255,0.75)',
|
|
}}
|
|
>
|
|
<Text style={{ color: '#47658d', fontSize: 13, fontWeight: 700, letterSpacing: '0.08em' }}>
|
|
INTELLIGENT MEETING WORKSPACE
|
|
</Text>
|
|
</div>
|
|
|
|
<div style={{ maxWidth: 600 }}>
|
|
<div
|
|
style={{
|
|
marginBottom: 24,
|
|
display: 'flex',
|
|
alignItems: 'baseline',
|
|
gap: 18,
|
|
flexWrap: 'wrap',
|
|
}}
|
|
>
|
|
<Title
|
|
level={2}
|
|
style={{
|
|
margin: 0,
|
|
fontSize: 38,
|
|
lineHeight: 1.05,
|
|
fontWeight: 700,
|
|
letterSpacing: '0.02em',
|
|
color: '#365b8d',
|
|
}}
|
|
>
|
|
iMeeting
|
|
</Title>
|
|
|
|
<Title
|
|
level={1}
|
|
style={{
|
|
margin: 0,
|
|
fontSize: 48,
|
|
lineHeight: 1.04,
|
|
fontWeight: 800,
|
|
letterSpacing: '-0.03em',
|
|
color: '#1677ff',
|
|
}}
|
|
>
|
|
{branding.app_name}
|
|
</Title>
|
|
</div>
|
|
|
|
<Paragraph
|
|
style={{
|
|
fontSize: 22,
|
|
color: '#334e73',
|
|
lineHeight: 1.65,
|
|
marginBottom: 18,
|
|
maxWidth: 560,
|
|
}}
|
|
>
|
|
{HOME_TAGLINE}
|
|
</Paragraph>
|
|
|
|
<Paragraph
|
|
style={{
|
|
fontSize: 16,
|
|
color: '#5a718f',
|
|
lineHeight: 1.9,
|
|
marginBottom: 28,
|
|
maxWidth: 560,
|
|
}}
|
|
>
|
|
</Paragraph>
|
|
|
|
<Space size={[10, 12]} wrap>
|
|
{BRAND_HIGHLIGHTS.map((item) => (
|
|
<span
|
|
key={item}
|
|
style={{
|
|
display: 'inline-flex',
|
|
alignItems: 'center',
|
|
padding: '9px 14px',
|
|
borderRadius: 999,
|
|
border: '1px solid rgba(113, 140, 178, 0.18)',
|
|
background: 'rgba(255, 255, 255, 0.62)',
|
|
color: '#4d678b',
|
|
fontSize: 14,
|
|
fontWeight: 600,
|
|
boxShadow: '0 8px 18px rgba(40, 72, 120, 0.06)',
|
|
}}
|
|
>
|
|
{item}
|
|
</span>
|
|
))}
|
|
</Space>
|
|
</div>
|
|
</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;
|