2025-03-04 03:38:50 +08:00
|
|
|
|
import React, { useEffect, useState } from 'react';
|
|
|
|
|
import { useDispatch, useSelector } from 'react-redux';
|
|
|
|
|
import { Link, useNavigate } from 'react-router-dom';
|
|
|
|
|
import { checkAuthThunk, signupThunk } from '../../store/auth/auth.thunk';
|
|
|
|
|
|
2025-03-22 10:13:42 +08:00
|
|
|
|
// 部门和组别映射关系
|
|
|
|
|
const departmentGroups = {
|
2025-04-13 01:37:23 +08:00
|
|
|
|
达人部门: ['达人部门'],
|
|
|
|
|
商务部门: ['商务部门'],
|
|
|
|
|
样本中心: ['样本中心'],
|
|
|
|
|
产品部门: ['产品部门'],
|
|
|
|
|
AI自媒体: ['AI自媒体'],
|
|
|
|
|
HR: ['HR'],
|
|
|
|
|
技术部门: ['技术部门'],
|
2025-03-22 10:13:42 +08:00
|
|
|
|
};
|
|
|
|
|
|
2025-03-04 03:38:50 +08:00
|
|
|
|
export default function Signup() {
|
|
|
|
|
const dispatch = useDispatch();
|
|
|
|
|
const navigate = useNavigate();
|
2025-03-22 10:13:42 +08:00
|
|
|
|
const [formData, setFormData] = useState({
|
|
|
|
|
username: '',
|
|
|
|
|
email: '',
|
|
|
|
|
password: '',
|
|
|
|
|
name: '',
|
|
|
|
|
role: 'member',
|
|
|
|
|
department: '',
|
|
|
|
|
group: '',
|
|
|
|
|
});
|
2025-03-04 03:38:50 +08:00
|
|
|
|
const [errors, setErrors] = useState({});
|
|
|
|
|
const [submitted, setSubmitted] = useState(false);
|
2025-03-22 10:13:42 +08:00
|
|
|
|
const [availableGroups, setAvailableGroups] = useState([]);
|
2025-03-04 03:38:50 +08:00
|
|
|
|
|
2025-03-22 10:13:42 +08:00
|
|
|
|
const { user, loading } = useSelector((state) => state.auth);
|
2025-03-04 03:38:50 +08:00
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
handleCheckAuth();
|
|
|
|
|
}, [dispatch]);
|
|
|
|
|
|
2025-03-22 10:13:42 +08:00
|
|
|
|
// 当部门变化时,更新可选的组别
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (formData.department && departmentGroups[formData.department]) {
|
|
|
|
|
setAvailableGroups(departmentGroups[formData.department]);
|
|
|
|
|
// 如果已选择的组别不在新部门的选项中,则重置组别
|
|
|
|
|
if (!departmentGroups[formData.department].includes(formData.group)) {
|
|
|
|
|
setFormData(prev => ({
|
|
|
|
|
...prev,
|
|
|
|
|
group: ''
|
|
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
setAvailableGroups([]);
|
|
|
|
|
setFormData(prev => ({
|
|
|
|
|
...prev,
|
|
|
|
|
group: ''
|
|
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|
}, [formData.department]);
|
|
|
|
|
|
2025-03-04 03:38:50 +08:00
|
|
|
|
const handleCheckAuth = async () => {
|
|
|
|
|
console.log('signup page handleCheckAuth');
|
2025-03-04 07:22:05 +08:00
|
|
|
|
try {
|
|
|
|
|
await dispatch(checkAuthThunk()).unwrap();
|
|
|
|
|
if (user) navigate('/');
|
|
|
|
|
} catch (error) {}
|
2025-03-04 03:38:50 +08:00
|
|
|
|
};
|
|
|
|
|
|
2025-03-22 10:13:42 +08:00
|
|
|
|
const handleInputChange = (e) => {
|
|
|
|
|
const { name, value } = e.target;
|
|
|
|
|
setFormData({
|
|
|
|
|
...formData,
|
|
|
|
|
[name]: value,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 清除对应的错误信息
|
|
|
|
|
if (errors[name]) {
|
|
|
|
|
setErrors({
|
|
|
|
|
...errors,
|
|
|
|
|
[name]: '',
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2025-03-04 03:38:50 +08:00
|
|
|
|
const validateForm = () => {
|
|
|
|
|
const newErrors = {};
|
2025-03-22 10:13:42 +08:00
|
|
|
|
if (!formData.username) {
|
2025-03-04 03:38:50 +08:00
|
|
|
|
newErrors.username = 'Username is required';
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-22 10:13:42 +08:00
|
|
|
|
if (!formData.email) {
|
2025-03-04 03:38:50 +08:00
|
|
|
|
newErrors.email = 'Email is required';
|
2025-03-22 10:13:42 +08:00
|
|
|
|
} else if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(formData.email)) {
|
2025-03-04 03:38:50 +08:00
|
|
|
|
newErrors.email = 'Invalid email address';
|
|
|
|
|
}
|
2025-03-04 07:22:05 +08:00
|
|
|
|
|
2025-03-22 10:13:42 +08:00
|
|
|
|
if (!formData.password) {
|
2025-03-04 03:38:50 +08:00
|
|
|
|
newErrors.password = 'Password is required';
|
2025-03-22 10:13:42 +08:00
|
|
|
|
} else if (formData.password.length < 6) {
|
2025-03-04 03:38:50 +08:00
|
|
|
|
newErrors.password = 'Password must be at least 6 characters';
|
|
|
|
|
}
|
2025-03-22 10:13:42 +08:00
|
|
|
|
|
|
|
|
|
if (!formData.name) {
|
|
|
|
|
newErrors.name = 'Name is required';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!formData.department) {
|
|
|
|
|
newErrors.department = '请选择部门';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!formData.group) {
|
|
|
|
|
newErrors.group = '请选择组别';
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-04 03:38:50 +08:00
|
|
|
|
setErrors(newErrors);
|
|
|
|
|
return Object.keys(newErrors).length === 0;
|
|
|
|
|
};
|
|
|
|
|
|
2025-03-04 07:22:05 +08:00
|
|
|
|
const handleSubmit = async (e) => {
|
2025-03-04 03:38:50 +08:00
|
|
|
|
e.preventDefault();
|
|
|
|
|
setSubmitted(true);
|
|
|
|
|
|
|
|
|
|
if (validateForm()) {
|
|
|
|
|
console.log('Form submitted successfully!');
|
2025-03-22 10:13:42 +08:00
|
|
|
|
console.log('Registration data:', formData);
|
2025-03-04 07:22:05 +08:00
|
|
|
|
try {
|
2025-03-22 10:13:42 +08:00
|
|
|
|
await dispatch(signupThunk(formData)).unwrap();
|
|
|
|
|
navigate('/login');
|
2025-03-04 07:22:05 +08:00
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('Signup failed:', error);
|
|
|
|
|
}
|
2025-03-04 03:38:50 +08:00
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div className='position-absolute top-50 start-50 translate-middle d-flex flex-column gap-4 align-items-center'>
|
|
|
|
|
<div className='title text-center h1'>OOIN 智能知识库</div>
|
|
|
|
|
<form
|
|
|
|
|
className='auth-form login-form d-flex flex-column gap-3 align-items-center'
|
|
|
|
|
onSubmit={handleSubmit}
|
|
|
|
|
noValidate
|
|
|
|
|
>
|
|
|
|
|
<div className='input-group has-validation'>
|
|
|
|
|
<input
|
|
|
|
|
type='text'
|
|
|
|
|
className={`form-control form-control-lg${submitted && errors.username ? ' is-invalid' : ''}`}
|
|
|
|
|
id='username'
|
2025-03-22 10:13:42 +08:00
|
|
|
|
name='username'
|
|
|
|
|
placeholder='用户名'
|
|
|
|
|
value={formData.username}
|
2025-03-04 03:38:50 +08:00
|
|
|
|
required
|
2025-03-22 10:13:42 +08:00
|
|
|
|
onChange={handleInputChange}
|
|
|
|
|
disabled={loading}
|
2025-03-04 03:38:50 +08:00
|
|
|
|
></input>
|
|
|
|
|
{submitted && errors.username && <div className='invalid-feedback'>{errors.username}</div>}
|
|
|
|
|
</div>
|
|
|
|
|
<div className='input-group has-validation'>
|
|
|
|
|
<input
|
|
|
|
|
type='email'
|
|
|
|
|
className={`form-control form-control-lg${submitted && errors.email ? ' is-invalid' : ''}`}
|
|
|
|
|
id='email'
|
2025-03-22 10:13:42 +08:00
|
|
|
|
name='email'
|
|
|
|
|
placeholder='邮箱'
|
|
|
|
|
value={formData.email}
|
2025-03-04 03:38:50 +08:00
|
|
|
|
required
|
2025-03-22 10:13:42 +08:00
|
|
|
|
onChange={handleInputChange}
|
|
|
|
|
disabled={loading}
|
2025-03-04 03:38:50 +08:00
|
|
|
|
></input>
|
|
|
|
|
{submitted && errors.email && <div className='invalid-feedback'>{errors.email}</div>}
|
|
|
|
|
</div>
|
|
|
|
|
<div className='input-group has-validation'>
|
|
|
|
|
<input
|
|
|
|
|
type='password'
|
|
|
|
|
id='password'
|
2025-03-22 10:13:42 +08:00
|
|
|
|
name='password'
|
|
|
|
|
placeholder='密码'
|
|
|
|
|
value={formData.password}
|
2025-03-04 03:38:50 +08:00
|
|
|
|
required
|
|
|
|
|
className={`form-control form-control-lg${submitted && errors.password ? ' is-invalid' : ''}`}
|
|
|
|
|
aria-describedby='passwordHelpBlock'
|
2025-03-22 10:13:42 +08:00
|
|
|
|
onChange={handleInputChange}
|
|
|
|
|
disabled={loading}
|
2025-03-04 03:38:50 +08:00
|
|
|
|
></input>
|
|
|
|
|
{submitted && errors.password && <div className='invalid-feedback'>{errors.password}</div>}
|
|
|
|
|
</div>
|
2025-03-22 10:13:42 +08:00
|
|
|
|
<div className='input-group has-validation'>
|
|
|
|
|
<input
|
|
|
|
|
type='text'
|
|
|
|
|
className={`form-control form-control-lg${submitted && errors.name ? ' is-invalid' : ''}`}
|
|
|
|
|
id='name'
|
|
|
|
|
name='name'
|
|
|
|
|
placeholder='姓名'
|
|
|
|
|
value={formData.name}
|
|
|
|
|
required
|
|
|
|
|
onChange={handleInputChange}
|
|
|
|
|
disabled={loading}
|
|
|
|
|
></input>
|
|
|
|
|
{submitted && errors.name && <div className='invalid-feedback'>{errors.name}</div>}
|
|
|
|
|
</div>
|
|
|
|
|
<div className='input-group has-validation'>
|
|
|
|
|
<select
|
|
|
|
|
className={`form-select form-select-lg${submitted && errors.department ? ' is-invalid' : ''}`}
|
|
|
|
|
id='department'
|
|
|
|
|
name='department'
|
|
|
|
|
value={formData.department}
|
|
|
|
|
onChange={handleInputChange}
|
|
|
|
|
disabled={loading}
|
|
|
|
|
required
|
|
|
|
|
>
|
|
|
|
|
<option value='' disabled>
|
|
|
|
|
选择部门
|
|
|
|
|
</option>
|
|
|
|
|
<option value='技术部'>技术部</option>
|
|
|
|
|
<option value='产品部'>产品部</option>
|
|
|
|
|
<option value='市场部'>市场部</option>
|
|
|
|
|
<option value='行政部'>行政部</option>
|
|
|
|
|
</select>
|
|
|
|
|
{submitted && errors.department && <div className='invalid-feedback'>{errors.department}</div>}
|
|
|
|
|
</div>
|
|
|
|
|
<div className='input-group has-validation'>
|
|
|
|
|
<select
|
|
|
|
|
className={`form-select form-select-lg${submitted && errors.group ? ' is-invalid' : ''}`}
|
|
|
|
|
id='group'
|
|
|
|
|
name='group'
|
|
|
|
|
value={formData.group}
|
|
|
|
|
onChange={handleInputChange}
|
|
|
|
|
disabled={loading || !formData.department}
|
|
|
|
|
required
|
|
|
|
|
>
|
|
|
|
|
<option value='' disabled>
|
|
|
|
|
{formData.department ? '选择组别' : '请先选择部门'}
|
|
|
|
|
</option>
|
|
|
|
|
{availableGroups.map((group, index) => (
|
|
|
|
|
<option key={index} value={group}>
|
|
|
|
|
{group}
|
|
|
|
|
</option>
|
|
|
|
|
))}
|
|
|
|
|
</select>
|
|
|
|
|
{submitted && errors.group && <div className='invalid-feedback'>{errors.group}</div>}
|
|
|
|
|
</div>
|
|
|
|
|
<div className='input-group'>
|
|
|
|
|
<select
|
|
|
|
|
className='form-select form-select-lg'
|
|
|
|
|
id='role'
|
|
|
|
|
name='role'
|
|
|
|
|
value={formData.role}
|
|
|
|
|
onChange={handleInputChange}
|
|
|
|
|
disabled={loading}
|
|
|
|
|
>
|
|
|
|
|
<option value='member'>普通成员</option>
|
|
|
|
|
<option value='leader'>组长</option>
|
|
|
|
|
<option value='admin'>管理员</option>
|
|
|
|
|
</select>
|
|
|
|
|
</div>
|
|
|
|
|
<button type='submit' className='btn btn-dark btn-lg w-100' disabled={loading}>
|
|
|
|
|
{loading ? (
|
|
|
|
|
<>
|
|
|
|
|
<span
|
|
|
|
|
className='spinner-border spinner-border-sm me-2'
|
|
|
|
|
role='status'
|
|
|
|
|
aria-hidden='true'
|
|
|
|
|
></span>
|
|
|
|
|
注册中...
|
|
|
|
|
</>
|
|
|
|
|
) : (
|
|
|
|
|
'注册'
|
|
|
|
|
)}
|
2025-03-04 03:38:50 +08:00
|
|
|
|
</button>
|
|
|
|
|
</form>
|
|
|
|
|
<Link to='/login' className='go-to-signup w-100 link-underline-light h5 text-center'>
|
2025-03-22 10:13:42 +08:00
|
|
|
|
已有账号?立即登录
|
2025-03-04 03:38:50 +08:00
|
|
|
|
</Link>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|