<template>
<el-select
:remote-method="remoteMethod"
:no-data-text="t('common.empty')"
:placeholder="t('common.chooseText')"
v-bind="$attrs"
v-model="state"
remote-show-suffix
fit-input-width
filterable
@visible-change="handleFetch"
@focus="fetch"
@input="handleInput"
@blur="handleBlur"
allow-input="true"
>
<el-option
:title="$attrs.title?item.label:''"
v-for="item in getOptions"
:key="item.value"
:label="item.label"
:value="$attrs.valueKey ? item : item.value"
:disabled="item.disabled"
/>
<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>
<template #empty v-if="loading">
<span>
{{ t('component.form.apiSelectNotFound') }}
</span>
</template>
</el-select>
</template>
<script lang="ts">
import { defineComponent, PropType, ref, watchEffect, computed, unref } from 'vue';
import { isFunction } from '@/utils/is';
import { useRuleFormItem } from '@/hooks/component/useFormItem';
import { useAttrs } from '@/hooks/core/useAttrs';
import { get } from 'lodash-es';
import { t } from '@/utils/common';
import { propTypes } from '@/utils/propTypes';
type OptionsItem = { label: string; value: string; disabled?: boolean };
export default defineComponent({
name: 'ApiSelect',
inheritAttrs: false,
props: {
value: propTypes.string || Array,
numberToString: propTypes.bool,
api: {
type: Function as PropType<(arg?: Recordable) => Promise<OptionsItem[]>>,
default: null,
},
afterFetch: {
type: Function as PropType<(items: OptionsItem[]) => (OptionsItem & Record<string, any>)[]>,
default: null,
},
// api params
params: {
type: Object as PropType<Recordable>,
default: () => {},
},
// support xxx.xxx.xx
filterField: propTypes.string.def(''),
resultField: propTypes.string.def(''),
labelField: propTypes.string.def('label'),
valueField: propTypes.string.def('value'),
labelRender: {
type: Function as PropType<(items: Recordable) => string>,
default: null,
},
immediate: {
type: Boolean,
default: true,
},
// 只有一条数据是默认选中
defalutSelect: {
type: Boolean,
default: false,
}
},
emits: ['options-change', 'change'],
setup(props, { emit }) {
const options = ref<OptionsItem[]>([]);
const loading = ref(false);
const attrs = useAttrs();
const inputValue = ref('');
// Embedded in the form, just use the hook binding to perform form verification
const [state, setState] = useRuleFormItem(props);
const getOptions = computed(() => {
const { labelField, valueField, numberToString, labelRender } = props;
return unref(options).reduce((prev, next: Recordable) => {
if (next) {
const value = next[valueField];
let label = next[labelField];
if (labelRender) {
label = labelRender(next);
}
prev.push({
...next,
label,
value: numberToString ? `${value}` : value,
});
}
return prev;
}, [] as OptionsItem[]);
});
const _valueField = ref(props.value);
let lastFetchId = 0; // 处理竞态问题
watchEffect(() => {
// 增加了一个立即执行prop,默认为true, 有个场景需要做到默认不加载,打开下拉框再加载.
if (props.immediate) fetch();
});
function remoteMethod(val) {
if (val !== '') {
lastFetchId = 0;
fetch({
[props.filterField]: val
})
}
}
async function fetch(params = {}) {
const api = props.api;
const afterFetch = props.afterFetch;
if (!api || !isFunction(api)) return;
options.value = [];
try {
loading.value = true;
lastFetchId += 1;
const fetchId = lastFetchId;
let res = await api({ ...props.params, ...params});
if (fetchId === lastFetchId) {
if (afterFetch && isFunction(afterFetch)) {
res = afterFetch(res);
}
if (Array.isArray(res)) {
options.value = res;
emit('options-change', unref(options));
return;
}
if (props.resultField) {
options.value = get(res, props.resultField) || [];
}
// 只有一条数数据是默认选中
if(options.value?.length === 1 && props.defalutSelect) {
if(attrs.value?.valueKey) {
attrs.value?.multiple ? setState([getOptions.value[0]]) : setState(getOptions.value[0])
if(props?.params?.approvalType&&props?.params?.approvalType=="EDQMS-ESER审批"){
emit('change',options.value[0]);
}
} else {
attrs.value?.multiple ? setState([options.value[0][props.valueField]]) : setState(options.value[0][props.valueField])
}
}
emit('options-change', unref(options));
}
} catch (error) {
console.warn(error);
} finally {
loading.value = false;
}
}
function handleFetch(visible) {
if (visible && !props.immediate) {
fetch();
}
}
// 新增:处理输入事件,保存完整输入值
const handleInput = (val: string) => {
console.log(state,'🍨🍨🍨🍨🍨🍨', val.data);
inputValue.value = val; // 存储用户输入的完整文本
};
// 新增:处理失焦事件,传递完整输入值
const handleBlur = () => {
// 调用外部绑定的 onBlur 事件,传入完整输入值
if (typeof attrs.onBlur === 'function') {
attrs.onBlur(inputValue.value);
}
};
return { state, attrs, getOptions, loading, t, handleFetch, fetch, remoteMethod , handleInput, handleBlur };
},
});
</script>
如何使组件在handleInput事件中获取到用户每次输入的完整内容
最新发布