<template>
    <div class="su-drag-template">
        <el-row v-drag-stop-propagation>
            <!-- 左侧拖拽模板，不可位置变化(sort: 位置变化时的事件) -->
            <el-col :span="5" class="drag-templates">
                <draggable
                    v-if="templates.length"
                    :list="templates"
                    :sort="false"
                    :group="{ name: 'contents', pull: repeat ? 'clone' : null, put: false }"
                    :clone="cloneDog"
                    @end="onEnd"
                >
                    <transition-group>
                        <div v-for="item in templates"
                             :key="item.type"
                             class="templateTypeItem"
                             :data-type="item.type"
                             :data-count="item.count || 0">
                            <span>{{ item.name }}</span>
                            <span>
								<i class="el-icon-rank"/>
							</span>
                        </div>
                    </transition-group>
                </draggable>
                <div v-if="templates.length == 0" style="text-align: center">暂无可用模板</div>
            </el-col>
            <!-- 右侧拖拽模板，可位置变化(sort: 位置变化时的事件) -->
            <el-col :span="18" class="drag-right">
                <!-- 插槽：模板显示区域头部 -->
                <slot name="tplTop"></slot>
                <!-- 模板显示区域内容 -->
                <draggable
                    :list="contents"
                    :sort="true"
                    group="contents"
                    class="drag-content"
                    v-if="contents.length===0"
                >
                    <div class="drag-empty">
                        <slot name="contentEmpty" v-if="$slots.contentEmpty"></slot>
                        <comp-empty v-else></comp-empty>
                    </div>
                </draggable>
                <draggable
                    :list="contents"
                    :sort="true"
                    group="contents"
                    filter=".ignore-elements"
                    class="drag-content"
                    @end="onContentEnd"
                    v-else
                >
                    <div v-for="(item, index) in contents"
                         :key="item.id"
                         :class="{'ignore-elements':item.fixTop||item.fixBottom}">
                        <div class="content-item">
                            <component
                                :is="item.component"
                                width="100%"
                                :ref="'content' + item.id"
                                :options="item.options"
                                v-on="item.listeners||{}"
                            />
                            <div class="right-button-wrap">
                                <el-button
                                    type="danger"
                                    icon="el-icon-delete"
                                    class="right-button"
                                    circle
                                    v-if="show.delete && item.show.delete"
                                    @click="delContent(index)"
                                    title="删除"
                                />
                                <el-button
                                    type="danger"
                                    icon="el-icon-arrow-up"
                                    class="right-button"
                                    circle
                                    v-if="show.up && item.show.up"
                                    v-show="index > 0"
                                    @click="(e)=>{movePrev(e,index)}"
                                    title="上移"
                                />
                                <el-button
                                    type="danger"
                                    icon="el-icon-arrow-down"
                                    class="right-button"
                                    circle
                                    v-if="show.down && item.show.down"
                                    v-show="index < contents.length - 1"
                                    @click="(e)=>{moveNext(e,index)}"
                                    title="下移"
                                />
                                <el-button
                                    type="danger"
                                    icon="el-icon-document-copy"
                                    class="right-button"
                                    circle
                                    v-if="show.copy && item.show.copy"
                                    @click="cloneRight(item, index)"
                                    title="复制"
                                />
                            </div>
                        </div>
                    </div>
                </draggable>
                <!-- 插槽：模板显示区域底部 -->
                <slot name="tplBottom"></slot>
            </el-col>
        </el-row>
    </div>
</template>

<script>
import DateUtil from "../../../util/pattern/date";
import * as ObjUtil from "../../../util/pattern/object";
import draggable from "vuedraggable";
import compEmpty from "../su-drag-template-02/comp-empty"
import mixin from "../../mixin";

export default {
    name: "veDragTemplate",
    mixins: [mixin],
    components: {draggable, compEmpty},
    directives: {
        "DragStopPropagation": {
            bind: function (el, binding, vnode) {
                el.ondrop = function (event) {
                    event.preventDefault();
                    event.stopPropagation();
                }
            }
        }
    },
    data() {
        return {
            contents: [], // 拖拽内容
            typeFrome: '',
            templates_bak: [],
        };
    },
    props: {
        templates: { // 模板列表
            type: Array,
            default() {
                return []
            }
        },
        repeat: { // 是否重复拖拽
            type: Boolean,
            default: true
        },
        show: {
            type: Object,
            default() {
                return {delete: true, up: true, down: true, copy: true}
            }
        }
    },
    created() {
        // this.templates_bak = [...this.templates];
        // this.typeCompMap = this.getTypeCompMap();
    },
    mounted() {
    },
    watch: {
        templates: {
            handler(val) {
                this.templates_bak = [...val]
                this.typeCompMap = this.getTypeCompMap();
            },
            deep: true,
            immediate: true,
        },
    },
    methods: {
        // 右侧操作区-数据复制
        cloneRight(item, index) {
            let resultData = this.$refs['content' + item.id][0].getData();
            let data = this.getTemplateItem({...item,data:JSON.parse(JSON.stringify(resultData))});
            this.contents.splice(index + 1, 0, data)
            this.$nextTick(() => {
                this.$refs['content' + data.id][0].initData(data.data);
            });
        },
        // 初始化数据
        initData(list) {
            let vm = this;
            let contents = [];
            for (let i = 0; i < list.length; i++) {
                let item = list[i];
                let type = item.type ? item.type : item.componentCode; // 新组件老数据中不存在type
                let comMap = this.typeCompMap[type];
                if (!comMap) {
                    console.error(type, '拖拽模板中未找到该模板类型！');
                    continue;
                }
                contents.push(this.getTemplateItem({
                    ...comMap,
                    data: item.data
                }));
            }
            this.contents = contents;
            for (let i = 0; i < contents.length; i++) {
                let item = contents[i];
                this.removeTemplate(item.type);
                let timer = setInterval((function (ref_, data_) {
                    let ref = ref_;
                    let data = data_;
                    return function () {
                        let cref = vm.$refs[ref];
                        if (cref && cref.length > 0) {
                            clearInterval(timer);
                            cref[0].initData && cref[0].initData(data);
                        }
                    };
                })('content' + item.id, item.data), 100);
            }
        },
        // 删除模板
        removeTemplate(type) {
            if (!this.repeat) { // 重复拖拽
                for (let i = 0; i < this.templates.length; i++) {
                    if (this.templates[i].type == type) {
                        this.templates.splice(i, 1);
                        return;
                    }
                }
            }
        },
        // 添加模板
        addTemplate(type) {
            if (!this.repeat) { // 重复拖拽
                for (let i = 0; i < this.templates_bak.length; i++) {
                    let item = this.templates_bak[i];
                    if (item.type == type) {
                        this.templates.push(item);
                        return;
                    }
                }
            }
        },
        // 获取模板类型
        getTypeCompMap() {
            let map = {};
            for (let i = 0; i < this.templates.length; i++) {
                let item = this.templates[i];
                map[item.type] = item;
            }
            return map;
        },
        // 从一个数组拖拽到另外一个数组时触发的事件和add不同，clone是复制了数组元素
        cloneDog(item) {
            this.typeFrome = item.type;
            return this.getTemplateItem(item);
        },
        getTemplateItem(item) {
            item.show = item.show || {};
            return {
                ...item,
                count: item.count || 999,
                componentCode: item.componentCode || item.type,
                options: item.options || {},
                listeners: item.listeners || {},
                show: {
                    delete: this.show.delete !== false && item.show.delete !== false,
                    onDelete: item.show.onDelete || function () {
                        return Promise.resolve();
                    },
                    up: this.show.delete !== false && item.show.up !== false,
                    down: this.show.delete !== false && item.show.down !== false,
                    copy: this.show.delete !== false && item.show.copy !== false,
                    mask: this.show.mask !== false && item.show.mask !== false,
                },
                id: DateUtil.getUUID(),
            }
        },
        // 拖拽完成时的事件
        onEnd(e) {
            let vm = this;
            let items = this.contents.filter(function (m) {
                return vm.typeFrome === m.type;
            });
            if (e.item.dataset.count > 0) {
                let num = items.filter(item => {
                    return item.type === e.item.dataset.type
                }).length
                if (num > e.item.dataset.count) {
                    this.$message.error(`该组件只能添加${e.item.dataset.count}个`)
                    this.contents.splice(e.newDraggableIndex, 1);
                    return false
                }
            }
            this.onContentEnd();
        },
        onContentEnd(e) {
            let fixTopIndex = -1;
            let fixBottomIndex = -1;
            this.contents.forEach(function (item, index) {
                if (item.fixTop) {
                    fixTopIndex = index;
                }
                if (item.fixBottom) {
                    fixBottomIndex = index;
                }
            })
            if (fixTopIndex > -1) {
                console.log("已强制置顶！");
                this.contents.unshift(this.contents.splice(fixTopIndex, 1)[0]);
            }
            if (fixBottomIndex > -1) {
                console.log("已强制置底！");
                this.contents.push(this.contents.splice(fixBottomIndex, 1)[0]);
            }
        },
        // 删除内容模板
        async delContent(index) {
            let item = this.contents[index];
            await item.show.onDelete();
            this.addTemplate(item.type);
            this.contents.splice(index, 1);
        },
        movePrev(e, index) {
            e.stopPropagation();
            if (index > 0 && this.contents[index - 1].fixTop) {
                this.$message.warning('无法上移,上层组件已置顶！');
                return;
            }
            this.contents.splice(index - 1, 0, ...this.contents.splice(index, 1))
        },
        moveNext(e, index) {
            e.stopPropagation();
            if (this.contents[index + 1].fixBottom) {
                this.$message.warning('无法下移,下层组件已置底！');
                return;
            }
            this.contents.splice(index + 1, 0, ...this.contents.splice(index, 1))
        },
        // 获取模板数据
        getData() {
            let vm = this;
            let data = [];
            for (let i = 0; i < this.contents.length; i++) {
                let item = this.contents[i];
                let ref = 'content' + item.id;
                let result = vm.$refs[ref][0].getData();
                data.push({
                    type: item.type,
                    componentCode: item.componentCode || item.type,
                    data: result
                });
            }
            return data;
        },
        // 校验数据
        async verify() {
            let data = this.getData();
            if (!data.length) {
                this.$message.error('页面模板内容不能为空');
                return false;
            }
            for (let i = 0; i < this.contents.length; i++) {
                let item = this.contents[i];
                let ref = await this.getItemRef(item);
                let bool = await ref.verify();
                if (!bool) {
                    return false;
                }
            }
            return true;
        },
        // 获取模板组件
        async getItemRef(item) {
            return await this.getRef('content' + item.id);
        },
    }
};
</script>

<style lang="less" scoped>
.img {
    width: calc(100% + 20px);
    padding-right: -20px;
}

.templateTypeItem {
    cursor: move;
    height: 36px;
    line-height: 36px;
    background-color: #fcfcfc;
    text-align: center;
    color: #000;
    border: 1px solid #cfcfcf;
    margin-bottom: 5px;
}

.drag-templates {
    display: inline-block;
    width: 150px;
    min-height: 20px;
}

.drag-right {
    display: inline-block;
    max-height: 700px;
    overflow-y: auto;
    width: calc(100% - 215px);
    border: 1px solid #d7d7d7;
    margin-right: 20px;
    margin-left: 30px;
    position: relative;

    .drag-content {
        min-height: 600px;

        .drag-empty {
            position: absolute;
            width: 100%;
        }
    }
}

.drag-right::-webkit-scrollbar {
    /*滚动条整体样式*/
    width: 5px; /*高宽分别对应横竖滚动条的尺寸*/
    height: 5px;
}

.drag-right::-webkit-scrollbar-thumb {
    /*滚动条里面小方块*/
    border-radius: 30px;
    box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
    background: #999;
}

.drag-right::-webkit-scrollbar-track {
    /*滚动条里面轨道*/
    box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
    border-radius: 30px;
    background: #ededed;
}

.content-item {
    box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
    width: calc(100% - 20px);
    padding: 10px;
    position: relative;
    min-height: 160px;
    overflow: hidden;

    .right-button-wrap {
        display: flex;
        flex-direction: column;
        position: absolute;
        // right: -20px;
        right: 10px;
        top: 10px;
        z-index: 100;

        .right-button {
            margin: 5px 0 0;
        }
    }
}
</style>
