<template> <a-spin :spinning="treeState.loading"> <div class="ns-tree-form"> <div v-if="header" class="ns-tree-title"> <ns-icon :name="header.icon" size="14" /> <span>{{ header.title }}</span> </div> <div v-if="!formConfig?.schema"> <ns-form ref="formElRef" v-bind="formConfig" :model="formModel" @finish="formFinish" /> </div> </div> <div style="min-height: 150px; overflow-y: scroll"> <ns-tree v-if="treeData?.length" v-bind="getBindValue" v-model:selectedKeys="selectedKeys"> <template #[item]="data" v-for="(item, index) in Object.keys($slots)" :key="index"> <slot :name="item" v-bind="{ ...data, formModel } || {}"></slot> </template> </ns-tree> <!-- <a-empty v-if="!treeData?.length" /> --> </div> </a-spin> </template> <script lang="ts" setup> import { computed, nextTick, reactive, ref, unref, useAttrs, watch } from 'vue'; import { TreeDataItem } from 'ant-design-vue/es/tree/Tree'; import { useApi } from '/nerv-lib/use/use-api'; import { AxiosRequestConfig } from 'axios'; import { get } from 'lodash-es'; import { useRoute } from 'vue-router'; import { debounce } from 'lodash-es'; import { treeProps, treeFormProps } from '/nerv-lib/component/tree/props'; defineOptions({ name: 'NsTreeApi', }); const emit = defineEmits(['update:treeData']); // const model = defineModel('treeData'); const formElRef = ref(); const props = defineProps(treeProps); const treeData = ref(props.treeData); const selectedKeys = ref(props.selectedKeys || []); const { httpRequest } = useApi(); const requestConfig: AxiosRequestConfig = { method: 'get' }; const route = useRoute(); const attrs = useAttrs(); const formModel = reactive({}); watch( () => props.treeData, (val) => { treeData.value = val; }, { deep: true, }, ); const treeState = reactive({ loading: false, }); const formConfig = computed(() => { return { ...treeFormProps, ...props.formConfig, }; }); const isSticky: any = computed(() => { return props.isSticky ? 'sticky' : 'static'; }); const formFinish = debounce((data: object) => { selectedKeys.value = []; getData(data); }, 200); const getBindValue = computed(() => ({ ...attrs, ...props, treeData: treeData.value, })); const setLoading = (loading: boolean) => { treeState.loading = loading; }; const httpPrams = computed(() => { return { ...route.params, ...route.query, ...props.params, ...formModel }; }); const getData = (params = {}) => { const { api, transform, resultField } = props; treeData.value = []; if (!api) return; setLoading(true); httpRequest({ api, params: { ...httpPrams.value, ...params }, pathParams: { ...route.params, ...route.query, ...params }, requestConfig: { ...requestConfig, data: { ...httpPrams.value, ...params } }, }) .then((res) => { treeData.value = transform(get(res, resultField)); emit('update:treeData', treeData.value); // model.value = treeData.value; }) .finally(() => { setLoading(false); }); }; getData(); const treeReload = (params) => { getData(params); }; const clearSelectedKeys = () => { selectedKeys.value = []; }; defineExpose({ treeReload, clearSelectedKeys }); </script> <style lang="less" scoped> @gap: 16px; :deep(.ant-form-item) { margin-bottom: @gap; } :deep(.ns-form::after) { display: none; } .ns-tree-form { position: v-bind(isSticky); top: 0; background-color: @white; z-index: 2; & ~ div { padding: 0 @gap !important; } } .ns-tree-title { font-weight: bold; user-select: text; padding: @gap; // margin-bottom: @gap; // padding-bottom: 10px; // border-bottom: 1px solid #e9e9e9; > span { padding-left: 6px; } & ~ div { padding: 0 @gap !important; width: 100%; } } </style>