Commit 5d25742b authored by 陈帅's avatar 陈帅

StepForm finish

parent 66635a08
export default {
'POST /api/BLOCK_NAME/forms': (req, res) => {
'POST /api/BLOCK_NAME/forms': (req: any, res: { send: (arg0: { message: string }) => void }) => {
res.send({ message: 'Ok' });
},
};
import React from 'react';
import { FormattedMessage } from 'umi-plugin-react/locale';
import Link from 'umi/link';
import { PageHeader } from 'ant-design-pro';
import styles from './index.less';
const PageHeaderWrapper = ({ children, wrapperClassName, ...restProps }) => (
<div style={{ margin: '-24px -24px 0' }} className={wrapperClassName}>
<PageHeader
home={<FormattedMessage id="BLOCK_NAME.menu.home" defaultMessage="Home" />}
key="pageheader"
{...restProps}
linkElement={Link}
itemRender={item => {
if (item.locale) {
return <FormattedMessage id={item.locale} defaultMessage={item.title} />;
}
return item.title;
}}
/>
{children ? <div className={styles.content}>{children}</div> : null}
</div>
);
export default PageHeaderWrapper;
@import '~antd/lib/style/themes/default.less';
.content {
.children-content {
margin: 24px 24px 0;
}
@media screen and (max-width: @screen-sm) {
.main {
.detail {
display: flex;
}
.row {
display: flex;
width: 100%;
}
.title-content {
margin-bottom: 16px;
}
@media screen and (max-width: @screen-sm) {
.content {
margin: 24px 0 0;
}
}
.title,
.content {
margin: 24px 0 0;
flex: auto;
}
.extraContent,
.main {
flex: 0 1 auto;
}
.main {
width: 100%;
}
.title {
margin-bottom: 16px;
}
.logo,
.content,
.extraContent {
margin-bottom: 16px;
}
.extraContent {
min-width: 242px;
margin-left: 88px;
text-align: right;
}
}
@media screen and (max-width: @screen-xl) {
.extraContent {
margin-left: 44px;
}
}
@media screen and (max-width: @screen-lg) {
.extraContent {
margin-left: 20px;
}
}
@media screen and (max-width: @screen-md) {
.row {
display: block;
}
.action,
.extraContent {
margin-left: 0;
text-align: left;
}
}
@media screen and (max-width: @screen-sm) {
.detail {
display: block;
}
}
import React from 'react';
import { RouteContext } from '@ant-design/pro-layout';
import { PageHeader, Typography } from 'antd';
import styles from './index.less';
import { GridContent } from '@ant-design/pro-layout';
interface IPageHeaderWrapperProps {
content?: React.ReactNode;
title: React.ReactNode;
extraContent?: React.ReactNode;
}
const PageHeaderWrapper: React.SFC<IPageHeaderWrapperProps> = ({
children,
title,
content,
extraContent,
...restProps
}) => (
<RouteContext.Consumer>
{value => (
<div style={{ margin: '-24px -24px 0' }}>
<PageHeader
title={
<Typography.Title
level={4}
style={{
margin: 0,
}}
>
{title}
</Typography.Title>
}
{...restProps}
{...value}
>
<div className={styles.detail}>
<div className={styles.main}>
<div className={styles.row}>
{content && <div className={styles.content}>{content}</div>}
{extraContent && <div className={styles.extraContent}>{extraContent}</div>}
</div>
</div>
</div>
</PageHeader>
{children ? (
<GridContent>
<div className={styles['children-content']}>{children}</div>
</GridContent>
) : null}
</div>
)}
</RouteContext.Consumer>
);
export default PageHeaderWrapper;
@import '~antd/lib/style/themes/default.less';
.result {
width: 72%;
margin: 0 auto;
text-align: center;
@media screen and (max-width: @screen-xs) {
width: 100%;
}
.icon {
margin-bottom: 24px;
font-size: 72px;
line-height: 72px;
& > .success {
color: @success-color;
}
& > .error {
color: @error-color;
}
}
.title {
margin-bottom: 16px;
color: @heading-color;
font-weight: 500;
font-size: 24px;
line-height: 32px;
}
.description {
margin-bottom: 24px;
color: @text-color-secondary;
font-size: 14px;
line-height: 22px;
}
.extra {
padding: 24px 40px;
text-align: left;
background: #fafafa;
border-radius: @border-radius-sm;
@media screen and (max-width: @screen-xs) {
padding: 18px 20px;
}
}
.actions {
margin-top: 32px;
button:not(:last-child) {
margin-right: 8px;
}
}
}
import React from 'react';
import classNames from 'classnames';
import { Icon } from 'antd';
import styles from './index.less';
export interface ResultProps {
actions?: React.ReactNode;
className?: string;
description?: React.ReactNode;
extra?: React.ReactNode;
style?: React.CSSProperties;
title?: React.ReactNode;
type: 'success' | 'error';
}
const Result: React.SFC<ResultProps> = ({
className,
type,
title,
description,
extra,
actions,
...restProps
}) => {
const iconMap = {
error: <Icon className={styles.error} type="close-circle" theme="filled" />,
success: <Icon className={styles.success} type="check-circle" theme="filled" />,
};
const clsString = classNames(styles.result, className);
return (
<div className={clsString} {...restProps}>
<div className={styles.icon}>{iconMap[type]}</div>
<div className={styles.title}>{title}</div>
{description && <div className={styles.description}>{description}</div>}
{extra && <div className={styles.extra}>{extra}</div>}
{actions && <div className={styles.actions}>{actions}</div>}
</div>
);
};
export default Result;
......@@ -2,6 +2,9 @@ import React, { Fragment } from 'react';
import { connect } from 'dva';
import { Form, Input, Button, Select, Divider } from 'antd';
import styles from './index.less';
import { FormComponentProps } from 'antd/lib/form';
import { IStateType } from '../../model';
import { Dispatch } from 'redux';
const { Option } = Select;
......@@ -13,18 +16,21 @@ const formItemLayout = {
span: 19,
},
};
interface Step1Props extends FormComponentProps {
data?: IStateType['step'];
dispatch?: Dispatch;
}
@connect(({ BLOCK_NAME_CAMEL_CASE }) => ({
data: BLOCK_NAME_CAMEL_CASE.step,
}))
@Form.create()
class Step1 extends React.PureComponent {
class Step1 extends React.PureComponent<Step1Props> {
render() {
const { form, dispatch, data } = this.props;
if (!data) {
return;
}
const { getFieldDecorator, validateFields } = form;
const onValidateForm = () => {
validateFields((err, values) => {
if (!err) {
if (!err && dispatch) {
dispatch({
type: 'BLOCK_NAME_CAMEL_CASE/saveStepFormData',
payload: values,
......@@ -114,4 +120,6 @@ class Step1 extends React.PureComponent {
}
}
export default Step1;
export default connect(({ BLOCK_NAME_CAMEL_CASE }: { BLOCK_NAME_CAMEL_CASE: IStateType }) => ({
data: BLOCK_NAME_CAMEL_CASE.step,
}))(Form.create()(Step1));
import React from 'react';
import { connect } from 'dva';
import { Form, Input, Button, Alert, Divider } from 'antd';
import { digitUppercase } from '../../utils/utils';
import { Form, Input, Button, Alert, Divider, Statistic } from 'antd';
import styles from './index.less';
import { FormComponentProps } from 'antd/lib/form';
import { IStateType } from '../../model';
import { Dispatch } from 'redux';
const formItemLayout = {
labelCol: {
......@@ -12,33 +14,38 @@ const formItemLayout = {
span: 19,
},
};
interface Step2Props extends FormComponentProps {
data?: IStateType['step'];
dispatch?: Dispatch;
submitting?: boolean;
}
@connect(({ BLOCK_NAME_CAMEL_CASE, loading }) => ({
submitting: loading.effects['BLOCK_NAME_CAMEL_CASE/submitStepForm'],
data: BLOCK_NAME_CAMEL_CASE.step,
}))
@Form.create()
class Step2 extends React.PureComponent {
class Step2 extends React.Component<Step2Props> {
render() {
const { form, data, dispatch, submitting } = this.props;
if (!data) {
return;
}
const { getFieldDecorator, validateFields } = form;
const onPrev = () => {
dispatch({
type: 'BLOCK_NAME_CAMEL_CASE/saveCurrentStep',
payload: 'info',
});
dispatch &&
dispatch({
type: 'BLOCK_NAME_CAMEL_CASE/saveCurrentStep',
payload: 'info',
});
};
const onValidateForm = e => {
const onValidateForm = (e: React.FormEvent) => {
e.preventDefault();
validateFields((err, values) => {
if (!err) {
dispatch({
type: 'BLOCK_NAME_CAMEL_CASE/submitStepForm',
payload: {
...data,
...values,
},
});
dispatch &&
dispatch({
type: 'BLOCK_NAME_CAMEL_CASE/submitStepForm',
payload: {
...data,
...values,
},
});
}
});
};
......@@ -61,7 +68,6 @@ class Step2 extends React.PureComponent {
</Form.Item>
<Form.Item {...formItemLayout} className={styles.stepFormText} label="转账金额">
<span className={styles.money}>{data.amount}</span>
<span className={styles.uppercase}>{digitUppercase(data.amount)}</span>
</Form.Item>
<Divider style={{ margin: '24px 0' }} />
<Form.Item {...formItemLayout} label="支付密码" required={false}>
......@@ -97,5 +103,17 @@ class Step2 extends React.PureComponent {
);
}
}
export default Step2;
export default connect(
({
BLOCK_NAME_CAMEL_CASE,
loading,
}: {
BLOCK_NAME_CAMEL_CASE: IStateType;
loading: {
effects: { [key: string]: boolean };
};
}) => ({
submitting: loading.effects['BLOCK_NAME_CAMEL_CASE/submitStepForm'],
data: BLOCK_NAME_CAMEL_CASE.step,
})
)(Form.create()(Step2));
import React, { Fragment } from 'react';
import { connect } from 'dva';
import { Button, Row, Col } from 'antd';
import { Result } from 'ant-design-pro';
import Result from '../Result';
import styles from './index.less';
import { IStateType } from '../../model';
import { Dispatch } from 'redux';
@connect(({ BLOCK_NAME_CAMEL_CASE }) => ({
data: BLOCK_NAME_CAMEL_CASE.step,
}))
class Step3 extends React.PureComponent {
interface Step3Props {
data?: IStateType['step'];
dispatch?: Dispatch;
}
@connect(
({
BLOCK_NAME_CAMEL_CASE,
}: {
BLOCK_NAME_CAMEL_CASE: IStateType;
loading: {
effects: { [key: string]: boolean };
};
}) => ({
data: BLOCK_NAME_CAMEL_CASE.step,
})
)
class Step3 extends React.Component<Step3Props> {
render() {
const { data, dispatch } = this.props;
if (!data) {
return;
}
const onFinish = () => {
dispatch({
type: 'BLOCK_NAME_CAMEL_CASE/saveCurrentStep',
payload: 'info',
});
dispatch &&
dispatch({
type: 'BLOCK_NAME_CAMEL_CASE/saveCurrentStep',
payload: 'info',
});
};
const information = (
<div className={styles.information}>
......
import React, { PureComponent, Fragment } from 'react';
import React, { Component, Fragment } from 'react';
import { Card, Steps } from 'antd';
import { connect } from 'dva';
import PageHeaderWrapper from './components/PageHeaderWrapper';
......@@ -6,13 +6,18 @@ import Step1 from './components/Step1';
import Step2 from './components/Step2';
import Step3 from './components/Step3';
import styles from './style.less';
import { IStateType } from './model';
const { Step } = Steps;
@connect(({ BLOCK_NAME_CAMEL_CASE }) => ({
interface PAGE_NAME_UPPER_CAMEL_CASEProps {
current: IStateType['current'];
}
@connect(({ BLOCK_NAME_CAMEL_CASE }: { BLOCK_NAME_CAMEL_CASE: IStateType }) => ({
current: BLOCK_NAME_CAMEL_CASE.current,
}))
class PAGE_NAME_UPPER_CAMEL_CASE extends PureComponent {
class PAGE_NAME_UPPER_CAMEL_CASE extends Component<PAGE_NAME_UPPER_CAMEL_CASEProps> {
getCurrentStep() {
const { current } = this.props;
switch (current) {
......
import { fakeSubmitForm } from './service';
import { Reducer } from 'redux';
import { EffectsCommandMap } from 'dva';
import { AnyAction } from 'redux';
export default {
export interface IStateType {
current?: string;
step?: {
payAccount: string;
receiverAccount: string;
receiverName: string;
amount: string;
};
}
export type Effect = (
action: AnyAction,
effects: EffectsCommandMap & { select: <T>(func: (state: IStateType) => T) => T }
) => void;
export interface ModelType {
namespace: string;
state: IStateType;
effects: {
submitStepForm: Effect;
};
reducers: {
saveStepFormData: Reducer<IStateType>;
saveCurrentStep: Reducer<IStateType>;
};
}
const Model: ModelType = {
namespace: 'BLOCK_NAME_CAMEL_CASE',
state: {
......@@ -39,10 +69,12 @@ export default {
return {
...state,
step: {
...state.step,
...state!.step,
...payload,
},
};
},
},
};
export default Model;
import nzh from 'nzh/cn';
export function digitUppercase(n) {
return nzh.toMoney(n);
}
{
"private": true,
"scripts": {
"dev": "cross-env PAGES_PATH='SearchListProjects/src' umi dev",
"dev": "cross-env PAGES_PATH='StepForm/src' umi dev",
"lint:style": "stylelint \"src/**/*.less\" --syntax less",
"lint": "eslint --ext .js src mock tests && npm run lint:style",
"lint:fix": "eslint --fix --ext .js src mock tests && npm run lint:style",
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment