<template>
    <!-- 需要select框 -->
    <el-select
        v-if="needSelect"
        ref="select"
        :title="multiple? optionData.name : ''"
        :value="value"
        placeholder="请选择"
        size="small"
        clearable
        :disabled="disabled"
        :filterable="filterable"
        :filter-method="filterMethod"
        style="width: 100%;"
        @clear="clear"
        @visible-change="visibleChange"
    >
        <el-option ref="option" class="tree-select__option" :value="optionData.id" :label="optionData.name">
            <el-tree
                ref="tree"
                class="tree-select__tree"
                :class="`tree-select__tree--${multiple ? 'checked' : 'radio'}`"
                :node-key="nodeKey"
                :data="data"
                :props="props"
                :check-strictly="relate"
                :default-expanded-keys="[value]"
                :show-checkbox="multiple"
                :highlight-current="!multiple"
                :expand-on-click-node="multiple"
                :filter-node-method="filterNode"
                @node-click="handleNodeClick"
                @check-change="handleCheckChange"
            >
                <span slot-scope="{ node, data }" class="custom-tree-node">
                    <span :class="!multiple&&data.disabled?'c-c0c4cc fw-normal':''">{{ node.label }}</span>
                    <span v-if="needSlot&&data.children&&data.children.length ">
                        <el-button type="text" size="mini" @click.stop="() => selectNode(data,false)">全选</el-button>
                        <el-button type="text" size="mini" @click.stop="() => selectNode(data,true)">取消全选 </el-button>
                    </span>
                </span>
            </el-tree>
        </el-option>
    </el-select>
    <!-- 平铺式树结构、菜单式直接勾选 -->
    <el-tree
        v-else
        ref="tree"
        class="tree-select__tree"
        :class="`tree-select__tree--${multiple ? 'checked' : 'radio'}`"
        :node-key="nodeKey"
        :data="data"
        :props="props"
        :check-strictly="relate"
        :default-expanded-keys="[value]"
        :show-checkbox="multiple"
        :highlight-current="!multiple"
        :expand-on-click-node="multiple"
        :filter-node-method="filterNode"
        @node-click="handleNodeClick"
        @check-change="handleCheckChange"
    >
        <span slot-scope="{ node, data }" class="custom-tree-node">
            <span :class="!multiple&&data.disabled?'c-c0c4cc':''">{{ node.label }}</span>
            <span v-if="needSlot&&data.children&&data.children.length ">
                <el-button type="text" size="mini" @click.stop="() => selectNode(data,false)">全选</el-button>
                <el-button type="text" size="mini" @click.stop="() => selectNode(data,true)">取消全选 </el-button>
            </span>
        </span>
    </el-tree>
</template>

<script>
export default {
    name: 'TreeSelect',
    props: {
        // v-model绑定
        value: {
            type: [String, Number],
            default: ''
        },
        multiple: {
            type: Boolean,
            default: false
        },
        // 多选状态下父子不关联
        relate: {
            type: Boolean,
            default: false
        },
        // 插槽，右侧全选
        needSlot: {
            type: Boolean,
            default: false
        },
        // 树形的数据
        data: {
            type: Array,
            default: function() {
                return [];
            }
        },
        // 每个树节点用来作为唯一标识的属性
        nodeKey: {
            type: [String, Number],
            default: 'id'
        },
        filterable: {
            type: Boolean,
            default: false
        },
        disabled: {
            type: Boolean,
            default: false
        },
        needSelect: {
            type: Boolean,
            default: true
        },
        // tree的props配置
        props: {
            type: Object,
            default: function() {
                return {
                    label: 'label',
                    children: 'children'
                };
            }
        }
    },
    data() {
        return {
            optionData: {
                id: '',
                name: ''
            },
            filterFlag: false
        };
    },
    watch: {
        value: {
            handler(newVal, oldVal) {
                if (!this.isEmpty(this.data)) {
                    this.init(newVal);
                }
            },
            immediate: true
        },
        data: function(val) {
            // if (!this.isEmpty(val)) {
            //     this.init(this.value);
            // }
        }
    },
    created() {},
    methods: {
    // 是否为空
        isEmpty(val) {
            for (const key in val) {
                return false;
            }
            return true;
        },
        handleNodeClick(data) {
            if (this.multiple || !this.needSelect || data.disabled) {
                return;
            }
            this.$emit('input', data[this.nodeKey]);
            this.$refs.select.visible = false;
        },
        handleCheckChange() {
            const nodes = this.$refs.tree.getCheckedNodes();
            const value = nodes.map((item) => item[this.nodeKey]).join(',');
            this.$emit('input', value);
        },
        // init的入参:多选是数组，单选是字符型
        init(val) {
            // 多选
            if (this.multiple) {
                const arr = val?.toString().split(',') || [];
                this.$nextTick(() => {
                    this.$refs.tree.setCheckedKeys(arr);
                    const nodes = this.$refs.tree.getCheckedNodes();
                    this.optionData.id = val;
                    console.log('多选选中项：', this.optionData.id);
                    this.optionData.name = nodes.map((item) => item[this.props.label]).join(',');
                    nodes.forEach(item => {
                        this.selectedParent(item);
                    });
                });
                // 选中子节点，子节点的父节点要高亮
            } else {
                if (val) {
                    this.$nextTick(() => {
                        this.$refs.tree.setCurrentKey(val);
                        const node = this.$refs.tree.getNode(val);
                        this.optionData.id = val;
                        console.log('单选选中项：', this.optionData.id);
                        this.optionData.name = node.label;
                    });
                } else {
                    this.$nextTick(() => {
                        this.$refs.tree.setCurrentKey(null);
                    });
                }
            }
        },
        visibleChange(e) {
            if (e) {
                const tree = this.$refs.tree;
                this.filterFlag && tree.filter('');
                this.filterFlag = false;
                let selectDom = null;
                if (this.multiple) {
                    selectDom = tree.$el.querySelector('.el-tree-node.is-checked');
                } else {
                    selectDom = tree.$el.querySelector('.is-current');
                }
                setTimeout(() => {
                    if (this.needSelect) {
                        this.$refs.select.scrollToOption({ $el: selectDom });
                    }
                }, 0);
            }
        },
        clear() {
            this.$emit('input', '');
        },
        filterMethod(val) {
            this.filterFlag = true;
            this.$refs.tree.filter(val);
        },
        filterNode(value, data) {
            if (!value) return true;
            const label = this.props.label || 'name';
            return data[label].indexOf(value) !== -1;
        },
        selectNode(data, flag) {
            // 多选才有这个功能
            const arr = this.optionData.id?.toString().split(',') || [];
            if (!flag) {
                // 全选：要选中的节点+过去已经选中的节点
                this.loop([data], arr);
                this.init(arr);
            } else {
                let delArr = [];
                this.loop([data], delArr);
                // 为了保证数据源的格式 string和num型都转成string型
                delArr = delArr.toString().split(',');
                // 取消，当前节点集 和 原来节点集取差
                const result = arr.filter(number => !delArr.includes(number));
                this.init(result);
            }
        },
        loop(data, arr) {
            data.forEach(item => {
                arr.push(item[this.nodeKey]);
                if (item.children?.length) {
                    this.loop(item.children, arr);
                }
            });
        },
        // 设置父节点的状态，父节点未选中就半选，选中就不变
        selectedParent(currentObj) {
            const currentNode = this.$refs.tree.getNode(currentObj);
            if (currentNode?.parent && currentNode.parent.data) {
                currentNode.parent.indeterminate = !currentNode.parent.checked;
                this.selectedParent(currentNode.parent.data);
            }
        }
    }
};
</script>
<style lang="scss">
.tree-select__option {
	&.el-select-dropdown__item {
		height: auto;
		line-height: 1;
		padding: 0;
		background-color: #fff;
	}
}

.tree-select__tree {
	padding: 4px 20px;
	font-weight: 400;
	&.tree-select__tree--radio {
		.el-tree-node.is-current > .el-tree-node__content {
			font-weight: 700;
		}
	}
}
.custom-tree-node {
	flex: 1;
	display: flex;
	align-items: center;
	justify-content: space-between;
	font-size: 14px;
	padding-right: 8px;
}
.fw-normal{
    font-weight: initial !important;
    }
</style>
