Commit d81db890dfeb533d60f378ddb86f8ac50a31252b
1 parent
c1178027
feat(api-tree-select): add `api` options to tree-select
添加ApiTreeSelect组件
Showing
9 changed files
with
79 additions
and
0 deletions
CHANGELOG.zh_CN.md
... | ... | @@ -2,6 +2,7 @@ |
2 | 2 | |
3 | 3 | - **NoticeList** 添加分页、超长自动省略、标题点击事件、标题删除线等功能 |
4 | 4 | - **MixSider** 优化 Mix 菜单布局时 底部折叠按钮 的样式,与其它菜单布局时的风格保持一致 |
5 | +- **ApiTreeSelect** 扩展`antdv`的`TreeSelect`组件,支持远程数据源,用法类似`ApiSelect` | |
5 | 6 | - 可以为不同的用户指定不同的后台首页: |
6 | 7 | - 在`getUserInfo`接口返回的用户信息中增加`homePath`字段(可选)即可为当前用户定制首页路径 |
7 | 8 | ... | ... |
mock/demo/tree-demo.ts
0 → 100644
1 | +import { MockMethod } from 'vite-plugin-mock'; | |
2 | +import { resultSuccess } from '../_util'; | |
3 | + | |
4 | +const demoTreeList = (keyword) => { | |
5 | + const result = { | |
6 | + list: [] as Recordable[], | |
7 | + }; | |
8 | + for (let index = 0; index < 5; index++) { | |
9 | + const children: Recordable[] = []; | |
10 | + for (let j = 0; j < 3; j++) { | |
11 | + children.push({ | |
12 | + title: `${keyword ?? ''}选项${index}-${j}`, | |
13 | + value: `${index}-${j}`, | |
14 | + key: `${index}-${j}`, | |
15 | + }); | |
16 | + } | |
17 | + result.list.push({ | |
18 | + title: `${keyword ?? ''}选项${index}`, | |
19 | + value: `${index}`, | |
20 | + key: `${index}`, | |
21 | + children, | |
22 | + }); | |
23 | + } | |
24 | + return result; | |
25 | +}; | |
26 | + | |
27 | +export default [ | |
28 | + { | |
29 | + url: '/basic-api/tree/getDemoOptions', | |
30 | + timeout: 1000, | |
31 | + method: 'get', | |
32 | + response: ({ query }) => { | |
33 | + const { keyword } = query; | |
34 | + console.log(keyword); | |
35 | + return resultSuccess(demoTreeList(keyword)); | |
36 | + }, | |
37 | + }, | |
38 | +] as MockMethod[]; | ... | ... |
src/api/demo/tree.ts
0 → 100644
1 | +import { defHttp } from '/@/utils/http/axios'; | |
2 | + | |
3 | +enum Api { | |
4 | + TREE_OPTIONS_LIST = '/tree/getDemoOptions', | |
5 | +} | |
6 | + | |
7 | +/** | |
8 | + * @description: Get sample options value | |
9 | + */ | |
10 | +export const treeOptionsListApi = (params?: Recordable) => | |
11 | + defHttp.get<Recordable[]>({ url: Api.TREE_OPTIONS_LIST, params }); | ... | ... |
src/components/Form/src/componentMap.ts
... | ... | @@ -22,6 +22,7 @@ import { |
22 | 22 | |
23 | 23 | import RadioButtonGroup from './components/RadioButtonGroup.vue'; |
24 | 24 | import ApiSelect from './components/ApiSelect.vue'; |
25 | +import ApiTreeSelect from './components/ApiTreeSelect.vue'; | |
25 | 26 | import { BasicUpload } from '/@/components/Upload'; |
26 | 27 | import { StrengthMeter } from '/@/components/StrengthMeter'; |
27 | 28 | import { IconPicker } from '/@/components/Icon'; |
... | ... | @@ -40,6 +41,7 @@ componentMap.set('AutoComplete', AutoComplete); |
40 | 41 | componentMap.set('Select', Select); |
41 | 42 | componentMap.set('ApiSelect', ApiSelect); |
42 | 43 | componentMap.set('TreeSelect', TreeSelect); |
44 | +componentMap.set('ApiTreeSelect', ApiTreeSelect); | |
43 | 45 | componentMap.set('Switch', Switch); |
44 | 46 | componentMap.set('RadioButtonGroup', RadioButtonGroup); |
45 | 47 | componentMap.set('RadioGroup', Radio.Group); | ... | ... |
src/components/Form/src/components/ApiTreeSelect.vue
0 → 100644
1 | +<template> <a-tree-select v-bind="getAttrs"> <template #[item]="data" v-for="item in Object.keys($slots)"> <slot :name="item" v-bind="data"></slot> </template> <template #suffixIcon v-if="loading"> <LoadingOutlined spin /> </template> </a-tree-select> </template> <script lang="ts"> import { computed, defineComponent, watch, ref, onMounted, unref } from 'vue'; import { TreeSelect } from 'ant-design-vue'; import { isArray, isFunction } from '/@/utils/is'; import { get } from 'lodash-es'; import { propTypes } from '/@/utils/propTypes'; import { LoadingOutlined } from '@ant-design/icons-vue'; export default defineComponent({ name: 'ApiTreeSelect', components: { ATreeSelect: TreeSelect, LoadingOutlined }, props: { api: { type: Function as PropType<(arg?: Recordable) => Promise<Recordable>> }, params: { type: Object }, immediate: { type: Boolean, default: true }, resultField: propTypes.string.def(''), }, emits: ['options-change'], setup(props, { attrs, emit }) { const treeData = ref<Recordable[]>([]); const isFirstLoaded = ref<Boolean>(false); const loading = ref(false); const getAttrs = computed(() => { return { ...(props.api ? { treeData: unref(treeData) } : {}), ...attrs, }; }); watch([() => props.params, () => props.immediate], () => { isFirstLoaded.value && fetch(); }); onMounted(() => { props.immediate && fetch(); }); async function fetch() { const { api } = props; if (!api || !isFunction(api)) return; loading.value = true; treeData.value = []; let result; try { result = await api(props.params); } catch (e) { console.error(e); } loading.value = false; if (!result) return; if (!isArray(result)) { result = get(result, props.resultField); } treeData.value = (result as Recordable[]) || []; isFirstLoaded.value = true; emit('options-change', treeData.value); } return { getAttrs, loading }; }, }); </script> | |
0 | 2 | \ No newline at end of file | ... | ... |
src/components/Form/src/types/index.ts
src/views/demo/form/index.vue
... | ... | @@ -46,6 +46,7 @@ |
46 | 46 | |
47 | 47 | import { optionsListApi } from '/@/api/demo/select'; |
48 | 48 | import { useDebounceFn } from '@vueuse/core'; |
49 | + import { treeOptionsListApi } from '/@/api/demo/tree'; | |
49 | 50 | |
50 | 51 | const provincesOptions = [ |
51 | 52 | { |
... | ... | @@ -348,6 +349,20 @@ |
348 | 349 | defaultValue: '0', |
349 | 350 | }, |
350 | 351 | { |
352 | + field: 'field33', | |
353 | + component: 'ApiTreeSelect', | |
354 | + label: '远程下拉树', | |
355 | + helpMessage: ['ApiTreeSelect组件', '使用接口提供的数据生成选项'], | |
356 | + required: true, | |
357 | + componentProps: { | |
358 | + api: treeOptionsListApi, | |
359 | + resultField: 'list', | |
360 | + }, | |
361 | + colProps: { | |
362 | + span: 8, | |
363 | + }, | |
364 | + }, | |
365 | + { | |
351 | 366 | field: 'field20', |
352 | 367 | component: 'InputNumber', |
353 | 368 | label: '字段20', | ... | ... |
src/views/demo/table/EditCellTable.vue
src/views/demo/table/EditRowTable.vue
... | ... | @@ -80,6 +80,10 @@ |
80 | 80 | label: 'Option2', |
81 | 81 | value: '2', |
82 | 82 | }, |
83 | + { | |
84 | + label: 'Option3', | |
85 | + value: '3', | |
86 | + }, | |
83 | 87 | ], |
84 | 88 | }, |
85 | 89 | width: 200, |
... | ... | @@ -91,6 +95,9 @@ |
91 | 95 | editComponent: 'ApiSelect', |
92 | 96 | editComponentProps: { |
93 | 97 | api: optionsListApi, |
98 | + resultField: 'list', | |
99 | + labelField: 'name', | |
100 | + valueField: 'id', | |
94 | 101 | }, |
95 | 102 | width: 200, |
96 | 103 | }, | ... | ... |