박정하 박정하 06-10
250610 정렬방식, 이미지 썸네일 수정사항 수정
@f39fe426a7d33b0a1f36b01eabb68ef1bc88986c
client/views/component/SearchFormComponent.vue
--- client/views/component/SearchFormComponent.vue
+++ client/views/component/SearchFormComponent.vue
@@ -111,7 +111,7 @@
         startYear: null,
         endYear: null,
         searchCtgries: [],
-        order: "rgsde",
+        order: "prdctn_year",
         // 페이지네이션 관련 속성
         currentPage: 1,
         recordSize: 24,
@@ -140,7 +140,8 @@
 
       // 정렬 목록
       orders: [
-        { key: "rgsde", value: "최신" },
+        { key: "prdctn_year", value: "생산연도" },
+        { key: "rgsde", value: "등록일" },
         { key: "rdcnt", value: "인기" },
       ],
     };
client/views/pages/bbsDcryPhoto/PicHistoryInsert.vue
--- client/views/pages/bbsDcryPhoto/PicHistoryInsert.vue
+++ client/views/pages/bbsDcryPhoto/PicHistoryInsert.vue
@@ -71,9 +71,14 @@
                     </label>
                   </div>
                   <div class="flex-sp-bw file-wrap">
-                    <div class="file-name">
-                      <img src="/client/resources/images/icon/imgicon.png" alt="fileicon">
-                      <p>{{ file.fileNm }}</p>
+                    <div class="file-item-with-thumbnail">
+                      <div class="thumbnail-container">
+                        <img :src="getFileUrl(file)" alt="thumbnail" class="file-thumbnail" @error="handleImageError">
+                      </div>
+                      <div class="file-name">
+                        <img src="/client/resources/images/icon/imgicon.png" alt="fileicon">
+                        <p>{{ file.fileNm }}</p>
+                      </div>
                     </div>
                     <button type="button" class="cancel" @click="fnDelFile('old', file.fileOrdr)"><b>✕</b></button>
                   </div>
@@ -87,9 +92,15 @@
                     </label>
                   </div>
                   <div class="flex-sp-bw file-wrap">
-                    <div class="file-name">
-                      <img src="/client/resources/images/icon/imgicon.png" alt="fileicon">
-                      <p>{{ file.name }}</p>
+                    <div class="file-item-with-thumbnail">
+                      <div class="thumbnail-container">
+                        <img :src="filePreviewUrls[idx]" alt="thumbnail" class="file-thumbnail" v-if="filePreviewUrls[idx]">
+                        <div class="thumbnail-loading" v-else>Loading...</div>
+                      </div>
+                      <div class="file-name">
+                        <img src="/client/resources/images/icon/imgicon.png" alt="fileicon">
+                        <p>{{ file.name }}</p>
+                      </div>
                     </div>
                     <button type="button" class="cancel" @click="fnDelFile('new', idx)"><b>✕</b></button>
                   </div>
@@ -149,6 +160,7 @@
       isDragging: false,
 
       fileNames: [],
+      filePreviewUrls: [],
 
       // 등록/수정 요청 객체
       requestDTO: {
@@ -188,6 +200,26 @@
   },
 
   methods: {
+    // 기존 파일의 URL 생성 (서버에서 제공하는 파일 URL)
+    getFileUrl(file) {
+      return file.filePath || '/client/resources/images/icon/imgicon.png';
+    },
+
+    // 이미지 로드 에러 처리
+    handleImageError(event) {
+      event.target.src = '/client/resources/images/icon/imgicon.png';
+    },
+
+    // 파일 미리보기 URL 생성
+    createFilePreview(file) {
+      return new Promise((resolve) => {
+        const reader = new FileReader();
+        reader.onload = (e) => resolve(e.target.result);
+        reader.onerror = () => resolve(null);
+        reader.readAsDataURL(file);
+      });
+    },
+
     // 상세 조회
     async fnFindDcry() {
       try {
@@ -220,6 +252,7 @@
       this.requestDTO.files = dcry.files.length > 0 ? dcry.files : []; // 기존 첨부파일
 
       this.multipartFiles = [];
+      this.filePreviewUrls = [];
       this.selectedCtgries = dcry.ctgrys.length > 0 ? dcry.ctgrys : [];
 
       // 썸네일
@@ -252,7 +285,7 @@
     },
 
     // 파일 업로드 처리 함수
-    processFiles(files) {
+    async processFiles(files) {
       const allowedTypes = ['jpg', 'jpeg', 'png', 'gif']; // 이미지 파일만 허용
       const maxSize = 10 * 1024 * 1024 * 1024; // 10GB
 
@@ -295,9 +328,13 @@
         this.multipartFiles.push(file);
         existingFilesMap.set(fileNameLower, file.name);
 
+        // 미리보기 URL 생성
+        const previewUrl = await this.createFilePreview(file);
+        this.filePreviewUrls.push(previewUrl);
+
         // 최초 등록 시 썸네일로 설정
-        if (this.requestDTO.files.length < 1 && this.multipartFiles.length > 0) {
-          this.selectedThumb = this.multipartFiles[0].name;
+        if (this.requestDTO.files.length < 1 && this.multipartFiles.length === 1) {
+          this.selectedThumb = file.name;
         }
       }
     },
@@ -306,6 +343,7 @@
     fnDelFile(type, separator) {
       if (type === 'new') {
         this.multipartFiles.splice(separator, 1);
+        this.filePreviewUrls.splice(separator, 1); // 미리보기 URL도 함께 삭제
 
         // 모든 새 파일이 삭제된 경우 input 요소 초기화
         if (this.multipartFiles.length === 0) {
@@ -496,4 +534,35 @@
   border-color: #1890ff;
   background-color: rgba(24, 144, 255, 0.1);
 }
+
+/* 썸네일 관련 스타일 */
+.file-item-with-thumbnail {
+  display: flex;
+  align-items: center;
+  gap: 12px;
+}
+
+.thumbnail-container {
+  flex-shrink: 0;
+}
+
+.file-thumbnail {
+  width: 120px;
+  height: 80px;
+  object-fit: cover;
+  border-radius: 4px;
+}
+
+.thumbnail-loading {
+  width: 120px;
+  height: 80px;
+  background-color: #f5f5f5;
+  border-radius: 4px;
+  border: 1px solid #ddd;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  font-size: 12px;
+  color: #666;
+}
 </style>
(파일 끝에 줄바꿈 문자 없음)
client/views/pages/bbsDcryPhoto/PicHistorySearch.vue
--- client/views/pages/bbsDcryPhoto/PicHistorySearch.vue
+++ client/views/pages/bbsDcryPhoto/PicHistorySearch.vue
@@ -108,7 +108,7 @@
         endYear: null,
         searchTy: "P", // 사진 기록물 고정
         searchCtgries: [],
-        order: "rgsde",
+        order: "prdctn_year",
         // 페이지네이션
         currentPage: 1, // 현재 페이지
         recordSize: 24, // 한 페이지에 표시할 데이터 개수
client/views/pages/bbsDcryVideo/VideoHistorySearch.vue
--- client/views/pages/bbsDcryVideo/VideoHistorySearch.vue
+++ client/views/pages/bbsDcryVideo/VideoHistorySearch.vue
@@ -107,7 +107,7 @@
         endYear: null,
         searchTy: "V", // 영상 기록물 고정
         searchCtgries: [],
-        order: "rgsde",
+        order: "prdctn_year",
         // 페이지네이션
         currentPage: 1, // 현재 페이지
         recordSize: 24, // 한 페이지에 표시할 데이터 개수
client/views/pages/bbsMediaVido/MediaVideoSearch.vue
--- client/views/pages/bbsMediaVido/MediaVideoSearch.vue
+++ client/views/pages/bbsMediaVido/MediaVideoSearch.vue
@@ -102,7 +102,7 @@
         endYear: null,
         searchTy: "M", // 미디어 영상 고정
         searchCtgries: [],
-        order: "rgsde",
+        order: "prdctn_year",
         // 페이지네이션
         currentPage: 1, // 현재 페이지
         recordSize: 24, // 한 페이지에 표시할 데이터 개수
client/views/pages/bbsNesDta/NewsReleaseInsert.vue
--- client/views/pages/bbsNesDta/NewsReleaseInsert.vue
+++ client/views/pages/bbsNesDta/NewsReleaseInsert.vue
@@ -62,20 +62,35 @@
               <div id="fileNames" class="file-names">
                 <div v-if="requestDTO.files.length === 0 && multipartFiles.length === 0">선택된 파일이 없습니다.</div>
                 <!-- 기존 등록된 파일 목록 -->
-                <div v-for="(file, idx) of requestDTO.files" :key="idx" class="flex-sp-bw mb-5 file-wrap">
-                  <div class="file-name">
-                    <img src="/client/resources/images/icon/imgicon.png" alt="fileicon">
-                    <p>{{ file.fileNm }}</p>
+                <div v-for="(file, idx) of requestDTO.files" :key="idx" class="mb-5">
+                  <div class="flex-sp-bw file-wrap">
+                    <div class="file-item-with-thumbnail">
+                      <div class="thumbnail-container">
+                        <img :src="getFileUrl(file)" alt="thumbnail" class="file-thumbnail" @error="handleImageError">
+                      </div>
+                      <div class="file-name">
+                        <img src="/client/resources/images/icon/imgicon.png" alt="fileicon">
+                        <p>{{ file.fileNm }}</p>
+                      </div>
+                    </div>
+                    <button type="button" class="cancel" @click="fnDelFile('old', file.fileId)"><b>✕</b></button>
                   </div>
-                  <button type="button" class="cancel" @click="fnDelFile('old', file.fileId)"><b>✕</b></button>
                 </div>
                 <!-- 새로 추가된 파일 목록 -->
-                <div v-for="(file, idx) of multipartFiles" :key="idx" class="flex-sp-bw mb-5 file-wrap">
-                  <div class="file-name">
-                    <img src="/client/resources/images/icon/imgicon.png" alt="fileicon">
-                    <p>{{ file.name }}</p>
+                <div v-for="(file, idx) of multipartFiles" :key="idx" class="mb-5">
+                  <div class="flex-sp-bw file-wrap">
+                    <div class="file-item-with-thumbnail">
+                      <div class="thumbnail-container">
+                        <img :src="filePreviewUrls[idx]" alt="thumbnail" class="file-thumbnail" v-if="filePreviewUrls[idx]">
+                        <div class="thumbnail-loading" v-else>Loading...</div>
+                      </div>
+                      <div class="file-name">
+                        <img src="/client/resources/images/icon/imgicon.png" alt="fileicon">
+                        <p>{{ file.name }}</p>
+                      </div>
+                    </div>
+                    <button type="button" class="cancel" @click="fnDelFile('new', idx)"><b>✕</b></button>
                   </div>
-                  <button type="button" class="cancel" @click="fnDelFile('new', idx)"><b>✕</b></button>
                 </div>
               </div>
             </li>
@@ -124,6 +139,7 @@
       isDragging: false,
 
       fileNames: [],
+      filePreviewUrls: [], // 새로 추가된 파일들의 미리보기 URL 저장
 
       // 등록/수정 요청 객체
       requestDTO: {
@@ -158,6 +174,26 @@
   },
 
   methods: {
+    // 기존 파일의 URL 생성 (서버에서 제공하는 파일 URL)
+    getFileUrl(file) {
+      return file.filePath || '/client/resources/images/icon/imgicon.png';
+    },
+
+    // 이미지 로드 에러 처리
+    handleImageError(event) {
+      event.target.src = '/client/resources/images/icon/imgicon.png';
+    },
+
+    // 파일 미리보기 URL 생성
+    createFilePreview(file) {
+      return new Promise((resolve) => {
+        const reader = new FileReader();
+        reader.onload = (e) => resolve(e.target.result);
+        reader.onerror = () => resolve(null);
+        reader.readAsDataURL(file);
+      });
+    },
+
     // 상세 조회
     async fnFindDcry() {
       try {
@@ -184,6 +220,7 @@
       this.requestDTO.files = nesDta.files.length > 0 ? nesDta.files : []; // 기존 첨부파일
 
       this.multipartFiles = [];
+      this.filePreviewUrls = [];
       this.selectedCtgries = nesDta.ctgrys.length > 0 ? nesDta.ctgrys : [];
     },
 
@@ -210,7 +247,7 @@
     },
 
     // 파일 업로드 처리 함수
-    processFiles(files) {
+    async processFiles(files) {
       const allowedTypes = ['jpg', 'jpeg', 'png', 'gif']; // 이미지 파일만 허용
       const maxSize = 10 * 1024 * 1024 * 1024; // 10GB
 
@@ -239,6 +276,10 @@
         }
 
         this.multipartFiles.push(file);
+
+        // 미리보기 URL 생성
+        const previewUrl = await this.createFilePreview(file);
+        this.filePreviewUrls.push(previewUrl);
       }
     },
 
@@ -253,6 +294,7 @@
     fnDelFile(type, separator) {
       if (type === 'new') {
         this.multipartFiles.splice(separator, 1);
+        this.filePreviewUrls.splice(separator, 1); // 미리보기 URL도 함께 삭제
 
         // 모든 새 파일이 삭제된 경우 input 요소 초기화
         if (this.multipartFiles.length === 0) {
@@ -323,6 +365,20 @@
           }
         }
 
+        // 파일 추가
+        if (this.multipartFiles.length > 0) {
+          for (let file of this.multipartFiles) {
+            formData.append("multipartFiles", file);
+          }
+        }
+
+        // 기존파일 수정
+        if (!this.$isEmpty(this.pageId) && this.requestDTO.files.length > 0) {
+          for (let file of this.requestDTO.files) {
+            formData.append("files", file.fileId);
+          }
+        }
+
         // API 통신
         const response = this.$isEmpty(this.pageId) ? await saveNesDtaProc(formData) : await updateNesDtaProc(formData);
         alert(this.$isEmpty(this.pageId) ? "등록되었습니다." : "수정되었습니다.");
@@ -379,4 +435,35 @@
   border-color: #1890ff;
   background-color: rgba(24, 144, 255, 0.1);
 }
+
+/* 썸네일 관련 스타일 */
+.file-item-with-thumbnail {
+  display: flex;
+  align-items: center;
+  gap: 12px;
+}
+
+.thumbnail-container {
+  flex-shrink: 0;
+}
+
+.file-thumbnail {
+  width: 120px;
+  height: 80px;
+  object-fit: cover;
+  border-radius: 4px;
+}
+
+.thumbnail-loading {
+  width: 120px;
+  height: 80px;
+  background-color: #f5f5f5;
+  border-radius: 4px;
+  border: 1px solid #ddd;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  font-size: 12px;
+  color: #666;
+}
 </style>
(파일 끝에 줄바꿈 문자 없음)
client/views/pages/bbsNesDta/NewsReleaseSearch.vue
--- client/views/pages/bbsNesDta/NewsReleaseSearch.vue
+++ client/views/pages/bbsNesDta/NewsReleaseSearch.vue
@@ -103,7 +103,7 @@
         endYear: null,
         searchTy: "N", // 스크랩 자료 고정
         searchCtgries: [],
-        order: "rgsde",
+        order: "prdctn_year",
         // 페이지네이션
         currentPage: 1, // 현재 페이지
         recordSize: 24, // 한 페이지에 표시할 데이터 개수
client/views/pages/main/TotalSearch.vue
--- client/views/pages/main/TotalSearch.vue
+++ client/views/pages/main/TotalSearch.vue
@@ -58,7 +58,7 @@
         startYear: null,
         endYear: null,
         searchCtgries: [],
-        order: "rgsde",
+        order: "prdctn_year",
       },
 
       // URL 파라미터로부터 가져온 초기 검색 조건
Add a comment
List