index.vue 4.58 KB
<script lang="ts" setup>
  import { BasicForm, FormSchema, useForm } from '/@/components/Form';
  import { ComponentType, ColEx } from '/@/components/Form/src/types/index';
  import { computed } from '@vue/reactivity';
  import { isFunction } from '/@/utils/is';
  import { unref } from 'vue';
  import { watch } from 'vue';
  import { nextTick } from 'vue';
  import { ref } from 'vue';
  import { onMounted } from 'vue';

  interface ValueItemType {
    value: any;
  }

  enum FormFieldsEnum {
    TOTAL_CONTROL = 'totalControl',
  }

  enum EmitEventEnum {
    UPDATE_VALUE = 'update:value',
  }

  const emit = defineEmits<{
    (event: EmitEventEnum.UPDATE_VALUE, value: ValueItemType[]): void;
  }>();

  const props = withDefaults(
    defineProps<{
      value: ValueItemType[];
      length?: number;
      component?: ComponentType;
      itemColProps?: Partial<ColEx>;
      itemLabel?: (index: number) => string;
      itemProps?: (index: number) => FormSchema;
      showTotalControl?: boolean;
      totalControlProps?: FormSchema;
    }>(),
    {
      value: () => [],
      length: 0,
      component: 'Switch',
      itemLabel: (index: number) => `#${index}`,
      itemProps: () => ({} as unknown as FormSchema),
      itemColProps: () => ({ span: 12 } as Partial<ColEx>),
      showTotalControl: true,
      totalControlProps: () => ({} as unknown as FormSchema),
    }
  );

  const getProps = computed(() => {
    return props;
  });

  const batchSetValue = (value: any): ValueItemType[] => {
    const { length } = unref(getProps);
    return Array.from({ length }, () => ({ value }));
  };

  const getTotalControlItem = computed(() => {
    const { totalControlProps, component, showTotalControl } = unref(getProps);
    return {
      ...totalControlProps,
      field: FormFieldsEnum.TOTAL_CONTROL,
      component,
      ifShow: showTotalControl,
      componentProps: {
        onChange(value: any) {
          handleUpdateValue(batchSetValue(value));
        },
      },
    } as FormSchema;
  });

  const getSchemas = computed(() => {
    const { itemProps, itemLabel, length, component } = unref(getProps);
    let label = isFunction(itemLabel) ? itemLabel : (index: number) => `#${index}`;
    let _itemProps = isFunction(itemProps) ? itemProps : () => ({});
    const schemas = Array.from(
      { length },
      (_item, index) =>
        ({
          ..._itemProps(index),
          label: label(index),
          field: index.toString(),
          component,
          componentProps: {
            onChange: async () => {
              await nextTick();
              handleUpdateValue();
            },
          },
        } as FormSchema)
    );

    length && schemas.unshift(unref(getTotalControlItem));

    return schemas;
  });

  const [registerForm, { getFieldsValue, setProps, setFieldsValue }] = useForm({
    showActionButtonGroup: false,
    schemas: unref(getSchemas),
    // baseColProps,
    baseColProps: props.itemColProps,
  });

  const handleUpdateValue = (value?: ValueItemType[]) => {
    if (value) {
      emit(EmitEventEnum.UPDATE_VALUE, value);
      return;
    }
    const allValue = getFieldsValue();
    const sortKeyList = Array.from({ length: unref(getProps).length }, (_v, key) => key);
    const res = sortKeyList.map((item) => ({ value: allValue[item] } as ValueItemType));

    emit(EmitEventEnum.UPDATE_VALUE, res);
  };

  const transformValue = (value: ValueItemType[]) => {
    const { length } = unref(getProps);
    if (value.length !== length) {
      value = Array.from(
        { length: unref(getProps).length },
        () => ({ value: null } as ValueItemType)
      );
    }
    return value.reduce((prev, next, index) => ({ ...prev, [index]: next.value }), {});
  };

  const initialized = ref(false);

  watch(
    () => props.value,
    async (target) => {
      if (target) {
        let flag = unref(initialized);
        if (!flag) {
          await nextTick();
        }
        const value = transformValue(target);
        setFieldsValue(value);

        if (!flag) {
          handleUpdateValue();
        }
      }
    },
    {
      immediate: true,
    }
  );

  watch(
    () => [props.length, props.component],
    (target) => {
      if (target !== undefined || target !== null) {
        setProps({
          schemas: unref(getSchemas),
        });
        handleUpdateValue();
      }
    }
  );

  onMounted(() => {
    initialized.value = true;
  });
</script>

<template>
  <BasicForm class="control-group-form" @register="registerForm" />
</template>

<style lang="less" scoped>
  .control-group-form {
    :deep(.ant-form-item-label) {
      font-weight: 700;
    }
  }
</style>