feat(web): 初始化前端项目

This commit is contained in:
R524809
2026-09-03 13:11:38 +08:00
parent 195b6d25e9
commit df40ddde8c
31 changed files with 948 additions and 848 deletions
+67 -63
View File
@@ -10,76 +10,80 @@ import { authToken } from '@/services/authToken';
import { emailFormatRule } from '@/utils/validators';
interface LoginFormValues {
email: string;
password: string;
email: string;
password: string;
}
/** 登录页,契约见 docs/api/auth.md §3 */
const LoginPage = () => {
const navigate = useNavigate();
const { message } = AntdApp.useApp();
const [submitting, setSubmitting] = useState(false);
const navigate = useNavigate();
const { message } = AntdApp.useApp();
const [submitting, setSubmitting] = useState(false);
const handleFinish = async (values: LoginFormValues) => {
setSubmitting(true);
try {
const session = await authApi.login({
email: values.email.trim(),
password: values.password,
});
authToken.set(session.access_token);
message.success('登录成功');
navigate('/online-products', { replace: true });
} catch (error) {
// 契约约定登录失败统一返回 401 INVALID_CREDENTIALS,不区分邮箱不存在或密码错误
if (axios.isAxiosError(error) && error.response?.status === 401) {
message.error('邮箱或密码不正确');
} else {
message.error(apiErrorMessage(error));
}
} finally {
setSubmitting(false);
}
};
const handleFinish = async (values: LoginFormValues) => {
setSubmitting(true);
try {
const session = await authApi.login({
email: values.email.trim(),
password: values.password,
});
authToken.set(session.access_token);
message.success('登录成功');
navigate('/online-products', { replace: true });
} catch (error) {
// 契约约定登录失败统一返回 401 INVALID_CREDENTIALS,不区分邮箱不存在或密码错误
if (axios.isAxiosError(error) && error.response?.status === 401) {
message.error('邮箱或密码不正确');
} else {
message.error(apiErrorMessage(error));
}
} finally {
setSubmitting(false);
}
};
return (
<AuthLayout
title="登录"
subtitle="登录 Atlas Seller Kit,继续管理你的商品"
footer={
<>
还没有账户?<Link to="/register">立即注册</Link>
</>
}
>
<Form<LoginFormValues> layout="vertical" requiredMark={false} onFinish={handleFinish}>
<Form.Item
name="email"
label="邮箱"
rules={[{ required: true, message: '请输入邮箱' }, emailFormatRule]}
return (
<AuthLayout
title="登录"
subtitle="登录 Atlas Seller Kit,继续管理你的商品"
footer={
<>
还没有账户?<Link to="/register">立即注册</Link>
</>
}
>
<Input
prefix={<MailOutlined style={{ color: 'var(--text-secondary)' }} />}
placeholder="请输入邮箱"
autoComplete="email"
autoFocus
/>
</Form.Item>
<Form.Item name="password" label="密码" rules={[{ required: true, message: '请输入密码' }]}>
<Input.Password
prefix={<LockOutlined style={{ color: 'var(--text-secondary)' }} />}
placeholder="请输入密码"
autoComplete="current-password"
/>
</Form.Item>
<Form.Item style={{ marginBottom: 0, marginTop: 8 }}>
<Button type="primary" htmlType="submit" block loading={submitting}>
登录
</Button>
</Form.Item>
</Form>
</AuthLayout>
);
<Form<LoginFormValues> layout="vertical" requiredMark={false} onFinish={handleFinish}>
<Form.Item
name="email"
label="邮箱"
rules={[{ required: true, message: '请输入邮箱' }, emailFormatRule]}
>
<Input
prefix={<MailOutlined style={{ color: 'var(--text-secondary)' }} />}
placeholder="请输入邮箱"
autoComplete="email"
autoFocus
/>
</Form.Item>
<Form.Item
name="password"
label="密码"
rules={[{ required: true, message: '请输入密码' }]}
>
<Input.Password
prefix={<LockOutlined style={{ color: 'var(--text-secondary)' }} />}
placeholder="请输入密码"
autoComplete="current-password"
/>
</Form.Item>
<Form.Item style={{ marginBottom: 0, marginTop: 8 }}>
<Button type="primary" htmlType="submit" block loading={submitting}>
登录
</Button>
</Form.Item>
</Form>
</AuthLayout>
);
};
export default LoginPage;