<template>
    <!-- 表单 -->
    <div class="form-view" :class="'applicable-' + applicable.toLowerCase()">
        <slot></slot>
        <div class="main">
            <el-link
                class="clear"
                type="danger"
                icon="el-icon-delete"
                @click="clear"
                v-if="list.length && list.every(item => !item.fixed)"
            >清空</el-link>
            <div class="box" ref="box">
                <draggable
                    class="view"
                    ghost-class="item-draging"
                    draggable=".drag"
                    :list="list"
                    :animation="300"
                    group="form"
                    @update="update"
                    @add="changeBothIndex($event.newIndex, -1, true)"
                    @start="isDraging = true"
                    @end="isDraging = false"
                >
                    <component
                        class="item"
                        :class="{ active: listIndex === index && listSubIndex === -1, subform: item.list, drag: !item.stick }"
                        v-for="(item, index) in list"
                        :key="index"
                        @click.native="itemClick(index)"

                        :is="applicable + 'Type'"
                        type="out"
                        :item="item"
                        :index="index"
                        @copy="copy"
                        @del="del"
                    >
                        <!-- 子表单 -->
                        <draggable
                            v-if="item.type === 'subform'"
                            class="draggable"
                            :class="{ 'min-h': item.list && !item.list.length }"
                            :list="item.list"
                            :animation="300"
                            :group="'form' + (isDraging || isSubDraging ? index : '')"
                            filter=".tips"
                            @update="update($event, true, index)"
                            @add="changeBothIndex(index, $event.newIndex, true)"
                            @start="isSubDraging = true"
                            @end="isSubDraging = false"
                        >
                            <component
                                class="item"
                                :class="{ active: listIndex === index && listSubIndex === subIndex }"
                                v-for="(subItem, subIndex) in item.list"
                                :key="subIndex"
                                @click.native.stop="itemClick(index, true, subIndex)"

                                :is="applicable + 'Type'"
                                type="in"
                                :item="subItem"
                                :index="index"
                                :sub-index="subIndex"
                                @copy="copy"
                                @del="del"
                            ></component>
                            <!-- 提示文字需放在 draggable 内，避免挡住拖拽 -->
                            <div class="tips" v-if="item.list && !item.list.length">
                                <i class="iconfont">&#xe64d;</i> 从左侧拖拽来添加控件
                            </div>
                        </draggable>
                    </component>
                </draggable>
            </div>
        </div>
    </div>
</template>

<script>
import { v1 as uuidv1 } from 'uuid'
import draggable from 'vuedraggable'
// 异步会导致第一次添加时无法拖拽添加到指定位置，所以使用同步
import FormType from './formView/FormType'
import QuestionType from './formView/QuestionType'
export default {
    name: 'FormView',
    components: { draggable, FormType, QuestionType },
    props: {
        applicable: { type: String, default: 'Form' },
        list: { type: Array, default: () => [] },
        listItem: { type: Object, default: () => ({}) },
        listIndex: { type: Number, default: -1 },
        listSubIndex: { type: Number, default: -1 }
    },
    data () {
        return {
            isDraging: false, // 控件是否在拖动
            isSubDraging: false // 子表单控件是否在拖动
        }
    },
    watch: {
        // 如果是问卷类型添加控件序号（排除说明文字）
        list: {
            handler (list) {
                if (this.applicable === 'Question') {
                    let index = 0
                    list.forEach(item => {
                        item.nth = item.type === 'info' ? '' : `${++index}、`
                    })
                }
            },
            immediate: true
        }
    },
    methods: {
        // 改变 listIndex
        changeIndex (index) {
            this.$emit('update:listIndex', index)
        },
        // 改变 listSubIndex
        changeSubIndex (index) {
            this.$emit('update:listSubIndex', index)
        },
        // 改变 listIndex 和 listSubIndex
        changeBothIndex (index, subIndex, isUpdate) {
            const oldIndex = this.listIndex
            const oldSubIndex = this.listSubIndex
            this.changeIndex(index)
            this.changeSubIndex(subIndex)
            // 如果新拖拽添加的控件或复制的控件，恰好处于当前选中控件的上一个位置时，index 没变，需要手动触发
            if (isUpdate && oldIndex === index && oldSubIndex === subIndex) this.$emit('update')
        },
        // 改变顺序时同步 index
        update (e, isSub, index) {
            if (!isSub) {
                // 移动当前控件
                if (this.listIndex === e.oldIndex) this.changeIndex(e.newIndex)
                // 如果其他控件从上往下越过了当前控件
                if (this.listIndex > e.oldIndex && this.listIndex <= e.newIndex) this.changeIndex(this.listIndex - 1)
                // 如果其他控件从下往上越过了当前控件
                if (this.listIndex < e.oldIndex && this.listIndex >= e.newIndex) this.changeIndex(this.listIndex + 1)
            } else if (this.listIndex === index) {
                // 移动当前子控件
                if (this.listSubIndex === e.oldIndex) this.changeSubIndex(e.newIndex)
                // 如果其他控件从上往下越过了当前控件
                if (this.listSubIndex > e.oldIndex && this.listSubIndex <= e.newIndex) this.changeSubIndex(this.listSubIndex - 1)
                // 如果其他控件从下往上越过了当前控件
                if (this.listSubIndex < e.oldIndex && this.listSubIndex >= e.newIndex) this.changeSubIndex(this.listSubIndex + 1)
            }
        },
        // 点击控件时同步 index
        itemClick (index, isSub, subIndex) {
            if (!isSub) {
                const i = this.listIndex === index && this.listSubIndex === -1 ? -1 : index
                this.changeBothIndex(i, -1)
            } else {
                const i = this.listIndex === index && this.listSubIndex === subIndex ? -1 : index
                const si = this.listIndex === index && this.listSubIndex === subIndex ? -1 : subIndex
                this.changeBothIndex(i, si)
            }
        },
        // 从左侧控件点击添加
        clickAdd (item) {
            // 非子表单聚焦或者添加的对象是个子表单在列表的最后添加，否则在该子表单内部的最后添加
            if (!(this.listIndex > -1 && this.list[this.listIndex].type === 'subform') || item.type === 'subform') {
                this.changeBothIndex(this.list.length, -1)
                this.list.push(item)
                this.$nextTick(() => {
                    this.$refs.box.scrollTop = this.$refs.box.scrollHeight
                })
            } else {
                this.changeSubIndex(this.list[this.listIndex].list.length)
                this.list[this.listIndex].list.push(item)
            }
        },
        // 复制
        copy (item, index, subIndex) {
            const obj = JSON.parse(JSON.stringify(item))
            obj.uuid = uuidv1()
            if (obj.type === 'subform') {
                for (let n of obj.list) {
                    n.uuid = uuidv1()
                    if (n.fixed) delete n.fixed
                }
            }
            if (obj.fixed) delete obj.fixed
            if (subIndex === -1) {
                this.list.splice(index + 1, 0, obj)
                this.changeBothIndex(index + 1, -1, true)
            } else {
                this.list[index].list.splice(subIndex + 1, 0, obj)
                this.changeBothIndex(index, subIndex + 1, true)
            }
        },
        // 删除
        del (item, index, subIndex) {
            if (subIndex === -1) {
                this.list.splice(index, 1)
                if (this.listIndex >= index) {
                    this.changeIndex(this.listIndex === index ? -1 : this.listIndex - 1)
                    if (this.listIndex === index) this.changeSubIndex(-1)
                }
            } else {
                this.list[index].list.splice(subIndex, 1)
                if (this.listSubIndex >= subIndex) {
                    this.changeSubIndex(this.listSubIndex === subIndex ? -1 : this.listSubIndex - 1)
                    if (this.listIndex === index && this.listSubIndex === subIndex) this.changeIndex(-1)
                }
            }
            // 计算公式需要校验其他控件，当前控件是计算公式并删除其他控件时需更新 FormEdit
            // 当删除计算公式本身时不用，所以使用 $nextTick（changeIndex 是异步的）
            this.$nextTick(() => {
                if (this.listItem.type === 'calculate') this.$emit('forceUpdate')
            })
        },
        // 清空
        clear () {
            this.$confirm('确定清空吗？', '提示', {
                type: 'warning'
            }).then(() => {
                this.list.splice(0, this.list.length)
                this.changeBothIndex(-1, -1)
            }).catch(() => {})
        }
    }
}
</script>

<style lang="less" scoped>
@import "~styles/varibles.less";
@import "./FormView/applicable.less";
// /deep/ li 是控件拖拽过来时的占位元素
// 外部容器
.main {
    padding-top: 20px;
    position: relative;
    font-size: 14px;
    .clear {
        position: absolute;
        top: 10px;
        right: 25px;
        font-size: 16px;
    }
    .box {
        height: 667px;
        overflow-y: auto;
        .view {
            min-height: 100%;
        }
        /deep/ li {
            position: relative;
            padding: 0 15px;
            list-style-type: none;
            background-color: #fff;
            text-align: left;
            i {
                margin-right: 10px;
                vertical-align: -2px;
            }
        }
    }
}
// 每个控件
.item {
    position: relative;
    &:hover {
        cursor: move;
        outline: 1px dashed @textBuleColor;
        z-index: 2;
        /deep/ .handle.out {
            display: flex;
        }
    }
    &:not(.drag):hover {
        cursor: default;
    }
    /deep/ .item:hover .handle.in {
        display: flex;
    }
    &.active {
        outline: 1px solid @textBuleColor;
    }
}
// 子表单控件
.subform {
    position: relative;
    .tips {
        position: absolute;
        top: 50px;
        left: 0;
        width: 100%;
        line-height: 1;
        text-align: center;
        cursor: default;
        color: #909399;
        i {
            vertical-align: -2px;
        }
    }
    /deep/ li {
        margin-top: 0 !important;
        border-top: 1px solid #E4E7ED;
    }
}
</style>
