FormRender.js 11.4 KB
import React,{PropTypes} from 'react';
import { connect } from 'react-redux'; 
import ReactDOM from 'react-dom';
import {reduxForm,destroy} from 'redux-form';
import { Button } from 'react-bootstrap';
import Section from './form/Section';
import TabularSection from './form/TabularSection'; 
import cx from 'classnames';
import s from './FormRender.scss';
import {getFieldKeys,getValidate,handleInitialValues,formatTabularValues,loadFormFields,getApproversByValues} from './form/FormUtils';
import {loadEmployees,loadOrganizations} from '../../redux/actions/hrSetting'; 
import {DropdownField} from './customForm'; 
import {Alert} from './custom';
import {getErrors} from './form/FormUtils';

  
const approverFields=['extra.first_approver'];
const approverValidate=(values)=>{
    const errors={};
    errors.extra={};
    if(!values.extra.first_approver){
        errors.extra.first_approver='此项是必填项';
    }
    return errors;
}

class ApproverForm extends React.Component {
    constructor(props) {
        super(props);    
        this.changeApprover=this.changeApprover.bind(this);
    }
    static propTypes = {    
        employees:PropTypes.array,
        previousForm:PropTypes.func
    } 
    changeApprover(value,values){

    }
    componentWillUnmount(){
       
    }
    render(){  
        const {fields:{extra:{first_approver}},submitting,handleSubmit,submit,employees,previousForm}=this.props;
        return (
            <div className={cx(s.approve_form)}>
                <form className={cx(s.form_body)} onSubmit={handleSubmit}>
                    <DropdownField displayName='选择审批人' labelKey='name' valueKey='uuid' field={first_approver} options={employees} onChange={first_approver.onChange}></DropdownField>
                </form>
                <div className={cx(this.props.className,'tr')}>
                    <Button className={cx('')} onClick={previousForm} bsStyle="info">上一页</Button>
                    <Button className={cx('')} disabled={submitting} onClick={handleSubmit(submit)} bsStyle="success"> 提交表单</Button>
                </div>
            </div>
        )
    }
}

class FormRender extends React.Component {
	constructor(props) {
        super(props);   
        this.formWillSubmit=this.formWillSubmit.bind(this); 
        this.changeType=this.changeType.bind(this);
        this.state={
            type:this.props.type
        }
    }
    static propTypes = {   
        formDefine:PropTypes.array,
        baseUrl:PropTypes.string,
        formStyle:PropTypes.object,
        sectionStyle:PropTypes.object,
        renderField:PropTypes.object,
        fields: PropTypes.object.isRequired,
        handleSubmit: PropTypes.func.isRequired,
        resetForm: PropTypes.func.isRequired,
        submitting: PropTypes.bool.isRequired,
        submit:PropTypes.func,
        column:PropTypes.number,
        className:PropTypes.string,
        customSection:PropTypes.func,
        customSectionKeys:PropTypes.array,
        defaultValues:PropTypes.object,
        type:PropTypes.string,
        service:PropTypes.string,
        needApprover:PropTypes.bool,
        nextForm:PropTypes.func 
    } 
    componentWillReceiveProps(nextProps) {
      this.setState({
        type:nextProps.type
      });
    }
    formWillSubmit(values){
        const {formDefine,submit,needApprover,nextForm,submitting}=this.props;
        if(submitting||this.submitFlag){
            this.submitFlag=false;
            return false;
        }
        const tempValues=formatTabularValues(values,formDefine); 
        this.submitFlag=true; 
        if(needApprover){
           return nextForm(tempValues);
        }else{
           return submit(tempValues); 
        } 
        
    } 
    changeType(){
        this.setState({
            type:'edit'
        })
    }
    render(){  
    	const {formDefine,fields,error,successMsg,baseUrl,submit,column,customSectionKeys,customSection,needApprover,employees,organizations}=this.props,self=this;
        const { resetForm, handleSubmit, submitting} = this.props;  
        const {type}=this.state;
        const hideSection=formDefine?formDefine.length==1:true;
        return( 
            <div className={cx(s.form_wrap)}>
                <form className={cx(s.form_body)}  onSubmit={handleSubmit(this.formWillSubmit)}>
                	{formDefine&&formDefine.map((section,index)=>{
                        if(customSectionKeys&&customSectionKeys.join("").indexOf(section.name)!=-1){
                            return (customSection(section,fields,index));
                        }else if(section.type=='tabular'){
                            return (<TabularSection employees={employees} organizations={organizations} key={index} className={this.props.className} column={column} hideSection={hideSection} formSection={section} baseUrl={baseUrl} fields={fields} formFields={section.fields} {...self.props} type={type}></TabularSection>);
                        }else{  
                		    return (<Section employees={employees} organizations={organizations} key={index} className={this.props.className} column={column} hideSection={hideSection} formSection={section} baseUrl={baseUrl} fields={fields} formFields={section.fields} {...self.props} type={type}/>);
                        }
                	})} 
                </form> 
                {successMsg&&<Alert autoHide={true} messageBlock='success'>{successMsg}</Alert>}
                {error&&<Alert messageBlock='danger'>{error}</Alert>}
                {needApprover&&
                    <div className={cx(this.props.className,'tr')}>
                        <a className={cx(s.submit_btn,submitting?s.disabled:'')}  disabled={submitting} onClick={handleSubmit(this.formWillSubmit)}  > 提交</a>
                    </div> 
                }
                {!needApprover&&
                    <div className={cx(this.props.className,'tr')}>
                        {('readOnly'==type)&&<Button className={cx('')} onClick={this.changeType} bsStyle="info">编辑表单</Button>}
                        {('readOnly'!=type)&&
                            <a className={cx(s.submit_btn,submitting?s.disabled:'')} disabled={submitting} onClick={handleSubmit(this.formWillSubmit)}  > 提交表单</a>
                        }
                    </div> 
                }
            </div> 
        )
    }
}

const approverFormFactory=(option=>{
    const {name,formDefine,defaultValues,destroyOnUnmount}=option;
    const fields=getFieldKeys(formDefine); 
    return reduxForm({
        form:'dynamic_form',
        validate:approverValidate,
        fields:fields.concat(approverFields),
        destroyOnUnmount 
    })(ApproverForm) 
})

export const formFactory=(option=>{
    const {formDefine,name,defaultValues,destroyOnUnmount}=option;
    const fields=getFieldKeys(formDefine);
    const validate =getValidate(formDefine);  
    return reduxForm({
        form:'dynamic_form',
        fields:fields,
        destroyOnUnmount,
        validate,
        initialValues:defaultValues?handleInitialValues(defaultValues):{}
    })(FormRender)
});

class FormWrap extends React.Component {
    constructor(props) {
        super(props);   
        this.getForm=this.getForm.bind(this);
        this.nextForm=this.nextForm.bind(this);
        this.preForm=this.preForm.bind(this);
        this.state={
            customForm:'',
            approveForm:'',
            formIndex:1
        } 
    }
    static propTypes = {   
        formName:PropTypes.string,
        baseUrl:PropTypes.string,
        fieldsConfig:PropTypes.object,
        column:PropTypes.number,
        className:PropTypes.string,
        submit:PropTypes.func,
        customSection:PropTypes.func,
        customSectionKeys:PropTypes.array, 
        defaultValues:PropTypes.object,
        type:PropTypes.string,
        needApprover:PropTypes.bool,
        service:PropTypes.string
    }
    static defaultProps = {  
        type:'create',//create|edit|readOnly
        needApprover:false
    }
    preForm(){
        this.setState({
            formIndex:1
        });
    }
    nextForm(values){
        const {service,submit,formName}=this.props,self=this; 
        return new Promise((resolve, reject) => {
            getApproversByValues(service,values,formName)
            .then(items=>{  
                if(!getErrors(items,reject)){ 
                    if(items&&items.approvers&&items.approvers.length>0&&items.approvers[0].type=='manual_specify'){
                        self.setState({
                            formIndex:2
                        });
                        resolve(values);
                    }else{
                        resolve(submit(values));
                    } 
                }  
            }).catch(err=>{
                reject({_error:err});
            }) 
        });   
    } 
    getForm(data){
        const {formName,fieldsConfig,submit,baseUrl,column,className,customSection,customSectionKeys,defaultValues,needApprover,employees,successMsg}=this.props,self=this;
        const CustomForm=formFactory({
            name:formName+'_form',
            formDefine:data.items,
            destroyOnUnmount:!needApprover, 
            defaultValues:defaultValues 
        });
        const ApproveForm=approverFormFactory({
            name:formName+'_form', 
            destroyOnUnmount:!needApprover, 
            formDefine:data.items, 
            defaultValues:defaultValues 
        })
        self.setState({
            customForm:<CustomForm {...this.props} successMsg={successMsg} needApprover={needApprover} nextForm={this.nextForm} customSection={customSection} customSectionKeys={customSectionKeys} formDefine={data.items} className={className} column={column} baseUrl={baseUrl}  submit={submit}  fieldsConfig={fieldsConfig} /> ,
            approveForm:<ApproveForm previousForm={this.preForm}  submit={submit}  employees={employees}/>
        })
    }
    componentDidMount(){ 
        const {formName,baseUrl,dispatch,needLoadEmp,needLoadOrg}=this.props,self=this;
        loadFormFields(formName,baseUrl)
        .then(function(data){  
            self.getForm.call(self,data); 
        }).catch(function(error){
            
        });  
        if(needLoadEmp){
            dispatch(loadEmployees());
        }
        if(needLoadOrg){
            dispatch(loadOrganizations());
        }
    } 
    componentWillReceiveProps(nextProps){
        const {formName,baseUrl,dispatch,needApprover}=nextProps,self=this;
        const preFormName=this.props.formName;
        if(formName!=preFormName){
            const destroyFormName=preFormName+'_form'; 
            dispatch(destroy('dynamic_form'));
        }
        loadFormFields(formName,baseUrl)
        .then(function(data){  
            self.getForm.call(self,data); 
        }).catch(function(error){

        });  
    } 
    componentWillUnmount(){
        const {formName,dispatch,needApprover}=this.props; 
        dispatch(destroy('dynamic_form'));
    }
    render(){  
        const {formIndex}=this.state; 
        return (
            <div className={cx('custom_form_wrap')}>
                {formIndex==1&&this.state.customForm}
                {formIndex==2&&this.state.approveForm} 
            </div>
        )
    }
}

const mapStateToProps = (state) => {  
  const {hrSetting:{needLoadEmp,employees,needLoadOrg,organizations,positions}}= state;
  return {
    needLoadEmp,
    employees,
    needLoadOrg,
    organizations,
    positions
  };
}


export default connect(mapStateToProps)(FormWrap);