Commit 67d514ad0e27083328c853e010a8eee9ed7f0408
Committed by
GitHub
1 parent
929141be
新增 api tree 组件 (#1582)
* tsconfig 增加 types , 解决webstorm提示错误 * api-tree
Showing
4 changed files
with
90 additions
and
0 deletions
src/components/Form/index.ts
... | ... | @@ -9,6 +9,7 @@ export { useForm } from './src/hooks/useForm'; |
9 | 9 | export { default as ApiSelect } from './src/components/ApiSelect.vue'; |
10 | 10 | export { default as RadioButtonGroup } from './src/components/RadioButtonGroup.vue'; |
11 | 11 | export { default as ApiTreeSelect } from './src/components/ApiTreeSelect.vue'; |
12 | +export { default as ApiTree } from './src/components/ApiTree.vue'; | |
12 | 13 | export { default as ApiRadioGroup } from './src/components/ApiRadioGroup.vue'; |
13 | 14 | export { default as ApiCascader } from './src/components/ApiCascader.vue'; |
14 | 15 | ... | ... |
src/components/Form/src/componentMap.ts
... | ... | @@ -24,6 +24,7 @@ import { |
24 | 24 | import ApiRadioGroup from './components/ApiRadioGroup.vue'; |
25 | 25 | import RadioButtonGroup from './components/RadioButtonGroup.vue'; |
26 | 26 | import ApiSelect from './components/ApiSelect.vue'; |
27 | +import ApiTree from './components/ApiTree.vue'; | |
27 | 28 | import ApiTreeSelect from './components/ApiTreeSelect.vue'; |
28 | 29 | import ApiCascader from './components/ApiCascader.vue'; |
29 | 30 | import { BasicUpload } from '/@/components/Upload'; |
... | ... | @@ -43,6 +44,7 @@ componentMap.set('AutoComplete', AutoComplete); |
43 | 44 | |
44 | 45 | componentMap.set('Select', Select); |
45 | 46 | componentMap.set('ApiSelect', ApiSelect); |
47 | +componentMap.set('ApiTree', ApiTree); | |
46 | 48 | componentMap.set('TreeSelect', TreeSelect); |
47 | 49 | componentMap.set('ApiTreeSelect', ApiTreeSelect); |
48 | 50 | componentMap.set('ApiRadioGroup', ApiRadioGroup); | ... | ... |
src/components/Form/src/components/ApiTree.vue
0 → 100644
1 | +<template> | |
2 | + <a-tree v-bind="getAttrs" @change="handleChange"> | |
3 | + <template #[item]="data" v-for="item in Object.keys($slots)"> | |
4 | + <slot :name="item" v-bind="data || {}"></slot> | |
5 | + </template> | |
6 | + <template #suffixIcon v-if="loading"> | |
7 | + <LoadingOutlined spin /> | |
8 | + </template> | |
9 | + </a-tree> | |
10 | +</template> | |
11 | + | |
12 | +<script lang="ts"> | |
13 | + import { computed, defineComponent, watch, ref, onMounted, unref } from 'vue'; | |
14 | + import { Tree } from 'ant-design-vue'; | |
15 | + import { isArray, isFunction } from '/@/utils/is'; | |
16 | + import { get } from 'lodash-es'; | |
17 | + import { propTypes } from '/@/utils/propTypes'; | |
18 | + import { LoadingOutlined } from '@ant-design/icons-vue'; | |
19 | + export default defineComponent({ | |
20 | + name: 'ApiTree', | |
21 | + components: { ATree: Tree, LoadingOutlined }, | |
22 | + props: { | |
23 | + api: { type: Function as PropType<(arg?: Recordable) => Promise<Recordable>> }, | |
24 | + params: { type: Object }, | |
25 | + immediate: { type: Boolean, default: true }, | |
26 | + resultField: propTypes.string.def(''), | |
27 | + }, | |
28 | + emits: ['options-change', 'change'], | |
29 | + setup(props, { attrs, emit }) { | |
30 | + const treeData = ref<Recordable[]>([]); | |
31 | + const isFirstLoaded = ref<Boolean>(false); | |
32 | + const loading = ref(false); | |
33 | + const getAttrs = computed(() => { | |
34 | + return { | |
35 | + ...(props.api ? { treeData: unref(treeData) } : {}), | |
36 | + ...attrs, | |
37 | + }; | |
38 | + }); | |
39 | + | |
40 | + function handleChange(...args) { | |
41 | + emit('change', ...args); | |
42 | + } | |
43 | + | |
44 | + watch( | |
45 | + () => props.params, | |
46 | + () => { | |
47 | + !unref(isFirstLoaded) && fetch(); | |
48 | + }, | |
49 | + { deep: true }, | |
50 | + ); | |
51 | + | |
52 | + watch( | |
53 | + () => props.immediate, | |
54 | + (v) => { | |
55 | + v && !isFirstLoaded.value && fetch(); | |
56 | + }, | |
57 | + ); | |
58 | + | |
59 | + onMounted(() => { | |
60 | + props.immediate && fetch(); | |
61 | + }); | |
62 | + | |
63 | + async function fetch() { | |
64 | + const { api } = props; | |
65 | + if (!api || !isFunction(api)) return; | |
66 | + loading.value = true; | |
67 | + treeData.value = []; | |
68 | + let result; | |
69 | + try { | |
70 | + result = await api(props.params); | |
71 | + } catch (e) { | |
72 | + console.error(e); | |
73 | + } | |
74 | + loading.value = false; | |
75 | + if (!result) return; | |
76 | + if (!isArray(result)) { | |
77 | + result = get(result, props.resultField); | |
78 | + } | |
79 | + treeData.value = (result as Recordable[]) || []; | |
80 | + isFirstLoaded.value = true; | |
81 | + emit('options-change', treeData.value); | |
82 | + } | |
83 | + return { getAttrs, loading, handleChange }; | |
84 | + }, | |
85 | + }); | |
86 | +</script> | ... | ... |