api-select.vue 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. <script setup lang="ts">
  2. import { computed, nextTick, onMounted, ref, unref } from 'vue';
  3. import { useDebounceFn } from '@vueuse/core';
  4. import { get } from '@/utils/zt/lodashChunk';
  5. import { isFunction } from '@/utils/zt/is';
  6. import { basicApiSelectProps } from './props';
  7. import type { ApiSelectProps } from './type';
  8. const debouncedFn = useDebounceFn(() => {
  9. fetchApi();
  10. }, 1000);
  11. const props = withDefaults(defineProps<ApiSelectProps>(), {
  12. immediate: true,
  13. resultFeild: 'data',
  14. clearable: true,
  15. pagination: false,
  16. pageNumFeild: 'current',
  17. pageSizeFeild: 'size'
  18. });
  19. const fetchLoading = ref(false);
  20. const basicProps = ref(basicApiSelectProps);
  21. const options = ref<Recordable[]>([]);
  22. const modelVlaue = defineModel<Array<string | number> | string | number | null>();
  23. const isFirstReq = ref(false);
  24. const searchText = ref('');
  25. const total = ref(0);
  26. const page = ref(1);
  27. const bindValue = computed(() => {
  28. return {
  29. ...props,
  30. ...basicProps
  31. };
  32. });
  33. async function fetchApi() {
  34. const api = props.api;
  35. if (!api || !isFunction(api)) return;
  36. const params = {
  37. ...props.params
  38. };
  39. if (unref(bindValue).filterFeild && unref(searchText)) {
  40. params[String(unref(bindValue).filterFeild)] = unref(searchText);
  41. // console.log(params, 'apiselect请求参数');
  42. }
  43. if (unref(bindValue).pagination) {
  44. params[unref(bindValue).pageNumFeild] = unref(page);
  45. params[unref(bindValue).pageSizeFeild] = 10;
  46. }
  47. const res = await api(params);
  48. options.value = unref(bindValue).pagination ? [...options.value, ...res.data.records] : get(res, props.resultFeild);
  49. fetchLoading.value = false;
  50. if (props.setDefaultValue) {
  51. console.log(options.value[0], unref(bindValue).valueFeild, 'options.value');
  52. nextTick(() => {
  53. modelVlaue.value = options.value[0][unref(bindValue).valueFeild as string];
  54. console.log(modelVlaue.value, '默认值');
  55. });
  56. }
  57. if (props.getOptions) {
  58. props.getOptions(options.value);
  59. }
  60. if (unref(bindValue).pagination) {
  61. total.value = res.data.total;
  62. }
  63. }
  64. onMounted(() => {
  65. if (unref(bindValue).immediate) {
  66. fetchApi();
  67. }
  68. });
  69. function handleFocus() {
  70. if (!unref(bindValue).immediate && !unref(isFirstReq)) {
  71. fetchApi();
  72. isFirstReq.value = true;
  73. }
  74. if (!unref(options).length && unref(bindValue).immediate) {
  75. fetchApi();
  76. }
  77. }
  78. function handleScroll(e: Event) {
  79. const currentTarget = e.currentTarget as HTMLElement;
  80. if (currentTarget.scrollTop + currentTarget.offsetHeight >= currentTarget.scrollHeight) {
  81. // console.log('到底了');
  82. if (options.value.length < total.value && !fetchLoading.value) {
  83. // console.log('请求数据');
  84. fetchLoading.value = true;
  85. page.value += 1;
  86. fetchApi();
  87. }
  88. }
  89. }
  90. function handleSearch(value: string) {
  91. fetchLoading.value = true;
  92. searchText.value = value;
  93. debouncedFn();
  94. }
  95. function handleClear() {
  96. searchText.value = '';
  97. fetchApi();
  98. }
  99. function handleBlur() {
  100. searchText.value = '';
  101. }
  102. </script>
  103. <template>
  104. <NSelect
  105. v-bind="bindValue"
  106. v-model:value="modelVlaue"
  107. :options="options"
  108. :label-field="labelFeild"
  109. :value-field="valueFeild"
  110. :loading="fetchLoading"
  111. @focus="handleFocus"
  112. @scroll="handleScroll"
  113. @search="handleSearch"
  114. @clear="handleClear"
  115. @blur="handleBlur"
  116. ></NSelect>
  117. </template>
  118. <style scoped></style>