<!-- Created by henian.xu on 2019/4/2. -->

<template>
    <div class="tree-transfer">
        <el-row>
            <el-col :span="11">
                <el-tree
                    key="leftTree"
                    ref="leftTree"
                    show-checkbox
                    :node-key="prop_.id"
                    :data="leftTreeData"
                    :default-expanded-keys="expandedKeys"
                    @node-expand="(data)=>setNodeExpanded('rightTree',data,true)"
                    @node-collapse="(data)=>setNodeExpanded('rightTree',data,false)"
                />
            </el-col>
            <el-col
                :span="2"
                class="ta-c"
            >
                <el-button @click="onToRight">
                    &gt;&gt;
                </el-button>
                <el-button
                    class="nma-a ma-t"
                    @click="onToLeft"
                >
                    &lt;&lt;
                </el-button>
            </el-col>
            <el-col :span="11">
                <el-tree
                    key="rightTree"
                    ref="rightTree"
                    show-checkbox
                    :node-key="prop_.id"
                    :data="rightTreeData"
                    :default-expanded-keys="expandedKeys"
                    @node-expand="(data)=>setNodeExpanded('leftTree',data,true)"
                    @node-collapse="(data)=>setNodeExpanded('leftTree',data,false)"
                />
            </el-col>
        </el-row>
        <!--<el-button @click="onTest">测试</el-button>-->
    </div>
</template>

<script>
// status: 1:未选中(左边); 2:已选中(右边); 1|2:半选中(即两边都有)
export default {
    name: 'TreeTransfer',
    data() {
        return {
            dataList: [],
            expandedKeysMap: {},
        };
    },
    props: {
        data: {
            type: Array,
            default: () => [],
        },
        prop: {
            type: Object,
            default: () => ({}),
        },
    },
    computed: {
        prop_() {
            const defaultData = {
                // tree 组件 props
                label: 'name',
                children: 'children',
                disabled: 'disabled',
                isLeaf: 'isLeaf',
                // 自定义的
                id: 'id',
                lv: 'lv',
                parentId: 'parentId',
                status: 'status',
            };
            return Object.keys(defaultData).reduce((p, c) => {
                p[c] = this.prop[c] || p[c];
                return p;
            }, defaultData);
        },
        treeProps() {
            return ['label', 'children', 'disabled', 'isLeaf'].reduce((p, c) => {
                p[c] = this.prop_[c];
                return p;
            }, {});
        },
        // dataList 如果用计算属性会失去响应能力
        /* dataList() {
            const { prop_ } = this;
            const propList = Object.keys(prop_);
            const cacheMap = {};
            return JSON.parse(JSON.stringify(this.data)).map(item => {
                // 字段转义
                const res = propList.reduce((p, c) => {
                    p[c] = p[c] || p[prop_[c]];
                    return p;
                }, item);

                if (!res.isLeaf) {
                    cacheMap[res.id] = res;
                } else {
                    const { parentId, status } = res;
                    const parentItem = cacheMap[parentId];
                    if (parentItem) {
                        parentItem.status = parentItem.status | status;
                    }
                }
                return res;
            });
        }, */
        dataMap() {
            return this.dataList.reduce((p, c) => {
                p[c.id] = c;
                return p;
            }, {});
        },
        leftTreeData() {
            return this.listToTree(JSON.parse(JSON.stringify(this.dataList)), 1);
        },
        rightTreeData() {
            return this.listToTree(JSON.parse(JSON.stringify(this.dataList)), 2);
        },
        treeData() {
            return this.$utils.Convert.listToTree(JSON.parse(JSON.stringify(this.dataList)));
        },
        $$leftTree() {
            return this.$refs.leftTree;
        },
        $$rightTree() {
            return this.$refs.rightTree;
        },
        expandedKeys() {
            const { expandedKeysMap } = this;
            return Object.keys(expandedKeysMap).reduce((p, c) => {
                if (expandedKeysMap[c]) {
                    p.push(+c);
                }
                return p;
            }, []);
        },
    },
    watch: {
        data: {
            handler(val) {
                if (!val || !val.length) return;
                this.buildDataList(val);
            },
            immediate: true,
        },
    },
    methods: {
        buildDataList(data) {
            const { prop_ } = this;
            const propList = Object.keys(prop_);
            const cacheMap = {};
            this.dataList = JSON.parse(JSON.stringify(data)).map(item => {
                // 字段转义
                const res = propList.reduce((p, c) => {
                    p[c] = item[c] || item[prop_[c]];
                    return p;
                }, {});

                res.original = item;

                if (!res.isLeaf) {
                    cacheMap[res.id] = res;
                } else {
                    const { parentId, status } = res;
                    const parentItem = cacheMap[parentId];
                    if (parentItem) {
                        parentItem.status |= status;
                    }
                }
                return res;
            });
            this.emitInput();
        },
        listToTree(list, status = 1, lv) {
            const res = [];
            const parentNodeMap = {};
            let minLv = 9999999;
            list.forEach(item => {
                // item.id 有值时才可能是父节点
                if (item.id) {
                    parentNodeMap[item.id] = item;
                    minLv = lv || (item.lv < minLv ? item.lv : minLv);
                }
            });
            list.forEach(item => {
                if (!(status & item.status)) return;
                if (item.lv === minLv) {
                    res.push(item);
                } else {
                    const parentNode = parentNodeMap[item.parentId];
                    if (parentNode) {
                        parentNode.children = parentNode.children || [];
                        parentNode.children.push(item);
                    } else {
                        console.error('此节点数据有问题', item);
                    }
                }
            });
            this.$utils.Convert.sortTreeData(res);
            return res;
        },
        onToRight() {
            const { $$leftTree } = this;
            const checkedNode = $$leftTree.getCheckedNodes();
            const halfNode = $$leftTree.getHalfCheckedNodes();
            this.setListItemsStatus(checkedNode, 2);
            this.setListItemsStatus(halfNode, 1 | 2);
            this.emitInput();
        },
        onToLeft() {
            const { $$rightTree } = this;
            const checkedNode = $$rightTree.getCheckedNodes();
            const halfNode = $$rightTree.getHalfCheckedNodes();
            this.setListItemsStatus(checkedNode, 1);
            this.setListItemsStatus(halfNode, 1 | 2);
            this.emitInput();
        },
        setListItemsStatus(list, status = 1) {
            list.forEach(item => {
                const { id } = item;
                const mapItem = this.dataMap[id];
                if (!mapItem) return;
                mapItem.status = status;
            });
        },
        emitInput() {
            const { prop_ } = this;
            const flatten = list =>
                list.reduce((pre, curr) => {
                    const { children } = curr;
                    curr.original[prop_.status] = curr.status;
                    return pre.concat(curr.original, children ? flatten(children) : []);
                }, []);
            this.$emit('input', flatten(this.rightTreeData));
        },
        /* 树形框组件操作 */
        setNodeExpanded(tree, data, val) {
            const treeComponent = this.$refs[tree];
            const key = data.id;
            this.recordExpandedKeys(key, val);
            const node = treeComponent.getNode(key);
            if (!node) return;
            node.expanded = val;
        },
        recordExpandedKeys(key, val) {
            const { expandedKeysMap } = this;
            this.$set(expandedKeysMap, key, val);
        },
        onTest() {
            console.log(JSON.stringify(this.treeData));
            console.log((this.dataMap[17520].label = 'name'));
        },
    },
};
</script>

<style lang="scss">
.tree-transfer {
}
</style>
