/*
 * @Author: housy
 * @Email: housy@guahao.com
 * @Date: 2019-07-04 20:33:23
 * @Last Modified by: housy
 * @Last Modified time: 2020-03-26 10:54:30
 * @Description: 对比页面组件
 */

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

            <!-- 全局tips顶部自定义插槽 -->
            <slot name="above-tips" />
            <bk-slot :config="contrastConfig"
                     slot-name="above-tips" />
                     
            <!-- 全局提示 -->
            <template v-if="contrastConfig.tips">
                <bk-title :label="contrastConfig.tips" />
            </template>

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

            <!-- 对比主体 -->
            <div v-if="Array.isArray(contrastConfig.data)">
                <template v-for="(dataConfig, i) in contrastConfig.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-extend="btn.extend"
                                       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" />

                    <!-- 对比元组件 -->
                    <bk-contrast-material :ref="`contrast${i}`"
                                          :contrastConfig="contrastConfig"
                                          :configKey="configKey"
                                          :material-config="dataConfig"
                                          :readonly="contrastConfig.readonly"
                                          :contrastStage="contrastConfig.stage"
                                          :results="(!isEmptyObj(dataConfig.results) && dataConfig.results)
                                              || contrastConfig.results"
                                          @handleNoPass="handleNoPass"
                                          @handlePass="handlePass"
                                          @formParamsChange="formParamsChange" />
                    
                    <!-- 表单form底部自定义插槽 -->
                    <bk-slot :config="dataConfig"
                             slot-name="under-form" />
                </template>
            </div>

            <!-- 原因顶部自定义插槽 -->
            <slot name="above-reason" />
            <bk-slot :config="contrastConfig"
                     slot-name="above-reason" />

            <!-- 显示原因 -->
            <div v-if="contrastConfig.reasonCode
                     && (contrastConfig.stage === 'firstAudit' || contrastConfig.stage === 'autoAudit'||contrastConfig.stage === 'audit')"
                 class="reason-box">
                <div class="reason-title-wrapper">
                    <span class="reason-title">审核结果：
                        <template v-if="auditPass === true">
                            <span class="audit-pass">审核通过</span>
                        </template>
                        <template v-else-if="auditPass === false">
                            <span class="audit-no-pass">审核不通过</span>
                        </template>
                    </span>
                </div>
                <div class="reason-content">
                    {{ reasonText }}
                </div>
            </div>

            <!-- 全局button顶部自定义插槽 -->
            <slot name="above-button" />
            <bk-slot :config="contrastConfig"
                     slot-name="above-button" />
        
            <!-- 底部按钮区域 -->
            <el-row v-if="contrastConfig.button
                        && Array.isArray(contrastConfig.button.data)
                        && contrastConfig.button.visible !== false"
                    class="contrast-footer">
                <el-button v-for="item in contrastConfig.button.data"
                           v-if="item.visible !== false"
                           :type="item.type ? item.type : 'primary'"
                           :key="item.name"
                           @click="() => handleBottomBtnClick(item)"
                           v-bind="item.extend"
                           :loading="item.loadingSwitch ? submitting : false">
                    {{ item.label }}
                </el-button>
            </el-row>

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

            <!-- 全局底部自定义插槽 -->
            <slot name="under-page" />
            <bk-slot :config="contrastConfig"
                     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, hasField, deepCopy
} from 'utils/util';

export default {
    name: 'BkContrast',
    props: {
        contrastConfig: {
            required: true,
            type: Object
        },
        dialogConfig: {
            type: Object,
            default: () => ({})
        }
    },
    data() {
        // formConfig格式化成contrast时，config的键名，以防和formConfig的name冲突
        const { configKey = 'config' } = this.contrastConfig;
        return {
            isEmptyObj,
            hasField,
            formParams: {}, // 表单值
            submitFormParams: {}, // 提交前格式化好的表单值
            dialogVisible: {}, // 所有弹窗显示状态集合
            submitting: false, //  防重复提交标志
            configKey,
            reasonText: '', // 不通过的原因
            noPassList: [], // 不通过的数据集合
            passList: [], // 通过的数据集合
            auditPass: '', // 操作结果，''：没有不通过也没有全部通过；true：全部通过；false：至少有一个不通过
            handlerSumNum: 0, // 整个页面所有操作栏的个数
            tableTitle: [ // 默认的table表头信息
                {
                    name: 'label',
                    label: ''
                },
                {
                    name: 'oldData',
                    label: '修改前信息'
                },
                {
                    name: 'newData',
                    label: '本次信息'
                },
                {
                    name: 'operation',
                    label: '操作',
                    formConfig: {
                        name: 'radioDemo',
                        type: 'radio',
                        options: [
                            {
                                value: '1',
                                label: ''
                            },
                            {
                                value: '0',
                                label: ''
                            }
                        ],
                        className: 'handleRadio',
                        rules: [{ required: true, message: '请审核' }],
                        grid: 1
                    }
                }
            ]
        };
    },
    computed: {
        // 操作已处理的个数
        handledNum() {
            return this.passList.length + this.noPassList.length;
        }
    },
    watch: {
        contrastConfig: {
            handler(val) {
                if (!val.formConfig || isEmptyObj(val.formConfig)) return;
                // 格式化配置
                this.formatConfig(val.formConfig);
            },
            deep: true
        },
        noPassList: {
            handler(val) {
                if (val.length > 0) {
                    const labelList = val.map(item => `【${item.label}审核不通过】`);
                    this.reasonText = `审核结果说明：${labelList.join('')}`;
                    this.auditPass = false;
                } else {
                    this.reasonText = '';
                    this.auditPass = this.handledNum !== this.handlerSumNum ? '' : true;
                }
            },
            deep: true
        },
        passList: {
            handler(val) {
                if (val.length === this.handlerSumNum) {
                    this.auditPass = true;
                }
            },
            deep: true
        },
        handlerSumNum(val) {
            if (this.passList.length === val) {
                this.auditPass = true;
            } else if (this.noPassList.length === 0) {
                this.auditPass = '';
            } else {
                this.auditPass = false;
            }
        }
    },
    created() {
        // 初始化dialogVisible

        if (this.dialogConfig && Array.isArray(this.dialogConfig.data)) {
            this.dialogConfig.data.forEach(item => {
                this.$set(this.dialogVisible, item.name, false);
            });
        }
        if (!this.contrastConfig.tabConfig) {
            this.$set(this.contrastConfig, 'tabConfig', {});
        }
        if (this.contrastConfig.formConfig) {
            this.formatConfig(this.contrastConfig.formConfig);
        }
    },
    updated() {
        // 子组件实例挂载后获取页面级所有的操作项个数
        if (this.handlerSumNum > 0) return;
        Object.keys(this.$refs).forEach(key => {
            Object.keys(this.$refs[key][0].$refs).forEach(name => {
                if (name.indexOf('operation-') < 0) return;
                this.handlerSumNum += 1;
            });
        });
    },
    methods: {
        /**
         * 将form表单组件的配置转化为contrast对比组件的配置
         * @param {Object} formConfigsF 页面级组件bk-form的配置
         */
        formatConfig(formConfigsF) {
            // 解构出对比组件的修改前信息列的值
            const { oldData, newData, titleConfig } = this.contrastConfig;
            let formConfigs = formConfigsF;

            if (typeof formConfigs === 'string') formConfigs = JSON.parse(formConfigsF);

            if (isEmptyObj(formConfigs)
                || !Array.isArray(formConfigs.data)
                || (!isEmptyObj(formConfigs) && isEmptyObj(newData))
            ) return;

            Object.keys(formConfigs).forEach(key => {
                if (key === 'data') {
                    this.contrastConfig.data = [];
                    const data = [];
                    formConfigs.data.forEach(formConfig => {
                        // 对比元组件配置
                        const contrastMaterialConfig = {};
                        if (formConfig.title) contrastMaterialConfig.title = formConfig.title;
                        if (hasField(formConfig, 'readonly')) contrastMaterialConfig.readonly = formConfig.readonly;
                        if (formConfig.stage) contrastMaterialConfig.stage = formConfig.stage;
                        contrastMaterialConfig.tableData = [];
                        if (Array.isArray(formConfig.data)) {
                            formConfig.data.forEach(config => {
                                // 每行数据对象
                                const row = {};
                                row.value = config.name;
                                row.label = config.label;
                                let extraKey = config.extraFields;
                                // 判断form字段是否有对应的额外字段,且值为字符串（回显时的文案）
                                if (typeof newData[extraKey] !== 'string') {
                                    extraKey = config.name;
                                    row[this.configKey] = deepCopy(config);
                                    row[this.configKey].readonly = true;
                                    delete row[this.configKey].label;
                                }
                                row.newData = newData[extraKey];
                                if (!isEmptyObj(oldData)) row.oldData = oldData[extraKey];
                                if (hasField(config, 'readonly')) row.readonly = config.readonly;
                                
                                contrastMaterialConfig.tableData.push(row);
                            });
                        }
                        contrastMaterialConfig.data = JSON.parse(JSON.stringify(this.tableTitle));
                        if (Array.isArray(titleConfig)) {
                            // 对比组件表头配置
                            const tableTitle = [];
                            this.tableTitle.forEach((item, i) => {
                                const title = titleConfig[i];
                                const that = JSON.parse(JSON.stringify(item));
                                if (typeof title === 'object') {
                                    Object.assign(that, title);
                                } else if (title) {
                                    that.label = title;
                                }
                                tableTitle.push(that);
                            });
                            contrastMaterialConfig.data = JSON.parse(JSON.stringify(tableTitle));
                        }
                        data.push(contrastMaterialConfig);
                    });
                    this.contrastConfig.data = data;
                } else {
                    this.$set(this.contrastConfig, key, formConfigs[key]);
                }
            });
        },

        /**
         * 切换tab标签页模拟锚点定位
         * @param {string} name 设置tab的name值
         */
        handleToggleTab(name) {
            const returnEle = document.querySelector(`#${name}`);
            if (returnEle) {
                returnEle.scrollIntoView(true);
            }
        },

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

        /**
         * 按钮点击事件
         * @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 被点击的按钮实例
         */
        handleSubmit(btn) {
            this.handleVerify(() => {
                if (btn.confirmText) {
                    // 用户确认后提交
                    this.$confirm(btn.confirmText).then(() => {
                        this.submitParams(btn);
                    });
                } else {
                    // 提交请求
                    this.submitParams(btn);
                }
            });
        },

        /**
         * 表单校验的函数
         * @param {Function} callback 校验通过后的回调函数
         */
        handleVerify(callback) {
            const { $refs } = this;
            let valid = true;
            Object.keys($refs).forEach(key => {
                $refs[key][0].handleVerify(val => {
                    if (!val) valid = false;
                });
            });
            if (valid && typeof callback === 'function') {
                callback(this);
                return true;
            }
            return false;
        },

        /**
         * 执行提交 数据
         * @param {Object} btn 被点击的按钮实例
         */
        submitParams(btn) {
            // 防重复提交
            if (!this.submitting) {
                const { http } = btn;
                const { onBefore, onSuccess, onFaild } = http || {};

                // 格式化表单参数
                let formatedFormParams = {};
                Object.keys(this.$refs).forEach(key => {
                    Object.assign(formatedFormParams, this.$refs[key][0].submitFormParams);
                });
                // 审核结果
                if (this.contrastConfig.reasonCode) {
                    formatedFormParams[this.contrastConfig.reasonCode] = this.reasonText;
                }

                // 调用请求发送前函数钩子
                if (typeof onBefore === 'function') {
                    const result = onBefore(formatedFormParams, this);
                    if (result === false) return false;
                    if (typeof result === 'object') formatedFormParams = result;
                }
                if (!http) {
                    console.warn('button.http属性不能为空');
                    return false;
                }
                const { url, params, method } = http;
                if (!url) {
                    console.warn('button.http.url属性不能为空');
                    return false;
                }

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

        /**
         * 审核类型下，操作不通过时触发的事件
         * @param {Object} rowData 不通过的行数据
         */
        handleNoPass(rowData) {
            this.$emit('handleNoPass', rowData);
            // 处理盛放不通过数据的容器
            if (this.contrastConfig.reasonCode) {
                // 处理不通过数据
                const nopassIndex = this.noPassList.findIndex(item => item.value === rowData.value);
                if (nopassIndex < 0) {
                    this.noPassList.push(rowData);
                }
                // 处理通过数据
                const passIndex = this.passList.findIndex(item => item.value === rowData.value);
                if (passIndex > -1) {
                    this.passList.splice(passIndex, 1);
                }
            }
        },

        /**
         * 审核类型下，操作不通过时触发的事件
         * @param {Object} rowData 不通过的行数据
         */
        handlePass(rowData) {
            this.$emit('handlePass', rowData);
            // 处理盛放通过数据的容器
            if (this.contrastConfig.reasonCode) {
                // 处理通过数据
                const passIndex = this.passList.findIndex(item => item.value === rowData.value);
                if (passIndex < 0) {
                    this.passList.push(rowData);
                }
                // 处理不通过数据
                const noPassIndex = this.noPassList.findIndex(item => item.value === rowData.value);
                if (noPassIndex > -1) {
                    this.noPassList.splice(noPassIndex, 1);
                }
            }
        },

        /**
         * 表单操作列的值发生变化事件
         * @param {Object} formParams 表单数据集合
         * @param {Object} submitFormParams 提交前格式化的表单数据集合
         */
        formParamsChange({ formParams, submitFormParams }) {
            this.formParams = Object.assign({}, this.formParams, formParams);
            this.submitFormParams = Object.assign({}, this.submitFormParams, submitFormParams);
            this.$emit('formParamsChange', this);
        }
    }
};
</script>
