<template>
  <view class="da-tree" :style="{'--theme-color': themeColor}">
    <scroll-view class="da-tree-scroll" :scroll-y="true" :scroll-x="false">
      <view
        class="da-tree-item"
        :class="{'is-show': item.show}"
        :style="{paddingLeft: item.level * indent + 'rpx'}"
        v-for="item in datalist"
        :key="item.key">
        <view
          v-if="item.showArrow"
          class="da-tree-item__icon"
          @click="handleExpandedChange(item)">
          <view :class="['da-tree-item__icon--arr','is-loading']" v-if="loadLoading && item.loading"></view>
          <view :class="['da-tree-item__icon--arr','is-expand', {'is-right':!item.expand}]" v-else></view>
        </view>
        <view v-else class="da-tree-item__icon"></view>
        <view
          class="da-tree-item__checkbox"
          :class="[`da-tree-item__checkbox--${checkboxPlacement}`,{'is--disabled': item.disabled}]"
          v-if="showCheckbox"
          @click="handleCheckChange(item)">
          <view class="da-tree-item__checkbox--icon da-tree-checkbox-checked" v-if="item.checkedStatus === isCheckedStatus"></view>
          <view class="da-tree-item__checkbox--icon da-tree-checkbox-indeterminate" v-else-if="item.checkedStatus === halfCheckedStatus"></view>
          <view class="da-tree-item__checkbox--icon da-tree-checkbox-outline" v-else></view>
        </view>
        <view
          class="da-tree-item__checkbox"
          :class="[`da-tree-item__checkbox--${checkboxPlacement}`,{'is--disabled': item.disabled}]"
          v-if="!showCheckbox && showRadioIcon"
          @click="handleRadioChange(item)">
          <view class="da-tree-item__checkbox--icon da-tree-radio-checked" v-if="item.checkedStatus === isCheckedStatus"></view>
          <view class="da-tree-item__checkbox--icon da-tree-radio-indeterminate" v-else-if="item.checkedStatus === halfCheckedStatus"></view>
          <view class="da-tree-item__checkbox--icon da-tree-radio-outline" v-else></view>
        </view>
        <view class="da-tree-item__label" :class="'da-tree-item__label--'+item.checkedStatus" @click="handleLabelClick(item)">{{ item.label }} <text class="da-tree-item__label--append" v-if="item.append">{{ item.append }}</text></view>
      </view>
    </scroll-view>
  </view>
</template>

<script>
import {
  unCheckedStatus,
  halfCheckedStatus,
  isCheckedStatus,
  deepClone,
  getAllNodeKeys,
  getAllNodes,
  logError,
  isArray,
  isString,
  isNumber,
  isFunction,
} from './utils'
import basicProps from './props'

export default {
  name: 'DaTree',
  props: basicProps,
  data() {
    return {
      unCheckedStatus,
      halfCheckedStatus,
      isCheckedStatus,
      /** 原始的树数据 */
      dataRef: [],
      /** 处理后的一维树项数据 */
      datalist: [],
      /** 处理后的以key为键值的树项数据 */
      datamap: {},
      /** 默认的展开数据 */
      expandedKeys: [],
      /** 默认的已选数据 */
      checkedKeys: null,
      /** 加载状态 */
      loadLoading: false,
      fieldMap: {
        value: 'value',
        label: 'label',
        children: 'children',
        disabled: 'disabled',
        append: 'append',
        leaf: 'leaf',
        sort: 'sort',
      },
    }
  },
  watch: {
    defaultExpandedKeys: {
      // deep: true,
      immediate: true,
      handler: function(v) {
        if (v?.length) {
          this.expandedKeys = v
        } else {
          this.expandedKeys = []
        }

        // if (v) this.checkInitData(this.datalist)
      },
    },
    defaultCheckedKeys: {
      // deep: true,
      immediate: true,
      handler: function(v) {
        if (this.showCheckbox) {
          if (v?.length) {
            this.checkedKeys = v
          } else {
            this.checkedKeys = []
          }
        } else {
          if (v || v === 0) {
            this.checkedKeys = v
          } else {
            this.checkedKeys = null
          }
        }
        // this.checkInitData(this.datalist)
      },
    },
    data: {
      deep: true,
      immediate: true,
      handler: function(v) {
        this.dataRef = deepClone(v)
        setTimeout(() => {
          this.initData()
        }, 36)
      },
    },
  },
  methods: {
    /**
     * 初始化数据结构
     */
    initData() {
      this.fieldMap = {
        value: this.field?.key || this.field?.value || this.valueField || 'value',
        label: this.field?.label || this.labelField || 'label',
        children: this.field?.children || this.childrenField || 'children',
        disabled: this.field?.disabled || this.disabledField || 'disabled',
        append: this.field?.append || this.appendField || 'append',
        leaf: this.field?.leaf || this.leafField || 'leaf',
        sort: this.field?.sort || this.sortField || 'sort',
      }

      const data = deepClone(this.dataRef)
      this.datalist = []
      this.datamap = {}

      // clean tree
      this.handleTreeData(data)
      // flat tree
      this.datalist = this.checkInitData(this.datalist)

      console.log('init datalist', this.datalist)
      console.log('init datamap', this.datamap)
    },

    /**
     * 转换为节点数据
     * @param data
     * @param parent
     * @param level
     */
    handleTreeData(data = [], parent = null, level = 0, insertIndex = -1) {
      return data.reduce((prev, cur, index) => {
        const key = cur[this.fieldMap.value]
        const children = cur[this.fieldMap.children] || null
        const newItem = this.createNewItem(cur, index, parent, level)
        if (insertIndex > -1) {
          // 插入子项尾部
          const index = (parent.childrenKeys?.length || 0) + insertIndex + 1
          if (!parent?.childrenKeys?.includes(key)) {
            this.datamap[key] = newItem
            this.datalist.splice(index, 0, newItem)
            parent.children.push(newItem)
            if (newItem.parentKeys?.length) {
              newItem.parentKeys.forEach(k => {
                this.datamap[k].childrenKeys = [...this.datamap[k].childrenKeys, newItem.key]
              })
            }
          }
        } else {
          this.datamap[key] = newItem
          this.datalist.push(newItem)
        }

        const hasChildren = children && children.length > 0
        if (hasChildren) {
          const childrenData = this.handleTreeData(children, newItem, level + 1)
          // childrenData.sort((a, b) => a.sort - b.sort)
          newItem.children = childrenData
          const childrenKeys = childrenData.reduce((p, k) => {
            const keys = k.childrenKeys
            p.push(...keys, k.key)
            return p
          }, [])
          newItem.childrenKeys = childrenKeys
        }
        prev.push(newItem)
        return prev
      }, [])
    },

    /**
     * 创建节点
     * @param item
     * @param index
     * @param parent
     * @param level
     */
    createNewItem(item, index, parent, level) {
      const key = item[this.fieldMap.value]
      const label = item[this.fieldMap.label]
      const sort = item[this.fieldMap.sort] || 0
      const children = item[this.fieldMap.children] || null
      const append = item[this.fieldMap.append] || null
      let disabled = item[this.fieldMap.disabled] || false
      // 优先继承父级禁用属性
      disabled = parent?.disabled || disabled
      let isLeaf = isFunction(this.isLeafFn) ? this.isLeafFn(item) : (item[this.fieldMap.leaf] || false)
      // const hasChildren = children && children.length > 0
      const isEmptyChildren = children && children.length === 0
      let showArrow = true
      // let isLeaf = !hasChildren
      let expand = this.defaultExpandAll || false
      // 是否异步加载模式
      const isLoadMode = this.loadMode && isFunction(this.loadApi)

      if (!children) {
        expand = false
        if (isLoadMode) {
          showArrow = true
        } else {
          isLeaf = true
          showArrow = false
        }
      }

      if (isEmptyChildren) {
        expand = false
        if (isLoadMode) {
          showArrow = true
        } else {
          isLeaf = true
          showArrow = false
        }
      }

      if (isLeaf) {
        showArrow = false
        expand = false
      } else {
        showArrow = true
      }

      // onlyRadioLeaf 单选只能选择末级节点
      if (!this.showCheckbox) {
        if (this.onlyRadioLeaf) {
          if (!isLeaf) {
            disabled = true
          } else {
            // 仍旧继承父类原始禁用状态
            disabled = parent?.originItem?.disabled || false
          }
        }
      }

      if (disabled) {
        if (isLeaf || !children || isEmptyChildren) {
          expand = false
          showArrow = false
        }
      }

      const parentKey = parent ? parent.key : null
      const show = this.defaultExpandAll || level === 0

      const newItem = {
        key,
        parentKey,
        label,
        append,
        isLeaf,
        showArrow,
        level,
        expand,
        show,
        sort,
        disabled,
        loaded: false,
        loading: false,
        indexs: [index],
        checkedStatus: unCheckedStatus,
        parentKeys: [],
        childrenKeys: [],
        children: [],
        originItem: item,
      }

      if (parent) {
        newItem.parentKeys = [parent.key, ...parent.parentKeys]
        newItem.indexs = [...parent.indexs, index]
      }

      return newItem
    },

    /**
     * 处理初始化内容
     * @param list
     */
    checkInitData(list) {
      let checkedKeyList = null
      let expandedKeyList = []
      if (this.showCheckbox) {
        checkedKeyList = [...new Set(this.checkedKeys || [])]
        expandedKeyList = this.expandChecked ? ([...(this.checkedKeys || []), ...(this.expandedKeys || [])]) : this.expandedKeys
      } else {
        checkedKeyList = this.checkedKeys || null
        expandedKeyList = this.expandChecked && this.checkedKeys ? ([this.checkedKeys, ...(this.expandedKeys || [])]) : this.expandedKeys
      }

      this.handleCheckState(list, checkedKeyList, true)

      // 处理初始展开
      expandedKeyList = [...new Set(expandedKeyList)]
      if (!this.defaultExpandAll) {
        this.handleExpandState(list, expandedKeyList, true)
      }

      list.sort((a, b) => {
        if (a.sort === 0 && b.sort === 0) {
          return 0
        }

        if (a.parentKey === b.parentKey) {
          if (a.sort - b.sort > 0) {
            return 1
          } else {
            return -1
          }
        }

        return 0
      })

      return list
    },

    /**
     * 处理选中
     * @param list
     * @param checkedKeyList
     */
    handleCheckState(list, checkedKeyList, checked = true) {
      // 多选
      if (this.showCheckbox) {
        if (checkedKeyList?.length) {
          checkedKeyList.forEach(k => {
            const item = this.datamap[k]
            if (item) {
              this.checkTheChecked(item, checked)
            }
          })
        }

        return
      }

      // 单选
      for (let i = 0; i < list.length; i++) {
        const item = list[i]
        if (item.key === checkedKeyList) {
          // console.log('item.key === checkedKeyList', item.key, checkedKeyList)
          this.checkTheRadio(item, checked)
          break
        }
      }
    },

    /**
     * 校验多选节点
     * @param item
     * @param checked
     */
    checkTheChecked(item, checked = true) {
      const { childrenKeys, parentKeys, disabled = false } = item
      if (!this.checkedDisabled && disabled) return

      // 当前
      item.checkedStatus = checked ? isCheckedStatus : unCheckedStatus

      if (!this.checkStrictly) {
        // 子类
        childrenKeys.forEach(k => {
          const childrenItem = this.datamap[k]
          childrenItem.checkedStatus = (!this.checkedDisabled && childrenItem.disabled) ? childrenItem.checkedStatus : item.checkedStatus
        })

        // 父类
        parentKeys.forEach(k => {
          const parentItem = this.datamap[k]
          parentItem.checkedStatus = this.getParentCheckedStatus(parentItem)
        })
      }
    },

    /**
     * 校验单选节点
     * @param item
     */
    checkTheRadio(item, checked) {
      const { parentKeys, isLeaf, disabled = false } = item
      if (!this.checkedDisabled && disabled) return

      // 限制末节点选中,但当前非末节点
      if (this.onlyRadioLeaf && !isLeaf) {
        logError(`限制了末节点选中,当前[${item.label}]非末节点`)
        return
      }

      if (this.datalist?.length) {
        this.datalist.forEach(k => {
          k.checkedStatus = unCheckedStatus
        })
      }
      console.log('000', item, parentKeys, this.datamap)

      parentKeys.forEach(k => {
        console.log('kkk', k, this.datamap[k])
        const parentItem = this.datamap[k]
        parentItem.checkedStatus = checked ? this.getParentCheckedStatus(parentItem) : unCheckedStatus
      })

      // 当前
      item.checkedStatus = checked ? isCheckedStatus : unCheckedStatus
    },

    /**
     * 处理父节点展开
     * @param item
     * @param expand
     */
    // handleExpandParentNode(item, expand = true) {
    //   if (!expand) return

    //   if (item?.parentKeys?.length) {
    //     item.parentKeys.forEach(pk => {
    //       if (!this.datamap[pk].expand) {
    //         this.datamap[pk].expand = true
    //       }
    //     })
    //   }
    // },

    /**
     * 处理节点展开
     * @param list
     * @param expandedKeyList
     * @param expand
     */
    handleExpandState(list, expandedKeyList, expand = true) {
      // 收起
      if (expand === false) {
        for (let i = 0; i < list.length; i++) {
          const item = list[i]
          if (expandedKeyList?.includes(item.key)) {
            item.expand = false
            if (item.childrenKeys?.length) {
              item.childrenKeys.forEach(ck => {
                this.datamap[ck].expand = false
                this.datamap[ck].show = false
              })
            }
          }
        }
        return
      }
      // 展开
      for (let i = 0; i < list.length; i++) {
        const item = list[i]
        // 处理展开
        if (expandedKeyList?.includes(item.key)) {
          // 父子
          item.expand = true
          if (item.children?.length) {
            item.children.forEach(k => {
              const kItem = this.datamap[k.key]
              kItem.show = true
            })
          }

          // 族系
          if (item.parentKeys?.length) {
            item.parentKeys.forEach(k => {
              const kItem = this.datamap[k]
              kItem.expand = true
              if (kItem.children?.length) {
                kItem.children.forEach(k => {
                  const skItem = this.datamap[k.key]
                  skItem.show = true
                })
              }
            })
          }
        }
      }
    },

    /**
     * 点击选框
     * @param item
     */
    handleCheckChange(item) {
      const { childrenKeys, parentKeys, checkedStatus, isLeaf, disabled = false } = item
      if (!this.showCheckbox) return
      if (disabled) return

      // 当前
      item.checkedStatus = checkedStatus === isCheckedStatus ? unCheckedStatus : isCheckedStatus

      // 子类
      if (!this.checkStrictly) {
        if (this.expandChecked) {
          item.show = true
          item.expand = childrenKeys?.length > 0 || isLeaf
        }

        childrenKeys.forEach(k => {
          const childrenItem = this.datamap[k]
          childrenItem.checkedStatus = childrenItem.disabled ? childrenItem.checkedStatus : item.checkedStatus

          if (this.expandChecked) {
            childrenItem.show = true
            childrenItem.expand = childrenItem?.childrenKeys?.length > 0 || childrenItem.isLeaf
          }
        })
      } else {
        if (this.expandChecked) {
          logError(`多选时,当 checkStrictly 为 true 时,不支持选择自动展开子节点属性(expandChecked)`)
        }
      }

      // 父类
      if (!this.checkStrictly) {
        parentKeys.forEach(k => {
          const parentItem = this.datamap[k]
          parentItem.checkedStatus = this.getParentCheckedStatus(parentItem)
        })
      }

      const hasCheckedKeys = []
      for (let i = 0; i < this.datalist.length; i++) {
        const k = this.datalist[i]
        if (k.checkedStatus === isCheckedStatus) {
          if ((this.packDisabledkey && k.disabled) || !k.disabled) {
            hasCheckedKeys.push(k.key)
          }
        }
      }

      this.checkedKeys = [...hasCheckedKeys]

      this.$emit('change', hasCheckedKeys, item)
    },

    /**
     * 点击单选
     * @param item
     */
    handleRadioChange(item) {
      const { parentKeys, checkedStatus, key, disabled = false, isLeaf } = item
      if (this.showCheckbox) return
      if (this.onlyRadioLeaf && !isLeaf) this.handleExpandedChange(item)

      if (disabled) return

      // 重置所有选择
      if (this.datalist?.length) {
        for (let i = 0; i < this.datalist.length; i++) {
          const k = this.datalist[i]
          k.checkedStatus = unCheckedStatus
        }
      }

      parentKeys.forEach(k => {
        const parentItem = this.datamap[k]
        parentItem.checkedStatus = this.getParentCheckedStatus(parentItem)
      })

      // 当前
      item.checkedStatus = checkedStatus === isCheckedStatus ? unCheckedStatus : isCheckedStatus

      this.checkedKeys = key
      this.$emit('change', key, item)
    },

    /**
     * 点击标签
     */
    handleLabelClick(item) {
      if (this.showCheckbox) {
        this.handleCheckChange(item)
      } else {
        this.handleRadioChange(item)
      }
    },

    /**
     * 点击展开收起
     * @param item
     */
    async handleExpandedChange(item) {
      const { expand, loading = false, disabled } = item
      if (this.loadLoading && loading) return

      this.checkExpandedChange(item)

      // 异步
      item.expand = !expand

      let currentItem = null
      if (!disabled) {
        if (!this.showCheckbox && this.onlyRadioLeaf && this.loadMode) {
          logError(`单选时,当 onlyRadioLeaf 为 true 时不支持动态数据`)
        } else {
          currentItem = await this.loadExpandNode(item)
        }
      }

      this.$emit('expand', !expand, currentItem || item || null)
    },

    /**
     * 检查展开状态
     * @param item
     */
    checkExpandedChange(item) {
      const { expand, childrenKeys, children = null } = item

      if (expand) {
        if (childrenKeys?.length) {
          childrenKeys.forEach(k => {
            if (this.datamap[k]) {
              this.datamap[k].show = false
              this.datamap[k].expand = false
            }
          })
        }
      } else {
        if (children?.length) {
          const childrenKeys = children.map(k => k.key)
          childrenKeys.forEach(k => {
            if (this.datamap[k]) {
              this.datamap[k].show = true
            }
          })
        }
      }
    },

    /**
     * 加载异步数据
     * @param item
     */
    async loadExpandNode(item) {
      const { expand, key, loaded, children } = item
      if (children?.length && !this.alwaysFirstLoad) {
        return item
      }

      if (expand && this.loadMode && !loaded) {
        if (isFunction(this.loadApi)) {
          this.expandedKeys.push(key)
          this.loadLoading = true
          item.loading = true

          const currentNode = deepClone(item)
          const apiRes = await this.loadApi(currentNode)

          // 新增子项
          let newChildren = [...(item.originItem?.children || []), ...(apiRes || [])]
          const newChildrenObj = {}
          newChildren = newChildren.reduce((total, next) => {
            newChildrenObj[next[this.fieldMap]] ? '' : newChildrenObj[next[this.fieldMap]] = true && total.push(next)
            return total
          }, [])

          item.originItem.children = newChildren || null
          if (apiRes?.length) {
            const insertIndex = this.datalist.findIndex(k => k.key === item.key)
            this.handleTreeData(apiRes, item, item.level + 1, insertIndex)
            this.datalist = this.checkInitData(this.datalist)
          } else {
            // 加载后无数据就移除展开图标
            item.expand = false
            item.isLeaf = true
            item.showArrow = false
          }

          this.loadLoading = false
          item.loading = false
          item.loaded = true
        }
      } else {
        const eki = this.expandedKeys.findIndex(k => k === key)
        if (eki >= 0) {
          this.expandedKeys.splice(eki, 1)
        }
      }

      return item
    },

    /**
     * 获取父类的选中状态
     * @param item
     */
    getParentCheckedStatus(item) {
      if (!item) {
        return unCheckedStatus
      }

      if (!this.checkedDisabled && item.disabled) {
        return item.checkedStatus || unCheckedStatus
      }

      // 单选时,父类永远为半选
      if (!this.showCheckbox) {
        return halfCheckedStatus
      }

      const { children } = item
      // 子类全选中
      const childrenCheckedAll = children.every(k => k.checkedStatus === isCheckedStatus)
      if (childrenCheckedAll) {
        return isCheckedStatus
      }

      // 子类全不选中
      const childrenUncheckedAll = children.every(k => k.checkedStatus === unCheckedStatus)
      if (childrenUncheckedAll) {
        return unCheckedStatus
      }

      return halfCheckedStatus
    },
    /**
     * 返回已选的 key
     */
    getCheckedKeys() {
      return getAllNodeKeys(this.datalist, 'checkedStatus', isCheckedStatus, this.packDisabledkey)
    },
    /**
     * 根据key设置已选
     * @param keys 多选时为key的数组,单选时为key
     * @param checked 多选时为key的数组,单选时为key
     */
    setCheckedKeys(keys, checked = true) {
      // 多选
      if (this.showCheckbox) {
        if (!isArray(keys)) {
          logError(`setCheckedKeys 第一个参数非数组,传入的是[${keys}]`)
          return
        }

        const list = this.datalist

        // 取消选择
        if (checked === false) {
          let newCheckedKeys = []
          for (let i = 0; i < this.checkedKeys.length; i++) {
            const ck = this.checkedKeys[i]
            if (!keys.includes(ck)) {
              newCheckedKeys.push(ck)
            }
          }
          newCheckedKeys = [...new Set(newCheckedKeys)]
          this.checkedKeys = newCheckedKeys
          this.handleCheckState(list, keys, false)

          return
        }

        // 选择
        const newCheckedKeys = [...this.checkedKeys, ...keys]
        this.checkedKeys = [...new Set(newCheckedKeys)]
        this.handleCheckState(list, this.checkedKeys, true)

        if (this.expandChecked && checked) {
          this.expandedKeys = [...new Set([...(this.checkedKeys || []), ...(keys || [])])]
          this.handleExpandState(list, keys, true)
        }
        return
      }

      // 单选
      // 如果为数组则拿第一个
      if (isArray(keys)) {
        keys = keys[0]
      }

      if (!isString(keys) && !isNumber(keys)) {
        logError('setCheckedKeys 第一个参数字符串或数字,传入的是==>', keys)
        return
      }

      const list = this.datalist
      this.checkedKeys = checked ? keys : null

      if (this.expandChecked && checked) {
        this.handleExpandState(list, [keys], true)
      }

      this.handleCheckState(list, keys, !!checked)
    },
    /**
     * 返回半选的 key
     */
    getHalfCheckedKeys() {
      return getAllNodeKeys(this.datalist, 'checkedStatus', halfCheckedStatus, this.packDisabledkey)
    },
    /**
     * 返回未选的 key
     */
    getUncheckedKeys() {
      return getAllNodeKeys(this.datalist, 'checkedStatus', unCheckedStatus, this.packDisabledkey)
    },
    /**
     * 返回已展开的 key
     */
    getExpandedKeys() {
      return getAllNodeKeys(this.datalist, 'expand', true)
    },
    /**
     * 根据key展开/收起
     * @param keys key的数组,或字符串 all
     * @param expand true为展开/false为收起
     */
    setExpandedKeys(keys, expand = true) {
      if (!Array.isArray(keys) && keys !== 'all') {
        logError('setExpandedKeys 第一个参数非数组,传入的是===>', keys)
        return
      }
      const list = this.datalist

      // 展开/收起全部
      if (keys === 'all') {
        list.forEach(k => {
          k.expand = expand
          if (k.level > 0) {
            k.show = expand
          }
        })
        return
      }

      // 收起
      if (expand === false) {
        const newExpandedKeys = []
        for (let i = 0; i < this.expandedKeys.length; i++) {
          const ek = this.expandedKeys[i]
          if (!keys.includes(ek)) {
            newExpandedKeys.push(ek)
          }
        }
        this.expandedKeys = [...new Set(newExpandedKeys)]
        this.handleExpandState(list, keys, false)

        return
      }

      // 展开
      const newExpandedKeys = []
      for (let i = 0; i < list.length; i++) {
        if (keys.includes(list[i].key)) {
          newExpandedKeys.push(list[i].key)
        }
      }
      this.expandedKeys = [...new Set(newExpandedKeys)]
      this.handleExpandState(list, newExpandedKeys, true)
    },
    /**
     * 返回未展开的 key
     */
    getUnexpandedKeys() {
      return getAllNodeKeys(this.datalist, 'expand', false)
    },
    /**
     * 返回已选的节点
     */
    getCheckedNodes() {
      return getAllNodes(this.datalist, 'checkedStatus', isCheckedStatus, this.packDisabledkey)
    },
    /**
     * 返回半选的节点
     */
    getHalfCheckedNodes() {
      return getAllNodes(this.datalist, 'checkedStatus', halfCheckedStatus, this.packDisabledkey)
    },
    /**
     * 返回未选的节点
     */
    getUncheckedNodes() {
      return getAllNodes(this.datalist, 'checkedStatus', unCheckedStatus, this.packDisabledkey)
    },
    /**
     * 返回已展开的节点
     */
    getExpandedNodes() {
      return getAllNodes(this.datalist, 'expand', true)
    },
    /**
     * 返回未展开的节点
     */
    getUnexpandedNodes() {
      return getAllNodes(this.datalist, 'expand', false)
    },
  },
}
</script>

<style lang="scss" scoped>
@font-face {
  font-family: 'da-tree-iconfont'; /* Project id  */
  src: url('data:application/octet-stream;base64,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') format('truetype');
}

.da-tree {
  width: 100%;
  height: 100%;

  &-scroll {
    width: 100%;
    height: 100%;
  }

  &-item {
    display: flex;
    align-items: center;
    height: 0;
    padding: 0;
    overflow: hidden;
    font-size: 28rpx;
    line-height: 1;
    visibility: hidden;
    opacity: 0;
    transition: opacity 0.2s linear;

    &.is-show {
      height: auto;
      padding: 12rpx 24rpx;
      visibility: visible;
      opacity: 1;
    }

    &__icon {
      display: flex;
      align-items: center;
      justify-content: center;
      width: 40rpx;
      height: 40rpx;
      overflow: hidden;

      &--arr {
        position: relative;
        display: flex;
        align-items: center;
        justify-content: center;
        width: 32rpx;
        height: 32rpx;

        &::after {
          position: relative;
          z-index: 1;
          overflow: hidden;
          /* stylelint-disable-next-line font-family-no-missing-generic-family-keyword */
          font-family: 'da-tree-iconfont' !important;
          font-size: 32rpx;
          font-style: normal;
          color: #999;
          -webkit-font-smoothing: antialiased;
          -moz-osx-font-smoothing: grayscale;
        }

        &.is-expand {
          &::after {
            content: '\e604';
          }
        }

        &.is-right {
          transform: rotate(-90deg);
        }

        &.is-loading {
          animation: IconLoading 1s linear 0s infinite;

          &::after {
            content: '\e7f1';
          }
        }
      }
    }

    &__checkbox {
      width: 40rpx;
      height: 40rpx;
      overflow: hidden;

      &--left {
        order: 0;
      }

      &--right {
        order: 1;
      }

      &--icon {
        position: relative;
        display: flex;
        align-items: center;
        justify-content: center;
        width: 40rpx;
        height: 40rpx;

        &::after {
          position: relative;
          top: 0;
          left: 0;
          z-index: 1;
          overflow: hidden;
          /* stylelint-disable-next-line font-family-no-missing-generic-family-keyword */
          font-family: 'da-tree-iconfont' !important;
          font-size: 32rpx;
          font-style: normal;
          -webkit-font-smoothing: antialiased;
          -moz-osx-font-smoothing: grayscale;
        }

        &.da-tree-checkbox-outline::after {
          color: #bbb;
          content: '\ead5';
        }

        &.da-tree-checkbox-checked::after {
          color: var(--theme-color,#007aff);
          content: '\ead4';
        }

        &.da-tree-checkbox-indeterminate::after {
          color: var(--theme-color,#007aff);
          content: '\ebce';
        }

        &.da-tree-radio-outline::after {
          color: #bbb;
          content: '\ecc5';
        }

        &.da-tree-radio-checked::after {
          color: var(--theme-color,#007aff);
          content: '\ecc4';
        }

        &.da-tree-radio-indeterminate::after {
          color: var(--theme-color,#007aff);
          content: '\ea4f';
        }
      }

      &.is--disabled {
        cursor: not-allowed;
        opacity: 0.35;
      }
    }

    &__label {
      flex: 1;
      margin-left: 4rpx;
      color: #555;

      &--2 {
        color: var(--theme-color,#007aff);
      }

      &--append {
        font-size: 60%;
        opacity: 0.6;
      }
    }
  }
}

@keyframes IconLoading {
  0% {
    transform: rotate(0deg);
  }

  100% {
    transform: rotate(360deg);
  }
}
</style>