Files
xiaoxia-saas/apps/web/src/pages/auth/Register.tsx
T
xiaoxia 3862996045
CI/CD Pipeline / Check if frontend-only change (push) Waiting to run
CI/CD Pipeline / Validate - Code Quality (push) Waiting to run
CI/CD Pipeline / Validate - Type Check (mypy) (push) Waiting to run
CI/CD Pipeline / Validate - Migration (alembic) (push) Waiting to run
CI/CD Pipeline / Unit Tests (push) Blocked by required conditions
CI/CD Pipeline / Integration Tests (push) Blocked by required conditions
CI/CD Pipeline / Frontend Lint (push) Waiting to run
CI/CD Pipeline / Frontend Unit Tests (push) Blocked by required conditions
CI/CD Pipeline / PR Build API Image (push) Waiting to run
CI/CD Pipeline / PR Build Web Image (push) Waiting to run
CI/CD Pipeline / PR Build Worker Image (push) Waiting to run
CI/CD Pipeline / Build Staging API Image (push) Waiting to run
CI/CD Pipeline / Build Staging Web Image (push) Waiting to run
CI/CD Pipeline / Build Staging Worker Image (push) Waiting to run
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Blocked by required conditions
CI/CD Pipeline / Staging E2E Tests (push) Blocked by required conditions
CI/CD Pipeline / Staging API Integration Tests (push) Blocked by required conditions
CI/CD Pipeline / Build Production API Image (push) Waiting to run
CI/CD Pipeline / Build Production Web Image (push) Waiting to run
CI/CD Pipeline / Build Production Worker Image (push) Waiting to run
CI/CD Pipeline / Deploy Production (push) Blocked by required conditions
CI/CD Pipeline / Production Browser E2E (push) Blocked by required conditions
CI/CD Pipeline / ACR Image Cleanup (push) Blocked by required conditions
refactor(#783): 统一API文件命名风格为kebab-case (#788)
2026-07-23 22:34:56 +08:00

132 lines
4.2 KiB
TypeScript

/**
* 注册页面 - V21 完全对标
*/
import React from "react"
import { Form, Input, message } from "antd"
import { UserOutlined, LockOutlined, MailOutlined } from "@ant-design/icons"
import { Link } from "react-router-dom"
import { useRegister } from "@/hooks/useAuth"
import Button from "@/components/ui/Button"
import "./Register.css"
interface RegisterFormValues {
email: string
username: string
password: string
confirmPassword: string
}
const Register: React.FC = () => {
const registerMutation = useRegister()
const [form] = Form.useForm()
const onFinish = async (values: RegisterFormValues) => {
try {
await registerMutation.mutateAsync({
email: values.email,
username: values.username,
password: values.password,
display_name: values.username,
})
message.success("注册成功!请查收验证邮件。")
} catch (error: unknown) {
if (!(error as { __msgShown?: boolean })?.__msgShown) message.error("注册失败,请重试")
}
}
return (
<div className="xx-auth-page">
<div className="xx-auth-card">
<div className="xx-auth-header">
<div className="xx-auth-brand">
<span className="xx-auth-logo">🦐</span>
<span className="xx-auth-brand-name">小虾智剪</span>
</div>
<p>创建账户,开启智能视频创作之旅</p>
</div>
<Form form={form} name="register" onFinish={onFinish} autoComplete="off" layout="vertical">
<Form.Item
name="email"
label="邮箱"
rules={[
{ required: true, message: "请输入邮箱" },
{ type: "email", message: "请输入有效的邮箱地址" },
]}
>
<Input prefix={<MailOutlined />} placeholder="name@example.com" size="large" />
</Form.Item>
<Form.Item
name="username"
label="用户名"
rules={[
{ required: true, message: "请输入用户名" },
{ min: 3, message: "用户名至少 3 个字符" },
{ max: 20, message: "用户名最多 20 个字符" },
{
pattern: /^[a-zA-Z0-9_]+$/,
message: "用户名只能包含字母、数字和下划线",
},
]}
>
<Input prefix={<UserOutlined />} placeholder="用户名" size="large" />
</Form.Item>
<Form.Item
name="password"
label="密码"
rules={[
{ required: true, message: "请输入密码" },
{ min: 8, message: "密码至少 8 个字符" },
{
pattern: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/,
message: "密码必须包含大小写字母和数字",
},
]}
>
<Input.Password prefix={<LockOutlined />} placeholder="•••••••••" size="large" />
</Form.Item>
<Form.Item
name="confirmPassword"
label="确认密码"
dependencies={["password"]}
rules={[
{ required: true, message: "请确认密码" },
({ getFieldValue }) => ({
validator(_, value) {
if (!value || getFieldValue("password") === value) {
return Promise.resolve()
}
return Promise.reject(new Error("两次输入的密码不一致"))
},
}),
]}
>
<Input.Password prefix={<LockOutlined />} placeholder="•••••••••" size="large" />
</Form.Item>
<Form.Item>
<Button
buttonType="primary"
buttonSize="lg"
htmlType="submit"
loading={registerMutation.isPending}
style={{ width: "100%" }}
>
{registerMutation.isPending ? "注册中..." : "注册"}
</Button>
</Form.Item>
<div className="xx-auth-footer">
已有账号? <Link to="/login">立即登录</Link>
</div>
</Form>
</div>
</div>
)
}
export default Register