From 9cb1c3c39136c89974bc4049fca5e450e757b1be Mon Sep 17 00:00:00 2001
From: 13404089107 <puwei@sinata.cn>
Date: 星期五, 15 八月 2025 17:51:03 +0800
Subject: [PATCH] fix

---
 laboratory/src/components/DynamicComponent/index.vue |  183 +++++++++++++++++++++++++++++----------------
 1 files changed, 119 insertions(+), 64 deletions(-)

diff --git a/laboratory/src/components/DynamicComponent/index.vue b/laboratory/src/components/DynamicComponent/index.vue
index 8faa19a..218e9c9 100644
--- a/laboratory/src/components/DynamicComponent/index.vue
+++ b/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="400px" :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">
@@ -33,12 +34,25 @@
                 <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 v-if="Array.isArray(scope.row[header.name])">
+                    <el-image
+                      v-for="(img, i) in scope.row[header.name]"
+                      :key="i"
+                      :src="getFullUrl(img)"
+                      :preview-src-list="scope.row[header.name].map(getFullUrl)"
+                      class="table-image"
+                    />
+                  </template>
+                  <template v-else>
+                    <el-image
+                      v-if="scope.row[header.name]"
+                      :src="getFullUrl(scope.row[header.name])"
+                      :preview-src-list="[getFullUrl(scope.row[header.name])]"
+                      class="table-image"
+                    />
+                  </template>
                 </template>
                 <!-- 其他类型 -->
                 <template v-else>
@@ -47,9 +61,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,29 +71,36 @@
         </div>
         <!-- 文件上传 -->
         <div v-else-if="item.type == 'fileUpload'">
-          <el-upload v-if="editable" action="#" :file-list="item.data.fileList"
-            :on-change="(file, fileList) => handleFileChange(idx, fileList)" list-type="text">
+          <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">
             <el-button size="small" icon="el-icon-upload2">点击上传</el-button>
           </el-upload>
           <div v-else>
-            <div v-for="file in item.data.fileList" :key="file.uid" class="file-list-item">
-              {{ file.name }}
+            <div v-for="file in item.data.fileList" :key="file.uid" class="file-list-item" >
+              <span style="color: #409EFF; cursor: pointer;" @click="downloadFileByUrl(file.url, file.name)">{{ file.name }}</span>
             </div>
           </div>
         </div>
         <!-- 图片上传 -->
         <div v-else-if="item.type == 'imageUpload'">
           <div class="image-upload-container">
-            <el-upload v-if="editable" action="#" :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"
-              :http-request="() => { }" :before-upload="beforeImageUpload" list-type="picture-card"
-              class="image-uploader">
+              :before-upload="beforeImageUpload" 
+              list-type="picture-card"
+              :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">
-              <img v-for="image in item.data.imageList" :key="image.uid" :src="image.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>
@@ -90,11 +111,15 @@
     </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">
+      <img :src="imagePreviewUrl" style="max-width:80vw;max-height:70vh;display:block;margin:auto;" />
+    </el-dialog>
   </div>
 </template>
 
@@ -104,6 +129,9 @@
 import Table from "../Table/index.vue";
 import addTableHeader from "./addTableHeader.vue";
 import addTableData from "./addTableData.vue";
+import apiConfig from '../../utils/baseurl'
+import { getFullUrl } from '@/utils/utils'
+import { downloadFileByUrl } from '@/utils/utils'
 
 export default {
   name: "DynamicComponent",
@@ -138,6 +166,11 @@
   },
   data() {
     return {
+      apiConfig: apiConfig,
+      uploadUrl: apiConfig.imgUrl,
+      uploadHeaders: {
+        Authorization: sessionStorage.getItem('token') || ''
+      },
       showAddDialog: false,
       components: [],
       tableHeaderDialog: {
@@ -155,6 +188,8 @@
       },
       headerList: [],
       defaultImageUrl: 'https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg', // 默认图片地址
+      imagePreviewVisible: false,
+      imagePreviewUrl: '',
     };
   },
   watch: {
@@ -176,9 +211,15 @@
                 break;
               case 'fileUpload':
                 componentData = { fileList: component.data };
+                console.log('component.data component.data',component.data)
                 break;
               case 'imageUpload':
-                componentData = { imageList: component.data };
+                componentData = { imageList: component.data.map(item=>{
+                  return {
+                    ...item,
+                    url: getFullUrl(item.url),
+                  }
+                }) };
                 break;
             }
             return {
@@ -195,20 +236,22 @@
     }
   },
   methods: {
+    getFullUrl,
+    downloadFileByUrl,
     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查找用户信息
@@ -217,12 +260,12 @@
           return user ? (user.nickName || user.userName || userId) : userId;
         }).join(', ');
       }
-      
+
       // 情况3: 已经是字符串(可能是之前格式化过的)
       if (typeof rowData[fieldName] === 'string') {
         return rowData[fieldName];
       }
-      
+
       // 默认返回空字符串
       return '';
     },
@@ -230,7 +273,7 @@
       if (!userArray || !Array.isArray(userArray) || userArray.length === 0) {
         return '';
       }
-      
+
       // 查找参与者列表中的用户,获取昵称并用逗号拼接
       const userNames = userArray.map(userId => {
         const user = this.participants.find(p => p.userId === userId);
@@ -263,6 +306,7 @@
     submit() {
       const data = this.components.map(component => {
         let componentData = null;
+        const prefix = apiConfig.showImgUrl;
 
         switch (component.type) {
           case 'richText':
@@ -278,10 +322,21 @@
             };
             break;
           case 'fileUpload':
-            componentData = component.data.fileList;
+            componentData = component.data.fileList.map(file => {
+              console.log('fileUpload fileUpload fileUpload',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;
         }
 
@@ -297,18 +352,16 @@
       // if (!this.editable) return;
 
       const { idx, rowIndex, isEdit } = this.rowDialog;
-      
+
       // 处理formData中的数据,保证用户信息的完整性
       const processedData = { ...formData };
-      
+
       // 调试输出
-      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()
@@ -321,15 +374,14 @@
           updateTime: new Date().toLocaleString()
         });
       }
-      console.log('this.components',this.components);
-      
+
       // 手动触发组件更新
       this.$forceUpdate();
       // 延迟发送事件,确保数据已更新
       this.$nextTick(() => {
         this.emitUpdate();
       });
-      
+
       this.rowDialog.visible = false;
       this.rowDialog.form = {};
     },
@@ -425,49 +477,50 @@
     },
     handleFileChange(idx, fileList) {
       if (!this.editable) return;
-
-      fileList = fileList.map(file => {
-        if (!file.url) {
-          file.url = 'https://picsum.photos/200/200';
-        }
-        if (!file.name) {
-          file.name = '默认文件.txt';
-        }
-        return file;
-      });
+      // 只做 fileList 同步
+      this.components[idx].data.fileList = fileList;
+      this.emitUpdate();
+    },
+    handleFileSuccess(res, file, fileList, idx) {
+      // 上传成功后设置真实 url
+      file.url = this.getFullUrl(res.msg);
       this.components[idx].data.fileList = fileList;
       this.emitUpdate();
     },
     handleImageChange(idx, fileList) {
       if (!this.editable) return;
-
-      fileList = fileList.map(file => {
-        if (!file.url) {
-          file.url = 'https://picsum.photos/200/200';
-        }
-        return file;
-      });
+      // 只做 imageList 同步
       this.components[idx].data.imageList = fileList;
       this.emitUpdate();
     },
     handleImageSuccess(res, file, fileList, idx) {
-      file.url = 'https://picsum.photos/200/200';
+      // 上传成功后设置真实 url
+      file.url = this.getFullUrl(res.msg);
       this.components[idx].data.imageList = fileList;
+      this.emitUpdate();
     },
     beforeImageUpload(file) {
       const isJPG = file.type === 'image/jpeg';
       const isPNG = file.type === 'image/png';
-      const isLt2M = file.size / 1024 / 1024 < 2;
+      // const isLt2M = file.size / 1024 / 1024 < 2;
 
       if (!isJPG && !isPNG) {
         this.$message.error('上传图片只能是 JPG 或 PNG 格式!');
         return false;
       }
-      if (!isLt2M) {
-        this.$message.error('上传图片大小不能超过 2MB!');
-        return false;
-      }
+      // if (!isLt2M) {
+      //   this.$message.error('上传图片大小不能超过 2MB!');
+      //   return false;
+      // }
+      this.imagePreviewVisible = true;
       return true;
+    },
+    handlePreview(file, idx) {
+      // 使用el-image的preview-src-list实现预览
+      // 这里直接用Element的图片预览能力,实际上el-upload会自动处理
+      // 但如果你想自定义弹窗,可以用如下代码:
+      this.imagePreviewUrl = this.getFullUrl(file.url);
+      this.imagePreviewVisible = true;
     },
     emitUpdate() {
       // 先创建新对象,这有助于触发更新
@@ -475,6 +528,8 @@
       this.$emit('update:dataSource', updatedComponents);
     },
   },
+  computed: {
+  },
 };
 </script>
 

--
Gitblit v1.7.1