From f90eb2159fc4aa79d7cd28e0f30b7e82a2cea779 Mon Sep 17 00:00:00 2001
From: 董国庆 <364620639@qq.com>
Date: 星期一, 26 五月 2025 13:47:20 +0800
Subject: [PATCH] 中试报告

---
 laboratory/src/views/dataManagement/schemeManagement/addPlan.vue |  832 +++++++++++++++++++++++++++++++++++++----------------------
 1 files changed, 523 insertions(+), 309 deletions(-)

diff --git a/laboratory/src/views/dataManagement/schemeManagement/addPlan.vue b/laboratory/src/views/dataManagement/schemeManagement/addPlan.vue
index f8eec6d..ef3538f 100644
--- a/laboratory/src/views/dataManagement/schemeManagement/addPlan.vue
+++ b/laboratory/src/views/dataManagement/schemeManagement/addPlan.vue
@@ -1,130 +1,120 @@
 <template>
   <Card>
     <template style="position: relative">
-      <el-form
-        ref="form"
-        :model="form"
-        :rules="rules"
-        inline
-        label-position="top"
-      >
-        <div class="header-title" style="margin-bottom: 38px;justify-content: space-between;">
-          <div style="display: flex;align-items: center;gap: 13px;">
+      <el-form ref="form" :model="form" :rules="rules" inline label-position="top">
+        <div v-if="!isEdit">
+          <div class="header-title" style="margin-bottom: 38px">
+            <div style="display: flex; align-items: center; gap: 13px">
+              <div class="header-title-left">
+                <img src="@/assets/public/headercard.png" />
+                <div>所属实验调度</div>
+              </div>
+              <el-button @click="showScheduling = true" class="el-icon-plus" type="primary">
+                选择实验调度</el-button>
+            </div>
+          </div>
+          <!-- //换到详情弹窗 -->
+          <!-- <el-button @click="handleStopExperiment" type="danger">
+            申请终止实验</el-button> -->
+          <Table :data="groupTableData" :total="0" :height="null" class="groupTable">
+            <el-table-column type="index" label="序号" width="80"></el-table-column>
+            <el-table-column prop="projectName" label="所属项目课题方案"></el-table-column>
+            <el-table-column prop="experimentCode" label="实验编号"></el-table-column>
+            <el-table-column prop="experimentName" label="实验名称"></el-table-column>
+            <el-table-column prop="experimentDate" label="通知时间"></el-table-column>
+            <el-table-column prop="experimentStartTime" label="实验开始时间"></el-table-column>
+            <el-table-column prop="experimentEndTime" label="实验结束时间"></el-table-column>
+            <el-table-column prop="participantsName" label="参加人员"></el-table-column>
+            <el-table-column prop="status" label="状态">
+              <template slot-scope="scope">
+                <el-tag :type="getStatusType(scope.row.status)">
+                  {{ getStatusText(scope.row.status) }}
+                </el-tag>
+              </template>
+            </el-table-column>
+          </Table>
+
+          <div class="header-title" style="margin-bottom: 38px">
             <div class="header-title-left">
               <img src="@/assets/public/headercard.png" />
-              <div>所属实验调度</div>
+              <span>基础信息</span>
             </div>
-            <el-button
-              @click="showScheduling = true"
-              class="el-icon-plus"
-              type="primary"
-            >
-              选择实验调度</el-button
-            >
           </div>
-          <el-button
-              @click="handleStopExperiment"
-              type="danger"
-            >
-              申请终止实验</el-button
-            >
-        </div>
-        <Table
-          :data="groupTableData"
-          :total="0"
-          :height="null"
-          class="groupTable"
-        >
-          <el-table-column
-            type="index"
-            label="序号"
-            width="80"
-          ></el-table-column>
-          <el-table-column prop="groupName" label="组别"></el-table-column>
-          <el-table-column prop="remark" label="备注"></el-table-column>
-          <el-table-column label="操作" width="200">
-            <template slot-scope="scope">
-              <el-button type="text" @click="handleEditGroup(scope.row)"
-                >编辑</el-button
-              >
-              <el-button type="text" @click="handleDeleteGroup(scope.row)"
-                >移除</el-button
-              >
-            </template>
-          </el-table-column>
-        </Table>
 
-        <div class="header-title" style="margin-bottom: 38px">
-          <div class="header-title-left">
-            <img src="@/assets/public/headercard.png" />
-            <span>基础信息</span>
+          <template v-if="groupData && groupData.length > 0">
+            <div class="add-group">
+              <span>组别列表</span>
+            </div>
+
+            <Table :data="groupData" :total="0" :height="null" class="groupTable">
+              <el-table-column type="index" label="序号" width="80"></el-table-column>
+              <el-table-column prop="groupName" label="组别"></el-table-column>
+              <el-table-column prop="remark" label="备注"></el-table-column>
+            </Table>
+          </template>
+
+          <div style="padding-left: 25px;margin-top: 28px;">
+            <el-form-item prop="experimentDate" label="试验日期">
+
+              <el-date-picker v-model="form.experimentDate" type="datetime" :disabled="isEdit" placeholder="选择日期时间">
+              </el-date-picker>
+            </el-form-item>
+          </div>
+        </div>
+        <div v-else>
+          <div class="header-title" style="margin-bottom: 18px">
+            <div class="header-title-left">
+              <img src="@/assets/public/headercard.png" />
+              <div>所属项目课题方案</div>
+            </div>
+          </div>
+          <div class="content-box">
+            <div class="content-box-left">
+              <div>项目课题方案名称:{{ groupTableData && groupTableData.length > 0 ? groupTableData[0].projectName : '' }}</div>
+              <div>实验编号:{{ groupTableData && groupTableData.length > 0 ? groupTableData[0].experimentCode : '' }}</div>
+            </div>
+            <div class="content-box-right">
+              <div>项目课题方案编号: {{ groupTableData && groupTableData.length > 0 ? groupTableData[0].projectCode : '' }}</div>
+              <div>实验名称: {{ groupTableData && groupTableData.length > 0 ? groupTableData[0].experimentName : '' }}</div>
+            </div>
           </div>
         </div>
 
-        <div class="add-group">
-          <span>组别列表</span>
-          <!-- <el-button type="primary" class="el-icon-plus" @click="handleAddGroup">添加组别</el-button> -->
-        </div>
-
-        <Table
-          :data="groupTableData"
-          :total="0"
-          :height="null"
-          class="groupTable"
-        >
-          <el-table-column
-            type="index"
-            label="序号"
-            width="80"
-          ></el-table-column>
-          <el-table-column prop="groupName" label="组别"></el-table-column>
-          <el-table-column prop="remark" label="备注"></el-table-column>
-        </Table>
-
-        <div style="padding-left: 25px">
-          <el-form-item prop="name" label="试验日期">
-            <el-input v-model="form.name" placeholder="请输入" />
-          </el-form-item>
-        </div>
-
-        <div class="add-group">
+        <div class="add-group" v-if="!isEdit">
           <div>*</div>
           <span>参加人员</span>
-          <el-button type="primary" class="el-icon-plus" @click="addMember"
-            >选择参加人员</el-button
-          >
+          <el-button type="primary" class="el-icon-plus" @click="addMember" >选择参加人员</el-button>
         </div>
+        <div class="add-group" v-else><span>实验人员</span> </div>
         <div class="member-list">
-          <div v-for="item in 3" :key="item" class="member-list-card">
+          <div class="member-list-card">
             <div class="member-item">
-              <div class="member-title">
-                {{ ["工艺工程师", "实验员", "化验师"][item - 1] }}
-              </div>
-              <div
-                :class="item == 1 || item == 2 ? 'member-name-box' : 'flex1'"
-              >
-                <div
-                  :class="
-                    item == 1 || item == 2
-                      ? 'member-name-box'
-                      : 'member-name-box-2'
-                  "
-                >
-                  <div
-                    v-for="i in memberList(item)"
-                    :key="i"
-                    class="member-name"
-                  >
-                    张三
+              <div class="member-title">实验员</div>
+              <div class="flex">
+                <div class="member-name-box-2">
+                  <div v-for="i in selectedParticipants" :key="i.id" class="member-name">
+                    {{ i.nickName }}
                   </div>
                 </div>
               </div>
               <div class="member-change">
-                <div class="member-change-btn">修改</div>
+                <div class="member-change-btn" @click="handleEditMember" v-if="!isEdit">修改</div>
               </div>
             </div>
           </div>
         </div>
+
+        <template v-if="groupData && groupData.length > 0 && isEdit">
+          <div class="add-group">
+            <span>组别列表</span>
+          </div>
+
+          <Table :data="groupData" :total="0" :height="null" class="groupTable">
+            <el-table-column type="index" label="序号" width="80"></el-table-column>
+            <el-table-column prop="groupName" label="组别"></el-table-column>
+            <el-table-column prop="remark" label="备注"></el-table-column>
+          </Table>
+        </template>
 
         <div class="header-title" style="margin-bottom: 38px">
           <div class="header-title-left">
@@ -133,12 +123,8 @@
           </div>
         </div>
         <div class="content-box">
-          <AiEditor
-            ref="purposeEditor"
-            v-model="editorContents.purpose"
-            height="200px"
-            placeholder="请输入实验目的..."
-          />
+          <AiEditor ref="purposeEditor" :readOnly="isEdit" :value="editorContents.purpose" height="200px"
+            placeholder="请输入实验目的..." />
         </div>
 
         <div class="header-title" style="margin-bottom: 38px">
@@ -148,12 +134,8 @@
           </div>
         </div>
         <div class="content-box">
-          <AiEditor
-            ref="processEditor"
-            v-model="editorContents.process"
-            height="200px"
-            placeholder="请输入工艺参数及路线..."
-          />
+          <AiEditor ref="processEditor" :readOnly="isEdit" :value="editorContents.process" height="200px"
+            placeholder="请输入工艺参数及路线..." />
         </div>
 
         <div class="header-title" style="margin-bottom: 38px">
@@ -162,25 +144,18 @@
             <div>三、实验材料及设备</div>
           </div>
         </div>
-        <DynamicComponent
-          ref="materialComponent"
-          title="实验材料"
-          @submit="handleMaterialSubmit"
-        />
-        <DynamicComponent
-          ref="equipmentComponent"
-          title="实验所用设备"
-          @submit="handleEquipmentSubmit"
-        />
+        <DynamicComponent ref="materialComponent" title="实验材料" :participants="participantsData"
+          @submit="handleMaterialSubmit" :dataSource="form.experimentMaterial" :editable="!isEdit" />
+        <DynamicComponent ref="equipmentComponent" title="实验所用设备" :participants="participantsData"
+          @submit="handleEquipmentSubmit" :dataSource="form.experimentDevice" :editable="!isEdit" />
 
         <div class="header-title" style="margin-bottom: 38px">
           <div class="header-title-left">
             <img src="@/assets/public/headercard.png" />
             <div>四、实验操作步骤记录</div>
           </div>
-          <el-button @click="handleAddStep" class="el-icon-plus" type="primary">
-            添加步骤</el-button
-          >
+          <el-button @click="handleAddStep" class="el-icon-plus" type="primary" v-if="!isEdit">
+            添加步骤</el-button>
         </div>
 
         <div class="step-list" v-for="(item, idx) in stepList" :key="idx">
@@ -189,55 +164,46 @@
               步骤{{ idx + 1 }}:{{ item.stepName }}
             </div>
             <div class="step-list-item-control">
-              <div class="controlBtn edit" @click="handleEditStep(idx)">
-                <img
-                  src="@/assets/public/edit.png"
-                  alt="编辑"
-                  class="edit-icon"
-                />
+              <div class="controlBtn edit" @click="handleEditStep(idx)" v-if="!isEdit">
+                <img src="@/assets/public/edit.png" alt="编辑" class="edit-icon" />
                 编辑
               </div>
-              <div class="controlBtn delete" @click="handleDeleteStep(idx)">
-                <img
-                  src="@/assets/public/delete.png"
-                  alt="删除"
-                  class="delete-icon"
-                />
+              <div class="controlBtn delete" @click="handleDeleteStep(idx)" v-if="!isEdit">
+                <img src="@/assets/public/delete.png" alt="删除" class="delete-icon" />
                 删除
               </div>
             </div>
           </div>
-          <DynamicComponent
-            :ref="'stepContent' + idx"
-            @submit="(content) => handleStepContentSubmit(idx, content)"
-          />
+          <DynamicComponent :ref="'stepContent' + idx" @submit="(content) => handleStepContentSubmit(idx, content)"
+            :dataSource="item.content" :editable="!isEdit" />
         </div>
 
         <div class="add-project-footer">
-          <el-button type="primary" class="save-btn" @click="handleSave"
-            >发送</el-button
-          >
+          <el-button type="primary" class="save-btn" @click="handleSave">发送</el-button>
           <el-button @click="handleSaveDraft">存草稿</el-button>
         </div>
       </el-form>
     </template>
-    <SelectMember ref="selectMember" />
-    <experimentalScheduling :show="showScheduling" />
+    <SelectMemberSimple ref="selectMember" @submit="handleMemberSubmit" />
+    <experimentalScheduling :show="showScheduling" @submit="handleSchedulingSubmit" @close="handleSchedulingClose" />
     <AddStep ref="addStepDialog" @submit="handleStepSubmit" />
   </Card>
 </template>
 
 <script>
-import SelectMember from "@/components/SelectMember";
-import experimentalScheduling from "../confirmation-sheet/components/experimental-scheduling.vue";
+import SelectMemberSimple from "@/components/SelectMemberSimple/index.vue";
+import experimentalScheduling from "./components/experimental-scheduling.vue";
 import DynamicComponent from "@/components/DynamicComponent";
 import AddStep from "./components/add-step.vue";
 import AiEditor from "@/components/AiEditor";
+import { getGroupByDispatchId, getParticipantsByDispatchId, getDetail } from "./service";
+import moment from 'moment';
+import { add,update } from "./service";
 
 export default {
   name: "AddProject",
   components: {
-    SelectMember,
+    SelectMemberSimple,
     experimentalScheduling,
     DynamicComponent,
     AddStep,
@@ -247,8 +213,16 @@
     return {
       showScheduling: false,
       form: {
-        material: null,
-        equipment: null,
+        experimentDate: '', // 实验日期
+        experimentMaterial: null,
+        experimentDevice: null,
+        experimentObjective: '', // 实验目的
+        experimentParamRoute: '', // 工艺参数及路线
+        experimentStepRecord: [], // 实验步骤记录
+        experimentSchemePersons: [], // 实验方案人员
+        dispatchId: '', // 实验调度id
+        status: -1, // 状态:-1=草稿箱 1=已发送
+        commitTime: '', // 提交时间
       },
       editorContents: {
         purpose: "",
@@ -257,158 +231,82 @@
       stepList: [],
       editingStepIndex: -1,
       rules: {
-        name: [
-          { required: true, message: "请输入项目组名称", trigger: "blur" },
+        experimentDate: [
+          { required: true, message: "请输入实验日期", trigger: "blur" },
         ],
-        description: [
-          { required: true, message: "请输入项目组描述", trigger: "blur" },
-        ],
-        material: [
+        experimentMaterial: [
           { required: true, message: "请添加实验材料", trigger: "change" },
         ],
-        equipment: [
+        experimentDevice: [
           { required: true, message: "请添加实验设备", trigger: "change" },
         ],
       },
       groupTableData: [],
+      groupData: [],
       taskTableData: [],
+      participantsData: [],
+      selectedParticipants: [],
+      isEdit: false, // 是否为编辑模式
+      editId: null, // 编辑的ID
+      viewMaterialData: [], // 查看模式的材料数据
+      viewEquipmentData: [], // 查看模式的设备数据
+      // 状态映射表
+      statusTypeMap: {
+        "-1": "info",
+        "1": "warning",
+        "2": "success",
+        "3": "info"
+      },
+      statusTextMap: {
+        "-1": "草稿箱",
+        "1": "待确认",
+        "2": "已确认",
+        "3": "已封存"
+      }
     };
   },
+  async created() {
+    // 检查是否为编辑模式
+    if (this.$route.query.type === 'edit' && this.$route.query.id) {
+      this.isEdit = true;
+      this.editId = this.$route.query.id;
+      await this.loadEditData();
+    }
+  },
   methods: {
-    submitForm() {
-      this.$refs.form.validate((valid) => {
-        if (valid) {
-          console.log("submit!");
-        }
-      });
-    },
+    // ===== 人员相关方法 =====
     addMember() {
-      this.$refs.selectMember.open();
+      this.$refs.selectMember.open(this.participantsData, []);
     },
-    memberList(i) {
-      switch (i) {
-        case 1:
-          return [1];
-        case 2:
-          return [1];
-        case 3:
-          return [1, 2, 3, 4, 5, 6, 7, 8];
-        case 4:
-          return [1, 2, 3, 4, 5, 6, 7, 8];
-        default:
-          break;
-      }
+    handleMemberSubmit(selectedMembers) {
+      this.selectedParticipants = selectedMembers;
+      this.$refs.selectMember.close();
     },
-    handleAddGroup() {
-      this.$refs.addGroupDialog.open();
+    handleEditMember() {
+      this.$refs.selectMember.open(this.participantsData, this.selectedParticipants);
     },
-    handleEditGroup(row) {
-      this.$refs.addGroupDialog.open(row);
-    },
-    handleDeleteGroup(row) {
-      this.$confirm("确认删除该组别吗?", "提示", {
-        confirmButtonText: "确定",
-        cancelButtonText: "取消",
-        type: "warning",
-      })
-        .then(() => {
-          const index = this.groupTableData.findIndex((item) => item === row);
-          if (index > -1) {
-            this.groupTableData.splice(index, 1);
-            this.$message.success("删除成功");
-          }
-        })
-        .catch(() => {});
-    },
-    handleGroupSubmit(form) {
-      const index = this.groupTableData.findIndex(
-        (item) => item.groupName === form.groupName
-      );
-      if (index > -1) {
-        this.groupTableData.splice(index, 1, form);
-      } else {
-        this.groupTableData.push(form);
-      }
-    },
-    handleAddTask() {
-      this.$refs.addTaskDialog.open();
-    },
-    handleEditTask(row) {
-      this.$refs.addTaskDialog.open(row);
-    },
-    handleDeleteTask(row) {
-      this.$confirm("确认删除该任务吗?", "提示", {
-        confirmButtonText: "确定",
-        cancelButtonText: "取消",
-        type: "warning",
-      })
-        .then(() => {
-          const index = this.taskTableData.findIndex((item) => item === row);
-          if (index > -1) {
-            this.taskTableData.splice(index, 1);
-            this.$message.success("删除成功");
-          }
-        })
-        .catch(() => {});
-    },
-    handleTaskSubmit(form) {
-      const index = this.taskTableData.findIndex(
-        (item) => item.taskName === form.taskName
-      );
-      if (index > -1) {
-        this.taskTableData.splice(index, 1, form);
-      } else {
-        this.taskTableData.push(form);
-      }
-    },
-    handleMaterialSubmit(data) {
-      this.form.material = data;
-    },
-    handleEquipmentSubmit(data) {
-      this.form.equipment = data;
-    },
-    handleSave() {
-      this.$refs.form.validate((valid) => {
-        if (valid && this.validateContent()) {
-          this.$refs.materialComponent.submit();
-          this.$refs.equipmentComponent.submit();
-
-          const formData = {
-            ...this.form,
-            ...this.getAllEditorContent(),
-            steps: this.stepList,
-          };
-          console.log("提交的数据:", formData);
-          this.$message.success("保存成功");
-        }
-      });
-    },
-    handleSaveDraft() {
-      this.$refs.materialComponent.submit();
-      this.$refs.equipmentComponent.submit();
-
-      const formData = {
-        ...this.form,
-        ...this.getAllEditorContent(),
-        steps: this.stepList,
-        status: "draft",
-      };
-      console.log("草稿数据:", formData);
-      this.$message.success("草稿保存成功");
-    },
+    
+    // ===== 步骤相关方法 =====
     handleAddStep() {
       this.$refs.addStepDialog.open();
     },
     handleStepSubmit(stepData) {
       if (this.editingStepIndex > -1) {
+        // 编辑现有步骤
         this.stepList[this.editingStepIndex].stepName = stepData.stepName;
         this.editingStepIndex = -1;
       } else {
+        // 添加新步骤
         this.stepList.push({
           stepName: stepData.stepName,
           content: null,
         });
       }
+    },
+    handleEditStep(index) {
+      this.editingStepIndex = index;
+      this.$refs.addStepDialog.open(true);
+      this.$refs.addStepDialog.setStepName(this.stepList[index].stepName);
     },
     handleDeleteStep(index) {
       this.$confirm("确认删除该步骤吗?删除后步骤内容将无法恢复", "警告", {
@@ -421,15 +319,110 @@
           this.stepList.splice(index, 1);
           this.$message.success("删除成功");
         })
-        .catch(() => {});
-    },
-    handleEditStep(index) {
-      this.editingStepIndex = index;
-      this.$refs.addStepDialog.open(true);
-      this.$refs.addStepDialog.setStepName(this.stepList[index].stepName);
+        .catch(() => { });
     },
     handleStepContentSubmit(index, content) {
       this.stepList[index].content = content;
+    },
+    
+    // ===== 材料设备相关方法 =====
+    handleMaterialSubmit(data) {
+      this.form.experimentMaterial = data;
+    },
+    handleEquipmentSubmit(data) {
+      this.form.experimentDevice = data;
+    },
+    
+    // ===== 保存提交相关方法 =====
+    handleSave() {
+      this.submitData(1);
+    },
+    handleSaveDraft() {
+      this.submitData(-1);
+    },
+    submitData(status) {
+      // 先获取所有动态组件的数据
+      this.$refs.materialComponent.submit();
+      this.$refs.equipmentComponent.submit();
+
+      // 获取所有步骤内容
+      const stepContentRefs = Object.keys(this.$refs)
+        .filter(key => key.startsWith('stepContent'))
+        .map(key => this.$refs[key]);
+      
+      stepContentRefs.forEach((ref) => {
+        const editor = Array.isArray(ref) ? ref[0] : ref;
+        if (editor && typeof editor.submit === 'function') {
+          editor.submit();
+        }
+      });
+
+      // 进行表单校验
+      this.$refs.form.validate((valid) => {
+        if (valid && this.validateContent()) {
+          // 获取富文本编辑器内容
+          const experimentObjective = this.$refs.purposeEditor.getContent();
+          const experimentParamRoute = this.$refs.processEditor.getContent();
+          
+          // 构建实验步骤记录数据
+          const experimentStepRecord = this.stepList.map(step => ({
+            stepName: step.stepName,
+            content: step.content
+          }));
+          
+          // 构建提交数据
+          const formData = {
+            ...this.form,
+            experimentDate: moment(this.form.experimentDate).format('YYYY-MM-DD HH:mm:ss'),
+            dispatchId: this.groupTableData && this.groupTableData.length > 0 ? this.groupTableData[0]?.id : '',
+            experimentObjective,
+            experimentParamRoute,
+            experimentSchemePersons: this.selectedParticipants.map(person => ({
+              userId: person.userId,
+              nickName: person.nickName,
+              roleType: person.roleType,
+              commitTime: moment().format('YYYY-MM-DD HH:mm:ss'),
+            })),
+            status,
+            commitTime: moment().format('YYYY-MM-DD HH:mm:ss'),
+          };
+          
+          // 统一转换JSON字符串
+          formData.experimentStepRecord = JSON.stringify(experimentStepRecord);
+          formData.experimentDevice = JSON.stringify(this.form.experimentDevice);
+          formData.experimentMaterial = JSON.stringify(this.form.experimentMaterial);
+          
+          // 编辑模式下添加id参数
+          if (this.isEdit && this.editId) {
+            formData.id = this.editId;
+          }
+          
+          // 根据是否为编辑模式调用不同接口
+          const apiCall = this.isEdit ? update(formData) : add(formData);
+          
+          apiCall.then(res => {
+            if (res.code === 200) {
+              this.$message.success(status === 1 ? '保存成功' : '草稿保存成功');
+              if (status === 1) {
+                this.$router.go(-1);
+              }
+            } else {
+              this.$message.error(res.msg || (status === 1 ? '保存失败' : '草稿保存失败'));
+            }
+          }).catch(err => {
+            this.$message.error(status === 1 ? '保存失败' : '草稿保存失败');
+            console.error(status === 1 ? '保存失败:' : '草稿保存失败:', err);
+          });
+        } else {
+          // 获取第一个错误字段并滚动到该位置
+          const firstError = this.$refs.form.fields.find(field => field.validateState === 'error');
+          if (firstError) {
+            this.$nextTick(() => {
+              firstError.$el.scrollIntoView({ behavior: 'smooth', block: 'center' });
+            });
+          }
+        }
+      });
     },
     getAllEditorContent() {
       return {
@@ -438,19 +431,221 @@
       };
     },
     validateContent() {
-      const contents = this.getAllEditorContent();
-      if (!contents.purpose) {
+      // 校验实验调度
+      if (!this.groupTableData || this.groupTableData.length === 0) {
+        this.$message.error("请选择实验调度");
+        return false;
+      }
+
+      // 校验实验日期
+      if (!this.form.experimentDate) {
+        this.$message.error("请填写实验日期");
+        return false;
+      }
+
+      // 校验参与人员
+      if (!this.selectedParticipants || this.selectedParticipants.length === 0) {
+        this.$message.error("请选择参与人员");
+        return false;
+      }
+
+      // 校验实验目的
+      const purpose = this.$refs.purposeEditor.getContent();
+      if (!purpose || purpose === '<p></p>' || purpose.trim() === '<p></p>') {
         this.$message.error("请填写实验目的");
         return false;
       }
-      if (!contents.process) {
+
+      // 校验工艺参数及路线
+      const process = this.$refs.processEditor.getContent();
+      if (!process || process === '<p></p>' || process.trim() === '<p></p>') {
         this.$message.error("请填写工艺参数及路线");
         return false;
       }
+
+      // 校验实验材料
+      if (!this.form.experimentMaterial) {
+        this.$message.error("请添加实验材料");
+        return false;
+      }
+
+      // 校验实验设备
+      if (!this.form.experimentDevice) {
+        this.$message.error("请添加实验设备");
+        return false;
+      }
+
+      // 校验实验步骤记录
+      if (!this.stepList || this.stepList.length === 0) {
+        this.$message.error("请添加实验操作步骤");
+        return false;
+      }
+
+      // 校验每个步骤是否都有内容
+      const invalidStep = this.stepList.findIndex(step => !step.content);
+      if (invalidStep !== -1) {
+        this.$message.error(`请完善第${invalidStep + 1}个步骤的内容`);
+        return false;
+      }
+
       return true;
     },
     handleStopExperiment() {
-      this.$router.push('/dataManagement/scheme-management/stop-experiment')
+      this.$router.push("/dataManagement/scheme-management/stop-experiment");
+    },
+    getStatusType(status) {
+      return this.statusTypeMap[status] || "info";
+    },
+    getStatusText(status) {
+      return this.statusTextMap[status] || "未知";
+    },
+    handleSchedulingSubmit(data) {
+      this.groupTableData = data || [];
+      if (data && data.length > 0 && data[0].id) {
+        getGroupByDispatchId({ dispatchId: data[0].id }).then(res => {
+          if (res) {
+            this.groupData = res || [];
+          } else {
+            this.$message.error(res.msg || '获取组别列表失败');
+          }
+        }).catch(err => {
+          this.$message.error('获取组别列表失败');
+          console.error('获取组别列表失败:', err);
+        });
+        getParticipantsByDispatchId({ dispatchId: data[0].id }).then(res => {
+          console.log("获取参加人员列表:", res);
+          if (res) {
+            this.participantsData = res || [];
+          } else {
+            this.$message.error(res.msg || '获取参加人员列表失败');
+          }
+        }).catch(err => {
+          this.$message.error('获取参加人员列表失败');
+          console.error('获取参加人员列表失败:', err);
+        });
+      }
+    },
+    handleSchedulingClose() {
+      this.showScheduling = false;
+    },
+    // ===== 数据加载方法 =====
+    async loadEditData() {
+      try {
+        const res = await getDetail({ id: this.editId });
+        if (!res) {
+          this.$message.error('获取详情失败');
+          return;
+        }
+        
+        console.log('编辑数据', res);
+        const data = res;
+
+        // 填充基本表单数据
+        this.form.experimentDate = data.experimentDate;
+
+        // 填充实验调度信息
+        if (data.experimentDispatch?.id) {
+          this.form.dispatchId = data.experimentDispatch.id;
+          this.groupTableData = [{ ...data.experimentDispatch }];
+          
+          // 获取组别信息
+          try {
+            const groupRes = await getGroupByDispatchId({ dispatchId: data.experimentDispatch.id });
+            this.groupData = groupRes || [];
+          } catch (err) {
+            console.error('获取组别列表失败:', err);
+          }
+        }
+
+        // 填充参与人员
+        this.selectedParticipants = Array.isArray(data.experimentSchemePersons)
+          ? data.experimentSchemePersons
+          : JSON.parse(data.experimentSchemePersons || '[]');
+
+        // 填充富文本编辑器内容
+        this.editorContents.purpose = data.experimentObjective || '';
+        this.editorContents.process = data.experimentParamRoute || '';
+
+        // 填充实验材料和设备
+        try {
+          this.form.experimentMaterial = typeof data.experimentMaterial === 'string'
+            ? JSON.parse(data.experimentMaterial)
+            : data.experimentMaterial;
+        } catch (err) {
+          console.error('解析实验材料数据失败:', err);
+          this.form.experimentMaterial = [];
+        }
+
+        try {
+          this.form.experimentDevice = typeof data.experimentDevice === 'string'
+            ? JSON.parse(data.experimentDevice)
+            : data.experimentDevice;
+        } catch (err) {
+          console.error('解析实验设备数据失败:', err);
+          this.form.experimentDevice = [];
+        }
+
+        // 填充实验步骤
+        try {
+          const stepsData = typeof data.experimentStepRecord === 'string'
+            ? JSON.parse(data.experimentStepRecord)
+            : data.experimentStepRecord;
+
+          this.stepList = (stepsData || []).map(step => ({
+            stepName: step.stepName,
+            content: step.content
+          }));
+        } catch (err) {
+          console.error('解析实验步骤数据失败:', err);
+          this.stepList = [];
+        }
+
+        // 等待组件渲染完成后设置编辑器内容
+        this.$nextTick(() => {
+          // 设置富文本编辑器内容
+          if (this.$refs.purposeEditor) {
+            this.$refs.purposeEditor.setContent(this.editorContents.purpose);
+          }
+          if (this.$refs.processEditor) {
+            this.$refs.processEditor.setContent(this.editorContents.process);
+          }
+
+          // 设置动态组件的初始数据
+          if (!this.isEdit) {
+            if (this.$refs.materialComponent && this.form.experimentMaterial) {
+              this.$refs.materialComponent.setInitialData(this.form.experimentMaterial);
+            }
+            if (this.$refs.equipmentComponent && this.form.experimentDevice) {
+              this.$refs.equipmentComponent.setInitialData(this.form.experimentDevice);
+            }
+
+            // 设置步骤内容的初始数据
+            this.stepList.forEach((step, index) => {
+              const stepContentRef = this.$refs['stepContent' + index];
+              if (stepContentRef && step.content) {
+                const editor = Array.isArray(stepContentRef) ? stepContentRef[0] : stepContentRef;
+                if (editor?.setInitialData) {
+                  editor.setInitialData(step.content);
+                }
+              }
+            });
+          }
+        });
+
+      } catch (error) {
+        this.$message.error('获取详情失败');
+        console.error('获取详情失败:', error);
+      }
+    },
+    // 转换数据格式为ViewDynamicComponent需要的格式
+    convertToViewFormat(data) {
+      if (!data || !Array.isArray(data)) return [];
+
+      return data.map(item => ({
+        id: item.id || Math.random().toString(36).substr(2, 9),
+        type: item.type,
+        data: item.data
+      }));
     },
   },
 };
@@ -467,6 +662,7 @@
   flex-wrap: wrap;
   gap: 13px;
   margin-top: 38px;
+
   .header-title-left {
     display: flex;
     align-items: center;
@@ -529,6 +725,7 @@
 
 .header-title:first-child {
   margin-top: 0px;
+
   .header-title-left {
     margin-top: 0;
   }
@@ -558,6 +755,7 @@
   width: 65%;
   padding-left: 40px;
 }
+
 .rwuTable {
   width: 85%;
   padding-left: 40px;
@@ -577,35 +775,27 @@
     border: 1px solid #dcdfe6;
 
     &:nth-child(1) {
-      background: linear-gradient(
-        to bottom,
-        rgba(4, 156, 154, 0.2) 0%,
-        rgba(5, 242, 194, 0) 70%
-      );
+      background: linear-gradient(to bottom,
+          rgba(4, 156, 154, 0.2) 0%,
+          rgba(5, 242, 194, 0) 70%);
     }
 
     &:nth-child(2) {
-      background: linear-gradient(
-        to bottom,
-        rgba(5, 160, 193, 0.2) 0%,
-        rgba(5, 242, 194, 0) 70%
-      );
+      background: linear-gradient(to bottom,
+          rgba(5, 160, 193, 0.2) 0%,
+          rgba(5, 242, 194, 0) 70%);
     }
 
     &:nth-child(3) {
-      background: linear-gradient(
-        to bottom,
-        rgba(255, 77, 79, 0.2) 0%,
-        rgba(255, 242, 194, 0) 70%
-      );
+      background: linear-gradient(to bottom,
+          rgba(255, 77, 79, 0.2) 0%,
+          rgba(255, 242, 194, 0) 70%);
     }
 
     &:nth-child(4) {
-      background: linear-gradient(
-        to bottom,
-        rgba(250, 199, 20, 0.21) 0%,
-        rgba(255, 242, 194, 0) 70%
-      );
+      background: linear-gradient(to bottom,
+          rgba(250, 199, 20, 0.21) 0%,
+          rgba(255, 242, 194, 0) 70%);
     }
 
     .member-item {
@@ -623,6 +813,7 @@
         line-height: 16px;
         text-align: center;
       }
+
       .flex1 {
         flex: 1;
       }
@@ -664,6 +855,7 @@
         padding: 10px 0;
         margin-top: auto;
         cursor: pointer;
+
         .member-change-btn {
           background: #fff1f0;
           border-radius: 4px;
@@ -695,14 +887,17 @@
   padding: 20px;
   margin-top: 37px;
 }
+
 .step-list {
   background: #eff8fa;
   padding: 20px;
+
   .step-list-item {
     display: flex;
     justify-content: space-between;
     padding: 25px;
     background: #ffffff;
+
     .step-list-item-title {
       font-weight: 500;
       font-size: 14px;
@@ -711,9 +906,11 @@
       flex-wrap: wrap;
       flex: 1;
     }
+
     .step-list-item-control {
       display: flex;
       align-items: center;
+
       .controlBtn {
         height: 24px;
         background: #ffffff;
@@ -722,6 +919,7 @@
         display: flex;
         align-items: center;
       }
+
       .edit {
         border: 1px solid #44be09;
         font-family: PingFangSC, PingFang SC;
@@ -731,6 +929,7 @@
         line-height: 24px;
         margin-right: 50px;
       }
+
       .delete {
         border: 1px solid #ff4d4f;
         font-family: PingFangSC, PingFang SC;
@@ -739,11 +938,13 @@
         color: #ff4d4f;
         line-height: 24px;
       }
+
       .edit-icon {
         width: 14px;
         height: 14px;
         margin-right: 8px;
       }
+
       .delete-icon {
         width: 13px;
         height: 13px;
@@ -755,7 +956,20 @@
 
 .content-box {
   padding: 0 25px;
-  margin-bottom: 30px;
+  margin-bottom: 20px;
   width: 65%;
+  display: flex;
+  .content-box-left{
+    flex: 1;
+    div{
+      padding: 10px 0;
+    }
+  }
+  .content-box-right{
+    flex: 1;
+    div{
+      padding: 10px 0;
+    }
+  }
 }
 </style>
\ No newline at end of file

--
Gitblit v1.7.1