<script setup lang="ts">
import { onMounted, ref, watch, nextTick, computed } from "vue";
import { getMenuListTree } from "@/api/system/menu";
import { type CheckboxValueType } from "element-plus";

onMounted(() => {
  getMenuList();
  console.log(model.value);
});

const emit = defineEmits(["update:modelValue"]);

const menuList = ref([]);
const getMenuList = async () => {
  let res = await getMenuListTree();
  menuList.value = res.data;
};

const model = defineModel<number[]>();

watch(
  model,
  (value: number[]) => {
    nextTick(() => {
      setCheckedKeys(value, true);
    });
  },
  { immediate: true, deep: true }
);

const menuRef = ref(null);

const menuCheckStrictly = ref(true);
const menuExpand = ref(false);
const handleCheckedTreeExpand = (value: CheckboxValueType) => {
  // 递归展开
  for (let i = 0; i < menuList.value.length; i++) {
    menuRef.value.store.nodesMap[menuList.value[i].id].expanded = value;
  }
};

// 只返回所有叶子节点 id
const getLeafKeys = (data: any[]) => {
  const keys: number[] = [];
  data.forEach(node => {
    if (node.children && node.children.length) {
      keys.push(...getLeafKeys(node.children));
    } else {
      keys.push(node.id);
    }
  });
  return keys;
};

// 叶子节点总集合（随菜单树变化动态计算）
const allLeafKeys = computed(() => getLeafKeys(menuList.value));

// 全选状态：由 model 与叶子总集合计算；设置时驱动 model 更新
const allSelected = computed({
  get() {
    const leafKeys = allLeafKeys.value;
    if (!leafKeys.length) return false;
    // model 中的所有 key 都在叶子集合，并且数量一致视为全选
    return (
      model.value.length === leafKeys.length &&
      model.value.every(k => leafKeys.includes(k))
    );
  },
  set(checked: boolean) {
    model.value = checked ? [...allLeafKeys.value] : [];
  }
});

// 半选状态：仅基于数量计算
const indeterminate = computed(() => {
  const total = allLeafKeys.value.length;
  const count = model.value.length;
  return count > 0 && count < total;
});

// 通过 watch(model) 来同步 UI 勾选状态，因此这里不再需要手动方法

const handleTreeCheck = (_: any, _checkedState: any) => {
  const leafKeys = menuRef.value?.getCheckedKeys(true) ?? [];
  model.value = leafKeys;
  emit("update:modelValue", leafKeys);
};

// 递归获取所有节点key
const getAllKeys = () => {
  // 目前被选中的菜单节点
  let checkedKeys = menuRef.value.getCheckedKeys();
  // 半选中的菜单节点
  let halfCheckedKeys = menuRef.value.getHalfCheckedKeys();
  checkedKeys.unshift.apply(checkedKeys, halfCheckedKeys);
  return checkedKeys;
};

const setCheckedKeys = (keys: number[], leafOnly: boolean) => {
  return menuRef.value.setCheckedKeys(keys, leafOnly);
};

// 级联开关变化时，重新应用当前 model 的叶子集合到树上
watch(menuCheckStrictly, () => {
  nextTick(() => setCheckedKeys(model.value, true));
});

defineExpose({
  getAllKeys
});
</script>

<template>
  <div style="width: 100%">
    <el-row type="flex" justify="space-between" align="middle">
      <el-col :span="4">
        <el-checkbox
          v-model="menuExpand"
          @change="handleCheckedTreeExpand($event)"
          >全部展开/折叠
        </el-checkbox>
      </el-col>
      <el-col :span="4">
        <el-checkbox v-model="allSelected" :indeterminate="indeterminate"
          >全选/全不选
        </el-checkbox>
      </el-col>
      <el-col :span="4">
        <el-checkbox v-model="menuCheckStrictly">级联下级 </el-checkbox>
      </el-col>
    </el-row>
    <el-tree
      ref="menuRef"
      class="border-1 rounded-[4px] border-[#e5e6e7] dark:border-[#4C4D4F]"
      :data="menuList"
      show-checkbox
      node-key="id"
      empty-text="加载中，请稍后"
      :check-strictly="!menuCheckStrictly"
      @check="handleTreeCheck"
    />
  </div>
</template>
