Commit 59eb828d4dbaf8a84122e5321b522ae07cbe631e
1 parent
52af1dd0
style: fixed line break style
修正换行符
Showing
2 changed files
with
176 additions
and
92 deletions
src/components/Form/src/components/ApiTreeSelect.vue
1 | -<template> <a-tree-select v-bind="getAttrs" @change="handleChange"> <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', '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, }; }); function handleChange(...args) { emit('change', ...args); } watch( () => props.params, () => { isFirstLoaded.value && fetch(); } ); watch( () => props.immediate, (v) => { v && !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, handleChange }; }, }); </script> | |
2 | 1 | \ No newline at end of file |
2 | +<template> | |
3 | + <a-tree-select v-bind="getAttrs" @change="handleChange"> | |
4 | + <template #[item]="data" v-for="item in Object.keys($slots)"> | |
5 | + <slot :name="item" v-bind="data"></slot> | |
6 | + </template> | |
7 | + <template #suffixIcon v-if="loading"> | |
8 | + <LoadingOutlined spin /> | |
9 | + </template> | |
10 | + </a-tree-select> | |
11 | +</template> | |
12 | + | |
13 | +<script lang="ts"> | |
14 | + import { computed, defineComponent, watch, ref, onMounted, unref } from 'vue'; | |
15 | + import { TreeSelect } from 'ant-design-vue'; | |
16 | + import { isArray, isFunction } from '/@/utils/is'; | |
17 | + import { get } from 'lodash-es'; | |
18 | + import { propTypes } from '/@/utils/propTypes'; | |
19 | + import { LoadingOutlined } from '@ant-design/icons-vue'; | |
20 | + export default defineComponent({ | |
21 | + name: 'ApiTreeSelect', | |
22 | + components: { ATreeSelect: TreeSelect, LoadingOutlined }, | |
23 | + props: { | |
24 | + api: { type: Function as PropType<(arg?: Recordable) => Promise<Recordable>> }, | |
25 | + params: { type: Object }, | |
26 | + immediate: { type: Boolean, default: true }, | |
27 | + resultField: propTypes.string.def(''), | |
28 | + }, | |
29 | + emits: ['options-change', 'change'], | |
30 | + setup(props, { attrs, emit }) { | |
31 | + const treeData = ref<Recordable[]>([]); | |
32 | + const isFirstLoaded = ref<Boolean>(false); | |
33 | + const loading = ref(false); | |
34 | + const getAttrs = computed(() => { | |
35 | + return { | |
36 | + ...(props.api ? { treeData: unref(treeData) } : {}), | |
37 | + ...attrs, | |
38 | + }; | |
39 | + }); | |
40 | + | |
41 | + function handleChange(...args) { | |
42 | + emit('change', ...args); | |
43 | + } | |
44 | + | |
45 | + watch( | |
46 | + () => props.params, | |
47 | + () => { | |
48 | + isFirstLoaded.value && fetch(); | |
49 | + } | |
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> | ... | ... |
src/components/Form/src/types/formItem.ts
1 | -import type { NamePath } from 'ant-design-vue/lib/form/interface'; | |
2 | -import type { ColProps } from 'ant-design-vue/lib/grid/Col'; | |
3 | -import type { HTMLAttributes, VNodeChild } from 'vue'; | |
4 | - | |
5 | -export interface FormItem { | |
6 | - /** | |
7 | - * Used with label, whether to display : after label text. | |
8 | - * @default true | |
9 | - * @type boolean | |
10 | - */ | |
11 | - colon?: boolean; | |
12 | - | |
13 | - /** | |
14 | - * The extra prompt message. It is similar to help. Usage example: to display error message and prompt message at the same time. | |
15 | - * @type any (string | slot) | |
16 | - */ | |
17 | - extra?: string | VNodeChild | JSX.Element; | |
18 | - | |
19 | - /** | |
20 | - * Used with validateStatus, this option specifies the validation status icon. Recommended to be used only with Input. | |
21 | - * @default false | |
22 | - * @type boolean | |
23 | - */ | |
24 | - hasFeedback?: boolean; | |
25 | - | |
26 | - /** | |
27 | - * The prompt message. If not provided, the prompt message will be generated by the validation rule. | |
28 | - * @type any (string | slot) | |
29 | - */ | |
30 | - help?: string | VNodeChild | JSX.Element; | |
31 | - | |
32 | - /** | |
33 | - * Label test | |
34 | - * @type any (string | slot) | |
35 | - */ | |
36 | - label?: string | VNodeChild | JSX.Element; | |
37 | - | |
38 | - /** | |
39 | - * The layout of label. You can set span offset to something like {span: 3, offset: 12} or sm: {span: 3, offset: 12} same as with <Col> | |
40 | - * @type Col | |
41 | - */ | |
42 | - labelCol?: ColProps & HTMLAttributes; | |
43 | - | |
44 | - /** | |
45 | - * Whether provided or not, it will be generated by the validation rule. | |
46 | - * @default false | |
47 | - * @type boolean | |
48 | - */ | |
49 | - required?: boolean; | |
50 | - | |
51 | - /** | |
52 | - * The validation status. If not provided, it will be generated by validation rule. options: 'success' 'warning' 'error' 'validating' | |
53 | - * @type string | |
54 | - */ | |
55 | - validateStatus?: '' | 'success' | 'warning' | 'error' | 'validating'; | |
56 | - | |
57 | - /** | |
58 | - * The layout for input controls, same as labelCol | |
59 | - * @type Col | |
60 | - */ | |
61 | - wrapperCol?: ColProps; | |
62 | - /** | |
63 | - * Set sub label htmlFor. | |
64 | - */ | |
65 | - htmlFor?: string; | |
66 | - /** | |
67 | - * text align of label | |
68 | - */ | |
69 | - labelAlign?: 'left' | 'right'; | |
70 | - /** | |
71 | - * a key of model. In the setting of validate and resetFields method, the attribute is required | |
72 | - */ | |
73 | - name?: NamePath; | |
74 | - /** | |
75 | - * validation rules of form | |
76 | - */ | |
77 | - rules?: object | object[]; | |
78 | - /** | |
79 | - * Whether to automatically associate form fields. In most cases, you can setting automatic association. | |
80 | - * If the conditions for automatic association are not met, you can manually associate them. See the notes below. | |
81 | - */ | |
82 | - autoLink?: boolean; | |
83 | - /** | |
84 | - * Whether stop validate on first rule of error for this field. | |
85 | - */ | |
86 | - validateFirst?: boolean; | |
87 | - /** | |
88 | - * When to validate the value of children node | |
89 | - */ | |
90 | - validateTrigger?: string | string[] | false; | |
91 | -} | |
1 | +import type { NamePath } from 'ant-design-vue/lib/form/interface'; | |
2 | +import type { ColProps } from 'ant-design-vue/lib/grid/Col'; | |
3 | +import type { HTMLAttributes, VNodeChild } from 'vue'; | |
4 | + | |
5 | +export interface FormItem { | |
6 | + /** | |
7 | + * Used with label, whether to display : after label text. | |
8 | + * @default true | |
9 | + * @type boolean | |
10 | + */ | |
11 | + colon?: boolean; | |
12 | + | |
13 | + /** | |
14 | + * The extra prompt message. It is similar to help. Usage example: to display error message and prompt message at the same time. | |
15 | + * @type any (string | slot) | |
16 | + */ | |
17 | + extra?: string | VNodeChild | JSX.Element; | |
18 | + | |
19 | + /** | |
20 | + * Used with validateStatus, this option specifies the validation status icon. Recommended to be used only with Input. | |
21 | + * @default false | |
22 | + * @type boolean | |
23 | + */ | |
24 | + hasFeedback?: boolean; | |
25 | + | |
26 | + /** | |
27 | + * The prompt message. If not provided, the prompt message will be generated by the validation rule. | |
28 | + * @type any (string | slot) | |
29 | + */ | |
30 | + help?: string | VNodeChild | JSX.Element; | |
31 | + | |
32 | + /** | |
33 | + * Label test | |
34 | + * @type any (string | slot) | |
35 | + */ | |
36 | + label?: string | VNodeChild | JSX.Element; | |
37 | + | |
38 | + /** | |
39 | + * The layout of label. You can set span offset to something like {span: 3, offset: 12} or sm: {span: 3, offset: 12} same as with <Col> | |
40 | + * @type Col | |
41 | + */ | |
42 | + labelCol?: ColProps & HTMLAttributes; | |
43 | + | |
44 | + /** | |
45 | + * Whether provided or not, it will be generated by the validation rule. | |
46 | + * @default false | |
47 | + * @type boolean | |
48 | + */ | |
49 | + required?: boolean; | |
50 | + | |
51 | + /** | |
52 | + * The validation status. If not provided, it will be generated by validation rule. options: 'success' 'warning' 'error' 'validating' | |
53 | + * @type string | |
54 | + */ | |
55 | + validateStatus?: '' | 'success' | 'warning' | 'error' | 'validating'; | |
56 | + | |
57 | + /** | |
58 | + * The layout for input controls, same as labelCol | |
59 | + * @type Col | |
60 | + */ | |
61 | + wrapperCol?: ColProps; | |
62 | + /** | |
63 | + * Set sub label htmlFor. | |
64 | + */ | |
65 | + htmlFor?: string; | |
66 | + /** | |
67 | + * text align of label | |
68 | + */ | |
69 | + labelAlign?: 'left' | 'right'; | |
70 | + /** | |
71 | + * a key of model. In the setting of validate and resetFields method, the attribute is required | |
72 | + */ | |
73 | + name?: NamePath; | |
74 | + /** | |
75 | + * validation rules of form | |
76 | + */ | |
77 | + rules?: object | object[]; | |
78 | + /** | |
79 | + * Whether to automatically associate form fields. In most cases, you can setting automatic association. | |
80 | + * If the conditions for automatic association are not met, you can manually associate them. See the notes below. | |
81 | + */ | |
82 | + autoLink?: boolean; | |
83 | + /** | |
84 | + * Whether stop validate on first rule of error for this field. | |
85 | + */ | |
86 | + validateFirst?: boolean; | |
87 | + /** | |
88 | + * When to validate the value of children node | |
89 | + */ | |
90 | + validateTrigger?: string | string[] | false; | |
91 | +} | ... | ... |