index.vue 3.63 KB
<script setup lang="ts">
import { Card } from 'ant-design-vue'
import { computed, nextTick, reactive, unref, watch } from 'vue'
import type { ComponentExposeType } from '../PublicForm'
import { getFormSchemas } from './config'
import { ThingsModelForm } from '.'
import type { StructJSON } from '@/api/device/model'
import { BasicForm, useForm } from '@/components/Form'
import { DataTypeEnum } from '@/enums/datasource'
import { FormLabelAlignEnum, FormLayoutEnum } from '@/components/Form/src/enum'

const props = withDefaults(defineProps<{
  value: Recordable
  inputData?: StructJSON[]
  required?: boolean
  title?: string
  transportType?: string
}>(), {
  inputData: () => [],
  required: true,
})

const thingsModelFormListElMap = reactive<Record<string, { el: InstanceType<typeof ThingsModelForm>; structJSON: StructJSON }>>({})

// const getLabelWidth = () => {
//   return Math.max(...((props.inputData || [])?.map(item => item?.functionName?.length))) * 12
// }

const [register, formActionType] = useForm({
  schemas: getFormSchemas({ structJSON: props.inputData || [], required: props.required, transportType: props.transportType }),
  showActionButtonGroup: false,
  // labelWidth: getLabelWidth() || 80,
  labelAlign: FormLabelAlignEnum.RIGHT,
  layout: FormLayoutEnum.HORIZONTAL,
})

const getStructFormItem = computed(() => {
  const { inputData } = props
  return inputData.filter(item => item.dataType?.type === DataTypeEnum.STRUCT)
})

const setFormElRef = (el: InstanceType<typeof ThingsModelForm>, structJSON: StructJSON) => {
  const _structJSON = unref(getStructFormItem).find(item => item.identifier === structJSON.identifier)

  if (_structJSON)
    thingsModelFormListElMap[structJSON.identifier] = { el, structJSON }
}

const getFieldsValue = () => {
  const basicValue = formActionType.getFieldsValue()

  const structValue: Recordable = {}
  for (const key of Object.keys(thingsModelFormListElMap)) {
    const item = thingsModelFormListElMap[key]
    const { el } = item
    structValue[key] = el.getFieldsValue() || {}
  }

  return {
    ...basicValue,
    ...structValue,
  }
}

const setFieldsValue = (value: Recordable) => {
  return formActionType.setFieldsValue(value)
}

const validate = async () => {
  await formActionType.validate()
  for (const key of Object.keys(thingsModelFormListElMap))
    await thingsModelFormListElMap[key].el.validate()
}

const updateSchema = (value: Recordable) => {
  return formActionType.updateSchema(value)
}

watch(() => props.value,
  async (value) => {
    await nextTick()
    formActionType.setFieldsValue(value || {})
  },
  { immediate: true },
)

watch(
  () => props.inputData,
  (value) => {
    if (value && value.length) {
      const schemas = getFormSchemas({ structJSON: props.inputData || [], required: props.required, transportType: props.transportType })
      formActionType.setProps({ schemas })
    }
  })

defineExpose<ComponentExposeType>({
  getFieldsValue,
  setFieldsValue,
  validate,
  updateSchema,
})
</script>

<template>
  <Card class="!border-2 !border-dashed" :title="title">
    <BasicForm class="things-model-form" @register="register">
      <template v-for="item in getStructFormItem" #[item.identifier]="{ model, field }" :key="item.identifier">
        <ThingsModelForm :ref="(el) => setFormElRef(el as InstanceType<typeof ThingsModelForm>, item) " v-model:value="model[field]" :input-data="(item.dataType?.specs as StructJSON[]) || []" :title="item.functionName" />
      </template>
    </BasicForm>
  </Card>
</template>

<style lang="less" scoped>
  .things-model-form {
    :deep(.ant-input-number) {
      width: 100%;
    }
  }
  :deep(.ant-form-item-control){
    margin-left: 6px;
  }
</style>