Files
crawler-plugin/admin-frontend-vue/src/pages/account/UserMenuAuthTree.vue
T

68 lines
1.8 KiB
Vue

<script setup lang="ts">
import { onMounted, ref, watch } from 'vue'
import type { MenuOptionNode } from './user-menu-auth'
import { fetchGrantableMenus } from './user-menu-auth-api'
const props = defineProps<{ checked?: number[] }>()
const emit = defineEmits<{
(e: 'update:checked', ids: number[]): void
(e: 'load', ok: boolean): void
}>()
/** 仅暴露 el-tree 我们需要的两个方法,避免整组件类型耦合。 */
type TreeRef = { setCheckedKeys(keys: unknown[]): void; getCheckedKeys(): unknown }
const tree = ref<{ setCheckedKeys(keys: unknown[]): void; getCheckedKeys(): unknown } | null>(null)
const data = ref<MenuOptionNode[]>([])
const loaded = ref(false)
function applyChecked(): void {
const el: TreeRef | null = tree.value
if (!el) return
const ids = Array.isArray(props.checked) ? props.checked.filter((id) => typeof id === 'number' && id > 0) : []
el.setCheckedKeys(ids)
}
function onCheck(): void {
const el: TreeRef | null = tree.value
if (!el) return
const keys = el.getCheckedKeys()
const ids = (Array.isArray(keys) ? keys : []).map((key) => Number(key)).filter((id) => id > 0)
emit('update:checked', ids)
}
async function load(): Promise<void> {
try {
data.value = await fetchGrantableMenus()
loaded.value = true
applyChecked()
emit('load', true)
} catch {
loaded.value = false
emit('load', false)
}
}
onMounted(load)
watch(
() => props.checked,
() => {
if (loaded.value) applyChecked()
},
)
</script>
<template>
<el-scrollbar max-height="300px" class="user-menu-tree-scroll">
<el-tree
ref="tree"
:data="data"
node-key="id"
show-checkbox
check-strictly
default-expand-all
:props="{ label: 'name', children: 'children' }"
@check="onCheck"
/>
</el-scrollbar>
</template>