LoginPage.tsx
4.96 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
import { useEffect, useState } from 'react'
import { useNavigate } from 'react-router-dom'
import { Button, Form, Input, Select, message } from 'antd'
import { getBrands, login, type BrandVO } from '../../api/auth'
import { setCredentials } from '../../store/slices/authSlice'
import { activateTab } from '../../store/slices/tabsSlice'
import { useAppDispatch } from '../../store/hooks'
const ANTLER_PATHS = [
'M14 10c2 4 1 8-1 11 3-1 7 0 10 3 1-4 4-7 8-7-3 3-4 7-3 11l4 1c-1 3 0 6 3 8-3 0-6 1-8 4-1-3-4-5-8-5 2-3 2-7 0-10-3 1-7 0-10-3 3 0 5-2 6-5l-1-8z',
'M48 14c-2 3-2 6-1 9-2-2-5-2-8-1 1 3 1 6-1 9 3 0 5 2 6 5 1-3 4-5 7-5-2-3-2-6 0-9 2 1 5 1 7-1-2 0-4-1-5-3-1-2-3-4-5-4z',
'M28 38c2 3 5 5 9 5 1 4 4 7 8 8-3 2-5 5-5 9-3-2-7-3-11-2 1-3 1-7-1-10-3 0-6-1-8-4 3-1 6-3 8-6z',
]
export default function LoginPage() {
const [brandOptions, setBrandOptions] = useState<BrandVO[]>([])
const [loading, setLoading] = useState(false)
const [form] = Form.useForm()
const dispatch = useAppDispatch()
const navigate = useNavigate()
useEffect(() => {
getBrands().then(brands => {
setBrandOptions(brands)
const std = brands.find(b => b.sName === '标准版')
const defaultNo = std ? std.sNo : brands[0]?.sNo
if (defaultNo) form.setFieldValue('brandNo', defaultNo)
}).catch(() => {})
}, [form])
const onFinish = async (values: { brandNo: string; username: string; password: string }) => {
setLoading(true)
try {
const result = await login(values)
dispatch(setCredentials({ accessToken: result.accessToken, refreshToken: result.refreshToken, userInfo: result.userInfo }))
dispatch(activateTab('main'))
navigate('/')
} catch (e: unknown) {
message.error(e instanceof Error ? e.message : '登录失败')
} finally {
setLoading(false)
}
}
return (
<div style={{ position: 'absolute', inset: 0, background: 'var(--color-login-bg)', display: 'flex', flexDirection: 'column' }}>
{/* Header */}
<div style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '18px 36px' }}>
<div style={{ width: 42, height: 42, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
<svg viewBox="0 0 64 64" width={42} height={42} fill="#0e1216">
{ANTLER_PATHS.map((d, i) => <path key={i} d={d} />)}
</svg>
</div>
<span style={{ fontSize: 24, fontWeight: 700, color: 'var(--color-login-brand)', letterSpacing: 2 }}>Antler ERP</span>
<span style={{ color: '#444', fontSize: 14, marginLeft: 6 }}>欢迎登录EBC平台</span>
</div>
{/* Hero */}
<div style={{ flex: 1, position: 'relative', background: 'radial-gradient(ellipse at center, var(--color-login-hero-start) 0%, var(--color-login-hero-mid) 60%, var(--color-login-hero-end) 100%)', overflow: 'hidden' }}>
{/* Brand text */}
<div style={{ position: 'absolute', left: '8%', top: '35%', color: '#fff', zIndex: 2 }}>
<div style={{ fontSize: 30, fontWeight: 300, color: '#cfe1ff', marginBottom: 6 }}>Enterprise Business Capability</div>
<div style={{ fontSize: 54, fontWeight: 700, letterSpacing: 4, marginBottom: 4 }}>企业业务能力平台</div>
<div style={{ fontSize: 90, fontWeight: 800, letterSpacing: 8, lineHeight: 0.9 }}>ERP</div>
</div>
{/* Login card */}
<div style={{ position: 'absolute', right: '8%', top: '50%', transform: 'translateY(-50%)', background: '#fff', width: 380, padding: '36px 32px', borderRadius: 2, boxShadow: '0 12px 40px rgba(0,0,0,.3)', zIndex: 3 }}>
<h3 style={{ margin: '0 0 22px', fontSize: 18, color: '#333', fontWeight: 500 }}>用户登录</h3>
<Form form={form} layout="vertical" onFinish={onFinish}>
<Form.Item label="公司/版本" name="brandNo" rules={[{ required: true, message: '请选择公司/版本' }]}>
<Select options={brandOptions.map(b => ({ value: b.sNo, label: b.sName }))} placeholder="请选择公司/版本" />
</Form.Item>
<Form.Item label="用户名" name="username" rules={[{ required: true, message: '请输入用户名' }]}>
<Input placeholder="请输入用户名" />
</Form.Item>
<Form.Item label="密码" name="password" rules={[{ required: true, message: '请输入密码' }]}>
<Input.Password placeholder="请输入密码" />
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit" loading={loading} block style={{ height: 42, fontSize: 15, letterSpacing: 8, borderRadius: 2 }}>
登 录
</Button>
</Form.Item>
</Form>
</div>
</div>
{/* Footer */}
<div style={{ background: 'var(--color-login-bg)', textAlign: 'center', padding: '14px 8px', color: 'var(--color-login-text-muted)', fontSize: 12, borderTop: '1px solid var(--color-login-border)' }}>
🛠 ©Copyright Antler Software | 印刷ERP | 400-880-6237
</div>
</div>
)
}