Selaa lähdekoodia

修改视频上传链接

yangg 6 kuukautta sitten
vanhempi
sitoutus
6eb5c6e941
1 muutettua tiedostoa jossa 247 lisäystä ja 51 poistoa
  1. 247 51
      src/views/report.vue

+ 247 - 51
src/views/report.vue

@@ -131,9 +131,20 @@
                   <template v-if="isImageFile(file)">
                     <div class="image-preview">
                       <img :src="file.url" class="preview-image" />
-                      <!-- <div class="image-info">
-                        <span>解析图片</span>
-                      </div> -->
+                    </div>
+                  </template>
+
+                  <!-- 视频文件显示 -->
+                  <template v-else-if="isVideoFile(file)">
+                    <div class="video-preview">
+                      <video
+                        controls
+                        class="preview-video"
+                        :src="file.url"
+                        preload="metadata"
+                      >
+                        Your browser does not support the video tag.
+                      </video>
                     </div>
                   </template>
 
@@ -142,11 +153,10 @@
                     <div class="file-info-display">
                       <img :src="getFileIcon(file)" class="file-type-icon" />
                       <div class="file-details">
-                        <span class="file-name">{{ file.name }}</span>
+                        <span class="file-name" :title="file.name">{{ file.name }}</span>
                         <span class="file-size">{{ file.size }}</span>
                       </div>
                     </div>
-                    <!--  <div class="file-action">解析文档中的内容</div> -->
                   </template>
                 </div>
               </template>
@@ -223,15 +233,24 @@
                 @dragover.prevent
                 @dragenter.prevent
               >
-                <img
-                  src="../assets/svg/upload.svg"
-                  alt="upload"
-                  class="upload-icon"
-                />
-                <div class="upload-text">Upload files</div>
-                <div class="upload-hint">
-                  Click or drag files to this area to upload
-                </div>
+                <!-- 移除条件判断,让整个区域始终可点击 -->
+                <template v-if="isUploading">
+                  <div class="upload-loading">
+                    <div class="loading-spinner"></div>
+                    <div class="upload-text">Uploading...</div>
+                  </div>
+                </template>
+                <template v-else>
+                  <img
+                    src="../assets/svg/upload.svg"
+                    alt="upload"
+                    class="upload-icon"
+                  />
+                  <div class="upload-text">Upload files</div>
+                  <div class="upload-hint">
+                    Click or drag files to this area to upload
+                  </div>
+                </template>
                 <input
                   type="file"
                   ref="fileInput"
@@ -251,12 +270,36 @@
                   :class="{ 'is-image': isImageFile(file) }"
                 >
                   <div :class="isImageFile(file) ? 'file-wrapper' : ''">
+                    <!-- 添加文件 loading 状态 -->
+                    <div v-if="file.isUploading" class="file-loading">
+                      <div class="loading-spinner"></div>
+                    </div>
+                    <!-- 其他文件显示逻辑保持不变 -->
+                    <img
+                      v-else-if="isImageFile(file)"
+                      :src="file.url"
+                      alt="file"
+                      class="file-icon"
+                    />
+                    <video
+                      v-else-if="isVideoFile(file)"
+                      :src="file.url"
+                      class="file-icon"
+                      preload="metadata"
+                    >
+                      Your browser does not support the video tag.
+                    </video>
                     <img
+                      v-else
                       :src="getFileIcon(file)"
                       alt="file"
-                      :class="isImageFile(file) ? 'file-icon' : ''"
+                      :class="isImageFile(file) || isVideoFile(file) ? 'file-icon' : ''"
                     />
-                    <button class="remove-btn" @click.stop="removeFile(file)">
+                    <button 
+                      class="remove-btn" 
+                      @click.stop="removeFile(file)"
+                      v-if="!file.isUploading"
+                    >
                       ×
                     </button>
                   </div>
@@ -411,6 +454,9 @@ const isPlaying = ref(false);
 // 添加当前播放消息的 ID
 const currentPlayingId = ref(null);
 
+// 添加新的响应式变量
+const isUploading = ref(false);
+
 // 方法
 const toggleAttachments = () => {
   showAttachments.value = !showAttachments.value;
@@ -421,7 +467,9 @@ const removeFile = (file) => {
 };
 
 const triggerFileInput = () => {
-  fileInput.value.click();
+  // 如果正在上传,不触发新的上传
+  if (isUploading.value) return;
+  fileInput.value?.click();
 };
 
 const uploadFile = async (file) => {
@@ -452,28 +500,61 @@ const uploadFile = async (file) => {
 
 const handleFileUpload = async (event) => {
   const files = Array.from(event.target.files);
+  if (files.length === 0) return;
+    // 添加文件大小检查
+    const MAX_VIDEO_SIZE = 10 * 1024 * 1024; // 10MB in bytes
+    const invalidFiles = files.filter(file => {
+    if (isVideoFile(file) && file.size > MAX_VIDEO_SIZE) {
+      return true;
+    }
+    return false;
+  });
 
-  try {
-    isLoading.value = true;
+  if (invalidFiles.length > 0) {
+    // 如果有超出大小限制的视频文件,显示错误提示
+    alert('Video files must not exceed 10MB');
+    event.target.value = ''; // 清空input
+    return;
+  }
+  isUploading.value = true;
 
-    const uploadPromises = files.map(async (file) => {
-      const url = await uploadFile(file);
-      return {
+  try {
+    for (const file of files) {
+      // 创建一个带有上传状态的文件对象
+      const fileWithStatus = {
         name: file.name,
-        size: file.size, // 保存原始大小(字节)
-        sizeFormatted: formatFileSize(file.size), // 格式化后的大小
+        size: file.size,
+        sizeFormatted: formatFileSize(file.size),
         type: file.type,
-        url: url,
+        isUploading: true
       };
-    });
-
-    const uploadedFiles = await Promise.all(uploadPromises);
-    attachedFiles.value = [...attachedFiles.value, ...uploadedFiles];
+      
+      // 先添加到文件列表中
+      attachedFiles.value.push(fileWithStatus);
+
+      try {
+        const url = await uploadFile(file);
+        // 直接修改数组中的对象
+        const index = attachedFiles.value.findIndex(f => f.name === file.name);
+        if (index !== -1) {
+          // 使用数组替换方式更新,确保响应式更新
+          attachedFiles.value.splice(index, 1, {
+            ...fileWithStatus,
+            url,
+            isUploading: false
+          });
+        }
+      } catch (error) {
+        // 如果上传失败,从列表中移除该文件
+        attachedFiles.value = attachedFiles.value.filter(f => f.name !== file.name);
+        console.error("单个文件上传失败:", error);
+      }
+    }
   } catch (error) {
     console.error("文件上传失败:", error);
   } finally {
-    isLoading.value = false;
-    event.target.value = "";
+    isUploading.value = false;
+    event.target.value = ""; // 清空input以允许重复上传相同文件
   }
 };
 
@@ -501,10 +582,19 @@ const isImageFile = (file) => {
   return imageTypes.includes(ext);
 };
 
+const isVideoFile = (file) => {
+  const videoTypes = ["mp4", "webm", "ogg"];
+  const ext = file.name?.split(".")?.pop()?.toLowerCase() || "";
+  return videoTypes.includes(ext);
+};
+
 const getFileType = (file) => {
   const ext = file.name.split(".").pop().toLowerCase();
   const imageTypes = ["jpg", "jpeg", "png", "gif", "webp"];
-  return imageTypes.includes(ext);
+  const videoTypes = ["mp4", "webm", "ogg"];
+  if (imageTypes.includes(ext)) return "image";
+  if (videoTypes.includes(ext)) return "video";
+  return "document";
 };
 
 // 添加滚动到底部的方法
@@ -531,11 +621,15 @@ const sendMessage = async () => {
 
   // 收集文件URLs
   const imageUrls = [];
+  const videoUrls = [];
   const documentUrls = [];
 
   attachedFiles.value.forEach((file) => {
-    if (getFileType(file)) {
+    const fileType = getFileType(file);
+    if (fileType === "image") {
       imageUrls.push(file.url);
+    } else if (fileType === "video") {
+      videoUrls.push(file.url);
     } else {
       documentUrls.push(file.url);
     }
@@ -580,11 +674,12 @@ const sendMessage = async () => {
       `${import.meta.env.VITE_BASE_AI_API}/chatbot/multimodal`,
       {
         message: currentInput,
-        chat_config_id: "17",
+        chat_config_id: "2",
         user_id: "13365429324",
         session_id: session_id.value,
         source: "pc",
         image_urls: imageUrls,
+        video_urls: videoUrls,
         documents: documentUrls,
       }
     );
@@ -690,26 +785,54 @@ const toggleRightMenu = () => {
 };
 
 const handleFileDrop = async (event) => {
+  if (isUploading.value) return;
+  
   const files = Array.from(event.dataTransfer.files);
+  if (files.length === 0) return;
+// 添加文件大小检查
+const MAX_VIDEO_SIZE = 10 * 1024 * 1024; // 10MB in bytes
+  const invalidFiles = files.filter(file => {
+    if (isVideoFile(file) && file.size > MAX_VIDEO_SIZE) {
+      return true;
+    }
+    return false;
+  });
+
+  isUploading.value = true;
+
   try {
-    isLoading.value = true;
-    const uploadPromises = files.map(async (file) => {
-      const url = await uploadFile(file);
-      return {
+    for (const file of files) {
+      const fileWithStatus = {
         name: file.name,
-        size: file.size, // 保存原始大小(字节)
-        sizeFormatted: formatFileSize(file.size), // 格式化后的大小
+        size: file.size,
+        sizeFormatted: formatFileSize(file.size),
         type: file.type,
-        url: url,
+        isUploading: true
       };
-    });
-
-    const uploadedFiles = await Promise.all(uploadPromises);
-    attachedFiles.value = [...attachedFiles.value, ...uploadedFiles];
+      
+      attachedFiles.value.push(fileWithStatus);
+
+      try {
+        const url = await uploadFile(file);
+        // 直接修改数组中的对象
+        const index = attachedFiles.value.findIndex(f => f.name === file.name);
+        if (index !== -1) {
+          // 使用数组替换方式更新,确保响应式更新
+          attachedFiles.value.splice(index, 1, {
+            ...fileWithStatus,
+            url,
+            isUploading: false
+          });
+        }
+      } catch (error) {
+        attachedFiles.value = attachedFiles.value.filter(f => f.name !== file.name);
+        console.error("单个文件上传失败:", error);
+      }
+    }
   } catch (error) {
     console.error("文件上传失败:", error);
   } finally {
-    isLoading.value = false;
+    isUploading.value = false;
   }
 };
 
@@ -1141,7 +1264,10 @@ const renderMarkdown = (content) => {
   object-fit: cover;
   border-radius: 4px;
 }
-
+/* 视频预览特定样式 */
+.file-wrapper video.file-icon {
+  background: #000; /* 视频加载前的背景色 */
+}
 .remove-btn {
   position: absolute;
   top: -8px;
@@ -1172,12 +1298,21 @@ const renderMarkdown = (content) => {
 
 .file-name {
   display: block;
+  max-width: 150px; /* 设置最大宽度 */
   color: rgba(0, 0, 0, 0.88);
   font-size: 14px;
   white-space: nowrap;
   overflow: hidden;
   text-overflow: ellipsis;
 }
+.file-info .file-name {
+  max-width: 150px; /* 可以根据实际布局调整宽度 */
+}
+
+/* 如果需要在hover时显示完整文件名,可以添加 title 属性和 tooltip 效果 */
+.file-name:hover {
+  cursor: pointer;
+}
 
 .file-size {
   display: block;
@@ -1550,11 +1685,11 @@ const renderMarkdown = (content) => {
   flex-direction: column;
 }
 
-.file-name {
+/* .file-name {
   font-size: 14px;
   color: rgba(0, 0, 0, 0.88);
   margin-bottom: 4px;
-}
+} */
 
 .file-size {
   font-size: 12px;
@@ -1625,11 +1760,11 @@ const renderMarkdown = (content) => {
   flex-direction: column;
 }
 
-.file-name {
+/* .file-name {
   font-size: 14px;
   color: rgba(0, 0, 0, 0.88);
   margin-bottom: 4px;
-}
+} */
 
 .file-size {
   font-size: 12px;
@@ -1766,6 +1901,67 @@ const renderMarkdown = (content) => {
   font-size: 14px;
   color: #1296db;
 }
+.video-preview {
+  position: relative;
+  width: 300px;
+  border-radius: 8px;
+  overflow: hidden;
+  background: #fff;
+  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
+  margin-bottom: 8px;
+}
+
+.preview-video {
+  width: 100%;
+  height: auto;
+  display: block;
+  max-height: 300px;
+}
+
+/* 添加 loading 相关样式 */
+.upload-loading {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  gap: 12px;
+}
+
+.loading-spinner {
+  width: 24px;
+  height: 24px;
+  border: 2px solid #f3f3f3;
+  border-top: 2px solid #1677ff;
+  border-radius: 50%;
+  animation: spin 1s linear infinite;
+}
+
+.file-loading {
+  position: absolute;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  background: rgba(255, 255, 255, 0.8);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  z-index: 1;
+}
+
+@keyframes spin {
+  0% { transform: rotate(0deg); }
+  100% { transform: rotate(360deg); }
+}
+
+/* 上传区域在上传时的样式 */
+.upload-area {
+  position: relative;
+  cursor: pointer; /* 始终保持指针样式 */
+}
+
+.upload-area.uploading {
+  opacity: 0.7;
+}
 </style>
 <style lang="less" scoped>
 ::v-deep .message-content {