Kaynağa Gözat

fix: 添加输入框字典复合组件

fan 2 yıl önce
ebeveyn
işleme
eef226822c

+ 2 - 0
src/components/Form/src/componentMap.ts

@@ -22,6 +22,7 @@ import {
 } from 'ant-design-vue';
 
 import ApiRadioGroup from './components/ApiRadioGroup.vue';
+import ApiInputDict from './components/ApiInputDict.vue';
 import ApiComplex from './components/ApiComplex.vue';
 import RadioButtonGroup from './components/RadioButtonGroup.vue';
 import ApiSelect from './components/ApiSelect.vue';
@@ -72,6 +73,7 @@ componentMap.set('Cascader', Cascader);
 componentMap.set('Slider', Slider);
 componentMap.set('Rate', Rate);
 componentMap.set('ApiTransfer', ApiTransfer);
+componentMap.set('ApiInputDict', ApiInputDict);
 
 componentMap.set('DatePicker', DatePicker);
 componentMap.set('MonthPicker', DatePicker.MonthPicker);

+ 0 - 8
src/components/Form/src/components/ApiComplex.vue

@@ -1,12 +1,4 @@
 <template>
-  <!-- <a-tree-select v-bind="getAttrs" @change="handleChange">
-    <template #[item]="data" v-for="item in Object.keys($slots)">
-      <slot :name="item" v-bind="data || {}" />
-    </template>
-    <template #suffixIcon v-if="loading">
-      <LoadingOutlined spin />
-    </template>
-  </a-tree-select> -->
   <div class="flex items-center">
     <a-form-item>
       <RadioGroup v-model:value="radioValue" :options="radioData" @change="handleRadioChange" />

+ 174 - 0
src/components/Form/src/components/ApiInputDict.vue

@@ -0,0 +1,174 @@
+<template>
+  <div class="flex items-center">
+    <a-input-group compact>
+      <template v-if="props.params?.dictSort">
+        <a-form-item class="select">
+          <a-select
+            v-model:value="dictValue"
+            :options="dictData"
+            @change="handleSelectChange"
+            style="width: 100%"
+          />
+        </a-form-item>
+        <a-form-item class="input">
+          <a-input v-model:value="inputValue" @change="handleInputChange" style="width: 100%" />
+        </a-form-item>
+      </template>
+      <template v-else>
+        <a-form-item class="input">
+          <a-input v-model:value="inputValue" @change="handleInputChange" style="width: 100%" />
+        </a-form-item>
+        <a-form-item class="select">
+          <a-select
+            v-model:value="dictValue"
+            :options="dictData"
+            @change="handleSelectChange"
+            style="width: 100%"
+          />
+        </a-form-item>
+      </template>
+    </a-input-group>
+  </div>
+</template>
+
+<script lang="ts">
+  import { computed, defineComponent, watch, ref, onMounted, unref } from 'vue';
+  import { propTypes } from '/@/utils/propTypes';
+  import { useDebounceFn } from '@vueuse/core';
+  import { isFunction } from '/@/utils/is';
+  import { get } from 'lodash-es';
+
+  export default defineComponent({
+    name: 'ApiInputDict',
+    props: {
+      api: { type: Function as PropType<(arg?: Recordable) => Promise<Recordable>> },
+      params: { type: Object },
+      immediate: { type: Boolean, default: true },
+      resultField: propTypes.string.def(''),
+      placeholder: { type: String },
+    },
+    emits: ['change'],
+    setup(props, { attrs, emit }) {
+      const dictData = ref([]);
+      const getAttrs = computed(() => {
+        return {
+          ...(props.api ? { dictData: unref(dictData) } : {}),
+          ...attrs,
+        } as any;
+      });
+      const inputValue = ref('');
+      const dictValue = ref('');
+      const isFirstLoaded = ref<Boolean>(false);
+      const loading = ref(false);
+      watch(
+        () => attrs.formValues,
+        (v: any) => {
+          // console.log('🚀 ~ file: ApiComplex.vue:102 ~ setup ~ v:', v);
+          const field = v.field;
+          const defaultValue = v?.model?.[field];
+          dictValue.value = defaultValue?.dictValue;
+          inputValue.value = defaultValue?.input;
+        },
+      );
+      watch(
+        () => props.params?.dictSort,
+        v => {
+          console.log('dictSort v', v);
+        },
+        { deep: true },
+      );
+      watch(
+        () => props.params?.dictCode,
+        () => {
+          !unref(isFirstLoaded) && fetch();
+        },
+        { deep: true },
+      );
+      watch(
+        () => props.immediate,
+        v => {
+          v && !isFirstLoaded.value && fetch();
+        },
+      );
+
+      onMounted(() => {
+        props.immediate && fetch();
+      });
+
+      async function fetch() {
+        const api = props.api;
+        if (!api || !isFunction(api)) return;
+        dictData.value = [];
+        try {
+          loading.value = true;
+          const res = await api(props.params);
+          if (Array.isArray(res)) {
+            dictData.value = res;
+            dictValue.value = dictData.value[0]['value'];
+            return;
+          }
+          if (props.resultField) {
+            dictData.value = get(res, props.resultField) || [];
+            dictValue.value = dictData.value[0]['value'];
+          }
+        } catch (error) {
+          console.warn(error);
+        } finally {
+          loading.value = false;
+        }
+      }
+
+      function emitChange() {
+        debouncedFn();
+      }
+
+      // 防抖
+      const debouncedFn = useDebounceFn(() => {
+        const data = {
+          input: inputValue.value,
+          dictValue: dictValue.value,
+          dictCode: props.params?.dictCode,
+        };
+        emit('change', data);
+      }, 1000);
+
+      // 复选改变
+      function handleSelectChange(value) {
+        console.log('🚀 ~ file: ApiInputDict.vue:137 ~ handleSelectChange ~ e:', value);
+        dictValue.value = value;
+        emitChange();
+      }
+
+      // 输入改变
+      function handleInputChange(e) {
+        inputValue.value = e.target.value || '';
+        emitChange();
+      }
+
+      return {
+        getAttrs,
+        loading,
+        props,
+        dictValue,
+        inputValue,
+        dictData,
+        handleSelectChange,
+        handleInputChange,
+      };
+    },
+  });
+</script>
+
+<style lang="less" scoped>
+  .fan-basic-form .ant-form-item {
+    border: 0;
+  }
+
+  .select {
+    width: 20%;
+  }
+
+  .input {
+    width: 80%;
+  }
+</style>

+ 18 - 20
src/components/Form/src/components/InputNumberGroup.vue

@@ -26,24 +26,11 @@
         />
       </div>
     </template>
-
-    <!-- <a-input
-      v-model:value="getValueSplit[0]"
-      style="width: 100px; text-align: center"
-      :placeholder="props.placelhoders[0]"
-    />
-
-    <a-input
-      v-model:value="getValueSplit[0]"
-      style="width: 100px; text-align: center; border-left: 0"
-      :placeholder="props.placelhoders[1]"
-    /> -->
   </InputGroup>
 </template>
 <script lang="ts">
-  import { defineComponent, computed, reactive } from 'vue';
+  import { defineComponent, computed, reactive, watch } from 'vue';
   import { Input, InputNumber, FormItem } from 'ant-design-vue';
-  import { useAttrs } from '/@/hooks/core/useAttrs';
 
   type OptionsItem = {
     min: number;
@@ -82,8 +69,7 @@
       },
     },
     emits: ['change'],
-    setup(props, { emit }) {
-      const attrs = useAttrs();
+    setup(props, { attrs, emit }) {
       const collect = reactive({
         min: 0,
         max: 0,
@@ -93,13 +79,10 @@
       const getOptions = computed((): OptionsItem[] => {
         const { options } = props;
         if (!options || options?.length === 0) return [];
-
-        // console.log('111111111 getOptions, props', props.value);
         const ret = options.map(item => {
+          item.key = Math.round(Math.random() * 1000);
           if (props.value == undefined || props.value == null) {
             item.value = undefined;
-            // 生成随机key,使页面刷新
-            item.key = Math.round(Math.random() * 1000);
           }
           return item;
         }) as OptionsItem[];
@@ -117,6 +100,21 @@
         emit('change', arr);
       }
 
+      // 监听赋值
+      watch(
+        () => attrs.formValues,
+        (v: any) => {
+          const field = v.field;
+          const defaultValue = v?.model?.[field];
+          if (defaultValue?.length) {
+            props.options.map((ele, idx) => {
+              ele['value'] = defaultValue[idx];
+              return ele;
+            });
+          }
+        },
+      );
+
       return { getOptions, attrs, handleChange, props };
     },
   });

+ 1 - 0
src/components/Form/src/types/index.ts

@@ -122,4 +122,5 @@ export type ComponentType =
   | 'InputNumberGroup'
   | 'RadioDescGroup'
   | 'ApiComplex'
+  | 'ApiInputDict'
   | 'Cron';