박정하 박정하 04-03
250403 박정하 썸네일 파일 별도 저장 형식으로 변경
@984c9c0e66dc05f5922576d9f4400248e7f5967f
 
client/views/component/VideoThumbnail.vue (deleted)
--- client/views/component/VideoThumbnail.vue
@@ -1,126 +0,0 @@
-<template>
-    <img v-if="thumbnailUrl" :src="thumbnailUrl" alt="비디오 썸네일">
-    <div v-else-if="error" class="error">썸네일 생성 실패</div>
-    <div v-else class="loading">로딩 중...</div>
-</template>
-<script>
-export default {
-  data() {
-    return {
-      thumbnailUrl: null,
-      error: false
-    }
-  },
-  props: {
-    filePath: String
-  },
-  methods: {
-    createThumbnail(videoBlob) {
-      return new Promise((resolve, reject) => {
-        // 동영상 요소 생성
-        const video = document.createElement('video');
-        video.style.display = 'none';
-        document.body.appendChild(video);
-
-        // 캔버스 요소 생성
-        const canvas = document.createElement('canvas');
-        canvas.width = 320;
-        canvas.height = 180;
-
-        // 동영상 파일로부터 URL 생성
-        const videoUrl = URL.createObjectURL(videoBlob);
-        video.src = videoUrl;
-
-        // 로드 시간 제한 설정 (10초)
-        const timeout = setTimeout(() => {
-          URL.revokeObjectURL(videoUrl);
-          document.body.removeChild(video);
-          reject(new Error('비디오 로드 시간 초과'));
-        }, 10000);
-
-        // 오류 처리
-        video.onerror = (e) => {
-          clearTimeout(timeout);
-          URL.revokeObjectURL(videoUrl);
-          document.body.removeChild(video);
-          reject(new Error('비디오 로드 실패: ' + e.message));
-        };
-
-        // 메타데이터 로드 후 처리
-        video.onloadedmetadata = () => {
-          // 첫 프레임이나 특정 시점으로 이동
-          video.currentTime = 0.5;
-        };
-
-        // 특정 시간으로 이동 완료 후 썸네일 생성
-        video.onseeked = () => {
-          try {
-            clearTimeout(timeout);
-
-            const ctx = canvas.getContext('2d');
-            ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
-
-            // 썸네일 URL 생성
-            const thumbnailUrl = canvas.toDataURL('image/jpeg', 0.7);
-
-            // 리소스 정리
-            URL.revokeObjectURL(videoUrl);
-            document.body.removeChild(video);
-
-            resolve(thumbnailUrl);
-          } catch (error) {
-            URL.revokeObjectURL(videoUrl);
-            document.body.removeChild(video);
-            reject(error);
-          }
-        };
-      });
-    }
-  },
-  async mounted() {
-    try {
-      console.log('비디오 파일 경로:', this.filePath);
-
-      // 백엔드에서 파일 가져오기
-      const response = await fetch(this.filePath, {
-        // credentials: 'include', // 필요한 경우 쿠키 포함
-        // mode: 'cors', // CORS 모드 설정
-      });
-
-      if (!response.ok) {
-        throw new Error(`HTTP 오류! 상태: ${response.status}`);
-      }
-
-      const blob = await response.blob();
-      console.log('비디오 Blob 크기:', blob.size);
-
-      // 썸네일 생성
-      this.thumbnailUrl = await this.createThumbnail(blob);
-    } catch (error) {
-      console.error('썸네일 생성 실패:', error);
-      this.error = true;
-    }
-  }
-}
-</script>
-<style scoped>
-.loading,
-.error {
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  width: 100%;
-  height: 100%;
-  min-height: 180px;
-  background-color: #f0f0f0;
-  border-radius: 30px;
-}
-
-.loading {
-  color: #666;
-}
-
-.error {
-  color: #e53935;
-}
-</style>(파일 끝에 줄바꿈 문자 없음)
client/views/component/listLayout/CardStyleComponent.vue
--- client/views/component/listLayout/CardStyleComponent.vue
+++ client/views/component/listLayout/CardStyleComponent.vue
@@ -3,8 +3,7 @@
     <li v-for="(item, idx) in list" :key="idx" class="mb-30" @click="fnMoveTo(item)">
       <div class="result-box">
         <div class="main-img">
-          <video-thumbnail v-if="name === 'V'" :file-path="item.files[0].filePath" :alt="item.sj + ' 영상 썸네일'" />
-          <img v-else-if="name === 'M'" :src="getYouTubeThumbnail(item.link)" alt="영상 썸네일">
+          <img v-if="name === 'M'" :src="getYouTubeThumbnail(item.link)" alt="영상 썸네일">
           <img v-else-if="item.hasOwnProperty('files') && item.files.length > 0" :src="item.files[0].filePath" :alt="item.sj + ' 첫 번째 이미지'">
           <img v-else src="client/resources/images/img6.png" alt="Not found image">
         </div>
@@ -31,14 +30,9 @@
 </template>
 <script>
 import { getYouTubeThumbnail } from '../../../resources/js/youtubeUtils';
-import VideoThumbnail from '../VideoThumbnail.vue';
 
 export default {
   name: "CardStyleComponent",
-
-  components: {
-    VideoThumbnail,
-  },
 
   props: {
     name: {
client/views/pages/bbsDcry/photo/PicHistoryDetail.vue
--- client/views/pages/bbsDcry/photo/PicHistoryDetail.vue
+++ client/views/pages/bbsDcry/photo/PicHistoryDetail.vue
@@ -26,18 +26,19 @@
       <div>
         <div class="gallery">
           <div class="main-swiper">
-            <swiper :style="{ '--swiper-navigation-color': '#fff', '--swiper-pagination-color': '#fff' }" :loop="true"
-              :spaceBetween="10" :thumbs="{ swiper: thumbsSwiper }" :modules="modules" class="mySwiper2">
+            <swiper :style="{ '--swiper-navigation-color': '#fff', '--swiper-pagination-color': '#fff' }" :loop="true" :spaceBetween="10" :thumbs="{ swiper: thumbsSwiper }" :modules="modules" class="mySwiper2">
               <swiper-slide v-for="(item, idx) of findResult.files" :key="idx">
                 <img :src="item.filePath" :alt="item.fileNm" />
               </swiper-slide>
             </swiper>
           </div>
           <div class="thumbnail">
-            <swiper @swiper="setThumbsSwiper" :spaceBetween="20" :slidesPerView="4" :freeMode="true"
-              :watchSlidesProgress="true" :modules="modules" :navigation="true" class="mySwiper">
+            <swiper @swiper="setThumbsSwiper" :spaceBetween="20" :slidesPerView="4" :freeMode="true" :watchSlidesProgress="true" :modules="modules" :navigation="true" class="mySwiper">
               <swiper-slide v-for="(item, idx) of findResult.files" :key="idx">
-                <input type="checkbox" :id="'photo_' + idx" :value="item.fileId" v-model="selectedFiles" />
+                <div class="checkbox-wrapper" @click.stop>
+                  <input type="checkbox" :id="'photo_' + idx" :value="item.fileId" v-model="selectedFiles" />
+                  <label :for="'photo_' + idx"></label>
+                </div>
                 <img :src="item.filePath" :alt="item.fileNm" />
               </swiper-slide>
             </swiper>
@@ -181,9 +182,11 @@
     // 파일 다운로드
     async fnDownload(type) {
       // 유효성 검사
-      if (type === 'selected' && this.selectedFiles.length === 0) {
-        alert("파일을 1개 이상 선택하거나 전체 다운로드를 클릭해주세요.");
-        return;
+      if (type === 'selected') {
+        if (this.selectedFiles.length === 0) {
+          alert("파일을 1개 이상 선택하거나 전체 다운로드를 클릭해주세요.");
+          return;
+        }
       }
 
       let url = null;
@@ -191,18 +194,19 @@
 
       try {
         // 파일 ID 수집
-        let fileIds;
+        let fileList;
         if (type === 'selected') {
-          if (this.selectedFiles.length == 1) {
-            fileIds = this.selectedFiles[0];
+          fileList = this.selectedFiles;
+        } else if (type === 'all') {
+          if (this.findResult.files.length == 1) {
+            fileList = this.findResult.files[0].fileId;
           } else {
-            fileIds = this.selectedFiles.join(',');
+            fileList = this.findResult.files.map(file => file.fileId);
           }
-        } else if (type === 'all' && this.findResult.files.length > 1) {
-          fileIds = this.findResult.files.map(file => file.fileId).join(',');
         }
 
-        let isMultiple = this.selectedFiles.length > 1;
+        let isMultiple = fileList.length > 1;
+        let fileIds = isMultiple ? fileList.join(',') : fileList[0];
         const response = isMultiple ? await multiFileDownloadProc(fileIds) : await fileDownloadProc(fileIds);
 
         // 파일명 조회
client/views/pages/bbsDcry/video/VideoHistoryDetail.vue
--- client/views/pages/bbsDcry/video/VideoHistoryDetail.vue
+++ client/views/pages/bbsDcry/video/VideoHistoryDetail.vue
@@ -23,8 +23,8 @@
         </dd>
       </dl>
       <div class="gallery video">
-        <img :src="eximg" alt="">
-        <Video-component :videoUrl="findResult.files[0].filePath" />
+        <Video-component v-if="findResult.hasOwnProperty('files') && findResult.files.length > 0" :videoUrl="findResult.files[0].filePath" />
+        <img v-else :src="eximg" alt="">
       </div>
     </form>
     <h3>내용</h3>
client/views/pages/main/Main.vue
--- client/views/pages/main/Main.vue
+++ client/views/pages/main/Main.vue
@@ -70,8 +70,7 @@
             <div class="new-pic">
               <div v-for="(item, idx2) in tabContent.list" :key="idx2" class="box-wrap">
                 <div class="box" @click="fnMoveTo(tabContent.view, item.dcryId)">
-                  <img v-if="tabContent.id === 'newPhoto'" :src="item.files[0].filePath" :alt="item.sj" class="tab-image" />
-                  <video-thumbnail v-if="tabContent.id === 'newVideo'" :file-path="item.files[0].filePath" :alt="item.sj" class="tab-image" />
+                  <img :src="item.files[0].filePath" :alt="item.sj" class="tab-image" />
                   <div class="info">
                     <p>{{ item.sj }}</p>
                     <span>{{ $dotFormatDate(item.rgsde) }}</span>
@@ -100,7 +99,7 @@
         <router-link :to="{ name: 'MediaVideoSearch' }" class="gopage">더보기</router-link>
       </div>
       <div class="media-wrap">
-        <template v-for="(item, index) of mediaContents" :key="index">
+        <template v-for="(item, idx) of mediaContents" :key="idx">
           <div class="media-box" @click="fnMoveTo('MediaVideoDetail', item.mediaVidoId)">
             <img :src="item.url" :alt="item.sj" class="media-image" />
             <div class="info">
@@ -157,7 +156,6 @@
 // 메인화면 조회
 import { findAllSttusesProc } from "../../../resources/api/main";
 import { getYouTubeThumbnail } from '../../../resources/js/youtubeUtils';
-import VideoThumbnail from '../../component/VideoThumbnail.vue';
 
 export default {
   components: {
@@ -165,7 +163,6 @@
     SwiperSlide,
     PauseOutlined,
     CaretRightOutlined,
-    VideoThumbnail,
   },
   setup() {
     return {
Add a comment
List