useGenerateFormSchemasByObjectModel.ts 6.74 KB
import { unref } from 'vue';
import { DeviceModelOfMatterAttrs } from '/@/api/device/model/deviceModel';
import { DataType, Specs, StructJSON } from '/@/api/device/model/modelOfMatterModel';
import { FormSchema } from '/@/components/Form';
import { DataTypeEnum, OriginalDataTypeEnum } from '/@/enums/objectModelEnum';
import { TCPProtocolTypeEnum } from '/@/enums/deviceEnum';
import { EdgeDeviceItemType } from '/@/api/edgeManage/model/edgeInstance';
import { useI18n } from '/@/hooks/web/useI18n';
export interface BasicCreateFormParams {
  identifier: string;
  functionName: string;
  dataType: DataType;
}

const { t } = useI18n();

const validateDouble = (value: number, min?: number | string, max?: number | string) => {
  min = Number(min) ?? Number.MIN_SAFE_INTEGER;
  max = Number(max) ?? Number.MAX_SAFE_INTEGER;

  return {
    flag: value < min || value > max,
    message: `取值范围在${min}~${max}之间`,
  };
};

export const useGenerateFormSchemasByObjectModel = () => {
  const createInputNumber = ({
    identifier,
    functionName,
    dataType,
  }: BasicCreateFormParams): FormSchema => {
    const { specs, type } = dataType;
    const { valueRange, step } = specs! as Partial<Specs>;
    const { max, min } = valueRange || {};
    return {
      field: identifier,
      label: functionName,
      component: 'InputNumber',
      rules: [
        {
          type: 'number',
          trigger: 'change',
          validator: (_rule, value) => {
            const { flag, message } = validateDouble(value, min, max);
            if (flag) {
              return Promise.reject(`${functionName}${message}`);
            }
            return Promise.resolve(value);
          },
        },
      ],
      componentProps: {
        max: max ?? Number.MAX_SAFE_INTEGER,
        min: min ?? Number.MIN_SAFE_INTEGER,
        step,
        placeholder: `${t('common.inputText')}${functionName}`,
        precision: type === DataTypeEnum.NUMBER_INT ? 0 : 2,
      },
    } as FormSchema;
  };

  const createInput = ({
    identifier,
    functionName,
    dataType,
  }: BasicCreateFormParams): FormSchema => {
    const { specs } = dataType;
    const { length = 10240 } = specs! as Partial<Specs>;
    return {
      field: identifier,
      label: functionName,
      component: 'Input',
      rules: [
        {
          type: 'string',
          trigger: 'change',
          validator: (_rule, value) => {
            if (value?.length > length) {
              return Promise.reject(`${functionName}数据长度应该小于${length}`);
            }
            return Promise.resolve(value);
          },
        },
      ],
      componentProps: {
        maxLength: length,
        placeholder: `${t('common.inputText')}${functionName}`,
      },
    } as FormSchema;
  };

  const createSelect = ({
    identifier,
    functionName,
    dataType,
  }: BasicCreateFormParams): FormSchema => {
    const { specs } = dataType;
    const { boolClose, boolOpen } = specs! as Partial<Specs>;
    return {
      field: identifier,
      label: functionName,
      component: 'Select',
      componentProps: {
        options: [
          { label: `${boolClose}-0`, value: 0 },
          { label: `${boolOpen}-1`, value: 1 },
        ],
        placeholder: `${t('common.chooseText')}${functionName}`,
        getPopupContainer: () => document.body,
      },
    };
  };

  const createEnumSelect = ({
    identifier,
    functionName,
    dataType,
  }: BasicCreateFormParams): FormSchema => {
    const { specsList } = dataType;
    return {
      field: identifier,
      label: functionName,
      component: 'Select',
      componentProps: {
        options: specsList?.map((item) => ({ label: item.name, value: item.value })),
        placeholder: `${t('common.chooseText')}${functionName}`,
        getPopupContainer: () => document.body,
      },
    };
  };

  const createModbusValueInput = (objectModel: DeviceModelOfMatterAttrs): FormSchema => {
    const { identifier, name, detail, extensionDesc } = objectModel;

    const { dataType } = detail || {};
    const { specs } = dataType || {};
    const { valueRange } = specs as Specs;
    const { max, min } = valueRange || {};

    if (extensionDesc?.originalDataType === OriginalDataTypeEnum.BOOLEAN) {
      const options = [
        { label: '闭合', value: parseInt('FF00', 16) },
        { label: '断开', value: parseInt('0000', 16) },
      ];

      return {
        field: identifier,
        label: name,
        component: 'Select',
        componentProps: () => {
          return {
            options,
            placeholder: `${t('common.chooseText')}${name}`,
            getPopupContainer: () => document.body,
          };
        },
      };
    }

    const isStringType = extensionDesc?.originalDataType === OriginalDataTypeEnum.STRING;
    return {
      field: identifier,
      label: name,
      component: isStringType ? 'Input' : 'InputNumber',
      rules: isStringType
        ? []
        : [
            {
              type: 'number',
              validator: (_rule, value) => {
                const { flag, message } = validateDouble(value, min, max);
                if (flag) {
                  return Promise.reject(`${name}${message}`);
                }
                return Promise.resolve(value);
              },
            },
          ],
      componentProps: {
        max: max ?? Number.MAX_SAFE_INTEGER,
        min: min ?? Number.MIN_SAFE_INTEGER,
        placeholder: `${t('common.inputText')}${name}`,
        // precision: floatType.includes(extensionDesc!.originalDataType) ? 2 : 0,
      },
    };
  };

  const schemaMethod = {
    [DataTypeEnum.BOOL]: createSelect,
    [DataTypeEnum.NUMBER_DOUBLE]: createInputNumber,
    [DataTypeEnum.NUMBER_INT]: createInputNumber,
    [DataTypeEnum.STRING]: createInput,
    [DataTypeEnum.ENUM]: createEnumSelect,
  };

  const getFormByObjectModel = (
    objectModel: DeviceModelOfMatterAttrs,
    deviceDetail: EdgeDeviceItemType
  ): FormSchema[] => {
    const { name, identifier, detail } = objectModel;

    const isTCPModbusProduct =
      unref(deviceDetail).deviceProfile?.profileData?.transportConfiguration?.protocol ===
      TCPProtocolTypeEnum.MODBUS_RTU;

    const { dataType } = detail;
    const { type } = dataType || {};

    if (isTCPModbusProduct) {
      return [createModbusValueInput(objectModel)];
    }

    if (type === DataTypeEnum.STRUCT) {
      return (dataType?.specs as StructJSON[]).map((item) => {
        const { functionName, identifier, dataType } = item;
        const { type } = dataType || {};

        return schemaMethod[type!]?.({ identifier, functionName, dataType });
      });
    }

    const result = schemaMethod[type!]?.({ identifier, functionName: name, dataType: dataType! });
    return result ? [result] : [];
  };

  return { getFormByObjectModel };
};