config.ts 10.7 KB
import { unref } from 'vue';
import { createHexCommandRuleValidator } from '.';
import { createFunctionNameFormItem, createIdentifierFormItem } from './DataTypeForm/config';
import { useObjectModelFormContext } from './useObjectModelFormContext';
import { findDictItemByCode } from '/@/api/system/dict';
import { FormSchema } from '/@/components/Form';
import {
  ServiceCallTypeEnum,
  ServiceCallTypeNameEnum,
  TCPProtocolTypeEnum,
  TransportTypeEnum,
} from '/@/enums/deviceEnum';
import { DictEnum } from '/@/enums/dictEnum';
import {
  ObjectModelAccessModeEnum,
  FunctionTypeEnum,
  FunctionTypeNameEnum,
  ObjectEventTypeEnum,
  BuiltInIdentifierEnum,
} from '/@/enums/objectModelEnum';
import { DataActionModeEnum } from '/@/enums/toolEnum';
import { DeviceTypeEnum } from '/@/api/device/model/deviceModel';
import { DeviceProfileDetail } from '/@/api/device/model/deviceConfigModel';

export enum FormFieldsEnum {
  FUNCTION_TYPE = 'functionType',
  FUNCTION_NAME = 'functionName',
  IDENTIFIER = 'identifier',
  DATA_TYPE = 'dataType',
  ACCESS_MODE = 'accessMode',
  VALUE_RANGE = 'valueRange',
  STEP = 'step',
  UNIT = 'unit',
  UNIT_NAME = 'unitName',
  REMARK = 'remark',
  BOOL_CLOSE = 'boolClose',
  BOOL_OPEN = 'boolOpen',
  LENGTH = 'length',
  EXTENSION_DESC = 'extensionDesc',
  ENUMS_DATA = 'enumsData',
  STRUCT_DATA = 'structData',

  CALL_TYPE = 'callType',
  SERVICE_COMMAND = 'serviceCommand',
  INPUT_DATA = 'inputData',
  OUTPUT_DATA = 'outputData',

  EVENT_TYPE = 'eventType',

  DATA_TYPE_FORM = 'dataTypeForm',
}

export enum FormFieldsNameEnum {
  FUNCTION_TYPE = '功能类型',
  FUNCTION_NAME = '功能名称',
  IDENTIFIER = '功能标识符',
  DATA_TYPE = '数据类型',
  ACCESS_MODE = '读写类型',
  VALUE_RANGE = '取值范围',
  STEP = '步长',
  UNIT = '单位',
  UNIT_NAME = '单位名称',
  REMARK = '备注',
  BOOL_CLOSE = '0 - 关',
  BOOL_OPEN = '1 - 开',
  LENGTH = '数据长度(字节)',
  EXTENSION_DESC = '拓展描述符',
  ENUMS_DATA = '枚举项',
  STRUCT_DATA = 'JSON对象',

  CALL_TYPE = '调用方式',
  SERVICE_COMMAND = '输入参数',
  INPUT_DATA = '输入参数',
  OUTPUT_DATA = '输出参数',

  EVENT_TYPE = '事件类型',
}

export const getFormSchemas = ({
  transportType,
  deviceRecord,
}: {
  transportType?: string;
  mode?: DataActionModeEnum;
  deviceRecord?: DeviceProfileDetail;
}): FormSchema[] => {
  const isTCPTransport = deviceRecord?.transportType === TransportTypeEnum.TCP;

  const isTCPModbusProduct =
    isTCPTransport &&
    deviceRecord?.profileData.transportConfiguration.protocol === TCPProtocolTypeEnum.MODBUS_RTU;

  return [
    {
      field: FormFieldsEnum.FUNCTION_TYPE,
      label: FormFieldsNameEnum.FUNCTION_TYPE,
      component: 'Segmented',
      defaultValue: FunctionTypeEnum.PROPERTIES,
      required: true,
      helpMessage: [
        '属性一般是指设备的运行状态,如当前温度等;服务是指设备可被调用的方法,支持定义参数,如执行某项任务;事件则是指设备上报的通知,如告警,需要被及时处理。',
      ],
      dynamicDisabled: () => {
        const { getModalMode } = useObjectModelFormContext();
        return unref(getModalMode) !== DataActionModeEnum.CREATE;
      },
      componentProps: ({ formActionType }) => {
        const isSensor = deviceRecord?.deviceType === DeviceTypeEnum.SENSOR;
        return {
          options: [
            { title: FunctionTypeNameEnum.PROPERTIES, value: FunctionTypeEnum.PROPERTIES },
            {
              title: FunctionTypeNameEnum.SERVICE,
              value: FunctionTypeEnum.SERVICE,
              disabled: (isTCPTransport && isSensor) || isTCPModbusProduct,
            },
            {
              title: FunctionTypeNameEnum.EVENTS,
              value: FunctionTypeEnum.EVENTS,
              disabled: isTCPTransport,
            },
          ],
          onChange() {
            const { setFieldsValue, clearValidate } = formActionType;
            setFieldsValue({
              [FormFieldsEnum.INPUT_DATA]: [],
              [FormFieldsEnum.OUTPUT_DATA]: [],
              [FormFieldsEnum.STRUCT_DATA]: [],
              [FormFieldsEnum.SERVICE_COMMAND]: null,
            });
            clearValidate();
          },
        };
      },
    },
    {
      field: FormFieldsEnum.DATA_TYPE_FORM,
      component: 'Input',
      label: '',
      ifShow: ({ model }) =>
        model[FormFieldsEnum.FUNCTION_TYPE] === FunctionTypeEnum.PROPERTIES && !isTCPModbusProduct,
      colSlot: FormFieldsEnum.DATA_TYPE_FORM,
    },
    createFunctionNameFormItem({
      ifShow: ({ model }) =>
        model[FormFieldsEnum.FUNCTION_TYPE] !== FunctionTypeEnum.PROPERTIES || isTCPModbusProduct,
    }),
    createIdentifierFormItem({
      helpMessage: ['支持大小写字母、数字和下划线', '如要支持原始数据留存,请使用标识符 "source"'],
      ifShow: ({ model }) =>
        model[FormFieldsEnum.FUNCTION_TYPE] !== FunctionTypeEnum.PROPERTIES || isTCPModbusProduct,
      component: 'AutoComplete',
      defaultValue: '',
      componentProps: {
        options: isTCPModbusProduct ? [{ value: BuiltInIdentifierEnum.SOURCE }] : [],
        placeholder: '请输入功能标识符',
        autocomplete: false,
      },
    }),
    {
      field: FormFieldsEnum.ACCESS_MODE,
      component: 'ApiRadioGroup',
      label: FormFieldsNameEnum.ACCESS_MODE,
      required: true,
      ifShow: ({ model }) =>
        ![FunctionTypeEnum.SERVICE, FunctionTypeEnum.EVENTS].includes(
          model[FormFieldsEnum.FUNCTION_TYPE]
        ) && !isTCPModbusProduct,
      defaultValue: ObjectModelAccessModeEnum.READ_AND_WRITE,
      componentProps: {
        placeholder: '请选择读写类型',
        api: findDictItemByCode,
        params: {
          dictCode: DictEnum.READ_WRITE_TYP,
        },
        labelField: 'itemText',
        valueField: 'itemValue',
      },
    },

    // 服务
    {
      field: FormFieldsEnum.CALL_TYPE,
      label: FormFieldsNameEnum.CALL_TYPE,
      component: 'RadioGroup',
      defaultValue: ServiceCallTypeEnum.ASYNC,
      required: true,
      ifShow: ({ model }) => model[FormFieldsEnum.FUNCTION_TYPE] === FunctionTypeEnum.SERVICE,
      componentProps: () => {
        return {
          options: Object.keys(ServiceCallTypeEnum).map((value) => ({
            label: ServiceCallTypeNameEnum[value],
            value,
          })),
        };
      },
    },
    {
      field: FormFieldsEnum.SERVICE_COMMAND,
      label: FormFieldsNameEnum.SERVICE_COMMAND,
      component: 'Input',
      required: true,
      rules: [{ message: '输入参数为必填项', required: true }, ...createHexCommandRuleValidator()],
      ifShow: ({ model }) =>
        model[FormFieldsEnum.FUNCTION_TYPE] === FunctionTypeEnum.SERVICE &&
        transportType === TransportTypeEnum.TCP,
      componentProps: () => {
        return {
          placeholder: '请输入ASCII或HEX服务命令',
        };
      },
    },
    {
      field: FormFieldsEnum.INPUT_DATA,
      label: FormFieldsNameEnum.INPUT_DATA,
      component: 'Input',
      slot: FormFieldsEnum.INPUT_DATA,
      changeEvent: 'update:value',
      valueField: 'value',
      required: true,
      ifShow: ({ model }) =>
        model[FormFieldsEnum.FUNCTION_TYPE] === FunctionTypeEnum.SERVICE &&
        transportType !== TransportTypeEnum.TCP,
    },

    // 事件
    {
      field: FormFieldsEnum.EVENT_TYPE,
      label: FormFieldsNameEnum.EVENT_TYPE,
      required: true,
      component: 'ApiRadioGroup',
      defaultValue: ObjectEventTypeEnum.INFO,
      ifShow: ({ model }) => model[FormFieldsEnum.FUNCTION_TYPE] === FunctionTypeEnum.EVENTS,
      componentProps: () => {
        return {
          placeholder: '请选择事件类型',
          api: findDictItemByCode,
          params: {
            dictCode: DictEnum.EVENT_TYPE,
          },
          labelField: 'itemText',
          valueField: 'itemValue',
          getPopupContainer: () => document.body,
        };
      },
    },
    {
      field: FormFieldsEnum.OUTPUT_DATA,
      label: FormFieldsNameEnum.OUTPUT_DATA,
      component: 'Input',
      slot: FormFieldsEnum.OUTPUT_DATA,
      changeEvent: 'update:value',
      valueField: 'value',
      ifShow: ({ model }) =>
        [FunctionTypeEnum.SERVICE, FunctionTypeEnum.EVENTS].includes(
          model[FormFieldsEnum.FUNCTION_TYPE]
        ),
    },

    // TCP Modbus
    {
      field: FormFieldsEnum.UNIT_NAME,
      label: FormFieldsNameEnum.UNIT_NAME,
      component: 'Input',
      show: false,
    },
    {
      field: FormFieldsEnum.UNIT,
      label: FormFieldsNameEnum.UNIT,
      component: 'ApiSelect',
      ifShow: () => isTCPModbusProduct,
      componentProps: ({ formActionType }) => {
        const { setFieldsValue } = formActionType;
        return {
          placeholder: '请选择单位',
          api: async (params: Recordable) => {
            const list = await findDictItemByCode(params);
            list.map((item) => (item.itemText = `${item.itemText} / ${item.itemValue}`));
            return list;
          },
          params: {
            dictCode: DictEnum.ATTRIBUTE_UNIT,
          },
          labelField: 'itemText',
          valueField: 'itemValue',
          onChange(_, record: Record<'label' | 'value', string>) {
            if (record) {
              const { label } = record;
              setFieldsValue({ [FormFieldsEnum.UNIT_NAME]: label });
            }
          },
          getPopupContainer: () => document.body,
          showSearch: true,
          filterOption: (inputValue: string, option: Record<'label' | 'value', string>) => {
            let { label, value } = option;
            label = label.toLowerCase();
            value = value.toLowerCase();
            inputValue = inputValue.toLowerCase();
            return label.includes(inputValue) || value.includes(inputValue);
          },
        };
      },
    },
    {
      field: FormFieldsEnum.EXTENSION_DESC,
      component: 'Input',
      label: FormFieldsNameEnum.EXTENSION_DESC,
      slot: FormFieldsEnum.EXTENSION_DESC,
      helpMessage: ['扩展描述用于配置设备接入网关协议和物模型定义之间的映射关系。'],
      rules: [
        {
          required: true,
          validator(_rule, value: any) {
            return Object.values(value || {}).length
              ? Promise.resolve()
              : Promise.reject('请填写拓展描述符');
          },
        },
      ],
      ifShow: ({ model }) =>
        isTCPModbusProduct && model[FormFieldsEnum.IDENTIFIER] !== BuiltInIdentifierEnum.SOURCE,
    },

    {
      field: FormFieldsEnum.REMARK,
      label: FormFieldsNameEnum.REMARK,
      component: 'InputTextArea',
      componentProps: {
        rows: 4,
        maxLength: 100,
        placeholder: '请输入描述',
      },
    },
  ];
};