董国庆
2025-06-21 8fcae32d5d75973c51c3f48c0e1797217059da1d
修改组件
4个文件已修改
213 ■■■■■ 已修改文件
laboratory/src/components/DynamicComponent/addTableData.vue 100 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/components/DynamicComponent/index.vue 108 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/utils/utils.js 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/dataManagement/schemeManagement/addPlan.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/components/DynamicComponent/addTableData.vue
@@ -53,16 +53,18 @@
                >
                  <el-upload
                    class="upload-demo"
                    action="#"
                    :file-list="spectrumList"
                    :auto-upload="false"
                    :action="uploadUrl"
                    :headers="uploadHeaders"
                    :file-list="imageList"
                    :auto-upload="true"
                    list-type="picture-card"
                    :on-change="handleSpectrumChange"
                    :on-remove="handleSpectrumRemove"
                    :on-change="handleImageChange"
                    :on-remove="handleImageRemove"
                    :on-success="handleImageSuccess"
                    :on-preview="handlePreview"
                    :disabled="!checkEditPermission(header)"
                  >
                    <i class="el-icon-plus"></i>
                    <!-- <div slot="tip" class="el-upload__tip">暂未连接服务器,使用默认图片</div> -->
                  </el-upload>
                </el-form-item>
                <el-form-item
@@ -140,11 +142,16 @@
      <el-button @click="handleClose">取 消</el-button>
      <el-button type="primary" @click="handleSubmit">确 定</el-button>
    </div>
    <el-dialog :visible.sync="imagePreviewVisible" append-to-body>
      <img width="100%" :src="imagePreviewUrl" alt="" />
    </el-dialog>
  </el-dialog>
</template>
  
<script>
import { listByRole } from './service';
import { getFullUrl } from '@/utils/utils';
import apiConfig from '@/utils/baseurl';
export default {
  name: "AddDialog",
@@ -173,9 +180,15 @@
      form: {},
      rules: {},
      photoList: [],
      spectrumList: [],
      imageList: [],
      defaultImageUrl: 'https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg', // 默认图片地址
      userOptions: []
      userOptions: [],
      imagePreviewVisible: false,
      imagePreviewUrl: '',
      uploadUrl: apiConfig.imgUrl,
      uploadHeaders: {
        Authorization: sessionStorage.getItem('token') || ''
      }
    };
  },
  computed: {
@@ -318,14 +331,13 @@
      }
      // 设置图谱列表
      if (data.spectrums && data.spectrums.length) {
        this.spectrumList = data.spectrums.map((spectrum) => ({
          name: spectrum.name,
          url: spectrum.url,
          status: "success",
        }));
      } else {
        this.spectrumList = [];
      this.imageList = [];
      const imageHeader = this.headerList.find(h => h.type === 'image');
      if (imageHeader && data[imageHeader.name]) {
        this.imageList = [{
          name: 'image',
          url: getFullUrl(data[imageHeader.name]),
        }];
      }
      // 重置表单校验状态
@@ -346,7 +358,7 @@
      this.dialogVisible = false;
      this.$refs.form?.resetFields();
      this.photoList = [];
      this.spectrumList = [];
      this.imageList = [];
      this.initFormData();
    },
    handleSubmit() {
@@ -356,7 +368,6 @@
          const submitData = {
            ...this.form,
            photos: this.photoList,
            spectrums: this.spectrumList,
          };
          
          // 为用户类型字段添加用户完整信息
@@ -380,32 +391,41 @@
        }
      });
    },
    handlePhotoChange(file, fileList) {
      this.photoList = fileList;
      this.$refs.form.validateField("photos");
    },
    handleSpectrumChange(file, fileList) {
      // 使用默认图片替代实际上传
      this.spectrumList = [{
        name: '默认图片.jpg',
        url: this.defaultImageUrl,
        status: 'success'
      }];
      // 同时更新form中对应的字段值以通过表单验证
    handleImageChange(file, fileList) {
      this.imageList = fileList;
      const imageHeader = this.headerList.find(h => h.type === 'image');
      if (imageHeader && imageHeader.name) {
        // 保存图片URL,这样在表格中可以直接使用
        this.$set(this.form, imageHeader.name, this.defaultImageUrl);
        console.log('设置图片字段:', imageHeader.name, this.defaultImageUrl);
      if (imageHeader) {
        this.$refs.form.validateField(imageHeader.name);
      }
      this.$refs.form.validateField("spectrums");
    },
    handleSpectrumRemove(file) {
      this.spectrumList = [];
    handleImageSuccess(res, file, fileList) {
      console.log('res, file, fileList',res, file, fileList)
      const url = res.msg;
      file.url = getFullUrl(url);
      const imageHeader = this.headerList.find(h => h.type === 'image');
      if (imageHeader) {
        this.$set(this.form, imageHeader.name, url);
        this.$refs.form.validateField(imageHeader.name);
      }
      this.imageList = fileList.map(f => {
        if (f.uid === file.uid) {
          return file;
        }
        return f;
      });
    },
    handleImageRemove(file, fileList) {
      const imageHeader = this.headerList.find(h => h.type === 'image');
      if (imageHeader) {
        this.$set(this.form, imageHeader.name, '');
      }
      this.imageList = fileList;
    },
    handlePreview(file) {
      this.imagePreviewUrl = file.url;
      this.imagePreviewVisible = true;
    },
    getFullUrl,
  },
  mounted() {
    // 获取用户列表数据
laboratory/src/components/DynamicComponent/index.vue
@@ -16,16 +16,17 @@
      <div v-for="(item, idx) in components" :key="item.id" class="dynamic-component">
        <!-- 富文本 -->
        <div v-if="item.type == 'richText'">
          <AiEditor :ref="`editor_${item.id}`" :value="item.data.content" height="200px" :readOnly="!editable" placeholder="请输入内容..."
            :disabled="!editable" />
          <AiEditor :ref="`editor_${item.id}`" :value="item.data.content" height="200px" :readOnly="!editable"
            placeholder="请输入内容..." :disabled="!editable" />
        </div>
        <!-- 自定义表格 -->
        <div v-else-if="item.type == 'customTable'" style="flex: 1">
          <div v-if="editable" class="table-actions">
            <el-button size="mini"  @click="showTableHeaderDialog(idx)">添加表头</el-button>
            <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" :key="item.id + '_' + JSON.stringify(item.data.rows).length">
          <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">
              <template slot-scope="scope">
@@ -35,10 +36,8 @@
                </template>
                <!-- 图片类型显示 -->
                <template v-else-if="header.type === 'image'">
                  <img v-if="scope.row[header.name]"
                       :src="getFullUrl(scope.row[header.name])"
                       alt="头像"
                       class="table-image" />
                  <img v-if="scope.row[header.name]" :src="getFullUrl(scope.row[header.name])" alt="头像"
                    class="table-image" />
                </template>
                <!-- 其他类型 -->
                <template v-else>
@@ -47,9 +46,9 @@
              </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">
            <el-table-column label="操作" min-width="200" v-if="dialogCanEdit">
              <template slot-scope="scope">
                <el-button type="text" @click="handleEditRow(idx, scope.$index)" >编辑</el-button>
                <el-button type="text" @click="handleEditRow(idx, scope.$index)">编辑</el-button>
                <el-button type="text" v-if="editable" @click="handleDeleteRow(idx, scope.$index)">删除</el-button>
              </template>
            </el-table-column>
@@ -57,7 +56,7 @@
        </div>
        <!-- 文件上传 -->
        <div v-else-if="item.type == 'fileUpload'">
          <el-upload v-if="editable" :http-request="customUploadRequest" :file-list="item.data.fileList"
          <el-upload v-if="editable" :action="uploadUrl" :headers="uploadHeaders" :file-list="item.data.fileList"
            :on-change="(file, fileList) => handleFileChange(idx, fileList)"
            :on-success="(res, file, fileList) => handleFileSuccess(res, file, fileList, idx)"
            list-type="text">
@@ -72,23 +71,21 @@
        <!-- 图片上传 -->
        <div v-else-if="item.type == 'imageUpload'">
          <div class="image-upload-container">
            <el-upload v-if="editable" :http-request="customUploadRequest" :file-list="item.data.imageList"
            <el-upload v-if="editable"
            :action="uploadUrl"
            :headers="uploadHeaders"
             :file-list="item.data.imageList"
              :on-change="(file, fileList) => handleImageChange(idx, fileList)"
              :on-success="(res, file, fileList) => handleImageSuccess(res, file, fileList, idx)"
              :auto-upload="true"
              :before-upload="beforeImageUpload"
              :on-success="(res, file, fileList) => handleImageSuccess(res, file, fileList, idx)" :auto-upload="true"
              :before-upload="beforeImageUpload"
              list-type="picture-card"
              :on-preview="(file) => handlePreview(file, idx)"
              class="image-uploader">
              :on-preview="(file) => handlePreview(file, idx)" class="image-uploader">
              <i class="el-icon-plus"></i>
              <div class="upload-text">上传图片</div>
            </el-upload>
            <div v-else class="image-preview">
              <el-image v-for="image in item.data.imageList"
                :key="image.uid"
                :src="getFullUrl(image.url)"
                :preview-src-list="item.data.imageList.map(img => getFullUrl(img.url))"
                class="preview-image" />
              <el-image v-for="image in item.data.imageList" :key="image.uid" :src="getFullUrl(image.url)"
                :preview-src-list="item.data.imageList.map(img => getFullUrl(img.url))" class="preview-image" />
            </div>
            <div class="uploaf-notice">支持.jpg .png格式</div>
          </div>
@@ -99,10 +96,10 @@
    </div>
    <addTableHeader  :visible.sync="tableHeaderDialog.visible" :participants="participants"
      @confirm="confirmAddHeader"></addTableHeader>
    <addTableData  :visible.sync="rowDialog.visible" :headerList="rowDialog.headers"
      :editData="rowDialog.form" :isEdit="rowDialog.isEdit" @success="confirmAddRow">
    <addTableHeader :visible.sync="tableHeaderDialog.visible" :participants="participants" @confirm="confirmAddHeader">
    </addTableHeader>
    <addTableData :visible.sync="rowDialog.visible" :headerList="rowDialog.headers" :editData="rowDialog.form"
      :isEdit="rowDialog.isEdit" @success="confirmAddRow">
    </addTableData>
    <el-dialog :visible.sync="imagePreviewVisible" width="auto" top="10vh" :show-close="true" v-if="imagePreviewUrl">
@@ -118,7 +115,7 @@
import addTableHeader from "./addTableHeader.vue";
import addTableData from "./addTableData.vue";
import apiConfig from '../../utils/baseurl'
import { customUploadRequest, getFullUrl } from '@/utils/utils'
import { getFullUrl } from '@/utils/utils'
export default {
  name: "DynamicComponent",
@@ -153,7 +150,11 @@
  },
  data() {
    return {
      apiConfig:apiConfig,
      apiConfig: apiConfig,
      uploadUrl: apiConfig.imgUrl,
      uploadHeaders: {
        Authorization: sessionStorage.getItem('token') || ''
      },
      showAddDialog: false,
      components: [],
      tableHeaderDialog: {
@@ -216,17 +217,17 @@
    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查找用户信息
@@ -235,12 +236,12 @@
          return user ? (user.nickName || user.userName || userId) : userId;
        }).join(', ');
      }
      // 情况3: 已经是字符串(可能是之前格式化过的)
      if (typeof rowData[fieldName] === 'string') {
        return rowData[fieldName];
      }
      // 默认返回空字符串
      return '';
    },
@@ -248,7 +249,7 @@
      if (!userArray || !Array.isArray(userArray) || userArray.length === 0) {
        return '';
      }
      // 查找参与者列表中的用户,获取昵称并用逗号拼接
      const userNames = userArray.map(userId => {
        const user = this.participants.find(p => p.userId === userId);
@@ -281,6 +282,7 @@
    submit() {
      const data = this.components.map(component => {
        let componentData = null;
        const prefix = apiConfig.showImgUrl;
        switch (component.type) {
          case 'richText':
@@ -296,10 +298,20 @@
            };
            break;
          case 'fileUpload':
            componentData = component.data.fileList;
            componentData = component.data.fileList.map(file => {
              if (file.url && file.url.startsWith(prefix)) {
                return { ...file, url: file.url.substring(prefix.length) };
              }
              return file;
            });
            break;
          case 'imageUpload':
            componentData = component.data.imageList;
            componentData = component.data.imageList.map(image => {
              if (image.url && image.url.startsWith(prefix)) {
                return { ...image, url: image.url.substring(prefix.length) };
              }
              return image;
            });
            break;
        }
@@ -315,18 +327,18 @@
      // if (!this.editable) return;
      const { idx, rowIndex, isEdit } = this.rowDialog;
      // 处理formData中的数据,保证用户信息的完整性
      const processedData = { ...formData };
      // 调试输出
      console.log('添加/编辑行数据:', processedData,'isEdit',isEdit);
      console.log('添加/编辑行数据:', processedData, 'isEdit', isEdit);
      if (isEdit) {
        // Vue无法检测到对象或数组深层属性的变化,使用Vue.set来确保响应式
        this.$set(
          this.components[idx].data.rows,
          rowIndex,
          this.components[idx].data.rows,
          rowIndex,
          {
            ...processedData,
            updateTime: new Date().toLocaleString()
@@ -339,15 +351,15 @@
          updateTime: new Date().toLocaleString()
        });
      }
      console.log('this.components',this.components);
      console.log('this.components', this.components);
      // 手动触发组件更新
      this.$forceUpdate();
      // 延迟发送事件,确保数据已更新
      this.$nextTick(() => {
        this.emitUpdate();
      });
      this.rowDialog.visible = false;
      this.rowDialog.form = {};
    },
@@ -449,7 +461,7 @@
    },
    handleFileSuccess(res, file, fileList, idx) {
      // 上传成功后设置真实 url
      file.url = res.data.url;
      file.url = this.getFullUrl(res.msg);
      this.components[idx].data.fileList = fileList;
      this.emitUpdate();
    },
@@ -461,7 +473,7 @@
    },
    handleImageSuccess(res, file, fileList, idx) {
      // 上传成功后设置真实 url
      file.url = res.data.url;
      file.url = this.getFullUrl(res.msg);
      this.components[idx].data.imageList = fileList;
      this.emitUpdate();
    },
@@ -478,6 +490,7 @@
        this.$message.error('上传图片大小不能超过 2MB!');
        return false;
      }
      this.imagePreviewVisible = true;
      return true;
    },
    handlePreview(file, idx) {
@@ -492,6 +505,7 @@
      const updatedComponents = JSON.parse(JSON.stringify(this.components));
      this.$emit('update:dataSource', updatedComponents);
    },
    getFullUrl,
  },
  computed: {
  },
laboratory/src/utils/utils.js
@@ -25,11 +25,9 @@
  axios.post(uploadUrl, formData, { headers: uploadHeaders })
    .then(res => {
      console.log('22222',res)
      onSuccess(res.data);
    })
    .catch(err => {
      console.log('222222222222',err)
      onError(err);
    });
};
laboratory/src/views/dataManagement/schemeManagement/addPlan.vue
@@ -241,6 +241,7 @@
          { required: true, message: "请添加实验设备", trigger: "change" },
        ],
      },
      userRole:'',
      groupTableData: [],
      groupData: [],
      taskTableData: [],
@@ -266,6 +267,8 @@
    };
  },
  async created() {
    const userInfo=JSON.parse(sessionStorage.getItem('userInfo') || '{}');
    this.userRole=userInfo.roleType || '';
    // 检查是否为编辑模式
    if (this.$route.query.type === 'edit' && this.$route.query.id) {
      this.isEdit = true;