-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: umi blocks
- Loading branch information
Showing
21 changed files
with
16,065 additions
and
10,495 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import { Button, Result } from 'antd'; | ||
import { Link } from 'umi'; | ||
|
||
export default () => ( | ||
<Result | ||
status="403" | ||
title="403" | ||
style={{ | ||
background: 'none', | ||
}} | ||
subTitle="Sorry, you don't have access to this page." | ||
extra={ | ||
<Link to="/"> | ||
<Button type="primary">Back to home</Button> | ||
</Link> | ||
} | ||
/> | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
// @ts-nocheck | ||
import type { Request, Response } from 'express'; | ||
|
||
export default { | ||
'POST /api/register': (_: Request, res: Response) => { | ||
res.send({ | ||
data: { status: 'ok', currentAuthority: 'user' }, | ||
}); | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,306 @@ | ||
import { | ||
Button, | ||
Col, | ||
Form, | ||
Input, | ||
message, | ||
Popover, | ||
Progress, | ||
Row, | ||
Select, | ||
} from 'antd'; | ||
import type { Store } from 'antd/es/form/interface'; | ||
import type { FC } from 'react'; | ||
import { useEffect, useState } from 'react'; | ||
import { history, Link, useRequest } from 'umi'; | ||
import type { StateType } from './service'; | ||
import { fakeRegister } from './service'; | ||
|
||
import useStyles from './style.style'; | ||
|
||
const FormItem = Form.Item; | ||
const { Option } = Select; | ||
const InputGroup = Input.Group; | ||
|
||
const passwordProgressMap: { | ||
ok: 'success'; | ||
pass: 'normal'; | ||
poor: 'exception'; | ||
} = { | ||
ok: 'success', | ||
pass: 'normal', | ||
poor: 'exception', | ||
}; | ||
|
||
const Register: FC = () => { | ||
const { styles } = useStyles(); | ||
|
||
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 [count, setCount]: [number, any] = useState(0); | ||
const [visible, 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 [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'; | ||
}; | ||
|
||
const { loading: submitting, run: register } = useRequest<{ | ||
data: StateType; | ||
}>(fakeRegister, { | ||
manual: true, | ||
onSuccess: (data, params) => { | ||
if (data.status === 'ok') { | ||
message.success('注册成功!'); | ||
history.push({ | ||
pathname: `/user/register-result?account=${params.email}`, | ||
}); | ||
} | ||
}, | ||
}); | ||
const onFinish = (values: Store) => { | ||
register(values); | ||
}; | ||
|
||
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 (!visible) { | ||
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 ? ( | ||
// @ts-ignore | ||
<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 | ||
name="mail" | ||
rules={[ | ||
{ | ||
required: true, | ||
message: '请输入邮箱地址!', | ||
}, | ||
{ | ||
type: 'email', | ||
message: '邮箱地址格式错误!', | ||
}, | ||
]} | ||
> | ||
<Input size="large" placeholder="邮箱" /> | ||
</FormItem> | ||
<Popover | ||
getPopupContainer={(node) => { | ||
if (node && node.parentNode) { | ||
return node.parentNode as HTMLElement; | ||
} | ||
return node; | ||
}} | ||
content={ | ||
visible && ( | ||
<div style={{ padding: '4px 0' }}> | ||
{passwordStatusMap[getPasswordStatus()]} | ||
{renderPasswordProgress()} | ||
<div style={{ marginTop: 10 }}> | ||
<span>请至少输入 6 个字符。请不要使用容易被猜到的密码。</span> | ||
</div> | ||
</div> | ||
) | ||
} | ||
overlayStyle={{ width: 240 }} | ||
placement="right" | ||
visible={visible} | ||
> | ||
<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> | ||
<InputGroup compact> | ||
<Select | ||
size="large" | ||
value={prefix} | ||
onChange={changePrefix} | ||
style={{ width: '20%' }} | ||
> | ||
<Option value="86">+86</Option> | ||
<Option value="87">+87</Option> | ||
</Select> | ||
<FormItem | ||
style={{ width: '80%' }} | ||
name="mobile" | ||
rules={[ | ||
{ | ||
required: true, | ||
message: '请输入手机号!', | ||
}, | ||
{ | ||
pattern: /^\d{11}$/, | ||
message: '手机号格式错误!', | ||
}, | ||
]} | ||
> | ||
<Input size="large" placeholder="手机号" /> | ||
</FormItem> | ||
</InputGroup> | ||
<Row gutter={8}> | ||
<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> | ||
</Row> | ||
<FormItem> | ||
<Button | ||
size="large" | ||
loading={submitting} | ||
className={styles.submit} | ||
type="primary" | ||
htmlType="submit" | ||
> | ||
<span>注册</span> | ||
</Button> | ||
<Link className={styles.login} to="/user/login"> | ||
<span>使用已有账户登录</span> | ||
</Link> | ||
</FormItem> | ||
</Form> | ||
</div> | ||
); | ||
}; | ||
export default Register; |
Oops, something went wrong.