<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 setup>
import { computed, reactive, toRefs, watch, nextTick, onMounted } from "vue";
import BgPermissionOption from "./bg-permission-option.vue";

const props = defineProps({
  values: {
    type: Array,
    default: () => [],
  }, // 选中的值
  options: {
    type: Array,
    default: () => [],
  }, // 菜单项
  props: {
    type: Object,
    default: () => ({
      name: "name",
      value: "value",
      children: "children",
    }),
  }, // 配置项（节点的一些字段）
  selectAll: {
    type: Boolean,
    default: true,
  }, // 是否在顶部显示全选按钮
});

const state = reactive({
  initFlag: true, // 是否需要初始化
  permissionData: [], // 数据项
  isSelected: false, // 是否全选
  isIndeterminate: false, // 是否半选
});

const emit = defineEmits(["changeMenu"]);

const depth = computed(() => {
  return getDepth({ children: state.permissionData });
});

watch(
  () => props.values,
  () => {
    if (state.initFlag) {
      initPermissionData();
    }
    state.initFlag = true;
  }
);

watch(
  () => props.options,
  () => {
    initPermissionData();
  }
);

const getDepth = (node) => {
  if (!node.children || node.children.length === 0) {
    return 1;
  }

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

  return Math.max(...maxChildrenDepth) + 1;
}; // 获取JsonTree深度

const initPermissionData = () => {
  let { name: nameProp, value: valueProp, children: childrenProp, remark: remarkProp } = props.props;
  let permissionData = [];
  let traverseOptions = (item) => {
    let result = {};
    let name = item[nameProp];
    let value = item[valueProp];
    let children = item[childrenProp];
    let isSelected = props.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;
  };
  props.options.forEach((v) => {
    permissionData.push(traverseOptions(v));
  });
  state.permissionData = permissionData;
  // 初始化完数据项后要更新一下全选半选状态
  if (permissionData.length > 0) {
    nextTick(() => {
      changeChild();
    });
  }
}; // 初始化数据项

const dealData = (arr, flag) => {
  arr.forEach((e) => {
    e.isSelected = !!flag;
    if (e.children && e.children.length) {
      dealData(e.children, flag);
    }
  });
};

const changeSelf = () => {
  let isSelected = state.isSelected;
  let children = state.permissionData || [];
  // 将自己的选中状态赋值给子级
  if (children.length > 0) {
    dealData(children, isSelected);
  }
  // 关于自己选中都是全选和不选，所以不存在半选状态
  state.isIndeterminate = false;
  // 出发双向绑定事件
  changeValues();
}; // 改变全选状态
const changeChild = () => {
  let isSelected = true;
  let isIndeterminate = false;
  let children = state.permissionData;
  children.forEach((v, i) => {
    isSelected = isSelected && v.isSelected; // 所有子级都为选中时，自己才为选中状态
    isIndeterminate = isIndeterminate || v.isIndeterminate || v.isSelected; // 只要有下级为半选状态，自己就为半选状态
  });
  // 自己为全选状态时，半选不生效
  isIndeterminate = isSelected ? false : isIndeterminate;
  // 赋值
  state.isSelected = isSelected;
  state.isIndeterminate = isIndeterminate;
  // 出发双向绑定事件
  changeValues();
}; // 下级选中状态发生变化

const changeValues = () => {
  let values = [];
  let i = 1;
  let traverseOptions = ({ isSelected, isIndeterminate, value, children, name }) => {
    if (isSelected) {
      values.push(value);
    }
    if (isIndeterminate) {
      values.push(value);
    }
    if (children && children.length > 0) {
      children.forEach((v) => {
        traverseOptions(v);
      });
    }
  };
  state.permissionData.forEach((v) => {
    traverseOptions(v);
  });
  state.initFlag = false; // 防止在watch中出发重新初始化
  emit("changeMenu", values);
}; // 双向绑定的处理

onMounted(() => {
  initPermissionData();
});

const { permissionData, isSelected, isIndeterminate } = toRefs(state);
</script>
