import React, { Component } from 'react'; import { connect } from 'dva'; import { formatMessage, FormattedMessage } from 'umi-plugin-react/locale'; import Link from 'umi/link'; import { Form, Input, message, Button, Select, Row, Col, Popover, Progress } from 'antd'; import styles from './style.less'; import { Dispatch } from 'redux'; import { IStateType } from './model'; import { FormComponentProps } from 'antd/es/form'; import router from 'umi/router'; const FormItem = Form.Item; const { Option } = Select; const InputGroup = Input.Group; const passwordStatusMap = { ok: ( <div className={styles.success}> <FormattedMessage id="BLOCK_NAME.strength.strong" /> </div> ), pass: ( <div className={styles.warning}> <FormattedMessage id="BLOCK_NAME.strength.medium" /> </div> ), poor: ( <div className={styles.error}> <FormattedMessage id="BLOCK_NAME.strength.short" /> </div> ), }; const passwordProgressMap: { ok: 'success'; pass: 'normal'; poor: 'exception'; } = { ok: 'success', pass: 'normal', poor: 'exception', }; interface BLOCK_NAME_CAMEL_CASEProps extends FormComponentProps { dispatch: Dispatch<any>; BLOCK_NAME_CAMEL_CASE: IStateType; submitting: boolean; } interface BLOCK_NAME_CAMEL_CASEState { count: number; confirmDirty: boolean; visible: boolean; help: string; prefix: string; } export interface IUserRegisterParams { mail: string; password: string; confirm: string; mobile: string; captcha: string; prefix: string; } @connect( ({ BLOCK_NAME_CAMEL_CASE, loading, }: { BLOCK_NAME_CAMEL_CASE: IStateType; loading: { effects: { [key: string]: string; }; }; }) => ({ BLOCK_NAME_CAMEL_CASE, submitting: loading.effects['BLOCK_NAME_CAMEL_CASE/submit'], }), ) class PAGE_NAME_UPPER_CAMEL_CASE extends Component< BLOCK_NAME_CAMEL_CASEProps, BLOCK_NAME_CAMEL_CASEState > { state: BLOCK_NAME_CAMEL_CASEState = { count: 0, confirmDirty: false, visible: false, help: '', prefix: '86', }; interval: number | undefined; componentDidUpdate() { const { BLOCK_NAME_CAMEL_CASE, form } = this.props; const account = form.getFieldValue('mail'); if (BLOCK_NAME_CAMEL_CASE.status === 'ok') { message.success('注册成功!'); router.push({ pathname: '/user/register-result', state: { account, }, }); } } componentWillUnmount() { clearInterval(this.interval); } onGetCaptcha = () => { let count = 59; this.setState({ count }); this.interval = window.setInterval(() => { count -= 1; this.setState({ count }); if (count === 0) { clearInterval(this.interval); } }, 1000); }; getPasswordStatus = () => { const { form } = this.props; const value = form.getFieldValue('password'); if (value && value.length > 9) { return 'ok'; } if (value && value.length > 5) { return 'pass'; } return 'poor'; }; handleSubmit = (e: React.FormEvent) => { e.preventDefault(); const { form, dispatch } = this.props; form.validateFields({ force: true }, (err, values) => { if (!err) { const { prefix } = this.state; dispatch({ type: 'BLOCK_NAME_CAMEL_CASE/submit', payload: { ...values, prefix, }, }); } }); }; checkConfirm = (rule: any, value: string, callback: (messgae?: string) => void) => { const { form } = this.props; if (value && value !== form.getFieldValue('password')) { callback(formatMessage({ id: 'BLOCK_NAME.password.twice' })); } else { callback(); } }; checkPassword = (rule: any, value: string, callback: (messgae?: string) => void) => { const { visible, confirmDirty } = this.state; if (!value) { this.setState({ help: formatMessage({ id: 'BLOCK_NAME.password.required' }), visible: !!value, }); callback('error'); } else { this.setState({ help: '', }); if (!visible) { this.setState({ visible: !!value, }); } if (value.length < 6) { callback('error'); } else { const { form } = this.props; if (value && confirmDirty) { form.validateFields(['confirm'], { force: true }); } callback(); } } }; changePrefix = (value: string) => { this.setState({ prefix: value, }); }; renderPasswordProgress = () => { const { form } = this.props; const value = form.getFieldValue('password'); const passwordStatus = this.getPasswordStatus(); return value && value.length ? ( <div className={styles[`progress-${passwordStatus}`]}> <Progress default={passwordProgressMap[passwordStatus]} status={passwordProgressMap[passwordStatus]} className={styles.progress} strokeWidth={6} percent={value.length * 10 > 100 ? 100 : value.length * 10} showInfo={false} /> </div> ) : null; }; render() { const { form, submitting } = this.props; const { getFieldDecorator } = form; const { count, prefix, help, visible } = this.state; return ( <div className={styles.main}> <h3> <FormattedMessage id="BLOCK_NAME.register.register" /> </h3> <Form onSubmit={this.handleSubmit}> <FormItem> {getFieldDecorator('mail', { rules: [ { required: true, message: formatMessage({ id: 'BLOCK_NAME.email.required' }), }, { type: 'email', message: formatMessage({ id: 'BLOCK_NAME.email.wrong-format' }), }, ], })( <Input size="large" placeholder={formatMessage({ id: 'BLOCK_NAME.email.placeholder' })} />, )} </FormItem> <FormItem help={help}> <Popover getPopupContainer={node => node && node.parentNode ? (node.parentNode as HTMLElement) : node } content={ <div style={{ padding: '4px 0' }}> {passwordStatusMap[this.getPasswordStatus()]} {this.renderPasswordProgress()} <div style={{ marginTop: 10 }}> <FormattedMessage id="BLOCK_NAME.strength.msg" /> </div> </div> } overlayStyle={{ width: 240 }} placement="right" visible={visible} > {getFieldDecorator('password', { rules: [ { validator: this.checkPassword, }, ], })( <Input size="large" type="password" placeholder={formatMessage({ id: 'BLOCK_NAME.password.placeholder' })} />, )} </Popover> </FormItem> <FormItem> {getFieldDecorator('confirm', { rules: [ { required: true, message: formatMessage({ id: 'BLOCK_NAME.confirm-password.required' }), }, { validator: this.checkConfirm, }, ], })( <Input size="large" type="password" placeholder={formatMessage({ id: 'BLOCK_NAME.confirm-password.placeholder' })} />, )} </FormItem> <FormItem> <InputGroup compact> <Select size="large" value={prefix} onChange={this.changePrefix} style={{ width: '20%' }} > <Option value="86">+86</Option> <Option value="87">+87</Option> </Select> {getFieldDecorator('mobile', { rules: [ { required: true, message: formatMessage({ id: 'BLOCK_NAME.phone-number.required' }), }, { pattern: /^\d{11}$/, message: formatMessage({ id: 'BLOCK_NAME.phone-number.wrong-format' }), }, ], })( <Input size="large" style={{ width: '80%' }} placeholder={formatMessage({ id: 'BLOCK_NAME.phone-number.placeholder' })} />, )} </InputGroup> </FormItem> <FormItem> <Row gutter={8}> <Col span={16}> {getFieldDecorator('captcha', { rules: [ { required: true, message: formatMessage({ id: 'BLOCK_NAME.verification-code.required' }), }, ], })( <Input size="large" placeholder={formatMessage({ id: 'BLOCK_NAME.verification-code.placeholder' })} />, )} </Col> <Col span={8}> <Button size="large" disabled={!!count} className={styles.getCaptcha} onClick={this.onGetCaptcha} > {count ? `${count} s` : formatMessage({ id: 'BLOCK_NAME.register.get-verification-code' })} </Button> </Col> </Row> </FormItem> <FormItem> <Button size="large" loading={submitting} className={styles.submit} type="primary" htmlType="submit" > <FormattedMessage id="BLOCK_NAME.register.register" /> </Button> <Link className={styles.login} to="/user/login"> <FormattedMessage id="BLOCK_NAME.register.sign-in" /> </Link> </FormItem> </Form> </div> ); } } export default Form.create<BLOCK_NAME_CAMEL_CASEProps>()(PAGE_NAME_UPPER_CAMEL_CASE);