222
schangxiang@126.com
2025-04-30 9bec4dcae002f36aa23231da11cb03a156b40110
PipeLineLems/web/src/components/DyForm/DyForm.tsx
@@ -3,20 +3,26 @@
  defineComponent,
  PropType,
  ref,
  Ref,
  onMounted,
  SetupContext,
  computed,
  unref,
  markRaw,
  DefineComponent,
  Component,
  watch,
  Fragment,
  useSlots,
} from 'vue'
import styles from './DyForm.module.scss'
import ElInput from 'element-plus/es/components/input/index'
import DyInput from '../Input/Input'
import Option from '@/components/Select/Option'
import Select from '@/components/Select/Select'
import SelectInput from '@/components/SelectInput/SelectInput'
import SearchSelect from '@/components/SearchSelect/SearchSelect'
import type { FormInstance } from 'element-plus'
import Icon from '../Icon/Icon'
import { Warning } from '@element-plus/icons-vue'
import RelationFlowDialog from '@/components/RelationFlowDialog/RelationFlowDialog'
import {
  FormPropsType,
  FormItemPropType,
@@ -28,19 +34,44 @@
import TextareaFlow from '../Flow/Flow'
import get from 'lodash/get'
import set from 'lodash/set'
import { has } from 'lodash'
import Tab from '@/components/Tab/Tab'
import TabPane from '@/components/Tab/TabPane'
import ElInputNumber from 'element-plus/es/components/input-number/index'
import { getCurrentLang, Language } from '@/libs/Language/Language'
const formItemElementMap = markRaw<Record<string, any>>({
  input: ElInput,
const formItemElementMap: Record<string, any> = markRaw({
  input: DyInput,
  inputNumber: ElInputNumber,
  select: Select,
  selectInput: SelectInput,
  flow: RelationFlowDialog,
  variable: Variable,
  textareaFlow: TextareaFlow,
  filterSelect: SearchSelect,
  switch: (props: PropType<any>, { attrs }: SetupContext) => {
    return <el-switch {...attrs} />
  },
  dateTime: (props: PropType<any>, { attrs }: SetupContext) => {
    return <el-date-picker
      type="datetime"
      format="YYYY-MM-DD HH:mm:ss"
      {...attrs}
    ></el-date-picker>
  },
  date: (props: PropType<any>, { attrs }: SetupContext) => {
    return <el-date-picker
      type="date"
      format="YYYY-MM-DD"
      {...attrs}
    ></el-date-picker>
  },
})
const Type: Record<string, any> = {
  select: 'select',
}
export default defineComponent<FormPropsType>({
export default defineComponent({
  //@ts-ignore
  name: '动态表单',
  props: {
@@ -57,16 +88,31 @@
      default: () => ({}),
    },
    formItemProps: {
      type: Array,
      type: Array as PropType<FormItemPropType[]>,
      default: () => [],
    },
    inLine: {
      type: Boolean,
      default: false,
    },
    customWidgetMap: {
      type: Object,
      default: () => ({}),
    },
    isCategory: {
      type: Boolean,
      default: false,
    },
    LanguageScopeKey: {
      type: String,
      default: '',
    },
  },
  setup(props: PropsType, { attrs, emit, expose }: SetupContext) {
    const formRef = ref<FormInstance>()
    const active = ref('')
    const isZh = ref(true)
    const slots = useSlots()
    const form: any = computed({
      get() {
        return props.formData
@@ -75,9 +121,14 @@
        emit('update:formData', v)
      },
    })
    const formPropsRef = ref<any>({})
    const currentWidgetModel = computed(() => {
      return (path: string) => {
        if (path.includes('.')) {
          const args = path.split('.')
          return get(form.value, args)
        }
        return get(form.value, path)
      }
    })
@@ -94,6 +145,14 @@
        })
      })
    }
    /**
     * 获取refs
     * @returns
     */
    const getRefByKey = (key: string) => {
      if (key) return formPropsRef.value[key]
      return formPropsRef.value
    }
    const resetForm = () => {
      if (!formRef.value) return false
@@ -101,10 +160,26 @@
    }
    const formItemProps = computed(() => {
      if (props.isCategory) {
        const tabMap: Record<string, FormItemPropType> = {}
        const tabs: FormItemPropType[] = []
        if (Array.isArray(props.formItemProps)) {
          props.formItemProps.forEach((item: any) => {
            tabMap[item.category] = tabMap[item.category] || []
            tabMap[item.category].push(item)
          })
          Object.keys(tabMap).forEach((key: string) => {
            tabs.push({
              name: key,
              content: tabMap[key],
            })
          })
        }
        return tabs
      }
      return props.formItemProps || []
    })
    expose({ validate, resetForm })
    const FormRender: any = ($props: any) => {
      const item: FormItemPropType = $props.item
@@ -112,17 +187,158 @@
      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>
            label={el.label || el.description || el.name}
            class={styles.optionLabel}
            key={el.value}
          >
            {el.label || el.description || el.name}
            {el.tip ? (
              <el-tooltip
                class="box-item"
                effect="dark"
                content={el.tip}
                placement="top"
                key={el.value}
                persistent={false}
              >
                <el-icon>
                  <Warning />
                </el-icon>
              </el-tooltip>
            ) : null}
          </Option>
        ))
      }
      return null
    }
    const onUpdateModelValue = (v: string | number, prop: string) => {
      set(form.value, prop, v)
    const onUpdateModelValue = (v: string | number, path: string) => {
      if (path.includes('.')) {
        const args = path.split('.')
        return set(form.value, args, v)
      }
      set(form.value, path, v)
    }
    const initFormData = () => {
      formItemProps.value.forEach((item: FormItemPropType) => {
        form.value[item.prop] = form.value[item.prop] || item.defaultValue
      })
      active.value = formItemProps.value[0].name
    }
    const checkZh = (lang: string) => {
      const languageStr = lang.toLowerCase()
      if (languageStr.includes('zh')) return true
      if (languageStr.includes('original')) return true
      return false
    }
    const onLanguageChange = () => {
      Language.useChange((language: any) => {
        isZh.value = checkZh(language.lang)
      })
    }
    onMounted(() => {
      isZh.value = checkZh(getCurrentLang())
      onLanguageChange()
    })
    const RenderItemProps = ($props: any) => {
      const WidgetMap = {
        ...formItemElementMap,
        ...props.customWidgetMap,
      }
      const formItemProps = $props.formItemProps
      return (
        <Fragment>
          {formItemProps.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'
                ? WidgetMap[itemProps.el]
                : itemProps.el || null
            const hasSlot = itemProps.slot
            const Component = hasSlot ? slots[itemProps.el] : el
            const isHide = has(item.isHide, 'value')
              ? item.isHide?.value
              : item.isHide
            return Component && !isHide ? (
              <el-form-item
                label={itemProps.label}
                prop={itemProps.prop}
                rules={itemProps.rules}
                key={itemProps.prop + index}
                class={styles.itemDistance}
                labelPosition={itemProps.labelPosition}
                labelWidth={isZh.value ? props.labelWidth : 'auto'}
                vSlots={
                  itemProps.icon
                    ? {
                      label: () => (
                        <label
                          key={itemProps.prop}
                          class={styles.formitemPropsLabel}
                        >
                          {itemProps.label}
                          {itemProps.icon ? (
                            <el-tooltip
                              class="box-item"
                              effect="dark"
                              content={itemProps.tip}
                              placement="top"
                              raw-content={itemProps.rawContent}
                              persistent={false}
                            >
                              <Icon
                                style="margin-left: 5px"
                                icon={itemProps.icon}
                              />
                            </el-tooltip>
                          ) : null}
                        </label>
                      ),
                    }
                    : null
                }
              >
                <Component
                  style={{
                    width: itemProps.width,
                    height: itemProps.height,
                  }}
                  {...itemProps}
                  placeholder={itemProps.placeholder}
                  ref={(ref) => (formPropsRef.value[itemProps.prop] = ref)}
                  modelValue={currentWidgetModel.value(itemProps.prop)}
                  onUpdate:modelValue={(val: string | number) =>
                    onUpdateModelValue(val, itemProps.prop)
                  }
                >
                  <FormRender item={itemProps} />
                </Component>
              </el-form-item>
            ) : null
          })}
        </Fragment>
      )
    }
    expose({ validate, resetForm, initFormData, getRefByKey })
    return () => {
      return (
@@ -130,67 +346,28 @@
          <el-form
            labelPosition={props.labelPosition}
            labelWidth={props.labelWidth}
            // labelWidth={isZh.value ? props.labelWidth : 'auto'}
            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
              }
            {props.isCategory ? (
              <Tab
                active={active.value}
                class={styles.tabContent}
                size="small"
                type="params"
              >
                {formItemProps.value.map((item: any) => {
                  return (
                    <TabPane key={item.name} label={item.name} name={item.name}>
                      <RenderItemProps formItemProps={item.content} />
                    </TabPane>
                  )
                })}
              </Tab>
            ) : (
              <RenderItemProps formItemProps={formItemProps.value} />
            )}
          </el-form>
        </div>