<!-- 通用表单组件 -->
<template>
    <el-form
        class="no-scrollbar"
        :disabled="disabled"
        label-position="right"
        :label-width="labelWidth.replace(/[^0-9]/g, '') + 'px'"
        :rules="rules"
        :model="data"
        ref="form"
        status-icon
    >
        <div class="row">
            <div class="col" v-for="(item, index) in cols" :key="index" :style="'width:' + width">
                <template v-for="(row, index) in item">
                    <el-form-item
                        v-if="row.offShow ? false : true"
                        :key="index"
                        :label="row.label"
                        :prop="row.prop || row.slot"
                        :class="{ 'show-required-icon': row.showRequired }"
                        :error="errors[row.prop || row.slot]"
                    >
                        <!-- 过滤器 -->
                        <p v-if="row.filter">{{ ft[row.filter](data[row.prop], row.filterParams) }}</p>
                        <!-- 过滤方法 -->
                        <p v-else-if="row.format">{{ row.format(data[row.prop], data) }}</p>
                        <!-- 绑定事件 -->
                        <a v-else-if="row.click" href="javascript:;" @click="row.click"
                            ><span>{{ data[row.prop] }}</span></a
                        >
                        <!-- 日期控件 -->
                        <el-date-picker
                            v-else-if="row.date"
                            v-model="data[row.prop]"
                            :value-format="row.dateFormat || 'yyyy-MM-dd'"
                            type="date"
                            :editable="row.editable || false"
                            placeholder="选择日期"
                            :class="row.widt ? 'width100':''"
                            @change="(obj) => (row.change ? row.change(obj) : {})"
                        ></el-date-picker>
                        <!-- input输入框 -->
                        <el-input
                            v-else-if="row.input"
                            clearable
                            v-trim
                            :disabled="row.disabled"
                            v-model.trim="data[row.prop]"
                            :placeholder="row.placeholder || '请输入' + row.label.replace('：', '').replace(':', '')"
                            :maxlength="row.maxlength"
                        ></el-input>
                        <!-- textarea输入框 -->
                        <el-input
                            v-else-if="row.textarea"
                            v-trim
                            v-model.trim="data[row.prop]"
                            type="textarea"
                            resize="none"
                            :rows="row.rows || 3"
                            :placeholder="'请输入' + row.label.replace('：', '').replace(':', '')"
                            :maxlength="row.maxlength"
                            :show-word-limit="row.maxlength"
                        ></el-input>
                        <!-- 插槽 -->
                        <slot v-else-if="row.slot" :name="row.slot"></slot>
                        <!-- zz-select -->
                        <zz-select
                            v-else-if="row.options"
                            :disabled="row.disabled"
                            v-model="data[row.prop]"
                            :options="row.options"
                            :placeholder="'请选择' + row.label.replace('：', '').replace(':', '')"
                            @change="(val) => row.change && row.change(val)"
                        ></zz-select>
                        <!-- zz-cache -->
                        <zz-cache
                            v-else-if="row.cache"
                            :getter="row.cache"
                            v-model="data[row.prop]"
                            @change="(val) => row.change && row.change(val)"
                            :labelValue="row.labelValue"
                        ></zz-cache>
                        <!-- 默认输出绑定的值 -->
                        <p v-else class="ellipsis" v-tip :data-txt="data[row.prop]">{{ data[row.prop] || '-' }}</p>
                    </el-form-item>
                </template>
            </div>
        </div>
        <!-- 表单按钮插槽 -->
        <div v-if="$slots.btns">
            <el-form-item>
                <slot name="btns"></slot>
            </el-form-item>
        </div>
        <slot name="row" class="slot-row"></slot>
    </el-form>
</template>
<script>
export default {
    name: 'zz-form',
    props: {
        /*
		字段设置:二维数组，包括label名字设置，字段绑定设置，第二维有多少个集合就有多少列
		[
			[
				{
					lable: 'label名，必须'，
					prop: '绑定字段,必须'，
					filter: 'vue过滤器名,',
					filterParams: '过滤的参数',
					format: '过滤方法，'，
					click: '绑定的click事件'，
					date: '日期输入控件'，
					dateFormat: '日期控件的返回值格式化字符串，默认为"yyyy-MM-dd"'
					change: 'date改变时触发的事件'
					input: 'input输入框',
					textarea: '内容输入框',
					rows: '内容输入框的行数，默认4行'，
					slot: '插槽名'，
				}
			]
			.
			.
			.
		]
		*/
        cols: {
            type: Array,
            default() {
                return [];
            }
        },
        // 绑定数据
        data: {
            type: Object,
            default() {
                return {};
            }
        },
        // 表单校验
        rules: {
            type: Object,
            default() {
                return {};
            }
        },
        // 表单标签宽度
        labelWidth: {
            type: String,
            default() {
                return '80px';
            }
        },
        // 错误的项目字段消息对象{prop: '错误消息'}
        errors: {
            type: Object,
            default() {
                return {};
            }
        },
        disabled: {
            type: Boolean,
            default() {
                return false;
            }
        }
    },
    data() {
        let self = this;
        return {
            ft: self.$root.$options.filters
        };
    },
    methods: {
        validate(resolve, reject) {
            this.$parent.errors = {};
            this.$refs.form.validate((valid) => {
                if (valid) {
                    resolve && resolve();
                } else {
                    this.$nextTick(() => {
                        const isError = this.$el.querySelectorAll('.is-error');
                        if (isError && isError[0]) {
                            isError[0].querySelector('input').focus();
                        }
                    });
                    reject && reject();
                }
            });
        },
        resetFields() {
            this.$refs.form.resetFields();
        },
        clearValidate() {
            this.$refs.form.clearValidate();
        }
    },
    computed: {
        width() {
            return 100 / this.cols.length + '%';
        }
    },
    watch: {
        errors(n) {
            const len = Object.keys(n).length;
            if (len) {
                this.$nextTick(() => {
                    const isError = this.$el.querySelectorAll('.is-error');
                    if (isError && isError[0]) {
                        isError[0].querySelector('input').focus();
                    }
                });
            }
        }
    }
};
</script>
<style lang='scss' scoped>
.row {
    &:after {
        content: '';
        width: 0;
        height: 0;
        visibility: hidden;
        clear: both;
        display: block;
        .col {
            float: left;
        }
    }
}
.slot-row {
    margin-top: -22px;
}
.show-required-icon /deep/ .el-form-item__label {
    &:before {
        content: '*';
        color: #f56c6c;
        margin-right: 4px;
    }
}
</style>
