Files
Airwallex/frontend/src/pages/Login.tsx
zqq61 4f53889a8e feat: Airwallex 发卡管理后台完整实现
- 后端: FastAPI + SQLAlchemy + SQLite, JWT认证, 代理支持的AirwallexClient
- 前端: React 18 + Vite + Ant Design 5, 中文界面
- 功能: 卡片管理, 持卡人管理, 交易记录, API令牌, 系统设置, 审计日志
- 第三方API: X-API-Key认证, 权限控制
- Docker部署: docker-compose编排前后端
2026-03-15 23:05:08 +08:00

52 lines
1.9 KiB
TypeScript

import { useState } from 'react'
import { useNavigate } from 'react-router-dom'
import { Card, Form, Input, Button, message } from 'antd'
import { UserOutlined, LockOutlined, CreditCardOutlined } from '@ant-design/icons'
import { useAuthStore } from '@/stores/auth'
export default function Login() {
const [loading, setLoading] = useState(false)
const login = useAuthStore((s) => s.login)
const navigate = useNavigate()
const onFinish = async (values: { username: string; password: string }) => {
setLoading(true)
try {
await login(values.username, values.password)
message.success('登录成功')
navigate('/')
} catch (err: unknown) {
const error = err as { response?: { data?: { detail?: string } } }
message.error(error.response?.data?.detail || '登录失败,请检查用户名和密码')
} finally {
setLoading(false)
}
}
return (
<div className="login-container">
<Card className="login-card">
<div style={{ textAlign: 'center', marginBottom: 32 }}>
<CreditCardOutlined style={{ fontSize: 48, color: '#667eea' }} />
<h2 className="login-title" style={{ marginTop: 12 }}>
Airwallex
</h2>
</div>
<Form name="login" onFinish={onFinish} size="large" autoComplete="off">
<Form.Item name="username" rules={[{ required: true, message: '请输入用户名' }]}>
<Input prefix={<UserOutlined />} placeholder="用户名" />
</Form.Item>
<Form.Item name="password" rules={[{ required: true, message: '请输入密码' }]}>
<Input.Password prefix={<LockOutlined />} placeholder="密码" />
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit" loading={loading} block>
</Button>
</Form.Item>
</Form>
</Card>
</div>
)
}