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
|
|
|
|
};
|