《Ant Design Pro v5 获取动态菜单与基于角色权限管理视频教程》 和 《零基础学习 Vue3 教程 2021 年最新教程 免费视频教程》 正在更新
世界上最伟大的投资就是投资自己的教育
https://ant.design/components/button-cn/
new.tsx
import { Form, Input, Row, Col, Button, message } from 'antd';
import React from 'react';
import styles from './style.less';
import { FormComponentProps } from 'antd/es/form';
import { Dispatch } from 'redux';
import { StateType } from './model';
import { connect } from 'dva';
import router from 'umi/router';
interface RegisterProps extends FormComponentProps {
dispatch: Dispatch<any>;
userRegister: StateType;
submitting: boolean;
}
interface RegisterState {
count: number;
disabled: boolean;
}
export interface UserRegisterParams {
user: {
email: string;
username: string;
password: string;
password_confirmation: string;
phone: string;
code: string;
};
}
export interface CaptchaParams {
mobile: string;
}
@connect(
({
userRegister,
loading,
}: {
userRegister: StateType;
loading: {
effects: {
[key: string]: string;
};
};
}) => ({
userRegister,
submitting: loading.effects['userRegister/submit'],
}),
)
class RegistrationForm extends React.Component<RegisterProps, RegisterState> {
state: RegisterState = {
count: 0,
disabled: false,
};
componentDidUpdate() {
const { userRegister } = this.props;
if (userRegister.success) {
message.success('注册成功!');
router.push({
pathname: '/',
state: {},
});
}
}
handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
const { dispatch, form } = this.props;
form.validateFieldsAndScroll((err, values) => {
dispatch({
type: 'userRegister/submit',
payload: { ...values },
});
});
};
interval: number | undefined = undefined;
onGetCaptcha = () => {
const { form, dispatch } = this.props;
const phone = form.getFieldValue('user[phone]');
if (phone === undefined || phone.trim() === '') {
message.error('请输入手机号码');
return;
}
let count = 59;
this.setState({
count,
disabled: true,
});
this.interval = window.setInterval(() => {
count -= 1;
this.setState({
count,
});
if (count === 0) {
clearInterval(this.interval);
this.setState({
disabled: false,
});
}
}, 1000);
dispatch({
type: 'userRegister/getCaptcha',
payload: { mobile: phone },
});
};
onGetCaptchaImage = () => {
// const randomString =
// Math.random()
// .toString(36)
// .substring(2, 15) +
// Math.random()
// .toString(36)
// .substring(2, 15);
// const randomString = uuidv4();
// this.setState({
// image: `http://localhost:5000/rucaptcha?a=${randomString}`,
// });
const { dispatch } = this.props;
dispatch({
type: 'userRegister/onGetCaptchaImage',
});
};
render() {
const { submitting, userRegister } = this.props;
const { getFieldDecorator } = this.props.form;
const { errors, image } = userRegister;
const { count, disabled } = this.state;
const formItemLayout = {
labelCol: {
xs: { span: 24 },
sm: { span: 8 },
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 16 },
},
};
const tailFormItemLayout = {
wrapperCol: {
xs: {
span: 24,
offset: 0,
},
sm: {
span: 16,
offset: 8,
},
},
};
return (
<div className={styles.custom_form}>
<Form {...formItemLayout} onSubmit={this.handleSubmit}>
<Form.Item
validateStatus={errors.username ? 'error' : ''}
help={errors.username ? errors.username.join(', ') : ''}
label={<span>Username </span>}
>
{getFieldDecorator('user[username]')(<Input />)}
</Form.Item>
<Form.Item
validateStatus={errors.email ? 'error' : ''}
help={errors.email ? errors.email.join(', ') : ''}
label="E-mail"
>
{getFieldDecorator('user[email]')(<Input type="email" />)}
</Form.Item>
<Form.Item
validateStatus={errors.password ? 'error' : ''}
help={errors.password ? errors.password.join(', ') : ''}
label="Password"
hasFeedback
>
{getFieldDecorator('user[password]')(<Input.Password />)}
</Form.Item>
<Form.Item
validateStatus={errors.password_confirmation ? 'error' : ''}
help={errors.password_confirmation ? errors.password_confirmation.join(', ') : ''}
label="Confirm Password"
hasFeedback
>
{getFieldDecorator('user[password_confirmation]')(<Input.Password />)}
</Form.Item>
<Form.Item
validateStatus={errors.phone ? 'error' : ''}
help={errors.phone ? errors.phone.join(', ') : ''}
label="Phone Number"
>
{getFieldDecorator('user[phone]')(<Input style={{ width: '100%' }} />)}
</Form.Item>
<Form.Item
validateStatus={errors.code ? 'error' : ''}
help={errors.code ? errors.code.join(', ') : ''}
label="Captcha"
extra="We must make sure that your are a human."
>
<Row gutter={8}>
<Col span={12}>{getFieldDecorator('user[code]')(<Input />)}</Col>
<Col span={12}>
<Button disabled={disabled} onClick={this.onGetCaptcha}>
{count ? `${count} s` : '获取验证码'}
</Button>
</Col>
</Row>
</Form.Item>
<Form.Item
validateStatus={errors.rucaptcha ? 'error' : ''}
help={errors.rucaptcha ? errors.rucaptcha.join(', ') : ''}
label="图形验证码"
>
<Row gutter={8}>
<Col span={12}>{getFieldDecorator('_rucaptcha')(<Input />)}</Col>
<Col span={12}>
<img src={image} onClick={this.onGetCaptchaImage} />
</Col>
</Row>
</Form.Item>
<Form.Item {...tailFormItemLayout}>
<Button loading={submitting} type="primary" htmlType="submit">
Register
</Button>
</Form.Item>
</Form>
</div>
);
}
}
export default Form.create<RegisterProps>({ name: 'register' })(RegistrationForm);
model.ts
import { AnyAction, Reducer } from 'redux';
import { EffectsCommandMap } from 'dva';
import { fakeRegister, fakeCaptcha } from './service';
import uuidv4 from 'uuid/v4';
export interface StateType {
success?: boolean;
currentAuthority?: 'user' | 'guest' | 'admin';
errors?: any;
image?: string;
response?: any;
}
export type Effect = (
action: AnyAction,
effects: EffectsCommandMap & { select: <T>(func: (state: StateType) => T) => T },
) => void;
export interface ModelType {
namespace: string;
state: StateType;
effects: {
submit: Effect;
getCaptcha: Effect;
onGetCaptchaImage: Effect;
};
reducers: {
registerHandle: Reducer<StateType>;
errorsHandle: Reducer<StateType>;
setCaptchaImage: Reducer<StateType>;
clearErrors: Reducer<StateType>;
};
}
const Model: ModelType = {
namespace: 'userRegister',
state: {
success: false,
errors: {},
response: {},
image: 'http://localhost:5000/rucaptcha',
},
effects: {
*submit({ payload }, { call, put }) {
try {
const response = yield call(fakeRegister, payload);
yield put({
type: 'registerHandle',
payload: response,
});
yield put({
type: 'clearErrors',
});
} catch (e) {
yield put({
type: 'errorsHandle',
payload: e.data.errors,
});
yield put({
type: 'onGetCaptchaImage',
});
}
},
*onGetCaptchaImage({}, { put }) {
yield put({
type: 'setCaptchaImage',
});
},
*getCaptcha({ payload }, { call }) {
yield call(fakeCaptcha, payload);
},
},
reducers: {
registerHandle(state, { payload }) {
return {
...state,
success: payload.success,
response: payload.response,
};
},
errorsHandle(state, { payload }) {
return {
...state,
errors: payload,
};
},
clearErrors(state, {}) {
return {
...state,
errors: {},
};
},
setCaptchaImage(state, {}) {
const randomString = uuidv4();
return {
...state,
image: `http://localhost:5000/rucaptcha?a=${randomString}`,
};
},
},
};
export default Model;
1FreeUmiJS & TypeScript & Ant Design Pro v4 从零开始实战教程 #1 开始玩起来
2FreeUmiJS & TypeScript & Ant Design Pro v4 从零开始实战教程 #2 了解项目源码并尝试修改
3FreeUmiJS & TypeScript & Ant Design Pro v4 从零开始实战教程 #3 继续了解项目源码并修改代码
4FreeUmiJS & TypeScript & Ant Design Pro v4 从零开始实战教程 #4 如何修改 footer 及其原理
5FreeUmiJS & TypeScript & Ant Design Pro v4 从零开始实战教程 #5 关于 footer 和 layout
6ProUmiJS & TypeScript & Ant Design Pro v4 从零开始实战教程 #6 如何好好利用 ant-design-pro-layout
7ProUmiJS & TypeScript & Ant Design Pro v4 从零开始实战教程 #7 如何下载和使用区块
8ProUmiJS & TypeScript & Ant Design Pro v4 从零开始实战教程 #8 为什么下载区块后会添加菜单
9ProUmiJS & TypeScript & Ant Design Pro v4 从零开始实战教程 #9 umi-plugin-pro-block-ts
10ProUmiJS & TypeScript & Ant Design Pro v4 从零开始实战教程 #10 删除国际化 i18n part 1
11ProUmiJS & TypeScript & Ant Design Pro v4 从零开始实战教程 #11 删除国际化 i18n part 2
12ProUmiJS & TypeScript & Ant Design Pro v4 从零开始实战教程 #12 用户注册的 block
13ProUmiJS & TypeScript & Ant Design Pro v4 从零开始实战教程 #13 让用户注册工作起来
14ProUmiJS & TypeScript & Ant Design Pro v4 从零开始实战教程 #14 注册的流程理解
15ProUmiJS & TypeScript & Ant Design Pro v4 从零开始实战教程 #15 准备好 API
16ProUmiJS & TypeScript & Ant Design Pro v4 从零开始实战教程 #16 对接好后端的注册功能
17ProUmiJS & TypeScript & Ant Design Pro v4 从零开始实战教程 #17 表单的前端验证与后端验证
18ProUmiJS & TypeScript & Ant Design Pro v4 从零开始实战教程 #18 后端的数据验证与前端的结合
19ProUmiJS & TypeScript & Ant Design Pro v4 从零开始实战教程 #19 自己写一个真实项目的注册页面 - 手机验证码 - 图形验证码
20ProUmiJS & TypeScript & Ant Design Pro v4 从零开始实战教程 #20 注册表单
21ProUmiJS & TypeScript & Ant Design Pro v4 从零开始实战教程 #21 表单与 TypeScript
22ProUmiJS & TypeScript & Ant Design Pro v4 从零开始实战教程 #22 注册表单 - connect - dispatch
23ProUmiJS & TypeScript & Ant Design Pro v4 从零开始实战教程 #23 实现注册功能并显示验证出错信息
24ProUmiJS & TypeScript & Ant Design Pro v4 从零开始实战教程 #24 详解注册页面手机验证码
25ProUmiJS & TypeScript & Ant Design Pro v4 从零开始实战教程 #25 注册页面手机验证码处理完成
26ProUmiJS & TypeScript & Ant Design Pro v4 从零开始实战教程 #26 手机验证码的原理(后端)
27ProUmiJS & TypeScript & Ant Design Pro v4 从零开始实战教程 #27 注册页面显示图形验证码
28ProUmiJS & TypeScript & Ant Design Pro v4 从零开始实战教程 #28 注册页面图形验证码的原理
29ProUmiJS & TypeScript & Ant Design Pro v4 从零开始实战教程 #29 注册页面提交失败时图形验证码重新刷新
FreeUmiJS & TypeScript & Ant Design Pro v4 从零开始实战教程 #30 注册页面成功跳转
31ProUmiJS & TypeScript & Ant Design Pro v4 从零开始实战教程 #31 用 localStorage 存储 jwt
32FreeUmiJS & TypeScript & Ant Design Pro v4 从零开始实战教程 #32 重构代码,封装 request
33ProUmiJS & TypeScript & Ant Design Pro v4 从零开始实战教程 #33 登录页面
34ProUmiJS & TypeScript & Ant Design Pro v4 从零开始实战教程 #34 完成登录
35ProUmiJS & TypeScript & Ant Design Pro v4 从零开始实战教程 #35 登录权限验证 - 发送请求带上头信息
36ProUmiJS & TypeScript & Ant Design Pro v4 从零开始实战教程 #36 登录权限验证 - umi-request 异常处理程序
37ProUmiJS & TypeScript & Ant Design Pro v4 从零开始实战教程 #37 解决 umi-request 的 extend 关于 headers 的问题
38ProUmiJS & TypeScript & Ant Design Pro v4 从零开始实战教程 #38 显示个人用户信息
39ProUmiJS & TypeScript & Ant Design Pro v4 从零开始实战教程 #39 菜单权限控制显示
40ProUmiJS & TypeScript & Ant Design Pro v4 从零开始实战教程 #40 通过修改 getAuthority 方法利用 jwt 显示正确的菜单权限
41ProUmiJS & TypeScript & Ant Design Pro v4 从零开始实战教程 #41 刷新当前权限
42ProUmiJS & TypeScript & Ant Design Pro v4 从零开始实战教程 #42 其他的权限方法 - 从远程服务器获取菜单
43ProUmiJS & TypeScript & Ant Design Pro v4 从零开始实战教程 #43 权限验证的安全性(准备进入下一阶段)
44ProUmiJS & TypeScript & Ant Design Pro v4 从零开始实战教程 #44 实战 - 视频管理
45ProUmiJS & TypeScript & Ant Design Pro v4 从零开始实战教程 #45 实战 - 视频管理 - 视频列表
46ProUmiJS & TypeScript & Ant Design Pro v4 从零开始实战教程 #46 实战 - 视频管理 - 视频列表 - 发送请求获得远程的数据
47ProUmiJS & TypeScript & Ant Design Pro v4 从零开始实战教程 #47 实战 - 视频管理 - 视频列表 - 显示列表数据
48ProUmiJS & TypeScript & Ant Design Pro v4 从零开始实战教程 #48 实战 - 视频管理 - 视频列表 - 修复列表数据
49ProUmiJS & TypeScript & Ant Design Pro v4 从零开始实战教程 #49 实战 - 视频管理 - 视频列表 - 搜索列表
50ProUmiJS & TypeScript & Ant Design Pro v4 从零开始实战教程 #50 实战 - 视频管理 - 搜索 - 使用 qs 处理 umi-request 提交参数的问题
51ProUmiJS & TypeScript & Ant Design Pro v4 从零开始实战教程 #51 实战 - 视频管理 - 搜索 - 处理 moment 的时间问题
52ProUmiJS & TypeScript & Ant Design Pro v4 从零开始实战教程 #52 实战 - 视频管理 - 完成分页
53ProUmiJS & TypeScript & Ant Design Pro v4 从零开始实战教程 #53 实战 - 视频管理 - 添加视频
54ProUmiJS & TypeScript & Ant Design Pro v4 从零开始实战教程 #54 实战 - 视频管理 - 添加视频 - 发送请求
55ProUmiJS & TypeScript & Ant Design Pro v4 从零开始实战教程 #55 实战 - 视频管理 - 添加视频 - 处理完成
56ProUmiJS & TypeScript & Ant Design Pro v4 从零开始实战教程 #56 实战 - 视频管理 - 错误处理
57ProUmiJS & TypeScript & Ant Design Pro v4 从零开始实战教程 #57 实战 - 视频管理 - 详情页面
58ProUmiJS & TypeScript & Ant Design Pro v4 从零开始实战教程 #58 实战 - 视频管理 - 完成详情页面
59ProUmiJS & TypeScript & Ant Design Pro v4 从零开始实战教程 #59 实战 - 视频管理 - 删除视频
60ProUmiJS & TypeScript & Ant Design Pro v4 从零开始实战教程 #60 实战 - 视频管理 - 添加视频
61ProUmiJS & TypeScript & Ant Design Pro v4 从零开始实战教程 #61 实战 - 视频管理 - 添加视频 part 2
62ProUmiJS & TypeScript & Ant Design Pro v4 从零开始实战教程 #62 实战 - 视频管理 - 添加视频 part 3
© 汕尾市求知科技有限公司 | 关注我们 | 专业版网站 | 在线学员:1122
粤公网安备 44152102000088号 | 粤ICP备19038915号