ApiSelect组件支持分页下拉方案 #7883

pull/8091/head
JEECG 2025-04-09 09:40:58 +08:00
parent 73a5f64d7e
commit 83b1c8692e
1 changed files with 73 additions and 18 deletions

View File

@ -1,5 +1,12 @@
<template> <template>
<Select @dropdownVisibleChange="handleFetch" v-bind="attrs_" @change="handleChange" :options="getOptions" v-model:value="state"> <Select
v-bind="attrs_"
v-model:value="state"
:options="getOptions"
@change="handleChange"
@dropdownVisibleChange="handleFetch"
@popupScroll="handlePopupScroll"
>
<template #[item]="data" v-for="item in Object.keys($slots)"> <template #[item]="data" v-for="item in Object.keys($slots)">
<slot :name="item" v-bind="data || {}"></slot> <slot :name="item" v-bind="data || {}"></slot>
</template> </template>
@ -24,9 +31,10 @@
import { LoadingOutlined } from '@ant-design/icons-vue'; import { LoadingOutlined } from '@ant-design/icons-vue';
import { useI18n } from '/@/hooks/web/useI18n'; import { useI18n } from '/@/hooks/web/useI18n';
import { propTypes } from '/@/utils/propTypes'; import { propTypes } from '/@/utils/propTypes';
import { isNumber } from '/@/utils/is';
type OptionsItem = { label: string; value: string; disabled?: boolean }; type OptionsItem = { label: string; value: string; disabled?: boolean };
// https://help.jeecg.com/ui/apiSelect#pageconfig%E5%8F%82%E6%95%B0%E9%85%8D%E7%BD%AE
export default defineComponent({ export default defineComponent({
name: 'ApiSelect', name: 'ApiSelect',
components: { components: {
@ -35,7 +43,7 @@
}, },
inheritAttrs: false, inheritAttrs: false,
props: { props: {
value: [Array, Object, String, Number], value: [Array, String, Number],
numberToString: propTypes.bool, numberToString: propTypes.bool,
api: { api: {
type: Function as PropType<(arg?: Recordable) => Promise<OptionsItem[]>>, type: Function as PropType<(arg?: Recordable) => Promise<OptionsItem[]>>,
@ -46,6 +54,11 @@
type: Object as PropType<Recordable>, type: Object as PropType<Recordable>,
default: () => ({}), default: () => ({}),
}, },
//
pageConfig: {
type: Object as PropType<Recordable>,
default: () => ({ isPage: false }),
},
// support xxx.xxx.xx // support xxx.xxx.xx
resultField: propTypes.string.def(''), resultField: propTypes.string.def(''),
labelField: propTypes.string.def('label'), labelField: propTypes.string.def('label'),
@ -60,7 +73,15 @@
const emitData = ref<any[]>([]); const emitData = ref<any[]>([]);
const attrs = useAttrs(); const attrs = useAttrs();
const { t } = useI18n(); const { t } = useI18n();
// update-begin--author:liusq---date:20250407---forQQYUN-11831ApiSelect #7883
const hasMore = ref(true);
const pagination = ref({
pageNo: 1,
pageSize: 10,
total: 0,
});
const defPageConfig = { isPage: false, pageField: 'pageNo', pageSizeField: 'pageSize', totalField: 'total', listField: 'records' };
// update-end--author:liusq---date:20250407---forQQYUN-11831ApiSelect #7883
// Embedded in the form, just use the hook binding to perform form verification // Embedded in the form, just use the hook binding to perform form verification
const [state, setState] = useRuleFormItem(props, 'value', 'change', emitData); const [state, setState] = useRuleFormItem(props, 'value', 'change', emitData);
// update-begin--author:liaozhiyang---date:20230830---forQQYUN-6308 // update-begin--author:liaozhiyang---date:20230830---forQQYUN-6308
@ -114,7 +135,7 @@
}, },
{ deep: true } { deep: true }
); );
// //
watchEffect(() => { watchEffect(() => {
props.value && handleFetch(); props.value && handleFetch();
}); });
@ -122,17 +143,33 @@
async function fetch() { async function fetch() {
const api = props.api; const api = props.api;
if (!api || !isFunction(api)) return; if (!api || !isFunction(api)) return;
options.value = []; // update-begin--author:liusq---date:20250407---forQQYUN-11831ApiSelect #7883
if (!props.pageConfig.isPage || pagination.value.pageNo == 1) {
options.value = [];
}
try { try {
loading.value = true; loading.value = true;
const res = await api(props.params); let { isPage, pageField, pageSizeField, totalField, listField } = { ...defPageConfig, ...props.pageConfig };
if (Array.isArray(res)) { let params = isPage
options.value = res; ? { ...props.params, [pageField]: pagination.value.pageNo, [pageSizeField]: pagination.value.pageSize }
emitChange(); : { ...props.params };
return; // update-end--author:liusq---date:20250407---forQQYUN-11831ApiSelect #7883
} const res = await api(params);
if (props.resultField) { if (isPage) {
options.value = get(res, props.resultField) || []; // update-begin--author:liusq---date:20250407---forQQYUN-11831ApiSelect #7883
options.value = [...options.value, ...res[listField]];
pagination.value.total = res[totalField] || 0;
hasMore.value = res[totalField] ? options.value.length < res[totalField] : res[listField] < pagination.value.pageSize;
// update-end--author:liusq---date:20250407---forQQYUN-11831ApiSelect #7883
} else {
if (Array.isArray(res)) {
options.value = res;
emitChange();
return;
}
if (props.resultField) {
options.value = get(res, props.resultField) || [];
}
} }
emitChange(); emitChange();
} catch (error) { } catch (error) {
@ -151,9 +188,17 @@
function initValue() { function initValue() {
let value = props.value; let value = props.value;
if (value && typeof value === 'string' && value != 'null' && value != 'undefined') { // update-begin--author:liaozhiyang---date:20250407---forissues/8037
state.value = value.split(','); if (unref(attrs).mode == 'multiple') {
if (value && typeof value === 'string' && value != 'null' && value != 'undefined') {
state.value = value.split(',');
} else if (isNumber(value)) {
state.value = [value];
}
} else {
state.value = value;
} }
// update-end--author:liaozhiyang---date:20250407---forissues/8037
} }
async function handleFetch() { async function handleFetch() {
@ -171,8 +216,18 @@
vModalValue && vModalValue(_); vModalValue && vModalValue(_);
emitData.value = args; emitData.value = args;
} }
// update-begin--author:liusq---date:20250407---forQQYUN-11831ApiSelect #7883
return { state, attrs_, attrs, getOptions, loading, t, handleFetch, handleChange }; //
function handlePopupScroll(e) {
const { scrollTop, scrollHeight, clientHeight } = e.target;
const isNearBottom = scrollHeight - scrollTop <= clientHeight + 20;
if (props.pageConfig.isPage && isNearBottom && hasMore.value && !loading.value) {
pagination.value.pageNo += 1;
fetch();
}
}
// update-end--author:liusq---date:20250407---forQQYUN-11831ApiSelect #7883
return { state, attrs_, attrs, getOptions, loading, t, handleFetch, handleChange, handlePopupScroll };
}, },
}); });
</script> </script>