doctor-mail/apps/web/src/app/auth/register.tsx

207 lines
5.4 KiB
TypeScript
Raw Normal View History

2025-01-26 11:36:31 +08:00
import AvatarUploader from "@web/src/components/common/uploader/AvatarUploader";
2025-01-23 23:59:49 +08:00
import DepartmentSelect from "@web/src/components/models/department/department-select";
import { Form, Input, Button, Select } from "antd";
2025-01-22 23:19:58 +08:00
import { motion } from "framer-motion";
2025-01-26 12:45:59 +08:00
import { useState } from "react";
2025-01-22 23:19:58 +08:00
2025-01-23 23:59:49 +08:00
export interface RegisterFormData {
2025-01-26 11:36:31 +08:00
deptId: string;
2025-01-26 12:45:59 +08:00
domainId: string;
2025-01-26 11:36:31 +08:00
username: string;
showname: string;
2025-01-26 12:45:59 +08:00
2025-01-26 11:36:31 +08:00
officerId: string;
password: string;
repeatPass: string;
2025-01-26 12:45:59 +08:00
rank: string;
office: string;
email: string;
phoneNumber: string;
2025-01-23 23:59:49 +08:00
}
interface RegisterFormProps {
2025-01-26 11:36:31 +08:00
onSubmit: (data: RegisterFormData) => void;
isLoading: boolean;
2025-01-23 23:59:49 +08:00
}
export const RegisterForm = ({ onSubmit, isLoading }: RegisterFormProps) => {
2025-01-26 11:36:31 +08:00
const [form] = Form.useForm<RegisterFormData>();
2025-01-26 12:45:59 +08:00
const [domainId, setDomainId] = useState<string>();
2025-01-26 11:36:31 +08:00
return (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}>
<Form
form={form}
layout="vertical"
onFinish={onSubmit}
scrollToFirstError>
2025-01-26 15:28:34 +08:00
<div className="flex items-center gap-2 mb-2">
<div className="flex-1">
2025-01-26 11:36:31 +08:00
<Form.Item name="photoUrl" label="头像" noStyle>
<AvatarUploader
2025-01-26 12:45:59 +08:00
className="rounded-lg"
2025-01-26 11:36:31 +08:00
placeholder="点击上传头像"
style={{
2025-01-26 15:28:34 +08:00
width: `100%`,
height: 210,
}}
/>
2025-01-26 11:36:31 +08:00
</Form.Item>
</div>
2025-01-26 15:28:34 +08:00
<div className="flex-1 grid grid-cols-1 gap-3">
2025-01-26 11:36:31 +08:00
<Form.Item
name="username"
label="用户名"
noStyle
rules={[
{ required: true, message: "请输入用户名" },
{ min: 2, message: "用户名至少需要2个字符" },
]}>
<Input placeholder="用户名" />
</Form.Item>
<Form.Item
name="showname"
label="姓名"
noStyle
rules={[
{ required: true, message: "请输入姓名" },
{ min: 2, message: "姓名至少需要2个字符" },
]}>
<Input placeholder="姓名" />
</Form.Item>
2025-01-26 12:45:59 +08:00
<Form.Item
noStyle
name={"domainId"}
label="所属域"
rules={[{ required: true }]}>
<DepartmentSelect
placeholder="选择域"
onChange={(value) => {
setDomainId(value as string);
}}
domain={true}
/>
</Form.Item>
2025-01-26 11:36:31 +08:00
<Form.Item
name="deptId"
noStyle
label="部门"
rules={[{ required: true, message: "请选择部门" }]}>
2025-01-26 15:28:34 +08:00
<DepartmentSelect rootId={domainId} />
</Form.Item>
<Form.Item noStyle name={"rank"}>
<Input
placeholder="请输入职级(可选)"
autoComplete="off"
spellCheck={false}
allowClear
/>
2025-01-26 11:36:31 +08:00
</Form.Item>
</div>
</div>
2025-01-26 15:28:34 +08:00
<div className="flex items-center gap-2">
<div className="flex-1 grid grid-cols-1 gap-2">
<Form.Item
noStyle
rules={[
{
required: false,
pattern: /^\d{6,11}$/,
message: "请输入正确的手机号(数字)",
2025-01-26 12:45:59 +08:00
},
2025-01-26 15:28:34 +08:00
]}
name={"phoneNumber"}
label="手机号">
<Input
autoComplete="new-phone" // 使用非标准的自动完成值
spellCheck={false}
allowClear
placeholder="请输入手机号(可选)"
/>
</Form.Item>
<Form.Item noStyle name={"office"}>
<Input
placeholder="请输入办公室地点"
autoComplete="off"
spellCheck={false}
allowClear
/>
</Form.Item>
<Form.Item
name="password"
rules={[
{ required: true, message: "请输入密码" },
{ min: 8, message: "密码至少需要8个字符" },
{
pattern:
/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/,
message:
"密码必须包含大小写字母、数字和特殊字符",
},
]}>
<Input.Password placeholder="密码" />
</Form.Item>
</div>
<div className="flex-1 grid grid-cols-1 gap-2">
<Form.Item
name="officerId"
label="证件号"
noStyle
rules={[
{ required: true, message: "请输入证件号" },
{
pattern: /^\d{5,12}$/,
message: "请输入有效的证件号5-12位数字",
},
]}>
<Input placeholder="证件号(可选)" />
</Form.Item>
<Form.Item noStyle name={"email"}>
<Input
placeholder="请输入邮箱(可选)"
autoComplete="off"
spellCheck={false}
allowClear
/>
</Form.Item>
<Form.Item
name="repeatPass"
dependencies={["password"]}
rules={[
{ required: true, message: "请确认密码" },
({ getFieldValue }) => ({
validator(_, value) {
if (
!value ||
getFieldValue("password") === value
) {
return Promise.resolve();
}
return Promise.reject(
new Error("两次输入的密码不一致")
);
},
}),
]}>
<Input.Password placeholder="确认密码" />
</Form.Item>
</div>
2025-01-26 12:45:59 +08:00
</div>
2025-01-26 15:28:34 +08:00
<div className="grid grid-cols-1 flex-1 my-2"></div>
2025-01-26 11:36:31 +08:00
<Form.Item>
<Button
type="primary"
htmlType="submit"
loading={isLoading}
className="w-full h-10 rounded-lg">
{isLoading ? "正在注册..." : "注册"}
</Button>
</Form.Item>
</Form>
</motion.div>
);
2025-01-23 23:59:49 +08:00
};