You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

197 lines
5.2 KiB

<template>
<a-spin :spinning="treeState.loading">
<div class="ns-tree-container">
<div class="ns-tree-form">
<div v-if="header" class="ns-tree-title">
<!-- <ns-icon :name="header.icon" size="14" /> -->
<span class="ns-title-extra-box">{{ 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">
<ns-tree v-if="treeData?.length" v-bind="getBindValue" :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>
</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, isEmpty } 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', 'select', 'reload']);
// 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);
// formConfig.value.schemas.forEach((item: any) => {
// if (item.callList) {
// emit('reload');
// }
// });
//只刷新列表
if (formConfig.value.callList && !formConfig.value.defaultSelection) {
emit('reload');
}
}, 200);
const handleSelect = (keys: any, selectedRows: any) => {
if (props.cancelable || !isEmpty(keys)) {
selectedKeys.value = keys;
// props.onSelect && props.onSelect(keys, selectedRows);
emit('select', keys, selectedRows);
}
};
const getBindValue = computed(() => ({
...attrs,
...props,
treeData: treeData.value,
onSelect: handleSelect,
}));
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));
//默认选择第一个 并刷新列表
selectedKeys.value = [];
if (formConfig.value.callList && formConfig.value.defaultSelection) {
handleSelect([treeData.value[0].id], {
selected: true,
event: 'select',
selectedNodes: treeData.value,
node: {
...treeData.value[0],
dataRef: { ...treeData.value[0] },
},
});
// 默认选择第一个
}
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%;
}
}
.ns-tree-container {
display: flex;
flex-direction: column;
&:last-child {
flex: 1;
}
}
</style>