박정하 박정하 04-04
250404 박정하 중복 파일 명 방지용 유효성 검사 추가
@e6891b09c9f2f0e31929344dfaea548057e8959c
client/resources/css/user/sub.css
--- client/resources/css/user/sub.css
+++ client/resources/css/user/sub.css
@@ -194,7 +194,7 @@
         }
     }
 
-   
+
 }
 
 /* 카테고리 */
@@ -343,7 +343,7 @@
             overflow-y: auto;
             overflow-x: hidden;
             }
-            
+
         }
         .mark {
             width: fit-content;
@@ -653,7 +653,7 @@
             font-size: 14px;
             font-family: "Pretendard-EL";
         }
-      
+
     }
 
 }
@@ -917,14 +917,14 @@
                 height: 120px;
                 margin: 0 auto;
                 .swiper-slide{
-                    background-image: linear-gradient(#fff, #fff), 
+                    background-image: linear-gradient(#fff, #fff),
                     linear-gradient(-45deg, #fff, #fff);
                     background-origin: border-box;
                     background-clip: content-box, border-box;
                     border: 3px solid transparent;
                 }
                 .swiper-slide:hover{
-                    background-image: linear-gradient(#fff, #fff), 
+                    background-image: linear-gradient(#fff, #fff),
                     linear-gradient(-45deg, #ca3e49, #3d355d);
                 }
                 .swiper-wrapper {
@@ -936,7 +936,7 @@
 
                 }
 
-                input{position: absolute; right: 6px; top: 6px;} 
+                input{position: absolute; right: 6px; top: 6px; z-index: 5;}
             }
         }
 
@@ -1142,7 +1142,7 @@
             overflow-y: auto;
             overflow-x: hidden; /* Optional: Prevent horizontal scroll */
           }
-          tbody tr{ 
+          tbody tr{
             table-layout: fixed; display: table;width: 100%;
             td{cursor: pointer;}
         }
client/views/pages/bbsDcry/photo/PicHistoryDetail.vue
--- client/views/pages/bbsDcry/photo/PicHistoryDetail.vue
+++ client/views/pages/bbsDcry/photo/PicHistoryDetail.vue
@@ -35,10 +35,7 @@
           <div class="thumbnail">
             <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">
-                <div class="checkbox-wrapper" @click.stop>
-                  <input type="checkbox" :id="'photo_' + idx" :value="item.fileId" v-model="selectedFiles" />
-                  <label :for="'photo_' + idx"></label>
-                </div>
+                <input type="checkbox" :id="'photo_' + idx" :value="item.fileId" v-model="selectedFiles" @click.stop />
                 <img :src="item.filePath" :alt="item.fileNm" />
               </swiper-slide>
             </swiper>
@@ -198,15 +195,12 @@
         if (type === 'selected') {
           fileList = this.selectedFiles;
         } else if (type === 'all') {
-          if (this.findResult.files.length == 1) {
-            fileList = this.findResult.files[0].fileId;
-          } else {
-            fileList = this.findResult.files.map(file => file.fileId);
-          }
+          fileList = this.findResult.files.map(file => file.fileId);
         }
 
         let isMultiple = fileList.length > 1;
         let fileIds = isMultiple ? fileList : fileList[0];
+
         const response = isMultiple ? await multiFileDownloadProc(fileIds) : await fileDownloadProc(fileIds);
 
         // 파일명 추출 부분 수정
client/views/pages/bbsDcry/photo/PicHistoryInsert.vue
--- client/views/pages/bbsDcry/photo/PicHistoryInsert.vue
+++ client/views/pages/bbsDcry/photo/PicHistoryInsert.vue
@@ -240,22 +240,45 @@
       const allowedTypes = ['jpg', 'jpeg', 'png', 'gif']; // 이미지 파일만 허용
       const maxSize = 10 * 1024 * 1024 * 1024; // 10GB
 
+      // 중복 파일 확인을 위한 Map (키: 파일명+확장자(소문자), 값: 원본 파일명)
+      const existingFilesMap = new Map();
+
+      // 기존 업로드된 파일 정보 추가
+      this.requestDTO.files.forEach(file => {
+        const fullName = file.fileNm.toLowerCase();
+        existingFilesMap.set(fullName, file.fileNm);
+      });
+
+      // 새로 추가된 파일 정보 추가
+      this.multipartFiles.forEach(file => {
+        existingFilesMap.set(file.name.toLowerCase(), file.name);
+      });
+
       for (let file of files) {
-        const fileType = file.name.split('.').pop().toLowerCase();
+        const fileNameLower = file.name.toLowerCase();
+        const fileExtension = fileNameLower.split('.').pop();
+
+        // 파일명+확장자 중복 검증 (대소문자 무시하고 비교)
+        if (existingFilesMap.has(fileNameLower)) {
+          alert("파일 목록에 이미 동일한 파일 명을 가진 파일이 있습니다. 동일한 이름을 가진 파일은 업로드할 수 없습니다.");
+          continue;
+        }
 
         // 파일 타입 검증
-        if (!allowedTypes.includes(fileType)) {
-          alert(`${file.name} 파일은 허용되지 않는 형식입니다. 이미지 파일(jpg, jpeg, png, gif)만 업로드 가능합니다.`);
-          return;
+        if (!allowedTypes.includes(fileExtension)) {
+          alert("이미지 파일(jpg, jpeg, png, gif)만 업로드 가능합니다.");
+          continue;
         }
 
         // 파일 크기 제한 검증
         if (file.size > maxSize) {
           alert(`${file.name} 파일이 10GB를 초과합니다.`);
-          return;
+          continue;
         }
 
+        // 파일명+확장자 조합이 중복되지 않으면 추가
         this.multipartFiles.push(file);
+        existingFilesMap.set(fileNameLower, file.name);
       }
     },
 
Add a comment
List