<template>
    <group gutter="0" :class="applicable.toLowerCase()">
        <component
            class="form-item"
            :class="{ sub: subType(item.type), first: !index, 'subform-item': item.type === 'subform' }"
            v-for="(item, index) in list"
            :key="index"
            :info.prop="info(item.title, form[index])"
            v-show="!form[index].hide"

            :is="'form-' + item.type"
            :form="form"
            :subform="form"
            :list-item="item"
            :form-item="form[index]"
            ref="component"
        >
            <template v-if="item.type !== 'subform'">
                <i :class="{ required: item.verify && item.verify.required }"></i>
                <span class="item-title" @click.stop.prevent>{{ item.nth }}{{ item.title }}</span>
                <i
                    class="info weui-icon-info"
                    :data-message="item.info"
                    @click.stop.prevent="toast(item.info)"
                    v-if="item.info"
                ></i>
                <i class="tips" data-field="value"></i>
            </template>
            <!-- 子表单 -->
            <template v-else>
                <group
                    gutter="0"
                    class="subform"
                    v-for="(valueItem, valueIndex) in form[index].value"
                    :key="valueIndex"
                    :data-title="(item.nth || '') + item.title"
                >
                    <div class="subform-title">
                        <span>{{ item.title }} {{ valueIndex + 1 }}</span>
                        <span class="del" @click="form[index].value.splice(valueIndex, 1)" v-if="valueIndex">删除</span>
                    </div>
                    <component
                        class="form-item"
                        :class="{ sub: subType(subItem.type), first: !subIndex }"
                        v-for="(subItem, subIndex) in item.list"
                        :key="subIndex"
                        :info.prop="info(subItem.title, valueItem[subIndex], item.title)"
                        v-show="!valueItem[subIndex].hide"

                        :is="'form-' + subItem.type"
                        :form="form"
                        :list-item="subItem"
                        :form-item="valueItem[subIndex]"
                        :subform="valueItem"
                        :subform-uuid="item.uuid"
                        :value-index="valueIndex"
                        ref="component"
                    >
                        <template>
                            <i :class="{ required: subItem.verify && subItem.verify.required }"></i>
                            <span class="item-title" @click.stop.prevent>{{ subItem.title }}</span>
                            <i
                                class="info weui-icon-info"
                                :data-message="item.info"
                                @click.stop.prevent="toast(subItem.info)"
                                v-if="subItem.info"
                            ></i>
                            <i class="tips" data-field="value"></i>
                        </template>
                    </component>
                </group>
            </template>
        </component>
        <div class="footer" v-if="!hideBtn">
            <slot name="before"></slot>
            <slot>
                <x-button type="primary" @click.native="submit">{{ btnText }}</x-button>
            </slot>
            <slot name="after"></slot>
        </div>
    </group>
</template>

<script>
import common from '@/common/formRender/mixin/common.js'
import components from './components.js'
import { Group, XButton } from 'vux'
import { mapMutations } from 'vuex'
export default {
    name: 'FormRender',
    mixins: [common],
    components: { Group, XButton, ...components },
    props: {
        formId: { type: String, default: '' }, // 表单 id
        applicable: { type: String, default: 'Form' }, // 控件类型，暂定 Form 和 Question
        btnText: { type: String, default: '提交' }, // 提交按钮文字
        hideBtn: { type: Boolean, default: false }, // 是否隐藏提交按钮
        watch: { type: Array, default: () => [] }, // 监听指定对象的值
        scroll: { type: Object, default: () => ({}) }, // 滚动对象
        noAuth: { type: Boolean, default: false } // 当前用户是否无身份
    },
    data () {
        return {
            list: [], // 表单列表
            form: {}, // 表单数据
            rule: {}, // 校验规则
            message: {}, // 提示文字
            dataList: [], // 转换成数组的表单数据
            ready: false, // form 是否准备好
            watchList: [] // 监听回调，避免重复监听
        }
    },
    provide () {
        return {
            applicable: this.applicable,
            formId: this.formId
        }
    },
    watch: {
        formId: {
            handler (formId) {
                if (this.formId) this.getList()
            },
            immediate: true
        },
        // 如果是问卷类型添加控件序号（排除说明文字）
        list: {
            handler (list) {
                if (this.applicable === 'Question') {
                    let index = 0
                    list.forEach(item => {
                        item.nth = item.type === 'info' ? '' : `${++index}、`
                    })
                }
            },
            immediate: true
        },
        watch () {
            // 如果 form 准备好了可以监听，否则 form 准备好会监听
            if (this.ready) this.watchValue()
        }
    },
    created () {
        // if (this.scroll.options) this.scroll.options.preventDefaultException.className = /(^|\s)matrix(\s|$)/
        this.saveScroll(this.scroll)
    },
    methods: {
        ...mapMutations(['saveScroll']),
        // 获取表单列表
        getList () {
            this.$api.commonApi.formInfoGet({
                b_id: this.formId
            }).then(res => {
                if (res.data.Status) {
                    this.list = JSON.parse(res.data.Data.content)
                    this.init()
                }
            })
        },
        // 初始化表单
        init () {
            const dataForm = {}
            const objectType = type => /dateRange|address/.test(type)
            const arrayType = type => /checkbox|img|file|contacts|subform/.test(type)
            // 表单数据对象
            const addForm = (list, form) => {
                list.forEach((item, index) => {
                    form[index] = {
                        uuid: item.uuid,
                        type: item.type,
                        value: arrayType(item.type) ? [] : objectType(item.type) ? {} : (item.value || '')
                    }
                    const { value } = form[index]
                    if (item.type === 'dateRange') {
                        value.start = ''
                        value.end = ''
                        if (item.date.time) {
                            value.result = ''
                            value.type = item.date.unit
                        }
                    }
                    if (item.type === 'address') {
                        value.region = item.value
                        if (item.address.type === 1) value.detail = item.value2 || ''
                    }
                    if (item.type === 'contacts') {
                        if (item.verify.value.length) value.push(...item.verify.value)
                    }
                    if (item.type === 'subform') {
                        value.push({})
                        addForm(item.list, value[0])
                    }
                })
            }
            // 单选关联
            const addRadio = (list, form) => {
                list.forEach((item, index) => {
                    if (item.type === 'radio') this.radioHide(form, item.option.list, item.option.checked) // mixin
                    if (item.type === 'subform') addRadio(item.list, form[index].value[0])
                })
            }
            addForm(this.list, dataForm)
            addRadio(this.list, dataForm)
            this.form = dataForm
            this.ready = true
            this.watchValue()
            this.$emit('init', this.list, this.form)
        },
        // 内部表单（label 内部显示）
        subType (type) {
            return /input|dateRange|address/.test(type)
        },
        // 校验表单
        verify () {
            return new Promise((resolve, reject) => {
                const list = !this.$refs.component ? [] : this.$refs.component
                    .filter(item => item.formItem && !item.formItem.hide && item.verify)
                    .map(item => item.verify())
                Promise.all(list)
                    .then(resolve)
                    .catch(({ message, el }) => {
                        this.toast(message)
                        if (this.scroll.scrollToElement) {
                            const offsetY = this.applicable === 'Question' ? -5 : 0
                            this.scroll.scrollToElement(el, 200, 0, offsetY)
                        }
                    })
            })
        },
        // form 转数组（排除隐藏的和说明文字）
        formatForm () {
            const dataForm = JSON.parse(JSON.stringify(this.form))
            const dataList = []
            const addList = (list, form, title) => {
                for (let i in form) {
                    const item = form[i]
                    if (!item.hide && item.type !== 'info') {
                        if (item.hide === false) delete item.hide
                        if (item.type === 'subform') {
                            const value = []
                            item.value.forEach((subform, subIndex) => {
                                value.push([])
                                addList(value[subIndex], subform)
                            })
                            item.value = value
                        }
                        list.push(item)
                    }
                }
            }
            addList(dataList, dataForm)
            this.dataList = dataList
            return JSON.stringify(dataList)
        },
        // 提交
        submit () {
            this.verify().then(() => {
                let api = 'formRecordCreate'
                const params = {
                    form_id: this.formId,
                    value: this.formatForm()
                }
                if (this.noAuth) {
                    api += 'NoAuth'
                    params.company_id = this.$store.state.companyId || ''
                    params.create_by = this.$store.state.nickName || ''
                    params.create_user_id = this.$store.state.openId || ''
                }
                this.$api.commonApi[api](params).then(res => {
                    if (res.data.Status) {
                        const $item = [...this.$el.querySelectorAll('.form-item')]
                        const infoList = $item.filter(item => item.info).map(item => JSON.parse(item.info))
                        this.$emit('submit', res.data.Data, infoList)
                    }
                })
            })
        },
        // 监听指定的值
        watchValue () {
            if (this.watch.length) {
                // 取消之前的监听
                if (this.watchList.length) {
                    for (let item of this.watchList) item.unwatch()
                    this.watchList = []
                }
                // 监听指定的值
                for (let index in this.form) {
                    const item = this.form[index]
                    if (this.watch.indexOf(item.uuid) > -1) {
                        const unwatch = this.$watch(() => item.value, this.emitWatch, { deep: true })
                        this.watchList.push({ index, unwatch })
                    }
                }
                // 第一次触发一次（控件有默认值的情况）
                this.emitWatch()
            }
        },
        // 触发回调
        emitWatch () {
            const valueList = this.watchList.map(item => this.form[item.index])
            this.$emit('watch', valueList)
        }
    }
}
</script>

<style lang="less" scoped>
@import "./question.less";
// 公共样式
/deep/ input.weui-input {
    color: #333;
    text-align: right;
}
/deep/ i {
    font-style: normal;
}
// 去除 vux 自带的错误提示
/deep/ .weui-icon-warn {
    display: none !important;
}
// label
/deep/ .weui-cell__hd {
    color: #333;
    padding-right: 15px;
}
// .empty-label 表示 label 的 hd 改 bd
/deep/ .empty-label {
    &  > .weui-cell__hd {
        padding-right: 0;
    }
    & > .vux-cell-bd {
        padding-right: 15px;
        white-space: nowrap;
    }
}
// 内部表单的 group 上边框靠右 15px 对齐，去掉下边框
/deep/ .sub {
    .weui-cells::before {
        left: 15px;
    }
    &.first .weui-cells::before, .weui-cells::after {
        display: none;
    }
}
// 必填 *
/deep/ .required::before {
    content: "*";
    color: #f56c6c;
    position: absolute;
    left: 6px;
}
// 校验提示
/deep/ .verify {
    color: #909399;
    font-size: 12px;
    margin-left: 5px;
    &::before {
        content: "(";
    }
    &::after {
        content: ")";
    }
}
// 提示文字的图标
/deep/ .info {
    margin-left: -3px;
    font-size: 16px;
    vertical-align: -2px;
}
// 错误提示图标
/deep/ .tips {
    position: absolute;
    left: 15px;
    bottom: 3px;
    font-size: 12px;
    color: #F56C6C;
    &:empty {
        display: none;
    }
}
// textarea
/deep/ .vux-x-textarea {
    display: block;
}
// value 加黑
/deep/ .value, /deep/ .vux-popup-picker-value, /deep/ .vux-cell-value {
    color: #333;
}
// 子表单项
/deep/ .subform-item + ::before{
    left: 0;
}
// 子表单
/deep/ .subform > .weui-cells::before {
    display: none;
}
// 子表单标题
.subform-title {
    height: 32px;
    font-size: 14px;
    padding: 0 15px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    background-color: #EBEEF5;
    color: #333;
    .del {
        color: #F56C6C;
    }
    & + ::before {
        left: 0 !important;
    }
}
.footer {
    padding: 15px;
    .weui-btn {
        height: 40px;
        line-height: 28px;
    }
}
</style>
