董国庆
7 天以前 b3f4499793fa7b21f6c5d1e099d6ed170ecbe47a
实验方案管理
7个文件已修改
1个文件已添加
850 ■■■■■ 已修改文件
laboratory/src/components/DynamicComponent/addTableData.vue 45 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/components/DynamicComponent/index.vue 112 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/components/DynamicComponent/service.js 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/components/SelectMember/index.vue 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/components/SelectMember/service.js 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/dataManagement/schemeManagement/addPlan.vue 609 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/dataManagement/schemeManagement/components/approvalDialog.vue 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/dataManagement/schemeManagement/list.vue 29 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/components/DynamicComponent/addTableData.vue
@@ -144,6 +144,8 @@
</template>
  
<script>
import { listByRole } from './service';
export default {
  name: "AddDialog",
  props: {
@@ -173,13 +175,7 @@
      photoList: [],
      spectrumList: [],
      defaultImageUrl: 'https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg', // 默认图片地址
      userOptions: [
        { value: '1', label: '用户1' },
        { value: '2', label: '用户2' },
        { value: '3', label: '用户3' },
        { value: '4', label: '用户4' },
        { value: '5', label: '用户5' }
      ]
      userOptions: []
    };
  },
  computed: {
@@ -228,6 +224,20 @@
    },
  },
  methods: {
    getUserOptions() {
      listByRole().then(res => {
        if (res) {
          this.userOptions = res.map(user => ({
            value: user.userId,
            label: user.nickName || user.userName
          }));
        } else {
          this.$message.error('获取用户列表失败');
        }
      }).catch(err => {
        console.error('获取用户列表失败', err);
      });
    },
    checkEditPermission(header) {
      if (!header.role || !Array.isArray(header.role)) {
        return true;
@@ -348,6 +358,21 @@
            photos: this.photoList,
            spectrums: this.spectrumList,
          };
          // 为用户类型字段添加用户完整信息
          if (this.headerList && this.headerList.length) {
            this.headerList.forEach(header => {
              if (header.type === 'user' && Array.isArray(submitData[header.name])) {
                // 为每个用户类型字段添加userInfo属性,包含用户完整信息
                submitData[`${header.name}_userInfo`] = submitData[header.name].map(userId => {
                  const userInfo = this.userOptions.find(user => user.value === userId);
                  return userInfo ? userInfo : { value: userId, label: userId };
                });
              }
            });
          }
          console.log(submitData,'修改的数据')
          this.$emit("success", submitData);
          this.handleClose();
        } else {
@@ -370,7 +395,9 @@
      // 同时更新form中对应的字段值以通过表单验证
      const imageHeader = this.headerList.find(h => h.type === 'image');
      if (imageHeader && imageHeader.name) {
        this.$set(this.form, imageHeader.name, '默认图片');
        // 保存图片URL,这样在表格中可以直接使用
        this.$set(this.form, imageHeader.name, this.defaultImageUrl);
        console.log('设置图片字段:', imageHeader.name, this.defaultImageUrl);
      }
      
      this.$refs.form.validateField("spectrums");
@@ -381,6 +408,8 @@
  },
  mounted() {
    // 获取用户列表数据
    this.getUserOptions();
  },
};
</script>
laboratory/src/components/DynamicComponent/index.vue
@@ -25,9 +25,27 @@
            <el-button size="mini"  @click="showTableHeaderDialog(idx)">添加表头</el-button>
            <el-button size="mini" type="primary" @click="showAddRowDialog(idx, item.data.headers)">添加数据</el-button>
          </div>
          <Table :data="item.data.rows" :total="null" :height="null" class="groupTable">
          <Table :data="item.data.rows" :total="null" :height="null" class="groupTable" :key="item.id + '_' + JSON.stringify(item.data.rows).length">
            <el-table-column v-for="(header, hidx) in item.data.headers" :key="hidx" :label="header.name"
              :prop="header.name" />
              :prop="header.name">
              <template slot-scope="scope">
                <!-- 用户类型显示 -->
                <template v-if="header.type === 'user'">
                  {{ getUserDisplayText(header.name, scope.row) }}
                </template>
                <!-- 图片类型显示 -->
                <template v-else-if="header.type === 'image'">
                  <img v-if="scope.row[header.name]"
                       :src="scope.row[header.name]"
                       alt="头像"
                       class="table-image" />
                </template>
                <!-- 其他类型 -->
                <template v-else>
                  {{ scope.row[header.name] }}
                </template>
              </template>
            </el-table-column>
            <el-table-column label="更新时间" prop="updateTime" min-width="180"></el-table-column>
            <el-table-column  label="操作" min-width="200" v-if="dialogCanEdit">
              <template slot-scope="scope">
@@ -136,6 +154,7 @@
        form: {},
      },
      headerList: [],
      defaultImageUrl: 'https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg', // 默认图片地址
    };
  },
  watch: {
@@ -176,6 +195,49 @@
    }
  },
  methods: {
    getUserDisplayText(fieldName, rowData) {
      // 检查是否有对应的userInfo数据
      const userInfoKey = `${fieldName}_userInfo`;
      // 如果没有rowData或fieldName,直接返回空字符串
      if (!rowData || !fieldName) {
        return '';
      }
      // 情况1: 有_userInfo数据
      if (rowData[userInfoKey] && Array.isArray(rowData[userInfoKey])) {
        return rowData[userInfoKey].map(user => user.label || '').join(', ');
      }
      // 情况2: 只有用户ID数组
      if (Array.isArray(rowData[fieldName])) {
        // 使用participants查找用户信息
        return rowData[fieldName].map(userId => {
          const user = this.participants.find(p => p.userId === userId);
          return user ? (user.nickName || user.userName || userId) : userId;
        }).join(', ');
      }
      // 情况3: 已经是字符串(可能是之前格式化过的)
      if (typeof rowData[fieldName] === 'string') {
        return rowData[fieldName];
      }
      // 默认返回空字符串
      return '';
    },
    formatUserNames(userArray) {
      if (!userArray || !Array.isArray(userArray) || userArray.length === 0) {
        return '';
      }
      // 查找参与者列表中的用户,获取昵称并用逗号拼接
      const userNames = userArray.map(userId => {
        const user = this.participants.find(p => p.userId === userId);
        return user ? user.nickName : userId;
      });
      return userNames.join(', ');
    },
    addComponent(type) {
      if (!this.editable) return;
@@ -232,23 +294,44 @@
      this.$emit('submit', data);
    },
    confirmAddRow(formData) {
      if (!this.editable) return;
      // if (!this.editable) return;
      const { idx, rowIndex, isEdit } = this.rowDialog;
      // 处理formData中的数据,保证用户信息的完整性
      const processedData = { ...formData };
      // 调试输出
      console.log('添加/编辑行数据:', processedData,'isEdit',isEdit);
      if (isEdit) {
        this.components[idx].data.rows[rowIndex] = {
          ...formData,
          updateTime: new Date().toLocaleString()
        };
        // Vue无法检测到对象或数组深层属性的变化,使用Vue.set来确保响应式
        this.$set(
          this.components[idx].data.rows,
          rowIndex,
          {
            ...processedData,
            updateTime: new Date().toLocaleString()
          }
        );
      } else {
        // 使用数组方法push会被Vue检测到
        this.components[idx].data.rows.push({
          ...formData,
          ...processedData,
          updateTime: new Date().toLocaleString()
        });
      }
      console.log('this.components',this.components);
      // 手动触发组件更新
      this.$forceUpdate();
      // 延迟发送事件,确保数据已更新
      this.$nextTick(() => {
        this.emitUpdate();
      });
      this.rowDialog.visible = false;
      this.rowDialog.form = {};
      this.emitUpdate();
    },
    removeComponent(idx) {
      if (!this.editable) return;
@@ -387,7 +470,9 @@
      return true;
    },
    emitUpdate() {
      this.$emit('update:dataSource', this.components);
      // 先创建新对象,这有助于触发更新
      const updatedComponents = JSON.parse(JSON.stringify(this.components));
      this.$emit('update:dataSource', updatedComponents);
    },
  },
};
@@ -519,4 +604,11 @@
  object-fit: cover;
  border-radius: 8px;
}
.table-image {
  width: 50px;
  height: 50px;
  object-fit: cover;
  border-radius: 4px;
}
</style>
laboratory/src/components/DynamicComponent/service.js
New file
@@ -0,0 +1,8 @@
import axios from '@/utils/request';
// 获取项目列表 获取用户列表-不分页-根据角色筛选
export const listByRole = (data) => {
    return axios.get('/system/user/listByRole', { params:data })
}
laboratory/src/components/SelectMember/index.vue
@@ -59,7 +59,7 @@
</template>
<script>
import { getRoleList, getUserList } from './service'
import { getRoleList, getUserList, listByRole } from './service'
export default {
    props: {
        projectId: {
@@ -118,7 +118,8 @@
            if (this.projectId) {
                params.projectId = this.projectId;
                // TODO: 这里需要替换为新的接口调用
                // const res = await getProjectUserList(params);
                const res = await listByRole(params);
                this.tableData = res.records;
            } else {
                const res = await getUserList(params);
                this.tableData = res.records;
laboratory/src/components/SelectMember/service.js
@@ -13,4 +13,10 @@
// 角色列表不分页
export const getRoleList = (data) => {
    return axios.post('/system/role/listNotPage', { ...data })
}
}
// 获取项目列表 获取用户列表-不分页-根据角色筛选
export const listByRole = (data) => {
    return axios.get('/system/user/listByRole', { params:data })
}
laboratory/src/views/dataManagement/schemeManagement/addPlan.vue
@@ -70,12 +70,12 @@
          </div>
          <div class="content-box">
            <div class="content-box-left">
              <div>项目课题方案名称:{{ groupTableData[0].projectName }}</div>
              <div>实验编号:{{ groupTableData[0].experimentCode }}</div>
              <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[0].projectCode }}</div>
              <div>实验名称: {{ groupTableData[0].experimentName }}</div>
              <div>项目课题方案编号: {{ groupTableData && groupTableData.length > 0 ? groupTableData[0].projectCode : '' }}</div>
              <div>实验名称: {{ groupTableData && groupTableData.length > 0 ? groupTableData[0].experimentName : '' }}</div>
            </div>
          </div>
        </div>
@@ -250,6 +250,19 @@
      editId: null, // 编辑的ID
      viewMaterialData: [], // 查看模式的材料数据
      viewEquipmentData: [], // 查看模式的设备数据
      // 状态映射表
      statusTypeMap: {
        "-1": "info",
        "1": "warning",
        "2": "success",
        "3": "info"
      },
      statusTextMap: {
        "-1": "草稿箱",
        "1": "待确认",
        "2": "已确认",
        "3": "已封存"
      }
    };
  },
  async created() {
@@ -261,182 +274,39 @@
    }
  },
  methods: {
    // ===== 人员相关方法 =====
    addMember() {
      this.$refs.selectMember.open(this.participantsData, []);
    },
    handleMaterialSubmit(data) {
      // 处理实验材料数据
      this.form.experimentMaterial = data;
    handleMemberSubmit(selectedMembers) {
      this.selectedParticipants = selectedMembers;
      this.$refs.selectMember.close();
    },
    handleEquipmentSubmit(data) {
      // 处理实验设备数据
      this.form.experimentDevice = data;
    handleEditMember() {
      this.$refs.selectMember.open(this.participantsData, this.selectedParticipants);
    },
    handleSave() {
      // 先获取所有动态组件的数据
      this.$refs.materialComponent.submit();
      this.$refs.equipmentComponent.submit();
      // 获取所有步骤内容 - 添加错误检查
      this.stepList.forEach((step, index) => {
        const stepContentRef = this.$refs['stepContent' + index];
        console.log('stepContentRef', stepContentRef)
        const editor = Array.isArray(stepContentRef) ? stepContentRef[0] : stepContentRef;
        if (editor && typeof editor.submit === 'function') {
          editor.submit();
        }
      });
      console.log('材料数据', this.form.experimentMaterial)
      console.log('设备数据', this.form.experimentDevice)
      console.log('步骤数据', this.form.stepList)
      // 然后进行表单校验
      this.$refs.form.validate((valid) => {
        if (valid && this.validateContent()) {
          // 构建提交数据
          const formData = {
            ...this.form,
            // 实验日期,使用 moment 格式化为指定格式
            experimentDate: moment(this.form.experimentDate).format('YYYY-MM-DD HH:mm:ss'),
            // 实验调度ID,从选中的调度数据中获取
            dispatchId: this.groupTableData[0]?.id,
            // 实验设备,转换为JSON字符串
            experimentDevice: this.form.experimentDevice,
            // 实验材料,转换为JSON字符串
            experimentMaterial: this.form.experimentMaterial,
            // 实验目的,从富文本编辑器获取内容
            experimentObjective: this.$refs.purposeEditor.getContent(),
            // 工艺参数及路线,从富文本编辑器获取内容
            experimentParamRoute: this.$refs.processEditor.getContent(),
            // 实验方案人员,包含用户ID、昵称和角色类型
            experimentSchemePersons: this.selectedParticipants.map(person => ({
              userId: person.userId,    // 用户ID
              nickName: person.nickName, // 用户昵称
              roleType: person.roleType,  // 角色类型
              commitTime: moment().format('YYYY-MM-DD HH:mm:ss'),
            })),
            // 实验步骤记录,转换为JSON字符串,包含步骤名称和内容
            experimentStepRecord: this.stepList.map(step => ({
              stepName: step.stepName,  // 步骤名称
              content: step.content     // 步骤内容
            })),
            // 状态:1=已发送
            status: 1,
            // 提交时间,使用 moment 格式化为指定格式
            commitTime: moment().format('YYYY-MM-DD HH:mm:ss'),
          };
          console.log('formData 提交数据', formData)
          // 调用添加接口
          add(formData).then(res => {
            if (res.code === 200) {
              this.$message.success('保存成功');
              this.$router.go(-1)
              // 可以在这里添加跳转逻辑
            } else {
              this.$message.error(res.msg || '保存失败');
            }
          }).catch(err => {
            this.$message.error('保存失败');
            console.error('保存失败:', err);
          });
        } else {
          // 获取第一个错误字段
          const firstError = this.$refs.form.fields.find(field => field.validateState === 'error');
          if (firstError) {
            // 滚动到错误字段
            this.$nextTick(() => {
              firstError.$el.scrollIntoView({ behavior: 'smooth', block: 'center' });
            });
          }
        }
      });
    },
    handleSaveDraft() {
      // 先获取所有动态组件的数据
      this.$refs.materialComponent.submit();
      this.$refs.equipmentComponent.submit();
      // 获取所有步骤内容 - 添加错误检查
      this.stepList.forEach((step, index) => {
        const stepContentRef = this.$refs['stepContent' + index];
        if (stepContentRef && typeof stepContentRef.submit === 'function') {
          stepContentRef.submit();
        }
      });
      // 然后进行表单校验
      this.$refs.form.validate((valid) => {
        if (valid && this.validateContent()) {
          // 构建草稿数据
          const formData = {
            ...this.form,
            // 实验日期,使用 moment 格式化为指定格式
            experimentDate: moment(this.form.experimentDate).format('YYYY-MM-DD HH:mm:ss'),
            // 实验调度ID,从选中的调度数据中获取
            dispatchId: this.groupTableData[0]?.id,
            // 实验设备,转换为JSON字符串
            experimentDevice: JSON.stringify(this.form.experimentDevice),
            // 实验材料,转换为JSON字符串
            experimentMaterial: JSON.stringify(this.form.experimentMaterial),
            // 实验目的,从富文本编辑器获取内容
            experimentObjective: this.$refs.purposeEditor.getContent(),
            // 工艺参数及路线,从富文本编辑器获取内容
            experimentParamRoute: this.$refs.processEditor.getContent(),
            // 实验方案人员,包含用户ID、昵称和角色类型
            experimentSchemePersons: this.selectedParticipants.map(person => ({
              userId: person.userId,    // 用户ID
              nickName: person.nickName, // 用户昵称
              roleType: person.roleType  // 角色类型
            })),
            // 实验步骤记录,转换为JSON字符串,包含步骤名称和内容
            experimentStepRecord: JSON.stringify(this.stepList.map(step => ({
              stepName: step.stepName,  // 步骤名称
              content: step.content     // 步骤内容
            }))),
            // 状态:-1=草稿箱
            status: -1,
            // 提交时间,使用 moment 格式化为指定格式
            commitTime: moment().format('YYYY-MM-DD HH:mm:ss'),
          };
          // 调用添加接口
          add(formData).then(res => {
            if (res.code === 200) {
              this.$message.success('草稿保存成功');
              // 可以在这里添加跳转逻辑
            } else {
              this.$message.error(res.msg || '草稿保存失败');
            }
          }).catch(err => {
            this.$message.error('草稿保存失败');
            console.error('草稿保存失败:', err);
          });
        } else {
          // 获取第一个错误字段
          const firstError = this.$refs.form.fields.find(field => field.validateState === 'error');
          if (firstError) {
            // 滚动到错误字段
            this.$nextTick(() => {
              firstError.$el.scrollIntoView({ behavior: 'smooth', block: 'center' });
            });
          }
        }
      });
    },
    // ===== 步骤相关方法 =====
    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("确认删除该步骤吗?删除后步骤内容将无法恢复", "警告", {
@@ -451,14 +321,108 @@
        })
        .catch(() => { });
    },
    handleEditStep(index) {
      this.editingStepIndex = index;
      this.$refs.addStepDialog.open(true);
      this.$refs.addStepDialog.setStepName(this.stepList[index].stepName);
    },
    handleStepContentSubmit(index, content) {
      console.log('步骤内容', 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 {
@@ -467,37 +431,37 @@
      };
    },
    validateContent() {
      // // 校验实验调度
      // if (!this.groupTableData || this.groupTableData.length === 0) {
      //   this.$message.error("请选择实验调度");
      //   return false;
      // }
      // 校验实验调度
      if (!this.groupTableData || this.groupTableData.length === 0) {
        this.$message.error("请选择实验调度");
        return false;
      }
      // // 校验实验日期
      // if (!this.form.experimentDate) {
      //   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;
      // }
      // 校验参与人员
      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;
      // }
      // 校验实验目的
      const purpose = this.$refs.purposeEditor.getContent();
      if (!purpose || purpose === '<p></p>' || purpose.trim() === '<p></p>') {
        this.$message.error("请填写实验目的");
        return false;
      }
      // // 校验工艺参数及路线
      // const process = this.$refs.processEditor.getContent();
      // if (!process || process === '<p></p>' || process.trim() === '<p></p>') {
      //   this.$message.error("请填写工艺参数及路线");
      //   return false;
      // }
      // 校验工艺参数及路线
      const process = this.$refs.processEditor.getContent();
      if (!process || process === '<p></p>' || process.trim() === '<p></p>') {
        this.$message.error("请填写工艺参数及路线");
        return false;
      }
      // 校验实验材料
      if (!this.form.experimentMaterial) {
@@ -518,11 +482,10 @@
      }
      // 校验每个步骤是否都有内容
      for (let i = 0; i < this.stepList.length; i++) {
        if (!this.stepList[i].content) {
          this.$message.error(`请完善第${i + 1}个步骤的内容`);
          return false;
        }
      const invalidStep = this.stepList.findIndex(step => !step.content);
      if (invalidStep !== -1) {
        this.$message.error(`请完善第${invalidStep + 1}个步骤的内容`);
        return false;
      }
      return true;
@@ -531,26 +494,14 @@
      this.$router.push("/dataManagement/scheme-management/stop-experiment");
    },
    getStatusType(status) {
      const statusMap = {
        "-1": "info",
        "1": "warning",
        "2": "success",
        "3": "info"
      };
      return statusMap[status] || "info";
      return this.statusTypeMap[status] || "info";
    },
    getStatusText(status) {
      const statusMap = {
        "-1": "草稿箱",
        "1": "待确认",
        "2": "已确认",
        "3": "已封存"
      };
      return statusMap[status] || "未知";
      return this.statusTextMap[status] || "未知";
    },
    handleSchedulingSubmit(data) {
      this.groupTableData = data;
      if (data && data.length > 0) {
      this.groupTableData = data || [];
      if (data && data.length > 0 && data[0].id) {
        getGroupByDispatchId({ dispatchId: data[0].id }).then(res => {
          if (res) {
            this.groupData = res || [];
@@ -577,141 +528,115 @@
    handleSchedulingClose() {
      this.showScheduling = false;
    },
    handleMemberSubmit(selectedMembers) {
      this.selectedParticipants = selectedMembers;
      this.$refs.selectMember.close();
    },
    handleEditMember() {
      this.$refs.selectMember.open(this.participantsData, this.selectedParticipants);
    },
    // 加载编辑数据
    // ===== 数据加载方法 =====
    async loadEditData() {
      try {
        const res = await getDetail({ id: this.editId });
        console.log('编辑数据', res);
        if (res) {
          const data = res;
          // 填充基本表单数据
          this.form.experimentDate = data.experimentDate;
          // 填充实验调度信息
          if (data.experimentDispatch && data.experimentDispatch.id) {
            this.form.dispatchId = data.experimentDispatch.id;
            // 获取组别信息
            try {
              const groupRes = await getGroupByDispatchId({ dispatchId: data.experimentDispatch.id });
              if (groupRes) {
                this.groupData = groupRes || [];
              }
            } catch (err) {
              console.error('获取组别列表失败:', err);
            }
            // 构建调度表格数据
            this.groupTableData = [{ ...data.experimentDispatch }];
          }
          // 填充参与人员
          if (data.experimentSchemePersons) {
            this.selectedParticipants = Array.isArray(data.experimentSchemePersons)
              ? data.experimentSchemePersons
              : JSON.parse(data.experimentSchemePersons || '[]');
          }
          // 填充富文本编辑器内容
          this.editorContents.purpose = data.experimentObjective || '';
          this.editorContents.process = data.experimentParamRoute || '';
          // 填充实验材料和设备(编辑模式下转换为查看格式)
          if (data.experimentMaterial) {
            try {
              const materialData = typeof data.experimentMaterial === 'string'
                ? JSON.parse(data.experimentMaterial)
                : data.experimentMaterial;
              this.form.experimentMaterial = materialData;
            } catch (err) {
              console.error('解析实验材料数据失败:', err);
              this.viewMaterialData = [];
            }
          }
          if (data.experimentDevice) {
            try {
              const deviceData = typeof data.experimentDevice === 'string'
                ? JSON.parse(data.experimentDevice)
                : data.experimentDevice;
              this.form.experimentDevice = deviceData;
            } catch (err) {
              console.error('解析实验设备数据失败:', err);
              this.viewEquipmentData = [];
            }
          }
          // 填充实验步骤(编辑模式下步骤内容也要转换为查看格式)
          if (data.experimentStepRecord) {
            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 && typeof editor.setInitialData === 'function') {
                    editor.setInitialData(step.content);
                  }
                }
              });
            }
          });
        } else {
          this.$message.error(res.msg || '获取详情失败');
          // this.$router.go(-1);
        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);
        // this.$router.go(-1);
      }
    },
    // 转换数据格式为ViewDynamicComponent需要的格式
    convertToViewFormat(data) {
      if (!data || !Array.isArray(data)) return [];
laboratory/src/views/dataManagement/schemeManagement/components/approvalDialog.vue
@@ -521,24 +521,54 @@
  border-bottom: 1px solid #e4e7ed;
}
::v-deep .el-dialog__body {
  padding: 20px;
  max-height: 80vh;
  overflow: hidden;
}
@media screen and (max-width: 1200px) {
  ::v-deep .el-dialog__body {
    max-height: none;
    overflow: auto;
  }
}
.approval-dialog {
  display: flex;
  height: 60vh;
  padding:20px;
  overflow: hidden;
  @media screen and (max-width: 1200px) {
    flex-direction: column;
    height: auto;
    .approval-content, .approval-flow {
      width: 100%;
      margin-right: 0;
      margin-bottom: 20px;
      height: 50vh;
    }
  }
  .approval-content {
    flex: 1;
    flex: 7;
    margin-right: 20px;
    background: #ffffff;
    box-shadow: 0px 4px 12px 4px rgba(0, 0, 0, 0.08);
    border-radius: 10px;
    overflow-y: auto;
  }
  .approval-flow {
    flex: 3;
    min-width: 350px;
    padding: 40px 20px;
    width: 405px;
    background: #ffffff;
    box-shadow: 0px 4px 12px 4px rgba(0, 0, 0, 0.08);
    border-radius: 10px;
    overflow-y: auto;
    .flow-title {
      font-size: 16px;
laboratory/src/views/dataManagement/schemeManagement/list.vue
@@ -23,6 +23,7 @@
          <el-form-item label="状态:">
            <el-select v-model="form.status" placeholder="请选择">
              <el-option label="全部" value=""></el-option>
              <el-option label="草稿" :value="-1"></el-option>
              <el-option label="已发送" :value="1"></el-option>
              <el-option label="申请中止待审核" :value="2"></el-option>
              <el-option label="申请中止已通过" :value="3"></el-option>
@@ -95,7 +96,7 @@
            <!-- 实验员(5) -->
            <template v-if="userRole == '5'">
              <el-button type="text" @click="handleEdit(scope.row)">编辑</el-button>
              <el-button type="text" @click="handleEdit(scope.row)" v-if="scope.row.status == 1">编辑</el-button>
            </template>
          </template>
        </el-table-column>
@@ -156,11 +157,19 @@
  methods: {
    handlePageChange(page) {
      this.form.pageNum = page;
      // 当处于草稿箱模式时,强制将状态设置为-1
      if (this.currentType === 'draft') {
        this.form.status = -1;
      }
      this.getTableData();
    },
    handleSizeChange(size) {
      this.form.pageSize = size;
      this.form.pageNum = 1;
      // 当处于草稿箱模式时,强制将状态设置为-1
      if (this.currentType === 'draft') {
        this.form.status = -1;
      }
      this.getTableData();
    },
    resetForm() {
@@ -174,10 +183,18 @@
        pageNum: 1,
        pageSize: 10
      };
      // 当处于草稿箱模式时,强制将状态设置为-1
      if (this.currentType === 'draft') {
        this.form.status = -1;
      }
      this.getTableData();
    },
    handleSearch() {
      this.form.pageNum = 1;
      // 当处于草稿箱模式时,强制将状态设置为-1
      if (this.currentType === 'draft') {
        this.form.status = -1;
      }
      this.getTableData();
    },
    getStatusType(status) {
@@ -187,7 +204,8 @@
        '2': "warning",
        '3': "success",
        '4': "danger",
        '5': "info"
        '5': "info",
        '6':'success'
      };
      return statusMap[status] || "info";
    },
@@ -198,7 +216,8 @@
        '2': "申请中止待审核",
        '3': "申请中止已通过",
        '4': "申请中止已驳回",
        '5': "已封存"
        '5': "已封存",
        '6':'实验员已提交'
      };
      return statusMap[status] || "未知";
    },
@@ -219,6 +238,10 @@
    },
    async getTableData() {
      try {
        // 当处于草稿箱模式时,强制将状态设置为-1
        if (this.currentType === 'draft') {
          this.form.status = -1;
        }
        const { data } = await getList(this.form);
        this.tableData = data.records || [];
        this.total = data.total || 0;