<template>
  <div class="bg-permission">
    <div class="permission-header" v-if="selectAll">
      <el-checkbox
        v-model="isSelected"
        :indeterminate="isIndeterminate"
        @change="changeSelf"
      >
        全选
      </el-checkbox>
    </div>
    <div class="permission-null" v-if="permissionData.length === 0">
      <p>暂无数据</p>
    </div>
    <div class="bg-permission-option--list" v-else>
      <BgPermissionOption
        v-for="(item, index) in permissionData"
        :ref="`child${index}`"
        :option="item"
        :key="`opt_${index}`"
        :props="props"
        :depth="depth"
        @change="changeChild"
      />
    </div>
  </div>
</template>

<script>
import { val } from "dom7";
import BgPermissionOption from "./bg-permission-option.vue";

export default {
  name: "BgPermission",
  components: {
    BgPermissionOption,
  },
  model: {
    prop: "values",
    event: "change",
  },
  props: {
    values: {
      type: Array,
      default: () => [],
    }, // 选中的值
    options: {
      type: Array,
      default: () => [],
    }, // 菜单项
    props: {
      type: Object,
      default: () => ({
        name: "name",
        value: "value",
        children: "children",
      }),
    }, // 配置项（节点的一些字段）
    selectAll: {
      type: Boolean,
      default: true,
    }, // 是否在顶部显示全选按钮
  },
  data() {
    return {
      initFlag: true, // 是否需要初始化
      permissionData: [], // 数据项
      isSelected: false, // 是否全选
      isIndeterminate: false, // 是否半选
    };
  },
  computed: {
    depth() {
      return this.getDepth({ children: this.permissionData });
    }, // 数据层级深度
  },
  watch: {
    values: {
      handler() {
        if (this.initFlag) {
          this.initPermissionData();
        }

        this.initFlag = true;
      },
      deep: true,
    },
    options: {
      handler() {
        this.initPermissionData();
      },
      deep: true,
    },
  },
  methods: {
    initPermissionData() {
      let {
        name: nameProp,
        value: valueProp,
        children: childrenProp,
        remark: remarkProp,
      } = this.props;
      let permissionData = [];
      let traverseOptions = (item) => {
        let result = {};
        let name = item[nameProp];
        let value = item[valueProp];
        let children = item[childrenProp];
        let isSelected = this.values.indexOf(value) > -1;
        let isIndeterminate = false;
        let remark = item[remarkProp];

        result.name = name;
        result.value = value;
        result.remark = remark;

        if (children && children.length > 0) {
          
          result.children = [];
          isSelected = true; // 如果存在子节点，则根据子节点反推当前节点选中状态
          isIndeterminate = false; // 当前节点半选状态
          children.forEach((v) => {
            result.children.push(traverseOptions(v));
          });

          result.children.forEach((v) => {
            isSelected = isSelected && v.isSelected; // 所有子节点都为选中状态，则当前节点选中状态为真
            isIndeterminate = isIndeterminate || v.isSelected || v.isIndeterminate; // 所有下级节点只要存在一个选中状态，则当前节点半选状态为真
          });
          
        }

        result.isSelected = isSelected;
        result.isIndeterminate = isSelected ? false : isIndeterminate; // 当前节点选中状态为真时，半选为假

        return result;
      };

      this.options.forEach((v) => {
        permissionData.push(traverseOptions(v));
      });
      this.permissionData = permissionData;

      // 初始化完数据项后要更新一下全选半选状态
      if (permissionData.length > 0) {
        this.$nextTick(() => {
          this.changeChild();
        });
      }
    }, // 初始化数据项
    getDepth(node) {
      if (!node.children || node.children.length === 0) {
        return 1;
      }

      let maxChildrenDepth = [...node.children].map((v) => this.getDepth(v));

      return Math.max(...maxChildrenDepth) + 1;
    }, // 获取JsonTree深度
    changeSelf() {
      let isSelected = this.isSelected;
      let children = this.permissionData || [];

      // 将自己的选中状态赋值给子级
      if (children.length > 0) {
        children.forEach((v, i) => {
          v.isSelected = isSelected;

          this.$nextTick(() => {
            this.$refs[`child${i}`][0].changeSelf();
          });
        });
      }

      // 关于自己选中都是全选和不选，所以不存在半选状态
      this.isIndeterminate = false;

      // 出发双向绑定事件
      this.changeValues();
    }, // 改变全选状态
    changeChild() {
      let isSelected = true;
      let isIndeterminate = false;
      let children = this.permissionData;

      children.forEach((v, i) => {
        isSelected = isSelected && v.isSelected; // 所有子级都为选中时，自己才为选中状态
        isIndeterminate = isIndeterminate || v.isIndeterminate || v.isSelected; // 只要有下级为半选状态，自己就为半选状态
      });

      // 自己为全选状态时，半选不生效
      isIndeterminate = isSelected ? false : isIndeterminate;

      // 赋值
      this.isSelected = isSelected;
      this.isIndeterminate = isIndeterminate;

      // 出发双向绑定事件
      this.changeValues();
    }, // 下级选中状态发生变化
    changeValues() {
      let values = [];
      let traverseOptions = ({
        isSelected,
        isIndeterminate,
        value,
        children,
      }) => {
        if (isSelected) {
          values.push(value);
        }
        if (isIndeterminate) {
          values.push(value);
        }

        if (children && children.length > 0) {
          children.forEach((v) => {
            traverseOptions(v);
          });
        }
      };

      this.permissionData.forEach((v) => {
        traverseOptions(v);
      });
      this.initFlag = false; // 防止在watch中出发重新初始化
      this.$emit("changeMenu", values);
    }, // 双向绑定的处理
  },
  mounted() {
    this.initPermissionData();
  },
};
</script>
