Sfoglia il codice sorgente

feat: 添加form 组件

fan 2 anni fa
parent
commit
18ee2bb2ae

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

@@ -22,6 +22,7 @@ import {
 } from 'ant-design-vue';
 
 import ApiRadioGroup from './components/ApiRadioGroup.vue';
+import ApiComplex from './components/ApiComplex.vue';
 import RadioButtonGroup from './components/RadioButtonGroup.vue';
 import ApiSelect from './components/ApiSelect.vue';
 import ApiTree from './components/ApiTree.vue';
@@ -49,6 +50,7 @@ componentMap.set('InputNumber', InputNumber);
 componentMap.set('AutoComplete', AutoComplete);
 
 componentMap.set('Select', Select);
+componentMap.set('ApiComplex', ApiComplex);
 componentMap.set('ApiSelect', ApiSelect);
 componentMap.set('ApiTree', ApiTree);
 componentMap.set('TreeSelect', TreeSelect);

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

@@ -0,0 +1,174 @@
+<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" />
+    </a-form-item>
+    <div v-if="checkboxData.length" class="flex items-center">
+      <div class="mb-2 mr-1">(</div>
+      <a-form-item>
+        <CheckboxGroup
+          v-model:value="checkboxValue"
+          :options="checkboxData"
+          @change="handleCheckboxChange"
+          :disabled="checkboxDisabled"
+        />
+      </a-form-item>
+      <a-form-item>
+        <a-input
+          :style="{ width: '150px', border: 0, borderBottom: '1px solid #ccc' }"
+          :placeholder="props.placeholder || '请输入'"
+          v-model:value="inputValue"
+          :disabled="disabled"
+        />
+      </a-form-item>
+      <div class="mb-2 ml-1">)</div>
+    </div>
+    <a-form-item v-else>
+      <a-input :placeholder="props.placeholder || '请输入'" v-model:value="inputValue" />
+    </a-form-item>
+  </div>
+</template>
+
+<script lang="ts">
+  import { computed, defineComponent, watch, ref, onMounted, unref } from 'vue';
+  import { RadioGroup, CheckboxGroup } from 'ant-design-vue';
+  import { isFunction } from '/@/utils/is';
+  import { get } from 'lodash-es';
+  import { propTypes } from '/@/utils/propTypes';
+  import { useRuleFormItem } from '/@/hooks/component/useFormItem';
+
+  export default defineComponent({
+    name: 'ApiComplex',
+    components: { RadioGroup, CheckboxGroup },
+    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 },
+      values: { type: Object },
+      value: { type: Object },
+    },
+    emits: ['change'],
+    setup(props, { attrs, emit }) {
+      const radioData = ref(
+        props.params?.radioData || [
+          { label: '无', value: 0 },
+          { label: '有', value: 1 },
+        ],
+      );
+      const radioValue = ref(props.values?.radioValue || 0);
+      const inputValue = ref(props.values?.inputValue || '');
+      const checkboxValue = ref(props.values?.checkboxValue || []);
+      const checkboxDisabled = ref(true);
+      const checkboxData = ref([]);
+      const disabled = ref(true);
+      const isFirstLoaded = ref<Boolean>(false);
+      const loading = ref(false);
+      const getAttrs = computed(() => {
+        return {
+          ...(props.api ? { checkboxData: unref(checkboxData) } : {}),
+          ...attrs,
+        };
+      });
+      console.log('🚀 ~ file: ApiComplex.vue:82 ~ getAttrs ~ getAttrs:', getAttrs);
+      const [state] = useRuleFormItem(props);
+      console.log('state', state);
+      console.log('value', props.value);
+      function handleChange(...args) {
+        // emitData.value = args;
+        emit('change', ...args);
+      }
+
+      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;
+        checkboxData.value = [];
+        try {
+          loading.value = true;
+          const res = await api(props.params);
+          if (Array.isArray(res)) {
+            checkboxData.value = res;
+            checkboxData.value.push({
+              label: '其他',
+              value: -1,
+            });
+            emitChange();
+            return;
+          }
+          if (props.resultField) {
+            checkboxData.value = get(res, props.resultField) || [];
+            checkboxData.value.push({
+              label: '其他',
+              value: -1,
+            });
+          }
+          emitChange();
+        } catch (error) {
+          console.warn(error);
+        } finally {
+          loading.value = false;
+        }
+      }
+
+      function emitChange() {
+        // emit('change', unref(getOptions));
+      }
+
+      // 单选改变
+      function handleRadioChange(e) {
+        console.log('🚀 ~ file: ApiComplex.vue:114 ~ handleRadioChange ~ e:', e);
+        checkboxDisabled.value = e.target.value ? false : true;
+      }
+
+      // 复选改变
+      function handleCheckboxChange(e) {
+        console.log('🚀 ~ file: ApiComplex.vue:114 ~ handleRadioChange ~ e:', e);
+        disabled.value = e.includes(-1) ? false : true;
+      }
+
+      return {
+        getAttrs,
+        loading,
+        handleChange,
+        props,
+        radioData,
+        radioValue,
+        checkboxData,
+        checkboxValue,
+        inputValue,
+        disabled,
+        checkboxDisabled,
+        handleRadioChange,
+        handleCheckboxChange,
+      };
+    },
+  });
+</script>

+ 10 - 2
src/components/Form/src/components/ApiTreeSelect.vue

@@ -36,7 +36,6 @@
           ...attrs,
         };
       });
-
       function handleChange(...args) {
         emit('change', ...args);
       }
@@ -76,7 +75,16 @@
         if (!isArray(result)) {
           result = get(result, props.resultField);
         }
-        treeData.value = (result as Recordable[]) || [];
+        treeData.value =
+          (props.params.root
+            ? [
+                {
+                  [attrs['fieldNames']['label']]: '根目录',
+                  [attrs['fieldNames']['key']]: '0',
+                  children: result,
+                },
+              ]
+            : (result as Recordable[])) || [];
         isFirstLoaded.value = true;
         emit('options-change', treeData.value);
       }

+ 0 - 1
src/components/Form/src/components/FormAction.vue

@@ -16,7 +16,6 @@
 
         <Button
           type="primary"
-          class="mr-2"
           v-bind="getSubmitBtnOptions"
           @click="submitAction"
           v-if="showSubmitButton"

+ 1 - 0
src/components/Form/src/props.ts

@@ -35,6 +35,7 @@ export const basicProps = {
   baseRowStyle: {
     type: Object as PropType<CSSProperties>,
   },
+  // Row
   baseRowGutter: {
     type: Array,
     default: () => [16, 0],

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

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