diff --git a/.umirc.js b/.umirc.js index 85f1038f928e8e09395f08268816b551e3e96b19..75ec0fc91214c0f490a31f8e6dd71856d8abe7d1 100644 --- a/.umirc.js +++ b/.umirc.js @@ -3,7 +3,7 @@ export default { [ 'umi-plugin-block-dev', { - layout: 'ant-design-pro', + layout: 'ant-design-pro-user', menu: { name: '主页', icon: 'home', diff --git a/UserLogin/src/_mock.js b/UserLogin/src/_mock.ts similarity index 100% rename from UserLogin/src/_mock.js rename to UserLogin/src/_mock.ts diff --git a/UserLogin/src/components/Login/LoginContext.tsx b/UserLogin/src/components/Login/LoginContext.tsx new file mode 100644 index 0000000000000000000000000000000000000000..6e46556ff6479612000b2cd0fc5a1290f05aacab --- /dev/null +++ b/UserLogin/src/components/Login/LoginContext.tsx @@ -0,0 +1,13 @@ +import { createContext } from 'react'; + +export interface ILoginContext { + tabUtil?: { + addTab: (id: string) => void; + removeTab: (id: string) => void; + }; + updateActive?: (activeItem: { [key: string]: string } | string) => void; +} + +const LoginContext: React.Context = createContext({}); + +export default LoginContext; diff --git a/UserLogin/src/components/Login/LoginItem.tsx b/UserLogin/src/components/Login/LoginItem.tsx new file mode 100644 index 0000000000000000000000000000000000000000..e3694eff163aa91b6dde13c947eaf16b0b9b16f2 --- /dev/null +++ b/UserLogin/src/components/Login/LoginItem.tsx @@ -0,0 +1,189 @@ +import React, { Component } from 'react'; +import { Form, Input, Button, Row, Col } from 'antd'; +import omit from 'omit.js'; +import styles from './index.less'; +import ItemMap from './map'; +import LoginContext, { ILoginContext } from './loginContext'; +import { FormComponentProps } from 'antd/lib/form'; + +type Omit = Pick>; + +export type WrappedLoginItemProps = Omit; +export type LoginItemKeyType = keyof typeof ItemMap; +export type LoginItemType = { [K in keyof typeof ItemMap]: React.FC }; + +export interface LoginItemProps extends FormComponentProps { + name?: string; + rules?: any[]; + style?: React.CSSProperties; + onGetCaptcha?: (event?: MouseEvent) => void | Promise | false; + placeholder?: string; + buttonText?: React.ReactNode; + onPressEnter?: (e: any) => void; + countDown?: number; + getCaptchaButtonText?: string; + getCaptchaSecondText?: string; + updateActive: ILoginContext['updateActive']; + type: string; + defaultValue?: string; + customProps?: { [key: string]: any }; + onChange?: (e: any) => void; +} + +interface LoginItemState { + count: number; +} + +const FormItem = Form.Item; + +class WrapFormItem extends Component { + static defaultProps = { + getCaptchaButtonText: 'captcha', + getCaptchaSecondText: 'second', + }; + + constructor(props: LoginItemProps) { + super(props); + this.state = { + count: 0, + }; + } + interval: number | undefined; + componentDidMount() { + const { updateActive, name = '' } = this.props; + if (updateActive) { + updateActive(name); + } + } + + componentWillUnmount() { + clearInterval(this.interval); + } + + onGetCaptcha = () => { + const { onGetCaptcha } = this.props; + const result = onGetCaptcha ? onGetCaptcha() : null; + if (result === false) { + return; + } + if (result instanceof Promise) { + result.then(this.runGetCaptchaCountDown); + } else { + this.runGetCaptchaCountDown(); + } + }; + + getFormItemOptions = ({ onChange, defaultValue, customProps = {}, rules }: LoginItemProps) => { + const options: { + rules?: Array; + onChange?: LoginItemProps['onChange']; + initialValue?: LoginItemProps['defaultValue']; + } = { + rules: rules || customProps.rules, + }; + if (onChange) { + options.onChange = onChange; + } + if (defaultValue) { + options.initialValue = defaultValue; + } + return options; + }; + + runGetCaptchaCountDown = () => { + const { countDown } = this.props; + let count = countDown || 59; + this.setState({ count }); + this.interval = window.setInterval(() => { + count -= 1; + this.setState({ count }); + if (count === 0) { + clearInterval(this.interval); + } + }, 1000); + }; + + render() { + const { count } = this.state; + + // 这么写是为了防止restProps中 带入 onChange, defaultValue, rules props + const { + onChange, + customProps, + defaultValue, + rules, + name, + getCaptchaButtonText, + getCaptchaSecondText, + updateActive, + type, + form, + ...restProps + } = this.props; + if (!name) { + console.warn('name is required!'); + return null; + } + console.log(form); + if (!form) { + return null; + } + const { getFieldDecorator } = form; + // get getFieldDecorator props + const options = this.getFormItemOptions(this.props); + + const otherProps = restProps || {}; + if (type === 'Captcha') { + const inputProps = omit(otherProps, ['onGetCaptcha', 'countDown']); + return ( + + + + {getFieldDecorator(name, options)()} + + + + + + + ); + } + return ( + + {getFieldDecorator(name, options)()} + + ); + } +} + +const LoginItem: Partial = {}; + +Object.keys(ItemMap).forEach(key => { + const item = ItemMap[key]; + LoginItem[key] = (props: LoginItemProps) => ( + + {context => { + console.log(context); + return ( + + ); + }} + + ); +}); + +export default LoginItem as LoginItemType; diff --git a/UserLogin/src/components/Login/LoginSubmit.tsx b/UserLogin/src/components/Login/LoginSubmit.tsx new file mode 100644 index 0000000000000000000000000000000000000000..2a6c246cc07517a5034536fc863e6a032506c87c --- /dev/null +++ b/UserLogin/src/components/Login/LoginSubmit.tsx @@ -0,0 +1,21 @@ +import React from 'react'; +import classNames from 'classnames'; +import { Button, Form } from 'antd'; +import styles from './index.less'; +import { ButtonProps } from 'antd/lib/button'; +const FormItem = Form.Item; + +interface LoginSubmitProps extends ButtonProps { + className: string; +} + +const LoginSubmit: React.SFC = ({ className, ...rest }) => { + const clsString = classNames(styles.submit, className); + return ( + +