<template>
  <div>
    <!-- 树形选择框 -->
    <a-form-model-item :ref="attr.model" :label="attr.name" :prop="attr.model" :rules="rules">
      <a-spin v-show="!loaded" size="small"/>
      <a-tree-select
        v-show="loaded"
        ref="tree-select"
        v-model="localValue"
        :disabled="disabled || readOnly"
        :tree-data="getTreeData()"
        :tree-checkable="(mode === '查询' && queryType !== 'RIGHT_LIKE') || (mode !== '查询' && attr.chooseForm === 'multipleChoice')"
        :placeholder="`请选择${name||''}`"
        :dropdown-style="{ maxHeight: '400px' }"
        tree-node-filter-prop="label"
        :show-checked-strategy="queryType === 'RIGHT_LIKE' ? 'SHOW_ALL' : undefined"
        allow-clear
        :showArrow="true"
        class="tree-select"
        :getPopupContainer="(triggerNode) => triggerNode.parentNode"
        @change="onTreeSelectChange">
      </a-tree-select>
    </a-form-model-item>
  </div>
</template>
<script>
import XFormCol from '@vue2-client/base-client/components/common/XFormCol'

export default {
  name: 'XTreeSelect',
  components: { XFormCol },
  model: {
    prop: 'value',
    event: 'onChange'
  },
  // eslint-disable-next-line vue/require-prop-types
  props: ['value', 'attr', 'rules', 'disabled', 'readOnly'],
  watch: {
    value (newVal) {
      if (!newVal || (Array.isArray(newVal) && (!newVal.length || !newVal[0]))) {
        this.localValue = undefined
      } else {
        this.localValue = newVal
      }
    },
  },
  data () {
    return {
      // 内容加载是否完成
      loaded: false,
      // 数据列表
      option: [],
      // 表单
      form: {},
      // 查询方式
      queryType: 'IN',
      // label名称
      name: undefined,
      // 模型名称
      model: undefined,
      // 使用方式
      mode: '查询',
      localValue: this.value
    }
  },
  methods: {
    init (params) {
      const {
        option = [], form, queryType = 'IN', name, model, mode = '查询'
      } = params
      this.loaded = false
      this.option = option
      this.form = form
      this.queryType = queryType
      this.name = name
      this.model = model
      this.mode = mode
      // 修改时恢复树形选择框选中状态
      if (this.queryType !== 'RIGHT_LIKE') {
        const value = this.form[this.model]
        if (value) {
          // 如果数据源中值含'-'，代表是由多个数据源组成的树，需要重新组织新增/编辑时的表单值
          if (this.option.length > 0 && this.option[0].value.toString().indexOf('-') !== -1) {
            this.localValue = model + '-' + value
          } else {
            if (this.mode === '查询') {
              const values = []
              this.getValues(option, value, values)
              this.$emit('onChange', values)
            } else {
              this.localValue = value
            }
            // value = option 自身和所有子得集合
          }
        } else {
          this.localValue = undefined
        }
      }
      this.$emit('mounted', this.attr)
      this.loaded = true
    },
    getValues (option, value, values) {
      const _values = []
      for (const item of option) {
        if (value.includes(item.value)) {
          values.push(item.value)
          _values.push(item.value)
          // 找到匹配节点后，递归添加所有子节点的值
          if (item.children && item.children.length) {
            this.getAllChildrenValues(item.children, values)
          }
        }
        if (item.children && item.children.length) {
          const tempV = this.getValues(item.children, value, values)
          if (tempV.length === item.children.length) {
            values.push(item.value)
          }
        }
      }
      return _values
    },
    getAllChildrenValues (children, values) {
      for (const child of children) {
        values.push(child.value)
        if (child.children && child.children.length) {
          this.getAllChildrenValues(child.children, values)
        }
      }
      return values
    },
    // 获取树形选择框数据
    getTreeData () {
      const treeData = this.option
      if (this.mode === '新增/修改') {
        this.setParentSelectable(treeData)
      }
      return treeData
    },
    // 设置树形选择框不能选择父节点
    setParentSelectable (treeData) {
      treeData.forEach(item => {
        if (item.children && item.children.length) {
          item.selectable = false
          this.setParentSelectable(item.children)
        }
      })
    },
    // 选中树节点
    onTreeSelectChange (value, label, extra) {
      if (this.queryType === 'RIGHT_LIKE') {
        // 获取可用于模糊查询的组织机构字符串
        let node = extra.triggerNode.$parent
        label = label[0]
        while (node && node.label) {
          label = node.label + '.' + label
          node = node.$parent
        }
        // this.form[this.model] = label
        this.$emit('onChange', label)
      } else {
        // 如果选中值含'-'，代表是由多个数据源组成的树，需要重新组织查询或新增/编辑时的表单
        if ((Array.isArray(value) && value.length > 0 && String(value[0]).indexOf('-') !== -1) || (typeof value === 'string' && value.indexOf('-') !== -1)) {
          const treeDatas = {}
          // 单选情况用于新增.修改表单场景，使用extra.triggerNode获取选中节点信息
          if (!extra.allCheckedNodes) {
            this.setNodeData(treeDatas, extra.triggerNode)
          } else {
            // 多选情况用于查询表单场景，使用extra.allCheckedNodes获取选中节点集合
            const nodes = extra.allCheckedNodes
            // 获取任意选中节点的叶子节点的字段名，用于查询时组织查询项的key
            const name = this.getNodeDataProps(nodes[0])
            // 获取所有选中节点的叶子节点的value,用于查询时组织查询项的value
            const values = []
            for (const node of nodes) {
              const ref = this.setDataRef(node)
              if (ref instanceof Array) {
                for (const nodeRef of ref) {
                  const keyValue = nodeRef.node.key
                  values.push(keyValue.substring(keyValue.lastIndexOf('-') + 1))
                }
              } else {
                const keyValue = ref.node.key
                values.push(keyValue.substring(keyValue.lastIndexOf('-') + 1))
              }
            }
            treeDatas[name] = values
          }
          // 移除默认的表单项，将组织好后的表单项合并进表单
          this.form[this.model] = undefined
          Object.assign(this.form, treeDatas)
          // this.$emit('onChange', treeDatas)
        } else {
          // 从单一数据源组成的树可以直接赋值
          // this.form[this.model] = value
          // 获取所有选中节点的value
          if (this.mode === '查询') {
            const values = []
            if (extra.allCheckedNodes) {
              for (const item of extra.allCheckedNodes) {
                if (item.node.key) {
                  if (item.node?.data?.props?.label === item.node?.data?.props?.value) {
                    if (!item.children?.length) {
                      values.push(`${item.node.key}`)
                    }
                  } else {
                    values.push(`${item.node.key}`)
                  }
                }
                if (item.children && item.children.length) {
                  this.getNodeValues(item.children, value, values)
                }
              }
            }
            this.$emit('onChange', values)
          } else {
            this.$emit('onChange', value)
          }
        }
      }
    },
    getNodeValues (data, value, values) {
      for (const item of data) {
        values.push(`${item.node.key}`)
        if (item.children && item.children.length) {
          this.getNodeValues(item.children, value, values)
        }
      }
    },
    // 设置选中值
    setValue (value) {
      this.localValue = value
    },
    setDataRef (node) {
      if (node.children) {
        return this.setDataRef(node.children)
      }
      return node
    },
    /**
     * 组织节点和每层父节点的数据，用于新增/修改时更新表单数据
     * @param data 组织完成的数据
     * @param node 节点
     * @return 返回示例： { parentId: 1, childId: 2 }
     */
    setNodeData (data, node) {
      if (node.value) {
        const value = node.value
        const columnsName = value.substring(0, value.indexOf('-'))
        data[columnsName] = value.substring(value.lastIndexOf('-') + 1)
        if (node.$parent) {
          this.setNodeData(data, node.$parent)
        }
      }
    },
    getNodeDataProps (node) {
      if (node.children && node.children.length > 0) {
        return this.getNodeDataProps(node.children[0])
      }
      const value = node.node.key
      return value.substring(0, value.indexOf('-'))
    }
  }
}
</script>
<style lang="less" scoped>
.tree-select {
  /deep/ .ant-select-selection.ant-select-selection--multiple {
    max-height: 32px;
    overflow-y: auto;
  }
}
</style>
