2 changed files with 176 additions and 92 deletions
@ -1 +1,85 @@ |
|||
<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> |
|||
<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> |
|||
|
|||
@ -1,91 +1,91 @@ |
|||
import type { NamePath } from 'ant-design-vue/lib/form/interface'; |
|||
import type { ColProps } from 'ant-design-vue/lib/grid/Col'; |
|||
import type { HTMLAttributes, VNodeChild } from 'vue'; |
|||
|
|||
export interface FormItem { |
|||
/** |
|||
* Used with label, whether to display : after label text. |
|||
* @default true |
|||
* @type boolean |
|||
*/ |
|||
colon?: boolean; |
|||
|
|||
/** |
|||
* The extra prompt message. It is similar to help. Usage example: to display error message and prompt message at the same time. |
|||
* @type any (string | slot) |
|||
*/ |
|||
extra?: string | VNodeChild | JSX.Element; |
|||
|
|||
/** |
|||
* Used with validateStatus, this option specifies the validation status icon. Recommended to be used only with Input. |
|||
* @default false |
|||
* @type boolean |
|||
*/ |
|||
hasFeedback?: boolean; |
|||
|
|||
/** |
|||
* The prompt message. If not provided, the prompt message will be generated by the validation rule. |
|||
* @type any (string | slot) |
|||
*/ |
|||
help?: string | VNodeChild | JSX.Element; |
|||
|
|||
/** |
|||
* Label test |
|||
* @type any (string | slot) |
|||
*/ |
|||
label?: string | VNodeChild | JSX.Element; |
|||
|
|||
/** |
|||
* 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> |
|||
* @type Col |
|||
*/ |
|||
labelCol?: ColProps & HTMLAttributes; |
|||
|
|||
/** |
|||
* Whether provided or not, it will be generated by the validation rule. |
|||
* @default false |
|||
* @type boolean |
|||
*/ |
|||
required?: boolean; |
|||
|
|||
/** |
|||
* The validation status. If not provided, it will be generated by validation rule. options: 'success' 'warning' 'error' 'validating' |
|||
* @type string |
|||
*/ |
|||
validateStatus?: '' | 'success' | 'warning' | 'error' | 'validating'; |
|||
|
|||
/** |
|||
* The layout for input controls, same as labelCol |
|||
* @type Col |
|||
*/ |
|||
wrapperCol?: ColProps; |
|||
/** |
|||
* Set sub label htmlFor. |
|||
*/ |
|||
htmlFor?: string; |
|||
/** |
|||
* text align of label |
|||
*/ |
|||
labelAlign?: 'left' | 'right'; |
|||
/** |
|||
* a key of model. In the setting of validate and resetFields method, the attribute is required |
|||
*/ |
|||
name?: NamePath; |
|||
/** |
|||
* validation rules of form |
|||
*/ |
|||
rules?: object | object[]; |
|||
/** |
|||
* Whether to automatically associate form fields. In most cases, you can setting automatic association. |
|||
* If the conditions for automatic association are not met, you can manually associate them. See the notes below. |
|||
*/ |
|||
autoLink?: boolean; |
|||
/** |
|||
* Whether stop validate on first rule of error for this field. |
|||
*/ |
|||
validateFirst?: boolean; |
|||
/** |
|||
* When to validate the value of children node |
|||
*/ |
|||
validateTrigger?: string | string[] | false; |
|||
} |
|||
import type { NamePath } from 'ant-design-vue/lib/form/interface'; |
|||
import type { ColProps } from 'ant-design-vue/lib/grid/Col'; |
|||
import type { HTMLAttributes, VNodeChild } from 'vue'; |
|||
|
|||
export interface FormItem { |
|||
/** |
|||
* Used with label, whether to display : after label text. |
|||
* @default true |
|||
* @type boolean |
|||
*/ |
|||
colon?: boolean; |
|||
|
|||
/** |
|||
* The extra prompt message. It is similar to help. Usage example: to display error message and prompt message at the same time. |
|||
* @type any (string | slot) |
|||
*/ |
|||
extra?: string | VNodeChild | JSX.Element; |
|||
|
|||
/** |
|||
* Used with validateStatus, this option specifies the validation status icon. Recommended to be used only with Input. |
|||
* @default false |
|||
* @type boolean |
|||
*/ |
|||
hasFeedback?: boolean; |
|||
|
|||
/** |
|||
* The prompt message. If not provided, the prompt message will be generated by the validation rule. |
|||
* @type any (string | slot) |
|||
*/ |
|||
help?: string | VNodeChild | JSX.Element; |
|||
|
|||
/** |
|||
* Label test |
|||
* @type any (string | slot) |
|||
*/ |
|||
label?: string | VNodeChild | JSX.Element; |
|||
|
|||
/** |
|||
* 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> |
|||
* @type Col |
|||
*/ |
|||
labelCol?: ColProps & HTMLAttributes; |
|||
|
|||
/** |
|||
* Whether provided or not, it will be generated by the validation rule. |
|||
* @default false |
|||
* @type boolean |
|||
*/ |
|||
required?: boolean; |
|||
|
|||
/** |
|||
* The validation status. If not provided, it will be generated by validation rule. options: 'success' 'warning' 'error' 'validating' |
|||
* @type string |
|||
*/ |
|||
validateStatus?: '' | 'success' | 'warning' | 'error' | 'validating'; |
|||
|
|||
/** |
|||
* The layout for input controls, same as labelCol |
|||
* @type Col |
|||
*/ |
|||
wrapperCol?: ColProps; |
|||
/** |
|||
* Set sub label htmlFor. |
|||
*/ |
|||
htmlFor?: string; |
|||
/** |
|||
* text align of label |
|||
*/ |
|||
labelAlign?: 'left' | 'right'; |
|||
/** |
|||
* a key of model. In the setting of validate and resetFields method, the attribute is required |
|||
*/ |
|||
name?: NamePath; |
|||
/** |
|||
* validation rules of form |
|||
*/ |
|||
rules?: object | object[]; |
|||
/** |
|||
* Whether to automatically associate form fields. In most cases, you can setting automatic association. |
|||
* If the conditions for automatic association are not met, you can manually associate them. See the notes below. |
|||
*/ |
|||
autoLink?: boolean; |
|||
/** |
|||
* Whether stop validate on first rule of error for this field. |
|||
*/ |
|||
validateFirst?: boolean; |
|||
/** |
|||
* When to validate the value of children node |
|||
*/ |
|||
validateTrigger?: string | string[] | false; |
|||
} |
|||
|
|||
Loading…
Reference in new issue