Pārlūkot izejas kodu

Merge branch 'development' of http://8.152.195.41:3000/alien/group_web_merchant into development

liudongzhi 2 mēneši atpakaļ
vecāks
revīzija
b57b8f453a

+ 73 - 26
src/views/operationManagement/activityDetail.vue

@@ -151,22 +151,29 @@
             <div class="promotion-image-item">
               <h3 style="font-weight: bold">活动详情图:</h3>
               <div class="image-container">
-                <div v-if="getImageUrl(activityModel.activityDetailImgUrl)" class="image-item">
-                  <el-image
-                    :src="getImageUrl(activityModel.activityDetailImgUrl)"
-                    fit=""
-                    class="promotion-image"
-                    :preview-src-list="getPreviewImageList()"
-                    :initial-index="getImageUrl(activityModel.activityTitleImgUrl) ? 1 : 0"
+                <div v-if="detailImageList.length > 0" class="detail-images-grid">
+                  <div
+                    v-for="(imgUrl, index) in detailImageList"
+                    :key="index"
+                    class="detail-image-item"
+                    @click="previewDetailImage(index)"
                   >
-                    <template #error>
-                      <div class="image-slot">
-                        <el-icon>
-                          <Picture />
-                        </el-icon>
-                      </div>
-                    </template>
-                  </el-image>
+                    <el-image
+                      :src="imgUrl"
+                      fit="cover"
+                      class="detail-image"
+                      :preview-src-list="getPreviewImageList()"
+                      :initial-index="getImageUrl(activityModel.activityTitleImgUrl) ? index + 1 : index"
+                    >
+                      <template #error>
+                        <div class="image-slot">
+                          <el-icon>
+                            <Picture />
+                          </el-icon>
+                        </div>
+                      </template>
+                    </el-image>
+                  </div>
                 </div>
                 <div v-else class="empty-text">--</div>
               </div>
@@ -183,7 +190,7 @@
  * 运营活动管理 - 详情页面
  * 功能:显示运营活动的详细信息
  */
-import { ref, onMounted } from "vue";
+import { ref, onMounted, computed } from "vue";
 import { useRouter, useRoute } from "vue-router";
 import { ElMessage } from "element-plus";
 import { Picture } from "@element-plus/icons-vue";
@@ -386,20 +393,51 @@ const getImageUrl = (img: any): string => {
 };
 
 /**
+ * 处理活动详情图列表(支持字符串、数组、对象数组)
+ */
+const detailImageList = computed(() => {
+  const imgData = activityModel.value.activityDetailImgUrl || activityModel.value.activityDetailImgUrlList;
+  if (!imgData) return [];
+
+  // 如果是字符串,可能是逗号分隔的多张图片
+  if (typeof imgData === "string") {
+    return imgData.split(",").filter((url: string) => url.trim());
+  }
+
+  // 如果是数组
+  if (Array.isArray(imgData)) {
+    return imgData
+      .map((item: any) => {
+        if (typeof item === "string") return item;
+        if (item && item.url) return item.url;
+        return "";
+      })
+      .filter((url: string) => url);
+  }
+
+  return [];
+});
+
+/**
  * 获取预览图片列表
  */
 const getPreviewImageList = () => {
   const list: string[] = [];
   const titleUrl = getImageUrl(activityModel.value.activityTitleImgUrl);
-  const detailUrl = getImageUrl(activityModel.value.activityDetailImgUrl);
   if (titleUrl) {
     list.push(titleUrl);
   }
-  if (detailUrl) {
-    list.push(detailUrl);
-  }
+  // 添加所有详情图
+  list.push(...detailImageList.value);
   return list;
 };
+
+/**
+ * 预览详情图
+ */
+const previewDetailImage = (index: number) => {
+  // 预览功能由 el-image 的 preview-src-list 自动处理
+};
 </script>
 
 <style scoped lang="scss">
@@ -541,20 +579,29 @@ const getPreviewImageList = () => {
   }
 }
 
-/* 活动详情图 - 竖版样式 */
+/* 活动详情图 - 网格布局 */
 .promotion-image-item:last-child {
   .image-container {
     width: 100%;
-    max-width: 300px;
   }
-  .image-item {
+  .detail-images-grid {
+    display: grid;
+    grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
+    gap: 12px;
     width: 100%;
-    aspect-ratio: 3 / 4;
   }
-  .promotion-image {
+  .detail-image-item {
+    width: 150px;
+    height: 150px;
+    overflow: hidden;
+    cursor: pointer;
+    background: #f5f7fa;
+    border-radius: 8px;
+  }
+  .detail-image {
     width: 100%;
     height: 100%;
-    object-fit: contain;
+    object-fit: cover;
   }
 }
 .image-slot {

+ 46 - 18
src/views/operationManagement/newActivity.vue

@@ -174,6 +174,7 @@
                     :before-remove="handleBeforeRemove"
                     :disabled="hasUnuploadedImages"
                     :limit="9"
+                    :multiple="true"
                     :on-change="handleDetailUploadChange"
                     :on-exceed="handleDetailUploadExceed"
                     :on-preview="handlePictureCardPreview"
@@ -713,14 +714,21 @@ const handleTitleUploadChange: UploadProps["onChange"] = async (uploadFile, uplo
     titleFileList.value.push(uploadFile);
   }
 
-  const readyFiles = titleFileList.value.filter(file => file.status === "ready");
-  if (readyFiles.length) {
-    readyFiles.forEach(file => {
-      if (!pendingUploadFiles.value.some(item => item.uid === file.uid)) {
-        pendingUploadFiles.value.push(file);
-      }
-    });
-  }
+  // 使用 nextTick 确保所有文件的 onChange 事件都处理完毕后再统一处理队列
+  await nextTick();
+
+  // 重新收集所有待上传的文件(包括新添加的和之前未上传的)
+  const readyFiles = titleFileList.value.filter(file => (file.status === "ready" || file.status === undefined) && file.raw);
+
+  // 清空并重新填充待上传队列
+  pendingUploadFiles.value = [];
+  readyFiles.forEach(file => {
+    if (!pendingUploadFiles.value.some(item => item.uid === file.uid)) {
+      pendingUploadFiles.value.push(file);
+    }
+  });
+
+  // 处理上传队列
   processUploadQueue("title");
 };
 
@@ -782,14 +790,21 @@ const handleDetailUploadChange: UploadProps["onChange"] = async (uploadFile, upl
     detailFileList.value.push(uploadFile);
   }
 
-  const readyFiles = detailFileList.value.filter(file => file.status === "ready");
-  if (readyFiles.length) {
-    readyFiles.forEach(file => {
-      if (!pendingUploadFiles.value.some(item => item.uid === file.uid)) {
-        pendingUploadFiles.value.push(file);
-      }
-    });
-  }
+  // 使用 nextTick 确保所有文件的 onChange 事件都处理完毕后再统一处理队列
+  await nextTick();
+
+  // 重新收集所有待上传的文件(包括新添加的和之前未上传的)
+  const readyFiles = detailFileList.value.filter(file => (file.status === "ready" || file.status === undefined) && file.raw);
+
+  // 清空并重新填充待上传队列
+  pendingUploadFiles.value = [];
+  readyFiles.forEach(file => {
+    if (!pendingUploadFiles.value.some(item => item.uid === file.uid)) {
+      pendingUploadFiles.value.push(file);
+    }
+  });
+
+  // 处理上传队列
   processUploadQueue("detail");
 };
 
@@ -797,14 +812,27 @@ const handleDetailUploadChange: UploadProps["onChange"] = async (uploadFile, upl
  * 处理上传队列 - 逐个上传文件
  */
 const processUploadQueue = async (type: string) => {
+  // 如果正在上传或队列为空,直接返回
   if (uploading.value || pendingUploadFiles.value.length === 0) {
     return;
   }
+
+  // 从队列中取出第一个文件
   const file = pendingUploadFiles.value.shift();
-  if (file) {
-    await uploadSingleFile(file, type);
+  if (!file || !file.raw) {
+    // 如果文件无效,继续处理下一个
     processUploadQueue(type);
+    return;
   }
+
+  // 上传文件
+  await uploadSingleFile(file, type);
+
+  // 上传完成后,继续处理队列中的下一个文件
+  // 使用 setTimeout 确保状态已更新
+  setTimeout(() => {
+    processUploadQueue(type);
+  }, 100);
 };
 
 /**