|  | @@ -0,0 +1,688 @@
 | 
	
		
			
				|  |  | +<template>
 | 
	
		
			
				|  |  | +  <div class="form-builder">
 | 
	
		
			
				|  |  | +    <div>
 | 
	
		
			
				|  |  | +      <h2 class="template-title">{{ templateName }}</h2>
 | 
	
		
			
				|  |  | +    </div>
 | 
	
		
			
				|  |  | +    <el-row :gutter="20" class="main-container">
 | 
	
		
			
				|  |  | +      <el-col :span="5" class="field-selector">
 | 
	
		
			
				|  |  | +        <div class="panel-content">
 | 
	
		
			
				|  |  | +          <h3 class="panel-title">选择组件</h3>
 | 
	
		
			
				|  |  | +          <div class="field-list">
 | 
	
		
			
				|  |  | +            <div
 | 
	
		
			
				|  |  | +              v-for="(field, index) in availableFields"
 | 
	
		
			
				|  |  | +              :key="field.componentId"
 | 
	
		
			
				|  |  | +              class="field-item"
 | 
	
		
			
				|  |  | +              @click="addFieldToForm(field, index)"
 | 
	
		
			
				|  |  | +            >
 | 
	
		
			
				|  |  | +              <el-button size="small">{{ field.label }}</el-button>
 | 
	
		
			
				|  |  | +            </div>
 | 
	
		
			
				|  |  | +          </div>
 | 
	
		
			
				|  |  | +        </div>
 | 
	
		
			
				|  |  | +      </el-col>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      <el-col :span="14" class="form-preview">
 | 
	
		
			
				|  |  | +        <template v-if="formFields.length === 0">
 | 
	
		
			
				|  |  | +          <div class="empty-tip">请选择添加左侧样式</div>
 | 
	
		
			
				|  |  | +        </template>
 | 
	
		
			
				|  |  | +        <draggable
 | 
	
		
			
				|  |  | +          v-model="formFields"
 | 
	
		
			
				|  |  | +          200 animation:
 | 
	
		
			
				|  |  | +          group="form-fields"
 | 
	
		
			
				|  |  | +          @end="handleDragEnd"
 | 
	
		
			
				|  |  | +        >
 | 
	
		
			
				|  |  | +          <el-scrollbar style="height: 500px; width: 100%;">
 | 
	
		
			
				|  |  | +            <div
 | 
	
		
			
				|  |  | +              v-for="(field, index) in formFields"
 | 
	
		
			
				|  |  | +              :key="index"
 | 
	
		
			
				|  |  | +              :class="{ 'form-field-active': activeFieldIndex === index }"
 | 
	
		
			
				|  |  | +              class="form-field-item"
 | 
	
		
			
				|  |  | +              @click="setActiveField(index)"
 | 
	
		
			
				|  |  | +            >
 | 
	
		
			
				|  |  | +              <div class="field-header">
 | 
	
		
			
				|  |  | +                <el-row align="middle" type="flex">
 | 
	
		
			
				|  |  | +                  <el-col :span="23" class="field-label">
 | 
	
		
			
				|  |  | +                    <span v-if="field.required" class="required-mark">*</span>
 | 
	
		
			
				|  |  | +                    {{ field.label }}
 | 
	
		
			
				|  |  | +                  </el-col>
 | 
	
		
			
				|  |  | +                  <el-col :span="1" class="field-operation">
 | 
	
		
			
				|  |  | +                    <i
 | 
	
		
			
				|  |  | +                      v-if="activeFieldIndex === index"
 | 
	
		
			
				|  |  | +                      class="el-icon-delete"
 | 
	
		
			
				|  |  | +                      @click.stop="removeFormField(index)"
 | 
	
		
			
				|  |  | +                    ></i>
 | 
	
		
			
				|  |  | +                  </el-col>
 | 
	
		
			
				|  |  | +                </el-row>
 | 
	
		
			
				|  |  | +              </div>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +              <!-- 字段输入组件 -->
 | 
	
		
			
				|  |  | +              <div class="field-input">
 | 
	
		
			
				|  |  | +                <!-- 单选框 -->
 | 
	
		
			
				|  |  | +                <template v-if="field.type === 'radio'">
 | 
	
		
			
				|  |  | +                  <el-radio-group v-model="field.value">
 | 
	
		
			
				|  |  | +                    <el-radio
 | 
	
		
			
				|  |  | +                      v-for="(option, optIdx) in field.options"
 | 
	
		
			
				|  |  | +                      :key="optIdx"
 | 
	
		
			
				|  |  | +                      :label="option"
 | 
	
		
			
				|  |  | +                      style="width: 90px"
 | 
	
		
			
				|  |  | +                    >
 | 
	
		
			
				|  |  | +                      {{ option }}
 | 
	
		
			
				|  |  | +                    </el-radio>
 | 
	
		
			
				|  |  | +                  </el-radio-group>
 | 
	
		
			
				|  |  | +                </template>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                <!-- 下拉选择框 -->
 | 
	
		
			
				|  |  | +                <template v-else-if="field.type === 'select'">
 | 
	
		
			
				|  |  | +                  <el-select
 | 
	
		
			
				|  |  | +                    v-if="!field.multiple"
 | 
	
		
			
				|  |  | +                    v-model="field.value"
 | 
	
		
			
				|  |  | +                    :multiple="field.multiple"
 | 
	
		
			
				|  |  | +                    :placeholder="`请选择${field.label}`"
 | 
	
		
			
				|  |  | +                    clearable
 | 
	
		
			
				|  |  | +                    size="small"
 | 
	
		
			
				|  |  | +                    style="width: 100%"
 | 
	
		
			
				|  |  | +                  >
 | 
	
		
			
				|  |  | +                    <el-option
 | 
	
		
			
				|  |  | +                      v-for="(option, optIdx) in field.options"
 | 
	
		
			
				|  |  | +                      :key="optIdx"
 | 
	
		
			
				|  |  | +                      :label="option"
 | 
	
		
			
				|  |  | +                      :value="optIdx"
 | 
	
		
			
				|  |  | +                    ></el-option>
 | 
	
		
			
				|  |  | +                  </el-select>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                  <el-select
 | 
	
		
			
				|  |  | +                    v-if="field.multiple"
 | 
	
		
			
				|  |  | +                    v-model="field.multiples"
 | 
	
		
			
				|  |  | +                    :multiple="field.multiple"
 | 
	
		
			
				|  |  | +                    :placeholder="`请选择${field.label}`"
 | 
	
		
			
				|  |  | +                    clearable
 | 
	
		
			
				|  |  | +                    size="small"
 | 
	
		
			
				|  |  | +                    style="width: 100%"
 | 
	
		
			
				|  |  | +                  >
 | 
	
		
			
				|  |  | +                    <el-option
 | 
	
		
			
				|  |  | +                      v-for="(option, optIdx) in field.options"
 | 
	
		
			
				|  |  | +                      :key="optIdx"
 | 
	
		
			
				|  |  | +                      :label="option"
 | 
	
		
			
				|  |  | +                      :value="optIdx"
 | 
	
		
			
				|  |  | +                    ></el-option>
 | 
	
		
			
				|  |  | +                  </el-select>
 | 
	
		
			
				|  |  | +                </template>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                <!-- 文本输入框 -->
 | 
	
		
			
				|  |  | +                <template v-else-if="field.type === 'text'">
 | 
	
		
			
				|  |  | +                  <el-input
 | 
	
		
			
				|  |  | +                    v-model="field.value"
 | 
	
		
			
				|  |  | +                    :placeholder="field.placeholder || `请输入${field.label}`"
 | 
	
		
			
				|  |  | +                    clearable
 | 
	
		
			
				|  |  | +                    size="small"
 | 
	
		
			
				|  |  | +                  ></el-input>
 | 
	
		
			
				|  |  | +                </template>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                <!-- 复选框 -->
 | 
	
		
			
				|  |  | +                <template v-else-if="field.type === 'checkbox'">
 | 
	
		
			
				|  |  | +                  <div class="option-container">
 | 
	
		
			
				|  |  | +                    <el-checkbox-group v-model="field.multiples">
 | 
	
		
			
				|  |  | +                      <el-checkbox
 | 
	
		
			
				|  |  | +                        v-for="(option, optIdx) in field.options"
 | 
	
		
			
				|  |  | +                        :key="optIdx"
 | 
	
		
			
				|  |  | +                        :label="optIdx"
 | 
	
		
			
				|  |  | +                        style="width: 90px"
 | 
	
		
			
				|  |  | +                      >{{ option }}
 | 
	
		
			
				|  |  | +                      </el-checkbox>
 | 
	
		
			
				|  |  | +                    </el-checkbox-group>
 | 
	
		
			
				|  |  | +                  </div>
 | 
	
		
			
				|  |  | +                </template>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +              </div>
 | 
	
		
			
				|  |  | +            </div>
 | 
	
		
			
				|  |  | +          </el-scrollbar>
 | 
	
		
			
				|  |  | +        </draggable>
 | 
	
		
			
				|  |  | +      </el-col>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      <el-col :span="5" class="field-configurator">
 | 
	
		
			
				|  |  | +        <template v-if="formFields.length > 0">
 | 
	
		
			
				|  |  | +          <el-form class="config-form">
 | 
	
		
			
				|  |  | +            <!-- 字段名称配置 -->
 | 
	
		
			
				|  |  | +            <el-form-item label="字段名称">
 | 
	
		
			
				|  |  | +              <el-input
 | 
	
		
			
				|  |  | +                v-model="formFields[activeFieldIndex].label"
 | 
	
		
			
				|  |  | +                clearable
 | 
	
		
			
				|  |  | +                size="small"
 | 
	
		
			
				|  |  | +              ></el-input>
 | 
	
		
			
				|  |  | +            </el-form-item>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            <!--            <template v-if="formFields[activeFieldIndex].type !== 'radio' && formFields[activeFieldIndex].type !== 'checkbox'">-->
 | 
	
		
			
				|  |  | +            <!--              <el-form-item label="默认值">-->
 | 
	
		
			
				|  |  | +            <!--                <el-select-->
 | 
	
		
			
				|  |  | +            <!--                  v-model="defaultValueMode"-->
 | 
	
		
			
				|  |  | +            <!--                  size="small"-->
 | 
	
		
			
				|  |  | +            <!--                  style="width: 100%; margin-bottom: 8px"-->
 | 
	
		
			
				|  |  | +            <!--                >-->
 | 
	
		
			
				|  |  | +            <!--                  <el-option-->
 | 
	
		
			
				|  |  | +            <!--                    v-for="mode in valueModes"-->
 | 
	
		
			
				|  |  | +            <!--                    :key="mode.value"-->
 | 
	
		
			
				|  |  | +            <!--                    :label="mode.label"-->
 | 
	
		
			
				|  |  | +            <!--                    :value="mode.value"-->
 | 
	
		
			
				|  |  | +            <!--                  ></el-option>-->
 | 
	
		
			
				|  |  | +            <!--                </el-select>-->
 | 
	
		
			
				|  |  | +            <!--                <el-input-->
 | 
	
		
			
				|  |  | +            <!--                  :v-model="formFields[activeFieldIndex].value"-->
 | 
	
		
			
				|  |  | +            <!--                  clearable-->
 | 
	
		
			
				|  |  | +            <!--                  placeholder="请输入默认值"-->
 | 
	
		
			
				|  |  | +            <!--                  size="small"-->
 | 
	
		
			
				|  |  | +            <!--                ></el-input>-->
 | 
	
		
			
				|  |  | +            <!--              </el-form-item>-->
 | 
	
		
			
				|  |  | +            <!--            </template>-->
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            <template v-if="['radio', 'select','checkbox'].includes(formFields[activeFieldIndex].type)">
 | 
	
		
			
				|  |  | +              <el-form-item label="选项配置">
 | 
	
		
			
				|  |  | +                <draggable
 | 
	
		
			
				|  |  | +                  v-model="formFields[activeFieldIndex].options"
 | 
	
		
			
				|  |  | +                  animation:50
 | 
	
		
			
				|  |  | +                  group="options"
 | 
	
		
			
				|  |  | +                  @end="handleOptionDragEnd"
 | 
	
		
			
				|  |  | +                >
 | 
	
		
			
				|  |  | +                  <el-row
 | 
	
		
			
				|  |  | +                    v-for="(option, idx) in formFields[activeFieldIndex].options"
 | 
	
		
			
				|  |  | +                    :key="idx"
 | 
	
		
			
				|  |  | +                    class="option-item"
 | 
	
		
			
				|  |  | +                  >
 | 
	
		
			
				|  |  | +                    <el-col :span="2" class="option-drag">
 | 
	
		
			
				|  |  | +                      <span class="el-icon-s-operation"></span>
 | 
	
		
			
				|  |  | +                    </el-col>
 | 
	
		
			
				|  |  | +                    <el-col :span="18">
 | 
	
		
			
				|  |  | +                      <el-input
 | 
	
		
			
				|  |  | +                        v-model="formFields[activeFieldIndex].options[idx]"
 | 
	
		
			
				|  |  | +                        clearable
 | 
	
		
			
				|  |  | +                        size="small"
 | 
	
		
			
				|  |  | +                      ></el-input>
 | 
	
		
			
				|  |  | +                    </el-col>
 | 
	
		
			
				|  |  | +                    <el-col :span="2" class="option-delete">
 | 
	
		
			
				|  |  | +                      <i
 | 
	
		
			
				|  |  | +                        class="el-icon-delete"
 | 
	
		
			
				|  |  | +                        @click.stop="removeOption(idx)"
 | 
	
		
			
				|  |  | +                      ></i>
 | 
	
		
			
				|  |  | +                    </el-col>
 | 
	
		
			
				|  |  | +                  </el-row>
 | 
	
		
			
				|  |  | +                </draggable>
 | 
	
		
			
				|  |  | +                <el-button
 | 
	
		
			
				|  |  | +                  size="small"
 | 
	
		
			
				|  |  | +                  style="width: 100%; margin-top: 8px"
 | 
	
		
			
				|  |  | +                  @click="addNewOption"
 | 
	
		
			
				|  |  | +                >
 | 
	
		
			
				|  |  | +                  <span class="el-icon-plus"></span> 添加选项
 | 
	
		
			
				|  |  | +                </el-button>
 | 
	
		
			
				|  |  | +              </el-form-item>
 | 
	
		
			
				|  |  | +            </template>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            <!-- 通用配置:是否必填 -->
 | 
	
		
			
				|  |  | +            <el-form-item class="required-config" label="是否必填">
 | 
	
		
			
				|  |  | +              <el-switch v-model="formFields[activeFieldIndex].required"></el-switch>
 | 
	
		
			
				|  |  | +            </el-form-item>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            <el-form-item v-if="'select' === formFields[activeFieldIndex].type" class="required-config"
 | 
	
		
			
				|  |  | +                          label="是否多选"
 | 
	
		
			
				|  |  | +            >
 | 
	
		
			
				|  |  | +              <el-switch v-model="formFields[activeFieldIndex].multiple"></el-switch>
 | 
	
		
			
				|  |  | +            </el-form-item>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            <!-- 文本字段:长度限制 -->
 | 
	
		
			
				|  |  | +            <el-form-item
 | 
	
		
			
				|  |  | +              v-if="formFields[activeFieldIndex].type === 'text' && formFields[activeFieldIndex].required"
 | 
	
		
			
				|  |  | +              class="length-limit"
 | 
	
		
			
				|  |  | +              label="长度限制"
 | 
	
		
			
				|  |  | +            >
 | 
	
		
			
				|  |  | +              <el-input
 | 
	
		
			
				|  |  | +                v-model.number="formFields[activeFieldIndex].minLength"
 | 
	
		
			
				|  |  | +                autocomplete="off"
 | 
	
		
			
				|  |  | +                clearable
 | 
	
		
			
				|  |  | +                placeholder="最小"
 | 
	
		
			
				|  |  | +                size="small"
 | 
	
		
			
				|  |  | +                style="width: 40%; display: inline-block"
 | 
	
		
			
				|  |  | +              ></el-input>
 | 
	
		
			
				|  |  | +              <span style="margin: 0 4px">-</span>
 | 
	
		
			
				|  |  | +              <el-input
 | 
	
		
			
				|  |  | +                v-model.number="formFields[activeFieldIndex].maxLength"
 | 
	
		
			
				|  |  | +                autocomplete="off"
 | 
	
		
			
				|  |  | +                clearable
 | 
	
		
			
				|  |  | +                placeholder="最大"
 | 
	
		
			
				|  |  | +                size="small"
 | 
	
		
			
				|  |  | +                style="width: 40%; display: inline-block"
 | 
	
		
			
				|  |  | +              ></el-input>
 | 
	
		
			
				|  |  | +            </el-form-item>
 | 
	
		
			
				|  |  | +          </el-form>
 | 
	
		
			
				|  |  | +        </template>
 | 
	
		
			
				|  |  | +      </el-col>
 | 
	
		
			
				|  |  | +    </el-row>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    <el-row class="action-bar">
 | 
	
		
			
				|  |  | +      <el-button size="small" @click="resetForm">重置</el-button>
 | 
	
		
			
				|  |  | +      <el-button size="small" type="primary" @click="submitForm">保存配置</el-button>
 | 
	
		
			
				|  |  | +    </el-row>
 | 
	
		
			
				|  |  | +  </div>
 | 
	
		
			
				|  |  | +</template>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +<script>
 | 
	
		
			
				|  |  | +import draggable from 'vuedraggable'
 | 
	
		
			
				|  |  | +import { getTemplateField, saveTemplate } from '@/api/his/physicalReportTemplateField'
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +export default {
 | 
	
		
			
				|  |  | +  props: {
 | 
	
		
			
				|  |  | +    templateName: {
 | 
	
		
			
				|  |  | +      type: String,
 | 
	
		
			
				|  |  | +      default: '体检报告',
 | 
	
		
			
				|  |  | +      required: true
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  },
 | 
	
		
			
				|  |  | +  components: { draggable },
 | 
	
		
			
				|  |  | +  data() {
 | 
	
		
			
				|  |  | +    return {
 | 
	
		
			
				|  |  | +      templateId: null,
 | 
	
		
			
				|  |  | +      availableFields: [
 | 
	
		
			
				|  |  | +        { componentId: '1', label: '输入框', type: 'text' },
 | 
	
		
			
				|  |  | +        { componentId: '2', label: '单选按钮', type: 'radio' },
 | 
	
		
			
				|  |  | +        { componentId: '3', label: '下拉选项', type: 'select' },
 | 
	
		
			
				|  |  | +        { componentId: '4', label: '复选框', type: 'checkbox' }
 | 
	
		
			
				|  |  | +      ],
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      // 中间表单已添加的字段列表
 | 
	
		
			
				|  |  | +      formFields: [],
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      // 当前激活的字段索引
 | 
	
		
			
				|  |  | +      activeFieldIndex: 0,
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      // 右侧配置:默认值模式
 | 
	
		
			
				|  |  | +      defaultValueMode: 1,
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      // 临时存储:默认值模式(用于非单选/下拉字段)
 | 
	
		
			
				|  |  | +      valueModes: [{ label: '自定义输入', value: 1 }]
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  },
 | 
	
		
			
				|  |  | +  created() {
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  },
 | 
	
		
			
				|  |  | +  computed: {
 | 
	
		
			
				|  |  | +    // 当前激活字段的类型
 | 
	
		
			
				|  |  | +    currentFieldType() {
 | 
	
		
			
				|  |  | +      return this.formFields[this.activeFieldIndex]?.type
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  },
 | 
	
		
			
				|  |  | +  methods: {
 | 
	
		
			
				|  |  | +    // 添加字段到表单
 | 
	
		
			
				|  |  | +    addFieldToForm(field, index) {
 | 
	
		
			
				|  |  | +      // 检查字段是否已添加(避免重复)
 | 
	
		
			
				|  |  | +      // const isExist = this.formFields.some(item => item.id === field.id)
 | 
	
		
			
				|  |  | +      // if (isExist) return
 | 
	
		
			
				|  |  | +      // 根据字段类型初始化配置
 | 
	
		
			
				|  |  | +      const fieldConfig = {
 | 
	
		
			
				|  |  | +        componentId: field.componentId,
 | 
	
		
			
				|  |  | +        label: field.label,
 | 
	
		
			
				|  |  | +        type: field.type,
 | 
	
		
			
				|  |  | +        required: false,
 | 
	
		
			
				|  |  | +        value: '',
 | 
	
		
			
				|  |  | +        multiple: false,
 | 
	
		
			
				|  |  | +        multiples: [],
 | 
	
		
			
				|  |  | +        placeholder: ''
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      // 文本字段
 | 
	
		
			
				|  |  | +      if (field.type === 'text') {
 | 
	
		
			
				|  |  | +        fieldConfig.minLength = null
 | 
	
		
			
				|  |  | +        fieldConfig.maxLength = null
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      // 单选/下拉字段
 | 
	
		
			
				|  |  | +      if (['radio', 'select', 'checkbox'].includes(field.type)) {
 | 
	
		
			
				|  |  | +        fieldConfig.options = ['选项1', '选项2']
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      this.formFields.push(fieldConfig)
 | 
	
		
			
				|  |  | +      this.activeFieldIndex = this.formFields.length - 1
 | 
	
		
			
				|  |  | +    },
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // 删除表单中的字段
 | 
	
		
			
				|  |  | +    removeFormField(index) {
 | 
	
		
			
				|  |  | +      this.formFields.splice(index, 1)
 | 
	
		
			
				|  |  | +      if (this.activeFieldIndex === index) {
 | 
	
		
			
				|  |  | +        this.activeFieldIndex = Math.min(index, this.formFields.length - 1)
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +    },
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // 添加新选项
 | 
	
		
			
				|  |  | +    addNewOption() {
 | 
	
		
			
				|  |  | +      const currentField = this.formFields[this.activeFieldIndex]
 | 
	
		
			
				|  |  | +      const optionCount = currentField.options.length + 1
 | 
	
		
			
				|  |  | +      currentField.options.push(`选项${optionCount}`)
 | 
	
		
			
				|  |  | +    },
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // 删除选项
 | 
	
		
			
				|  |  | +    removeOption(index) {
 | 
	
		
			
				|  |  | +      this.formFields[this.activeFieldIndex].options.splice(index, 1)
 | 
	
		
			
				|  |  | +    },
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // 设置当前激活的字段
 | 
	
		
			
				|  |  | +    setActiveField(index) {
 | 
	
		
			
				|  |  | +      this.activeFieldIndex = index
 | 
	
		
			
				|  |  | +    },
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // 拖拽结束事件
 | 
	
		
			
				|  |  | +    handleDragEnd() {
 | 
	
		
			
				|  |  | +      console.log('字段排序已更新----')
 | 
	
		
			
				|  |  | +    },
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // 拖拽结束事件
 | 
	
		
			
				|  |  | +    handleOptionDragEnd() {
 | 
	
		
			
				|  |  | +      console.log('选项排序已更新----')
 | 
	
		
			
				|  |  | +    },
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // 表单验证
 | 
	
		
			
				|  |  | +    validateForm() {
 | 
	
		
			
				|  |  | +      if (this.formFields.length === 0) {
 | 
	
		
			
				|  |  | +        this.$message.error('请至少添加一个字段')
 | 
	
		
			
				|  |  | +        return false
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      for (let i = 0; i < this.formFields.length; i++) {
 | 
	
		
			
				|  |  | +        const field = this.formFields[i]
 | 
	
		
			
				|  |  | +        if (!field.label.trim()) {
 | 
	
		
			
				|  |  | +          this.activeFieldIndex = i
 | 
	
		
			
				|  |  | +          this.$message.error('字段名称不能为空')
 | 
	
		
			
				|  |  | +          return false
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // // 验证必填字段
 | 
	
		
			
				|  |  | +        // if (field.required && field.type !== 'checkbox' && !field.multiple && !field.value && field.value !== 0 || field.required && field.type === 'checkbox' && field.options.length === 0) {
 | 
	
		
			
				|  |  | +        //   this.activeFieldIndex = i
 | 
	
		
			
				|  |  | +        //   this.$message.error(`“${field.label}”为必填项,请补充`)
 | 
	
		
			
				|  |  | +        //   return false
 | 
	
		
			
				|  |  | +        // }
 | 
	
		
			
				|  |  | +        //
 | 
	
		
			
				|  |  | +        // // 验证文本字段长度限制
 | 
	
		
			
				|  |  | +        // if (field.type === 'text' && field.required) {
 | 
	
		
			
				|  |  | +        //   const valueLength = (field.value || '').length
 | 
	
		
			
				|  |  | +        //   if (field.minLength !== null && valueLength < field.minLength) {
 | 
	
		
			
				|  |  | +        //     this.$message.error(`“${field.label}”长度不能小于${field.minLength}个字符`)
 | 
	
		
			
				|  |  | +        //     return false
 | 
	
		
			
				|  |  | +        //   }
 | 
	
		
			
				|  |  | +        //   if (field.maxLength !== null && valueLength > field.maxLength) {
 | 
	
		
			
				|  |  | +        //     this.$message.error(`“${field.label}”长度不能大于${field.maxLength}个字符`)
 | 
	
		
			
				|  |  | +        //     return false
 | 
	
		
			
				|  |  | +        //   }
 | 
	
		
			
				|  |  | +        // }
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      return true
 | 
	
		
			
				|  |  | +    },
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // 提交表单配置
 | 
	
		
			
				|  |  | +    submitForm() {
 | 
	
		
			
				|  |  | +      if (!this.validateForm()) return
 | 
	
		
			
				|  |  | +      // 数据过滤
 | 
	
		
			
				|  |  | +      const formData = this.formFields.map(field => {
 | 
	
		
			
				|  |  | +        const multiple = field.multiple ? 1 : 0
 | 
	
		
			
				|  |  | +        const required = field.required ? 1 : 0
 | 
	
		
			
				|  |  | +        const {
 | 
	
		
			
				|  |  | +          componentId,
 | 
	
		
			
				|  |  | +          label,
 | 
	
		
			
				|  |  | +          type,
 | 
	
		
			
				|  |  | +          value,
 | 
	
		
			
				|  |  | +          options,
 | 
	
		
			
				|  |  | +          maxLength,
 | 
	
		
			
				|  |  | +          minLength
 | 
	
		
			
				|  |  | +        } = field
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        const result = {
 | 
	
		
			
				|  |  | +          componentId,
 | 
	
		
			
				|  |  | +          label,
 | 
	
		
			
				|  |  | +          type,
 | 
	
		
			
				|  |  | +          required,
 | 
	
		
			
				|  |  | +          value,
 | 
	
		
			
				|  |  | +          maxLength,
 | 
	
		
			
				|  |  | +          minLength,
 | 
	
		
			
				|  |  | +          multiple
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        if (options) {
 | 
	
		
			
				|  |  | +          result.options = options.join(',')
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        return result
 | 
	
		
			
				|  |  | +      })
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      saveTemplate({ templateId: this.templateId, templateFieldList: formData }).then(response => {
 | 
	
		
			
				|  |  | +        if (response.code === 200) {
 | 
	
		
			
				|  |  | +          this.$message.success('保存成功!')
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        this.getTemplateField(this.templateId)
 | 
	
		
			
				|  |  | +      })
 | 
	
		
			
				|  |  | +    },
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // 重置表单
 | 
	
		
			
				|  |  | +    resetForm() {
 | 
	
		
			
				|  |  | +      this.formFields = []
 | 
	
		
			
				|  |  | +      this.activeFieldIndex = 0
 | 
	
		
			
				|  |  | +      this.$message.info('已重置表单配置')
 | 
	
		
			
				|  |  | +    },
 | 
	
		
			
				|  |  | +    /**
 | 
	
		
			
				|  |  | +     * 获取自定义数据列表
 | 
	
		
			
				|  |  | +     * **/
 | 
	
		
			
				|  |  | +    getTemplateField(templateId) {
 | 
	
		
			
				|  |  | +      this.templateId = templateId
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      getTemplateField(templateId).then(response => {
 | 
	
		
			
				|  |  | +        if (response.data.length > 0) {
 | 
	
		
			
				|  |  | +          //处理数据处理
 | 
	
		
			
				|  |  | +          this.formFields = response.data.map(item => {
 | 
	
		
			
				|  |  | +            const multiple = item.multiple === 1
 | 
	
		
			
				|  |  | +            const required = item.required === 1
 | 
	
		
			
				|  |  | +            const multiples = []
 | 
	
		
			
				|  |  | +            const {
 | 
	
		
			
				|  |  | +              componentId,
 | 
	
		
			
				|  |  | +              label,
 | 
	
		
			
				|  |  | +              type,
 | 
	
		
			
				|  |  | +              value,
 | 
	
		
			
				|  |  | +              options,
 | 
	
		
			
				|  |  | +              maxLength,
 | 
	
		
			
				|  |  | +              minLength
 | 
	
		
			
				|  |  | +            } = item
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            const result = {
 | 
	
		
			
				|  |  | +              componentId,
 | 
	
		
			
				|  |  | +              label,
 | 
	
		
			
				|  |  | +              type,
 | 
	
		
			
				|  |  | +              required,
 | 
	
		
			
				|  |  | +              value,
 | 
	
		
			
				|  |  | +              maxLength,
 | 
	
		
			
				|  |  | +              minLength,
 | 
	
		
			
				|  |  | +              multiple,
 | 
	
		
			
				|  |  | +              multiples
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            if (options) {
 | 
	
		
			
				|  |  | +              result.options = options.split(',').map(item => item.trim())
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            return result
 | 
	
		
			
				|  |  | +          })
 | 
	
		
			
				|  |  | +          this.activeFieldIndex = this.formFields.length - 1
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +      })
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +</script>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +<style scoped>
 | 
	
		
			
				|  |  | +.form-builder {
 | 
	
		
			
				|  |  | +  padding: 15px;
 | 
	
		
			
				|  |  | +  background-color: #f5f7fa;
 | 
	
		
			
				|  |  | +  min-height: calc(94vh - 30px);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +.main-container {
 | 
	
		
			
				|  |  | +  margin-bottom: 20px;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +.field-selector {
 | 
	
		
			
				|  |  | +  background-color: #fff;
 | 
	
		
			
				|  |  | +  border-radius: 6px;
 | 
	
		
			
				|  |  | +  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
 | 
	
		
			
				|  |  | +  padding: 15px !important;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +.panel-title {
 | 
	
		
			
				|  |  | +  font-size: 15px;
 | 
	
		
			
				|  |  | +  color: #1f2329;
 | 
	
		
			
				|  |  | +  margin: 0 0 15px;
 | 
	
		
			
				|  |  | +  padding-left: 4px;
 | 
	
		
			
				|  |  | +  font-weight: 500;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +.field-list {
 | 
	
		
			
				|  |  | +  display: flex;
 | 
	
		
			
				|  |  | +  flex-wrap: wrap;
 | 
	
		
			
				|  |  | +  gap: 10px;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +.field-item {
 | 
	
		
			
				|  |  | +  width: 100px;
 | 
	
		
			
				|  |  | +  box-sizing: border-box;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +.field-item .el-button {
 | 
	
		
			
				|  |  | +  width: 100%;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/* 中间表单预览区 */
 | 
	
		
			
				|  |  | +.form-preview {
 | 
	
		
			
				|  |  | +  padding: 0 10px !important;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +.empty-tip {
 | 
	
		
			
				|  |  | +  height: 60px;
 | 
	
		
			
				|  |  | +  line-height: 60px;
 | 
	
		
			
				|  |  | +  text-align: center;
 | 
	
		
			
				|  |  | +  border: 1px dashed #dcdfe6;
 | 
	
		
			
				|  |  | +  color: #8c8c8c;
 | 
	
		
			
				|  |  | +  border-radius: 6px;
 | 
	
		
			
				|  |  | +  margin-top: 10px;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +.form-field-item {
 | 
	
		
			
				|  |  | +  background-color: #fff;
 | 
	
		
			
				|  |  | +  border: 1px solid #e5e6eb;
 | 
	
		
			
				|  |  | +  border-radius: 6px;
 | 
	
		
			
				|  |  | +  padding: 12px 15px;
 | 
	
		
			
				|  |  | +  margin-bottom: 12px;
 | 
	
		
			
				|  |  | +  transition: all 0.2s;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +.form-field-item:hover {
 | 
	
		
			
				|  |  | +  border-color: #c0c4cc;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +.form-field-active {
 | 
	
		
			
				|  |  | +  border-color: #409eff;
 | 
	
		
			
				|  |  | +  background-color: #f0f7ff;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +.field-header {
 | 
	
		
			
				|  |  | +  margin-bottom: 10px;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +.field-label {
 | 
	
		
			
				|  |  | +  font-size: 14px;
 | 
	
		
			
				|  |  | +  color: #1f2329;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +.required-mark {
 | 
	
		
			
				|  |  | +  color: #ff4d4f;
 | 
	
		
			
				|  |  | +  margin-right: 4px;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +.field-operation {
 | 
	
		
			
				|  |  | +  color: #8c8c8c;
 | 
	
		
			
				|  |  | +  cursor: pointer;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +.field-operation:hover {
 | 
	
		
			
				|  |  | +  color: #ff4d4f;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +.field-configurator {
 | 
	
		
			
				|  |  | +  background-color: #fff;
 | 
	
		
			
				|  |  | +  border-radius: 6px;
 | 
	
		
			
				|  |  | +  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
 | 
	
		
			
				|  |  | +  padding: 15px !important;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +.config-form .el-form-item {
 | 
	
		
			
				|  |  | +  margin-bottom: 12px;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +.config-form .el-form-item__label {
 | 
	
		
			
				|  |  | +  font-size: 13px;
 | 
	
		
			
				|  |  | +  color: #4e5969;
 | 
	
		
			
				|  |  | +  padding: 0 0 6px;
 | 
	
		
			
				|  |  | +  line-height: 1;
 | 
	
		
			
				|  |  | +  width: 100%;
 | 
	
		
			
				|  |  | +  text-align: left;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +.option-item {
 | 
	
		
			
				|  |  | +  display: flex;
 | 
	
		
			
				|  |  | +  align-items: center;
 | 
	
		
			
				|  |  | +  width: 100%;
 | 
	
		
			
				|  |  | +  margin: 0 !important;
 | 
	
		
			
				|  |  | +  padding: 4px 0;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +.option-drag {
 | 
	
		
			
				|  |  | +  color: #c9cdD4;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +.option-delete {
 | 
	
		
			
				|  |  | +  color: #8c8c8c;
 | 
	
		
			
				|  |  | +  cursor: pointer;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +.option-delete:hover {
 | 
	
		
			
				|  |  | +  color: #ff4d4f;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +.action-bar {
 | 
	
		
			
				|  |  | +  text-align: center;
 | 
	
		
			
				|  |  | +  padding: 10px 0;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +.action-bar .el-button {
 | 
	
		
			
				|  |  | +  margin: 0 5px;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +.empty-tip {
 | 
	
		
			
				|  |  | +  height: 60px;
 | 
	
		
			
				|  |  | +  line-height: 60px;
 | 
	
		
			
				|  |  | +  text-align: center;
 | 
	
		
			
				|  |  | +  border: 1px dashed #dcdfe6;
 | 
	
		
			
				|  |  | +  color: #8c8c8c;
 | 
	
		
			
				|  |  | +  border-radius: 6px;
 | 
	
		
			
				|  |  | +  margin-top: 10px;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +@media (max-width: 1200px) {
 | 
	
		
			
				|  |  | +  .field-selector,
 | 
	
		
			
				|  |  | +  .field-configurator {
 | 
	
		
			
				|  |  | +    padding: 10px !important;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +.option-container {
 | 
	
		
			
				|  |  | +  display: flex;
 | 
	
		
			
				|  |  | +  flex-wrap: wrap;
 | 
	
		
			
				|  |  | +  align-items: flex-start;
 | 
	
		
			
				|  |  | +  gap: 16px;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +.template-title {
 | 
	
		
			
				|  |  | +  text-align: center;
 | 
	
		
			
				|  |  | +  margin: 0;
 | 
	
		
			
				|  |  | +  line-height: 50px;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +</style>
 |