<template>
	<div class="xd-remote-cascader-panel" v-if="status">
		<div class="xd-remote-cascader-panel__show" v-if="selectedList.length > 0">
			<xd-check-group
				:list.sync="selectedList"
				:default-value="selectedValue"
				v-model="selectedValue"
				@change="handleChange"
				@close="handleClose"
        :disabled="disabled"
			>
			</xd-check-group>
		</div>
		<div class="xd-remote-cascader-panel__operate">
			<div :class="{disabled:disabled}">
				<el-cascader-panel
          :disabled="disabled"
					ref="xdCascadePanel"
					:style="{height: height}"
					:props="props"
					filterable
					clearable
					collapse-tags
					@change="handleCascadeChange"
				>
        <template slot-scope="{ data }">
          <span>{{ data.label }}</span>
          <span v-if="data.profit_rate_string">{{data.profit_rate_string}}</span>
        </template>
				</el-cascader-panel>
			</div>
		</div>
		<div class="xd-remote-cascader-panel__btn" v-if="uiSize !== null">
			<el-button type="primary" :size="uiSize" :disabled="currentNodesValue.length === 0 || disabled" @click="add()">添加</el-button>
			<el-button :disabled="disabled" v-if="allSelectName" type="primary" :size="uiSize" @click="addAll">{{allSelectName}}</el-button>
		</div>
		<div class="xd-remote-cascader-panel__tips" v-if="setting.tips" v-html="setting.tips"></div>
	</div>
</template>

<script>
	import XdCheckGroup from "@/components/XdCheckGroup";
  import emitter from 'element-ui/src/mixins/emitter';
  import XdSelectList from "@/components/XdSelectList";

	let CityData = {
	  value: "",
		label: ""
	};

  export default {
    name: "XdRemoteCascaderPanel",
    mixins: [emitter],
		components: {
      XdSelectList,
      XdCheckGroup
		},
    componentName: 'XdRemoteCascaderPanel',
		props:{
      defaultValue: {
        type: Array[CityData],
        default() {
          return []
        },
      },

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

      setting: {
        type: Object,
        default() {
          return {}
        },
      },

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

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

      placeholder: {
        type: Object,
        default() {
          return {}
        },
      },

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

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

			/**
			 * @description 自定义方法
			 * @param params {Object}
			 * @param params.action {string} 行为标示
			 * @param params.data {any} 传递参数
			 */
			handleCustom: {
        type:Function||null,
				default: null
			},

		},
		data(){
      return {
        status: false,
        uiSize: null,
				isInclude: true, //是否支持数据重复
				selectItemEmpty: '请选择',
        selectItemRepeat: '您选择选项@repeat@已存在。',
        selectItemInclude: '您选择选项@repeat@存在包含或者被包含关系.',

        //全选功能选中第一层
        allSelectLevel: 1,
				allSelectName:'', //是否启动和显示名称 为空不显示

        /**
				 * @description 选中提交数据
         * @type CityData[]
         */
        selectedList: [],
        selectedValue: [],
        selectNodes: [], //已选的节点列表
				currentNodesValue: [],//当次选中列表
        multipleTruePaceHolder: '-', //启动复选并且不可重复时候值与值的连接符，例如：1-2

        //默认map关系显示
        defaultMap: {
          label: 'label',
          value: 'value'
        },

				//级联属性
        height: '260px',
        props: {
          lazy: true,
          multiple: true,
          checkStrictly: true,
          lazyLoad:(node, resolve)=> {
            this.handleCustom({action: 'lazyLoad', data: {node, resolve}});
          }
        }
			}
		},

		created(){
      if(typeof this.handleCustom !== 'function') throw new Error('handleCustom 自定义方法不传参数');
      if(this.size) this.uiSize = this.size;
      this.uiSize = this.$xdHelper.isPC() ? 'medium' : 'mini';
      this.height = this.$xdHelper.isPC() ?
				(this.setting.height ? this.setting.height: '260px')
				: '220px';
      if(this.setting.isInclude !== undefined) this.isInclude = this.setting.isInclude;
      if(this.setting.allSelectName) this.allSelectName = this.setting.allSelectName;
      if (this.setting.multiple !== undefined && this.$xdHelper.checkVarType(this.setting.multiple) === 'boolean') {
        this.$set(this.props, 'multiple', this.setting.multiple)
			}
      if (this.setting.checkStrictly !== undefined && this.$xdHelper.checkVarType(this.setting.checkStrictly) === 'boolean') {
        this.$set(this.props, 'checkStrictly', this.setting.checkStrictly)
      }
      this.status = true;
      if (this.setting.multipleTruePaceHolder) this.multipleTruePaceHolder = this.setting.multipleTruePaceHolder;

      //设置选中默认值
      if(this.defaultValue !== null && this.$xdHelper.checkVarType(this.defaultValue) === 'array') {
        this.handleMapToList();
			}

      //绑定数据
      this.update();
		},

		methods: {
      handleClose({index, value}){
      	this.selectedList.splice(index,1);
      	this.selectedValue.filter(item=>{
      	  return item !== value
				})
			},
      /**
			 * @description 当前面板选中的节点ID
			 * @param value {array} 选中的值
			 */
      handleCascadeChange(value=[]){
        this.currentNodesValue = value;
			},
			/**
			 * @description 选中事件
			 */
      handleChange(){
        this.update();
        this.change();
			},

      /**
       * @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,
            valueAllKey: nodeDataValue.join('-'),
            labelAllKey: nodeDataName.join('/'),
            value: this.isInclude ? nodeDataValue[nodeDataValue.length - 1]:nodeDataValue.join(this.multipleTruePaceHolder),
            label: nodeDataName[nodeDataName.length - 1],
          }
        })
      },

			/**
			 * @description 简单检查当前选中的一个或者多个数据是否在选中对象中（可允许包括包含数据出现）
			 * @description 检查规则：检查value 和 label 值是否重复
			 * @param nodes {Object} 当前选中数据项节点
			 */
      checkInclude(nodes){
        let temp = nodes.filter(item => {
          let isInclude = false;
          this.selectedList.map(it=>{
            if(it['value'] === item.valueAllKey || it['value'] === item.value || it['label'] === item.labelAllKey
						) {
              isInclude = true;
						}
					});
          return isInclude;
        });

        //已经存在
        if(temp.length > 0) {
          let str = temp.map(item => {
            return item.labelAll.join('/')
          }).join('】【');
          this.$message({
            message: this.selectItemRepeat.replace(/@repeat@/,`【${str}】`),
            type: 'error',
            showClose: true,
            duration: 2000,
            onClose: () => {},
          });
          return false
				}

        //不存在
        return true;
			},

      /**
       * @description 深度检查当前选中的一个或者多个数据是否在选中对象中，（不允许包括包含数据出现）
			 * @description 检查规则：检查value值是否重复 值必须包含：每条选中对象的所有节点value值
       * @param nodes {Object} 当前选中数据项节点
       */
      checkNotInclude(nodes) {

        let temp = nodes.filter(item=>{
          let isInclude = false;
          //选中数据为空
          if(this.selectedList.length === 0) return false;
          this.selectedList.map(it => {
            let value = it['value'];
            if(this.$xdHelper.checkVarType(value)) {
              value += '';
						}
            //查找列表1-2-3， 1，1-2，1-2-3
          	if(value.indexOf(item.valueAllKey)===0) {
              isInclude = true;
						}
          	console.log(item.valueAllKey, it['value'])
            //查找列表[1] , [1], [1-2], [1-2-3]
          	if(item.valueAllKey.indexOf(it['value']) === 0) {
              isInclude = true;
						}
          });
          return isInclude;
				});

        if (temp.length > 0) {
          let str = temp.map(item => {
            return item.labelAll.join('/')
          }).join('】【');
          this.$message({
            message: this.selectItemInclude.replace(/@repeat@/, `【${str}】`),
            type: 'error',
            showClose: true,
            duration: 2000,
            onClose: () => {
            },
          });
          return false
        }

        //不存在
        return true;
      },

			/**
			 * @description 添加城市操作
			 * @return {*}
			 */
      add(nodes=null){
        nodes = nodes || this.getNodeData(this.$refs['xdCascadePanel'].getCheckedNodes());
        //选中为空
        if (nodes.length === 0) {
          this.$message({
            message: this.selectItemEmpty,
            type: 'error',
            showClose: true,
            duration: 2000,
            onClose: () => {
            },
          });
          return;
        }

        //检查是否已经存在
				/**（包含也可选中）**/
				if(this.isInclude) {
				  if(!this.checkInclude(nodes)) {
            //选择之后清空选择
            this.$refs['xdCascadePanel'].clearCheckedNodes();
            return;
          }
        }
				else {
          if (!this.checkNotInclude(nodes)){
            //选择之后清空选择
            this.$refs['xdCascadePanel'].clearCheckedNodes();
            return;
					}
				}

        //设置选中值
        nodes.map(item => {
          this.selectNodes.push(item);
          this.selectedList.push({
            label: item.labelAll.join('/'),
            value: item.valueAllKey
          });
          this.selectedValue.push(item.valueAllKey);
        });

				//选择之后清空选择
        this.$refs['xdCascadePanel'].clearCheckedNodes();

        this.change();
        this.update();

			},

			/**
			 * @description 快捷选中第一层
			 */
			addAll(){
        let nodes = this.getNodeData(this.$refs['xdCascadePanel'].getFlattedNodes().filter(item => {
          let inFilter = item.level === this.allSelectLevel;
          let outFilter = true;
          if(typeof this.handleCustom === 'function') {
            outFilter = this.handleCustom({
							action: 'filter',
							data: item
            });
					}
          return inFilter && outFilter;
        }));
        this.add(nodes);
			},

			/**
			 * @description 判断节点是否选中
			 */
			getExistNodes(item){
   			let temp = null;
   			this.selectNodes.map(itm=>{
   			  if(itm.value === item.value || itm.labelAllKey === item.label) {
            temp = itm;
					}
				});
   			return temp
			},

      /**
       * @description 返回映射关系对象数据（需要自己实现）
			 * 把内部数据转化为返回数据格式
       */
      handleListToMap() {
        return this.selectedList
          .filter((item) => {
            let data = this.selectedValue.filter(it => {
              return item['value'] === it
            });
            return data.length > 0
          })
          .map(item => {
            let temp = {};
            if (this.getExistNodes(item) !== null) item = this.getExistNodes(item);
            Object.keys(item).map(key => {
              if (key !== 'key') {
                let str = this.getMap(key, false);
                if (str) temp[str] = item[key];
                else temp[key] = item[key]
              }
            });
            return temp;
          });
      },

      /**
       * @description 初始化映射关系到数据列表(需要自己实现)
			 * 把默认数据转化为内部数据
       */
      handleMapToList() {
        let value = [];
        this.selectedList = this.defaultValue
					.map(item => {
						let temp = {
							key: this.$xdHelper.randomChar(20)
						};
						Object.keys(item).map(key => {
							let keyStr = this.getMap(key, true);
							if (keyStr) {
								temp[keyStr] = item[key];
							}
						});
						return temp
					})
					.filter(item => {
						if(item.value && item.label) value.push(item.value);
						return item.value && item.label
					});
        this.selectedValue = value;
        this.$nextTick(() => {
          setTimeout(() => {
            this.update();
          }, 30)
        })
      },

      //插件系统方法///////////////////////////////////////
      /**
       * @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('change', 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-remote-cascader-panel {

		::v-deep .el-cascader-menu,
		::v-deep .el-cascader-menu__wrap {
			height: 100%;
		}

		&__show {
			margin-bottom: 15px;
		}
		&__tips {
			line-height: 22px;
			font-size: 12px;
			color: #999;
		}

		&__operate {
			width: 100%;
			overflow-x: auto;

			& > div:first-child {
				display: flex;
				justify-items: flex-start;
			}

      & > div.disabled {
        position: relative;
        &::after{
          position: absolute;
          border-radius: 6px;
          left: 0;
          right: 15px;
          bottom: 0;
          top:0;
          content: ' ';
          cursor: not-allowed;
          background: rgba(0,0,0,.03);
          z-index: 100;
        }
      }
		}
		&__btn {
			margin: 20px 0;
		}
	}

	@media screen and (max-width: 768px) {
		.xd-remote-cascader-panel {
			&__show {
				margin-bottom: 5px;
			}

			&__btn {
				margin: 5px 0;
			}

			&__operate {
				padding-bottom: 10px;
			}
		}
	}
</style>
