/*
 * @Author: zhangzc
 * @Email: zhangzc2@guahao.com
 * @Date: 2019-04-25 11:30:30
 * @Last Modified by: mikey.zhaopeng
 * @Last Modified time: 2022-06-02 16:44:57
 * @Description: 表单页面组件
 */

<template>
    <!-- 锚点组件 -->
    <bk-anchor-location-tag :tabConfig="formConfig.tabConfig">
        <div class="form-wrapper">
            <!-- 全局顶部自定义插槽 -->
            <slot name="above-page" />
            <bk-slot :config="formConfig"
                     slot-name="above-page" />

            <!-- 全局tips顶部自定义插槽 -->
            <slot name="above-tips" />
            <bk-slot :config="formConfig"
                     slot-name="above-tips" />

            <!-- 全局提示 -->
            <template v-if="formConfig.tips">
                <bk-title :label="formConfig.tips" />
            </template>

            <!-- 全局tips底部自定义插槽 -->
            <slot name="under-tips" />
            <bk-slot :config="formConfig"
                     slot-name="under-tips" />

            <!-- 表单主体 -->
            <el-form ref="formGroup"
                     v-if="formConfig.data"
                     :model="formParams"
                     :class="[formConfig.layout && `form-${formConfig.layout}` || 'form-grid']"
                     @submit.native.prevent
                     v-bind="getMergedObject(formConfig.extend?formConfig.extend:formConfig,
                                             {labelWidth: formConfig.layout === 'flow' ? '70px' : '120px', 
                                              inline:true})">
                <!-- 表单组，可以配置多个表单组 -->
                <template v-for="(dataConfig, i) in formConfig.data">
                    <!-- 表单title顶部自定义插槽 -->
                    <bk-slot :config="dataConfig"
                             slot-name="above-title" />

                    <!-- 表单标题 -->
                    <div v-if="dataConfig.title"
                         class="form-title-wrapper">
                        <bk-title :label="dataConfig.title.label"
                                  :note="dataConfig.title.note" />
                        <!-- 表单标题同行按钮配置 -->
                        <template v-if="dataConfig.title.button && Array.isArray(dataConfig.title.button.data)">
                            <el-button v-for="btn in dataConfig.title.button.data"
                                       :key="btn.name"
                                       @click="() => handleBtnClick(btn)"
                                       v-bind="getMergedObject(btn.extend?btn.extend:btn,
                                                               {size:'small'})">
                                {{ btn.label }}
                            </el-button>
                        </template>
                    </div>

                    <!-- 表单title底部自定义插槽 -->
                    <bk-slot :config="dataConfig"
                             slot-name="under-title" />

                    <!-- 表单form顶部自定义插槽 -->
                    <bk-slot :config="dataConfig"
                             slot-name="above-form" />

                    <!-- 表单项 -->
                    <template v-if="(formConfig.layout === 'flow'
                        && formConfig.media !== false
                        && Array.isArray(formConfig.data)
                        && Array.isArray(dataConfig.data))">
                        <template v-for="materialConfig in dataConfig.data">
                            <div v-show="handleSearchFormVisible(materialConfig)"
                                 :key="materialConfig.name"
                                 :class="{'form-material': true,
                                          'hide': dependOnChange(materialConfig),
                                          'search-show': handleSearchFormVisible(materialConfig),
                                          [materialConfig.className]: materialConfig.className }">
                                <bk-form-material :ref="`form-${materialConfig.name}`"
                                                  :key="materialConfig.name"
                                                  :materialConfig="materialConfig"
                                                  :formConfig="formConfig"
                                                  :formParams="formParams"
                                                  @toggle="handleToggle"
                                                  @dependOnChange="dependOnChange"
                                                  @btnClick="handleBtnClick"
                                                  @handlerEnter="handlerEnter"
                                                  :extend="materialConfig.extend 
                                                      ? materialConfig.extend : materialConfig" />
                            </div>
                        </template>
                    </template>
                    <template v-else>
                        <div v-if="Array.isArray(materialConfigsforLayout[i].data) && materialConfigsforLayout[i].data.length > 0"
                             class="form-body-wrapper">
                            <template v-for="materialConfigsInRow in materialConfigsforLayout[i].data">
                                <template>
                                    <el-row v-show="!materialConfigsInRow.data.every(item => item.visible === false)">
                                        <template v-for="materialConfig in materialConfigsInRow.data">
                                            <el-col v-show="handleSearchFormVisible(materialConfig)"
                                                    :key="materialConfig.name"
                                                    :span="materialConfig.grid ? parseInt(24 / materialConfig.grid) : 24"
                                                    :class="{'hide': dependOnChange(materialConfig),
                                                             [materialConfig.className]: materialConfig.className }">
                                                <bk-form-material :ref="`form-${materialConfig.name}`"
                                                                  :key="materialConfig.name"
                                                                  :materialConfig="materialConfig"
                                                                  :formConfig="formConfig"
                                                                  :formParams="formParams"
                                                                  @toggle="handleToggle"
                                                                  @dependOnChange="dependOnChange"
                                                                  @btnClick="handleBtnClick"
                                                                  @handlerEnter="handlerEnter"
                                                                  :extend="materialConfig.extend 
                                                                      ? materialConfig.extend : materialConfig" />
                                            </el-col>
                                        </template>
                                    </el-row>
                                </template>
                            </template>
                        </div>
                    </template>

                    <!-- 流式布局按钮插槽 -->
                    <template v-if="!formConfig.readonly">
                        <slot name="search" />
                    </template>

                    <!-- 表单form底部自定义插槽 -->
                    <bk-slot :config="dataConfig"
                             slot-name="under-form" />
                </template>

                <!-- 弹窗区域 -->
                <!-- TODO -->

                <!-- 匿名插槽 -->
                <slot />
            </el-form>

            <!-- 全局button顶部自定义插槽 -->
            <slot name="above-button" />
            <bk-slot :config="formConfig"
                     slot-name="above-button" />

            <!-- 底部按钮区域 -->
            <el-row v-if="formConfig.button
                        && Array.isArray(formConfig.button.data)
                        && formConfig.button.visible !== false"
                    justify="center"
                    class="form-footer">
                <el-button v-for="item in formConfig.button.data"
                           v-if="item.visible !== false"
                           :key="item.name"
                           @click="() => handleBottomBtnClick(item)"
                           v-bind="item.extend ? getMergedObject(item.extend, {
                               type: 'primary'
                           }) : getMergedObject(item, {
                               type: 'primary'
                           })"
                           :loading="item.loadingSwitch ? submittingObj[item.name] : false">
                    {{ item.label }}
                </el-button>
            </el-row>

            <!-- 全局button底部自定义插槽 -->
            <slot name="under-button" />
            <bk-slot :config="formConfig"
                     slot-name="under-button" />

            <!-- 全局底部自定义插槽 -->
            <slot name="under-page" />
            <bk-slot :config="formConfig"
                     slot-name="under-page" />

            <!-- 弹窗区域 -->
            <div v-if="!isEmptyObj(dialogConfig)"
                 class="dialog-wrapper">
                <!--dialog数据下传-->
                <bk-dialog ref="dialog"
                           :dialog-config="dialogConfig"
                           :dialog-visible="dialogVisible" />
            </div>
        </div>
    </bk-anchor-location-tag>
</template>

<script>
import {
    isEmptyObj, getMergedObject, nameMatchType, allKeysValueExpected, hasField 
} from 'utils/util';

export default {
    name: 'BkForm',
    props: {
        formConfig: {
            required: true,
            type: Object,
            default: () => ({})
        },
        dialogConfig: {
            type: Object,
            default: () => ({})
        }
    },
    data() {
        const bkConfig = this.$root.bkConfig || this.$bkConfig;
        return {
            bkConfig,
            isEmptyObj,
            getMergedObject,
            formParams: {}, // 表单的所有参数集合
            dialogVisible: {}, // 所有弹窗显示状态集合
            materialConfigs: [], // 将formConfig转化后的一维元组件配置数组，拿掉了data这一层
            materialConfigsforLayout: [], // 将元组件配置按照grid进行二维化，方便进行多栏布局
            rangeTypeList: ['daterange', 'monthrange', 'datetimerange'], // 时间区域选择控件
            typeArrayList: ['cascader', 'checkbox', 'transfer', 'areaselect', 'listselect'], // 数据类型为数组的列表
            // 下列参数的作用有待优化
            allowEmpty: true, // 关联赋值是控制参数 不清空
            codeSign: '', // 保存验证码时间戳
            submittingObj: {}, //  按钮防重复提交标志对象集合
            formWrapperHeight: 0, // 表单容器的高度
            tabSaveArr: [], // 保存tab初始化距离窗口顶部的高度
            tabWrapperHeight: 0, // 初始化tab标签的高度
            tabActiveName: '' // 初始化tab高亮name
        };
    },
    watch: {
        // 监听formConfig的改变，更新materialConfigs
        formConfig() {
            this.formatFormConfigToMaterialConfigs();
        },
        // 监听formParams表单值的改变
        formParams: {
            handler(val) {
                this.$emit('formParamsChange', val);
            },
            deep: true
        },
        // 监听results的变化，进行赋值
        'formConfig.results': {
            handler(val) {
                if (!isEmptyObj(val) && JSON.stringify(val) !== JSON.stringify(this.formParams)) {
                    this.handleServerData(Object.assign(this.formParams, val));
                }
            },
            deep: true
        }
    },
    created() {
        // 格式化materialConfigs
        this.formatFormConfigToMaterialConfigs();
        const { formConfig, dialogConfig } = this;

        // 初始化dialogVisible
        if (dialogConfig && Array.isArray(dialogConfig.data)) {
            dialogConfig.data.forEach(item => {
                this.$set(this.dialogVisible, item.name, false);
            });
        }

        // 当results属性不存在，进行初始化，否则无法对results进行监听
        if (!formConfig.results) {
            this.$set(formConfig, 'results', {});
        } else {
            this.handleServerData(formConfig.results);
        }

        // 初始化按钮防重复提交标志对象集合
        if (formConfig.button && Array.isArray(formConfig.button.data) && formConfig.button.visible !== false) {
            formConfig.button.data.forEach(btn => {
                this.$set(this.submittingObj, btn.name, false);
            });
        }

        const { http } = formConfig;
        // 请求页面数据
        if (http && http.url) this.load();
    },
    methods: {
        /**
         * 请求页面数据
         */
        load() {
            const { http } = this.formConfig;
            if (!http || !http.url) return;
            const { data } = this.bkConfig.responseProps;
            const { onSuccess, onBefore, method } = http;
            let params = Object.assign({}, http.params);
            if (onBefore) {
                params = onBefore(params, this) === false ? false : params;
                if (params === false) return;
            }
            this.$fetch({
                url: http.url,
                method,
                params
            }).then(res => {
                this.$emit('server-change', res);
                if (!res) return;
                let form = res[data];
                if (onSuccess) {
                    form = onSuccess(res, this) || form;
                    if (form === false) return;
                }
                this.handleServerData(form);
            });
        },

        /**
         * 转化数据结构并设置表单参数的值
         * @param {Object} formParamsValue 表单参数值，来源于父组件给的初始值或更新值
         */
        handleServerData(formParamsValue) {
            // 关闭关联清空
            this.allowEmpty = false;

            const tprFormParams = {};
            // 所有表单配置
            this.materialConfigs.forEach(item => {
                this.setFormParamValue(item, formParamsValue, tprFormParams);
            });

            // TODO
            this.formParams = tprFormParams;
        },

        /**
         * 将formConfig的二维数组配置转化为一维数组materialConfigs
         */
        formatFormConfigToMaterialConfigs() {
            this.materialConfigs = [];
            this.materialConfigsforLayout = [];
            if (!Array.isArray(this.formConfig.data)) return;

            this.formConfig.data.forEach((config, i) => {
                this.materialConfigsforLayout.push({
                    data: []
                });
                const { data } = config;
                if (Array.isArray(data)) {
                    let k = 0;
                    // 多表单组
                    const tb = this.materialConfigsforLayout[i].data;
                    data.forEach(item => {
                        this.materialConfigs.push(item);
                        if (!tb[k]) {
                            tb[k] = {
                                data: [item]
                            };
                            if (item.grid === 1 || !item.grid) {
                                k += 1;
                            }
                        } else {
                            let num = 24 / item.grid;
                            const row = tb[k].data; // 行

                            for (let n = 0; n < row.length; n += 1) {
                                const col = row[n];
                                const { grid = 1 } = col; 
                                num += (24 / grid);
                                const isLast = n === row.length - 1; // 是否为最后一个元素
                                if (item.grid === 1) {
                                    // 单行
                                    tb[k + 1] = {
                                        data: [item]
                                    };
                                    k += 2;
                                    break;
                                } else if (num === 24 && isLast) {
                                    // 总和刚刚好则下一行
                                    row.push(item);
                                    k += 1;
                                    break;
                                } else if (num > 24) {
                                    // 超出另起一行
                                    k += 1;
                                    tb[k] = {
                                        data: [item]
                                    };
                                    break;
                                } else if (isLast) {
                                    // 最后一个时num 不大于24时添加
                                    row.push(item);
                                    break;
                                }
                            }
                        }
                    });
                }
            });
        },

        /**
         * 设置表单参数的值
         * @param {object} materialConfig 元组件配置
         * @param {object} formParamsValue 表单参数值，来源于父组件给的初始值或更新值
         * @param {object} tprFormParams 临时的formParams对象
         */
        setFormParamValue(materialConfig, formParamsValue, tprFormParams) {
            const {
                name, type, extraFields, http = {} 
            } = materialConfig;
            const value = formParamsValue[name];
            const extraValue = formParamsValue[extraFields];

            if (value === undefined || value === null) {
                tprFormParams[name] = this.typeArrayList.includes(type) ? [] : type === 'number' ? undefined : '';
            }

            // 判断extraFields字段是否都为空
            let extraFieldsHasValue = false;
            if (Array.isArray(extraFields)) {
                extraFieldsHasValue = extraFields.findIndex(item => formParamsValue[item]) > -1;
            }
            // 当获取的值不存在则跳出
            if (!this.rangeTypeList.includes(type) && (value === undefined || value === null)) return;
            if (
                typeof extraFields === 'string'
                && http.initSwitch === false
                && (extraValue === undefined || extraValue === null)
            ) return;
            if (Array.isArray(extraFields) && !extraFieldsHasValue) return;
            // 数据转换
            this.dealMaterialFieldByConfig(materialConfig, formParamsValue, tprFormParams);
        },

        /**
         * 根据元组件配置对部分特殊元组件参数进行处理
         * @param {object} materialConfigF 元组件配置
         * @param {object} formParamsValue 表单参数值，来源于父组件给的初始值或更新值
         * @param {object} tprFormParamsF 临时的formParams对象
         */
        dealMaterialFieldByConfig(materialConfigF, formParamsValue, tprFormParamsF) {
            const materialConfig = materialConfigF;
            const tprFormParams = tprFormParamsF;
            const {
                name, type, extraFields, props 
            } = materialConfig;
            const value = formParamsValue[name];

            // 默认直接赋值
            tprFormParams[name] = value;

            // 特殊情况
            if (type === 'checkbox' && typeof value === 'string') {
                // 多选框，字符串数据需格式化为数组
                tprFormParams[name] = value.split(',');
            } else if (type === 'cascader') {
                // 获取cascader实例
                const key = `form-${name}`;
                const $item = this.$refs[key] ? this.$refs[key][0] : undefined;
                if (!$item) return;
                $item.getOptions('', () => {
                    $item.getCascaderSubset(value);
                });
            } else if ((type === 'search' || type === 'autocomplete') && formParamsValue[extraFields]) {
                // // select search 用显示
                // label key
                const keyLabel = props && props.label ? props.label : 'label';
                // val key
                const keyVal = props && props.value ? props.value : 'value';

                // search value
                const extraFieldValue = formParamsValue[extraFields];
                const option = {
                    [keyLabel]: extraFieldValue,
                    [keyVal]: value
                };
                this.$set(materialConfig, 'options', [option]);
            } else if (this.rangeTypeList.includes(type) && Array.isArray(extraFields)) {
                if (!value || !Array.isArray(value)) {
                    const valueArr = [];
                    extraFields.forEach(key => {
                        valueArr.push(formParamsValue[key]);
                    });
                    tprFormParams[name] = valueArr;
                } else {
                    // 同bk-form-material的handleTimeChange方法的应用场景
                    extraFields.forEach(key => {
                        tprFormParams[key] = formParamsValue[key] || '';
                    });
                }
            } else if (type === 'areaselect' || type === 'listselect') {
                if (typeof value === 'string') {
                    const valueObj = JSON.parse(value);
                    if (Array.isArray(valueObj)) {
                        tprFormParams[name] = valueObj;
                    } else {
                        console.warn(`${name}返回数据结构异常`);
                        tprFormParams[name] = [];
                    }
                } else if (!Array.isArray(value)) {
                    console.warn(`${name}返回数据结构异常`);
                    tprFormParams[name] = [];
                }
            } else if (type === 'address') {
                if (extraFields && Array.isArray(extraFields)) {
                    extraFields.forEach(extraFieldsItem => {
                        tprFormParams[extraFieldsItem] = formParamsValue[extraFieldsItem];
                    });
                }
            }
        },

        /**
         * 获取formItem实例
         * @param {String} name item name
         */
        getFormItem(name) {
            let obj = this.$refs[`form-${name}`];
            if (Array.isArray(obj)) {
                [obj] = obj;
            }
            if (!obj) {
                console.warn(`没有找到${name}的item`);
            }
            return obj;
        },

        /**
         * 重置所有/单个元组件为初始值
         * @param {String} name 元组件标识
         */
        resetFormParams(name) {
            if (name) {
                // 单个
                this.getFormItem(name).resetField();
            } else if (this.$refs.formGroup) {
                // 全部
                this.$refs.formGroup.resetFields();
            }
        },

        /**
         * 清空所有/单个元组件的值
         */
        clearFormParams() {
            this.handleServerData({});
        },

        /**
         * 当元组件发生变更，触发此函数
         * @param {String} val 元组件变更后的值
         * @param {Object} item 元组件配置
         */
        handleToggle(val, item) {
            this.$emit('toggle-config', {
                item,
                value: val
            });
        },

        /**
         * 按钮点击事件
         * @param {Object} btn 被点击的按钮实例
         */
        handleBtnClick(btn) {
            if (btn.target) {
                this.dialogVisible[btn.target] = true;
            } else if (btn.callback && typeof btn.callback === 'function') {
                // 自定义回调
                btn.callback(this);
            }
        },

        /**
         * 底部按钮点击
         * @param {Object} btn 被点击的按钮实例
         */
        handleBottomBtnClick(btn) {
            const { target, callback } = btn;
            if (target) {
                // 弹窗
                this.handleBtnClick(btn);
            } else if (typeof callback === 'function') {
                callback(this);
            } else {
                this.handleSubmit(btn);
            }
        },

        /**
         * 表单校验的函数
         * @param {Function} callback 校验通过后的回调函数
         * @param {Function} errorCallback 校验不通过的回调函数
         */
        handleVerify(callback, errorCallback) {
            const validFieldArr = [];
            this.formConfig.data.forEach(dataConfig => {
                if (Array.isArray(dataConfig.data)) {
                    dataConfig.data.forEach(materialConfig => {
                        if (materialConfig.visible !== false && !this.dependOnChange(materialConfig) && (materialConfig.required || Array.isArray(materialConfig.rules))) {
                            validFieldArr.push(materialConfig.name);
                        }
                    });
                }
            });
            let valid = true;
            this.$refs.formGroup.validateField(validFieldArr, message => {
                if (message) {
                    valid = false;
                }
            });
            if (valid && typeof callback === 'function') {
                callback();
                return true;
            } 
            if (typeof errorCallback === 'function') errorCallback();
            return false;
        },

        /**
         * 调用表单校验及用户确认
         * @param {Object} btn 被点击的按钮实例
         * @param {Object} obj 需要改变submitting提交状态的实例
         */
        handleSubmit(btn, obj) {
            this.handleVerify(() => {
                if (btn.confirmText) {
                    // 用户确认后提交
                    this.$confirm(btn.confirmText).then(() => {
                        this.submitParams(btn, obj);
                    });
                } else if (btn.http && btn.http.confirm) {
                    this.$confirm(btn.http.confirm).then(() => {
                        this.submitParams(btn, obj);
                    });
                } else {
                    // 提交请求
                    this.submitParams(btn, obj);
                }
            });
        },

        /**
         * 执行提交 数据
         * @param {Object} btn 被点击的按钮实例
         * @param {Object} objF 需要改变submitting提交状态的实例
         */
        submitParams(btn, objF) {
            const obj = objF || this;
            const { name } = btn;
            // 防重复提交
            if (!obj.submittingObj[name]) {
                obj.submittingObj[name] = true;
                const { http } = btn;
                const { onBefore, onSuccess, onFaild } = http || {};
                // 格式化表单参数
                let formatedFormParams = this.formatFormParams();
                // 调用请求发送前函数钩子
                if (typeof onBefore === 'function') {
                    const result = onBefore(formatedFormParams, this);
                    if (result === false) {
                        obj.submittingObj[name] = false;
                        return false;
                    }
                    if (typeof result === 'object') formatedFormParams = result;
                }
                if (!http) {
                    console.error('button.http is undefined');
                    obj.submittingObj[name] = false;
                    return false;
                }
                const { url, params, method } = http;
                if (!url) {
                    console.error('button.http.url is undefined');
                    obj.submittingObj[name] = false;
                    return false;
                }

                let finalParams = JSON.parse(JSON.stringify(formatedFormParams));
                if (typeof params === 'object') {
                    // 一定要注意params会覆盖formatedFormParams的值
                    // 在使用时不能在params里定义formatedFormParams涉及到的属性
                    finalParams = Object.assign({}, formatedFormParams, params);
                }
                return this.$fetch({
                    url,
                    params: finalParams,
                    method: method || 'post'
                })
                    .then(res => {
                        obj.submittingObj[name] = false;
                        if (!res) {
                            if (typeof onFaild === 'function') onFaild(res, obj);
                            return;
                        }
                        // 成功回调
                        if (typeof onSuccess === 'function') {
                            onSuccess(res, obj);
                        }
                    })
                    .catch(err => {
                        obj.submittingObj[name] = false;
                        // 失败回调
                        if (typeof onFaild === 'function') {
                            onFaild(err, obj);
                        }
                    });
            }
            return false;
        },

        /**
         * 转换数据成服务器接收的格式
         * @param {Boolean} isHasVisible  过滤visible
         */
        formatFormParams(isHasVisible) {
            const { formParams } = this;
            const params = {};

            this.materialConfigs.forEach(materialConfig => {
                const {
                    name,
                    type,
                    options,
                    visible,
                    extraFields,
                    props,
                    noSubmit,
                    toString,
                    objToString,
                    separator,
                    depend = {}
                } = materialConfig;

                // 如果目标不存在name
                if (!name) {
                    console.warn('name字段不能为空！');
                    return;
                }

                let value = formParams[name];
                // 过滤隐藏字段(包括依赖值不符时的隐藏)和非提交字段
                if (
                    value === undefined
                    || (visible === false && isHasVisible !== false)
                    || (depend.noSubmit && this.dependOnChange(materialConfig))
                ) {
                    return;
                }

                // 对额外字段的配置进行处理
                if (extraFields) {
                    Object.assign(params, this.dealExtraFieldsValue(materialConfig, value));
                }
                if ((type === 'checkbox' || type === 'transfer') && Array.isArray(value) && toString === true) {
                    // 将数组值转化为数组字符串
                    params[name] = value.join(',');
                    if (params[extraFields] && Array.isArray(params[extraFields])) {
                        const arrExtra = [];
                        params[extraFields].forEach(item => {
                            if (item) arrExtra.push(item);
                        });
                        params[extraFields] = arrExtra.join(',');
                    }
                } else if (type === 'transfer' && Array.isArray(value) && objToString) {
                    const arr = [];
                    value.forEach(val => {
                        const obj = options.find(i => i[(props && props.key) || 'key'] === val);
                        if (!obj) return;
                        arr.push(obj);
                    });
                    params[name] = Array.isArray(arr) ? JSON.stringify(arr) : arr;
                } else if (type === 'upload') {
                    // 图片转ids
                    let key = this.bkConfig.responseFileProps.fileId;
                    if (materialConfig.responseFileProps && materialConfig.responseFileProps.fileId) {
                        key = materialConfig.responseFileProps.fileId;
                    }
                    if (Array.isArray(value)) {
                        value = value
                            .map(item => {
                                if (typeof item === 'string' && item.trim()) {
                                    return item;
                                } 
                                if (item && item[key]) {
                                    return item[key];
                                }
                                return ''; 
                            })
                            .filter(item => item)
                            .join(',');
                    }

                    params[name] = value;
                } else if (
                    (type === 'areaselect' || type === 'listselect')
                    && typeof value !== 'string'
                    && toString === true
                ) {
                    params[name] = JSON.stringify(value);
                } else if (type === 'tag' && toString === true) {
                    params[name] = value.join(separator);
                } else if (typeof value !== 'string' && toString === true) {
                    params[name] = JSON.stringify(value);
                } else if (type === 'address' && Array.isArray(extraFields)) {
                    extraFields.forEach(item => {
                        params[item] = formParams[item];
                    });
                } else {
                    params[name] = value;
                }
                if (noSubmit) delete params[name];
            });

            // 验证码提交时需要用时间戳
            if (this.codeSign) params.codeSign = this.codeSign;

            return params;
        },

        /**
         * 根据extraFields配置对元组件进行表单属性值处理
         * @param {Object} materialConfig 元组件配置
         * @param {Array} val 元组件对应的表单属性值
         * */
        dealExtraFieldsValue(materialConfig, val) {
            const {
                props, extraFields, type, options 
            } = materialConfig;

            // 若表单值清空，则额外字段也清空
            if ((val !== 0 && !val) || Object.keys(val).length === 0) {
                return {};
            }

            // 要返回的额外字段对象
            const extraFieldsObj = {};
            // 元组件其他的表单值
            let extraValues = [];
            // 元组件的表单值
            const values = Array.isArray(val) ? val : [val];
            // 元组件额外字段的键值
            const extraFieldsArray = Array.isArray(extraFields) ? extraFields : [extraFields];
            // option编码值的键，默认为label
            const labelKey = props && props.label ? props.label : 'label';
            // option显示值的键，默认为value
            const valueKey = props && props.value ? props.value : 'value';
            const childrenKey = props && props.children ? props.children : 'children';
            // 查询
            if (type === 'cascader') {
                // 针对cascader级联元组件
                this.dealCascaderExtraValues({
                    options: materialConfig.options,
                    valueKey,
                    childrenKey,
                    values,
                    extraFieldsArray,
                    extraValues
                });
            } else if (Array.isArray(options)) {
                // 针对有options的元组件，例如select，search等
                // 基于匹配值获取valueKey所对应的值
                values.forEach(target => {
                    // 查找匹配的option对象
                    const optionObj = this.queryOptionObjByValueKey(options, valueKey, target);
                    if (optionObj) extraValues.push(optionObj[labelKey]);
                });
            } else {
                // 针对value为数组的情况，例如：daterange
                extraValues = values;
            }

            extraFieldsArray.forEach((extraField, i) => {
                if (extraField instanceof Object) {
                    Object.keys(extraField).forEach(key => {
                        if (extraValues[i] && extraValues[i][extraField[key]]) {
                            extraFieldsObj[extraField[key]] = extraValues[i][extraField[key]];
                        }
                    });
                } else if (type === 'checkbox') {
                    extraFieldsObj[extraField] = extraValues;
                } else if (type === 'upload' && extraValues[i].constructor === Object) {
                    const field = this.bkConfig.responseFileProps.fileId;
                    extraFieldsObj[extraField] = extraValues[i][field];
                } else {
                    extraFieldsObj[extraField] = extraValues[i];
                }
            });
            return extraFieldsObj;
        },

        /**
         * 针对cascader的表单提交，处理extraFields
         * @param {Object} objF 需要的各个字段组成的对象
         * @param {Number} i 循环遍历的索引
         */
        dealCascaderExtraValues(objF, i = 0) {
            const {
                options, valueKey, childrenKey, values, extraFieldsArray, extraValues 
            } = objF;
            const optionObj = this.queryOptionObjByValueKey(options, valueKey, values[i]);
            if (optionObj) {
                if (extraFieldsArray[i] instanceof Object) {
                    const fieldsObj = extraFieldsArray[i];
                    const tmpObj = {};
                    Object.keys(fieldsObj).forEach(key => {
                        tmpObj[fieldsObj[key]] = optionObj[key];
                    });
                    extraValues.push(tmpObj);
                } else {
                    extraValues.push(optionObj[valueKey]);
                }
                // 继续查询
                if (values.length > i + 1 && Array.isArray(optionObj[childrenKey])) {
                    this.dealCascaderExtraValues(
                        {
                            options: optionObj[childrenKey],
                            valueKey,
                            childrenKey,
                            values,
                            extraFieldsArray,
                            extraValues
                        },
                        i + 1
                    );
                }
            }
        },

        /**
         * 根据选中目标的值查询options数组中该值所在数据对象并返回
         * @param {Array} options 下拉选项数组
         * @param {String} valueKey option显示值的键，默认为value
         * @param {String} target 选中目标的值
         */
        queryOptionObjByValueKey(options, valueKey, target) {
            return options && options.find(option => option[valueKey] === target);
        },

        /**
         * 依赖字段值匹配时隐藏
         * @param {Object} materialConfig 元组件配置
         */
        dependOnChange(materialConfig) {
            const { depend } = materialConfig;
            const { name, value, visibleSwitch } = depend || {};
            if (!depend || !name || value === undefined || value === null || !visibleSwitch) return false;
            // 默认依赖字段符合预期
            let visibleFlag = true;
            // 根据预期值判断是否有不符合预期的情况
            visibleFlag = allKeysValueExpected({
                value,
                name,
                formParamisArray: this.formParamisArray,
                formParams: this.formParams
            });
            // 控制数据的rules，隐藏的标签都不需要校验数据 v0.13.12
            // if (materialConfig.rules) {
            //     if (visibleSwitch) {
            //         if (visibleFlag || materialConfig.visible === false) {
            //             this.$set(materialConfig, 'required', false);
            //             materialConfig.rules.map(item => {
            //                 this.$set(item, 'required', false);
            //                 return '';
            //             });
            //         } else {
            //             this.$set(materialConfig, 'required', true);
            //             materialConfig.rules.map(item => {
            //                 this.$set(item, 'required', true);
            //                 return '';
            //             });
            //         }
            //     }
            // }
            return visibleFlag;
        },

        /**
         * 根据name找到对应的元组件，判断表单值是否为数组类型
         * @param {String} name 匹配元组件的依赖值
         */
        formParamisArray(name) {
            return this.typeArrayList.includes(nameMatchType(name, this.formConfig));
        },

        /**
         * 针对list组件查询条件部分的显示隐藏
         */
        handleSearchFormVisible(materialConfig) {
            const { noFold, visible } = materialConfig;
            let visibleVal;
            if (typeof visible === 'function') {
                visibleVal = visible.call(materialConfig, this);
            } else if (typeof visible === 'boolean') {
                visibleVal = visible;
            }
            if (hasField(materialConfig, 'noFold')) {
                if (noFold === true && hasField(materialConfig, 'visible')) {
                    return visibleVal;
                }
                return noFold;
            }
            if (hasField(materialConfig, 'visible')) {
                return visibleVal;
            }
            return true;
        },
        handlerEnter() {
            this.$emit('handlerEnter');
        }
    }
};
</script>
