<template>
    <div class="cu-tree-node-children">
        <div class="cu-tree-node-view is-leaf" v-for="item in nodes" :key="item[format.key]">
            <div class="cu-tree-node-label">
                <div class="cu-tree-node-label-text">
                    <div class="cu-tree-node-label-name" :id="`node-tree-${item.key}`" @click="nodeLabelClick(item)" @dblclick="nodeLabelDblClick(item)" @contextmenu="nodeLabelContextMenu($event,item)">
                        <template v-if="TreeIsColor">
                            <el-button hc-btn color="#0081ff" :loading="item.loading" v-if="item?.colorStatus === 2">{{item.label}}</el-button>
                            <el-button hc-btn color="#f37b1d" :loading="item.loading" v-else-if="item?.colorStatus === 3">{{item.label}}</el-button>
                            <el-button type="primary" hc-btn :loading="item.loading" v-else-if="item?.colorStatus === 4">{{item.label}}</el-button>
                            <el-button type="info" hc-btn :loading="item.loading" v-else>{{item.label}}</el-button>
                        </template>
                        <template v-if="!TreeIsColor">
                            <el-button type="info" hc-btn :loading="item.loading">{{item.label}}</el-button>
                        </template>
                    </div>
                    <span class="cu-tree-node-label-btn" :class="[ifExpanded(item)?'expanded':'']" v-if="isExpanded(item)" @click="expandedClick(item)"/>
                </div>
            </div>
            <TreeNodeChildren :data="item.childNodes" :format="format" :menus="menusData" :isMark="menuMark" :parentNodes="item" v-if="ifExpanded(item)" :isColor="TreeIsColor"
                              @expandClick="ChildrenExpandedClick" @nodeClick="ChildrenNodeLabelClick" @nodeDblClick="ChildrenNodeLabelDblClick" @menuClick="ChildrenCpoverMenuClick"/>
        </div>
    </div>
    <!--菜单-->
    <n-dropdown placement="bottom" trigger="manual" :x="x" :y="y" size="huge" :options="menusData" :show="showDropdown" @clickoutside="onClickoutside" @select="handleMenuSelect"/>
</template>

<script setup>
import {ref,watch,onMounted,nextTick} from "vue";
import TreeNodeChildren from "./children.vue"
import {hIconJs} from "~src/plugins/renderele";
import {isType} from "vue-utils-plus"
import { NDropdown } from 'naive-ui';

const { isObject, isBoolean } = isType()
const props = defineProps({
    data: {
        type: Array,
        default: () => ([])
    },
    parentNodes: {
        type: Object,
        default: () => ({})
    },
    format: {
        type: Object,
        default: () => ({
            key: "key",
            label: "label",
            children: "children",
        })
    },
    menus: {
        type: Array,
        default: () => ([])
    },
    isMark: {
        type: Boolean,
        default: false
    },
    accordion: {
        type: Boolean,
        default: false
    },
    isColor: {
        type: Boolean,
        default: false
    },
})

//初始数据
const datas = ref(props.data)
const parent = ref(props.parentNodes)
const menusData = ref(props.menus)
const menuMark = ref(props.isMark)
const nodes = ref([])
const TreeIsColor = ref(props.isColor)

//树的菜单相关变量
const showDropdown = ref(false)
const menuRefItem = ref(null)
const x = ref(0);
const y = ref(0);

//监听
watch(() => [
    props.data,
    props.parentNodes,
    props.menus,
    props.isMark,
    props.isColor,
], ([val,Nodes,menus,isMark,isColor]) => {
    datas.value = val
    menusData.value = menus
    menuMark.value = isMark
    TreeIsColor.value = isColor
    if (isDataType(Nodes)) {
        parent.value = Nodes
        setDatasToNodes()
    } else {
        parent.value = {}
    }
})

//渲染完成
onMounted(()=> {
    if (isDataType(props.parentNodes)) {
        parent.value = props.parentNodes
        setDatasToNodes()
    } else {
        parent.value = {}
    }
})

//检查数据类型
const isDataType = (data) => {
    if (isObject(data)) {
        return Object.keys(data).length !== 0;
    } else {
        return false
    }
}

//处理为node节点类型的数据
const setDatasToNodes = () => {
    let nodesArr = [];
    const {key,label,children} = props.format
    const deepData = datas.value
    for (let i = 0; i < deepData.length; i++) {
        let childNodes = deepData[i][children] //子级数据
        let ifChildren = !!(childNodes && childNodes.length > 0);
        nodesArr.push({
            childNodes: childNodes, //子节点原始数据
            childrenNodes: [],      //子节点node封装数据
            data: deepData[i],      //节点主要数据
            parentNodes: parent.value,  //父节点数据
            expanded: ifChildren || deepData[i]['expanded'] || false,  //是否展开
            isExpand: ifChildren || deepData[i]['isExpand'] || false,   //是否能展开
            isLeaf: deepData[i]['isLeaf'] || false,     //是否为最后一节
            loading: deepData[i]['loading'] || false,   //加载状态
            colorStatus: deepData[i]['colorStatus'] || 1,   //颜色状态
            key: deepData[i][key],      //节点的key
            label: deepData[i][label]   //节点显示的名称
        })
    }
    nodes.value = nodesArr //渲染使用
    parent.value['childrenNodes'] = nodes.value //把当前节点数据，存入父节点的数据里。
}

const emit = defineEmits(['expandClick','nodeMouseover','nodeMouseout', 'nodeClick', 'nodeDblClick', 'menuClick'])

//下级数据是否存在
const isChildren = (item) => {
    return !!(item.childNodes && item.childNodes.length > 0);
}
//是否显示展开和隐藏按钮
const isExpanded = (item) => {
    let ifChildren = isChildren(item);
    if (isBoolean(item['expanded'])) {
        let res = !!(item['expanded'] && ifChildren);
        item['expanded'] = res;
        return res;
    } else {
        item['expanded'] = false;
        return false;
    }
}
//处理展开和隐藏的样式
const ifExpanded = (item) => {
    let ifChildren = isChildren(item);
    if (isBoolean(item['isExpand'])) {
        let res = !!(item['isExpand'] && ifChildren);
        item['isExpand'] = res;
        return res;
    } else {
        item['isExpand'] = ifChildren;
        return ifChildren;
    }
}
//展开和隐藏按钮被点击
const expandedClick = (item) => {
    emit('expandClick', {
        node: item,
        data: item.data
    })
}
const ChildrenExpandedClick = ({node,data}) => {
    emit('expandClick', {node,data})
}


//鼠标左键单击事件
const nodeLabelClick = (item) => {
    emit('nodeClick', {
        node: item,
        data: item.data
    })
}
const ChildrenNodeLabelClick = ({node,data}) => {
    emit('nodeClick', {node,data})
}

//双击事件
const nodeLabelDblClick = (item) => {
    emit('nodeDblClick', {
        node: item,
        data: item.data
    })
}
const ChildrenNodeLabelDblClick = ({node,data}) => {
    emit('nodeDblClick', {node,data})
}

//鼠标右键事件
const nodeLabelContextMenu = (e,item) => {
    const rows = menusData.value || [];
    if (rows.length > 0) {
        e.preventDefault();
        menuRefItem.value = item;
        if (menuMark.value) {
            setMenuMarkVal(rows, item)
        }
        nextTick().then(() => {
            showDropdown.value = true;
            x.value = e.clientX;
            y.value = e.clientY;
        });
    }
}

//设置菜单标记状态
const setMenuMarkVal = (rows,item) => {
    for (let i = 0; i < rows.length; i++) {
        if (rows[i].key === 'mark' || rows[i].key === 'cancel_mark') {
            if (item?.data?.isFirst) {
                menusData.value[i].label = '取消标记为首件';
                menusData.value[i].key = 'cancel_mark';
                menusData.value[i].icon = hIconJs({
                    name: 'grade', fill: true
                });
            } else {
                menusData.value[i].label = '标记为首件';
                menusData.value[i].key = 'mark';
                menusData.value[i].icon = hIconJs({name: 'grade'});
            }
            break;
        }
    }
}

const onClickoutside = () => {
    menuRefItem.value = null;
    showDropdown.value = false;
}

//鼠标右键菜单被点击
const handleMenuSelect = (key) => {
    const item = menuRefItem.value;
    showDropdown.value = false;
    emit('menuClick', {
        key,
        node: item,
        data: item.data
    })
}

//菜单被点击
const ChildrenCpoverMenuClick = ({key,node,data}) => {
    emit('menuClick', {key,node,data})
}
</script>

<style lang="scss" scoped>
@import "style";
</style>
