<template>
  <div class="page_container">
    <div class="bg-breadcrumb">
      <el-breadcrumb separator="/">
        <el-breadcrumb-item> 开发管理 </el-breadcrumb-item>
        <el-breadcrumb-item > 菜单管理 </el-breadcrumb-item>
      </el-breadcrumb>
    </div>
    <div class="flex_row">
      <div class="flex_left">
           <div class="tree_content">
             <div class="search"> 
               <el-input
                  v-model="search"
                  placeholder="请输入内容"
                  :prefix-icon="Search"
                />
             </div>
             <div class="tree">
              <el-tree 
                :data="data" 
                :props="defaultProps" 
                @node-click="handleNodeClick" 
                :default-expand-all="true" 
                :highlight-current="true"
                node-key="menu_id"
                ref="menuTree"
                :filter-node-method="filterNode"
              >
                <template #default="{ node, data }">
                  <div class="custom-tree-node" pointer-events="none">
                    
                    <span
                      class="label-text text_clip"
                      :title="data.menu_name"
                      >{{ data.menu_name }}</span
                    >
                  </div>
                  <span class="tree-action-box">
                    <bg-icon
                      @click.stop="showAction($event, data,node)"
                      class="tree-more"
                      icon="#bg-ic-s-more"
                    ></bg-icon>
                  </span>
                </template>
               </el-tree >
               <Teleport to="body">
                <div
                  class="tree-action"
                  ref="treeAction"
                  v-show="actionFlag"
                  :style="{ top: acTop, left: acLeft,bottom:acBottom }"
                >
                  <div class="action" @click="fileAction(1,selectData,selectParentData)">
                    新建本级
                  </div>
                  <div class="action" @click="fileAction(2,selectData,selectParentData)">
                    新建下级
                  </div>
                  <div class="action" @click="fileAction(3,selectData,selectParentData)">
                    删除
                  </div>
                  <div class="action" :class="{'disable':moveIndex==0}" @click="fileAction(4,selectData,selectParentData,moveIndex==0)">
                    上移
                  </div>
                  <div class="action" :class="{'disable': !selectParentData ? moveIndex == data.length - 1 : moveIndex==selectParentData.Child.length-1}" @click="fileAction(5,selectData,selectParentData,!selectParentData ? moveIndex == data.length - 1 : moveIndex==selectParentData.Child.length-1)" >
                    下移
                  </div>
                </div>
              </Teleport>
             </div>
           </div>
      </div>
      <div class="flex_right">
        <div class="main_container">
          <div class="base-info bg-scroll">
            <menuForm ref="menuFormRef" :data="menuFormData"></menuForm>
          </div>
          <div class="base-btn">
            <el-button  type="primary" @click="saveMenu(menuFormRef,addType)">
                保存
            </el-button>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
import { Search } from '@element-plus/icons-vue'
import { reactive, toRefs, ref, nextTick, computed, onBeforeMount, onBeforeUnmount, watch } from 'vue'
import { useRouter } from 'vue-router';
import { ElMessage } from 'element-plus'
import axios from '../../../../request/http.js'
import menuForm from './menu-form.vue'
const router = useRouter();

const menuTree = ref(null) // 树形
const treeAction = ref(null) // 树形操作弹出框
const menuFormRef = ref(null) // 右侧表单
const acTop = ref('');
const acLeft = ref('');
const acBottom = ref('');
const actionFlag = ref(false) // 弹出框状态标识

const state = reactive({
  data: [], // 树形数据
  search: "", // 树形搜索
  selectData:null, // 当前选中的节点
  selectParentData:null, // 当前选中节点的父节点
  treeAction,
  menuTree,
  bottomGap:30,//弹窗吸底高度
  defaultProps: {
    children: 'Child',
    label: 'menu_name',
  }, // 树形配置
  actionDataIndex: 0, // 当前选中节点在本级的位置，用来判断是否可以上下移动
  menuFormData: null, // 菜单数据
  addType: 1, // 1-新增本级 2-新增下级
  newMenuId: 0, // 新增菜单时用来指定menu_id，达到选中效果
  timer: null, // 定时器
})

const moveIndex = computed({
  get: () => {  
    let index = 0
    if(state.selectData) {
      findIndex(state.selectData.menu_id,state.data)
      index = state.actionDataIndex
    }
    
    return index
  }
}) // 计算上下移动

watch(() => state.search,(n,o) => {
  if (state.timer) {
    clearTimeout(state.timer);
  }
  state.timer = setTimeout(() => {
    state.menuTree.filter(n)
  }, 500);
}) // 树形搜索值

const getMenuTree = () => {
  axios
    .get(`/apaas/system/v5/menu/tree`)
    .then((res) => {
      if (res.data.code == 200) {
        state.data = res.data.data || []
        nextTick().then(() => {
          if (state.selectData) {
            state.menuTree && state.menuTree.setCurrentKey(state.selectData.menu_id);
            handleNodeClick(state.selectData);
          }else {
            state.menuTree && state.menuTree.setCurrentKey(state.data[0].menu_id);
            handleNodeClick(state.data[0]);
          }
        })

      }else {
        ElMessage.error(res.data.data)
      }
    })
} // 获取菜单树

const findIndex= (code,arr) => {
  arr.forEach((e,i) => {
    if (e.menu_id == code) {
      state.actionDataIndex = i
    }else {
      if (e.Child && e.Child.length > 0) {
        findIndex(code,e.Child)
      }
    }
  })
} // 处理数据 用于判断能否上下移

const showAction = (e, data,node) => {
  acTop.value = ''
  acLeft.value = ''
  acBottom.value = ''
  const rect = e.target.getBoundingClientRect(); //获取点击的dom的位置
  var allHeight = document.body.scrollHeight
  
  actionFlag.value = true;
  state.selectData = data
  if(node.parent.data.Child){
    state.selectParentData = node.parent.data
  }else{
    //没有children则是最上层元素
    state.selectParentData = null
  }
  nextTick().then(()=>{
    setTimeout(()=>{
      var height = window.getComputedStyle(state.treeAction).height
      height = parseInt(height)
      //判断弹窗位置是否超过屏幕，超过则吸底展示
      if(height+rect.y - 17>allHeight-state.bottomGap){
        acBottom.value = state.bottomGap+ "px";
        acLeft.value = rect.x + 35 + "px";
      }else{
        acTop.value = rect.y - 17 + "px";
        acLeft.value = rect.x + 35 + "px";
      }
    })
  })
} // 树形操作框

const handleNodeClick = (data) => {
  if (state.selectData && state.selectData.menu_id == data.menu_id) {
    return
  }
  state.selectData = data
  menuFormRef.value.setForm(state.selectData)
  closeAction()
  if (menuFormRef) {
    nextTick().then(() => {
      menuFormRef.value.menuRef.validate(valid => {
        if (!valid) {
          menuFormRef.value.menuRef.clearValidate()
        }
      })
    })
  } // 清除表单验证
} // 菜单树节点点击

const filterNode = (val,data) => {
  if (!val) {
    return true
  }
  return data.menu_name.includes(val)
} // 树形筛选

const fileAction = (val,data,parent,disabled=false) => {
  if (val == 1) { // 新建本级菜单
    state.addType = 1
    let newChild = {
      menu_name: "新菜单",
      menu_id: 'new' + state.newMenuId,
      menu_type: 0,
      dict_group_id: "",
      state: 1,
      menu_url: "",
      menu_logo: "",
      level: data.level
    }
    state.menuTree.insertAfter(newChild,parent? parent.Child[parent.Child.length-1] : state.data[state.data.length -1])
    state.menuTree && state.menuTree.setCurrentKey(newChild.menu_id);
      handleNodeClick(newChild);
    state.newMenuId++
  }else if (val == 2) { // 新建下级菜单
    if (disabled) {
      return
    }
    state.addType = 2
    let newChild = {
      menu_name: "新菜单",
      menu_id: 'new' + state.newMenuId,
      menu_type: data.menu_type == 0 ? 0 : data.menu_type == 1 ? 1 : 2,
      dict_group_id: "",
      state: 1,
      menu_url: "",
      menu_logo: "",
      p_menu_type: data.menu_type
    }
    state.menuTree.append(newChild,data)
    state.menuTree && state.menuTree.setCurrentKey(newChild.menu_id);
      handleNodeClick(newChild);
    state.selectParentData = data
    state.newMenuId++
  }else if (val == 3) { // 删除菜单
    axios
      .delete(`/apaas/system/v5/menu/${data.id}`)
      .then((res) => {
        if (res.data.code == 200) {
          ElMessage.success(res.data.data)
          state.selectData = null
          getMenuTree()
        }else {
          ElMessage.error(res.data.data)
        }
      })
  }else if (val == 4) { // 菜单上移
    if (disabled) {
      return
    }
    let nextObj = null
    if (parent) {
      parent.Child.forEach((e,i)=> {
        if (data.id == e.id) {
          nextObj = parent.Child[i-1]
        }
      })
    }else {
      state.data.forEach((e,i) => {
        if (data.id == e.id) {
          nextObj = state.data[i-1]
        }
      })
    }
    changeSort(data,nextObj)
  }else { // 菜单下移
    if (disabled) {
      return
    }
    let nextObj = null
    if (parent) {
      parent.Child.forEach((e,i)=> {
        if (data.id == e.id) {
          nextObj = parent.Child[i+1]
        }
      })
    }else {
      state.data.forEach((e,i) => {
        if (data.id == e.id) {
          nextObj = state.data[i+1]
        }
      })
    }
    changeSort(data,nextObj)
  }
  if (menuFormRef) {
    nextTick().then(() => {
      menuFormRef.value.menuRef.validate(valid => {
        if (!valid) {
          menuFormRef.value.menuRef.clearValidate()
        }
      })
    })
  } // 清除表单验证
} // 各种操作按钮

const changeSort = (data,nextObj) => {
  let params = [
    {
      id: data.id,
      sort: nextObj.sort
    },
    {
      id: nextObj.id,
      sort: data.sort
    }
  ]
  axios
    .put(`/apaas/system/v5/menu/sort`,params)
    .then((res) => {
      if (res.data.code == 200) {
        ElMessage.success(res.data.data)
        getMenuTree()
      }else {
        ElMessage.error(res.data.data)
      }
    })
} // 菜单上下移

const closeAction = () => {
  actionFlag.value = false;
} // 点击其他地方，菜单操作框关闭

const saveMenu = (el,type) => {
  el.menuRef.validate(valid => {
    if (valid) {
      let params = {
        menu_name: el.menuForm.menu_name,
        menu_type: el.menuForm.menu_type,
        dict_group_id: el.menuForm.dict_group_id,
        state: el.menuForm.state,
        menu_url: el.menuForm.menu_url,
        menu_logo: el.menuForm.menu_logo,
      }
      if (state.selectData.id) { // 编辑
        axios
          .put(`/apaas/system/v5/menu/${state.selectData.id}`,params)
          .then((res) => {
            if (res.data.code == 200) {
              ElMessage.success(res.data.msg)
              getMenuTree()
            }else {
              ElMessage.error(res.data.data)
            }
          })
        }else { // 新增
        if (state.selectParentData) {
          if (state.selectParentData.menu_type == 1 && el.menuForm.menu_type == 0) {
            ElMessage.error("菜单之下不可以新建目录")
            return
          }
        }
        if(type == 1) { // 新增本级
          params.p_menu_id = state.selectParentData ? state.selectParentData.menu_id : ""
        }else { // 新增下级
          params.p_menu_id = state.selectParentData.menu_id
        }
        if (params.menu_type != 0) {
          params.dict_group_id = ""
        }
        axios
          .post(`/apaas/system/v5/menu/add`,params)
          .then((res) => {
            if (res.data.code == 200) {
              ElMessage.success(res.data.data)
              state.selectData = null
              getMenuTree()
            }else {
              ElMessage.error(res.data.data)
            }
          })
      }
    }
  })
} // 保存按钮，新增或编辑菜单

onBeforeMount(()=>{
  window.addEventListener("click", closeAction)
  window.addEventListener("scroll", closeAction,true)
  getMenuTree()
})

onBeforeUnmount(()=>{
  window.removeEventListener('click', closeAction);
  window.removeEventListener('scroll', closeAction);
  
})

const {
  data,
  search,
  defaultProps,
  selectParentData,
  selectData,
  menuFormData,
  addType,
} = toRefs(state)
</script>

<style scoped>

.flex_left {
  background-color: #fff;
  height: calc(100% - 16px);
  width: 320px;
  box-shadow: 0px 1px 4px 0px 
		rgba(0, 7, 101, 0.15);
	border-radius: 6px;
  margin-right: 10px;
  overflow: hidden;
}
.flex_right {
  background-color: #fff;
  height: calc(100% - 16px);
  flex: 1;
  box-shadow: 0px 1px 4px 0px 
		rgba(0, 7, 101, 0.15);
	border-radius: 6px;
  overflow: hidden;
}

.tree_content {
  overflow: hidden;
  height: calc(100% - 4px);
  position: relative;
}
.search {
  padding: 16px 16px 10px;
}
.tree {
  overflow: auto;
  height: calc(100% - 65px);
}
.tree :deep().el-tree-node>.el-tree-node__content {
  /* padding: 0 16px!important; */
} 
.tree :deep() .el-tree-node>.el-tree-node__children {
  overflow: unset;
  /* padding-left: 16px; */
}

.tree-action-box {
  display: none;
  position: absolute;
  right: 0px;
  background-color: #f2f3f7;
  width: 44px;
  text-align: center;
  height: 36px;
  line-height: 36px;
}
.tree .el-tree-node__content:hover .tree-action-box {
  display: inline-block;
}
.tree .el-tree {
  position: static!important;
}
.tree .el-tree :deep().el-tree-node__content{
  height: 36px!important;
}
.tree .el-tree :deep().el-tree-node__content:hover {
  background-image: linear-gradient(90deg, 
		rgba(255, 255, 255, 0.05) 83%, 
		rgba(0, 0, 0, 0.05) 86%);
}
.tree-more {
  font-size: 12px;
  color: #3759be;
}
.tree-action {
  width: 144px;
  background-color: #ffffff;
  box-shadow: 0px 1px 4px 0px rgba(0, 7, 101, 0.15);
  padding: 4px 0;
  border-radius: 4px;
  position: fixed;
  z-index: 9;
}
.tree-action .action {
  width: 100%;
  height: 34px;
  line-height: 34px;
  padding-left: 16px;
  font-size: 14px;
  color: #202531;
  cursor: pointer;
}
.tree-action .action:hover {
  background-color: #f2f3f7;
  color: #3759be;
}

.tree-action .disable{
  cursor: not-allowed;
  color: #616f94;
}
.tree-action .disable:hover{
  background-color: #fff;
  color: #616f94;
}
.main_container {
  height: 100%;
}
</style>

<style lang="scss" scoped>
.main_container {
  .base-info {
    height: calc(100% - 68px);
    padding: 40px 0 0 40px;
  }
  .base-btn {
    height: 68px;
    border-top: 1px solid #e6e9ef;
    text-align: right;
    padding: 16px;
    .el-button {
      width: 92px;
    }
  }
}
</style>