<template>
    <div class="para-tree3">
        <Tree :checkable="options.checkable"
              :treeData="treeData"
              :loadData="asyncTreeData"
              :expandedKeys.sync="dExpandedKeys"
              :defaultExpandedKeys="dExpandedKeys"
              :defaultSelectedKeys="dSelectedKeys"
              :defaultCheckedKeys="dCheckedKeys"
              :replaceFields="options.replaceFields"
              :showIcon="icon || options.icon"
              :draggable="dragable || options.dragable"
              @select="onSelect"
              @check="onCheck"
              @expand="onExpand"
              @load="onLoadFinish"
              @drop="onDrop"
              @dragstart="onDragstart"
              @dragenter="onDragEnter"
              @dragover="onDragOver"
        >
            <Icon v-if="options.iconSlots.length"
                  v-for="opt in options.iconSlots"
                  :slot="opt.name"
                  :type="opt.type"
                  :class="opt.disabled ? 'hidden':''"
            >
            </Icon>
            <span ref="moreDom" class="loading-more-dom" slot="title0010" style="color: #1890ff"
                  slot-scope="value">{{value.name}}
            </span>
            <template #title="title">
                <slot name="header" :props="title"></slot>
            </template>
        </Tree>
    </div>
</template>

<script>
    import {Tree, Icon} from "ant-design-vue";
    import {isObject, isString, uniq, cloneDeep, random} from "lodash";
    import {$http, $objectConverParameters} from "@chenxihub/sweet";

    const LOCALTYPE = "OPEN_TREE_KEY";
    const Lang = {
      name: {
        zh_CN: "查看更多",
        en_GB: "More",
      }
    }
    export default {
        props: {
            data: Array,
            defaultExpandedKeys: {
                type: Array,
                default() {
                    return [];
                }
            },
            defaultSelectedKeys: {
                type: Array,
                default() {
                    return [];
                }
            },
            config: Object,
            pagination: Boolean,
            icon: {
                type: Boolean,
                default() {
                    return false;
                }
            },
            /* 是否可拖拽 */
            dragable: {
                type: Boolean,
                default() {//
                    return false;
                }
            },
            dropCallback: {
                type: Function,
                default() {
                    return () => {
                    };
                }
            }
        },
        components: {
            Tree,
            Icon
        },
        data() {
            return {
                MORE: {
                    key: random(0, 100000),
                    name: Lang.name[this.language],
                    kind: "more",
                    labels: {},
                    entityType: "more",
                    slots: {icon: "more", title: "title0010"},
                    scopedSlots: {title: "title0010"},
                    includeGroup: true,
                    class: "moreClass"
                },
                treeData: [], // 树渲染的数据
                options: {
                    checkable: false,
                    replaceFields: {}, // 自己定义渲染字段对应mapping
                    request: null,// string or object
                    requestCallback: null, // 函数请求的回调函数
                    formatParams: null, // 外部序列化请求参数
                    extraFiled: null, // 自定义添加节点的时候判断的字段
                    extraRoot: null // 自iconSlots定义添加节点的数组,从前往后加
                }, // 配置文件
                dExpandedKeys: [], // 默认展开的key
                dSelectedKeys: [], // 默认选中的key
                dCheckedKeys: [], // 默认勾选的key
                paginationInfo: null, // 后台返回的所有的分页信息
                localKeyStore: [], // 本地存储的展开的key
                iconSlots: [], // 图标插槽
                enumMapping: {}, // 所有数据依赖关系图
                enumPagination: {} // 所有查看更多的分页数据索引表
            };
        },
        created() {
            this.init();
        },
        computed: {
            localKeyStoreComputed() {
                try {
                    return JSON.parse(window.localStorage.getItem(LOCALTYPE));
                } catch (e) {
                    return [];
                }
            },
            getSizeByParams() {
                return (this.options.request.params && this.options.request.params.size) ? this.options.request.params.size : 25;
            },
            language() {
                return JSON.parse(window.localStorage[window.$project]).setting.language || "zh_CN";
            }
        },
        methods: {
            async init() {
                if (!window.localStorage.getItem(LOCALTYPE)) {
                    window.localStorage.setItem(LOCALTYPE, JSON.stringify([]));
                }
                if (this.data) this.treeData = this.data;
                if (this.defaultExpandedKeys) this.dExpandedKeys = this.defaultExpandedKeys; // 默认展开
                if (this.defaultSelectedKeys) this.dSelectedKeys = this.defaultSelectedKeys; // 默认选择
                if (this.defaultCheckedKeys) this.dCheckedKeys = this.defaultCheckedKeys; // 默认勾选
                if (this.config) Object.assign(this.options, this.config);
                if (this.options.request) {
                    if (isString(this.options.request)) {
                        this.getTreeDataByService("string");
                    }
                    if (isObject(this.options.request)) {
                        const data = await this.getTreeDataByService("object");
                        this.serializationPagination(data);
                    }
                }
            },
            async onSelect(selectedKeys, info) {
                if (typeof info.node.dataRef.key === "number" && info.node.dataRef.kind && info.node.dataRef.kind === "more") {
                    if (info.node.$parent.eventKey) { // 查看更多
                        if (typeof info.node.$parent.eventKey === "number") { // 组的查看更多
                            const dag = await this.getTreeDataByService("object", info.node.$parent.$parent.eventKey, info.node, {from: "more"});
                            this.serializationPagination(dag, true, info.node);
                        } else { // 普通的查看更多
                            const dat = await this.getTreeDataByService("object", info.node.$parent.eventKey, info.node.$parent, {from: "more"});
                            this.serializationPagination(dat, true, info.node);
                        }
                    } else {
                        const dat = await this.getTreeDataByService("object",
                            info.node.dataRef.key, // 是个数字
                            null,
                            {from: "root"});
                        this.serializationPagination(dat, false);
                    }
                }
                this.$emit("select", selectedKeys, info, info.node.dataRef);
            },
            onCheck(checkedKeys, info) {
                this.$emit("check", checkedKeys, info, info.node.dataRef);
            },
            onExpand(expandedKeys, info) {
                if (info.expanded) { // 展开
                    this.setLocalDefaultKey(info, true); // 设置本地展开的key
                } else {
                    //  设置收起的key,更新下次展开的key
                    this.setLocalDefaultKey(info, false);
                }
                this.$emit("expand", expandedKeys, info, info.node.dataRef);
            },
            onLoadFinish() {
                this.serializationSelectKey([]);
            },
            /* 发起树接口请求 */
            async getTreeDataByService(type, key, treeNode, ops) {
                switch (type) {
                    case "object":
                        let conf = {};
                        const {url, params, method, project} = this.options.request;
                        if (!url) throw Error("请传入请求地址");
                        if (params) {
                            let nParams = cloneDeep(params);
                            if (ops && ops.from && ops.from === "more") {
                                if (this.pagination) {
                                    nParams.page = this.enumPagination[treeNode.dataRef.key].page++;
                                }
                            }
                            if (ops && ops.from && ops.from === "root") {
                                if (this.pagination) {
                                    nParams.page = this.enumPagination["root"].page++;
                                }
                            }
                            if (key && this.options.formatParams) {
                                let p = this.options.formatParams(nParams, key, treeNode);
                                conf.url = this.serializationURL(url, p);
                            } else {
                                if (key) nParams.key = key;
                                conf.url = this.serializationURL(url, nParams);
                            }
                        }
                        method ? conf.method = method.toLocaleUpperCase() : conf.method = "GET";
                        if (project) conf.project = project;
                        const {data} = await $http[`$para${conf.method}`](Object.assign({}, ...conf));
                        return data;
                    case "string":
                        const {da} = await $http.$paraGET(this.request);
                        return da;
                    default:
                        break;
                }
            },
            /**
             *  序列化分页数据处理
             *  {value} 节点的数组
             *  {isChild} 是否是子节点数据
             *  {treeNode} 需要插入的节点
             */
            async serializationPagination(value, isChild, treeNode) {
                if (this.options.requestCallback) {
                    this.options.requestCallback(value, async n => {
                        if (this.pagination) {
                            const {page, list} = n;
                            this.paginationInfo = page; // 存储后台返回的分页信息，包含总共多少条数据
                            this.serializationEnumMapping(list);
                            if (isChild) {
                                //  来自子节点的数据
                                await this.editSerializationNodeLeaf(treeNode, list);
                            } else {
                                //  来自根节点的数据（第一次的时候是不存在isChild）多根的情况
                                await this.editSerializationNodeLeaf(null, list);
                            }
                            this.serializationExpandKey(); // 设置展开的叶子节点的key
                            this.serializationSelectKey([]);
                        } else {
                            // 不用分页
                            this.treeData = value;
                        }
                    });
                } else {
                    // 没有数据回调的时候
                    this.treeData = value;
                }
            },
            // 设置本地展开的key
            setLocalDefaultKey(info, bol) {
                if (this.localKeyStoreComputed.length > 0) this.localKeyStore = this.localKeyStoreComputed;
                if (bol) {
                    this.localKeyStore.push(info.node.dataRef.key);
                } else {
                    this.localKeyStore = this.localKeyStore.filter(v => v !== info.node.dataRef.key);
                }
                window.localStorage.setItem(LOCALTYPE, JSON.stringify(uniq(this.localKeyStore)));
            },
            // 设置默认展开的Key
            serializationExpandKey(source) {
                if (source) {
                    for (let i = 0; i < source.length; i++) {
                        if (this.dExpandedKeys.indexOf(source[i]) === -1) {
                            this.dExpandedKeys.push(source[i]);
                        }
                    }
                    this.refresh();
                } else {
                    //  设置默认展开值
                    this.serializationExpandKey(this.localKeyStoreComputed);
                }
            },
            serializationSelectKey(source) {
                if (source) {
                    for (let i = 0; i < source.length; i++) {
                        if (this.dSelectedKeys.indexOf(source[i]) === -1) {
                            this.dSelectedKeys.push(source[i]);
                        }
                    }
                    this.refresh();
                } else {
                    //  设置默认选中值
                    this.serializationSelectKey(this.defaultSelectedKeys);
                }
            },
            asyncTreeData(treeNode) {
                return new Promise(async resolve => {
                    if (treeNode.dataRef.children) {
                        resolve();
                        return;
                    }
                    let data = await this.getTreeDataByService("object", treeNode.dataRef.key, treeNode);
                    await this.serializationPagination(data, true, treeNode);
                    resolve();
                });
            },
            /**
             * @return {string}
             */
            serializationURL(url, params) {
                if (url.indexOf("?") !== -1) {
                    return `${url}&${$objectConverParameters(params)}`;
                } else {
                    return `${url}?${$objectConverParameters(params)}`;
                }
            },
            serializationEnumMapping(data, node) {
                for (let i = 0, l = data.length; i < l; i++) {
                    let item = data[i];
                    if (data[i - 1])
                        item.prev = data[i - 1];
                    if (data[i + 1])
                        item.next = data[i + 1];
                    this.enumMapping[item.key] = item;
                    this.enumPagination[data[i].key] = {page: 2, size: this.getSizeByParams, $parent: node};
                }
            },
            /**
             *
             * @param treeNode
             * @param list
             * @returns {Promise<void>}
             */
            async editSerializationNodeLeaf(treeNode, list) {
                if (treeNode && treeNode.dataRef.kind && treeNode.dataRef.kind === "more") {
                    await this.editAddMore(treeNode, list);
                } else {
                    await this.editExtraNodeLeaf(treeNode, list);
                }
            },
            async editAddMore(treeNode, list) {
                if (list.length >= this.getSizeByParams) {
                    // 需要更改请求的页数加1
                    treeNode.$parent.dataRef.children.splice(-1, 0, ...list);
                } else {
                    treeNode.$parent.dataRef.children.splice(-1, 1, ...list);
                }
                this.refresh();
            },
            /**
             * 处理额外添加的节点数据的时候
             * @param treeNode
             * @param list
             * @returns {Promise<void>}
             */
            async editExtraNodeLeaf(treeNode, list) {
                let cloneExtraMore = cloneDeep(this.MORE);
                cloneExtraMore.key = random(0, 10000);
                if (this.options.extraFiled && this.options.extraRoot) {
                    let cloneExtraRoot = cloneDeep(this.options.extraRoot);
                    if (!treeNode) {
                        await this.editMultiRoot(treeNode, list, cloneExtraMore);
                    } else {
                        // treeNode是否包含组选项
                        if (treeNode.dataRef[this.options.extraFiled]) { // 根据外部字段判断是否需要添加额外的节点
                            cloneExtraRoot.map(v => v.key = random(0, 100000));
                            if (list.length >= this.getSizeByParams) { // 是否开启分页
                                if (typeof treeNode.dataRef.key === "number") { // 是自己插入的组，不需要新增组
                                    treeNode.dataRef.children = [...list, cloneExtraMore];
                                    this.serializationEnumMapping(treeNode.dataRef.children, treeNode);
                                } else {
                                    treeNode.dataRef.children = [...cloneExtraRoot, ...list, cloneExtraMore];
                                    this.serializationEnumMapping(treeNode.dataRef.children, treeNode);
                                }
                            } else {
                                this.refresh();
                                if (typeof treeNode.dataRef.key === "number") { // 是自己插入的组，不需要新增组
                                    treeNode.dataRef.children = list;
                                } else {
                                    treeNode.dataRef.children = [...cloneExtraRoot, ...list];
                                }
                            }
                            this.refresh();
                        } else {
                            if (list.length >= this.getSizeByParams) { // 是否开启分页
                                treeNode.dataRef.children = [...list, cloneExtraMore];
                                this.serializationEnumMapping(treeNode.dataRef.children, treeNode);
                            } else {
                                treeNode.dataRef.children = list;
                            }
                            this.refresh();
                        }
                    }
                } else {
                    // 组织的添加 不需要额外的添加extraFiled，extraRoot
                    await this.editMultiRoot(treeNode, list, cloneExtraMore);
                }
            },
            /**
             * 多根的带分页的处理
             */
            async editMultiRoot(treeNode, list, cloneExtraMore) {
                if (!treeNode) { // 多根的情况
                    if (list.length >= this.getSizeByParams) { // 多根分页
                        if (this.treeData.length > 0 && typeof (this.treeData[this.treeData.length - 1]).key === "number") {
                            this.treeData.splice(-1, 0, ...list);
                            this.serializationEnumMapping(this.treeData, treeNode);
                        } else {
                            this.refresh();
                            this.treeData = [...this.treeData, ...list, cloneExtraMore];
                            this.serializationEnumMapping(this.treeData, treeNode);
                        }
                        this.refresh();
                        if (!this.enumPagination["root"]) {
                            this.enumPagination["root"] = {page: 2, size: this.getSizeByParams, $parent: null};
                        }
                    } else { // 多根不分页
                        // 如果数据不够分页了，那么要清除掉元数据中的分页数据
                        if (this.treeData.length > 0 && typeof (this.treeData[this.treeData.length - 1]).key === "number") {
                            this.treeData.splice(-1, 1);
                        }
                        this.treeData = [...this.treeData, ...list];
                        this.serializationEnumMapping(this.treeData, treeNode);
                    }
                    this.refresh();
                } else {
                    if (list.length >= this.getSizeByParams) {
                        treeNode.dataRef.children = [...list, cloneExtraMore];
                        this.serializationEnumMapping(treeNode.dataRef.children, treeNode);
                    } else {
                        this.refresh();
                        treeNode.dataRef.children = list;
                    }
                    this.refresh();
                }
            },
            refresh() {
                this.$forceUpdate();
            },
            /**
             * 拖拽
             * onDrop
             */
            onDrop(info) {
                if (this.dropCallback) {
                    this.dropCallback(info, (data) => {
                        this.treeData = data;
                    });
                } else {
                    throw Error("请传入dropCallback");
                }
            },
            onDragOver({event, node}) {
                this.$emit("onDragOver", {event, node});
            },
            onDragEnter(info) {
                this.$emit("onDragEnter", {info});
            },
            onDragstart({event, node}) {
                this.$emit("onDragstart", {event, node});
            }
        }
    };
</script>
<style lang="less">
    .hidden {
        display: none !important;
    }

    .moreClass {
        .ant-tree-switcher {
            display: none !important;
        }

        .ant-tree-node-selected {
            background-color: transparent !important;
        }
    }
</style>
