import React from 'react';
import { Row, Col, Button, Select, Input, Field, createEasyForm, TagSelect, RadioGroup, Radio, CheckboxGroup, Checkbox, Upload, DatePicker, AutoComplete } from 'neatui';
import { withRouter } from 'react-router-dom';
import xhr from 'SERVICE/xhr';
import Axios from 'axios';
import QS from 'querystring';
import BaseComponent from 'COMPONENT/common/BaseComponent';
import { error, success } from 'UTIL/notification';
import Loading from 'COMPONENT/container/Loading/Loading';
import projectConfig from 'CONFIG/projectConfig.json';
import { getSearchParams, isArray, getBLen, setDefaultValue, switchDataWithShowInfo, parseData2Url, parseFixedParameter } from 'UTIL/util';
import TreeSelect from 'COMPONENT/common/TreeSelect/TreeSelect';
import moment from 'moment';
import 'moment/locale/zh-cn';
import './index.scss';

const localHost = projectConfig.localhost || [];
localHost.push('localhost');

class Fastform extends BaseComponent {
    constructor(props) {
        super(props);
        this.env = localHost.indexOf(window.location.hostname) > -1 ? 'local.' : '';
        const { getInstance } = props;
        if (typeof getInstance === 'function') {
            getInstance(this);
        }
        /*
            config, key, submit, goback
        */
        this.config = this.props.config || {};
        this.searchParams = getSearchParams();
        const fastmode = this.searchParams.fastmode || this.config.fastmode || 'create';
        const defaultValueMap = {};
        const disabledMap = {};
        const placeholderMap = {};
        const helperTextMap = {};
        const formDataType = {};
        const formMap = {};
        const groupsVal = {};
        const groups = {};
        const { allFormList, parseSrcFormList } = this.parseFormList(fastmode);
        for ( let i = 0; i < allFormList.length; i+=1 ) {
            const item = allFormList[i];
            formMap[item.key] = item;
            if (item.type === 'group') {
                groups[item.key] = [];
                groupsVal[item.key] = [];
                for (let gi = 0; gi < item.groups.length; gi += 1) {
                    groups[item.key].push(item.groups[gi].key)
                }
            }
            if (['uploadimage', 'multuploadimage', 'uploadfiles', 'uploadNosFile', 'tags', 'check'].indexOf(item.type) > -1) {
                if (!item.defaultValue) Object.assign(item, {
                    defaultValue: []
                });
            }
            defaultValueMap[item.key] = setDefaultValue(item.defaultValue);
            placeholderMap[item.key] = item.placeholder || '';
            helperTextMap[item.key] = item.helperText || '';
            disabledMap[item.key] = item.notModify || false;
            formDataType[item.key] = {
                type: item.type,
                ajaxType: item.ajaxType,
                format: item.format
            }
        }
        const schema = {};
        for (let i = 0; i < allFormList.length; i+=1) {
            const formItem = allFormList[i];
            if (formItem.rule) {
                schema[formItem.key] = this.getSchema(formItem);
            }
        }

        this.notInit = (this.config[fastmode] && this.config[fastmode].notInit) || false;
        this.state = {
            allFormList,
            parseSrcFormList,
            defaultDataMap: {},
            formMap,
            defaultValueMap,
            disabledMap,
            placeholderMap,
            helperTextMap,
            suggest: {},
            formDataType,
            more: {},
            fastmode,
            groupsVal,
            groupIndex: 0,
            groups,
            schema,
            deleteKeys: []
        };
    }

    componentDidMount() {
        const mine = this;
        let canSearch = true;
        const { searchForm, mustArr = [] } = mine.props;
        mustArr.forEach(mustItem => {
            if (searchForm[mustItem.key] === '' || searchForm[mustItem.key] === undefined) {
                canSearch = false;
            }
        });
        const { allFormList, fastmode, defaultValueMap, formMap, schema } = mine.state;
        mine.initForm();
        const dataKeys = mine.config[fastmode] && mine.config[fastmode].data && mine.config[fastmode].data.key;
        if (dataKeys && !mine.notInit && canSearch) {
            const configParams = {};
            if (isArray(dataKeys)) {
                for (let i = 0; i < dataKeys.length; i += 1) {
                    configParams[dataKeys[i]] = setDefaultValue(mine.searchParams[dataKeys[i]]);
                }
            } else {
                configParams[dataKeys] = setDefaultValue(mine.searchParams[dataKeys]);
            }
            mine.setState({
                loading: true
            });
            mine.fetchDataHandler(configParams, (rs) => {
                const { data } = rs;
                for (let i = 0; i < allFormList.length; i+=1) {
                    const item = allFormList[i];
                    if (!item[`${mine.env}url`] && !item[`${mine.env}nextUrl`]) continue;
                    if (item.type === 'suggest') {
                        mine.inputSuggest(data[item.key] || defaultValueMap[item.key], item);
                    }
                    mine.getSearchFormListHandler(item, data);
                    if (item.nextKey) mine.getSonData(item, data[item.key] || defaultValueMap[item.key]);
                    if (item.nextKeys) {
                        item.nextKeys.map(nextItem => mine.getSearchFormListHandler(formMap[nextItem], data))
                    }
                }
            });
        } else {
            for (let i = 0; i < allFormList.length; i+=1) {
                const item = allFormList[i];
                if (!item[`${mine.env}url`] && !item[`${mine.env}nextUrl`]) continue;
                mine.getSearchFormListHandler(item);
                if (item.nextKey) mine.getSonData(item, defaultValueMap[item.key]);
                if (item.nextKeys) {
                    item.nextKeys.map(nextItem => mine.getSearchFormListHandler(formMap[nextItem]))
                }
            }
        }
        mine.props.updateSchema(schema);
    }

    getSchema = (formItem) => {
        const len = formItem.rule ? formItem.rule.len || 0 : 0;
        return {
            validator(val) {
                if (formItem.inputType === 'number') {
                    if (isArray(formItem.rule.between) && formItem.rule.between.length === 2) {
                        return val >= formItem.rule.between[0] && val <= formItem.rule.between[1];
                    }
                }
                const valTmp = `${val === undefined || val === null ? '' : val}`;
                const valTmpLen = formItem.rule.type === 'cn' ? getBLen(valTmp) : valTmp.length;
                if (formItem.rule.isMust && len > 0) return valTmp && valTmpLen <= len;
                if (formItem.rule.isMust) return valTmp;
                if (len > 0) return valTmpLen <= len;
                return true;
            },
            message: (val) => {
                if (formItem.inputType === 'number') {
                    if (isArray(formItem.rule.between) && formItem.rule.between.length === 2) {
                        return `${formItem.rule.log}！当前数字${val}` || `${formItem.label}是介于${formItem.rule.between[0]}和${formItem.rule.between[1]}之间的数字！当前数字${val}`;
                    }
                    return '配置项错误，查看文档';
                }
                if (formItem.rule.isMust && len > 0) return `${formItem.rule.log}${formItem.rule.needLen ? '当前长度' : ''}${formItem.rule.needLen ? getBLen(val) : ''}` || `${formItem.label}不能为空且长度不超过${len}个字符！${formItem.rule.needLen ? '当前长度' : ''}${formItem.rule.needLen ? getBLen(val) : ''}`;
                if (formItem.rule.isMust) return `${formItem.rule.log}${formItem.rule.needLen ? '当前长度' : ''}${formItem.rule.needLen ? getBLen(val) : ''}` || `${formItem.label}不能为空！${formItem.rule.needLen ? '当前长度' : ''}${formItem.rule.needLen ? getBLen(val) : ''}`;
                return `${formItem.rule.log}！${formItem.rule.needLen ? '当前长度' : ''}${formItem.rule.needLen ? getBLen(val) : ''}` || `${formItem.label}长度不超过${len}个字符！${formItem.rule.needLen ? '当前长度' : ''}${formItem.rule.needLen ? getBLen(val) : ''}`;
            }
        }
    }

    initForm = () => {
        const { updateFieldValue } = this.props;
        const { allFormList, defaultValueMap } = this.state;
        for (let i = 0; i < allFormList.length; i+=1) {
            const item = allFormList[i] || {};
            if (item.key) {
                if (item.type === 'datepicker') {
                    updateFieldValue(item.key, (defaultValueMap[item.key] ? moment().subtract(item.defaultValue, 'days') : ''));
                } else {
                    updateFieldValue(item.key, defaultValueMap[item.key]);
                }
            }
        }
    }

    parentToChildren = (params, formData, fastmode) => {
        const mine = this;
        const { allFormList, defaultValueMap, formMap } = mine.state;
        mine.setState({
            fastmode: fastmode || mine.state.fastmode
        }, () => {
            const newFormData = Object.assign(mine.searchParams || {}, formData || {});
            const configParams = {...(params || {})};
            const dataKeys = mine.config[fastmode] && mine.config[fastmode].data && mine.config[fastmode].data.key;
            if (dataKeys) {
                if (isArray(dataKeys)) {
                    for (let i = 0; i < dataKeys.length; i += 1) {
                        configParams[dataKeys[i]] = setDefaultValue(newFormData[dataKeys[i]]);
                    }
                } else {
                    configParams[dataKeys] = setDefaultValue(newFormData[dataKeys]);
                }
            }
            mine.fetchDataHandler(configParams, (rs) => {
                const { data } = rs;
                for (let i = 0; i < allFormList.length; i+=1) {
                    const item = allFormList[i];
                    if (!item[`${mine.env}url`] && !item[`${mine.env}nextUrl`]) continue;
                    if (item.type === 'suggest') {
                        mine.inputSuggest(data[item.key] || defaultValueMap[item.key], item);
                    }
                    mine.getSearchFormListHandler(item, data);
                    if (item.nextKey) mine.getSonData(item, data[item.key] || defaultValueMap[item.key]);
                    if (item.nextKeys) {
                        item.nextKeys.map(nextItem => mine.getSearchFormListHandler(formMap[nextItem], data))
                    }
                }
            });
        });
    }

    parseFormList = (fastmode) => {
        let allFormList = [];
        let parseSrcFormList = [];
        if (this.config.vertical === true) {
            for (let i = 0; i < (this.config.forms || []).length; i += 1) {
                const itemForm = this.config.forms[i];
                if (isArray(itemForm)) {
                    allFormList = [...allFormList, ...itemForm];
                    parseSrcFormList.push(itemForm);
                } else {
                    console.error('vertical模式下，config.forms内元素只接收数组!');
                }
            }
            for (let j = 0; this.config[fastmode] && j < (this.config[fastmode].forms || []).length; j += 1) {
                const itemForm = this.config[fastmode].forms[j];
                if (isArray(itemForm)) {
                    allFormList = [...allFormList, ...itemForm];
                    if (this.config[fastmode].insertPos === 'before') parseSrcFormList.unshift(itemForm);
                    else parseSrcFormList.push(itemForm);
                } else {
                    console.error(`vertical模式下，config.${fastmode}.forms内元素只接收数组!`);
                }
            }
        } else if (this.config[fastmode].insertPos === 'before') {
            allFormList = [...((this.config[fastmode] && this.config[fastmode].forms) || []), ...(this.config.forms || [])];
            parseSrcFormList = [...((this.config[fastmode] && this.config[fastmode].forms) || []), ...(this.config.forms || [])];
        } else {
            allFormList = [...(this.config.forms || []), ...((this.config[fastmode] && this.config[fastmode].forms) || [])];
            parseSrcFormList = [...(this.config.forms || []), ...((this.config[fastmode] && this.config[fastmode].forms) || [])];
        }
        return {
            allFormList,
            parseSrcFormList
        };
    }

    getSearchFormListHandler = (itemParam, formData) => {
        if (itemParam.notInit) return;
        const postData = {};
        if(itemParam.controled && formData) {
            for (let j = 0; j < item.controled.length; j+=1) {
                postData[itemParam.controled[j].ajaxKey] = setDefaultValue(formData[itemParam.controled[j].valueKey]);
            }
        }
        const mine = this;
        // TODO  关于more的需要重新梳理一下
        const item = JSON.parse(JSON.stringify(itemParam));
        const locationSearch = {};
        if (item.isNeedLocationSearch && isArray(item.isNeedLocationSearch)) {
            for (let i = 0; i < item.isNeedLocationSearch.length; i+=1) {
                const key = item.isNeedLocationSearch[i];
                locationSearch[key] = mine.searchParams[key];
            }
        }
        const { data, url } = parseData2Url({
            ...parseFixedParameter(mine.config.fixedParameter),
            ...parseFixedParameter(item.fixedParameter),
            ...locationSearch,
            ...(postData || {})
        }, item[`${this.env}url`] || '', item.accept);
        if (url) {
            xhr({
                url,
                method: item.method || 'get',
                data,
                type: 'json',
                contentType: item.contentType,
                notSwitchArrToStr: item.notSwitchArrToStr
            }).then((rs) => {
                if (rs[projectConfig.codeKey] === projectConfig.code) {
                    const { defaultDataMap, suggest, more } = mine.state;
                    let responData = [];
                    const { key } = item;
                    if (item.type === 'suggest') {
                        suggest[key] = rs.data || [];
                    } else if (item.responseKey) {
                        if (item.listStr === true) {
                            defaultDataMap[key] = rs.data[item.responseKey] && isArray(rs.data[item.responseKey]) ? rs.data[item.responseKey].map(dItem => { return { "id": dItem, "name": dItem } }) : [];
                        } else {
                            responData = rs.data[item.responseKey] && isArray(rs.data[item.responseKey]) ? rs.data[item.responseKey] : [];
                        }
                    } else if (item.listStr === true) {
                        defaultDataMap[key] = rs.data && isArray(rs.data) ? rs.data.map(dItem => { return { "id": dItem, "name": dItem } }) : [];
                    } else {
                        responData = rs.data && isArray(rs.data) ? rs.data : [];
                    }
                    if (item.moreKey && !item.listStr) {
                        const dData = [];
                        const mData = [];
                        for (let att = 0; att < responData.length; att += 1) {
                            if (responData[att][item.moreKey] === true) {
                                mData.push(responData[att]);
                            } else {
                                dData.push(responData[att]);
                            }
                        }
                        defaultDataMap[key] = dData;
                        more[key] = mData;
                    } else {
                        defaultDataMap[key] = responData || [];
                    }
                    mine.setState({
                        defaultDataMap : {...(defaultDataMap || {})},
                        suggest,
                        more
                    });
                } else {
                    error(rs[projectConfig.msg]);
                }
            });
        }
    };

    getSonData = (item, value) => {
        if (item.notInit) return;
        const mine = this;
        const postData = {};
        postData[item.nextAjaxKey] = value;
        
        const locationSearch = {};
        if (item.isNeedLocationSearch && isArray(item.isNeedLocationSearch)) {
            for (let i = 0; i < item.isNeedLocationSearch.length; i+=1) {
                const key = item.isNeedLocationSearch[i];
                locationSearch[key] = mine.searchParams[key];
            }
        }
        const { data, url } = parseData2Url({
            ...parseFixedParameter(mine.config.fixedParameter),
            ...parseFixedParameter(item.fixedParameter),
            ...locationSearch,
            ...(postData || {})
        }, item[`${this.env}nextUrl`] || '', item.accept);
        if (url) {
            xhr({
                url,
                method: item.nextMethod || 'get',
                data,
                type: 'json',
                contentType: item.nextContentType,
                notSwitchArrToStr: item.nextNotSwitchArrToStr
            }).then((rs) => {
                if (rs[projectConfig.codeKey] === projectConfig.code) {
                    const { defaultDataMap, suggest, more } = mine.state;
                    let responData = [];
                    const key = item.nextKey;
                    if (item.type === 'suggest') {
                        suggest[key] = rs.data || [];
                    } else if (item.responseKey) {
                        if (item.listStr === true) {
                            defaultDataMap[key] = rs.data[item.responseKey] && isArray(rs.data[item.responseKey]) ? rs.data[item.responseKey].map(dItem => { return { "id": dItem, "name": dItem } }) : [];
                        } else {
                            responData = rs.data[item.responseKey] && isArray(rs.data[item.responseKey]) ? rs.data[item.responseKey] : [];
                        }
                    } else if (item.listStr === true) {
                        defaultDataMap[key] = rs.data && isArray(rs.data) ? rs.data.map(dItem => { return { "id": dItem, "name": dItem } }) : [];
                    } else {
                        responData = rs.data && isArray(rs.data) ? rs.data : [];
                    }
                    if (item.moreKey && !item.listStr) {
                        const dData = [];
                        const mData = [];
                        for (let att = 0; att < responData.length; att += 1) {
                            if (responData[att][item.moreKey] === true) {
                                mData.push(responData[att]);
                            } else {
                                dData.push(responData[att]);
                            }
                        }
                        defaultDataMap[key] = dData;
                        more[key] = mData;
                    } else {
                        defaultDataMap[key] = responData || [];
                    }
                    mine.setState({
                        defaultDataMap,
                        suggest,
                        more
                    });
                } else {
                    error(rs[projectConfig.msg]);
                }
            });
        }
    }

    inputSuggest = (value, item) => {
        const mine = this;
        const { suggest } = mine.state;
        const postData = {};
        if (item.ajaxKey) postData[item.ajaxKey] = value;

        const locationSearch = {};
        if (item.isNeedLocationSearch && isArray(item.isNeedLocationSearch)) {
            for (let i = 0; i < item.isNeedLocationSearch.length; i+=1) {
                const key = item.isNeedLocationSearch[i];
                locationSearch[key] = mine.searchParams[key];
            }
        }
        const { data, url } = parseData2Url({
            ...parseFixedParameter(mine.config.fixedParameter),
            ...parseFixedParameter(item.fixedParameter),
            ...locationSearch,
            ...(postData || {})
        }, item[`${this.env}url`] || '', item.accept);

        if (url && !item.cache) {
            xhr({
                url,
                method: item.method || 'get',
                data,
                type: 'json',
                contentType: item.contentType,
                notSwitchArrToStr: item.notSwitchArrToStr
            }).then((rs) => {
                if (rs[projectConfig.codeKey] === projectConfig.code) {
                    suggest[item.key] = rs.data || [];
                    mine.setState({
                        suggest
                    });
                } else {
                    error(rs[projectConfig.msg]);
                }
            });
        }
    }

    parseResponseData = (data) => {
        let index = 0;
        const { allFormList } = this.state;
        allFormList.forEach(item => {
            if (item.key && item.type === 'group' && isArray(data[item.key])) {
                (data[item.key] || []).forEach(g => {
                    Object.keys(g).forEach(xx => {
                        const key = `bjgroup-${index}-${item.key}-${xx}`;
                        const tmpJSON = {};
                        tmpJSON[key] = g[xx];
                        Object.assign(data, tmpJSON)
                    });
                    index += 1;
                });
            }
        });
        return data;
    }

    fetchDataHandler = (configParams, callback) => {
        const mine = this;
        const { fastmode, allFormList, groupsVal } = this.state;
        let groupIndex = 0;
        const dataConfig = mine.config[fastmode].data;
        if (!dataConfig) return;
        const method = dataConfig.method || 'get';
        const locationSearch = {};
        if (dataConfig.isNeedLocationSearch && isArray(dataConfig.isNeedLocationSearch)) {
            for (let i = 0; i < dataConfig.isNeedLocationSearch.length; i+=1) {
                const key = dataConfig.isNeedLocationSearch[i];
                locationSearch[key] = mine.searchParams[key];
            }
        }
        const { searchForm } = mine.props;
        const { data, url } = parseData2Url({
                ...parseFixedParameter(mine.config.fixedParameter),
                ...parseFixedParameter(dataConfig.fixedParameter),
                ...locationSearch,
                ...searchForm,
                ...configParams
            }, dataConfig[`${mine.env}url`] || '', dataConfig.accept);
        if (url) {
            xhr({
                url,
                method,
                type: 'json',
                data,
                contentType: dataConfig.contentType,
                notSwitchArrToStr: dataConfig.notSwitchArrToStr
            }).then((rs) => {
                if (callback) callback(rs);
                if (rs[projectConfig.codeKey] === projectConfig.code) {
                    const responseData = this.parseResponseData(rs.data);
                    const { defaultValueMap, formMap, formDataType, schema, placeholderMap, helperTextMap, disabledMap } = mine.state;
                    const willUpdateSchema = {};
                    for (let i = 0; i < allFormList.length; i += 1) {
                        const key = allFormList[i].key || '';
                        const type = allFormList[i].type || '';
                        if (key && type !== 'group') {
                            mine.props.updateFieldValue(key, setDefaultValue(responseData[key]));
                            defaultValueMap[key] = setDefaultValue(responseData[key]);
                        }
                        if (key && type === 'group') {
                            for (let ri = 0; isArray(responseData[key]) && ri < responseData[key].length; ri += 1) {
                                for (let gi = 0; gi < allFormList[i].groups.length; gi += 1) {
                                    const newKey = `bjgroup-${groupIndex}-${key}-${allFormList[i].groups[gi].key}`;
                                    const sitem = allFormList[i].groups[gi];
                                    mine.props.updateFieldValue(newKey, setDefaultValue(responseData[newKey]));
                                    defaultValueMap[newKey] = setDefaultValue(responseData[newKey]);
                                    const newItem = Object.assign({}, sitem, {
                                        key: newKey
                                    });
                                    willUpdateSchema[newKey] = this.getSchema(newItem, { index: groupIndex + 1 });
                                    if (newItem[`${mine.env}url`] || newItem[`${mine.env}nextUrl`]) {
                                        mine.getSearchFormListHandler(newItem);
                                        if (newItem.nextKey) mine.getSonData(newItem, defaultValueMap[newItem.key]);
                                        if (newItem.nextKeys) {
                                            newItem.nextKeys.map(nextItem => mine.getSearchFormListHandler(formMap[nextItem]))
                                        }
                                    }
                                    formMap[newItem.key] = newItem;
                                    defaultValueMap[newItem.key] = setDefaultValue(newItem.defaultValue);
                                    placeholderMap[newItem.key] = newItem.placeholder || '';
                                    helperTextMap[newItem.key] = newItem.helperText || '';
                                    disabledMap[newItem.key] = newItem.notModify || false;
                                    formDataType[newItem.key] = {
                                        type: newItem.type,
                                        ajaxType: newItem.ajaxType,
                                        format: newItem.format
                                    }
                                }
                                groupsVal[key].push({index: groupIndex});
                                groupIndex += 1;
                            }
                        }
                    }
                    mine.props.validateAll();
                    mine.setState({
                        loading: false,
                        groupIndex,
                        groupsVal,
                        defaultValueMap: { ...defaultValueMap },
                        schema: {
                            ...schema,
                            ...willUpdateSchema
                        },
                        formMap, placeholderMap, helperTextMap, disabledMap, formDataType
                    }, () => {
                        mine.props.updateSchema(this.state.schema);
                    });
                } else {
                    error(rs[projectConfig.msg]);
                }
            });
        }
    };

    parseData = (data) => {
        const { formDataType, groupIndex, groups, deleteKeys, formMap } = this.state;
        const postData = {...(data || {})};
        /*
            可单独对数据做处理，对比 createSonFiled的过滤内容
         */
        (Object.keys(groups) || []).forEach(item => {
            let i = 0;
            postData[item] = [];
            while(i <= groupIndex) {
                const tmpJSON = {};
                const indexI = i;
                let flag = false;
                (groups[item] || []).forEach(subItem => {
                    const key = `bjgroup-${indexI}-${item}-${subItem}`;
                    if (data[key] !== undefined && deleteKeys.indexOf(key) === -1) {
                        tmpJSON[subItem] = data[key];
                        flag = true;
                    }
                    delete postData[key];
                });
                if (flag) postData[item].push(tmpJSON);
                i += 1;
            }
        });

        const dataKeys = Object.keys(data) || [];
        for (let d = 0; d < dataKeys.length; d+=1) {
            if (formMap[dataKeys[d]].conKey &&
                (isArray(postData[formMap[dataKeys[d]].conKey]) && !formMap[dataKeys[d]].conValue.includes(postData[formMap[dataKeys[d]].conKey])
                || (!isArray(postData[formMap[dataKeys[d]].conKey]) && postData[formMap[dataKeys[d]].conKey] !== formMap[dataKeys[d]].conValue))
            )
            {
                delete postData[dataKeys[d]];
                continue;
            }
            if (formDataType[dataKeys[d]] && formDataType[dataKeys[d]].ajaxType === 'none') {
                delete postData[dataKeys[d]];
                continue;
            }
            if (formDataType[dataKeys[d]] && formDataType[dataKeys[d]].type === "uploadimage") {
                postData[dataKeys[d]] = data[dataKeys[d]].length > 0 ? data[dataKeys[d]][0].url : '';
            }
            if (formDataType[dataKeys[d]] && formDataType[dataKeys[d]].type === "multuploadimage") {
                postData[dataKeys[d]] = data[dataKeys[d]].map(item => item.url);
            }
            if (formDataType[dataKeys[d]] && formDataType[dataKeys[d]].type === "uploadfiles") {
                postData[dataKeys[d]] = data[dataKeys[d]].map(item => item.name);
            }
            if (formDataType[dataKeys[d]] && formDataType[dataKeys[d]].type === "uploadNosFile") {
                postData[dataKeys[d]] = data[dataKeys[d]].map(item => { return {
                    fileKey: item.fileKey,
                    fileName: item.fileName
                }})
            }
            if (formDataType[dataKeys[d]] && formDataType[dataKeys[d]].ajaxType === 'timestamp') {
                postData[dataKeys[d]] = moment(data[dataKeys[d]]).valueOf();
            } else if (formDataType[dataKeys[d]] && formDataType[dataKeys[d]].ajaxType === 'second') {
                postData[dataKeys[d]] = parseInt(moment(data[dataKeys[d]]).valueOf() / 1000, 10);
            } else if (formDataType[dataKeys[d]] && formDataType[dataKeys[d]].ajaxType === 'time') {
                postData[dataKeys[d]] = data[dataKeys[d]].format(formDataType[dataKeys[d]].format);
            } else if (formDataType[dataKeys[d]] && formDataType[dataKeys[d]].ajaxType === 'number') {
                postData[dataKeys[d]] = Number(data[dataKeys[d]]);
            } else if (formDataType[dataKeys[d]] && formDataType[dataKeys[d]].ajaxType === 'json2Str') {
                postData[dataKeys[d]] = JSON.stringify(data[dataKeys[d]])
            } else if (formDataType[dataKeys[d]] && formDataType[dataKeys[d]].ajaxType === 'str2Json') {
                postData[dataKeys[d]] = JSON.parse(data[dataKeys[d]])
            }
        }
        return postData;
    }

    submitHandler = (data, itemConfig) => {
        const mine = this;
        const { defaultValueMap } = mine.state;
        const submitConfig = itemConfig.submit;
        const method = submitConfig.method || 'post';
        const msg = submitConfig.msg || '操作成功';
        const result = itemConfig.result || {};
        const locationSearch = {};
        if (submitConfig.isNeedLocationSearch && isArray(submitConfig.isNeedLocationSearch)) {
            for (let i = 0; i < submitConfig.isNeedLocationSearch.length; i+=1) {
                const key = submitConfig.isNeedLocationSearch[i];
                locationSearch[key] = mine.searchParams[key];
            }
        }
        const { data: postData, url } = parseData2Url({
            ...parseFixedParameter(mine.config.fixedParameter),
            ...parseFixedParameter(submitConfig.fixedParameter),
            ...locationSearch,
            ...defaultValueMap,
            ...data
        }, submitConfig[`${mine.env}url`] || '');
        if (url) {
            xhr({
                url,
                method,
                data: this.parseData(postData),
                type: 'json',
                contentType: submitConfig.contentType,
                notSwitchArrToStr: submitConfig.notSwitchArrToStr
            }).then((rs) => {
                if (rs[projectConfig.codeKey] === projectConfig.code) {
                    success(msg);
                    if (mine.searchParams.url) mine.props.history.push(mine.searchParams.url);
                    mine.initForm();
                    if (result.type === 'route') {
                        let search = '?';
                        const values = [...(result.gotoValue || [])];
                        for (let i = 0; i < values.length; i+=1) {
                            const key = values[i];
                            if (mine.searchParams[key]) {
                                search += `&${key}=`;
                                search += (mine.searchParams[key]);
                            }
                        }
                        const router = result.address || '/404';
                        mine.props.history.push(router + search);
                    } else if (result.type === 'current') {
                        mine.setState({
                            defaultValueMap: {...(defaultValueMap || {}), ...(data || {})}
                        }, () => {
                            mine.initForm();
                        });
                        mine.props.searchChild(result.moduleids);
                    } else {
                        console.warn("submitHandler type is wrong!");
                    }
                } else {
                    error(rs[projectConfig.msg]);
                }
            });
        }
    };

    cancelHandler = () => {
        let search = '?';
        const values = this.config.goback && this.config.goback.gotoValue ? [...(this.config.goback.gotoValue || [])] : [];
        for (let i = 0; i < values.length; i+=1) {
            const key = values[i];
            if (this.searchParams[key]) {
                search += `&${key}=`;
                search += (this.searchParams[key]);
            }
        }
        const router = this.config.goback ? (this.config.goback.address || '/404') : '/404';
        this.props.history.push(router + search);
    };

    resetHandler = () => {
        this.initForm();
    }

    beforeUpload = file => {
        const data = new FormData();
        const uploadUrl = `http://upfile.m.163.com/nos/upload/pub`;
        if (!/(gif|png|jpe?g)$/.test(file.type)) {
            error(`${file.name || ''}文件类型错误！`);
            return false;
        }
        data.append('myfile', file);
        return Axios.post(uploadUrl, data).then(res => {
            if (res.data.status === 1) {
                return {url: res.data.url};
            }
            return false;
        });
    }

    beforeUploadFiles = (file, config) => {
        const { values } = this.props;
        if (config.len && values[config.key] && values[config.key].length > config.len) {
            error(`${config.label || config.key || ''}最多上传${config.len}个文件！`);
            return false;
        }
        const data = new FormData();
        const uploadUrl = `http://upfile.m.163.com/nos/upload/pub`;
        if (config.acceptType && config.acceptType.indexOf(file.type) === -1) {
            error(`${file.name || ''}文件类型错误！`);
            console.log(`上传文件格式为：${file.type}，如果支持，请添加到acceptType配置上。`);
            return false;
        }
        data.append('myfile', file);
        return Axios.post(uploadUrl, data).then(res => {
            if (res.data.status === 1) {
                return {name: res.data.url};
            }
            return false;
        });
    }

    cropSure = base64 => {
        const data = new FormData();
        const uploadUrl = `http://upload.buzz.163.com/picupload`;
        data.append('from', 'push');
        data.append('uploadtype', 'base64');
        data.append('body', base64);
        return Axios.post(uploadUrl, data).then(res => {
            if (res.data.code === 200) {
                return {url: res.data.data.url};
            }
            return false;
        });
    }

    beforeUploadNosFile = file => {
        const { name } = file;
        const uploadUrl = '/fileUpload/buildUpLoadPolicy';
        const fileName = `163/newcmslog/${name}`;
        const params = {nosObject: fileName};
        return Axios.request({
            url: uploadUrl,
            method: "POST",
            data: QS.stringify(params),
            headers: {
                "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8" 
            }
        }).then(res => {
            if (res.data && res.data.code === 200) {
                const token = res.data.data;
                const uploader = Uploader({ // eslint-disable-line no-undef
                    onError: (errObj) => {
                        error(errObj.errMsg || '上传出错！');
                    }
                }); 
                uploader.addFile(file);
                const param = {
                    bucketName: "static163",
                    objectName: fileName,
                    token
                }
                return new Promise((resolve) => {
                    uploader.upload(param, curFile => {
                        const { fileKey } = curFile;
                        if(fileKey) resolve({ fileKey, fileName, name });
                    });
                }) 
            }
            return false;
        });
    }

    handleAddTags = (e, key, sourceKeys) => {
        const { values, updateFieldValue } = this.props;
        const currentTags = [...(values[key] || [])];
        const obj = {};
        sourceKeys.forEach(sourceKey => {
            obj[sourceKey] = values[sourceKey] || "";
        });
        if (!values[sourceKeys[0]]) return;
        currentTags.push(obj)
        updateFieldValue(key, currentTags);
    }

    handleRemoveTags = (e, key, tag, sourceKeys) => {
        const { values, updateFieldValue } = this.props;
        const currentTags = [...(values[key] || [])];
        const obj = {};
        sourceKeys.forEach(sourceKey => {
            if (values[sourceKey]) obj[sourceKey] = values[sourceKey];
        });
        const nextTags = currentTags.filter(item => {
            return item[sourceKeys[0]] !== tag
        })
        updateFieldValue(key, nextTags);
    }

    // more less map  维护
    showMore = (item) => {
        const cloneState = JSON.parse(JSON.stringify(this.state));
        const { more } = cloneState;
        more[item.key] = [...(item.more || [])];
        this.setState({
            more
        });
    }

    showLess = (item) => {
        const { values } = this.props;
        const cloneState = JSON.parse(JSON.stringify(this.state));
        const { more, defaultDataMap } = cloneState;
        delete more[item.key];
        this.setState({
            more
        }, () => {
            const { updateFieldValue } = this.props;
            let flag = false;
            const parseData = [...(item.data || []), ...(defaultDataMap[item.key] || [])];
            for (let i = 0; i < parseData.length; i += 1) {
                if (parseData[i][item.dataKey || 'id'] === values[item.key] || (values[item.key] || '').indexOf(parseData[i][item.dataKey || 'id']) > -1) {
                    flag = true;
                    break;
                }
            }
            if (flag) updateFieldValue(item.key, values[item.key]);
            else updateFieldValue(item.key, (item.defaultValue !== '' ? item.defaultValue : ''));
        });
    }

    handleSearch = (value, item) => {
        const mine = this;
        const postData = {};
        if (item.ajaxKey) postData[item.ajaxKey] = value;
        const locationSearch = {};
        if (item.isNeedLocationSearch && isArray(item.isNeedLocationSearch)) {
            for (let i = 0; i < item.isNeedLocationSearch.length; i+=1) {
                const key = item.isNeedLocationSearch[i];
                locationSearch[key] = mine.searchParams[key];
            }
        }
        const { data, url } = parseData2Url({
            ...parseFixedParameter(mine.config.fixedParameter),
            ...parseFixedParameter(item.fixedParameter),
            ...locationSearch,
            ...(postData || {})
        }, item[`${this.env}url`] || '', item.accept);
        if (url) {
            xhr({
                url,
                method: item.method || 'get',
                data,
                type: 'json',
                contentType: item.contentType,
                notSwitchArrToStr: item.notSwitchArrToStr
            }).then((rs) => {
                if (rs[projectConfig.codeKey] === projectConfig.code) {
                    const { defaultDataMap } = mine.state;
                    const { key } = item;
                    if (item.responseKey) {
                        if (item.listStr === true) {
                            defaultDataMap[key] = rs.data[item.responseKey] && isArray(rs.data[item.responseKey]) ? rs.data[item.responseKey].map(dItem => { return { "id": dItem, "name": dItem } }) : [];
                        } else {
                            defaultDataMap[key] = rs.data[item.responseKey] && isArray(rs.data[item.responseKey]) ? rs.data[item.responseKey] : [];
                        }
                    } else if (item.listStr === true) {
                        defaultDataMap[key] = rs.data && isArray(rs.data) ? rs.data.map(dItem => { return { "id": dItem, "name": dItem } }) : [];
                    } else {
                        defaultDataMap[key] = rs.data && isArray(rs.data) ? rs.data : [];
                    }
                    mine.setState({
                        defaultDataMap
                    });
                } else {
                    error(rs[projectConfig.msg]);
                }
            });
        }
    };

    createSonField = (formList) => {
        const mine = this;
        const { values, aliasArrMap } = this.props;
        const { defaultDataMap, disabledMap: dm, placeholderMap, helperTextMap, suggest, more, groupsVal, groupIndex, schema, deleteKeys = [] } = this.state;
        const disabledMap = JSON.parse(JSON.stringify(dm));
        const result = [];
        for (let i = 0; i < formList.length; i+=1) {
            const item = formList[i];
            if ((isArray(item.conValue) && !item.conValue.includes(values[item.conKey])) || (!isArray(item.conValue) && values[item.conKey] !== item.conValue)) {
                continue;
            }
            if (item.disabledKey && item.disabledValue) {
                const initDisabled = disabledMap[item.key];
                if ((values[item.disabledKey] === item.disabledValue)) {
                    disabledMap[item.key] = true;
                } else {
                    disabledMap[item.key] = initDisabled;
                }
            }
            
            if (item.type === 'link') {
                const data = JSON.parse(values[item.key] || '[]') || [];
                result.push(<Field
                    className="fastform-field"
                    style={item.style || {}}
                    label={<span>{item.rule && item.rule.isMust ? <span className="required">*</span> : ''}{item.label}</span>}
                    name={item.key}
                    helperText={helperTextMap[item.key]}
                    labelLayout={{ size: item.labelLayout || 8 }}
                    contentLayout={{ size: item.contentLayout || 16 }}>
                    <span>{ data.map((link, index) => {
                        if (index === 0) return <span>
                            <a href={link.url || ""} target="_blank" rel="noopener noreferrer" style={{ lineHeight: "32px", wordBreak: "break-all" }}>
                                { link.name || "" }
                            </a></span>
                        return <span>， 
                            <a href={link.url || ""} target="_blank" rel="noopener noreferrer" style={{ lineHeight: "32px", wordBreak: "break-all" }}>
                                { link.name || "" }
                            </a></span>
                        })
                    }</span>
                </Field>);
            } else if (item.type === 'span') {
                const spanVal = setDefaultValue(values[item.key]);
                const formatVal = item.showinfo ? switchDataWithShowInfo(spanVal, item.showinfo) : spanVal;
                result.push(<Field
                    className="fastform-field"
                    style={item.style || {}}
                    label={<span>{item.rule && item.rule.isMust ? <span className="required">*</span> : ''}{item.label}</span>}
                    name={item.key}
                    helperText={helperTextMap[item.key]}
                    labelLayout={{ size: item.labelLayout || 8 }}
                    contentLayout={{ size: item.contentLayout || 16 }}>
                    <span style={{ lineHeight: "32px", wordBreak: "break-all" }}>{ item.template ? item.template.replace(/\${key}/g, formatVal) : formatVal}</span>
                </Field>);
            } else if (item.type === 'suggest') {
                result.push(<Field
                    className="fastform-field"
                    style={item.style || {}}
                    label={<span>{item.rule && item.rule.isMust ? <span className="required">*</span> : ''}{item.label}</span>}
                    name={item.key}
                    helperText={helperTextMap[item.key]}
                    validateTrigger='onChange'
                    nativeStatusIcon
                    onChange={(value) => { this.inputSuggest(value, item); }}
                    labelLayout={{ size: item.labelLayout || 8 }}
                    contentLayout={{ size: item.contentLayout || 16 }}>
                        <AutoComplete fullWidth suggestions={ suggest[item.key] || [] } defaultValue={values[item.key] || ''} disabled={disabledMap[item.key]} placeholder={ placeholderMap[item.key] || `请输入${item.label}` } />
                </Field>);
            } else if (item.type === 'input') {
                result.push(<Field
                    className="fastform-field"
                    style={item.style || {}}
                    label={<span>{item.rule && item.rule.isMust ? <span className="required">*</span> : ''}{item.label}</span>}
                    name={item.key}
                    helperText={`${helperTextMap[item.key] || ''}${item.rule && item.rule.needLen ? '当前长度' : ''}${item.rule && item.rule.needLen ? getBLen(values[item.key]) : ''}`}
                    validateTrigger='onChange'
                    nativeStatusIcon
                    labelLayout={{ size: item.labelLayout !== undefined ? item.labelLayout : 8 }}
                    contentLayout={{ size: item.contentLayout !== undefined ? item.contentLayout : 16 }}>
                    <Input disabled={disabledMap[item.key]} autoComplete="off" placeholder={placeholderMap[item.key] || `请输入${item.label}`} type={item.inputType || "text" }/>
                </Field>);
            } else if (item.type === 'multinput') {
                result.push(<Field
                    className="fastform-field"
                    style={item.style || {}}
                    label={<span>{item.rule && item.rule.isMust ? <span className="required">*</span> : ''}{item.label}</span>}
                    name={item.key}
                    helperText={`${helperTextMap[item.key]}${item.rule && item.rule.needLen ? '当前长度' : ''}${item.rule && item.rule.needLen ? getBLen(values[item.key]) : ''}`}
                    validateTrigger='onChange'
                    nativeStatusIcon
                    labelLayout={{ size: item.labelLayout || 8 }}
                    contentLayout={{ size: item.contentLayout || 16 }}>
                    <Input multiline rows={item.rows || 5} disabled={disabledMap[item.key]} autoComplete="off" placeholder={placeholderMap[item.key] || `请输入${item.label}`}/>
                </Field>);
            } else if (item.type === 'select') {
                const data = [].concat(item.data || []).concat(item.alias && aliasArrMap ? ((aliasArrMap[item.alias] || []).map(aliasItem => { return { id: item.aliasType === 'number' ? parseInt(aliasItem.id, 10) : aliasItem.id, name: aliasItem.name } }) || []) : []).concat(defaultDataMap[item.key] || []);
                let checkName = '';
                const selectItems = data.map(selectItem => {if (values[item.key] === selectItem[item.dataKey || 'id']) checkName = selectItem[item.dataLabel || 'name']; return { 'label': selectItem[item.dataLabel || 'name'], 'value': selectItem[item.dataKey || 'id'] }});
                result.push(<Field
                    className="fastform-field"
                    style={item.style || {}}
                    label={<span>{item.rule && item.rule.isMust ? <span className="required">*</span> : ''}{item.label}</span>}
                    name={item.key}
                    helperText={helperTextMap[item.key]}
                    validateTrigger='onChange'
                    valuePropName='defaultValue'
                    nativeStatusIcon
                    labelLayout={{ size: item.labelLayout || 8 }}
                    contentLayout={{ size: item.contentLayout || 16 }}>
                    {
                        disabledMap[item.key] ? <Input disabled value={checkName || ''} /> : <Select
                            placeholder={placeholderMap[item.key] || `请选择${item.label}`}
                            options={item.notAll ? [...selectItems] : [{ label: '全部', value: '' }, ...selectItems]}
                            onSearch={(e, value) => {if (item.searchable) this.handleSearch(value, item)}}
                            searchable
                            needReceive={item.searchable || false}
                        ></Select>
                    }
                </Field>);
            } else if (item.type === 'multselect') {
                const data = [].concat(item.data || []).concat(item.alias && aliasArrMap ? ((aliasArrMap[item.alias] || []).map(aliasItem => { return { id: item.aliasType === 'number' ? parseInt(aliasItem.id, 10) : aliasItem.id, name: aliasItem.name } }) || []) : []).concat(defaultDataMap[item.key] || []);
                const selectItems = data.map(selectItem => {return { 'label': selectItem[item.dataLabel || 'name'], 'value': selectItem[item.dataKey || 'id'] }});
                result.push(<Field
                    className="fastform-field"
                    style={item.style || {}}
                    label={<span>{item.rule && item.rule.isMust ? <span className="required">*</span> : ''}{item.label}</span>}
                    name={item.key}
                    helperText={helperTextMap[item.key]}
                    validateTrigger='onChange'
                    valuePropName='defaultValue'
                    nativeStatusIcon
                    labelLayout={{ size: item.labelLayout || 8 }}
                    contentLayout={{ size: item.contentLayout || 16 }}>
                    <Select
                        searchable
                        multiple
                        placeholder={placeholderMap[item.key] || `请选择${item.label}`}
                        options={item.notAll ? [...selectItems] : [{ label: '全部', value: "" }, ...selectItems]}
                    >
                    </Select>
                </Field>);
            } else if (item.type === 'tags') {
                //  待测试
                const data = [].concat(item.data || []).concat(item.alias && aliasArrMap ? ((aliasArrMap[item.alias] || []).map(aliasItem => { return { id: item.aliasType === 'number' ? parseInt(aliasItem.id, 10) : aliasItem.id, name: aliasItem.name } }) || []) : []).concat(defaultDataMap[item.key] || []);
                const selectItems = data.map(selectItem => {return { 'label': selectItem[item.dataLabel || 'name'], 'value': selectItem[item.dataKey || 'id'] }});
                result.push(<Field
                    className="fastform-field"
                    style={item.style || {}}
                    label={<span>{item.rule && item.rule.isMust ? <span className="required">*</span> : ''}{item.label}</span>}
                    name={item.key}
                    helperText={helperTextMap[item.key]}
                    validateTrigger='onChange'
                    valuePropName='defaultValue'
                    nativeStatusIcon
                    labelLayout={{ size: item.labelLayout || 8 }}
                    contentLayout={{ size: item.contentLayout || 16 }}>
                        <TagSelect
                            triggerKey={item.keyCode || 32}
                            placeholder={placeholderMap[item.key] || `请选择/输入${item.label}`}
                            options={item.notAll ? [...selectItems] : [{ label: '全部', value: '' }, ...selectItems]}
                        >
                        </TagSelect>
                </Field>);
            } else if (item.type === 'radio') {
                const data = [].concat(item.data || []).concat(item.alias && aliasArrMap ? ((aliasArrMap[item.alias] || []).map(aliasItem => { return { id: item.aliasType === 'number' ? parseInt(aliasItem.id, 10) : aliasItem.id, name: aliasItem.name } }) || []) : []).concat(defaultDataMap[item.key] || []);
                const hasMore = !more[item.key] ? <Button variant="contained" color={item.primary || 'primary'} onClick={() => {this.showMore(item)}}>展开</Button>
                            : <Button variant="contained" color={item.primary || 'primary'} onClick={() => {this.showLess(item)}}>收起</Button>;
                result.push(<Field
                    className="fastform-field"
                    style={item.style || {}}
                    label={<span>{item.rule && item.rule.isMust ? <span className="required">*</span> : ''}{item.label}</span>}
                    name={item.key}
                    helperText={helperTextMap[item.key]}
                    validateTrigger='onChange'
                    valuePropName='value'
                    nativeStatusIcon
                    labelLayout={{ size: item.labelLayout || 8 }}
                    contentLayout={{ size: item.contentLayout || 16 }}>
                    <RadioGroup>
                        {
                            data.map(radioItem => <Radio label={radioItem[item.dataLabel || 'name']} value={radioItem[item.dataKey || 'id']} key={radioItem[item.dataKey || 'id']} /> )
                        }
                        {
                            item.more ? hasMore : ''
                        }
                    </RadioGroup>
                </Field>);
            } else if (item.type === 'check') {
                const data = [].concat(item.data || []).concat(item.alias && aliasArrMap ? ((aliasArrMap[item.alias] || []).map(aliasItem => { return { id: item.aliasType === 'number' ? parseInt(aliasItem.id, 10) : aliasItem.id, name: aliasItem.name } }) || []) : []).concat(defaultDataMap[item.key] || []);
                const hasMore = !more[item.key] ? <Button variant="contained" color={item.primary || 'primary'} onClick={() => {this.showMore(item)}}>展开</Button>
                            : <Button variant="contained" color={item.primary || 'primary'} onClick={() => {this.showLess(item)}}>收起</Button>;
                result.push(<Field
                    className="fastform-field"
                    style={item.style || {}}
                    label={<span>{item.rule && item.rule.isMust ? <span className="required">*</span> : ''}{item.label}</span>}
                    name={item.key}
                    helperText={helperTextMap[item.key]}
                    validateTrigger='onChange'
                    valuePropName='value'
                    nativeStatusIcon
                    labelLayout={{ size: item.labelLayout || 8 }}
                    contentLayout={{ size: item.contentLayout || 16 }}>
                    <CheckboxGroup disabled={disabledMap[item.key]}>
                        {
                            data.map(checkItem => <Checkbox label={checkItem[item.dataLabel || 'name']} value={checkItem[item.dataKey || 'id']} key={checkItem[item.dataKey || 'id']} /> )
                        }
                        {
                            item.more ? hasMore : ''
                        }
                    </CheckboxGroup>
                </Field>);
            } else if (item.type === 'uploadimage') {
                result.push(<Field
                    className="fastform-field fastform-field-uploadimage"
                    style={item.style || {}}
                    label={<span>{item.rule && item.rule.isMust ? <span className="required">*</span> : ''}{item.label}</span>}
                    name={item.key}
                    helperText={helperTextMap[item.key]}
                    validateTrigger='onChange'
                    valuePropName='defaultFiles'
                    nativeStatusIcon
                    labelLayout={{ size: item.labelLayout || 8 }}
                    contentLayout={{ size: item.contentLayout || 16 }}>
                        <Upload
                            disabled={disabledMap[item.key]}
                            single
                            radioList={[
                                <Radio label="600*600" value="600*600" key="600*600" />,
                                <Radio label="600*400" value="600*400" key="600*400" />
                            ]}
                            radioDefault="600*600"
                            beforeUpload={this.beforeUpload}
                            cropSure={this.cropSure} >
                                <Button>上传本地</Button>
                        </Upload>
                </Field>);
            } else if (item.type === 'multuploadimage') {
                // 待测试
                result.push(<Field
                    className="fastform-field fastform-field-multuploadimage"
                    style={item.style || {}}
                    label={<span>{item.rule && item.rule.isMust ? <span className="required">*</span> : ''}{item.label}</span>}
                    name={item.key}
                    helperText={helperTextMap[item.key]}
                    validateTrigger='onChange'
                    valuePropName='defaultFiles'
                    nativeStatusIcon
                    labelLayout={{ size: item.labelLayout || 8 }}
                    contentLayout={{ size: item.contentLayout || 16 }}>
                        <Upload
                            disabled={disabledMap[item.key]}
                            multiple
                            gallery
                            radioList={[
                                <Radio label="600*600" value="600*600" key="600*600" />,
                                <Radio label="600*400" value="600*400" key="600*400" />
                            ]}
                            radioDefault="600*600"
                            beforeUpload={this.beforeUpload}
                            cropSure={this.cropSure} >
                                <Button>上传本地</Button>
                        </Upload>
                </Field>);
            } else if (item.type === 'uploadfiles') {
                result.push(<Field
                    className="fastform-field fastform-field-uploadfiles"
                    style={item.style || {}}
                    label={<span>{item.rule && item.rule.isMust ? <span className="required">*</span> : ''}{item.label}</span>}
                    name={item.key}
                    helperText={helperTextMap[item.key]}
                    validateTrigger='onChange'
                    valuePropName='defaultFiles'
                    nativeStatusIcon
                    labelLayout={{ size: item.labelLayout || 8 }}
                    contentLayout={{ size: item.contentLayout || 16 }}>
                        <Upload
                            disabled={disabledMap[item.key]}
                            multiple
                            beforeUpload={(file) => this.beforeUploadFiles(file, item)} >
                                <Button>上传本地</Button>
                        </Upload>
                </Field>);
            } else if (item.type === 'uploadNosFile') {
                result.push(<Field
                    className="fastform-field fastform-field-uploadfile"
                    style={item.style || {}}
                    label={<span>{item.rule && item.rule.isMust ? <span className="required">*</span> : ''}{item.label}</span>}
                    name={item.key}
                    helperText={helperTextMap[item.key]}
                    validateTrigger='onChange'
                    valuePropName='defaultFiles'
                    nativeStatusIcon
                    labelLayout={{ size: item.labelLayout || 8 }}
                    contentLayout={{ size: item.contentLayout || 16 }}>
                        <Upload
                            disabled={disabledMap[item.key]}
                            multiple
                            beforeUpload={this.beforeUploadNosFile} >
                                <Button>上传本地</Button>
                        </Upload>
                </Field>);
            } else if (item.type === 'datepicker') {
                const datePickProps = Object.assign({
                    type: 'date',
                    format: item.format || 'YYYY-MM-DD HH:mm:ss',
                    selectType: 'date',
                    clearable: true,
                    showTime: item.showTime || false
                }, item.option || {});
                result.push(<Field
                    className="fastform-field"
                    style={item.style || {}}
                    label={<span>{item.rule && item.rule.isMust ? <span className="required">*</span> : ''}{item.label}</span>}
                    name={item.key}
                    helperText={helperTextMap[item.key]}
                    validateTrigger='onChange'
                    valuePropName='defaultValue'
                    nativeStatusIcon
                    labelLayout={{ size: item.labelLayout || 8 }}
                    contentLayout={{ size: item.contentLayout || 16 }}>
                    <DatePicker
                        { ...datePickProps }
                    />
                </Field>);
            } else if (item.type === 'treeselect'){
                const treeData = defaultDataMap[item.key] || item.data || [];
                result.push(<Field 
                    className="fastform-field"
                    style={item.style || {}}
                    label={<span>{item.rule && item.rule.isMust ? <span className="required">*</span> : ''}{item.label}</span>}
                    name={item.key}
                    helperText={helperTextMap[item.key]}
                    validateTrigger='onChange'
                    nativeStatusIcon
                    labelLayout={{ size: item.labelLayout || 8 }}
                    contentLayout={{ size: item.contentLayout || 16 }}>
                    <TreeSelect 
                        multiple={ false }
                        options={ treeData }
                    />
                </Field>);
            } else if (item.type === 'multtreeselect'){
                const treeData = defaultDataMap[item.key] || item.data || [];
                result.push(<Field 
                    className="fastform-field"
                    style={item.style || {}}
                    label={<span>{item.rule && item.rule.isMust ? <span className="required">*</span> : ''}{item.label}</span>}
                    name={item.key}
                    helperText={helperTextMap[item.key]}
                    validateTrigger='onChange'
                    nativeStatusIcon
                    labelLayout={{ size: item.labelLayout || 8 }}
                    contentLayout={{ size: item.contentLayout || 16 }}>
                    <TreeSelect 
                        showCheckedStrategy={ item.showCheckedStrategy || "all" }
                        multiple
                        options={ treeData }
                    />
                </Field>);
            } else if (item.type === 'todo') {
                result.push(<Field
                    className="fastform-field"
                    style={item.style || {}}
                    label={<span>{item.rule && item.rule.isMust ? <span className="required">*</span> : ''}{item.label}</span>}
                    name={item.key}
                    helperText={helperTextMap[item.key]}
                    labelLayout={{ size: item.labelLayout || 8 }}
                    contentLayout={{ size: item.contentLayout || 16 }}>
                        <div>TODO这里还没有配置</div>
                </Field>);
            } else if (item.type === 'group') {
                result.push(<Row>
                    <Col size={item.labelLayout || 8} style={{ textAlign: "right", lineHeight: "32px", marginTop: 10, marginBottom: 24 }}>{
                        item.label ? <span>{item.rule && item.rule.isMust ? <span className="required">*</span> : ''}{item.label}</span> : ''}</Col>
                    <Col size={item.contentLayout || 13} style={{marginTop: 10, marginBottom: 24}}>{ groupsVal[item.key].map((gv) => {
                        return <div style={Object.assign(item.layout === 'hor' ? { display: 'flex' } : { display: 'block' }, item.style || {})}>{[...this.createSonField(this.updateGroupKey(item, gv)),
                            <Button style={{ marginTop: 10, marginBottom: 24, minWidth: 60 }} onClick={() => {
                                const { updateFieldValue } = this.props;
                                (item.groups || []).forEach((gItem) => {
                                    const newKey = `bjgroup-${(gv && gv.index) || (gv && !gv.index && gv.index === 0) ? gv.index : groupIndex}-${item.key}-${gItem.key}`;
                                    updateFieldValue(newKey, undefined);
                                    deleteKeys.push(newKey);
                                    delete schema[newKey];
                                });
                                this.setState({
                                    deleteKeys,
                                    schema: {
                                        ...schema
                                    },
                                    groupsVal: {
                                        ...groupsVal,
                                        [item.key]: groupsVal[item.key].filter((s) => s.index !== gv.index)
                                    }
                                });
                            }}>删除</Button>]}</div>
                    }) }</Col>
                    <Col size={3}><Button onClick={() => {
                        const { formMap, defaultValueMap, formDataType } = mine.state;
                        const willUpdateSchema = {};
                        (item.groups || []).forEach(sitem => {
                            const newKey = `bjgroup-${groupIndex + 1}-${item.key}-${sitem.key}`;
                            const newItem = Object.assign({}, sitem, {
                                key: newKey
                            });
                            willUpdateSchema[newKey] = this.getSchema(newItem, { index: groupIndex + 1 });
                            if (newItem[`${mine.env}url`] || newItem[`${mine.env}nextUrl`]) {
                                mine.getSearchFormListHandler(newItem);
                                if (newItem.nextKey) mine.getSonData(newItem, defaultValueMap[newItem.key]);
                                if (newItem.nextKeys) {
                                    newItem.nextKeys.map(nextItem => mine.getSearchFormListHandler(formMap[nextItem]))
                                }
                            }
                            formMap[newItem.key] = newItem;
                            defaultValueMap[newItem.key] = setDefaultValue(newItem.defaultValue);
                            placeholderMap[newItem.key] = newItem.placeholder || '';
                            helperTextMap[newItem.key] = newItem.helperText || '';
                            disabledMap[newItem.key] = newItem.notModify || false;
                            formDataType[newItem.key] = {
                                type: newItem.type,
                                ajaxType: newItem.ajaxType,
                                format: newItem.format
                            }
                            const { updateFieldValue } = mine.props;
                            updateFieldValue(newItem.key, defaultValueMap[newItem.key]);
                        });
                        this.setState({
                            groupsVal: {
                                ...groupsVal,
                                [item.key]: [...groupsVal[item.key], { index: groupIndex + 1 }]
                            },
                            groupIndex: groupIndex + 1,
                            schema: {
                                ...schema,
                                ...willUpdateSchema
                            },
                            formMap, defaultValueMap, placeholderMap, helperTextMap, disabledMap, formDataType
                        }, () => {
                            mine.props.updateSchema(this.state.schema);
                        }) }}>添加{item.label}</Button></Col>
                </Row>);
            } else {
                result.push(<Field
                    className="fastform-field"
                    style={item.style || {}}
                    label={<span>{item.rule && item.rule.isMust ? <span className="required">*</span> : ''}{item.label}</span>}
                    name={item.key}
                    helperText={helperTextMap[item.key]}
                    labelLayout={{ size: item.labelLayout || 8 }}
                    contentLayout={{ size: item.contentLayout || 16 }}>
                        <div>这里是错误类型</div>
                </Field>);
            }
        }
        return result;
    };

    getGroupKey = (item, groups, gv) => {
        const mine = this;
        const { groupIndex } = mine.state;
        return `bjgroup-${(gv && gv.index) || (gv && !gv.index && gv.index === 0) ? gv.index : groupIndex}-${groups.key}-${item.key}`;
    }

    updateGroupKey = (groups, gv) => {
        const mine = this;
        return (groups.groups || []).map(item => {
            return Object.assign({}, item, {
                key: mine.getGroupKey(item, groups, gv)
            });
        });
    };

    createField = () => {
        const result = [];
        const { parseSrcFormList } = this.state;
        if (this.config.vertical === true) {
            for (let i = 0; i < parseSrcFormList.length; i += 1) {
                if (isArray(parseSrcFormList[i])) {
                    result.push(<div style={{float: 'left', width: `${Math.floor(100 / parseSrcFormList.length)}%`}}>{this.createSonField(parseSrcFormList[i])}</div>);
                } else {
                    console.error('vertical模式下,forms元素为数组.');
                }
            }
        } else if (isArray(parseSrcFormList)) {
            return this.createSonField(parseSrcFormList);
        } else {
            console.error('vertical模式下,forms元素为数组.');
        }
        return result;
    };

    createFunBtns = () => {
        const { submit, values } = this.props;
        const { fastmode } = this.state;
        const result = [];
        for (let i = 0; i < (this.config.funBtns || []).length; i += 1) {
            const itemKey = this.config.funBtns[i].key || '';
            const showmode = this.config.funBtns[i].showmode || [];
            const itemConfig = this.config[itemKey] || '';
            if (itemKey && itemConfig && showmode.indexOf(fastmode) > -1) {
                if (itemConfig.type === 'link') {
                    result.push ( <Button style={Object.assign(this.config.funBtns[i].style || {}, this.config[itemKey].style || {})}
                                variant="contained" color={this.config[itemKey].primary || 'primary'}
                                onClick={() => {this.goback(this.config[itemKey]);}}>{this.config[itemKey].label || this.config.funBtns[i].label}</Button> );
                } else if (!itemConfig.notValidate === true)
                    result.push ( <Button style={Object.assign(this.config.funBtns[i].style || {}, this.config[itemKey].style || {})}
                                variant="contained" color={this.config[itemKey].primary || 'primary'}
                                onClick={submit(data => this.submitHandler(data, itemConfig), err => console.log(err))}>{this.config[itemKey].label || this.config.funBtns[i].label}</Button> );
                else
                    result.push ( <Button style={Object.assign(this.config.funBtns[i].style || {}, this.config[itemKey].style || {})}
                                variant="contained" color={this.config[itemKey].primary || 'primary'}
                                onClick={() => this.submitHandler(values, itemConfig)}>{this.config[itemKey].label || this.config.funBtns[i].label}</Button> );
            }
        }
        return result;
    }

    switchJsOrJson = (data) => {
        xhr({
            url: '/local/api/switchJsOrJson',
            method: 'post',
            data,
            type: 'json'
        }).then((rs) => {
            if (rs[projectConfig.codeKey] === projectConfig.code) {
                success('格式转换成功!');
            } else {
                error(rs[projectConfig.msg]);
            }
        });
    }

    render() {
        return (<Row className="mb-10">
                    <Col>
                        <div className={!this.config.nbg ? "section" : ''} style={{padding: '10px 30px'}}>
                            {
                                !this.props.notModify && this.env === 'local.' ? <Button
                                    variant="contained" color="info"
                                    size="small"
                                    style={{"height": "auto", "float": "right"}}
                                    onClick={() => {
                                        this.switchJsOrJson({
                                            path: this.props.path,
                                            uuid: this.config.uuid
                                        })
                                    }}>toJS</Button> : ''
                            }
                            <Row justify="center">
                                <Col align="stretch">
                                    {
                                        this.config.name ? <span style={{fontSize: 16, fontWeight: 'bold'}}>{ this.config.name }</span> : ''
                                    }
                                    {
                                        this.config.name && this.config.description ? <span style={{ marginLeft: 12 }}>({ this.config.description })</span> : ''
                                    }
                                </Col>
                            </Row>
                            <Row justify="center">
                                <Col align="stretch">
                                    {this.state.loading ? <Loading /> : ''}
                                    {this.createField()}
                                </Col>
                            </Row>
                            <Row justify="center">
                                <Col align="stretch" style={{ textAlign: 'right', marginTop: 15 }}>
                                    { this.createFunBtns() }
                                    {
                                        this.config.reset ? <Button style={{ marginLeft: 10 }} onClick={this.resetHandler} type="hollow">重置</Button> : ''
                                    }
                                    {
                                        this.config.goback ? <Button style={{ marginLeft: 10 }} onClick={this.cancelHandler} type="hollow">{this.config.goback.label || '取消'}</Button> : ''
                                    }
                                </Col>
                            </Row>
                        </div>
                    </Col>
                </Row>
        );
    }
}

export default withRouter(createEasyForm({}, {})(Fastform));
