# externals/vue-vben-admin/effects/common-ui/src/components/api-component/api-component.vue

> `<T = any,>() => {}` comma in generic param is removed even in .ts(x) file

## Option 1

`````json
{"printWidth":80}
`````

### Diff

`````diff
===================================================================
--- prettier
+++ oxfmt
@@ -64,9 +64,13 @@
    * - 函数：自定义选择逻辑，函数的参数为请求的结果数组，返回值为选择的选项
    * - false：不自动选择(默认)
    */
   autoSelect?:
-    "first" | "last" | "one" | ((item: OptionsItem[]) => OptionsItem) | false;
+    | "first"
+    | "last"
+    | "one"
+    | ((item: OptionsItem[]) => OptionsItem)
+    | false;
 }
 
 defineOptions({ name: "ApiComponent", inheritAttrs: false });
 
@@ -270,9 +274,9 @@
   getOptions: () => unref(getOptions),
   /** 获取当前值 */
   getValue: () => unref(modelValue),
   /** 获取被包装的组件实例 */
-  getComponentRef: <T = any,>() => componentRef.value as T,
+  getComponentRef: <T = any>() => componentRef.value as T,
   /** 更新Api参数 */
   updateParam(newParams: Record<string, any>) {
     innerParams.value = newParams;
   },

`````

### Actual (oxfmt)

`````vue
<script lang="ts" setup>
import type { Component } from "vue";

import type { AnyPromiseFunction } from "@vben/types";

import { computed, nextTick, ref, unref, useAttrs, watch } from "vue";

import { LoaderCircle } from "@vben/icons";

import { cloneDeep, get, isEqual, isFunction } from "@vben-core/shared/utils";

import { objectOmit } from "@vueuse/core";

type OptionsItem = {
  [name: string]: any;
  children?: OptionsItem[];
  disabled?: boolean;
  label?: string;
  value?: string;
};

interface Props {
  /** 组件 */
  component: Component;
  /** 是否将value从数字转为string */
  numberToString?: boolean;
  /** 获取options数据的函数 */
  api?: (arg?: any) => Promise<OptionsItem[] | Record<string, any>>;
  /** 传递给api的参数 */
  params?: Record<string, any>;
  /** 从api返回的结果中提取options数组的字段名 */
  resultField?: string;
  /** label字段名 */
  labelField?: string;
  /** children字段名，需要层级数据的组件可用 */
  childrenField?: string;
  /** value字段名 */
  valueField?: string;
  /** disabled字段名 */
  disabledField?: string;
  /** 组件接收options数据的属性名 */
  optionsPropName?: string;
  /** 是否立即调用api */
  immediate?: boolean;
  /** 每次`visibleEvent`事件发生时都重新请求数据 */
  alwaysLoad?: boolean;
  /** 在api请求之前的回调函数 */
  beforeFetch?: AnyPromiseFunction<any, any>;
  /** 在api请求之后的回调函数 */
  afterFetch?: AnyPromiseFunction<any, any>;
  /** 直接传入选项数据，也作为api返回空数据时的后备数据 */
  options?: OptionsItem[];
  /** 组件的插槽名称，用来显示一个"加载中"的图标 */
  loadingSlot?: string;
  /** 触发api请求的事件名 */
  visibleEvent?: string;
  /** 组件的v-model属性名，默认为modelValue。部分组件可能为value */
  modelPropName?: string;
  /**
   * 自动选择
   * - `first`：自动选择第一个选项
   * - `last`：自动选择最后一个选项
   * - `one`: 当请求的结果只有一个选项时，自动选择该选项
   * - 函数：自定义选择逻辑，函数的参数为请求的结果数组，返回值为选择的选项
   * - false：不自动选择(默认)
   */
  autoSelect?:
    | "first"
    | "last"
    | "one"
    | ((item: OptionsItem[]) => OptionsItem)
    | false;
}

defineOptions({ name: "ApiComponent", inheritAttrs: false });

const props = withDefaults(defineProps<Props>(), {
  labelField: "label",
  valueField: "value",
  disabledField: "disabled",
  childrenField: "",
  optionsPropName: "options",
  resultField: "",
  visibleEvent: "",
  numberToString: false,
  params: () => ({}),
  immediate: true,
  alwaysLoad: false,
  loadingSlot: "",
  beforeFetch: undefined,
  afterFetch: undefined,
  modelPropName: "modelValue",
  api: undefined,
  autoSelect: false,
  options: () => [],
});

const emit = defineEmits<{
  optionsChange: [OptionsItem[]];
}>();

const modelValue = defineModel<any>({ default: undefined });

const attrs = useAttrs();
const innerParams = ref({});
const refOptions = ref<OptionsItem[]>([]);
const loading = ref(false);
// 首次是否加载过了
const isFirstLoaded = ref(false);
// 标记是否有待处理的请求
const hasPendingRequest = ref(false);

const getOptions = computed(() => {
  const {
    labelField,
    valueField,
    disabledField,
    childrenField,
    numberToString,
  } = props;

  const refOptionsData = unref(refOptions);

  function transformData(data: OptionsItem[]): OptionsItem[] {
    return data.map((item) => {
      const value = get(item, valueField);
      const disabled = get(item, disabledField);
      return {
        ...objectOmit(item, [labelField, valueField, disabled, childrenField]),
        label: get(item, labelField),
        value: numberToString ? `${value}` : value,
        disabled: get(item, disabledField),
        ...(childrenField && item[childrenField]
          ? { children: transformData(item[childrenField]) }
          : {}),
      };
    });
  }

  const data: OptionsItem[] = transformData(refOptionsData);

  return data.length > 0 ? data : props.options;
});

const bindProps = computed(() => {
  return {
    [props.modelPropName]: unref(modelValue),
    [props.optionsPropName]: unref(getOptions),
    [`onUpdate:${props.modelPropName}`]: (val: string) => {
      modelValue.value = val;
    },
    ...objectOmit(attrs, [`onUpdate:${props.modelPropName}`]),
    ...(props.visibleEvent
      ? {
          [props.visibleEvent]: handleFetchForVisible,
        }
      : {}),
  };
});

async function fetchApi() {
  const { api, beforeFetch, afterFetch, resultField } = props;

  if (!api || !isFunction(api)) {
    return;
  }

  // 如果正在加载，标记有待处理的请求并返回
  if (loading.value) {
    hasPendingRequest.value = true;
    return;
  }

  refOptions.value = [];
  try {
    loading.value = true;
    let finalParams = unref(mergedParams);
    if (beforeFetch && isFunction(beforeFetch)) {
      finalParams = (await beforeFetch(cloneDeep(finalParams))) || finalParams;
    }
    let res = await api(finalParams);
    if (afterFetch && isFunction(afterFetch)) {
      res = (await afterFetch(res)) || res;
    }
    isFirstLoaded.value = true;
    if (Array.isArray(res)) {
      refOptions.value = res;
      emitChange();
      return;
    }
    if (resultField) {
      refOptions.value = get(res, resultField) || [];
    }
    emitChange();
  } catch (error) {
    console.warn(error);
    // reset status
    isFirstLoaded.value = false;
  } finally {
    loading.value = false;
    // 如果有待处理的请求，立即触发新的请求
    if (hasPendingRequest.value) {
      hasPendingRequest.value = false;
      // 使用 nextTick 确保状态更新完成后再触发新请求
      await nextTick();
      fetchApi();
    }
  }
}

async function handleFetchForVisible(visible: boolean) {
  if (visible) {
    if (props.alwaysLoad) {
      await fetchApi();
    } else if (!props.immediate && !unref(isFirstLoaded)) {
      await fetchApi();
    }
  }
}

const mergedParams = computed(() => {
  return {
    ...props.params,
    ...unref(innerParams),
  };
});

watch(
  mergedParams,
  (value, oldValue) => {
    if (isEqual(value, oldValue)) {
      return;
    }
    fetchApi();
  },
  { deep: true, immediate: props.immediate },
);

function emitChange() {
  if (
    modelValue.value === undefined &&
    props.autoSelect &&
    unref(getOptions).length > 0
  ) {
    let firstOption;
    if (isFunction(props.autoSelect)) {
      firstOption = props.autoSelect(unref(getOptions));
    } else {
      switch (props.autoSelect) {
        case "first": {
          firstOption = unref(getOptions)[0];
          break;
        }
        case "last": {
          firstOption = unref(getOptions)[unref(getOptions).length - 1];
          break;
        }
        case "one": {
          if (unref(getOptions).length === 1) {
            firstOption = unref(getOptions)[0];
          }
          break;
        }
      }
    }

    if (firstOption) modelValue.value = firstOption.value;
  }
  emit("optionsChange", unref(getOptions));
}
const componentRef = ref();
defineExpose({
  /** 获取options数据 */
  getOptions: () => unref(getOptions),
  /** 获取当前值 */
  getValue: () => unref(modelValue),
  /** 获取被包装的组件实例 */
  getComponentRef: <T = any>() => componentRef.value as T,
  /** 更新Api参数 */
  updateParam(newParams: Record<string, any>) {
    innerParams.value = newParams;
  },
});
</script>
<template>
  <component
    :is="component"
    v-bind="bindProps"
    :placeholder="$attrs.placeholder"
    ref="componentRef"
  >
    <template v-for="item in Object.keys($slots)" #[item]="data">
      <slot :name="item" v-bind="data || {}"></slot>
    </template>
    <template v-if="loadingSlot && loading" #[loadingSlot]>
      <LoaderCircle class="animate-spin" />
    </template>
  </component>
</template>

`````

### Expected (prettier)

`````vue
<script lang="ts" setup>
import type { Component } from "vue";

import type { AnyPromiseFunction } from "@vben/types";

import { computed, nextTick, ref, unref, useAttrs, watch } from "vue";

import { LoaderCircle } from "@vben/icons";

import { cloneDeep, get, isEqual, isFunction } from "@vben-core/shared/utils";

import { objectOmit } from "@vueuse/core";

type OptionsItem = {
  [name: string]: any;
  children?: OptionsItem[];
  disabled?: boolean;
  label?: string;
  value?: string;
};

interface Props {
  /** 组件 */
  component: Component;
  /** 是否将value从数字转为string */
  numberToString?: boolean;
  /** 获取options数据的函数 */
  api?: (arg?: any) => Promise<OptionsItem[] | Record<string, any>>;
  /** 传递给api的参数 */
  params?: Record<string, any>;
  /** 从api返回的结果中提取options数组的字段名 */
  resultField?: string;
  /** label字段名 */
  labelField?: string;
  /** children字段名，需要层级数据的组件可用 */
  childrenField?: string;
  /** value字段名 */
  valueField?: string;
  /** disabled字段名 */
  disabledField?: string;
  /** 组件接收options数据的属性名 */
  optionsPropName?: string;
  /** 是否立即调用api */
  immediate?: boolean;
  /** 每次`visibleEvent`事件发生时都重新请求数据 */
  alwaysLoad?: boolean;
  /** 在api请求之前的回调函数 */
  beforeFetch?: AnyPromiseFunction<any, any>;
  /** 在api请求之后的回调函数 */
  afterFetch?: AnyPromiseFunction<any, any>;
  /** 直接传入选项数据，也作为api返回空数据时的后备数据 */
  options?: OptionsItem[];
  /** 组件的插槽名称，用来显示一个"加载中"的图标 */
  loadingSlot?: string;
  /** 触发api请求的事件名 */
  visibleEvent?: string;
  /** 组件的v-model属性名，默认为modelValue。部分组件可能为value */
  modelPropName?: string;
  /**
   * 自动选择
   * - `first`：自动选择第一个选项
   * - `last`：自动选择最后一个选项
   * - `one`: 当请求的结果只有一个选项时，自动选择该选项
   * - 函数：自定义选择逻辑，函数的参数为请求的结果数组，返回值为选择的选项
   * - false：不自动选择(默认)
   */
  autoSelect?:
    "first" | "last" | "one" | ((item: OptionsItem[]) => OptionsItem) | false;
}

defineOptions({ name: "ApiComponent", inheritAttrs: false });

const props = withDefaults(defineProps<Props>(), {
  labelField: "label",
  valueField: "value",
  disabledField: "disabled",
  childrenField: "",
  optionsPropName: "options",
  resultField: "",
  visibleEvent: "",
  numberToString: false,
  params: () => ({}),
  immediate: true,
  alwaysLoad: false,
  loadingSlot: "",
  beforeFetch: undefined,
  afterFetch: undefined,
  modelPropName: "modelValue",
  api: undefined,
  autoSelect: false,
  options: () => [],
});

const emit = defineEmits<{
  optionsChange: [OptionsItem[]];
}>();

const modelValue = defineModel<any>({ default: undefined });

const attrs = useAttrs();
const innerParams = ref({});
const refOptions = ref<OptionsItem[]>([]);
const loading = ref(false);
// 首次是否加载过了
const isFirstLoaded = ref(false);
// 标记是否有待处理的请求
const hasPendingRequest = ref(false);

const getOptions = computed(() => {
  const {
    labelField,
    valueField,
    disabledField,
    childrenField,
    numberToString,
  } = props;

  const refOptionsData = unref(refOptions);

  function transformData(data: OptionsItem[]): OptionsItem[] {
    return data.map((item) => {
      const value = get(item, valueField);
      const disabled = get(item, disabledField);
      return {
        ...objectOmit(item, [labelField, valueField, disabled, childrenField]),
        label: get(item, labelField),
        value: numberToString ? `${value}` : value,
        disabled: get(item, disabledField),
        ...(childrenField && item[childrenField]
          ? { children: transformData(item[childrenField]) }
          : {}),
      };
    });
  }

  const data: OptionsItem[] = transformData(refOptionsData);

  return data.length > 0 ? data : props.options;
});

const bindProps = computed(() => {
  return {
    [props.modelPropName]: unref(modelValue),
    [props.optionsPropName]: unref(getOptions),
    [`onUpdate:${props.modelPropName}`]: (val: string) => {
      modelValue.value = val;
    },
    ...objectOmit(attrs, [`onUpdate:${props.modelPropName}`]),
    ...(props.visibleEvent
      ? {
          [props.visibleEvent]: handleFetchForVisible,
        }
      : {}),
  };
});

async function fetchApi() {
  const { api, beforeFetch, afterFetch, resultField } = props;

  if (!api || !isFunction(api)) {
    return;
  }

  // 如果正在加载，标记有待处理的请求并返回
  if (loading.value) {
    hasPendingRequest.value = true;
    return;
  }

  refOptions.value = [];
  try {
    loading.value = true;
    let finalParams = unref(mergedParams);
    if (beforeFetch && isFunction(beforeFetch)) {
      finalParams = (await beforeFetch(cloneDeep(finalParams))) || finalParams;
    }
    let res = await api(finalParams);
    if (afterFetch && isFunction(afterFetch)) {
      res = (await afterFetch(res)) || res;
    }
    isFirstLoaded.value = true;
    if (Array.isArray(res)) {
      refOptions.value = res;
      emitChange();
      return;
    }
    if (resultField) {
      refOptions.value = get(res, resultField) || [];
    }
    emitChange();
  } catch (error) {
    console.warn(error);
    // reset status
    isFirstLoaded.value = false;
  } finally {
    loading.value = false;
    // 如果有待处理的请求，立即触发新的请求
    if (hasPendingRequest.value) {
      hasPendingRequest.value = false;
      // 使用 nextTick 确保状态更新完成后再触发新请求
      await nextTick();
      fetchApi();
    }
  }
}

async function handleFetchForVisible(visible: boolean) {
  if (visible) {
    if (props.alwaysLoad) {
      await fetchApi();
    } else if (!props.immediate && !unref(isFirstLoaded)) {
      await fetchApi();
    }
  }
}

const mergedParams = computed(() => {
  return {
    ...props.params,
    ...unref(innerParams),
  };
});

watch(
  mergedParams,
  (value, oldValue) => {
    if (isEqual(value, oldValue)) {
      return;
    }
    fetchApi();
  },
  { deep: true, immediate: props.immediate },
);

function emitChange() {
  if (
    modelValue.value === undefined &&
    props.autoSelect &&
    unref(getOptions).length > 0
  ) {
    let firstOption;
    if (isFunction(props.autoSelect)) {
      firstOption = props.autoSelect(unref(getOptions));
    } else {
      switch (props.autoSelect) {
        case "first": {
          firstOption = unref(getOptions)[0];
          break;
        }
        case "last": {
          firstOption = unref(getOptions)[unref(getOptions).length - 1];
          break;
        }
        case "one": {
          if (unref(getOptions).length === 1) {
            firstOption = unref(getOptions)[0];
          }
          break;
        }
      }
    }

    if (firstOption) modelValue.value = firstOption.value;
  }
  emit("optionsChange", unref(getOptions));
}
const componentRef = ref();
defineExpose({
  /** 获取options数据 */
  getOptions: () => unref(getOptions),
  /** 获取当前值 */
  getValue: () => unref(modelValue),
  /** 获取被包装的组件实例 */
  getComponentRef: <T = any,>() => componentRef.value as T,
  /** 更新Api参数 */
  updateParam(newParams: Record<string, any>) {
    innerParams.value = newParams;
  },
});
</script>
<template>
  <component
    :is="component"
    v-bind="bindProps"
    :placeholder="$attrs.placeholder"
    ref="componentRef"
  >
    <template v-for="item in Object.keys($slots)" #[item]="data">
      <slot :name="item" v-bind="data || {}"></slot>
    </template>
    <template v-if="loadingSlot && loading" #[loadingSlot]>
      <LoaderCircle class="animate-spin" />
    </template>
  </component>
</template>

`````

## Option 2

`````json
{"printWidth":100,"vueIndentScriptAndStyle":true,"singleQuote":true}
`````

### Diff

`````diff
===================================================================
--- prettier
+++ oxfmt
@@ -259,9 +259,9 @@
     getOptions: () => unref(getOptions),
     /** 获取当前值 */
     getValue: () => unref(modelValue),
     /** 获取被包装的组件实例 */
-    getComponentRef: <T = any,>() => componentRef.value as T,
+    getComponentRef: <T = any>() => componentRef.value as T,
     /** 更新Api参数 */
     updateParam(newParams: Record<string, any>) {
       innerParams.value = newParams;
     },

`````

### Actual (oxfmt)

`````vue
<script lang="ts" setup>
  import type { Component } from 'vue';

  import type { AnyPromiseFunction } from '@vben/types';

  import { computed, nextTick, ref, unref, useAttrs, watch } from 'vue';

  import { LoaderCircle } from '@vben/icons';

  import { cloneDeep, get, isEqual, isFunction } from '@vben-core/shared/utils';

  import { objectOmit } from '@vueuse/core';

  type OptionsItem = {
    [name: string]: any;
    children?: OptionsItem[];
    disabled?: boolean;
    label?: string;
    value?: string;
  };

  interface Props {
    /** 组件 */
    component: Component;
    /** 是否将value从数字转为string */
    numberToString?: boolean;
    /** 获取options数据的函数 */
    api?: (arg?: any) => Promise<OptionsItem[] | Record<string, any>>;
    /** 传递给api的参数 */
    params?: Record<string, any>;
    /** 从api返回的结果中提取options数组的字段名 */
    resultField?: string;
    /** label字段名 */
    labelField?: string;
    /** children字段名，需要层级数据的组件可用 */
    childrenField?: string;
    /** value字段名 */
    valueField?: string;
    /** disabled字段名 */
    disabledField?: string;
    /** 组件接收options数据的属性名 */
    optionsPropName?: string;
    /** 是否立即调用api */
    immediate?: boolean;
    /** 每次`visibleEvent`事件发生时都重新请求数据 */
    alwaysLoad?: boolean;
    /** 在api请求之前的回调函数 */
    beforeFetch?: AnyPromiseFunction<any, any>;
    /** 在api请求之后的回调函数 */
    afterFetch?: AnyPromiseFunction<any, any>;
    /** 直接传入选项数据，也作为api返回空数据时的后备数据 */
    options?: OptionsItem[];
    /** 组件的插槽名称，用来显示一个"加载中"的图标 */
    loadingSlot?: string;
    /** 触发api请求的事件名 */
    visibleEvent?: string;
    /** 组件的v-model属性名，默认为modelValue。部分组件可能为value */
    modelPropName?: string;
    /**
     * 自动选择
     * - `first`：自动选择第一个选项
     * - `last`：自动选择最后一个选项
     * - `one`: 当请求的结果只有一个选项时，自动选择该选项
     * - 函数：自定义选择逻辑，函数的参数为请求的结果数组，返回值为选择的选项
     * - false：不自动选择(默认)
     */
    autoSelect?: 'first' | 'last' | 'one' | ((item: OptionsItem[]) => OptionsItem) | false;
  }

  defineOptions({ name: 'ApiComponent', inheritAttrs: false });

  const props = withDefaults(defineProps<Props>(), {
    labelField: 'label',
    valueField: 'value',
    disabledField: 'disabled',
    childrenField: '',
    optionsPropName: 'options',
    resultField: '',
    visibleEvent: '',
    numberToString: false,
    params: () => ({}),
    immediate: true,
    alwaysLoad: false,
    loadingSlot: '',
    beforeFetch: undefined,
    afterFetch: undefined,
    modelPropName: 'modelValue',
    api: undefined,
    autoSelect: false,
    options: () => [],
  });

  const emit = defineEmits<{
    optionsChange: [OptionsItem[]];
  }>();

  const modelValue = defineModel<any>({ default: undefined });

  const attrs = useAttrs();
  const innerParams = ref({});
  const refOptions = ref<OptionsItem[]>([]);
  const loading = ref(false);
  // 首次是否加载过了
  const isFirstLoaded = ref(false);
  // 标记是否有待处理的请求
  const hasPendingRequest = ref(false);

  const getOptions = computed(() => {
    const { labelField, valueField, disabledField, childrenField, numberToString } = props;

    const refOptionsData = unref(refOptions);

    function transformData(data: OptionsItem[]): OptionsItem[] {
      return data.map((item) => {
        const value = get(item, valueField);
        const disabled = get(item, disabledField);
        return {
          ...objectOmit(item, [labelField, valueField, disabled, childrenField]),
          label: get(item, labelField),
          value: numberToString ? `${value}` : value,
          disabled: get(item, disabledField),
          ...(childrenField && item[childrenField]
            ? { children: transformData(item[childrenField]) }
            : {}),
        };
      });
    }

    const data: OptionsItem[] = transformData(refOptionsData);

    return data.length > 0 ? data : props.options;
  });

  const bindProps = computed(() => {
    return {
      [props.modelPropName]: unref(modelValue),
      [props.optionsPropName]: unref(getOptions),
      [`onUpdate:${props.modelPropName}`]: (val: string) => {
        modelValue.value = val;
      },
      ...objectOmit(attrs, [`onUpdate:${props.modelPropName}`]),
      ...(props.visibleEvent
        ? {
            [props.visibleEvent]: handleFetchForVisible,
          }
        : {}),
    };
  });

  async function fetchApi() {
    const { api, beforeFetch, afterFetch, resultField } = props;

    if (!api || !isFunction(api)) {
      return;
    }

    // 如果正在加载，标记有待处理的请求并返回
    if (loading.value) {
      hasPendingRequest.value = true;
      return;
    }

    refOptions.value = [];
    try {
      loading.value = true;
      let finalParams = unref(mergedParams);
      if (beforeFetch && isFunction(beforeFetch)) {
        finalParams = (await beforeFetch(cloneDeep(finalParams))) || finalParams;
      }
      let res = await api(finalParams);
      if (afterFetch && isFunction(afterFetch)) {
        res = (await afterFetch(res)) || res;
      }
      isFirstLoaded.value = true;
      if (Array.isArray(res)) {
        refOptions.value = res;
        emitChange();
        return;
      }
      if (resultField) {
        refOptions.value = get(res, resultField) || [];
      }
      emitChange();
    } catch (error) {
      console.warn(error);
      // reset status
      isFirstLoaded.value = false;
    } finally {
      loading.value = false;
      // 如果有待处理的请求，立即触发新的请求
      if (hasPendingRequest.value) {
        hasPendingRequest.value = false;
        // 使用 nextTick 确保状态更新完成后再触发新请求
        await nextTick();
        fetchApi();
      }
    }
  }

  async function handleFetchForVisible(visible: boolean) {
    if (visible) {
      if (props.alwaysLoad) {
        await fetchApi();
      } else if (!props.immediate && !unref(isFirstLoaded)) {
        await fetchApi();
      }
    }
  }

  const mergedParams = computed(() => {
    return {
      ...props.params,
      ...unref(innerParams),
    };
  });

  watch(
    mergedParams,
    (value, oldValue) => {
      if (isEqual(value, oldValue)) {
        return;
      }
      fetchApi();
    },
    { deep: true, immediate: props.immediate },
  );

  function emitChange() {
    if (modelValue.value === undefined && props.autoSelect && unref(getOptions).length > 0) {
      let firstOption;
      if (isFunction(props.autoSelect)) {
        firstOption = props.autoSelect(unref(getOptions));
      } else {
        switch (props.autoSelect) {
          case 'first': {
            firstOption = unref(getOptions)[0];
            break;
          }
          case 'last': {
            firstOption = unref(getOptions)[unref(getOptions).length - 1];
            break;
          }
          case 'one': {
            if (unref(getOptions).length === 1) {
              firstOption = unref(getOptions)[0];
            }
            break;
          }
        }
      }

      if (firstOption) modelValue.value = firstOption.value;
    }
    emit('optionsChange', unref(getOptions));
  }
  const componentRef = ref();
  defineExpose({
    /** 获取options数据 */
    getOptions: () => unref(getOptions),
    /** 获取当前值 */
    getValue: () => unref(modelValue),
    /** 获取被包装的组件实例 */
    getComponentRef: <T = any>() => componentRef.value as T,
    /** 更新Api参数 */
    updateParam(newParams: Record<string, any>) {
      innerParams.value = newParams;
    },
  });
</script>
<template>
  <component
    :is="component"
    v-bind="bindProps"
    :placeholder="$attrs.placeholder"
    ref="componentRef"
  >
    <template v-for="item in Object.keys($slots)" #[item]="data">
      <slot :name="item" v-bind="data || {}"></slot>
    </template>
    <template v-if="loadingSlot && loading" #[loadingSlot]>
      <LoaderCircle class="animate-spin" />
    </template>
  </component>
</template>

`````

### Expected (prettier)

`````vue
<script lang="ts" setup>
  import type { Component } from 'vue';

  import type { AnyPromiseFunction } from '@vben/types';

  import { computed, nextTick, ref, unref, useAttrs, watch } from 'vue';

  import { LoaderCircle } from '@vben/icons';

  import { cloneDeep, get, isEqual, isFunction } from '@vben-core/shared/utils';

  import { objectOmit } from '@vueuse/core';

  type OptionsItem = {
    [name: string]: any;
    children?: OptionsItem[];
    disabled?: boolean;
    label?: string;
    value?: string;
  };

  interface Props {
    /** 组件 */
    component: Component;
    /** 是否将value从数字转为string */
    numberToString?: boolean;
    /** 获取options数据的函数 */
    api?: (arg?: any) => Promise<OptionsItem[] | Record<string, any>>;
    /** 传递给api的参数 */
    params?: Record<string, any>;
    /** 从api返回的结果中提取options数组的字段名 */
    resultField?: string;
    /** label字段名 */
    labelField?: string;
    /** children字段名，需要层级数据的组件可用 */
    childrenField?: string;
    /** value字段名 */
    valueField?: string;
    /** disabled字段名 */
    disabledField?: string;
    /** 组件接收options数据的属性名 */
    optionsPropName?: string;
    /** 是否立即调用api */
    immediate?: boolean;
    /** 每次`visibleEvent`事件发生时都重新请求数据 */
    alwaysLoad?: boolean;
    /** 在api请求之前的回调函数 */
    beforeFetch?: AnyPromiseFunction<any, any>;
    /** 在api请求之后的回调函数 */
    afterFetch?: AnyPromiseFunction<any, any>;
    /** 直接传入选项数据，也作为api返回空数据时的后备数据 */
    options?: OptionsItem[];
    /** 组件的插槽名称，用来显示一个"加载中"的图标 */
    loadingSlot?: string;
    /** 触发api请求的事件名 */
    visibleEvent?: string;
    /** 组件的v-model属性名，默认为modelValue。部分组件可能为value */
    modelPropName?: string;
    /**
     * 自动选择
     * - `first`：自动选择第一个选项
     * - `last`：自动选择最后一个选项
     * - `one`: 当请求的结果只有一个选项时，自动选择该选项
     * - 函数：自定义选择逻辑，函数的参数为请求的结果数组，返回值为选择的选项
     * - false：不自动选择(默认)
     */
    autoSelect?: 'first' | 'last' | 'one' | ((item: OptionsItem[]) => OptionsItem) | false;
  }

  defineOptions({ name: 'ApiComponent', inheritAttrs: false });

  const props = withDefaults(defineProps<Props>(), {
    labelField: 'label',
    valueField: 'value',
    disabledField: 'disabled',
    childrenField: '',
    optionsPropName: 'options',
    resultField: '',
    visibleEvent: '',
    numberToString: false,
    params: () => ({}),
    immediate: true,
    alwaysLoad: false,
    loadingSlot: '',
    beforeFetch: undefined,
    afterFetch: undefined,
    modelPropName: 'modelValue',
    api: undefined,
    autoSelect: false,
    options: () => [],
  });

  const emit = defineEmits<{
    optionsChange: [OptionsItem[]];
  }>();

  const modelValue = defineModel<any>({ default: undefined });

  const attrs = useAttrs();
  const innerParams = ref({});
  const refOptions = ref<OptionsItem[]>([]);
  const loading = ref(false);
  // 首次是否加载过了
  const isFirstLoaded = ref(false);
  // 标记是否有待处理的请求
  const hasPendingRequest = ref(false);

  const getOptions = computed(() => {
    const { labelField, valueField, disabledField, childrenField, numberToString } = props;

    const refOptionsData = unref(refOptions);

    function transformData(data: OptionsItem[]): OptionsItem[] {
      return data.map((item) => {
        const value = get(item, valueField);
        const disabled = get(item, disabledField);
        return {
          ...objectOmit(item, [labelField, valueField, disabled, childrenField]),
          label: get(item, labelField),
          value: numberToString ? `${value}` : value,
          disabled: get(item, disabledField),
          ...(childrenField && item[childrenField]
            ? { children: transformData(item[childrenField]) }
            : {}),
        };
      });
    }

    const data: OptionsItem[] = transformData(refOptionsData);

    return data.length > 0 ? data : props.options;
  });

  const bindProps = computed(() => {
    return {
      [props.modelPropName]: unref(modelValue),
      [props.optionsPropName]: unref(getOptions),
      [`onUpdate:${props.modelPropName}`]: (val: string) => {
        modelValue.value = val;
      },
      ...objectOmit(attrs, [`onUpdate:${props.modelPropName}`]),
      ...(props.visibleEvent
        ? {
            [props.visibleEvent]: handleFetchForVisible,
          }
        : {}),
    };
  });

  async function fetchApi() {
    const { api, beforeFetch, afterFetch, resultField } = props;

    if (!api || !isFunction(api)) {
      return;
    }

    // 如果正在加载，标记有待处理的请求并返回
    if (loading.value) {
      hasPendingRequest.value = true;
      return;
    }

    refOptions.value = [];
    try {
      loading.value = true;
      let finalParams = unref(mergedParams);
      if (beforeFetch && isFunction(beforeFetch)) {
        finalParams = (await beforeFetch(cloneDeep(finalParams))) || finalParams;
      }
      let res = await api(finalParams);
      if (afterFetch && isFunction(afterFetch)) {
        res = (await afterFetch(res)) || res;
      }
      isFirstLoaded.value = true;
      if (Array.isArray(res)) {
        refOptions.value = res;
        emitChange();
        return;
      }
      if (resultField) {
        refOptions.value = get(res, resultField) || [];
      }
      emitChange();
    } catch (error) {
      console.warn(error);
      // reset status
      isFirstLoaded.value = false;
    } finally {
      loading.value = false;
      // 如果有待处理的请求，立即触发新的请求
      if (hasPendingRequest.value) {
        hasPendingRequest.value = false;
        // 使用 nextTick 确保状态更新完成后再触发新请求
        await nextTick();
        fetchApi();
      }
    }
  }

  async function handleFetchForVisible(visible: boolean) {
    if (visible) {
      if (props.alwaysLoad) {
        await fetchApi();
      } else if (!props.immediate && !unref(isFirstLoaded)) {
        await fetchApi();
      }
    }
  }

  const mergedParams = computed(() => {
    return {
      ...props.params,
      ...unref(innerParams),
    };
  });

  watch(
    mergedParams,
    (value, oldValue) => {
      if (isEqual(value, oldValue)) {
        return;
      }
      fetchApi();
    },
    { deep: true, immediate: props.immediate },
  );

  function emitChange() {
    if (modelValue.value === undefined && props.autoSelect && unref(getOptions).length > 0) {
      let firstOption;
      if (isFunction(props.autoSelect)) {
        firstOption = props.autoSelect(unref(getOptions));
      } else {
        switch (props.autoSelect) {
          case 'first': {
            firstOption = unref(getOptions)[0];
            break;
          }
          case 'last': {
            firstOption = unref(getOptions)[unref(getOptions).length - 1];
            break;
          }
          case 'one': {
            if (unref(getOptions).length === 1) {
              firstOption = unref(getOptions)[0];
            }
            break;
          }
        }
      }

      if (firstOption) modelValue.value = firstOption.value;
    }
    emit('optionsChange', unref(getOptions));
  }
  const componentRef = ref();
  defineExpose({
    /** 获取options数据 */
    getOptions: () => unref(getOptions),
    /** 获取当前值 */
    getValue: () => unref(modelValue),
    /** 获取被包装的组件实例 */
    getComponentRef: <T = any,>() => componentRef.value as T,
    /** 更新Api参数 */
    updateParam(newParams: Record<string, any>) {
      innerParams.value = newParams;
    },
  });
</script>
<template>
  <component
    :is="component"
    v-bind="bindProps"
    :placeholder="$attrs.placeholder"
    ref="componentRef"
  >
    <template v-for="item in Object.keys($slots)" #[item]="data">
      <slot :name="item" v-bind="data || {}"></slot>
    </template>
    <template v-if="loadingSlot && loading" #[loadingSlot]>
      <LoaderCircle class="animate-spin" />
    </template>
  </component>
</template>

`````
