zs
2025-05-06 55bf797dcc730b37bc691ebab2b51ff9db8ed245
HIAWms/web/src/components/DyForm/DyForm.tsx
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,200 @@
// import { ElInput } from "element-plus";
import {
  defineComponent,
  PropType,
  ref,
  Ref,
  SetupContext,
  computed,
  unref,
  markRaw,
  DefineComponent,
} from 'vue'
import styles from './DyForm.module.scss'
import ElInput from 'element-plus/es/components/input/index'
import Option from '@/components/Select/Option'
import Select from '@/components/Select/Select'
import SelectInput from '@/components/SelectInput/SelectInput'
import type { FormInstance } from 'element-plus'
import Icon from '../Icon/Icon'
import {
  FormPropsType,
  FormItemPropType,
  PropsType,
  OptionItemType,
} from './DyForm.d'
import Variable from '../Variable/Variable'
import Title from '../Title/Title'
import TextareaFlow from '../Flow/Flow'
import get from 'lodash/get'
import set from 'lodash/set'
const formItemElementMap = markRaw<Record<string, any>>({
  input: ElInput,
  select: Select,
  selectInput: SelectInput,
  variable: Variable,
  textareaFlow: TextareaFlow,
})
const Type: Record<string, any> = {
  select: 'select',
}
export default defineComponent<FormPropsType>({
  //@ts-ignore
  name: '动态表单',
  props: {
    labelWidth: {
      type: String,
      default: '100px',
    },
    labelPosition: {
      type: String,
      default: 'right',
    },
    formData: {
      type: Object as PropType<{ [key: string]: any }>,
      default: () => ({}),
    },
    formItemProps: {
      type: Array,
      default: () => [],
    },
    inLine: {
      type: Boolean,
      default: false,
    },
  },
  setup(props: PropsType, { attrs, emit, expose }: SetupContext) {
    const formRef = ref<FormInstance>()
    const form: any = computed({
      get() {
        return props.formData
      },
      set(v) {
        emit('update:formData', v)
      },
    })
    const currentWidgetModel = computed(() => {
      return (path: string) => {
        return get(form.value, path)
      }
    })
    const validate = () => {
      if (!formRef.value) return false
      return new Promise((resolve, reject) => {
        formRef.value?.validate((valid: boolean) => {
          if (valid) {
            resolve(true)
          } else {
            reject(false)
          }
        })
      })
    }
    const resetForm = () => {
      if (!formRef.value) return false
      formRef.value.resetFields()
    }
    const formItemProps = computed(() => {
      return props.formItemProps || []
    })
    expose({ validate, resetForm })
    const FormRender: any = ($props: any) => {
      const item: FormItemPropType = $props.item
      const options = $props.item.options || []
      if (item.el && Type[item.el as string]) {
        return options.map((el: OptionItemType) => (
          <Option
            label={el.label || el.description || el.name}
            value={el.value}
          ></Option>
        ))
      }
      return null
    }
    const onUpdateModelValue = (v: string | number, prop: string) => {
      set(form.value, prop, v)
    }
    return () => {
      return (
        <div class={styles.formStyle}>
          <el-form
            labelPosition={props.labelPosition}
            labelWidth={props.labelWidth}
            model={form.value}
            ref={formRef}
            inline={props.inLine}
          >
            {formItemProps.value.map(
              (item: FormItemPropType, index: number) => {
                if (item.isTitle) {
                  if (typeof item.title === 'string') {
                    return (
                      <Title style="margin-bottom: 10px">{item.title}</Title>
                    )
                  }
                  return item.title
                }
                const itemProps: FormItemPropType = {}
                Object.entries(item).forEach(([key, value]) => {
                  itemProps[key] = unref(value)
                })
                const el =
                  typeof itemProps.el === 'string'
                    ? formItemElementMap[itemProps.el]
                    : itemProps.el || null
                const Component = el
                return Component && !item.isHide ? (
                  <el-form-item
                    label={itemProps.label}
                    prop={itemProps.prop}
                    rules={itemProps.rules}
                    key={itemProps.prop}
                    vSlots={
                      itemProps.labelIcon
                        ? {
                            label: () => (
                              <label class={styles.formitemPropsLabel}>
                                {itemProps.label}
                                <Icon icon={itemProps.labelIcon} />
                              </label>
                            ),
                          }
                        : null
                    }
                  >
                    <Component
                      style={{
                        width: itemProps.width,
                        height: itemProps.height,
                      }}
                      {...itemProps}
                      // v-model={form.value[itemProps.prop as keyof any]}
                      modelValue={currentWidgetModel.value(itemProps.prop)}
                      onUpdate:modelValue={(val: string | number) =>
                        onUpdateModelValue(val, itemProps.prop)
                      }
                    >
                      <FormRender item={itemProps} />
                    </Component>
                  </el-form-item>
                ) : null
              }
            )}
          </el-form>
        </div>
      )
    }
  },
})