<template>
  <div class="meta-treeChecked-wrap">
    <van-overlay :show="showTreeCheck" :lock-scroll="false">
      <div
        class="treeChecked-wrapper"
        :style="'margin-top:' + wrapperTop + 'vw;'"
      >
        <!-- 树形多选组件部分头部 -->
        <div class="meta-treeChecked-header">
          <div class="header">
            <svg-icon
              :icon-class="'左箭头'"
              @click="hideCheckInfo()"
            ></svg-icon>
            <div class="title">{{ checkTitle }}</div>
          </div>
        </div>
        <div
          class="meta-treeChecked-info"
        >
          <div>
            <div v-for="item in treeDataList" :key="item">
              <div
                class="list-item"
                :style="'padding-left:' + item.retractNum + 'vw'"
                v-show="item.show"
              >
                <div class="open-handle" @click="checkItemEvent(item, 'show')">
                  <div class="open-icon">
                    <svg-icon
                      v-if="item[childrenKey] && item[childrenKey].length"
                      :icon-class="item.showChildren ? '下箭头' : '右箭头'"
                      :class="item.showChildren ? 'right-down' : 'right-icon'"
                    ></svg-icon>
                  </div>
                  <div class="check-title">{{ item[checkedLabel] }}</div>
                </div>
                <div class="check-box">
                  <van-checkbox
                    :checked="item.checked"
                    @click.stop="checkItemEvent(item, 'check')"
                  ></van-checkbox>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </van-overlay>
  </div>
</template>
<script>
export default {
  name: "MetaTreeChecked",
  props: {
    showTreeCheck: {
      type: Boolean,
      default: false,
    },
    treeData: {
      type: Array,
      default: () => {
        return [];
      },
      required: true,
    },
    checkTitle: {
      type: String,
      default: "",
    },
    // checkbox所有选中数据映射的Key
    checkedBoxDataKey: {
      type: String,
      default: "",
      required: true,
    },
    // checkbox选中的数据映射的key
    checkKey: {
      type: String,
      default: "",
      required: true,
    },
    // 渲染提示信息需要的字段key
    checkedLabel: {
      type: String,
      default: "",
      required: true,
    },
    // 页面id
    pictureid: {
      type: String,
      default: "",
    },
    // 父子层级缩进
    retract: {
      type: Number,
      default: 3.2,
    },
    childrenKey: {
      type: String,
      default: "children",
    },
    // 遮罩内容距离页面顶部高度
    // 传入此处参数时需注意 .meta-treeChecked-info 该样式的高度是否会导致备选列表显示不完全
    wrapperTop: {
      type: Number,
      default: 23.7,
    },
  },
  data() {
    return {
      resetTreeData: [],
      newTreeList: [],
      checkType: "",
    };
  },
  computed: {
    treeDataList() {
      return this.newTreeList;
    },
    defaultPictureId() {
      return this.pictureid || this.$getRouterInfo().name;
    },
    defaultCheckedBoxDataKey() {
      return this.checkedBoxDataKey;
    },
    defaultCheckKey() {
      return this.checkKey;
    },
  },
  methods: {
    // 将树形结构的treeData数据拆解为一维数据
    getTreeDataList(list, newList = []) {
      let childrenKey = this.childrenKey;
      if (list.length) {
        list.forEach((item) => {
          let children = item[childrenKey];
          newList.push(item);
          if (children && children.length) {
            this.getTreeDataList(children, newList);
          }
        });
      }
      return newList;
    },
    // 将父组件传入的treeData数据深拷贝处理，并为每个对象增加自定义属性
    resetTree(item, itemLevel = 0) {
      let childrenKey = this.childrenKey,
        children = item[childrenKey],
        haveChildren = Array.isArray(children) && children.length > 0,
        metaLevel = itemLevel + 1,
        isLeaf = !haveChildren;
      return {
        retractNum: (metaLevel * this.retract).toFixed(2),
        show: metaLevel == 1,
        showChildren: false,
        metaLevel,
        isLeaf,
        ...item,
        [childrenKey]: haveChildren
          ? children.map((i) => this.resetTree(i, metaLevel))
          : [],
      };
    },
    // 根据特定值切换树形结构的显隐状态和选中状态
    toggleChildrenById(
      checkId,
      type,
      itemData = { [this.childrenKey]: this.resetTreeData }
    ) {
      let childrenKey = this.childrenKey,
        children = itemData[childrenKey],
        checkedKey = this.defaultCheckKey;
      if (itemData[checkedKey] == checkId) {
        if (children && children.length) {
          this.setTreeItemById(children, type);
        }
        return itemData;
      } else if (children && children.length) {
        let childrenData = null,
          childLen = children.length;
        for (let i = 0; i < childLen; i++) {
          childrenData = this.toggleChildrenById(checkId, type, children[i]);
          if (childrenData) {
            return childrenData;
          }
        }
        return childrenData;
      }
      return null;
    },
    setTreeItemById(children, type) {
      let childrenKey = this.childrenKey,
        checkType = this.checkType;
      children.forEach((item) => {
        let itemChild = item[childrenKey];
        if (checkType == "show") {
          item.show = type;
          if (itemChild && itemChild.length) {
            item.showChildren = type;
          }
        } else if (checkType == "check") {
          item.checked = type;
        }
        if (itemChild && itemChild.length) {
          this.setTreeItemById(itemChild, type, checkType);
        }
      });
    },
    // 更新树形展开状态
    checkItemEvent(checkItem, checkType) {
      let checkedKey = this.defaultCheckKey,
        childrenKey = this.childrenKey,
        showChildren = !checkItem.showChildren,
        checked = !checkItem.checked;
      this.checkType = checkType;
      if (checkType == "show") {
        if (checkItem.isLeaf) {
          // 叶子节点直接选中，不做显隐切换
          checkItem.checked = checked;
        } else {
          checkItem.showChildren = showChildren;
          this.toggleChildrenById(checkItem[checkedKey], showChildren);
        }
      } else if (checkType == "check") {
        checkItem.checked = checked;
        if (checkItem[childrenKey]?.length) {
          this.toggleChildrenById(checkItem[checkedKey], checked);
        }
      }
      this.newTreeList = this.getTreeDataList(this.resetTreeData);
    },
    // 获取最新的树形结构勾选和展开状态
    getCheckList(checkType) {
      let newTreeList = this.newTreeList,
        checkedKey = this.defaultCheckKey,
        checkedList = [],
        showList = [];
      newTreeList.forEach((item) => {
        if (item.showChildren) {
          showList.push(item[checkedKey]);
        }
        if (item.checked) {
          checkedList.push(item[checkedKey]);
        }
      });
      if (checkType == "show") {
        return showList;
      } else if (checkType == "check") {
        return checkedList;
      }
    },
    // 更新vuex内数据状态
    updataStore() {
      this.$store.commit("resetShowChildListData", {
        data: this.getCheckList("show"),
        pictureid: this.defaultPictureId,
        checkKey: this.defaultCheckedBoxDataKey,
      });
      this.$store.commit("resetTreeCheckedData", {
        data: this.getCheckList("check"),
        pictureid: this.defaultPictureId,
        checkKey: this.defaultCheckedBoxDataKey,
      });
    },
    // 获取vuex内存储的数据回显勾选状态
    updataTreeList() {
      let newTreeList = this.newTreeList,
        defaultCheckedBoxDataKey = this.defaultCheckedBoxDataKey,
        defaultCheckKey = this.defaultCheckKey,
        pictureId = this.defaultPictureId,
        treeChecked = this.$store.getters.getTreeCheckedData[pictureId] || {},
        checkList = treeChecked[defaultCheckedBoxDataKey] || [],
        showChildren =
          this.$store.getters.getShowChildListData[pictureId] || {},
        showList = showChildren[defaultCheckedBoxDataKey] || [];
      newTreeList.forEach((item) => {
        if (showList.length) {
          if (showList.indexOf(item[defaultCheckKey]) > -1) {
            item.show = true;
            item.showChildren = true;
          }
          if (showList.indexOf(item.parentid) > -1) {
            item.show = true;
            item.showChildren = true;
          }
        } else {
          item.show = item.metaLevel == 1;
          item.showChildren = false;
        }
        if (checkList.length) {
          if (checkList.indexOf(item[defaultCheckKey]) > -1) {
            item.checked = true;
          }
        } else {
          item.checked = false;
        }
      });
    },
    hideCheckInfo() {
      this.updataStore();
      this.$emit("meta-treeChecked-checked");
    },
    init() {
      this.resetTreeData = this.treeData.map((org) => this.resetTree(org));
      this.newTreeList = this.getTreeDataList(this.resetTreeData);
    },
  },
  watch: {
    checkedBoxDataKey: {
      deep: true,
      immediate: true,
      handler() {
        this.init();
        this.updataTreeList();
      },
    },
  },
};
</script>
<style lang="scss" scoped>
.meta-treeChecked-wrap {
  .van-overlay {
    width: 100%;
    height: calc(100% - 11.7vw);
    margin-top: 11.7vw;
    box-sizing: border-box;
  }
  .treeChecked-wrapper {
    background-color: #f6f6f9;
    height: 100%;
    box-sizing: border-box;
  }
  .meta-treeChecked-header {
    width: 100%;
    .header {
      position: relative;
      height: 13.86vw;
      overflow: hidden;
      svg {
        position: absolute;
        top: 4.78vw;
        left: 5.06vw;
        width: 2.43vw;
        height: 4.26vw;
      }
      .title {
        width: 80%;
        height: 5.3vw;
        line-height: 5.3vw;
        text-align: center;
        margin: 4.26vw auto;
      }
    }
  }
  .meta-treeChecked-info {
    height: calc(100% - 40vw);
    overflow-y: auto;
  }
  .list-item {
    display: flex;
    align-items: center;
    justify-content: flex-start;
  }
  .open-handle {
    width: calc(100% - 10vw);
    display: flex;
    align-items: center;
    justify-content: space-around;
  }
  .open-icon {
    width: 3.2vw;
    height: 10.66vw;
    margin-right: 2.13vw;
    box-sizing: border-box;
    svg {
      margin-top: 4.4vw;
      height: 1.86vw;
    }
    .down-icon {
      width: 1.86vw;
      height: 3.23vw;
    }
    .right-icon {
      width: 3.23vw;
      height: 1.86vw;
    }
  }
  .check-title {
    width: calc(100% - 5.5vw);
  }
  .check-box {
    width: 10vw;
    height: 10.66vw;
    display: flex;
    align-items: center;
    justify-content: center;
  }
}
</style>