<!--
 * @Author: xiejiang
 * @Date: 2024-12-04 14:06:18
 * @LastEditors: xiejiang
 * @LastEditTime: 2024-12-09 16:51:19
 * @Description: 菜单排序
 * Copyright（c）2024 by 好老师教育科技有限公司 All right Reserved.
-->
<template>
  <Drawer :drawer-visible="drawerVisible" width="480" title="菜单排序" :footer="false" @close="close">
    <t-tree
      :data="menuTree"
      activable
      expand-mutex
      hover
      transition
      draggable
      :allow-drop="handleAllowDrop"
      @drop="handleDrop"
    >
      <template #label="{ node }">
        <div class="flex justify-between items-center">
          <span> {{ node.label }}</span>
          <span><ViewListIcon /></span>
        </div>
      </template>
    </t-tree>
  </Drawer>
</template>

<script setup lang="ts" name="menu-sort">
import { TreeProps } from 'tdesign-vue-next'
import { ResMenuTree } from '@/api/interface/menu/index'
import { getMenuTree, postMenuSort } from '@/api/modules/menu/index'

const drawerVisible = ref(false)

const loading = ref(false)
const menuTree = ref<ResMenuTree[]>([])

// 为树形结构的每个节点添加新参数
function addNewParamToTree(tree: ResMenuTree[], newParamName: string): ResMenuTree[] {
  return tree.map(node => {
    const newNode = {
      ...node,
      children: node?.children || [],
      [newParamName]: node?.menuName || '-'
    }
    if (newNode.children && newNode.children.length > 0) {
      newNode.children = addNewParamToTree(newNode.children, newParamName)
    }
    return newNode
  })
}

const getData = () => {
  loading.value = true
  getMenuTree({})
    .then(res => {
      menuTree.value = addNewParamToTree(res.data, 'label')
    })
    .finally(() => {
      loading.value = false
    })
}

// 根据父节点的 menuId 查找其所有子节点
function findChildrenByParentId(tree: ResMenuTree[], parentId: string): ResMenuTree[] {
  let result: ResMenuTree[] = []

  for (const node of tree) {
    if (node.menuId === parentId) {
      result = node.children || []
      break
    } else if (node.children && node.children.length > 0) {
      const childrenResult = findChildrenByParentId(node.children, parentId)
      if (childrenResult.length > 0) {
        result = childrenResult
        break
      }
    }
  }

  return result
}

const handleAllowDrop: TreeProps['allowDrop'] = ctx => {
  const { dropPosition, dropNode, dragNode } = ctx
  // 只允许同级拖动
  if (dropPosition === 1) {
    //  允许同级拖动
    if (dragNode?.data?.parentId === dropNode?.data?.parentId) {
      return true
    } else {
      return false
    }
  } else {
    return false
  }
}

const handleDrop: TreeProps['onDrop'] = ctx => {
  const { dragNode, dropNode } = ctx

  // 获取拖动节点的原始父节点
  const originalParentId = dragNode.data?.parentId

  // 获取拖动节点
  const targetNodeId = dropNode.data?.menuId as string

  // 获取拖动节点的原始父节点下的所有子节点
  const oldOriginal = originalParentId ? findChildrenByParentId(menuTree.value, originalParentId) : menuTree.value

  // 拖动菜单索引
  const dragNodeIndex = oldOriginal.findIndex(item => item.menuId === dragNode.data?.menuId)

  // 目标节点索引
  const targetIndex = oldOriginal.findIndex(item => item.menuId === targetNodeId)

  //  从原数组中移除拖动节点
  oldOriginal.splice(dragNodeIndex, 1)

  //  插入到目标节点之前
  oldOriginal.splice(targetIndex, 0, dragNode.data as ResMenuTree)
  const from = oldOriginal.map((e, index) => {
    return { menuId: e.menuId as string, newSortNum: index + 1 }
  })

  postMenuSort(from).then(() => {
    MessagePlugin.success('排序成功')
  })
}

const open = () => {
  drawerVisible.value = true
  getData()
}
const close = () => {
  drawerVisible.value = false
}

defineExpose({
  open,
  close
})
</script>

<style lang="less" scoped></style>
