Explorar el Código

体检报告模板

yjwang hace 2 días
padre
commit
68fab3aefa

+ 53 - 0
src/api/his/physicalReportTemplate.js

@@ -0,0 +1,53 @@
+import request from '@/utils/request'
+
+// 查询体检报告模板列表
+export function listFSPhysicalReportTemplate(query) {
+  return request({
+    url: '/his/physicalReportTemplate/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询体检报告模板详细
+export function getFSPhysicalReportTemplate(id) {
+  return request({
+    url: '/his/physicalReportTemplate/' + id,
+    method: 'get'
+  })
+}
+
+// 新增体检报告模板
+export function addFSPhysicalReportTemplate(data) {
+  return request({
+    url: '/his/physicalReportTemplate',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改体检报告模板
+export function updateFSPhysicalReportTemplate(data) {
+  return request({
+    url: '/his/physicalReportTemplate',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除体检报告模板
+export function delFSPhysicalReportTemplate(id) {
+  return request({
+    url: '/his/physicalReportTemplate/' + id,
+    method: 'delete'
+  })
+}
+
+// 导出体检报告模板
+export function exportFSPhysicalReportTemplate(query) {
+  return request({
+    url: '/his/physicalReportTemplate/export',
+    method: 'get',
+    params: query
+  })
+}

+ 71 - 0
src/api/his/physicalReportTemplateField.js

@@ -0,0 +1,71 @@
+import request from '@/utils/request'
+
+// 查询体检报告模板字段列表
+export function listPhysicalReportTemplateField(query) {
+  return request({
+    url: '/his/physicalReportTemplateField/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询体检报告模板字段详细
+export function getPhysicalReportTemplateField(id) {
+  return request({
+    url: '/his/physicalReportTemplateField/' + id,
+    method: 'get'
+  })
+}
+
+// 新增体检报告模板字段
+export function addPhysicalReportTemplateField(data) {
+  return request({
+    url: '/his/physicalReportTemplateField',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改体检报告模板字段
+export function updatePhysicalReportTemplateField(data) {
+  return request({
+    url: '/his/physicalReportTemplateField',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除体检报告模板字段
+export function delPhysicalReportTemplateField(id) {
+  return request({
+    url: '/his/physicalReportTemplateField/' + id,
+    method: 'delete'
+  })
+}
+
+// 导出体检报告模板字段
+export function exportPhysicalReportTemplateField(query) {
+  return request({
+    url: '/his/physicalReportTemplateField/export',
+    method: 'get',
+    params: query
+  })
+}
+
+// 导出体检报告模板字段
+export function getTemplateField(templateId) {
+  return request({
+    url: '/his/physicalReportTemplateField/getTemplateField/'+templateId,
+    method: 'post'
+  })
+}
+
+
+// 新增体检报告模板字段
+export function saveTemplate(data) {
+  return request({
+    url: '/his/physicalReportTemplateField/saveTemplate',
+    method: 'post',
+    data: data
+  })
+}

+ 383 - 0
src/views/his/physicalReportTemplate/index.vue

@@ -0,0 +1,383 @@
+<template>
+  <div class="app-container">
+    <el-form v-show="showSearch" ref="queryForm" :inline="true" :model="queryParams" label-width="68px">
+      <el-form-item label="模板名称" prop="templateName">
+        <el-input
+          v-model="queryParams.templateName"
+          clearable
+          placeholder="请输入体检模板名称"
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="状态" prop="status">
+        <el-select v-model="queryParams.status" clearable placeholder="状态" size="small">
+          <el-option
+            v-for="dict in statusOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item>
+        <el-button icon="el-icon-search" size="mini" type="primary" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          v-hasPermi="['his:physicalReportTemplate:add']"
+          icon="el-icon-plus"
+          plain
+          size="mini"
+          type="primary"
+          @click="handleAdd"
+        >新增
+        </el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          v-hasPermi="['his:physicalReportTemplate:edit']"
+          :disabled="single"
+          icon="el-icon-edit"
+          plain
+          size="mini"
+          type="success"
+          @click="handleUpdate"
+        >修改
+        </el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          v-hasPermi="['his:physicalReportTemplate:remove']"
+          :disabled="multiple"
+          icon="el-icon-delete"
+          plain
+          size="mini"
+          type="danger"
+          @click="handleDelete"
+        >删除
+        </el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          v-hasPermi="['his:physicalReportTemplate:export']"
+          :loading="exportLoading"
+          icon="el-icon-download"
+          plain
+          size="mini"
+          type="warning"
+          @click="handleExport"
+        >导出
+        </el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="fSPhysicalReportTemplateList" border @selection-change="handleSelectionChange">
+      <el-table-column align="center" type="selection" width="55"/>
+      <el-table-column align="center" label="模板编码" prop="id"/>
+      <el-table-column align="center" label="模板名称" prop="templateName"/>
+      <el-table-column align="center" label="备注" prop="remark"/>
+      <el-table-column align="center" label="状态" prop="status">
+        <template v-slot="scope">
+          <el-tag v-for="item in statusOptions" v-if="scope.row.status==item.dictValue" :key="item.dictValue"
+                  :type="scope.row.status==1?'success':'danger'"
+                  prop="status"
+          >{{ item.dictLabel }}
+          </el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column align="center" class-name="small-padding fixed-width" label="操作">
+        <template v-slot="scope">
+          <el-button
+            v-hasPermi="['his:physicalReportTemplate:edit']"
+            icon="el-icon-edit"
+            size="mini"
+            type="text"
+            @click="handleUpdate(scope.row)"
+          >修改
+          </el-button>
+          <el-button
+            v-hasPermi="['his:physicalReportTemplate:remove']"
+            icon="el-icon-delete"
+            size="mini"
+            type="text"
+            @click="handleDelete(scope.row)"
+          >删除
+          </el-button>
+          <el-button
+            v-if="scope.row.status==='1'"
+            icon="el-icon-document-add"
+            size="mini"
+            type="text"
+            @click="customizeTemplate(scope.row)"
+          >自定义模板
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :limit.sync="queryParams.pageSize"
+      :page.sync="queryParams.pageNum"
+      :total="total"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改体检报告模板对话框 -->
+    <el-dialog :title="title" :visible.sync="open" append-to-body width="500px">
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="模板名称" prop="templateName">
+          <el-input v-model="form.templateName" placeholder="请输入体检模板名称"/>
+        </el-form-item>
+        <el-form-item label="备注" prop="remark">
+          <el-input v-model="form.remark" placeholder="请输入内容" type="textarea"/>
+        </el-form-item>
+        <el-form-item label="状态">
+          <el-radio-group v-model="form.status">
+            <el-radio
+              v-for="item in statusOptions"
+              :key="item.dictValue"
+              :label="item.dictValue"
+            >{{ item.dictLabel }}
+            </el-radio>
+          </el-radio-group>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+
+    <el-dialog
+      :before-close="handleClose"
+      :title="'自定义模板'+templateTitle"
+      :visible.sync="dialogVisible"
+      center
+      width="80%"
+    >
+      <customizeTemplate ref="customizeTemplate" :templateName="templateTitle"></customizeTemplate>
+      <span slot="footer" class="dialog-footer">
+    <el-button @click="dialogVisible = false">取 消</el-button>
+    <el-button type="primary" @click="dialogVisible = false">确 定</el-button>
+    </span>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import {
+  listFSPhysicalReportTemplate,
+  getFSPhysicalReportTemplate,
+  delFSPhysicalReportTemplate,
+  addFSPhysicalReportTemplate,
+  updateFSPhysicalReportTemplate,
+  exportFSPhysicalReportTemplate
+} from '@/api/his/physicalReportTemplate'
+
+import customizeTemplate from '@/views/his/physicalReportTemplateField'
+
+export default {
+  name: 'FSPhysicalReportTemplate',
+  data() {
+    return {
+      //模板ID
+      templateId: null,
+      //弹窗名称
+      templateTitle: null,
+      dialogVisible: false,
+      //状态
+      statusOptions: [],
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 体检报告模板表格数据
+      fSPhysicalReportTemplateList: [],
+      // 弹出层标题
+      title: '',
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        templateName: null,
+        status: null
+      },
+      // 表单参数
+      form: {
+        status: ''
+      },
+      // 表单校验
+      rules: {
+        templateName: [
+          { required: true, message: '体检模板名称不能为空', trigger: 'blur' }
+        ],
+        createTime: [
+          { required: true, message: '添加时间不能为空', trigger: 'blur' }
+        ]
+      }
+    }
+  },
+  components: {
+    customizeTemplate
+  },
+  created() {
+    this.getList()
+
+    //字典状态查询
+    this.getDicts('sys_company_status').then((response) => {
+      this.statusOptions = response.data
+    })
+  },
+  methods: {
+    /** 查询体检报告模板列表 */
+    getList() {
+      this.loading = true
+      listFSPhysicalReportTemplate(this.queryParams).then(response => {
+        this.fSPhysicalReportTemplateList = response.rows
+        this.total = response.total
+        this.loading = false
+      })
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false
+      this.reset()
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        templateName: null,
+        remark: null,
+        createTime: null,
+        updateTime: null,
+        status: 0,
+        createBy: null,
+        updateBy: null
+      }
+      this.resetForm('form')
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1
+      this.getList()
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm('queryForm')
+      this.handleQuery()
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length !== 1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset()
+      this.open = true
+      this.title = '添加体检报告模板'
+      this.form.status = '1'
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset()
+      const id = row.id || this.ids
+      getFSPhysicalReportTemplate(id).then(response => {
+        this.form = response.data
+        this.open = true
+        this.title = '修改体检报告模板'
+      })
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs['form'].validate(valid => {
+        if (valid) {
+          if (this.form.id != null) {
+            updateFSPhysicalReportTemplate(this.form).then(response => {
+              this.msgSuccess('修改成功')
+              this.open = false
+              this.getList()
+            })
+          } else {
+            addFSPhysicalReportTemplate(this.form).then(response => {
+              this.msgSuccess('新增成功')
+              this.open = false
+              this.getList()
+            })
+          }
+        }
+      })
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids
+      this.$confirm('是否确认删除体检报告模板编号为"' + ids + '"的数据项?', '警告', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(function() {
+        return delFSPhysicalReportTemplate(ids)
+      }).then(() => {
+        this.getList()
+        this.msgSuccess('删除成功')
+      }).catch(() => {
+      })
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams
+      this.$confirm('是否确认导出所有体检报告模板数据项?', '警告', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        this.exportLoading = true
+        return exportFSPhysicalReportTemplate(queryParams)
+      }).then(response => {
+        this.download(response.msg)
+        this.exportLoading = false
+      }).catch(() => {
+      })
+    },
+    /**
+     * 自定义模板
+     * **/
+    customizeTemplate(row) {
+      this.templateTitle = row.templateName
+      this.dialogVisible = true
+      this.$nextTick(() => {
+        this.$refs.customizeTemplate.getTemplateField(row.id)
+      })
+    },
+    handleClose(done) {
+      this.$confirm('确认关闭?')
+        .then(_ => {
+          done()
+        })
+        .catch(_ => {
+        })
+    }
+  }
+}
+</script>

+ 688 - 0
src/views/his/physicalReportTemplateField/index.vue

@@ -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>