<template>
  <a-card :class="[{ [$style.treewrap]: !hideLeftBtn }, { [$style.collapse]: fold }]">
    <a-input-search
      v-if="treeData.length > 0 && !hideSearch"
      placeholder="请输入"
      allow-clear
      @change="onSearchChange"
    />
    <a-spin :spinning="spinning" :class="$style.spin" />
    <a-empty v-if="empty" />
    <a-tree
      v-if="treeData.length > 0"
      show-icon
      :expanded-keys.sync="expandedKeys"
      :auto-expand-parent="autoExpandParent"
      :tree-data="treeData"
      :replace-fields="replacefields"
      :selected-keys.sync="selectedkey"
      @select="onSelect"
      @expand="onExpand"
    >
      <template v-slot:title="{ text }">
        <span v-if="text.indexOf(searchValue) > -1">
          {{ text.substr(0, text.indexOf(searchValue))
          }}<span :class="$style.searchColor">{{ searchValue }}</span
          >{{ text.substr(text.indexOf(searchValue) + searchValue.length) }}</span
        ><span v-else>{{ text }}</span>
      </template>
    </a-tree>
    <a-button v-if="!hideLeftBtn" type="primary" :class="$style.fold" @click="foldClick">
      <a-icon :type="icontype" />
    </a-button>
  </a-card>
</template>

<script>
import lodash from 'lodash'
import axios from '@/common/services/axios-instance'
import components from './_import-components/km-tree-import'

export default {
  name: 'KmTree',
  components,
  props: {
    dataUrl: {
      type: String,
      required: true,
    },
    hideLeftBtn: {
      type: Boolean,
      default: false,
    },
    hideSearch: {
      type: Boolean,
      default: false,
    },
    // 默认选中的节点
    defaultselectedkey: {
      type: String,
      default: '',
    },
  },
  data() {
    return {
      searchValue: '',
      dataList: [], // 数组dataList，搜索要用

      spinning: true,
      empty: false,

      treeData: [],
      expandedKeys: [],
      autoExpandParent: true,
      replacefields: {
        title: 'text',
        key: 'id',
      },

      selectedkey: [], // 选中的节点

      icontype: 'left',
      fold: false,
    }
  },
  watch: {
    // prop变化时，刷新表格
    dataUrl() {
      this.loadData()
    },

    defaultselectedkey(value) {
      this.selectedkey = [value]
      this.expandedKeys = [value]
      this.fnGetNodeItem(this.treeData, value).then((item) => {
        this.$emit('treeSelectd', item)
      })
    },
  },
  created() {
    this.loadData()
  },

  methods: {
    transformData(data) {
      return data.map((d) => {
        const { children, checkable, selectable, leaf, ...rest } = d
        return {
          ...rest,
          checkable: checkable ?? false,
          selectable: selectable ?? true,
          isLeaf: leaf ?? true,
          key: d[this.optionValue],
          title: d[this.optionName],
          children: children && this.transformData(children),
          scopedSlots: { title: 'title' },
          originalValue: rest,
        }
      })
    },

    // 搜索相关
    onExpand(expandedKeys) {
      this.expandedKeys = expandedKeys
      this.autoExpandParent = false
    },

    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
    },

    // 获取当前选中节点的根节点
    getRootKey(key) {
      let rootKey
      const strKey = key.toString()
      if (this.treeData.length === 1) {
        rootKey = this.treeData[0].id
      } else {
        for (let index = 0; index < this.treeData.length; index++) {
          var item = this.treeData[index]
          // 先判断选中的是不是根节点
          if (item.id === strKey) {
            rootKey = key
            break
          } else {
            if (this.getParentKey(strKey, [item])) {
              // 说明选中的是这个根节点下的分类
              rootKey = item.id
              break
            }
          }
        }
      }
      return parseInt(rootKey)
    },

    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)
      Object.assign(this, {
        expandedKeys,
        searchValue: value,
        autoExpandParent: true,
      })
    },
    // 处理搜索用的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
        this.dataList.push({ key, id: key, title: title, props })
        if (node.children) {
          this.generateList(node.children)
        }
      }
    },

    // 获取树数据
    loadData() {
      const req = {
        url: this.dataUrl,
        method: 'get',
      }

      return axios(req).then((res) => {
        this.spinning = false
        if (res.data) {
          let newArr = []
          if (lodash.isArray(res.data)) {
            newArr = res.data
          } else {
            if (lodash.isObject(res.data)) {
              newArr.push(res.data)
            }
          }

          this.treeData = this.transformData(newArr)
          this.empty = false

          if (this.defaultselectedkey) {
            this.expandedKeys = [this.defaultselectedkey] // 默认展开的结点
            this.selectedkey = [this.defaultselectedkey]
            this.fnGetNodeItem(this.treeData, this.defaultselectedkey).then((item) => {
              this.$emit('treeSelectd', item)
            })
          } else {
            this.expandedKeys = [newArr[0].id]
            this.selectedkey = [newArr[0].id]
            this.$emit('treeSelectd', res.data[0])
          }

          // 生成搜索要用的数组
          this.generateList(this.treeData)
        } else {
          this.treeData = []
          this.empty = true
          this.$emit('treeSelectd')
        }
      })
    },

    // 获取被选中的节点
    fnGetNodeItem(data, key) {
      return new Promise((resolve, reject) => {
        for (var i in data) {
          if (data[i].id === key) {
            resolve(data[i])
            break
          } else {
            if (data[i].children) {
              this.fnGetNodeItem(data[i].children, key).then((data) => {
                resolve(data)
              })
            }
          }
        }
      })
    },

    // 刷新树
    refresh() {
      this.treeData = []
      this.spinning = true
      const req = {
        url: this.dataUrl,
        method: 'get',
      }

      return axios(req).then((res) => {
        this.spinning = false
        if (res.data) {
          let newArr = []
          if (lodash.isArray(res.data)) {
            newArr = res.data
          } else {
            if (lodash.isObject(res.data)) {
              newArr.push(res.data)
            }
          }
          this.treeData = this.transformData(newArr)

          this.empty = false
          // 生成搜索要用的数组
          this.generateList(this.treeData)
          // this.expandedKeys = [newArr[0].id] // 默认展开顶结点
        } else {
          this.treeData = []
          this.empty = true
        }
      })
    },

    // 树选中调用
    onSelect(selectedKeys, info) {
      this.selectedkey = selectedKeys
      this.$emit('treeSelectd', info)
    },

    // 展示/隐藏树的小箭头点击事件
    foldClick() {
      this.fold = !this.fold
      if (this.fold) {
        this.icontype = 'right'
      } else {
        this.icontype = 'left'
      }
    },
  },
}
</script>

<style module lang="scss">
@use '@/common/design' as *;
.spin {
  width: 100%;
  line-height: 30;
}
.treewrap {
  :global(.ant-input-search) {
    margin: 8px 0;
    overflow: hidden;
  }

  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-x: auto;
    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;
    }
  }
}
.search-color {
  color: $primary-color;
}
</style>
