<template>
	<div class="xd-cascade">
		<el-cascader
			ref="xdCascade"
			popper-class="xd-cascade-popper"
			:disabled="disabled"
			v-model="cascade"
			:placeholder="uiPlaceholder"
			:options="uiList"
			:props="props"
			:filterable="filterable"
			:clearable="clearable"
			:collapse-tags="collapseTags"
			@change="()=>{change();update()}"
			@visible-change="(status)=>{if(status===false){removeAndShow()}}"
			@remove-tag="()=>{removeAndShow()}"
		>
			<template slot-scope="{ node, data }">
				<span>{{ data.label }}</span>
				<span v-if="!node.isLeaf"> ({{ data.children.length }}) </span>
			</template>
		</el-cascader>
	</div>
</template>

<script>
import emitter from 'element-ui/src/mixins/emitter';
  export default {
    name: "XdCascade",
    mixins: [emitter],
		props:{
      defaultValue: {
        type: Array|String|Number,
        default() {
          return []
        },
      },

      list: {
        type: Object | null,
        default() {
          return null
        },
      },

      maps: {
        type: Object | null,
        default() {
          return null
        },
      },

      setting: {
        type: Object,
        default() {
          return {
            filterable: false,
            clearable: true,
            collapseTags: false
					}
        },
      },

      disabled: {
        type: Boolean,
        default: false,
      },

      size: {
        type: String,
        default: 'medium', //medium / small / mini
      },

      placeholder: {
        type: Object,
        default() {
          return {
            placeholder: '请选择',
          }
        },
      },

      required: {
        type: Boolean,
        default: false,
      },

      //是否启用自定义校验器
      useCustomRules: {
        type: Boolean,
        default: false,
      },

      //数字字符串 转 数字
      isNumber: {
        type: Boolean,
        default: true,
      },

      //自定义方法
      handleCustom: {
        type: Function || null,
        default: null
      },
			
		},
		data(){
      return {
        uiList: [],
        uiPlaceholder: '',
        cascade: [],
        filterable: false, //允许搜索
        clearable: true, //允许清空
        collapseTags: false, //允许折叠
        isBackLeaf: true, //是否只返回叶子节点
        initStatus: false, //加载完成
        isGeRoot: false, //返回值节点的当子集合选择返回父节点选
       
        props: {
          multiple: true,
          checkStrictly: false,
          emitPath: false
        },
				
				loading: false,
				
        //默认map关系显示
        defaultMap: {
          value: 'value',
          label: 'label'
        },
			}
		},
		watch:{
      loading(){
        this.handleMapToList();
			}
		},
		
		created(){
      if (this.list === null) this.uiList = this.testData;
      else this.uiList = this.list;
      if (this.placeholder['placeholder']) this.uiPlaceholder = this.placeholder['placeholder'];
      if (this.setting['filterable'] !== undefined) this.filterable = this.setting['filterable'];
      if (this.setting['clearable'] !== undefined) this.clearable = this.setting['clearable'];
      if (this.setting['collapseTags'] !== undefined) this.collapseTags = this.setting['collapseTags'];
      if (this.setting.isBackLeaf !== undefined) this.isBackLeaf = this.setting.isBackLeaf;
      if (this.setting.isGeRoot !== undefined) this.isGeRoot = this.setting.isGeRoot;
      
      //props
      if (this.setting.multiple !== undefined) {
        this.$set(this.props, 'multiple', this.setting.multiple);
			}
      if (this.setting.checkStrictly !== undefined) {
        this.$set(this.props, 'checkStrictly', this.setting.checkStrictly);
      }
      
      //设置默认值为空时候处理
			this.$nextTick(()=>{
        this.loading = true;
			})
   
		},
		
		methods: {
      //==Root==================
      getRootNodes() {
        let data = {};
        let nodes = this.$refs['xdCascade'].getCheckedNodes(this.isBackLeaf);
        const nodeFn = (node) => {
          if (node.parent === null) {
            data[node.value] = node;
          } else nodeFn(node.parent);
        };
        nodes.map(item => {
          nodeFn(item)
        });
        return Object.keys(data).map(key => {
          return data[key]
        });
      },

      getRootNodesValue() {
        let nodes = this.getRootNodes();
        let list = [];
        const handle = (root) => {
          let len = root.length;
          for (let i = 0; i < len; i++) {
            //有子节点并且半选时候
            if (root[i].children.length > 0
              && root[i].indeterminate === true
            ) {
              handle(root[i].children);
            } else {
              if (root[i].checked) list.push({
                ...this.getNodeData([root[i]])[0],
                //...root[i].data
              });
            }
          }
        };
        handle(nodes);
        return list;
      },

      getRootValueForLeafValue(select) {
        let selectValue = [];
        let data = this.$xdHelper.cloneDeep(this.uiList);
        const handle = (root, parentData) => {
          let len = root.length;
          for (let i = 0; i < len; i++) {
            //判断当前节点是否已经选中
            root[i].checked = select.filter(val => {
              return val === root[i].value;
            }).length > 0;

            //父级已经选中
            if (parentData && parentData.checked) root[i].checked = true;

            //检查最后一层是否为选中
            if ((!root[i].children || root[i].children.length === 0)
              && root[i].checked
            ) {
              selectValue.push(root[i].value);
            }

            if (root[i].children && root[i].children.length > 0) {
              handle(root[i].children, root[i]);
            }
          }
        };
        handle(data, null);
        this.cascade = selectValue;
      },
      //==Root==================
   
			removeAndShow(){
			  setTimeout(()=>{
			    this.change();
			    this.update();
				}, 100)
			},

      /**
       * @description 获取node级联 数据项名称与数据项值
       * @param nodes {Object} 数据项节点
       */
      getNodeData(nodes) {
        let nodeDataName = [];
        let nodeDataValue = [];
        const nodeFn = (node) => {
          nodeDataName.unshift(node.label);
          nodeDataValue.unshift(node.value);
          if (node.parent === null) return;
          else nodeFn(node.parent);
        };
        return nodes.map((item) => {
          nodeDataName = [];
          nodeDataValue = [];
          nodeFn(item);
          return {
            labelAll: nodeDataName,
            valueAll: nodeDataValue,
            value: nodeDataValue[nodeDataValue.length - 1],
            label: nodeDataName[nodeDataName.length - 1]
          }
        })
      },

      /**
       * @description 返回映射关系对象数据（需要自己实现）
			 * 把内部数据转化为返回数据格式
       */
      handleListToMap() {
        let nodes = this.getNodeData(this.$refs['xdCascade'].getCheckedNodes(this.isBackLeaf));
        //多选并且需要获取子集已全选返回父级数据
        if (this.props.multiple && this.isGeRoot) {
          return this.getRootNodesValue();
        }
        return nodes.map(item => {
          let temp = {};
          Object.keys(item).map(key => {
            let str = this.getMap(key, false);
            if (str) {
              temp[str] = item[key];
            } else {
              temp[key] = item[key];
            }
          });
          return temp;
        });
      },
			
			/**
			 * @description 单选模式设置默认值
			 * @param select {*} 选中的值
			 */
      selectOne(select) {
        let list = this.$xdHelper.cloneDeep(this.list);
        const findParentIdList = (source, key, children = 'children', level = 0) => {
          var arrRes = [];
          let rootObj = {
            value: -1,
            [children]: source
          }

          function toFindId(data, key, level) {
            if (!data || !data[children] || !data[children].length) {
              return;
            }
            for (var i = 0; i < data[children].length; i++) {
              let item = data[children][i];
              if (item.value === key) {
                // 将匹配到的结果保存到数组
                arrRes.unshift(item);
                // 递归它的父级
                toFindId(rootObj, data.value, 0);
                break;

              } else if (item[children] && item[children].length > 0) {
                //如果有子集，则把子集作为参数重新执行本方法
                toFindId(item, key, level + 1);

              }
            }
          };
          toFindId(rootObj, key, level);
          return arrRes;
        }
        return findParentIdList(list, select).map(item => {
          return item.value;
        });
      },

      /**
       * @description 初始化映射关系到数据列表(需要自己实现)
			 * 把默认数据转化为内部数据
       */
      handleMapToList() {
        if (this.defaultValue !== null && this.defaultValue && this.defaultValue.length > 0) {
          let cascade = [];
          if (this.$xdHelper.checkVarType(this.defaultValue[0]) === 'object') {
            this.defaultValue.map(item => {
              Object.keys(item).map(key => {
                let keyStr = this.getMap(key, true);
                if (keyStr && keyStr === 'value') {
                  cascade.push(item[key]);
                }
              })
            });
          }
          else {
            cascade = this.defaultValue
          }
					
          //复选模式设置默认值
					if(this.props.multiple) {
            //设置父节点为选择模式
						if(this.isGeRoot) {
              this.getRootValueForLeafValue(cascade);
              this.$nextTick(() => {
                setTimeout(() => {
                  this.update();
                }, 50)
              })
						}
						//子节点选择模式
						else{
              this.cascade = cascade;
							this.$nextTick(() => {
								setTimeout(() => {
								this.update();
								}, 50)
							})
						}
					}
          //单选模式设置默认值
					else{
            this.cascade = this.selectOne(cascade[0]);
            this.$nextTick(() => {
              setTimeout(() => {
                this.update();
              }, 50)
            })
					}
        }
      },

      //插件系统方法///////////////////////////////////////
      /**
       * @description 获取Maps中键与值
       * @param type {boolean} 返回值类型  true=>获取键  false=>值
       * @param keyword {string} 查找关键字
       * @return {null|string} null=>未找到  string=>找到
       */
      getMap(keyword, type) {
        let maps = null;
        let value = null;
        if (this.maps !== null && !this.$xdHelper.isEmpty(this.maps)) {
          maps = this.$xdHelper.cloneDeep(this.maps);
        }

        //先默认maps关系中找
        Object.keys(this.defaultMap).map(ky => {
          //获取键
          if (type) {
            if (this.defaultMap[ky] === keyword) {
              value = ky;
            }
          } else {
            if (this.defaultMap[keyword]) value = this.defaultMap[keyword];
          }
        });

        //无外部map关系并且在默认关系表中无键
        if (value === null && maps === null) {
          //console.log('1')
          return null;
        }

        //无外部map关系并且在默认关系表中键
        if (value !== null && maps === null) {
          //console.log('2', value)
          return value;
        }

        //有外部map关系进行查找
        Object.keys(maps).map(ky => {
          //获取键
          if (type) {
            if (maps[ky] === keyword) {
              value = ky;
            }
          } else {
            if (this.maps[keyword]) value = this.maps[keyword];
          }
        });
        //console.log('3')
        return value;

      },
			

      /**
			 * @description 需要校验检查参数是正确处理方法
       */
			checkParams(){
        if (!this.required) return this.handleListToMap();
				
        //校验成功
        return this.handleListToMap();
			},
			
			/**
			 * @description 数据改变事件
			 */
			change(){
			  this.$emit('onChange', this.checkParams())
			},


      /**
			 * @description 双向绑定数据处理
       */
			update(){
        this.$emit('input', this.checkParams());
        if (this.$parent.$options['componentName'] === 'ElFormItem') {
          this.dispatch('ElFormItem', 'el.form.change', [this.checkParams()]);
          this.dispatch('ElFormItem', 'el.form.blur', [this.checkParams()])
        }
			},
		}
  }
</script>

<style scoped lang="scss">
	.xd-cascade {
		width: 100%;
		min-width: 200px;
		
		& > * {
			width: 100%;
		}
	}
	
	@media screen and (max-width: 768px) {
		.xd-cascade {
			width: 100%;
		}
	}
</style>
