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 | \ No newline at end of file | 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 | +} |