2025-07-22 22:52:55 +08:00
|
|
|
|
import { history, Link, useRequest } from '@umijs/max';
|
|
|
|
|
|
import { Button, Col, Form, Input, message, Popover, Progress, Row, Select, Space } from 'antd';
|
|
|
|
|
|
import type { Store } from 'antd/es/form/interface';
|
|
|
|
|
|
import type { FC } from 'react';
|
|
|
|
|
|
import { useEffect, useState } from 'react';
|
|
|
|
|
|
import type { StateType } from './service';
|
|
|
|
|
|
import { fakeRegister } from './service';
|
|
|
|
|
|
import useStyles from './style.style';
|
2025-12-26 15:12:49 +08:00
|
|
|
|
import { registerUser } from '@/services/user/api';
|
|
|
|
|
|
import { CommonResponse } from '@/types/common';
|
2025-07-22 22:52:55 +08:00
|
|
|
|
|
|
|
|
|
|
const FormItem = Form.Item;
|
|
|
|
|
|
const { Option } = Select;
|
|
|
|
|
|
|
|
|
|
|
|
const passwordProgressMap: {
|
|
|
|
|
|
ok: 'success';
|
|
|
|
|
|
pass: 'normal';
|
|
|
|
|
|
poor: 'exception';
|
|
|
|
|
|
} = {
|
|
|
|
|
|
ok: 'success',
|
|
|
|
|
|
pass: 'normal',
|
|
|
|
|
|
poor: 'exception',
|
|
|
|
|
|
};
|
|
|
|
|
|
const Register: FC = () => {
|
|
|
|
|
|
const { styles } = useStyles();
|
|
|
|
|
|
const [count, setCount]: [number, any] = useState(0);
|
|
|
|
|
|
const [open, setVisible]: [boolean, any] = useState(false);
|
|
|
|
|
|
const [prefix, setPrefix]: [string, any] = useState('86');
|
|
|
|
|
|
const [popover, setPopover]: [boolean, any] = useState(false);
|
|
|
|
|
|
const confirmDirty = false;
|
|
|
|
|
|
let interval: number | undefined;
|
|
|
|
|
|
|
|
|
|
|
|
const passwordStatusMap = {
|
|
|
|
|
|
ok: (
|
|
|
|
|
|
<div className={styles.success}>
|
|
|
|
|
|
<span>强度:强</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
),
|
|
|
|
|
|
pass: (
|
|
|
|
|
|
<div className={styles.warning}>
|
|
|
|
|
|
<span>强度:中</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
),
|
|
|
|
|
|
poor: (
|
|
|
|
|
|
<div className={styles.error}>
|
|
|
|
|
|
<span>强度:太短</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
),
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const [form] = Form.useForm();
|
|
|
|
|
|
useEffect(
|
|
|
|
|
|
() => () => {
|
|
|
|
|
|
clearInterval(interval);
|
|
|
|
|
|
},
|
|
|
|
|
|
[interval],
|
|
|
|
|
|
);
|
|
|
|
|
|
const onGetCaptcha = () => {
|
|
|
|
|
|
let counts = 59;
|
|
|
|
|
|
setCount(counts);
|
|
|
|
|
|
interval = window.setInterval(() => {
|
|
|
|
|
|
counts -= 1;
|
|
|
|
|
|
setCount(counts);
|
|
|
|
|
|
if (counts === 0) {
|
|
|
|
|
|
clearInterval(interval);
|
|
|
|
|
|
}
|
|
|
|
|
|
}, 1000);
|
|
|
|
|
|
};
|
|
|
|
|
|
const getPasswordStatus = () => {
|
|
|
|
|
|
const value = form.getFieldValue('password');
|
|
|
|
|
|
if (value && value.length > 9) {
|
|
|
|
|
|
return 'ok';
|
|
|
|
|
|
}
|
|
|
|
|
|
if (value && value.length > 5) {
|
|
|
|
|
|
return 'pass';
|
|
|
|
|
|
}
|
|
|
|
|
|
return 'poor';
|
|
|
|
|
|
};
|
2025-12-26 15:12:49 +08:00
|
|
|
|
const { loading: submitting, run: register } = useRequest(
|
|
|
|
|
|
(params) => registerUser(params, { skipErrorHandler: true }),
|
|
|
|
|
|
{
|
|
|
|
|
|
manual: true,
|
|
|
|
|
|
onSuccess: (data, params) => {
|
|
|
|
|
|
console.log('注册成功 - data:', data, 'params:', params);
|
|
|
|
|
|
const response = data as CommonResponse<string>;
|
|
|
|
|
|
if (response?.code === 200) {
|
|
|
|
|
|
message.success('注册成功!');
|
|
|
|
|
|
const formValues = params[0] as any;
|
|
|
|
|
|
history.push({
|
|
|
|
|
|
pathname: `/user/register-result?account=${formValues?.email || formValues?.username || ''}`,
|
|
|
|
|
|
});
|
|
|
|
|
|
} else {
|
|
|
|
|
|
message.error(response?.message || '注册失败,请重试');
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
2025-07-22 22:52:55 +08:00
|
|
|
|
},
|
2025-12-26 15:12:49 +08:00
|
|
|
|
);
|
|
|
|
|
|
|
2025-07-22 22:52:55 +08:00
|
|
|
|
const onFinish = (values: Store) => {
|
2025-12-26 15:12:49 +08:00
|
|
|
|
// 将表单数据映射为后端需要的格式
|
|
|
|
|
|
const registerParams = {
|
|
|
|
|
|
username: values.username,
|
|
|
|
|
|
nickname: values.nickname,
|
|
|
|
|
|
password: values.password,
|
|
|
|
|
|
email: values.email || '',
|
|
|
|
|
|
phone: values.phone || '',
|
|
|
|
|
|
};
|
|
|
|
|
|
register(registerParams);
|
2025-07-22 22:52:55 +08:00
|
|
|
|
};
|
|
|
|
|
|
const checkConfirm = (_: any, value: string) => {
|
|
|
|
|
|
const promise = Promise;
|
|
|
|
|
|
if (value && value !== form.getFieldValue('password')) {
|
|
|
|
|
|
return promise.reject('两次输入的密码不匹配!');
|
|
|
|
|
|
}
|
|
|
|
|
|
return promise.resolve();
|
|
|
|
|
|
};
|
|
|
|
|
|
const checkPassword = (_: any, value: string) => {
|
|
|
|
|
|
const promise = Promise;
|
|
|
|
|
|
// 没有值的情况
|
|
|
|
|
|
if (!value) {
|
|
|
|
|
|
setVisible(!!value);
|
|
|
|
|
|
return promise.reject('请输入密码!');
|
|
|
|
|
|
}
|
|
|
|
|
|
// 有值的情况
|
|
|
|
|
|
if (!open) {
|
|
|
|
|
|
setVisible(!!value);
|
|
|
|
|
|
}
|
|
|
|
|
|
setPopover(!popover);
|
|
|
|
|
|
if (value.length < 6) {
|
|
|
|
|
|
return promise.reject('');
|
|
|
|
|
|
}
|
|
|
|
|
|
if (value && confirmDirty) {
|
|
|
|
|
|
form.validateFields(['confirm']);
|
|
|
|
|
|
}
|
|
|
|
|
|
return promise.resolve();
|
|
|
|
|
|
};
|
|
|
|
|
|
const changePrefix = (value: string) => {
|
|
|
|
|
|
setPrefix(value);
|
|
|
|
|
|
};
|
|
|
|
|
|
const renderPasswordProgress = () => {
|
|
|
|
|
|
const value = form.getFieldValue('password');
|
|
|
|
|
|
const passwordStatus = getPasswordStatus();
|
|
|
|
|
|
return value && value.length ? (
|
|
|
|
|
|
<div className={styles[`progress-${passwordStatus}`]}>
|
|
|
|
|
|
<Progress
|
|
|
|
|
|
status={passwordProgressMap[passwordStatus]}
|
|
|
|
|
|
strokeWidth={6}
|
|
|
|
|
|
percent={value.length * 10 > 100 ? 100 : value.length * 10}
|
|
|
|
|
|
showInfo={false}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
) : null;
|
|
|
|
|
|
};
|
|
|
|
|
|
return (
|
|
|
|
|
|
<div className={styles.main}>
|
|
|
|
|
|
<h3>注册</h3>
|
|
|
|
|
|
<Form form={form} name="UserRegister" onFinish={onFinish}>
|
|
|
|
|
|
<FormItem
|
2025-12-26 15:12:49 +08:00
|
|
|
|
name="username"
|
2025-07-22 22:52:55 +08:00
|
|
|
|
rules={[
|
2025-12-26 15:12:49 +08:00
|
|
|
|
{ required: true, message: '请输入用户名!' },
|
|
|
|
|
|
{ max: 50, message: '用户名过长' },
|
2025-07-22 22:52:55 +08:00
|
|
|
|
]}
|
|
|
|
|
|
>
|
2025-12-26 15:12:49 +08:00
|
|
|
|
<Input size="large" placeholder="用户名" />
|
|
|
|
|
|
</FormItem>
|
|
|
|
|
|
<FormItem
|
|
|
|
|
|
name="nickname"
|
|
|
|
|
|
rules={[
|
|
|
|
|
|
{ required: true, message: '请输入昵称!' },
|
|
|
|
|
|
{ max: 50, message: '昵称过长' },
|
|
|
|
|
|
]}
|
|
|
|
|
|
>
|
|
|
|
|
|
<Input size="large" placeholder="昵称" />
|
2025-07-22 22:52:55 +08:00
|
|
|
|
</FormItem>
|
|
|
|
|
|
<Popover
|
|
|
|
|
|
getPopupContainer={(node) => {
|
|
|
|
|
|
if (node && node.parentNode) {
|
|
|
|
|
|
return node.parentNode as HTMLElement;
|
|
|
|
|
|
}
|
|
|
|
|
|
return node;
|
|
|
|
|
|
}}
|
|
|
|
|
|
content={
|
|
|
|
|
|
open && (
|
|
|
|
|
|
<div
|
|
|
|
|
|
style={{
|
|
|
|
|
|
padding: '4px 0',
|
|
|
|
|
|
}}
|
|
|
|
|
|
>
|
|
|
|
|
|
{passwordStatusMap[getPasswordStatus()]}
|
|
|
|
|
|
{renderPasswordProgress()}
|
|
|
|
|
|
<div
|
|
|
|
|
|
style={{
|
|
|
|
|
|
marginTop: 10,
|
|
|
|
|
|
}}
|
|
|
|
|
|
>
|
|
|
|
|
|
<span>请至少输入 6 个字符。请不要使用容易被猜到的密码。</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
)
|
|
|
|
|
|
}
|
|
|
|
|
|
overlayStyle={{
|
|
|
|
|
|
width: 240,
|
|
|
|
|
|
}}
|
|
|
|
|
|
placement="right"
|
|
|
|
|
|
open={open}
|
|
|
|
|
|
>
|
|
|
|
|
|
<FormItem
|
|
|
|
|
|
name="password"
|
|
|
|
|
|
className={
|
|
|
|
|
|
form.getFieldValue('password') &&
|
|
|
|
|
|
form.getFieldValue('password').length > 0 &&
|
|
|
|
|
|
styles.password
|
|
|
|
|
|
}
|
|
|
|
|
|
rules={[
|
|
|
|
|
|
{
|
|
|
|
|
|
validator: checkPassword,
|
|
|
|
|
|
},
|
|
|
|
|
|
]}
|
|
|
|
|
|
>
|
|
|
|
|
|
<Input size="large" type="password" placeholder="至少6位密码,区分大小写" />
|
|
|
|
|
|
</FormItem>
|
|
|
|
|
|
</Popover>
|
|
|
|
|
|
<FormItem
|
|
|
|
|
|
name="confirm"
|
|
|
|
|
|
rules={[
|
|
|
|
|
|
{
|
|
|
|
|
|
required: true,
|
|
|
|
|
|
message: '确认密码',
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
validator: checkConfirm,
|
|
|
|
|
|
},
|
|
|
|
|
|
]}
|
|
|
|
|
|
>
|
|
|
|
|
|
<Input size="large" type="password" placeholder="确认密码" />
|
|
|
|
|
|
</FormItem>
|
|
|
|
|
|
<FormItem
|
2025-12-26 15:12:49 +08:00
|
|
|
|
name="email"
|
|
|
|
|
|
/* rules={[
|
|
|
|
|
|
{
|
|
|
|
|
|
required: true,
|
|
|
|
|
|
message: '请输入邮箱地址!',
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
type: 'email',
|
|
|
|
|
|
message: '邮箱地址格式错误!',
|
|
|
|
|
|
},
|
|
|
|
|
|
]} */
|
|
|
|
|
|
>
|
|
|
|
|
|
<Input size="large" placeholder="邮箱" />
|
|
|
|
|
|
</FormItem>
|
|
|
|
|
|
<FormItem
|
|
|
|
|
|
name="phone"
|
|
|
|
|
|
/* rules={[
|
2025-07-22 22:52:55 +08:00
|
|
|
|
{
|
|
|
|
|
|
required: true,
|
|
|
|
|
|
message: '请输入手机号!',
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
pattern: /^\d{11}$/,
|
|
|
|
|
|
message: '手机号格式错误!',
|
|
|
|
|
|
},
|
2025-12-26 15:12:49 +08:00
|
|
|
|
]} */
|
2025-07-22 22:52:55 +08:00
|
|
|
|
>
|
|
|
|
|
|
<Space.Compact style={{ width: '100%' }}>
|
|
|
|
|
|
<Select
|
|
|
|
|
|
size="large"
|
|
|
|
|
|
value={prefix}
|
|
|
|
|
|
onChange={changePrefix}
|
|
|
|
|
|
style={{
|
|
|
|
|
|
width: '30%',
|
|
|
|
|
|
}}
|
|
|
|
|
|
>
|
|
|
|
|
|
<Option value="86">+86</Option>
|
|
|
|
|
|
<Option value="87">+87</Option>
|
|
|
|
|
|
</Select>
|
|
|
|
|
|
|
|
|
|
|
|
<Input size="large" placeholder="手机号" />
|
|
|
|
|
|
</Space.Compact>
|
|
|
|
|
|
</FormItem>
|
2025-12-26 15:12:49 +08:00
|
|
|
|
{/* <Row gutter={8}>
|
2025-07-22 22:52:55 +08:00
|
|
|
|
<Col span={16}>
|
|
|
|
|
|
<FormItem
|
|
|
|
|
|
name="captcha"
|
|
|
|
|
|
rules={[
|
|
|
|
|
|
{
|
|
|
|
|
|
required: true,
|
|
|
|
|
|
message: '请输入验证码!',
|
|
|
|
|
|
},
|
|
|
|
|
|
]}
|
|
|
|
|
|
>
|
|
|
|
|
|
<Input size="large" placeholder="验证码" />
|
|
|
|
|
|
</FormItem>
|
|
|
|
|
|
</Col>
|
|
|
|
|
|
<Col span={8}>
|
|
|
|
|
|
<Button
|
|
|
|
|
|
size="large"
|
|
|
|
|
|
disabled={!!count}
|
|
|
|
|
|
className={styles.getCaptcha}
|
|
|
|
|
|
onClick={onGetCaptcha}
|
|
|
|
|
|
>
|
|
|
|
|
|
{count ? `${count} s` : '获取验证码'}
|
|
|
|
|
|
</Button>
|
|
|
|
|
|
</Col>
|
2025-12-26 15:12:49 +08:00
|
|
|
|
</Row> */}
|
2025-07-22 22:52:55 +08:00
|
|
|
|
<FormItem>
|
|
|
|
|
|
<div className={styles.footer}>
|
|
|
|
|
|
<Button
|
|
|
|
|
|
size="large"
|
|
|
|
|
|
loading={submitting}
|
|
|
|
|
|
className={styles.submit}
|
|
|
|
|
|
type="primary"
|
|
|
|
|
|
htmlType="submit"
|
|
|
|
|
|
>
|
|
|
|
|
|
<span>注册</span>
|
|
|
|
|
|
</Button>
|
|
|
|
|
|
<Link to="/user/login">
|
|
|
|
|
|
<span>使用已有账户登录</span>
|
|
|
|
|
|
</Link>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</FormItem>
|
|
|
|
|
|
</Form>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
);
|
|
|
|
|
|
};
|
|
|
|
|
|
export default Register;
|