Bläddra i källkod

修复图片上传bug

sunshibo 2 månader sedan
förälder
incheckning
eb5daea6c7
1 ändrade filer med 40 tillägg och 187 borttagningar
  1. 40 187
      src/views/storeDecoration/personnelConfig/index.vue

+ 40 - 187
src/views/storeDecoration/personnelConfig/index.vue

@@ -710,7 +710,7 @@ const formData = reactive({
   description: ""
 });
 
-// 同步组件内部文件列表到 formData
+// 同步组件内部文件列表到 formData(避免上传中因过滤 blob 导致列表被清空或重复)
 const syncFileListFromComponent = async () => {
   if (!backgroundImagesUploadRef.value || !dialogVisible.value) return;
 
@@ -719,47 +719,43 @@ const syncFileListFromComponent = async () => {
     if (componentInstance && componentInstance._fileList) {
       const internalFileList = componentInstance._fileList.value || componentInstance._fileList;
       if (Array.isArray(internalFileList)) {
+        // 若组件内仍有 blob URL,说明还有文件在上传中,不覆盖 formData,避免清空或重复
+        const hasUploading = internalFileList.some((file: UploadUserFile) => file?.url && String(file.url).startsWith("blob:"));
+        if (hasUploading) return;
+
         // 同步内部文件列表到 formData(排除 blob URL,只保留服务器 URL)
         const validFiles = internalFileList
           .filter((file: UploadUserFile) => {
             const hasUrl = file && file.url && typeof file.url === "string" && file.url.trim() !== "";
-            // 排除 blob URL,只保留服务器 URL
-            const isBlobUrl = hasUrl && file.url.startsWith("blob:");
+            const isBlobUrl = hasUrl && (file.url as string).startsWith("blob:");
             return hasUrl && !isBlobUrl;
           })
-          .map((file: UploadUserFile) => {
-            // 确保每个文件对象都有必要的属性
-            return {
-              ...file,
-              url: file.url!.trim(),
-              name: file.name || file.url!.split("/").pop() || "image",
-              uid: file.uid || `file-${Date.now()}-${Math.random()}`
-            };
-          });
+          .map((file: UploadUserFile) => ({
+            ...file,
+            url: file.url!.trim(),
+            name: file.name || file.url!.split("/").pop() || "image",
+            uid: file.uid ?? `file-${Date.now()}-${Math.random()}`
+          }));
+
+        // 按 URL 去重,避免同一张图出现多次
+        const seenUrls = new Set<string>();
+        const uniqueFiles = validFiles.filter((f: { url?: string }) => {
+          const u = f.url?.trim();
+          if (!u || seenUrls.has(u)) return false;
+          seenUrls.add(u);
+          return true;
+        });
 
-        // 检查是否需要更新(比较 URL 列表,避免不必要的更新)
-        // 只比较非 blob URL 的 URLs
         const currentUrls = formData.backgroundImages
-          .filter((f: UploadUserFile) => f && f.url && !f.url.startsWith("blob:"))
+          .filter((f: UploadUserFile) => f && f.url && !(f.url as string).startsWith("blob:"))
           .map((f: UploadUserFile) => f.url!.trim())
           .sort();
-        const newUrls = validFiles.map((f: UploadUserFile) => f.url!.trim()).sort();
+        const newUrls = uniqueFiles.map((f: { url?: string }) => (f.url || "").trim()).sort();
 
-        // 未传背景时不以组件内残留数据覆盖:表单为空且组件有项,说明是上次编辑的残留,不覆盖
-        if (formData.backgroundImages.length === 0 && validFiles.length > 0) return;
+        if (formData.backgroundImages.length === 0 && uniqueFiles.length > 0) return;
 
-        // 如果不一致,更新 formData(直接使用组件内部的文件列表)
         if (JSON.stringify(currentUrls) !== JSON.stringify(newUrls)) {
-          // 直接使用组件内部的文件列表,确保数据一致
-          formData.backgroundImages = [...validFiles];
-
-          console.log("同步文件列表成功,更新数量:", validFiles.length);
-          console.log(
-            "同步后的文件列表 URLs:",
-            formData.backgroundImages.map(f => f.url)
-          );
-
-          // 触发验证
+          formData.backgroundImages = [...uniqueFiles] as UploadUserFile[];
           await nextTick();
           if (formRef.value) {
             formRef.value.validateField("backgroundImages");
@@ -772,157 +768,11 @@ const syncFileListFromComponent = async () => {
   }
 };
 
-// 背景图片上传成功回调
-const handleBackgroundImageSuccess = async (url: string) => {
-  console.log("=== 背景图片上传成功回调 ===");
-  console.log("上传成功的URL:", url);
-  console.log("当前 formData.backgroundImages 数量:", formData.backgroundImages.length);
-  console.log(
-    "当前 formData.backgroundImages URLs:",
-    formData.backgroundImages.map(f => f?.url)
-  );
-
-  // 立即将新上传的 URL 添加到 formData(如果还没有的话)
-  const urlExists = formData.backgroundImages.some((file: UploadUserFile) => {
-    return file && file.url && file.url.trim() === url.trim();
-  });
-
-  if (!urlExists) {
-    console.log("新上传的 URL 不在 formData 中,立即添加");
-    const newFile: UploadUserFile = {
-      uid: `upload-${Date.now()}-${Math.random()}`,
-      name: url.split("/").pop() || "image.jpg",
-      url: url.trim(),
-      status: "success" as const,
-      response: { fileUrl: url }
-    };
-    formData.backgroundImages = [...formData.backgroundImages, newFile];
-    console.log("添加新文件后的 formData.backgroundImages 数量:", formData.backgroundImages.length);
-    console.log(
-      "添加新文件后的 formData.backgroundImages URLs:",
-      formData.backgroundImages.map(f => f.url)
-    );
-  }
-
-  // 等待组件更新完成(el-upload 的 onSuccess 可能需要时间)
-  await nextTick();
-  await nextTick();
+// 背景图片上传成功回调(仅做校验触发,不重复添加文件,避免与 UploadImgs 的 v-model/on-change 重复导致多传)
+const handleBackgroundImageSuccess = async (_url: string) => {
   await nextTick();
-
-  // 使用轮询方式,确保组件内部已完全更新
-  let retryCount = 0;
-  const maxRetries = 15;
-
-  while (retryCount < maxRetries) {
-    if (backgroundImagesUploadRef.value) {
-      try {
-        const componentInstance = backgroundImagesUploadRef.value;
-        if (componentInstance && componentInstance._fileList) {
-          const internalFileList = componentInstance._fileList.value || componentInstance._fileList;
-          if (Array.isArray(internalFileList)) {
-            // 获取所有有效文件(排除 blob URL)
-            const validFiles = internalFileList
-              .filter((file: UploadUserFile) => {
-                const hasUrl = file && file.url && typeof file.url === "string" && file.url.trim() !== "";
-                const isBlobUrl = hasUrl && file.url.startsWith("blob:");
-                return hasUrl && !isBlobUrl;
-              })
-              .map((file: UploadUserFile) => ({
-                ...file,
-                url: file.url!.trim(),
-                name: file.name || file.url!.split("/").pop() || "image",
-                uid: file.uid || `file-${Date.now()}-${Math.random()}`
-              }));
-
-            // 检查新上传的 URL 是否已经在组件内部的文件列表中
-            const hasNewUrl = validFiles.some((file: UploadUserFile) => {
-              return file && file.url && file.url.trim() === url.trim();
-            });
-
-            console.log(`轮询第 ${retryCount + 1} 次 - 组件内部文件数量: ${validFiles.length}, 是否包含新URL: ${hasNewUrl}`);
-            console.log(
-              `轮询第 ${retryCount + 1} 次 - 组件内部文件 URLs:`,
-              validFiles.map(f => f.url)
-            );
-
-            if (hasNewUrl || retryCount >= maxRetries - 1) {
-              // 合并 formData 和组件内部的文件,确保包含所有图片
-              const allUrls = new Set<string>();
-              const mergedFiles: UploadUserFile[] = [];
-
-              // 先添加 formData 中的文件
-              formData.backgroundImages.forEach((file: UploadUserFile) => {
-                if (file && file.url && !file.url.startsWith("blob:")) {
-                  const fileUrl = file.url.trim();
-                  if (!allUrls.has(fileUrl)) {
-                    allUrls.add(fileUrl);
-                    mergedFiles.push({
-                      ...file,
-                      url: fileUrl
-                    });
-                  }
-                }
-              });
-
-              // 再添加组件内部的文件(确保新上传的文件被包含)
-              validFiles.forEach((file: UploadUserFile) => {
-                const fileUrl = file.url;
-                if (fileUrl && !fileUrl.startsWith("blob:") && !allUrls.has(fileUrl)) {
-                  allUrls.add(fileUrl);
-                  mergedFiles.push(file);
-                  console.log("从组件内部添加文件:", fileUrl);
-                }
-              });
-
-              // 更新 formData,确保包含新上传的图片
-              formData.backgroundImages = [...mergedFiles];
-
-              console.log("上传成功后同步的文件列表,数量:", mergedFiles.length);
-              console.log(
-                "上传成功后同步的文件列表 URLs:",
-                mergedFiles.map(f => f.url)
-              );
-
-              // 触发验证
-              await nextTick();
-              if (formRef.value) {
-                formRef.value.validateField("backgroundImages");
-              }
-              break;
-            }
-          }
-        }
-      } catch (error) {
-        console.error("上传成功后同步文件列表失败:", error);
-        break;
-      }
-    }
-
-    // 如果还没找到新上传的 URL,等待一下再重试
-    retryCount++;
-    if (retryCount < maxRetries) {
-      await new Promise(resolve => setTimeout(resolve, 150)); // 等待 150ms
-      await nextTick();
-    }
-  }
-
-  if (retryCount >= maxRetries) {
-    console.warn("⚠️ 上传成功后,等待组件更新超时,但已同步当前文件列表");
-    // 即使超时,也确保新上传的 URL 在 formData 中
-    const urlExists = formData.backgroundImages.some((file: UploadUserFile) => {
-      return file && file.url && file.url.trim() === url.trim();
-    });
-    if (!urlExists) {
-      const newFile: UploadUserFile = {
-        uid: `upload-${Date.now()}-${Math.random()}`,
-        name: url.split("/").pop() || "image.jpg",
-        url: url.trim(),
-        status: "success" as const,
-        response: { fileUrl: url }
-      };
-      formData.backgroundImages = [...formData.backgroundImages, newFile];
-      console.log("超时后强制添加新文件到 formData");
-    }
+  if (formRef.value) {
+    formRef.value.validateField("backgroundImages");
   }
 };
 
@@ -991,14 +841,17 @@ watch(
                   lastFileListUrls = currentUrls;
                   lastFileListLength = currentLength;
 
-                  // 直接更新 formData,确保计数正确
-                  const mappedFiles = validFiles.map((file: UploadUserFile) => ({
-                    ...file,
-                    url: file.url!.trim()
-                  }));
-                  formData.backgroundImages = [...mappedFiles];
-
-                  console.log("定时检查检测到文件列表变化,数量:", mappedFiles.length);
+                  // 按 URL 去重后更新 formData,避免同一张图出现多次
+                  const seen = new Set<string>();
+                  const mappedFiles = validFiles
+                    .map((file: UploadUserFile) => ({ ...file, url: (file.url || "").trim() }))
+                    .filter((f: UploadUserFile) => {
+                      const u = f?.url;
+                      if (!u || seen.has(u)) return false;
+                      seen.add(u);
+                      return true;
+                    });
+                  formData.backgroundImages = [...mappedFiles] as UploadUserFile[];
 
                   // 触发验证
                   await nextTick();