芹菜是一根葱
专业解决各种前端Bug,吊打各种面试官

那么否则: 1<总数量<=20

赋值的每个项都是必填

父组件:

ActionThenElse.vue

<template>
  <el-form :model="formData" ref="formRef" :rules="formRules">
    <ActionGroup
      v-model="formData.actions"
      prop="actions"
      label="那么:"
      :variable-options="variableOptions"
      :total-count="totalActionCount"
      :other-count="formData.elseActions.length"
      :required="isActionsRequired"
    />

    <ActionGroup
      v-model="formData.elseActions"
      prop="elseActions"
      label="否则:"
      :variable-options="variableOptions"
      :total-count="totalActionCount"
      :other-count="formData.actions.length"
      :required="isElseActionsRequired"
    />

    <el-form-item>
      <el-button type="primary" @click="validateForm">校验表单</el-button>
      <el-button @click="resetForm">重置</el-button>
    </el-form-item>
  </el-form>
</template>

<script setup>
import { ref, computed } from 'vue'
import ActionGroup from './ActionGroup.vue'

const formRef = ref()
const formData = ref({
  actions: [],
  elseActions: [],
})

const variableOptions = [
  { value: 'var1', label: '变量1' },
  { value: 'var2', label: '变量2' },
]

const totalActionCount = computed(() => {
  return formData.value.actions.length + formData.value.elseActions.length
})

const isActionsRequired = computed(() => {
  return formData.value.elseActions.length === 0
})

const isElseActionsRequired = computed(() => {
  return formData.value.actions.length === 0
})

const formRules = {
  actions: [
    {
      validator: (rule, value, callback) => {
        if (totalActionCount.value === 0) {
          callback(new Error('至少需要一条操作(在"那么"或"否则"中)'))
        } else {
          callback()
        }
      },
      trigger: 'change',
    },
  ],
  elseActions: [
    {
      validator: (rule, value, callback) => {
        if (totalActionCount.value === 0) {
          callback(new Error('至少需要一条操作(在"那么"或"否则"中)'))
        } else {
          callback()
        }
      },
      trigger: 'change',
    },
  ],
}

const validateForm =  () => {
   formRef.value.validate((valid, fields) => {
    if (!valid) {
      return
    } 
  })
  
}

const resetForm = () => {
  formRef.value.resetFields()
  formData.value = {
    actions: [{ actionType: '', leftValue: '', rightValue: '' }],
    elseActions: [],
  }
}
</script>

子组件ActionGroup.vue:

<!-- ActionGroup.vue -->
<template>
  <el-form-item :label="label" :prop="prop">
    <div class="action-container">
      <el-button
        type="primary"
        link
        @click="addAction"
        icon="Plus"
        :disabled="disableAdd"
      >
        添加操作 ({{ modelValue.length }})
      </el-button>
      <div v-if="showEmptyTip" class="empty-tip">
        {{ emptyTip }}
      </div>

      <div
        v-for="(action, index) in modelValue"
        :key="`${prop}-${index}`"
        class="action-row"
      >
        <el-form-item
          :prop="`${prop}.${index}.actionType`"
          :rules="[{ required: true, message: '请选择操作类型', trigger: 'change' }]"
        >
          <el-select
            v-model="action.actionType"
            placeholder="选择操作类型"
            style="width: 180px; margin-right: 10px"
          >
            <el-option value="assignment" label="赋值" />
          </el-select>
        </el-form-item>

        <el-form-item
          :prop="`${prop}.${index}.leftValue`"
          :rules="[{ required: true, message: '请选择变量', trigger: 'change' }]"
        >
          <el-select
            v-model="action.leftValue"
            placeholder="选择变量"
            style="width: 180px; margin-right: 10px"
          >
            <el-option
              v-for="opt in variableOptions"
              :key="opt.value"
              :label="opt.label"
              :value="opt.value"
            />
          </el-select>
        </el-form-item>

        <span class="operator">=</span>

        <el-form-item
          :prop="`${prop}.${index}.rightValue`"
          :rules="[{ required: true, message: '请输入值', trigger: 'blur' }]"
        >
          <el-input
            v-model="action.rightValue"
            placeholder="输入值"
            style="width: 180px; margin-right: 10px"
          />
        </el-form-item>

        <el-button
          type="danger"
          link
          @click="removeAction(index)"
          icon="Delete"
        />
      </div>
    </div>
  </el-form-item>
</template>

<script setup>
import { computed } from 'vue'

const props = defineProps({
  modelValue: {
    type: Array,
    required: true,
    default: () => []
  },
  prop: {
    type: String,
    required: true
  },
  label: {
    type: String,
    default: ''
  },
  variableOptions: {
    type: Array,
    default: () => []
  },
  totalCount: {
    type: Number,
    default: 0
  },
  otherCount: {
    type: Number,
    default: 0
  },
  emptyTip: {
    type: String,
    default: '请添加操作'
  },
  required: {
    type: Boolean,
    default: false
  }
})

const emit = defineEmits(['update:modelValue'])

const disableAdd = computed(() => {
  return props.totalCount >= 20
})


const showEmptyTip = computed(() => {
  return props.required && props.modelValue.length === 0
})

const addAction = () => {
  const newActions = [...props.modelValue, {
    actionType: '',
    leftValue: '',
    rightValue: ''
  }]
  emit('update:modelValue', newActions)
}

const removeAction = (index) => {
  const newActions = [...props.modelValue]
  newActions.splice(index, 1)
  emit('update:modelValue', newActions)
}
</script>

<style scoped>
.action-container {
  border: 1px solid #dcdfe6;
  padding: 12px;
  border-radius: 4px;
  background-color: #f5f7fa;
}
.action-row {
  display: flex;
  align-items: center;
  margin-top: 10px;
}
.operator {
  margin: 0 10px;
  font-weight: bold;
  color: #606266;
}
.empty-tip {
  color: #f56c6c;
  font-size: 12px;
  margin: 5px 0;
}
</style>

效果:

 

 

 

posted on 2025-07-13 23:16  芹菜是一根葱  阅读(9)  评论(0)    收藏  举报