141 lines
4.4 KiB
TypeScript
141 lines
4.4 KiB
TypeScript
import {
|
|
DashboardOutlined,
|
|
LockOutlined,
|
|
SafetyCertificateOutlined,
|
|
SettingOutlined,
|
|
UserOutlined,
|
|
} from '@ant-design/icons'
|
|
import { App, Button, Form, Input } from 'antd'
|
|
import { useState } from 'react'
|
|
import { useNavigate } from 'react-router'
|
|
|
|
import { loginAdmin } from '@/services/admin'
|
|
import { setAdminSession } from '@/utils/admin-auth'
|
|
|
|
type LoginForm = {
|
|
username: string
|
|
password: string
|
|
}
|
|
|
|
const brandFeatures = [
|
|
{
|
|
icon: <DashboardOutlined />,
|
|
title: '运营看板',
|
|
desc: '订单、打手、财务数据一目了然',
|
|
},
|
|
{
|
|
icon: <SafetyCertificateOutlined />,
|
|
title: '权限管控',
|
|
desc: '按角色开放操作,操作可审计',
|
|
},
|
|
{
|
|
icon: <SettingOutlined />,
|
|
title: '灵活配置',
|
|
desc: '平台、规则、费率在线可调',
|
|
},
|
|
]
|
|
|
|
export default function AdminLoginPage() {
|
|
const navigate = useNavigate()
|
|
const { message } = App.useApp()
|
|
const [loading, setLoading] = useState(false)
|
|
|
|
async function submitLogin(values: LoginForm) {
|
|
setLoading(true)
|
|
|
|
try {
|
|
const response = await loginAdmin({
|
|
username: values.username.trim(),
|
|
password: values.password.trim(),
|
|
})
|
|
setAdminSession(response.data.token, response.data.expiresAt, response.data.user)
|
|
message.success('登录成功')
|
|
navigate('/admin/dashboard', { replace: true })
|
|
} catch (error) {
|
|
message.error(error instanceof Error ? error.message : '后台登录失败')
|
|
} finally {
|
|
setLoading(false)
|
|
}
|
|
}
|
|
|
|
return (
|
|
<main className="auth-page">
|
|
<div className="auth-shell">
|
|
{/* 品牌信息区:移动端隐藏 */}
|
|
<aside className="auth-brand">
|
|
<div className="auth-brand-logo">
|
|
<span className="auth-logo-mark">
|
|
<DashboardOutlined />
|
|
</span>
|
|
<strong>Order Site Admin</strong>
|
|
</div>
|
|
|
|
<div className="auth-brand-body">
|
|
<h2>运营后台管理中心</h2>
|
|
<p>统一管理订单履约、打手调度与财务结算,按角色开放不同操作权限。</p>
|
|
<div className="auth-brand-features">
|
|
{brandFeatures.map((item) => (
|
|
<div className="auth-brand-feature" key={item.title}>
|
|
<span className="auth-feature-icon">{item.icon}</span>
|
|
<div className="auth-brand-feature-text">
|
|
<strong>{item.title}</strong>
|
|
<span>{item.desc}</span>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
<div className="auth-brand-footer">
|
|
© {new Date().getFullYear()} Order Site · 保留所有权利
|
|
</div>
|
|
</aside>
|
|
|
|
{/* 登录表单区 */}
|
|
<section className="auth-form-side">
|
|
<div className="auth-form-card">
|
|
{/* 移动端精简品牌栏 */}
|
|
<div className="auth-mobile-brand">
|
|
<span className="auth-logo-mark">
|
|
<DashboardOutlined />
|
|
</span>
|
|
<strong>Order Site Admin</strong>
|
|
</div>
|
|
|
|
<div className="auth-form-header">
|
|
<h1>运营后台登录</h1>
|
|
<p>使用账号密码进入后台,并按角色开放不同操作权限</p>
|
|
</div>
|
|
|
|
<Form<LoginForm> layout="vertical" requiredMark={false} onFinish={submitLogin}>
|
|
<Form.Item
|
|
name="username"
|
|
label="账号"
|
|
rules={[{ required: true, message: '请输入账号' }]}
|
|
>
|
|
<Input prefix={<UserOutlined />} placeholder="输入账号" autoComplete="username" />
|
|
</Form.Item>
|
|
<Form.Item
|
|
name="password"
|
|
label="密码"
|
|
rules={[{ required: true, message: '请输入密码' }]}
|
|
>
|
|
<Input.Password
|
|
prefix={<LockOutlined />}
|
|
placeholder="输入密码"
|
|
autoComplete="current-password"
|
|
/>
|
|
</Form.Item>
|
|
<Button type="primary" htmlType="submit" block loading={loading} size="large">
|
|
登录后台
|
|
</Button>
|
|
</Form>
|
|
|
|
<div className="auth-form-footer">仅限授权运营人员访问</div>
|
|
</div>
|
|
</section>
|
|
</div>
|
|
</main>
|
|
)
|
|
}
|