<template>
    <table class="webform" v-if="opType==='browser'">
        <col :key="'A' + ix1" :width="w" v-for="(w,ix1) in config.colWidths" />
        <tr
            :key="'B' + ix1"
            :style="trStyle2(ix1)"
            class="webform__row"
            v-for="(r, ix1) in config.rows"
        >
            <td
                :colspan="getColSpan(c)"
                :key="'C' + ix2"
                :rowspan="getRowSpan(c)"
                class="webform__cell"
                v-for="(c, ix2) in rowCells[ix1]"
            >
                <div class="webform__cell--label" v-if="c.type==='Label'">{{c.caption}}</div>
                <div class="webform__cell--readonly" v-else>{{data[c.model]}}</div>
            </td>
        </tr>
    </table>
    <Form v-else>
        <table class="webform">
            <col :key="'D' + ix1" :width="w" v-for="(w,ix1) in config.colWidths" />
            <tr
                :key="'E' + ix1"
                :style="trStyle(ix1)"
                class="webform__row"
                v-for="(r, ix1) in config.rows"
            >
                <td
                    :colspan="getColSpan(c)"
                    :key="'F' + ix2"
                    :rowspan="getRowSpan(c)"
                    class="webform__cell"
                    v-for="(c, ix2) in rowCells[ix1]"
                >
                    <component
                        :config="c"
                        :dsType="c.dsType"
                        :dsValue="c.dsValue"
                        :is="'F' + c.type"
                        :itemValueChange="c.itemValueChange"
                        :listenProp="c.filter"
                        :placeholder="c.placeholder"
                        :prop="c.model"
                        :required="c.required"
                        :noEdit="c.noEdit"
                    ></component>
                </td>
            </tr>
        </table>
    </Form>
</template>
<script>
import Validator from './validator'
import Data from '../../data/web-form'
import FInput from './item/input'
import FInputArea from './item/input-area'
import FLabel from './item/label'
import FNumberInput from './item/number-input'
import FSelect from './item/select'
import FDate from './item/date'
import FSelectTree from './item/select-tree'
import FFileSelector from './item/file-selector'
import require from './validator/funcs/require'

const FNS = {}

export default {
    name: 'SuperForm',
    componentName: 'SuperForm',
    data() {
        return {
            //字段信息
            fields: [],
            //每行Cell配置
            rowCells: {},
            //验证错误信息
            formError: {},
            /* 验证规则 */
            ruleMap: {},
            // 当前数据集
            data: {}
        }
    },
    props: {
        /* 配置信息 */
        config: {},
        /* 表单guid */
        guid: {
            type: String
        },
        /* 业务guid*/
        bizGuid: {
            type: [String, Number]
        },
        /** 操作类型：insert|update|copy|browser*/
        opType: {
            type: String
        }
    },
    components: {
        FDate,
        FInput,
        FInputArea,
        FLabel,
        FNumberInput,
        FSelect,
        FSelectTree,
        FFileSelector
    },
    watch: {
        config: {
            handler(newVal) {
                this.ruleMap = newVal.ruleMap
            },
            immediate: true
        },
        bizGuid: {
            handler(newVal) {
                if (this.bizGuid) {
                    // 如果是修改，则会传递bizGuid
                    this.$nextTick(() => {
                        Data.getFormData(this.guid, this.bizGuid).then(
                            formData => {
                                this.updateForm(formData)
                            }
                        )
                    })
                }
            },
            immediate: true
        }
    },
    computed: {
        /*获取表单值*/
        formValues() {
            return this.fields.reduce((data, { prop, item }) => {
                let values = item.getValue()
                if (typeof values === 'object') {
                    data = { ...data, ...values }
                } else {
                    data[prop] = item.getValue()
                }
                return data
            }, {})
        }
    },
    mounted() {},
    created() {
        this.$on('_.form.addItem', field => {
            this.fields = [...this.fields, field]
            /*赋初始值*/
            field.item.formValueChange(this.model)
        })

        /*Select发送*/
        this.$on('_.form.itemChange', ({ prop, value }) => {
            const listenProp = prop

            this.fields.forEach(({ prop, item }) => {
                if (item.listenProp == listenProp) {
                    const lfn = item.itemValueChange

                    lfn && lfn.call(item, listenProp, value, this.formValues)
                }
            })
        })

        this.setupRowCellsMap()
    },
    destroyed() {
        this.$off('_.form.addItem')
        this.$off('_.form.itemChange')
    },

    methods: {
        trStyle(index) {
            return {
                height: Math.max(this.config.rowHeights[index], 56) + 'px'
            }
        },

        trStyle2(index) {
            return {
                height: Math.max(this.config.rowHeights[index], 48) + 'px'
            }
        },

        getRowSpan(cell) {
            if (cell.rowSpan > 1) {
                return cell.rowSpan
            } else {
                return 1
            }
        },

        getColSpan(cell) {
            if (cell.colSpan > 1) {
                return cell.colSpan
            } else {
                return 1
            }
        },
        /*行所有单元格*/
        setupRowCellsMap() {
            let rowCells = {}
            for (let i = 0; i < this.config.rows; i++) {
                rowCells[i] = []
            }

            this.config.cells.forEach(function(value) {
                rowCells[value.row].push(value)
            })

            this.rowCells = rowCells
        },

        /**
         * 外部验证函数
         */
        externValidFunc(funcBody) {
            const fnName = this.$md5(funcBody)
            if (!FNS[fnName]) {
                FNS[fnName] = new Function('opType', 'self', funcBody)
            }

            return FNS[fnName]
        },

        save() {
            return new Promise((resolve, reject) => {
                this.validate(error => {
                    if (error && error.length > 0) {
                        //验证不通过
                        reject()
                    } else {
                        let values = this.formValues
                        if (this.bizGuid) {
                            // 如果是保存，写入guid
                            values['guid'] = this.bizGuid
                        }

                        if (this.config.validScript) {
                            let message = this.externValidFunc(
                                this.config.validScript
                            )(this.opType, values)

                            if (message) {
                                this.$Notice.warning({
                                    title: '警告',
                                    desc: message
                                })
                                
                                return reject()
                            }
                        }
                        Data.saveData(this.guid, values)
                            .then(guid => {
                                resolve(guid)
                            })
                            .catch(() => {
                                reject()
                            })
                    }
                })
            })
        },
        validate(callback) {
            Validator.validate(this.formValues, this.ruleMap).then(errors => {
                let formError = {}

                if (errors && errors.length) {
                    errors.forEach(({ message, field }) => {
                        formError[field] = message
                    })
                }

                this.formError = formError

                const errInfo = []
                this.fields.forEach(({ prop }) => {
                    if (formError[prop]) {
                        errInfo.push(formError[prop])
                    }
                })
                callback(errInfo)
            })
        },

        /*更新表单*/
        updateForm(model) {
            this.data = model
            this.fields.forEach(({ item }) => {
                item.formValueChange(model)
            })
        }
    }
}
</script>

<style lang="less">
.nx-form-cell {
    text-align: right;
}

.webform {
    &__cell--label {
        text-align: right;
        font-weight: bold;
        margin-right: 10px;
    }
    &__cell--readonly {
        display: inline-block;
        width: 95%;
        min-height: 32px;
        line-height: 32px;
        padding: 0px 7px;
        font-size: 12px;
        border: 1px solid #dcdee2;
        border-radius: 4px;
        color: #515a6e;
        background-color: #fff;
        background-image: none;
        position: relative;
    }
}
</style>
