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

interface ThingsModelFormPropsType {
  value?: Recordable
  inputData?: StructJSON[]
  required?: boolean
  title?: string
  transportType?: string
}

const props = withDefaults(defineProps<ThingsModelFormPropsType>(), {
  inputData: () => [],
  required: true,
})

const propsRef = ref<Partial<ThingsModelFormPropsType>>({})

const getProps = computed<ThingsModelFormPropsType>(() => ({ ...props, ...unref(propsRef) }))

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

const [register, formActionType] = useForm({
  schemas: getFormSchemasByProps(),
  showActionButtonGroup: false,
  name: Math.random().toString(16).substring(2),
  labelWidth: 100,
  labelAlign: FormLabelAlignEnum.RIGHT,
  layout: FormLayoutEnum.HORIZONTAL,
})

const getStructFormItem = computed(() => {
  const { inputData } = unref(getProps)
  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()
}

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

function getFormSchemasByProps() {
  return getFormSchemas({ structJSON: unref(getProps).inputData || [], required: unref(getProps).required, transportType: unref(getProps).transportType })
}

watch(
  () => unref(getProps).inputData,
  (value) => {
    if (value && value.length)
      formActionType.setProps({ schemas: getFormSchemasByProps() })
  })

function setProps(props: Partial<ThingsModelFormPropsType>) {
  propsRef.value = deepMerge(unref(propsRef) || {}, props) as any
}

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

<template>
  <Card class="!border-2 !border-dashed" :title="getProps.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-label) {
    >label {
      display: block;
      text-align: right;
      white-space: nowrap;
      text-overflow: ellipsis;
      overflow: hidden;
    }
  }
}

:deep(.ant-form-item-control) {
  margin-left: 6px;
}
</style>