Sfoglia il codice sorgente

feat: api-component support autoSelect prop (#5931)

* feat: api-component support autoSelect prop

* docs: add version requirement
Netfan 5 mesi fa
parent
commit
a8c4786311

+ 30 - 20
docs/src/components/common-ui/vben-api-component.md

@@ -131,26 +131,36 @@ function fetchApi(): Promise<Record<string, any>> {
 
 ### Props
 
-| 属性名 | 描述 | 类型 | 默认值 |
-| --- | --- | --- | --- |
-| modelValue(v-model) | 当前值 | `any` | - |
-| component | 欲包装的组件(以下称为目标组件) | `Component` | - |
-| numberToString | 是否将value从数字转为string | `boolean` | `false` |
-| api | 获取数据的函数 | `(arg?: any) => Promise<OptionsItem[] \| Record<string, any>>` | - |
-| params | 传递给api的参数 | `Record<string, any>` | - |
-| resultField | 从api返回的结果中提取options数组的字段名 | `string` | - |
-| labelField | label字段名 | `string` | `label` |
-| childrenField | 子级数据字段名,需要层级数据的组件可用 | `string` | `` |
-| valueField | value字段名 | `string` | `value` |
-| optionsPropName | 目标组件接收options数据的属性名称 | `string` | `options` |
-| modelPropName | 目标组件的双向绑定属性名,默认为modelValue。部分组件可能为value | `string` | `modelValue` |
-| immediate | 是否立即调用api | `boolean` | `true` |
-| alwaysLoad | 每次`visibleEvent`事件发生时都重新请求数据 | `boolean` | `false` |
-| beforeFetch | 在api请求之前的回调函数 | `AnyPromiseFunction<any, any>` | - |
-| afterFetch | 在api请求之后的回调函数 | `AnyPromiseFunction<any, any>` | - |
-| options | 直接传入选项数据,也作为api返回空数据时的后备数据 | `OptionsItem[]` | - |
-| visibleEvent | 触发重新请求数据的事件名 | `string` | - |
-| loadingSlot | 目标组件的插槽名称,用来显示一个"加载中"的图标 | `string` | - |
+| 属性名 | 描述 | 类型 | 默认值 | 版本要求 |
+| --- | --- | --- | --- | --- |
+| modelValue(v-model) | 当前值 | `any` | - | - |
+| component | 欲包装的组件(以下称为目标组件) | `Component` | - | - |
+| numberToString | 是否将value从数字转为string | `boolean` | `false` | - |
+| api | 获取数据的函数 | `(arg?: any) => Promise<OptionsItem[] \| Record<string, any>>` | - | - |
+| params | 传递给api的参数 | `Record<string, any>` | - | - |
+| resultField | 从api返回的结果中提取options数组的字段名 | `string` | - | - |
+| labelField | label字段名 | `string` | `label` | - |
+| childrenField | 子级数据字段名,需要层级数据的组件可用 | `string` | `` | - |
+| valueField | value字段名 | `string` | `value` | - |
+| optionsPropName | 目标组件接收options数据的属性名称 | `string` | `options` | - |
+| modelPropName | 目标组件的双向绑定属性名,默认为modelValue。部分组件可能为value | `string` | `modelValue` | - |
+| immediate | 是否立即调用api | `boolean` | `true` | - |
+| alwaysLoad | 每次`visibleEvent`事件发生时都重新请求数据 | `boolean` | `false` | - |
+| beforeFetch | 在api请求之前的回调函数 | `AnyPromiseFunction<any, any>` | - | - |
+| afterFetch | 在api请求之后的回调函数 | `AnyPromiseFunction<any, any>` | - | - |
+| options | 直接传入选项数据,也作为api返回空数据时的后备数据 | `OptionsItem[]` | - | - |
+| visibleEvent | 触发重新请求数据的事件名 | `string` | - | - |
+| loadingSlot | 目标组件的插槽名称,用来显示一个"加载中"的图标 | `string` | - | - |
+| autoSelect | 自动设置选项 | `'first' \| 'last' \| 'none'\| false` | `false` | >5.5.4 |
+
+#### autoSelect 自动设置选项
+
+如果当前值为undefined,在选项数据成功加载之后,自动从备选项中选择一个作为当前值。默认值为`false`,即不自动选择选项。注意:该属性不应用于多选组件。可选值有:
+
+- `first`:自动选择第一个选项
+- `last`:自动选择最后一个选项
+- `one`:有且仅有一个选项时,自动选择它
+- false:不自动选择选项
 
 ### Methods
 

+ 35 - 1
packages/effects/common-ui/src/components/api-component/api-component.vue

@@ -54,6 +54,14 @@ interface Props {
   visibleEvent?: string;
   /** 组件的v-model属性名,默认为modelValue。部分组件可能为value */
   modelPropName?: string;
+  /**
+   * 自动选择
+   * - `first`:自动选择第一个选项
+   * - `last`:自动选择最后一个选项
+   * - `one`: 当请求的结果只有一个选项时,自动选择该选项
+   * - false:不自动选择(默认)
+   */
+  autoSelect?: 'first' | 'last' | 'one' | false;
 }
 
 defineOptions({ name: 'ApiComponent', inheritAttrs: false });
@@ -74,6 +82,7 @@ const props = withDefaults(defineProps<Props>(), {
   afterFetch: undefined,
   modelPropName: 'modelValue',
   api: undefined,
+  autoSelect: false,
   options: () => [],
 });
 
@@ -81,7 +90,7 @@ const emit = defineEmits<{
   optionsChange: [OptionsItem[]];
 }>();
 
-const modelValue = defineModel({ default: '' });
+const modelValue = defineModel<any>({ default: undefined });
 
 const attrs = useAttrs();
 const innerParams = ref({});
@@ -194,6 +203,31 @@ watch(
 );
 
 function emitChange() {
+  if (
+    modelValue.value === undefined &&
+    props.autoSelect &&
+    unref(getOptions).length > 0
+  ) {
+    let firstOption;
+    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[props.valueField];
+  }
   emit('optionsChange', unref(getOptions));
 }
 const componentRef = ref();

+ 1 - 0
playground/src/views/examples/form/basic.vue

@@ -74,6 +74,7 @@ const [BaseForm, baseFormApi] = useVbenForm({
         },
         // 菜单接口
         api: getAllMenusApi,
+        autoSelect: 'first',
       },
       // 字段名
       fieldName: 'api',