<template>
<a-select
v-model:value="valueId"
v-bind="getBindValues"
show-search
:filter-option="false"
:options="options"
@search="handleSearch"
@popupScroll="popupScroll"
@change="handelChange"
style="min-width: 200px"
>
<template #notFoundContent>
<a-spin size="small" v-if="fetching" />
<a-empty v-else />
</template>
<template #dropdownRender="{ menuNode: menu }" v-if="isSelectAll">
<v-nodes :vnodes="menu" />
<a-divider style="margin: 4px 0" />
<div
style="
padding: 4px 8px;
cursor: pointer;
display: flex;
justify-content: space-between;
width: 100%;
"
@mousedown="(e) => e.preventDefault()"
>
<a-button type="link" @click="selectAll">全选</a-button>
<a-button type="link" @click="clearAll">清空</a-button>
</div>
</template>
<template #[item]="data" v-for="item in Object.keys($slots)" :key="item">
<slot :name="item" v-bind="data || {}"></slot>
</template>
</a-select>
</template>
<script>
import { defineComponent, reactive, toRefs, watch, useAttrs } from 'vue';
import { Select } from 'ant-design-vue';
import { debounce } from 'lodash-es';
export default defineComponent({
name: 'SelectSearch',
components: {
VNodes: (_, { attrs }) => {
return attrs.vnodes;
},
},
props: Object.assign(Select.props, {
data: {
type: Function,
default: () => {},
},
fieldNames: {
type: Object,
default: () => {
return { label: 'label', value: 'value', options: 'options' };
},
},
allowClear: {
type: Boolean,
default: true,
},
pager: {
type: Object,
default: {},
},
searchKey: {
type: String,
default: '',
},
isSelectAll: {
type: Boolean,
default: false,
},
}),
setup(props, { emit }) {
const attrs = useAttrs();
const getBindValues = computed(() => {
let propsData = {
class: 's-select-warp',
...props,
};
return propsData;
});
const valueId = computed({
get: () => {
handelMoreVmodel(props.value)
return props.value;
},
set: (val) => {
emit('update:value', val);
},
});
const state = reactive({
options: [],
fetching: false,
total: 0,
fetchId: 0,
parmas: {},
lastFetchId: 0,
pager: props.pager || {},
});
const handelMoreVmodel = (val) => {
let arr = [];
for (let i in attrs) {
if (i.toString().indexOf('onUpdate') > -1) {
arr.push(i);
}
}
let item = state.options.find((item) => {
return item[props.fieldNames.value] === val;
});
arr.forEach((s) => {
const key = s.split(':')[1];
if (item) {
emit(`update:${key}`, item[key] || '');
} else {
emit(`update:${key}`, '');
}
});
};
const reset = () => {
if (props.searchKey) state.parmas[props.searchKey] = '';
if (state.pager.pageNum) state.pager.pageNum = 1;
state.options = [];
getList();
};
const getList = () => {
state.fetching = true;
if (props.data) {
const result = props.data(Object.assign(state.pager, state.parmas));
result.then((res) => {
if (res.code === 0) {
state.total = res.total;
state.options = state.options.concat(res.data);
state.fetching = false;
}
});
}
};
const popupScroll = (e) => {
if (state.pager.pageNum) {
const { target } = e;
const scrllHeight = target.scrollHeight - target.scrollTop;
const clientHeight = target.clientHeight;
if (scrllHeight === 0 && clientHeight === 0) {
state.pager.pageNum = 1;
} else if (scrllHeight - clientHeight == 0) {
if (state.options.length < state.total) {
state.pager.pageNum++;
getList();
}
}
}
};
const handelChange = (value) => {
if (!value) {
reset();
}
};
const handleSearch = debounce((value) => {
state.lastFetchId += 1;
if (state.pager.pageNum) state.pager.pageNum = 1;
if (props.searchKey) state.parmas[props.searchKey] = value;
state.fetchId = state.lastFetchId;
state.options = [];
if (state.fetchId !== state.lastFetchId) {
return;
}
getList();
}, 800);
const selectAll = () => {
let vals = state.options.map((item) => item[props.fieldNames.value]);
emit('update:value', vals);
};
const clearAll = () => {
emit('update:value', []);
};
getList();
return {
...toRefs(state),
handleSearch,
handelChange,
getList,
popupScroll,
getBindValues,
valueId,
selectAll,
clearAll,
};
},
});
</script>