提交 70b9d7aaa22c2e35ab049ee2f87c09aa4f89e3c1

作者 愚道
1 个父辈 85828494

improve user register code

1 export default { 1 export default {
2 plugins: [ 2 plugins: [
3 - ['umi-plugin-block-dev', {}],  
4 - ['umi-plugin-react', {  
5 - dva: true,  
6 - locale: true,  
7 - antd: true,  
8 - }] 3 + [
  4 + 'umi-plugin-block-dev',
  5 + {
  6 + layout: 'ant-design-pro-user',
  7 + },
  8 + ],
  9 + [
  10 + 'umi-plugin-react',
  11 + {
  12 + dva: true,
  13 + locale: true,
  14 + antd: true,
  15 + },
  16 + ],
9 ], 17 ],
10 -} 18 +};
1 { 1 {
2 - "name": "@umi-block/userregister", 2 + "name": "@umi-block/user-register",
3 "version": "0.0.1", 3 "version": "0.0.1",
4 "description": "UserRegister", 4 "description": "UserRegister",
5 "main": "src/index.js", 5 "main": "src/index.js",
1 export default { 1 export default {
2 - 'POST /api/register': (req, res) => { 2 + 'POST /api/BLOCK_NAME/register': (req, res) => {
3 res.send({ status: 'ok', currentAuthority: 'user' }); 3 res.send({ status: 'ok', currentAuthority: 'user' });
4 }, 4 },
5 }; 5 };
1 -import React, { PureComponent } from 'react';  
2 -import { Dropdown } from 'antd';  
3 -import classNames from 'classnames';  
4 -import styles from './index.less';  
5 -  
6 -export default class HeaderDropdown extends PureComponent {  
7 - render() {  
8 - const { overlayClassName, ...props } = this.props;  
9 - return (  
10 - <Dropdown overlayClassName={classNames(styles.container, overlayClassName)} {...props} />  
11 - );  
12 - }  
13 -}  
1 -@import '~antd/lib/style/themes/default.less';  
2 -  
3 -.container > *:global(:not(.ant-dropdown-menu)) {  
4 - background-color: #fff;  
5 - box-shadow: @shadow-1-down;  
6 - border-radius: 4px;  
7 -}  
8 -  
9 -@media screen and (max-width: @screen-xs) {  
10 - .container {  
11 - width: 100% !important;  
12 - }  
13 - .container > * {  
14 - border-radius: 0 !important;  
15 - }  
16 -}  
1 -import React, { PureComponent } from 'react';  
2 -import { formatMessage, setLocale, getLocale } from 'umi/locale';  
3 -import { Menu, Icon } from 'antd';  
4 -import classNames from 'classnames';  
5 -import HeaderDropdown from '../HeaderDropdown';  
6 -import styles from './index.less';  
7 -  
8 -export default class SelectLang extends PureComponent {  
9 - changeLang = ({ key }) => {  
10 - setLocale(key);  
11 - };  
12 -  
13 - render() {  
14 - const { className } = this.props;  
15 - const selectedLang = getLocale();  
16 - const langMenu = (  
17 - <Menu className={styles.menu} selectedKeys={[selectedLang]} onClick={this.changeLang}>  
18 - <Menu.Item key="zh-CN">  
19 - <span role="img" aria-label="简体中文">  
20 - 🇨🇳  
21 - </span>{' '}  
22 - 简体中文  
23 - </Menu.Item>  
24 - <Menu.Item key="zh-TW">  
25 - <span role="img" aria-label="繁体中文">  
26 - 🇭🇰  
27 - </span>{' '}  
28 - 繁体中文  
29 - </Menu.Item>  
30 - <Menu.Item key="en-US">  
31 - <span role="img" aria-label="English">  
32 - 🇬🇧  
33 - </span>{' '}  
34 - English  
35 - </Menu.Item>  
36 - <Menu.Item key="pt-BR">  
37 - <span role="img" aria-label="Português">  
38 - 🇵🇹  
39 - </span>{' '}  
40 - Português  
41 - </Menu.Item>  
42 - </Menu>  
43 - );  
44 - return (  
45 - <HeaderDropdown overlay={langMenu} placement="bottomRight">  
46 - <span className={classNames(styles.dropDown, className)}>  
47 - <Icon type="global" title={formatMessage({ id: 'navBar.lang' })} />  
48 - </span>  
49 - </HeaderDropdown>  
50 - );  
51 - }  
52 -}  
1 -@import '~antd/lib/style/themes/default.less';  
2 -  
3 -.menu {  
4 - :global(.anticon) {  
5 - margin-right: 8px;  
6 - }  
7 - :global(.ant-dropdown-menu-item) {  
8 - min-width: 160px;  
9 - }  
10 -}  
11 -  
12 -.dropDown {  
13 - cursor: pointer;  
14 - vertical-align: top;  
15 - line-height: @layout-header-height;  
16 - > i {  
17 - font-size: 14px !important;  
18 - transform: none !important;  
19 - svg {  
20 - position: relative;  
21 - top: -1px;  
22 - }  
23 - }  
24 -}  
1 -import React, { Fragment } from 'react';  
2 -import { formatMessage } from 'umi/locale';  
3 -import Link from 'umi/link';  
4 -import { Icon } from 'antd';  
5 -import { GlobalFooter } from 'ant-design-pro';  
6 -import SelectLang from '../SelectLang';  
7 -import styles from './index.less';  
8 -import logo from './logo.svg';  
9 -  
10 -const links = [  
11 - {  
12 - key: 'help',  
13 - title: formatMessage({ id: 'layout.user.link.help' }),  
14 - href: '',  
15 - },  
16 - {  
17 - key: 'privacy',  
18 - title: formatMessage({ id: 'layout.user.link.privacy' }),  
19 - href: '',  
20 - },  
21 - {  
22 - key: 'terms',  
23 - title: formatMessage({ id: 'layout.user.link.terms' }),  
24 - href: '',  
25 - },  
26 -];  
27 -  
28 -const copyright = (  
29 - <Fragment>  
30 - Copyright <Icon type="copyright" /> 2018 蚂蚁金服体验技术部出品  
31 - </Fragment>  
32 -);  
33 -  
34 -class UserLayout extends React.PureComponent {  
35 - // @TODO title  
36 - // getPageTitle() {  
37 - // const { routerData, location } = this.props;  
38 - // const { pathname } = location;  
39 - // let title = 'Ant Design Pro';  
40 - // if (routerData[pathname] && routerData[pathname].name) {  
41 - // title = `${routerData[pathname].name} - Ant Design Pro`;  
42 - // }  
43 - // return title;  
44 - // }  
45 -  
46 - render() {  
47 - const { children } = this.props;  
48 - return (  
49 - // @TODO <DocumentTitle title={this.getPageTitle()}>  
50 - <div className={styles.container}>  
51 - <div className={styles.lang}>  
52 - <SelectLang />  
53 - </div>  
54 - <div className={styles.content}>  
55 - <div className={styles.top}>  
56 - <div className={styles.header}>  
57 - <Link to="/">  
58 - <img alt="logo" className={styles.logo} src={logo} />  
59 - <span className={styles.title}>Ant Design</span>  
60 - </Link>  
61 - </div>  
62 - <div className={styles.desc}>Ant Design 是西湖区最具影响力的 Web 设计规范</div>  
63 - </div>  
64 - {children}  
65 - </div>  
66 - <GlobalFooter links={links} copyright={copyright} />  
67 - </div>  
68 - );  
69 - }  
70 -}  
71 -  
72 -export default UserLayout;  
1 -@import '~antd/lib/style/themes/default.less';  
2 -  
3 -.container {  
4 - display: flex;  
5 - flex-direction: column;  
6 - height: 100vh;  
7 - overflow: auto;  
8 - background: @layout-body-background;  
9 -}  
10 -  
11 -.lang {  
12 - text-align: right;  
13 - width: 100%;  
14 - height: 40px;  
15 - line-height: 44px;  
16 - :global(.ant-dropdown-trigger) {  
17 - margin-right: 24px;  
18 - }  
19 -}  
20 -  
21 -.content {  
22 - padding: 32px 0;  
23 - flex: 1;  
24 -}  
25 -  
26 -@media (min-width: @screen-md-min) {  
27 - .container {  
28 - background-image: url('https://gw.alipayobjects.com/zos/rmsportal/TVYTbAXWheQpRcWDaDMu.svg');  
29 - background-repeat: no-repeat;  
30 - background-position: center 110px;  
31 - background-size: 100%;  
32 - }  
33 -  
34 - .content {  
35 - padding: 32px 0 24px 0;  
36 - }  
37 -}  
38 -  
39 -.top {  
40 - text-align: center;  
41 -}  
42 -  
43 -.header {  
44 - height: 44px;  
45 - line-height: 44px;  
46 - a {  
47 - text-decoration: none;  
48 - }  
49 -}  
50 -  
51 -.logo {  
52 - height: 44px;  
53 - vertical-align: top;  
54 - margin-right: 16px;  
55 -}  
56 -  
57 -.title {  
58 - font-size: 33px;  
59 - color: @heading-color;  
60 - font-family: Avenir, 'Helvetica Neue', Arial, Helvetica, sans-serif;  
61 - font-weight: 600;  
62 - position: relative;  
63 - top: 2px;  
64 -}  
65 -  
66 -.desc {  
67 - font-size: @font-size-base;  
68 - color: @text-color-secondary;  
69 - margin-top: 12px;  
70 - margin-bottom: 40px;  
71 -}  
1 -<?xml version="1.0" encoding="UTF-8" standalone="no"?>  
2 -<svg width="200px" height="200px" viewBox="0 0 200 200" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">  
3 - <!-- Generator: Sketch 47.1 (45422) - http://www.bohemiancoding.com/sketch -->  
4 - <title>Group 28 Copy 5</title>  
5 - <desc>Created with Sketch.</desc>  
6 - <defs>  
7 - <linearGradient x1="62.1023273%" y1="0%" x2="108.19718%" y2="37.8635764%" id="linearGradient-1">  
8 - <stop stop-color="#4285EB" offset="0%"></stop>  
9 - <stop stop-color="#2EC7FF" offset="100%"></stop>  
10 - </linearGradient>  
11 - <linearGradient x1="69.644116%" y1="0%" x2="54.0428975%" y2="108.456714%" id="linearGradient-2">  
12 - <stop stop-color="#29CDFF" offset="0%"></stop>  
13 - <stop stop-color="#148EFF" offset="37.8600687%"></stop>  
14 - <stop stop-color="#0A60FF" offset="100%"></stop>  
15 - </linearGradient>  
16 - <linearGradient x1="69.6908165%" y1="-12.9743587%" x2="16.7228981%" y2="117.391248%" id="linearGradient-3">  
17 - <stop stop-color="#FA816E" offset="0%"></stop>  
18 - <stop stop-color="#F74A5C" offset="41.472606%"></stop>  
19 - <stop stop-color="#F51D2C" offset="100%"></stop>  
20 - </linearGradient>  
21 - <linearGradient x1="68.1279872%" y1="-35.6905737%" x2="30.4400914%" y2="114.942679%" id="linearGradient-4">  
22 - <stop stop-color="#FA8E7D" offset="0%"></stop>  
23 - <stop stop-color="#F74A5C" offset="51.2635191%"></stop>  
24 - <stop stop-color="#F51D2C" offset="100%"></stop>  
25 - </linearGradient>  
26 - </defs>  
27 - <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">  
28 - <g id="logo" transform="translate(-20.000000, -20.000000)">  
29 - <g id="Group-28-Copy-5" transform="translate(20.000000, 20.000000)">  
30 - <g id="Group-27-Copy-3">  
31 - <g id="Group-25" fill-rule="nonzero">  
32 - <g id="2">  
33 - <path d="M91.5880863,4.17652823 L4.17996544,91.5127728 C-0.519240605,96.2081146 -0.519240605,103.791885 4.17996544,108.487227 L91.5880863,195.823472 C96.2872923,200.518814 103.877304,200.518814 108.57651,195.823472 L145.225487,159.204632 C149.433969,154.999611 149.433969,148.181924 145.225487,143.976903 C141.017005,139.771881 134.193707,139.771881 129.985225,143.976903 L102.20193,171.737352 C101.032305,172.906015 99.2571609,172.906015 98.0875359,171.737352 L28.285908,101.993122 C27.1162831,100.824459 27.1162831,99.050775 28.285908,97.8821118 L98.0875359,28.1378823 C99.2571609,26.9692191 101.032305,26.9692191 102.20193,28.1378823 L129.985225,55.8983314 C134.193707,60.1033528 141.017005,60.1033528 145.225487,55.8983314 C149.433969,51.69331 149.433969,44.8756232 145.225487,40.6706018 L108.58055,4.05574592 C103.862049,-0.537986846 96.2692618,-0.500797906 91.5880863,4.17652823 Z" id="Shape" fill="url(#linearGradient-1)"></path>  
34 - <path d="M91.5880863,4.17652823 L4.17996544,91.5127728 C-0.519240605,96.2081146 -0.519240605,103.791885 4.17996544,108.487227 L91.5880863,195.823472 C96.2872923,200.518814 103.877304,200.518814 108.57651,195.823472 L145.225487,159.204632 C149.433969,154.999611 149.433969,148.181924 145.225487,143.976903 C141.017005,139.771881 134.193707,139.771881 129.985225,143.976903 L102.20193,171.737352 C101.032305,172.906015 99.2571609,172.906015 98.0875359,171.737352 L28.285908,101.993122 C27.1162831,100.824459 27.1162831,99.050775 28.285908,97.8821118 L98.0875359,28.1378823 C100.999864,25.6271836 105.751642,20.541824 112.729652,19.3524487 C117.915585,18.4685261 123.585219,20.4140239 129.738554,25.1889424 C125.624663,21.0784292 118.571995,14.0340304 108.58055,4.05574592 C103.862049,-0.537986846 96.2692618,-0.500797906 91.5880863,4.17652823 Z" id="Shape" fill="url(#linearGradient-2)"></path>  
35 - </g>  
36 - <path d="M153.685633,135.854579 C157.894115,140.0596 164.717412,140.0596 168.925894,135.854579 L195.959977,108.842726 C200.659183,104.147384 200.659183,96.5636133 195.960527,91.8688194 L168.690777,64.7181159 C164.472332,60.5180858 157.646868,60.5241425 153.435895,64.7316526 C149.227413,68.936674 149.227413,75.7543607 153.435895,79.9593821 L171.854035,98.3623765 C173.02366,99.5310396 173.02366,101.304724 171.854035,102.473387 L153.685633,120.626849 C149.47715,124.83187 149.47715,131.649557 153.685633,135.854579 Z" id="Shape" fill="url(#linearGradient-3)"></path>  
37 - </g>  
38 - <ellipse id="Combined-Shape" fill="url(#linearGradient-4)" cx="100.519339" cy="100.436681" rx="23.6001926" ry="23.580786"></ellipse>  
39 - </g>  
40 - </g>  
41 - </g>  
42 - </g>  
43 -</svg>  
@@ -4,7 +4,6 @@ import { formatMessage, FormattedMessage } from 'umi/locale'; @@ -4,7 +4,6 @@ import { formatMessage, FormattedMessage } from 'umi/locale';
4 import Link from 'umi/link'; 4 import Link from 'umi/link';
5 import router from 'umi/router'; 5 import router from 'umi/router';
6 import { Form, Input, Button, Select, Row, Col, Popover, Progress } from 'antd'; 6 import { Form, Input, Button, Select, Row, Col, Popover, Progress } from 'antd';
7 -import UserLayout from './components/UserLayout';  
8 import styles from './style.less'; 7 import styles from './style.less';
9 8
10 const FormItem = Form.Item; 9 const FormItem = Form.Item;
@@ -35,12 +34,12 @@ const passwordProgressMap = { @@ -35,12 +34,12 @@ const passwordProgressMap = {
35 poor: 'exception', 34 poor: 'exception',
36 }; 35 };
37 36
38 -@connect(({ register, loading }) => ({  
39 - register,  
40 - submitting: loading.effects['register/submit'], 37 +@connect(({ BLOCK_NAME_CAMEL_CASE, loading }) => ({
  38 + BLOCK_NAME_CAMEL_CASE,
  39 + submitting: loading.effects['BLOCK_NAME_CAMEL_CASE/submit'],
41 })) 40 }))
42 @Form.create() 41 @Form.create()
43 -class Register extends Component { 42 +class PAGE_NAME_UPPER_CAMEL_CASE extends Component {
44 state = { 43 state = {
45 count: 0, 44 count: 0,
46 confirmDirty: false, 45 confirmDirty: false,
@@ -50,9 +49,9 @@ class Register extends Component { @@ -50,9 +49,9 @@ class Register extends Component {
50 }; 49 };
51 50
52 componentDidUpdate() { 51 componentDidUpdate() {
53 - const { form, register } = this.props; 52 + const { form, BLOCK_NAME_CAMEL_CASE } = this.props;
54 const account = form.getFieldValue('mail'); 53 const account = form.getFieldValue('mail');
55 - if (register.status === 'ok') { 54 + if (BLOCK_NAME_CAMEL_CASE.status === 'ok') {
56 router.push({ 55 router.push({
57 pathname: '/user/register-result', 56 pathname: '/user/register-result',
58 state: { 57 state: {
@@ -97,7 +96,7 @@ class Register extends Component { @@ -97,7 +96,7 @@ class Register extends Component {
97 if (!err) { 96 if (!err) {
98 const { prefix } = this.state; 97 const { prefix } = this.state;
99 dispatch({ 98 dispatch({
100 - type: 'register/submit', 99 + type: 'BLOCK_NAME_CAMEL_CASE/submit',
101 payload: { 100 payload: {
102 ...values, 101 ...values,
103 prefix, 102 prefix,
@@ -179,159 +178,157 @@ class Register extends Component { @@ -179,159 +178,157 @@ class Register extends Component {
179 const { getFieldDecorator } = form; 178 const { getFieldDecorator } = form;
180 const { count, prefix, help, visible } = this.state; 179 const { count, prefix, help, visible } = this.state;
181 return ( 180 return (
182 - <UserLayout>  
183 - <div className={styles.main}>  
184 - <h3>  
185 - <FormattedMessage id="app.register.register" />  
186 - </h3>  
187 - <Form onSubmit={this.handleSubmit}>  
188 - <FormItem>  
189 - {getFieldDecorator('mail', { 181 + <div className={styles.main}>
  182 + <h3>
  183 + <FormattedMessage id="app.register.register" />
  184 + </h3>
  185 + <Form onSubmit={this.handleSubmit}>
  186 + <FormItem>
  187 + {getFieldDecorator('mail', {
  188 + rules: [
  189 + {
  190 + required: true,
  191 + message: formatMessage({ id: 'validation.email.required' }),
  192 + },
  193 + {
  194 + type: 'email',
  195 + message: formatMessage({ id: 'validation.email.wrong-format' }),
  196 + },
  197 + ],
  198 + })(
  199 + <Input size="large" placeholder={formatMessage({ id: 'form.email.placeholder' })} />
  200 + )}
  201 + </FormItem>
  202 + <FormItem help={help}>
  203 + <Popover
  204 + getPopupContainer={node => node.parentNode}
  205 + content={
  206 + <div style={{ padding: '4px 0' }}>
  207 + {passwordStatusMap[this.getPasswordStatus()]}
  208 + {this.renderPasswordProgress()}
  209 + <div style={{ marginTop: 10 }}>
  210 + <FormattedMessage id="validation.password.strength.msg" />
  211 + </div>
  212 + </div>
  213 + }
  214 + overlayStyle={{ width: 240 }}
  215 + placement="right"
  216 + visible={visible}
  217 + >
  218 + {getFieldDecorator('password', {
190 rules: [ 219 rules: [
191 { 220 {
192 - required: true,  
193 - message: formatMessage({ id: 'validation.email.required' }),  
194 - },  
195 - {  
196 - type: 'email',  
197 - message: formatMessage({ id: 'validation.email.wrong-format' }), 221 + validator: this.checkPassword,
198 }, 222 },
199 ], 223 ],
200 })( 224 })(
201 - <Input size="large" placeholder={formatMessage({ id: 'form.email.placeholder' })} /> 225 + <Input
  226 + size="large"
  227 + type="password"
  228 + placeholder={formatMessage({ id: 'form.password.placeholder' })}
  229 + />
202 )} 230 )}
203 - </FormItem>  
204 - <FormItem help={help}>  
205 - <Popover  
206 - getPopupContainer={node => node.parentNode}  
207 - content={  
208 - <div style={{ padding: '4px 0' }}>  
209 - {passwordStatusMap[this.getPasswordStatus()]}  
210 - {this.renderPasswordProgress()}  
211 - <div style={{ marginTop: 10 }}>  
212 - <FormattedMessage id="validation.password.strength.msg" />  
213 - </div>  
214 - </div>  
215 - }  
216 - overlayStyle={{ width: 240 }}  
217 - placement="right"  
218 - visible={visible} 231 + </Popover>
  232 + </FormItem>
  233 + <FormItem>
  234 + {getFieldDecorator('confirm', {
  235 + rules: [
  236 + {
  237 + required: true,
  238 + message: formatMessage({ id: 'validation.confirm-password.required' }),
  239 + },
  240 + {
  241 + validator: this.checkConfirm,
  242 + },
  243 + ],
  244 + })(
  245 + <Input
  246 + size="large"
  247 + type="password"
  248 + placeholder={formatMessage({ id: 'form.confirm-password.placeholder' })}
  249 + />
  250 + )}
  251 + </FormItem>
  252 + <FormItem>
  253 + <InputGroup compact>
  254 + <Select
  255 + size="large"
  256 + value={prefix}
  257 + onChange={this.changePrefix}
  258 + style={{ width: '20%' }}
219 > 259 >
220 - {getFieldDecorator('password', {  
221 - rules: [  
222 - {  
223 - validator: this.checkPassword,  
224 - },  
225 - ],  
226 - })(  
227 - <Input  
228 - size="large"  
229 - type="password"  
230 - placeholder={formatMessage({ id: 'form.password.placeholder' })}  
231 - />  
232 - )}  
233 - </Popover>  
234 - </FormItem>  
235 - <FormItem>  
236 - {getFieldDecorator('confirm', { 260 + <Option value="86">+86</Option>
  261 + <Option value="87">+87</Option>
  262 + </Select>
  263 + {getFieldDecorator('mobile', {
237 rules: [ 264 rules: [
238 { 265 {
239 required: true, 266 required: true,
240 - message: formatMessage({ id: 'validation.confirm-password.required' }), 267 + message: formatMessage({ id: 'validation.phone-number.required' }),
241 }, 268 },
242 { 269 {
243 - validator: this.checkConfirm, 270 + pattern: /^\d{11}$/,
  271 + message: formatMessage({ id: 'validation.phone-number.wrong-format' }),
244 }, 272 },
245 ], 273 ],
246 })( 274 })(
247 <Input 275 <Input
248 size="large" 276 size="large"
249 - type="password"  
250 - placeholder={formatMessage({ id: 'form.confirm-password.placeholder' })} 277 + style={{ width: '80%' }}
  278 + placeholder={formatMessage({ id: 'form.phone-number.placeholder' })}
251 /> 279 />
252 )} 280 )}
253 - </FormItem>  
254 - <FormItem>  
255 - <InputGroup compact>  
256 - <Select  
257 - size="large"  
258 - value={prefix}  
259 - onChange={this.changePrefix}  
260 - style={{ width: '20%' }}  
261 - >  
262 - <Option value="86">+86</Option>  
263 - <Option value="87">+87</Option>  
264 - </Select>  
265 - {getFieldDecorator('mobile', { 281 + </InputGroup>
  282 + </FormItem>
  283 + <FormItem>
  284 + <Row gutter={8}>
  285 + <Col span={16}>
  286 + {getFieldDecorator('captcha', {
266 rules: [ 287 rules: [
267 { 288 {
268 required: true, 289 required: true,
269 - message: formatMessage({ id: 'validation.phone-number.required' }),  
270 - },  
271 - {  
272 - pattern: /^\d{11}$/,  
273 - message: formatMessage({ id: 'validation.phone-number.wrong-format' }), 290 + message: formatMessage({ id: 'validation.verification-code.required' }),
274 }, 291 },
275 ], 292 ],
276 })( 293 })(
277 <Input 294 <Input
278 size="large" 295 size="large"
279 - style={{ width: '80%' }}  
280 - placeholder={formatMessage({ id: 'form.phone-number.placeholder' })} 296 + placeholder={formatMessage({ id: 'form.verification-code.placeholder' })}
281 /> 297 />
282 )} 298 )}
283 - </InputGroup>  
284 - </FormItem>  
285 - <FormItem>  
286 - <Row gutter={8}>  
287 - <Col span={16}>  
288 - {getFieldDecorator('captcha', {  
289 - rules: [  
290 - {  
291 - required: true,  
292 - message: formatMessage({ id: 'validation.verification-code.required' }),  
293 - },  
294 - ],  
295 - })(  
296 - <Input  
297 - size="large"  
298 - placeholder={formatMessage({ id: 'form.verification-code.placeholder' })}  
299 - />  
300 - )}  
301 - </Col>  
302 - <Col span={8}>  
303 - <Button  
304 - size="large"  
305 - disabled={count}  
306 - className={styles.getCaptcha}  
307 - onClick={this.onGetCaptcha}  
308 - >  
309 - {count  
310 - ? `${count} s`  
311 - : formatMessage({ id: 'app.register.get-verification-code' })}  
312 - </Button>  
313 - </Col>  
314 - </Row>  
315 - </FormItem>  
316 - <FormItem>  
317 - <Button  
318 - size="large"  
319 - loading={submitting}  
320 - className={styles.submit}  
321 - type="primary"  
322 - htmlType="submit"  
323 - >  
324 - <FormattedMessage id="app.register.register" />  
325 - </Button>  
326 - <Link className={styles.login} to="/User/Login">  
327 - <FormattedMessage id="app.register.sign-in" />  
328 - </Link>  
329 - </FormItem>  
330 - </Form>  
331 - </div>  
332 - </UserLayout> 299 + </Col>
  300 + <Col span={8}>
  301 + <Button
  302 + size="large"
  303 + disabled={count}
  304 + className={styles.getCaptcha}
  305 + onClick={this.onGetCaptcha}
  306 + >
  307 + {count
  308 + ? `${count} s`
  309 + : formatMessage({ id: 'app.register.get-verification-code' })}
  310 + </Button>
  311 + </Col>
  312 + </Row>
  313 + </FormItem>
  314 + <FormItem>
  315 + <Button
  316 + size="large"
  317 + loading={submitting}
  318 + className={styles.submit}
  319 + type="primary"
  320 + htmlType="submit"
  321 + >
  322 + <FormattedMessage id="app.register.register" />
  323 + </Button>
  324 + <Link className={styles.login} to="/User/Login">
  325 + <FormattedMessage id="app.register.sign-in" />
  326 + </Link>
  327 + </FormItem>
  328 + </Form>
  329 + </div>
333 ); 330 );
334 } 331 }
335 } 332 }
336 333
337 -export default Register; 334 +export default PAGE_NAME_UPPER_CAMEL_CASE;
1 import { fakeRegister } from './service'; 1 import { fakeRegister } from './service';
2 -import { setAuthority } from './utils/authority';  
3 -import { reloadAuthorized } from './utils/Authorized';  
4 2
5 export default { 3 export default {
6 - namespace: 'register', 4 + namespace: 'BLOCK_NAME_CAMEL_CASE',
7 5
8 state: { 6 state: {
9 status: undefined, 7 status: undefined,
@@ -21,8 +19,6 @@ export default { @@ -21,8 +19,6 @@ export default {
21 19
22 reducers: { 20 reducers: {
23 registerHandle(state, { payload }) { 21 registerHandle(state, { payload }) {
24 - setAuthority('user');  
25 - reloadAuthorized();  
26 return { 22 return {
27 ...state, 23 ...state,
28 status: payload.status, 24 status: payload.status,
1 import request from 'umi-request'; 1 import request from 'umi-request';
2 2
3 export async function fakeRegister(params) { 3 export async function fakeRegister(params) {
4 - return request('/api/register', { 4 + return request('/api/BLOCK_NAME/register', {
5 method: 'POST', 5 method: 'POST',
6 body: params, 6 body: params,
7 }); 7 });
1 -import RenderAuthorized from 'ant-design-pro/lib/Authorized';  
2 -import { getAuthority } from './authority';  
3 -  
4 -let Authorized = RenderAuthorized(getAuthority()); // eslint-disable-line  
5 -  
6 -// Reload the rights component  
7 -const reloadAuthorized = () => {  
8 - Authorized = RenderAuthorized(getAuthority());  
9 -};  
10 -  
11 -export { reloadAuthorized };  
12 -export default Authorized;  
1 -// use localStorage to store the authority info, which might be sent from server in actual project.  
2 -export function getAuthority(str) {  
3 - // return localStorage.getItem('antd-pro-authority') || ['admin', 'user'];  
4 - const authorityString =  
5 - typeof str === 'undefined' ? localStorage.getItem('antd-pro-authority') : str;  
6 - // authorityString could be admin, "admin", ["admin"]  
7 - let authority;  
8 - try {  
9 - authority = JSON.parse(authorityString);  
10 - } catch (e) {  
11 - authority = authorityString;  
12 - }  
13 - if (typeof authority === 'string') {  
14 - return [authority];  
15 - }  
16 - return authority || ['admin'];  
17 -}  
18 -  
19 -export function setAuthority(authority) {  
20 - const proAuthority = typeof authority === 'string' ? [authority] : authority;  
21 - return localStorage.setItem('antd-pro-authority', JSON.stringify(proAuthority));  
22 -}  
1 -import moment from 'moment';  
2 -import React from 'react';  
3 -import nzh from 'nzh/cn';  
4 -import { parse, stringify } from 'qs';  
5 -  
6 -export function fixedZero(val) {  
7 - return val * 1 < 10 ? `0${val}` : val;  
8 -}  
9 -  
10 -export function getTimeDistance(type) {  
11 - const now = new Date();  
12 - const oneDay = 1000 * 60 * 60 * 24;  
13 -  
14 - if (type === 'today') {  
15 - now.setHours(0);  
16 - now.setMinutes(0);  
17 - now.setSeconds(0);  
18 - return [moment(now), moment(now.getTime() + (oneDay - 1000))];  
19 - }  
20 -  
21 - if (type === 'week') {  
22 - let day = now.getDay();  
23 - now.setHours(0);  
24 - now.setMinutes(0);  
25 - now.setSeconds(0);  
26 -  
27 - if (day === 0) {  
28 - day = 6;  
29 - } else {  
30 - day -= 1;  
31 - }  
32 -  
33 - const beginTime = now.getTime() - day * oneDay;  
34 -  
35 - return [moment(beginTime), moment(beginTime + (7 * oneDay - 1000))];  
36 - }  
37 -  
38 - if (type === 'month') {  
39 - const year = now.getFullYear();  
40 - const month = now.getMonth();  
41 - const nextDate = moment(now).add(1, 'months');  
42 - const nextYear = nextDate.year();  
43 - const nextMonth = nextDate.month();  
44 -  
45 - return [  
46 - moment(`${year}-${fixedZero(month + 1)}-01 00:00:00`),  
47 - moment(moment(`${nextYear}-${fixedZero(nextMonth + 1)}-01 00:00:00`).valueOf() - 1000),  
48 - ];  
49 - }  
50 -  
51 - const year = now.getFullYear();  
52 - return [moment(`${year}-01-01 00:00:00`), moment(`${year}-12-31 23:59:59`)];  
53 -}  
54 -  
55 -export function getPlainNode(nodeList, parentPath = '') {  
56 - const arr = [];  
57 - nodeList.forEach(node => {  
58 - const item = node;  
59 - item.path = `${parentPath}/${item.path || ''}`.replace(/\/+/g, '/');  
60 - item.exact = true;  
61 - if (item.children && !item.component) {  
62 - arr.push(...getPlainNode(item.children, item.path));  
63 - } else {  
64 - if (item.children && item.component) {  
65 - item.exact = false;  
66 - }  
67 - arr.push(item);  
68 - }  
69 - });  
70 - return arr;  
71 -}  
72 -  
73 -export function digitUppercase(n) {  
74 - return nzh.toMoney(n);  
75 -}  
76 -  
77 -function getRelation(str1, str2) {  
78 - if (str1 === str2) {  
79 - console.warn('Two path are equal!'); // eslint-disable-line  
80 - }  
81 - const arr1 = str1.split('/');  
82 - const arr2 = str2.split('/');  
83 - if (arr2.every((item, index) => item === arr1[index])) {  
84 - return 1;  
85 - }  
86 - if (arr1.every((item, index) => item === arr2[index])) {  
87 - return 2;  
88 - }  
89 - return 3;  
90 -}  
91 -  
92 -function getRenderArr(routes) {  
93 - let renderArr = [];  
94 - renderArr.push(routes[0]);  
95 - for (let i = 1; i < routes.length; i += 1) {  
96 - // 去重  
97 - renderArr = renderArr.filter(item => getRelation(item, routes[i]) !== 1);  
98 - // 是否包含  
99 - const isAdd = renderArr.every(item => getRelation(item, routes[i]) === 3);  
100 - if (isAdd) {  
101 - renderArr.push(routes[i]);  
102 - }  
103 - }  
104 - return renderArr;  
105 -}  
106 -  
107 -/**  
108 - * Get router routing configuration  
109 - * { path:{name,...param}}=>Array<{name,path ...param}>  
110 - * @param {string} path  
111 - * @param {routerData} routerData  
112 - */  
113 -export function getRoutes(path, routerData) {  
114 - let routes = Object.keys(routerData).filter(  
115 - routePath => routePath.indexOf(path) === 0 && routePath !== path  
116 - );  
117 - // Replace path to '' eg. path='user' /user/name => name  
118 - routes = routes.map(item => item.replace(path, ''));  
119 - // Get the route to be rendered to remove the deep rendering  
120 - const renderArr = getRenderArr(routes);  
121 - // Conversion and stitching parameters  
122 - const renderRoutes = renderArr.map(item => {  
123 - const exact = !routes.some(route => route !== item && getRelation(route, item) === 1);  
124 - return {  
125 - exact,  
126 - ...routerData[`${path}${item}`],  
127 - key: `${path}${item}`,  
128 - path: `${path}${item}`,  
129 - };  
130 - });  
131 - return renderRoutes;  
132 -}  
133 -  
134 -export function getPageQuery() {  
135 - return parse(window.location.href.split('?')[1]);  
136 -}  
137 -  
138 -export function getQueryPath(path = '', query = {}) {  
139 - const search = stringify(query);  
140 - if (search.length) {  
141 - return `${path}?${search}`;  
142 - }  
143 - return path;  
144 -}  
145 -  
146 -/* eslint no-useless-escape:0 */  
147 -const reg = /(((^https?:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+(?::\d+)?|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[\w]*))?)$/;  
148 -  
149 -export function isUrl(path) {  
150 - return reg.test(path);  
151 -}  
152 -  
153 -export function formatWan(val) {  
154 - const v = val * 1;  
155 - if (!v || Number.isNaN(v)) return '';  
156 -  
157 - let result = val;  
158 - if (val > 10000) {  
159 - result = Math.floor(val / 10000);  
160 - result = (  
161 - <span>  
162 - {result}  
163 - <span  
164 - style={{  
165 - position: 'relative',  
166 - top: -2,  
167 - fontSize: 14,  
168 - fontStyle: 'normal',  
169 - marginLeft: 2,  
170 - }}  
171 - >  
172 -  
173 - </span>  
174 - </span>  
175 - );  
176 - }  
177 - return result;  
178 -}  
179 -  
180 -// 给官方演示站点用,用于关闭真实开发环境不需要使用的特性  
181 -export function isAntdPro() {  
182 - return window.location.hostname === 'preview.pro.ant.design';  
183 -}  
注册登录 后发表评论