<template>
    <div class="hc-context-menu-box" :class="ui" :id="uuid" v-click-outside="onClickOutside">
        <template v-for="item in menus">
            <div class="hc-context-menu-item" @click.stop="optionClicked(item)">
                <slot :name='item.key' :item="item" v-if="item.isSlot"/>
                <template v-else>
                    <HcIcon :name="item.icon" class="menu-item-icon" v-if="item.icon"/>
                    <span class="menu-item-name">{{item.label}}</span>
                </template>
            </div>
        </template>
    </div>
</template>

<script setup>
import {ref, useSlots, watch, nextTick, onMounted, onBeforeUnmount} from "vue";
import {ClickOutside as vClickOutside} from 'element-plus'
import {getRandom, deepClone} from "js-fast-way"

const props = defineProps({
    ui: {
        type: String,
        default: ''
    },
    datas: {
        type: Array,
        default: () => ([])
    }
})

//初始变量
const uuid = getRandom()
const menus = ref(props.datas)

//监听表头
watch(() => [
    props.datas
], ([datas]) => {
    setIsSlots(datas)
})

//加载完成
nextTick(()=>{
    setIsSlots(props.datas)
})

//渲染完成
onMounted(()=>{
    document.body.addEventListener('keyup', onEscKeyRelease);
})

//判断<slot>是否有传值
const slots = useSlots()
const setIsSlots = (datas) => {
    let arr = deepClone(datas)
    for (let i = 0; i < arr.length; i++) {
        arr[i].isSlot = !!slots[arr[i].key]
    }
    menus.value = arr
}

//显示菜单
const showMenu = (event) => {
    let menu = document.getElementById(uuid);
    if (!menu) return;
    //取宽高
    menu.style.visibility = 'hidden';
    menu.style.display = 'block';
    let menuWidth = menu.offsetWidth;
    let menuHeight = menu.offsetHeight;
    menu.removeAttribute('style');
    //宽
    if (menuWidth + event.pageX >= window.innerWidth) {
        menu.style.left = event.pageX - menuWidth + 2 + 'px';
    } else {
        menu.style.left = event.pageX - 2 + 'px';
    }
    //高
    if (menuHeight + event.pageY >= window.innerHeight) {
        menu.style.top = event.pageY - menuHeight + 2 + 'px';
    } else {
        menu.style.top = event.pageY - 2 + 'px';
    }
    menu.classList.add('active');
}

//事件
const emit = defineEmits(['closed', 'item-click'])

const hideContextMenu = () => {
    const element = document.getElementById(uuid);
    if (element) {
        element.classList.remove('active');
        emit('closed')
    }
}

const onClickOutside = () => {
    hideContextMenu()
}

//菜单被点击
const optionClicked = (item) => {
    hideContextMenu()
    emit('item-click', item)
}

const onEscKeyRelease = (event) => {
    if (event.keyCode === 27) {
        hideContextMenu()
    }
}

//卸载之前
onBeforeUnmount(() => {
    document.removeEventListener('keyup', onEscKeyRelease);
})

// 暴露出去
defineExpose({
    showMenu
})
</script>

<style lang="scss" scoped>
.hc-context-menu-box {
    position: fixed;
    background-color: #fff;
    border-radius: 4px;
    width: max-content;
    display: none;
    left: 0;
    top: 0;
    box-shadow: 0 3px 6px -4px rgba(0, 0, 0, 0.12), 0 6px 16px 0 rgba(0, 0, 0, 0.08), 0 9px 28px 8px rgba(0, 0, 0, 0.05);
    z-index: 1000000;
    &.active {
        display: block;
    }
    .hc-context-menu-item {
        align-items: center;
        padding: 5px 15px;
        display: flex;
        cursor: pointer;
        position: relative;
        height: 40px;
        font-size: 16px;
        color: #333639;
        .menu-item-icon {
            margin-right: 6px;
        }
        &:hover {
            background-color: #f3f3f5;
        }
        &:first-of-type {
            margin-top: 4px;
        }
        &:last-of-type {
            margin-bottom: 4px;
        }
    }
}
</style>

<style lang="scss">
.hc-context-menu-box .hc-context-menu-item .menu-item-icon {
    margin-right: 6px;
}
</style>
