박정하 박정하 04-21
250421 박정하 이슈 수정
@61f4ad96778349e6f7b785438f273925dee7d26e
client/resources/api/user.js
--- client/resources/api/user.js
+++ client/resources/api/user.js
@@ -1,41 +1,39 @@
-import {apiClient} from "./index";
+import { apiClient } from "./index";
 import store from '../../views/pages/AppStore';
 
 // 로그인
 export const loginProc = mber => {
-    return apiClient.post(`/user/login.json`, mber);
+  return apiClient.post(`/user/login.json`, mber);
 }
 
 // 로그아웃
 export const logOutProc = () => {
-    return apiClient.post(`/user/logout.json`, {}, {
-        headers: {
-            'refresh': store.state.refresh
-        }
-    });
+  return apiClient.post(`/user/logout.json`, {}, {
+    headers: { 'refresh': store.state.refresh }
+  });
 }
 
 // 아이디로 유저 찾기
 export const findByIdProc = userId => {
-    return apiClient.get(`/user/${userId}/users.json`);
+  return apiClient.get(`/user/${userId}/users.json`);
 }
 
 // 회원가입
 export const join = mber => {
-    return apiClient.post(`/user/join.json`, mber);
+  return apiClient.post(`/user/join.json`, mber);
 }
 
 // 유저 정보 변경
 export const updateUsers = (userId, updateUserDTO) => {
-    return apiClient.put(`/user/${userId}/users.json`, updateUserDTO);
+  return apiClient.put(`/user/${userId}/users.json`, updateUserDTO);
 }
 
 // 유저 비밀번호 변경
 export const updatePassword = (userId, passwordDTO) => {
-    return apiClient.put(`/user/${userId}/updatePassword.json`, passwordDTO);
+  return apiClient.put(`/user/${userId}/updatePassword.json`, passwordDTO);
 }
 
 // 유저저 목록 조회 (검색조건 있음)
 export const findAllUsers = searchReqDTO => {
-    return apiClient.get(`/user/users.json`, { params: searchReqDTO });
-  }
(파일 끝에 줄바꿈 문자 없음)
+  return apiClient.get(`/user/users.json`, { params: searchReqDTO });
+}
(파일 끝에 줄바꿈 문자 없음)
client/resources/js/cmmnPlugin.js
--- client/resources/js/cmmnPlugin.js
+++ client/resources/js/cmmnPlugin.js
@@ -1,3 +1,5 @@
+import store from '../../views/pages/AppStore'
+
 export default {
   install(Vue) {
     // 빈값체크
@@ -32,8 +34,7 @@
         try {
           // 브라우저 환경에서는 DOMParser 사용
           const doc = new DOMParser().parseFromString(html, 'text/html');
-          let text = doc.body.textContent || '';
-          return text.replace(/\s+/g, ' ').trim();
+          return doc.body.textContent || '';
         } catch (e) {
           // DOMParser 실패시 정규식 방식으로 폴백
           console.warn('DOMParser failed, falling back to regex', e);
@@ -68,10 +69,33 @@
       // 남은 이름 있는 엔티티 제거 (… 등)
       text = text.replace(/&[a-zA-Z]+;/g, '');
 
-      // 연속된 공백 문자 하나로 처리
-      text = text.replace(/\s+/g, ' ').trim();
-
       return text;
     };
-  }
+
+    // 게시물 권한 체크
+    Vue.config.globalProperties.$registerChk = (register) => {
+      // 사용자 권한 확인
+      const roles = store.state.roles;
+      if (roles != null && roles.length > 0) {
+        for (let role of roles) {
+          if (role.authority === 'ROLE_ADMIN') {
+            return true; // 관리자인 경우 true 반환
+          }
+        }
+      }
+
+      // 관리자가 아닌 경우 작성자 확인
+      const userId = store.state.userId;
+      if (register === userId) {
+        return true; // 작성자인 경우 true 반환
+      } else {
+        return false; // 작성자가 아닌 경우 false 반환
+      }
+    };
+
+    Vue.config.globalProperties.$processTitle = (title) => {
+      if (!title) return '';
+      return title.trim().replace(/\s+/g, ' ');
+    }
+  },
 }
(파일 끝에 줄바꿈 문자 없음)
client/resources/js/youtubeUtils.js
--- client/resources/js/youtubeUtils.js
+++ client/resources/js/youtubeUtils.js
@@ -43,6 +43,6 @@
 export function getYouTubeThumbnail(url) {
   const videoId = extractYouTubeVideoId(url);
   if (!videoId) return '';
-  // return `https://i.ytimg.com/vi/${videoId}/mqdefault.jpg`; // 기본 해상도
-  return `https://i.ytimg.com/vi/${videoId}/maxresdefault.jpg`; // 고해상도 (지원 안되는 영상 있음)
+  return `https://i.ytimg.com/vi/${videoId}/mqdefault.jpg`; // 기본 해상도
+  //return `https://i.ytimg.com/vi/${videoId}/maxresdefault.jpg`; // 고해상도 (지원 안되는 영상 있음)
 }
(파일 끝에 줄바꿈 문자 없음)
client/views/component/SearchFormComponent.vue
--- client/views/component/SearchFormComponent.vue
+++ client/views/component/SearchFormComponent.vue
@@ -256,6 +256,16 @@
         }
       }
 
+      if (!this.$isEmpty(this.formData.startYear) && !this.$isEmpty(this.formData.endYear)) {
+        const startYear = parseInt(this.formData.startYear);
+        const endYear = parseInt(this.formData.endYear);
+
+        if (startYear > endYear) {
+          alert('종료 연도는 시작 연도보다 작을 수 없습니다.');
+          return;
+        }
+      }
+
       // 부모 컴포넌트에 이벤트 발생 (데이터 전달)
       this.$emit('search', JSON.parse(JSON.stringify(this.formData)));
     },
client/views/component/editor/EditorComponent.vue
--- client/views/component/editor/EditorComponent.vue
+++ client/views/component/editor/EditorComponent.vue
@@ -160,17 +160,8 @@
     updateContents(data) {
       this.$emit('update:contents', data);
 
-      // 순수 텍스트 추출 (방법 2)
-      if (this.editorInstance) {
-        const plainText = Array.from(this.editorInstance.model.document.getRoot().getChildren())
-          .map(rootChild => this.editorInstance.data.processor.toData(
-            this.editorInstance.editing.mapper.toViewElement(rootChild)
-          ))
-          .join('\n')
-          .replace(/<[^>]*>?/gm, '');
-
-        this.$emit('update:plainContents', plainText);
-      }
+      const plainText = this.$stripHtml(data);
+      this.$emit('update:plainContents', plainText);
     }
   }
 };
client/views/component/listLayout/CardStyleComponent.vue
--- client/views/component/listLayout/CardStyleComponent.vue
+++ client/views/component/listLayout/CardStyleComponent.vue
@@ -11,7 +11,7 @@
           <h5>{{ item.sj }}</h5>
           <p v-if="item.hasOwnProperty('adres')" class="address">{{ item.adres }}</p>
           <p class="text">{{ item.cn ? $stripHtml(item.cn) : '' }}</p>
-          <div class="mb-20">
+          <div class="mb-20" style="white-space: pre">
             <ul class="category">
               <li v-for="(ctgry, ctgryIdx) of item.ctgrys" :key="ctgryIdx" class="category1">{{ ctgry.ctgryNm }}</li>
             </ul>
client/views/pages/bbsDcry/photo/PicHistoryDetail.vue
--- client/views/pages/bbsDcry/photo/PicHistoryDetail.vue
+++ client/views/pages/bbsDcry/photo/PicHistoryDetail.vue
@@ -85,8 +85,8 @@
       </dl>
     </form>
     <div class="btn-group flex-center">
-      <button class="red-line " type="button" @click="fnDelete">삭제</button>
-      <button class="blue-line " type="button" @click="fnMoveTo('edit', pageId)">수정</button>
+      <button v-if="isRegister" class="red-line " type="button" @click="fnDelete">삭제</button>
+      <button v-if="isRegister" class="blue-line " type="button" @click="fnMoveTo('edit', pageId)">수정</button>
       <button class="gray-line-bg " type="button" @click="fnMoveTo('list')">목록</button>
     </div>
   </div>
@@ -149,6 +149,8 @@
       loading: false,
 
       activeIndex: 0,
+
+      isRegister: false,
     };
   },
 
@@ -179,6 +181,7 @@
           alert('올바른 접근이 아닙니다.');
           this.fnMoveTo('list'); // 목록으로 이동
         }
+        this.isRegister = this.$registerChk(this.findResult.register);
       } catch (error) {
         alert('조회중 오류가 발생했습니다.');
         this.fnMoveTo('list');
client/views/pages/bbsDcry/photo/PicHistoryInsert.vue
--- client/views/pages/bbsDcry/photo/PicHistoryInsert.vue
+++ client/views/pages/bbsDcry/photo/PicHistoryInsert.vue
@@ -55,7 +55,7 @@
               </div>
             </li>
             <li class="file-insert">
-              <input type="file" id="fileInput" class="file-input" multiple accept="image/jpeg,image/png,image/gif,image/jpg" @change="handleFileSelect">
+              <input type="file" id="fileInput" ref="fileInput" class="file-input" multiple accept="image/jpeg,image/png,image/gif,image/jpg" @change="handleFileSelect">
               <label for="fileInput" class="file-label mb-20" @dragover.prevent="handleDragOver" @dragleave.prevent="handleDragLeave" @drop.prevent="handleDrop" :class="{ 'drag-over': isDragging }">
                 <div class="flex-center align-center">
                   <img :src="fileicon" alt="">
@@ -322,6 +322,11 @@
     fnDelFile(type, separator) {
       if (type === 'new') {
         this.multipartFiles.splice(separator, 1);
+
+        // 모든 새 파일이 삭제된 경우 input 요소 초기화
+        if (this.multipartFiles.length === 0) {
+          this.$refs.fileInput.value = '';
+        }
       } else if (type === 'old') {
         this.requestDTO.files = this.requestDTO.files.filter(item => item.fileOrdr !== separator);
       }
@@ -357,6 +362,10 @@
 
     // 등록
     async submitForm() {
+      // 공백제거
+      this.requestDTO.sj = this.$processTitle(this.requestDTO.sj);
+      this.requestDTO.adres = this.$processTitle(this.requestDTO.adres);
+
       // 유효성 검사
       if (this.$isEmpty(this.requestDTO.sj)) {
         alert("제목을 입력해 주세요.");
@@ -473,6 +482,9 @@
       };
 
       if (routes[type]) {
+        if (!this.$isEmpty(this.pageId) && type === 'list') {
+          this.$router.push({ name: 'PicHistoryDetail', query: { id: this.pageId } });
+        }
         this.$router.push(routes[type]);
       } else {
         alert("올바르지 않은 경로를 요청하여 목록으로 이동합니다.");
client/views/pages/bbsDcry/video/VideoHistoryDetail.vue
--- client/views/pages/bbsDcry/video/VideoHistoryDetail.vue
+++ client/views/pages/bbsDcry/video/VideoHistoryDetail.vue
@@ -58,8 +58,8 @@
       </dl>
     </form>
     <div class="btn-group flex-center">
-      <button type="button" class="red-line" @click="fnDelete">삭제</button>
-      <button type="button" class="blue-line" @click="fnMoveTo('edit', pageId)">수정</button>
+      <button v-if="isRegister" type="button" class="red-line" @click="fnDelete">삭제</button>
+      <button v-if="isRegister" type="button" class="blue-line" @click="fnMoveTo('edit', pageId)">수정</button>
       <button type="button" class="gray-line-bg" @click="fnMoveTo('list')">목록</button>
       <button type="button" class="gradient" @click="fnDownload">다운로드</button>
       <div v-if="loading" class="loading-overlay">
@@ -98,6 +98,8 @@
       findResult: {},
       selectedFiles: [],
       loading: false,
+
+      isRegister: false,
     };
   },
 
@@ -124,6 +126,7 @@
           alert('올바른 접근이 아닙니다.');
           this.fnMoveTo('list'); // 목록으로 이동
         }
+        this.isRegister = this.$registerChk(this.findResult.register);
       } catch (error) {
         alert('조회중 오류가 발생했습니다.');
         this.fnMoveTo('list');
client/views/pages/bbsDcry/video/VideoHistoryInsert.vue
--- client/views/pages/bbsDcry/video/VideoHistoryInsert.vue
+++ client/views/pages/bbsDcry/video/VideoHistoryInsert.vue
@@ -248,7 +248,7 @@
       // 유효성 검사
       if ((files.length + this.multipartFiles.length + this.requestDTO.files.length) > 1) {
         alert("영상 파일은 한 개만 등록 가능합니다.");
-        this.resetFileInput();
+        this.resetFileInput(); // input 파일 목록 비움
         return;
       }
 
@@ -258,14 +258,14 @@
         // 파일 타입 검증
         if (!allowedTypes.includes(fileType)) {
           alert(`${file.name} 파일은 허용되지 않는 형식입니다. 영상 파일(mp4, mov, avi, wmv, mkv, webm)만 업로드 가능합니다.`);
-          this.resetFileInput();
+          this.resetFileInput(); // input 파일 목록 비움
           return;
         }
 
         // 파일 크기 제한 검증
         if (file.size > maxSize) {
           alert(`${file.name} 파일이 10GB를 초과합니다.`);
-          this.resetFileInput();
+          this.resetFileInput(); // input 파일 목록 비움
           return;
         }
 
@@ -284,6 +284,11 @@
     fnDelFile(type, separator) {
       if (type === 'new') {
         this.multipartFiles.splice(separator, 1);
+
+        // 모든 새 파일이 삭제된 경우 input 요소 초기화
+        if (this.multipartFiles.length === 0) {
+          this.resetFileInput(); // input 파일 목록 비움
+        }
       } else if (type === 'old') {
         this.requestDTO.files = this.requestDTO.files.filter(item => item.fileOrdr !== separator);
       }
@@ -291,6 +296,9 @@
 
     // 등록
     async submitForm() {
+      // 공백제거
+      this.requestDTO.sj = this.$processTitle(this.requestDTO.sj);
+      this.requestDTO.adres = this.$processTitle(this.requestDTO.adres);
       // 유효성 검사
       if (this.$isEmpty(this.requestDTO.sj)) {
         alert("제목을 입력해 주세요.");
@@ -398,6 +406,9 @@
       };
 
       if (routes[type]) {
+        if (!this.$isEmpty(this.pageId) && type === 'list') {
+          this.$router.push({ name: 'PicHistoryDetail', query: { id: this.pageId } });
+        }
         this.$router.push(routes[type]);
       } else {
         alert("올바르지 않은 경로를 요청하여 목록으로 이동합니다.");
client/views/pages/bbsMediaVido/MediaVideoDetail.vue
--- client/views/pages/bbsMediaVido/MediaVideoDetail.vue
+++ client/views/pages/bbsMediaVido/MediaVideoDetail.vue
@@ -57,8 +57,8 @@
       </dl>
     </form>
     <div class="btn-group flex-center">
-      <button class="red-line " type="button" @click="fnDelete">삭제</button>
-      <button class="blue-line " type="button" @click="fnMoveTo('edit', pageId)">수정</button>
+      <button v-if="isRegister" class="red-line " type="button" @click="fnDelete">삭제</button>
+      <button v-if="isRegister" class="blue-line " type="button" @click="fnMoveTo('edit', pageId)">수정</button>
       <button class="gray-line-bg " type="button" @click="fnMoveTo('list')">목록</button>
     </div>
   </div>
@@ -91,6 +91,8 @@
       pageId: null,
       findResult: {},
       selectedFiles: [],
+
+      isRegister: false,
     };
   },
 
@@ -112,6 +114,7 @@
       try {
         const response = await findMediaVidoProc(this.pageId);
         this.findResult = response.data.data.mediaVido;
+        this.isRegister = this.$registerChk(this.findResult.register);
       } catch (error) {
         alert('조회중 오류가 발생했습니다.');
         this.fnMoveTo('list');
client/views/pages/bbsMediaVido/MediaVideoInsert.vue
--- client/views/pages/bbsMediaVido/MediaVideoInsert.vue
+++ client/views/pages/bbsMediaVido/MediaVideoInsert.vue
@@ -159,6 +159,8 @@
 
     // 등록
     async submitForm() {
+      // 공백제거
+      this.requestDTO.sj = this.$processTitle(this.requestDTO.sj);
       // 유효성 검사
       if (this.$isEmpty(this.requestDTO.sj)) {
         alert("제목을 입력해 주세요.");
@@ -215,6 +217,9 @@
       };
 
       if (routes[type]) {
+        if (!this.$isEmpty(this.pageId) && type === 'list') {
+          this.$router.push({ name: 'PicHistoryDetail', query: { id: this.pageId } });
+        }
         this.$router.push(routes[type]);
       } else {
         alert("올바르지 않은 경로를 요청하여 목록으로 이동합니다.");
client/views/pages/bbsNesDta/NewsReleaseDetail.vue
--- client/views/pages/bbsNesDta/NewsReleaseDetail.vue
+++ client/views/pages/bbsNesDta/NewsReleaseDetail.vue
@@ -35,7 +35,7 @@
               <dd class="mb-20">
                 <img :src="addressicon" alt="">
                 <span>링크</span>
-                <p>{{ findResult.link }}</p>
+                <p><a :href="findResult.link" target="_blank">{{ findResult.link }}</a></p>
               </dd>
               <dd class="mb-20">
                 <img :src="yearicon" alt="">
@@ -63,8 +63,8 @@
       </dl>
     </form>
     <div class="btn-group flex-center">
-      <button class="red-line " type="button" @click="fnDelete">삭제</button>
-      <button class="blue-line " type="button" @click="fnMoveTo('edit', pageId)">수정</button>
+      <button v-if="isRegister" class="red-line " type="button" @click="fnDelete">삭제</button>
+      <button v-if="isRegister" class="blue-line " type="button" @click="fnMoveTo('edit', pageId)">수정</button>
       <button class="gray-line-bg " type="button" @click="fnMoveTo('list')">목록</button>
     </div>
   </div>
@@ -95,6 +95,8 @@
       pageId: null,
       findResult: {},
       selectedFiles: [],
+
+      isRegister: false,
     };
   },
 
@@ -116,6 +118,7 @@
       try {
         const response = await findNesDtaProc(this.pageId);
         this.findResult = response.data.data.nesDta;
+        this.isRegister = this.$registerChk(this.findResult.register);
       } catch (error) {
         alert('조회중 오류가 발생했습니다.');
 
client/views/pages/bbsNesDta/NewsReleaseInsert.vue
--- client/views/pages/bbsNesDta/NewsReleaseInsert.vue
+++ client/views/pages/bbsNesDta/NewsReleaseInsert.vue
@@ -233,7 +233,7 @@
       // 유효성 검사
       if ((files.length + this.multipartFiles.length + this.requestDTO.files.length) > 1) {
         alert("썸네일은 한 개만 등록 가능합니다.");
-        this.resetFileInput();
+        this.resetFileInput(); // input 파일 목록 비움
         return;
       }
 
@@ -243,14 +243,14 @@
         // 파일 타입 검증
         if (!allowedTypes.includes(fileType)) {
           alert(`${file.name} 파일은 허용되지 않는 형식입니다. 이미지 파일(jpg, jpeg, png, gif)만 업로드 가능합니다.`);
-          this.resetFileInput();
+          this.resetFileInput(); // input 파일 목록 비움
           return;
         }
 
         // 파일 크기 제한 검증
         if (file.size > maxSize) {
           alert(`${file.name} 파일이 10GB를 초과합니다.`);
-          this.resetFileInput();
+          this.resetFileInput(); // input 파일 목록 비움
           return;
         }
 
@@ -269,6 +269,11 @@
     fnDelFile(type, separator) {
       if (type === 'new') {
         this.multipartFiles.splice(separator, 1);
+
+        // 모든 새 파일이 삭제된 경우 input 요소 초기화
+        if (this.multipartFiles.length === 0) {
+          this.resetFileInput(); // input 파일 목록 비움
+        }
       } else if (type === 'old') {
         this.requestDTO.files = this.requestDTO.files.filter(item => item.fileId !== separator);
       }
@@ -276,6 +281,8 @@
 
     // 등록
     async submitForm() {
+      // 공백제거
+      this.requestDTO.sj = this.$processTitle(this.requestDTO.sj);
       // 유효성 검사
       if (this.$isEmpty(this.requestDTO.sj)) {
         alert("제목을 입력해 주세요.");
@@ -378,6 +385,9 @@
       };
 
       if (routes[type]) {
+        if (!this.$isEmpty(this.pageId) && type === 'list') {
+          this.$router.push({ name: 'PicHistoryDetail', query: { id: this.pageId } });
+        }
         this.$router.push(routes[type]);
       } else {
         alert("올바르지 않은 경로를 요청하여 목록으로 이동합니다.");
Add a comment
List