<template>
    <div class="info-tree">
        <div
            v-if="isShowFilterText()"
            class="input-box"
        >
            <el-input
                v-model="filterText"
                :placeholder="$t('pleaseInputKeywordFilter')"
                :suffix-icon="Search"
                @input="inputFilter"
            />
        </div>
        <div
            v-if="isRemote"
            class="input-box"
        >
            <el-select
                v-model="selectFilter"
                class="remote-select"
                placeholder="检索内容"
                size="small"
                clearable
                filterable
                remote
                :loading="remoteLoading"
                :remote-method="remoteSelect"
                @change="remoteSelectChange"
            >
                <el-option
                    v-for="(item, index) in filterType.filter(o => o.id !== 'load')"
                    :key="index"
                    :label="item.label"
                    :value="item.value"
                />
                <el-tooltip
                    v-if="filterType[filterType.length - 1]?.id === 'load'"
                    content="加载更多"
                >
                    <div
                        class="load-data"
                        @click="remoteSelect"
                    >
                        <i class="el-icon-more" />
                    </div>
                </el-tooltip>
            </el-select>
        </div>
        <el-tree
            ref="treeRef"
            :class="[{ 'is-filter': isShowFilterText() || isRemote,'info-design': infoDesign }]"
            :node-key="treeProps.nodeKey"
            :accordion="config.accordion !== undefined ? config.accordion : true"
            :lazy="lazyComputed"
            :props="treeProps"
            :data="dataTree"
            highlight-current
            :draggable="config.draggable"
            :current-node-key="currentNodeKey"
            :default-expanded-keys="defaultExpandedKeys.list"
            :load="loadNode"
            :allow-drag="allowDrag"
            :allow-drop="allowDrop"
            :filter-node-method="filterNode"
            :show-checkbox="showCheckbox"
            :expand-on-click-node="clickExpend"
            :default-expand-all="config.expandAll"
            @check="handleCheckChange"
            @node-drop="dropEnd"
            @node-drag-start="dropStart"
            @node-click="handleNodeClick"
            @node-contextmenu="handleContextmenu"
            @node-expand="handleExpand"
        >
            <template
                #default="{ node, data }"
            >
            <div
                class="custom-tree-node"
                :class="[
                    { 'general': data.general === 1 },
                    { 'no-selected': data.selected === 0 }
                ]"
            >
                <i
                    v-if="data.custom"
                    :class="['custom-button', data.custom]"
                    @click.stop="handleCustom(data)"
                />
                <!-- 自定义icon -->
                <img
                    v-if="data.imgType"
                    class="type-icon-img"
                    :src="data.imgType"
                />
                <img
                    v-if="iconImg && data[defaultProps.nodeKey as string] !== 'load'"
                    class="icon-img"
                    alt="icon"
                    :src="iconImg(node)"
                >
                <i
                    v-else-if="treeProps.customClass"
                    :class="treeProps.customClass(node,data)"
                />
                <el-tooltip
                    v-if="data[defaultProps.nodeKey as string] === 'load'"
                    :content="$t('loadMore')"
                >
                    <div class="load-data">
                        <el-icon><MoreFilled /></el-icon>
                    </div>
                </el-tooltip>
                <el-tooltip
                    v-if="data[defaultProps.nodeKey as string] !== 'load'"
                    :content="treeProps.label && data[treeProps.label]"
                    :disabled="typeof tipDisabled === 'function' ? tipDisabled() : tipDisabled"
                >
                    <span
                        v-if="editCode !== data[treeProps.nodeKey || 'id']"
                        class="name text-overflow"
                        :draggable="nameDraggable"
                        @dblclick="dblclickHandler(data)"
                        @dragstart.stop="handleDragStart($event, data)"
                        @dragend.stop="handleDragEnd($event, data)"
                    >
                        {{ nameFilter(treeProps.label && data[treeProps.label]) }}
                    </span>
                    <el-input
                        v-if="config.isEdit && editCode === data[treeProps.nodeKey || 'id']"
                        ref="inputRef"
                        v-model="inputValue"
                        class="input-tree"
                        @click.stop="inputClickHandler"
                        @blur="inputBlurHandler"
                    />
                </el-tooltip>
                <!-- <span
                    v-if="config.customCount || (data.children && data.children.length)"
                    class="length"
                >({{ (config.customCount && data[config.customCount]) || data.children.length }})</span> -->
                <span
                    v-if="getResourceHandler(data) && data.selected !== 0"
                    class="length"
                >({{ getResourceHandler(data) }})</span>
                <slot
                    v-if="isCustomIcon"
                    :data="data"
                    :node="node"
                />
            </div>
            </template>
        </el-tree>
    </div>
</template>
<script lang="ts">
import { MoreFilled, Search } from '@element-plus/icons-vue'
import { defineComponent,  PropType, ref, computed, getCurrentInstance, nextTick } from 'vue'
import { TreePropsInterface, TreeConfigInterface, LoadChildrenNodesInterface } from './index'
import { dropHooks, initHooks, editHooks } from './treeHooks'
import { ObjectInterface, __getItem } from '../../script/index'
export default defineComponent({
    name: 'InfoTree',
    components: {
        MoreFilled, Search
    },
    props: {
        dataTree: {
            type: Array as any,
            default: () => []
        },
        defaultProps: {
            type: Object as PropType<TreePropsInterface>,
            default: () => {
                return {
                    children: 'children',
                    label: 'name',
                    nodeKey: 'id'
                }
            }
        },
        // eslint-disable-next-line
        loadChildrenNodes: {
            type: Function as PropType<LoadChildrenNodesInterface>
        },
        contextmenu: {
            type: Function,
            default: () => {
            }
        },
        nodeCheck: {
            type: Boolean,
            default: false
        },
        initCurrent: { // 默认加载首节点数据
            type: Boolean,
            default: true
        },
        tipDisabled: { // 默认不显示tooltip
            type: [Boolean, Function],
            default: true
        },
        lazy: { // 懒加载
            type: Boolean
        },
        showCheckbox: {
            type: Boolean,
            default: false
        },
        clickExpend: {
            type: Boolean,
            default: true
        },
        config: { // 关于树形菜单的配置
            type: Object as PropType<TreeConfigInterface>,
            default: () => {
                return {
                    draggable: false,
                    expandAll: false
                }
            }
        },
        isRemote: {
            type: Boolean,
            default: () => false
        },
        remoteLoading: {
            type: Boolean,
            default: () => false
        },
        filterType: {
            type: Array,
            default: () => []
        },
        isShowFilterText: { // 是否显示搜索框
            type: Function,
            default: () => {
                return false
            }
        },
        infoDesign: {
            type: Boolean,
            default: true
        },
        isCustomIcon: {
            type: Boolean,
            default: false
        },
        // eslint-disable-next-line
        iconImg: Function
    },
    emits: ['treeCurrentData', 'dropStart', 'dropEnd', 'nodeExpand', 'checkChange', 'handleCustom', 'remoteSelect', 'remoteSelectChange', 'editBlur', 'node-name-drag-start', 'node-name-drag-end'],
    setup (props, ctx1) {
        const { proxy } = getCurrentInstance() as any
        
        const treeProps = ref<TreePropsInterface>(props.defaultProps)
        const {
            currentNodeKey,
            defaultExpandedKeys,
            lazyComputed,
            filterText,
            nameFilter,
            handleNodeClick,
            handleContextmenu,
            loadNode,
            handleCheckChange,
            inputFilter,
            filterNode,
            handleCustom,
            treeRef,
            setCurrent,
            setExpand,
            loadPaging,
            loadCurrentApi,
            routeName,
            uploadNode,
            requestPayload,
            buildParameter,
            loadCurrentNode,
            getResourceHandler
        } = initHooks(treeProps, props, ctx1, proxy)
        const {
            inputValue,
            editCode,
            inputRef,
            inputBlurHandler,
            dblclickHandler,
            inputClickHandler
        } = editHooks(treeProps, props.config, ctx1)
        const {
            allowDrop,
            allowDrag
        } = dropHooks(props.config, ctx1 )
        const dropEnd = (sourceNode: ObjectInterface, targetNode: ObjectInterface, position: string): void => {
            ctx1.emit('dropEnd', { sourceNode, targetNode, position })
            nextTick(() => {
                setDefaultHandler()
            })

        }
        const dropStart = (sourceNode: ObjectInterface, targetNode: ObjectInterface, position: string): void => {
            setDefaultHandler()
            ctx1.emit('dropStart', { sourceNode, targetNode, position })
        }
        const setDefaultHandler = () => {
            const nodeData = __getItem('nodeData')
            if (!nodeData) return
            const currentNode = nodeData[routeName as string] || {}
            const nodeId = currentNode.nodeId
            const parentNodeId = currentNode.nodePId
            currentNodeKey.value = nodeId
            defaultExpandedKeys.list = [parentNodeId]
            const handleCurrentNodeKey = currentNodeKey.value
            treeRef.value.setCurrentKey(handleCurrentNodeKey)
            setExpand(handleCurrentNodeKey)
        }
        const handleExpand = (data, node, vm) => {
            ctx1.emit('nodeExpand', data, node, vm)
        }
        const append = (data, parent) => {
            treeRef.value.append(data, parent)
        }
        // 带搜索
        const selectFilter = ref('')
        const remoteSelect = (val) => {
            if (typeof val === 'string') {
                selectFilter.value = val // 输入框保持
            }
            ctx1.emit('remoteSelect', selectFilter.value, typeof val === 'string')
        }
        const remoteSelectChange = (val) => {
            ctx1.emit('remoteSelectChange', val)
        }
        const nameDraggable = computed(() => !props.config.draggable && props.config.nameDraggable)
        const handleDragStart = (event: DragEvent, data: ObjectInterface): void => {
            if (!nameDraggable.value) return
            ctx1.emit('node-name-drag-start', event, data)
        }
        const handleDragEnd = (event: DragEvent, data: ObjectInterface): void => {
            if (!nameDraggable.value) return
            ctx1.emit('node-name-drag-end', event, data)
        }
        return {
            inputValue,
            editCode,
            inputRef,
            inputBlurHandler,
            dblclickHandler,
            inputClickHandler,
            allowDrop,
            allowDrag,
            filterText,
            lazyComputed,
            dropEnd,
            Search,
            routeName,
            currentNodeKey,
            defaultExpandedKeys,
            treeProps,
            nameFilter,
            uploadNode,
            handleNodeClick,
            handleContextmenu,
            loadNode,
            setExpand,
            setCurrent,
            handleCheckChange,
            inputFilter,
            filterNode,
            handleCustom,
            requestPayload,
            buildParameter,
            dropStart,
            getResourceHandler,
            loadCurrentApi,
            loadCurrentNode,
            loadPaging,
            append,
            handleExpand,
            treeRef,
            selectFilter,
            remoteSelect,
            remoteSelectChange,
            nameDraggable,
            handleDragStart,
            handleDragEnd
        }
    }
})
</script>
<style lang="scss" scoped>
@use './index.scss';

.input-box {
    width: 90%;
    margin: 5px auto 15px;
}
.remote-select {
    width: 100%;
}
::v-deep(.input-tree) {
    position: relative;
    z-index: 100;
    .ep-input__wrapper{
        box-shadow: none;
        border: 0;
        padding: 0;
        background-color: transparent;
    }
}
.load-data {
    width: 100%;
    height: 20px;
    text-align: center;
    line-height: 20px;
    font-size: 14px;
}
</style>
