<template>
  <a-card
    ref="scroll"
    :class="[
      $style.treewrap,
      $style.ywlxtree,
      { [$style.collapse]: fold, [$style.single]: single },
    ]"
  >
    <!-- 选择部门 -->
    <div :class="$style.frameDiv">
      <a-select
        v-model="framevalue"
        :label-in-value="true"
        :options="frameOptions"
        @change="changeframe"
      >
      </a-select>
      <!-- 新建审计框架按钮 -->
      <a-button v-if="showbtns" type="primary" @click="createframe">
        新建
      </a-button>
    </div>

    <a-spin :spinning="spinning" :class="$style.spin" />
    <a-empty v-if="empty" />
    <a-dropdown
      v-else
      v-model="showMenu"
      :get-popup-container="() => this.$refs.scroll.$el"
      :trigger="['contextmenu']"
      :disabled="single"
      @visibleChange="menuVisibleChange"
    >
      <a-tree
        ref="frameTree"
        v-model="checkedKeys"
        :block-node="false"
        :show-icon="true"
        :show-line="true"
        :checkable="checkable"
        :draggable="draggable"
        :check-strictly="true"
        :tree-data="treeData"
        :replace-fields="replaceFields"
        :selected-keys="defaultSelectedKeys"
        :expanded-keys="expandedKeys"
        :default-expanded-keys="defaultTreeExpandedKeys"
        :load-data="onLoadData"
        @select="treeSelect"
        @check="treeCheck"
        @expand="onExpand"
        @rightClick="treeRightClick"
        @contextmenu.native.capture="treeRightClickNative"
        @dragenter="onDragEnter"
        @drop="onDrop"
      >
        <template v-slot:title="{ text, props }">
          <span v-if="text.indexOf(searchValue) > -1">
            {{ text.substr(0, text.indexOf(searchValue))
            }}<span :class="$style.active">{{ searchValue }}</span
            >{{ text.substr(text.indexOf(searchValue) + searchValue.length) }}</span
          ><span v-else>{{ text }}</span>
          <!-- 后台返回数量，如果有数量的话就显示 -->
          <span v-if="props.count > 0">（{{ props.count }}）</span>
        </template>
        <!-- 如果已配置负责人，则展示用户图标 -->
        <template slot="hasuser" slot-scope="item">
          <a-icon
            :class="$style.itemIcon"
            type="team"
            :title="'审计人员：' + getItemUser(item.props.username)"
          />
        </template>
      </a-tree>
      <a-menu slot="overlay" @click="menuClick">
        <a-menu-item key="1" :disabled="!selectedNodeHasSelectableChild">
          <a-icon type="check" />选中下一级节点
        </a-menu-item>
        <a-menu-item key="2" :disabled="!selectedNodeHasSelectableChild">
          <a-icon type="close" />取消下一级节点
        </a-menu-item>
      </a-menu>
    </a-dropdown>
    <a-button v-if="showPrimary" type="primary" :class="$style.fold" @click="foldClick">
      <a-icon :type="icontype" />
    </a-button>
  </a-card>
</template>

<script>
import { Message } from 'ant-design-vue'
import iamAuditFrameService from './iam-audit-frame-service'
import components from './_import-components/iam-audit-frame-tree-import'

// 判断是否已经选择
function isChecked(selectedKeys, eventKey) {
  return selectedKeys.indexOf(eventKey) === -1
}

export default {
  name: 'IamAuditFrameTree',
  metaInfo: {
    title: '审计框架树',
  },
  components,
  props: {
    // 默认选中节点
    selectedKeys: {
      type: Array,
      default: function() {
        return []
      },
    },
    // 是否开启搜索
    isSearch: {
      type: Boolean,
      default: false,
    },

    // 根节点名称
    topNodeText: {
      type: String,
      default: '审计框架',
    },
    // 地址树接口数据源
    treeparams: {
      type: Object,
      default: () => {
        return {}
      },
    },
    // 默认展开节点id
    defaultExpandedKeys: {
      type: Array,
      default: () => {
        return ['0']
      },
    },

    // 部门下拉框列表值
    depOptions: {
      type: Array,
      default: () => {
        return []
      },
    },
    // 部门下拉框默认值
    defaultDepValue: {
      type: Array,
      default: () => {
        return []
      },
    },
    // 是否显示隐藏按钮
    showPrimary: {
      type: Boolean,
      default: false,
    },
    // 地址树是否单选
    single: {
      type: Boolean,
      default: false,
    },
    // 默认展示的审计框架名称
    frameName: {
      type: String,
      default: null,
    },
    // 是否展示审计事项
    isShowItem: {
      type: Boolean,
      default: true,
    },
    draggable: {
      type: Boolean,
      default: true,
    },
    checkable: {
      type: Boolean,
      default: true,
    },
    createnewframe: {
      type: Boolean,
      default: true,
    },
    showbtns: {
      type: Boolean,
      default: false,
    },
  },
  data() {
    return {
      projectId: this.$root.$route.query.projectId,
      defaultTreeExpandedKeys: [],
      defaultSelectedKeys: [],
      framevalue: {}, // 选择的组织数据
      frameOptions: [], // 下拉框默认值
      checkedKeys: {
        checked: [],
        halfChecked: [],
      }, // 选中的节点数据
      treeData: [],
      dataList: [], // 数组dataList，搜索要用
      spinning: true,
      empty: false,
      icontype: 'left',
      fold: false,
      replaceFields: {
        title: 'text',
        key: 'id',
      },
      expandedKeys: ['0'],
      backupsExpandedKeys: [],
      autoExpandParent: false,
      searchValue: '',
      searchStr: '',
      defaultTopNodeText: '审计框架',
      defaultTopNodeId: '0',
      key: 0,
      allCheckedKeys: [],
      allCheckedObj: null,
      selectedNode: undefined,
      showMenu: false,
    }
  },
  computed: {
    selectedNodeHasSelectableChild() {
      return this.selectedNode?.dataRef.children?.some((item) => !item.disabled)
    },
  },
  created() {
    // 如果有默认展开节点，则赋值
    if (this.defaultExpandedKeys) {
      this.defaultTreeExpandedKeys = [...this.defaultExpandedKeys]
    }
    // 如果有传根节点名称，则赋值
    if (this.topNodeText) {
      this.defaultTopNodeText = this.topNodeText
    }
    // 如果有传默认选中节点，则赋值
    if (this.selectedKeys.length > 0) {
      this.checkedKeys.checked = [...this.selectedKeys]
      this.defaultSelectedKeys = [...this.selectedKeys]
    }
  },
  mounted() {
    // 加载时获取下拉框内容
    iamAuditFrameService.getFrameListInfo(this.projectId).then((res) => {
      res.data.forEach((item, index) => {
        // 先把第一个获取的赋给默认值
        if (index === 0) {
          this.framevalue = { key: item.id, label: item.frameName }
        }
        // 如果有传默认值，则显示默认值
        if (this.frameName && this.frameName === item.frameName) {
          this.framevalue = { key: item.id, label: item.frameName }
        }
        this.frameOptions.push({
          value: item.id,
          label: item.frameName,
        })
      })

      this.initTreeData()
    })
  },
  methods: {
    hideContextMemu() {
      this.showMenu = false
      this.menuVisibleChange(false)
    },
    menuVisibleChange(visible) {
      if (!visible) this.selectedNode = undefined
    },
    treeRightClick({ node }) {
      // 记录当前点击的节点
      if (this.single) return
      this.selectedNode = node
    },
    treeRightClickNative(evt) {
      // 右键如果没有点击到树节点，不触发右键菜单
      if (this.single) return
      if (evt.target.nodeName !== 'SPAN') evt.stopPropagation()
    },
    menuClick(menu) {
      this.selectedNode.dataRef.children?.forEach((item) => {
        if (!item.disabled) this.itemSelect(item.id, menu.key === '1')
      })
      this.hideContextMemu()
    },
    itemSelect(key, checked) {
      if (checked) {
        if (!this.checkedKeys.checked.includes(key)) {
          this.checkedKeys.checked.push(key)
        }
      } else {
        this.checkedKeys.checked.splice(this.checkedKeys.checked.indexOf(key), 1)
      }
    },
    // 审计人员姓名去重
    getItemUser(userS) {
      const userList = new Set(userS.split(','))
      return [...userList].join(',')
    },
    onDragEnter(info) {
      // expandedKeys 需要受控时设置
      this.expandedKeys = info.expandedKeys
    },
    // 拖拽节点方法
    onDrop(info) {
      // 被插入节点信息
      const dropKey = info.node.eventKey
      const dropNode = info.node.dataRef
      // 拖拽节点信息
      const dragKey = info.dragNode.eventKey
      const dragNode = info.dragNode.dataRef

      const dropPos = info.node.pos.split('-')
      // -1表示之前 0表示合并 1表示之后
      const dropPosition = info.dropPosition - Number(dropPos[dropPos.length - 1])
      // 分类合并至事项内
      if (dragNode.props.isItem === false && dropNode.props.isItem && dropPosition === 0) {
        Message.info('不能将分类合并至事项内', 1)
        return false
      }
      // 事项合并至事项
      if (dragNode.props.isItem && dropNode.props.isItem && dropPosition === 0) {
        Message.info('不能将事项合并至事项内', 1)
        return false
      }
      const loop = (data, key, callback) => {
        data.forEach((item, index, arr) => {
          if (item.id === key) {
            return callback(item, index, arr)
          }
          if (item.children) {
            return loop(item.children, key, callback)
          }
        })
      }
      const data = this.treeData

      // Find dragObject
      let dragObj
      loop(data, dragKey, (item, index, arr) => {
        arr.splice(index, 1)
        dragObj = item
      })
      if (!info.dropToGap) {
        // Drop on the content
        loop(data, dropKey, (item) => {
          item.children = item.children || []
          // where to insert 示例添加到尾部，可以是随意位置
          item.children.push(dragObj)
        })
      } else if (
        (info.node.children || []).length > 0 && // Has children
        info.node.expanded && // Is expanded
        dropPosition === 1 // On the bottom gap
      ) {
        loop(data, dropKey, (item) => {
          item.children = item.children || []
          // where to insert 示例添加到尾部，可以是随意位置
          item.children.unshift(dragObj)
        })
      } else {
        let ar
        let i
        loop(data, dropKey, (item, index, arr) => {
          ar = arr
          i = index
        })
        if (dropPosition === -1) {
          ar.splice(i, 0, dragObj)
        } else {
          ar.splice(i + 1, 0, dragObj)
        }
      }
      this.treeData = data

      // 拖拽完成，调用接口
      const dragParams = {
        nodeType: dragNode.props.isItem ? 'item' : 'category', // category/item
        nodeId: dragNode.id.toString().replace('sx_', ''),
        targetnodeType: dropNode.props.isroot
          ? 'root'
          : dropNode.props.isItem
          ? 'item'
          : 'category', // root/category/item
        targetnodeId: dropNode.id.toString().replace('sx_', ''),
        position: dropPosition, // -1 0 1  之前 合并 之后
      }

      iamAuditFrameService.dragNode(dragParams)
    },

    // 点击地址树展开时调用
    onLoadData(treeNode) {
      const params = {
        parentId: treeNode.dataRef.props.id,
        frameId: this.framevalue.key,
        isShowItem: this.isShowItem,
      }
      return iamAuditFrameService.getFrameTreeNodeInfo(params).then((res) => {
        res.data.forEach((d) => {
          d.props.id = d.id
          if (d.props.isItem) {
            d.id = 'sx_' + d.id
          }
        })
        treeNode.dataRef.children = [...res.data]
        this.treeData = this.transformData([...this.treeData])
        this.generateList(this.treeData)
      })
    },
    // 初始化地址树
    initTreeData(depId) {
      const params = {
        parentId: this.framevalue.key,
        frameId: this.framevalue.key,
        isShowItem: this.isShowItem,
      }
      iamAuditFrameService.getFrameTreeNodeInfo(params).then((res) => {
        this.spinning = false
        const treeNode = [
          {
            id: -1,
            text: this.framevalue.label,
            isLeaf: false,
            props: {
              isroot: true,
              id: this.framevalue.key,
            },
            key: 0,
          },
        ]
        if (res.data.length > 0) {
          res.data.forEach((d) => {
            d.props.id = d.id
            if (d.props.isItem) {
              d.id = 'sx_' + d.id
            }
          })
          treeNode[0].children = [...res.data]
        }
        this.treeData = this.transformData(treeNode)
        this.expandedKeys = [this.framevalue.key]
        this.generateList(this.treeData)
        this.$emit('treeinit', this.framevalue)
      })
    },
    // 审计框架下拉框选择时触发
    changeframe(value, option) {
      this.initTreeData(value)
      this.$emit('changeframe', value, option)
    },
    /**
     * 显示分类负责人
     */
    showUser(item) {
      this.$emit('showUser', item)
    },

    /***
     * 选中复选框时的事件
     */
    treeCheck(allKeys, echecked) {
      this.$emit('checkedKeys', echecked.node.dataRef, echecked.checkedNodes)
    },
    getTree(node) {
      const removeIndex = []
      node.children.forEach((item, index) => {
        if (item.hidden === true) {
          removeIndex.push(index)
        } else {
          if (item.children) {
            this.getTree(item)
          }
        }
      })
      // 删除元素
      removeIndex.forEach((oneindex, index) => {
        node.children.splice(oneindex - index, 1)
      })
    },

    // 点击树
    treeSelect(selectedKeys, info) {
      this.defaultSelectedKeys = selectedKeys
      this.$emit('treeSelect', selectedKeys, info)
    },
    // 筛选树
    onSearchChange(e) {
      const value = e.target.value

      const expandedKeys = this.dataList
        .map((item) => {
          if (item.title.indexOf(value) > -1) {
            return this.getParentKey(item.key, this.treeData)
          }
          return null
        })
        .filter((item, i, self) => item && self.indexOf(item) === i)

      expandedKeys.unshift('0') // 顶结点永远展开

      Object.assign(this, {
        expandedKeys,
        searchValue: value,
        autoExpandParent: true,
      })
    },

    getParentKey(key, tree) {
      let parentKey
      for (let i = 0; i < tree.length; i++) {
        const node = tree[i]
        if (node.children) {
          if (node.children.some((item) => item.id === key)) {
            parentKey = node.id
          } else if (this.getParentKey(key, node.children)) {
            parentKey = this.getParentKey(key, node.children)
          }
        }
      }
      return parentKey
    },

    transformData(data) {
      return data.map((d) => {
        const { children, ...rest } = d
        if (rest.props.isItem !== undefined) {
          rest.isLeaf = rest.props.isItem
        }
        return {
          ...rest,
          children: children && this.transformData(children),
          scopedSlots: { title: 'title' },
        }
      })
    },

    // 处理搜索用的dataList
    generateList(data) {
      for (let i = 0; i < data.length; i++) {
        const node = data[i]
        const key = node.id
        const title = node.text
        const props = node.props
        // 用来判断此几点是否已经配置了用户，需要后台返回标识位进行判断
        if (props.showuser) {
          data[i].scopedSlots.icon = 'hasuser'
        }
        this.dataList.push({ key, id: key, title: title, props })
        if (node.children) {
          this.generateList(node.children)
        }
      }
    },

    onExpand(expandedKeys) {
      // 用户点击展开时，取消自动展开效果
      this.expandedKeys = expandedKeys
      this.autoExpandParent = false
    },
    // 小箭头点击事件
    foldClick() {
      this.fold = !this.fold
      if (this.fold) {
        this.icontype = 'right'
      } else {
        this.icontype = 'left'
      }
    },
    // 组织下拉框change时触发
    changedep(value, option, extra) {
      this.key++
      if (!value) {
        this.defaultTreeExpandedKeys = ['0']
        this.defaultSelectedKeys = ['0']
        this.defaultTopNodeId = '0'
        this.defaultTopNodeText = this.topNodeText
      } else {
        this.defaultTreeExpandedKeys = [extra.triggerNode.dataRef.value]
        this.defaultSelectedKeys = [extra.triggerNode.dataRef.value]
        this.defaultTopNodeId = extra.triggerNode.dataRef.value
        this.defaultTopNodeText = extra.triggerNode.dataRef.title
      }
      this.initTreeData(value)
      this.$emit('depChanged', value, option)
    },
    // 刷新树方法
    refreshTree() {
      this.key++
    },
    // 新建审计框架
    createframe() {
      this.$emit('createframe')
    },
  },
}
</script>

<style module lang="scss">
@use '@/common/design' as *;
.spin {
  width: 100%;
  line-height: 30;
}
.ywlxtree {
  :global(.ant-tree-title) {
    display: inline-block;
    width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  :global(.ant-input-search) {
    margin: 8px 0;
    overflow: hidden;
  }
  .active {
    color: $primary-color;
  }
  :global(.ant-select) {
    width: 100%;
    overflow: hidden;
  }
}
.treewrap {
  border: 1px solid #efefef;
  position: relative;
  display: flex;
  flex-direction: column;
  width: 20%;
  min-height: 100%;
  margin-right: $padding-lg;
  transition: width 0.2s;
  .fold {
    position: absolute;
    top: calc(50% - 30px);
    right: -15px;
    z-index: 2;
    width: 15px;
    height: 75px;
    padding: 0;
    border-radius: 0 10px 10px 0;
  }
  :global(.ant-tree) {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  :global(.ant-card-body) {
    background: $white;
  }
}
.collapse {
  width: 0;
  :global(.ant-card-body) {
    background: transparent;
    :global(.ant-empty) {
      display: none;
    }
  }
}
// 单选样式
.single {
  :global .ant-tree-checkbox {
    .ant-tree-checkbox-inner {
      border-radius: 100px;
      &::after {
        position: absolute;
        top: 3px;
        left: 3px;
        display: table;
        width: 8px;
        height: 8px;
        content: ' ';
        background-color: $primary-color;
        border: 0;
        border-radius: 8px;
        opacity: 0;
        transition: all 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
        transform: scale(0);
      }
    }
    &.ant-tree-checkbox-checked {
      &::after {
        position: absolute;
        top: 16.67%;
        left: 0;
        width: 100%;
        height: 66.67%;
        content: '';
        border: 1px solid #1890ff;
        border-radius: 50%;
        animation: antRadioEffect 0.36s ease-in-out;
        animation-fill-mode: both;
      }
      .ant-tree-checkbox-inner {
        background-color: $white;
        &::after {
          opacity: 1;
          transition: all 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
          transform: scale(1);
        }
      }
    }
  }
}
.frame-div {
  display: inline-flex;
  width: 100%;
  :global(.ant-select) {
    width: calc(100% - 80px);
  }
  button {
    margin-left: 10px;
  }
}
.item-icon {
  color: red;
}
</style>
