hmkim 05-19
250519 김혜민 로그인실패시 확인 keyup 오류 수정
@41f04d841fcb286c547391d00d8d94987b206869
client/resources/css/component.css
--- client/resources/css/component.css
+++ client/resources/css/component.css
@@ -427,6 +427,8 @@
     justify-content: center;
     align-items: center;
     z-index: 100000;
+    /* 키보드 이벤트를 위한 포커스 관련 스타일 */
+    outline: none;
 }
 
 .modal-container {
client/views/component/common/AlertModal.vue
--- client/views/component/common/AlertModal.vue
+++ client/views/component/common/AlertModal.vue
@@ -1,5 +1,5 @@
 <template>
-  <div v-show="isModalOpen" class="modal-wrapper">
+  <div v-show="isModalOpen" class="modal-wrapper" tabindex="-1" ref="modalContainer">
     <div class="modal-container small-modal">
       <div class="modal-title text-ct">
         <h2>{{ modalTitle }}</h2>
@@ -17,13 +17,14 @@
         </div>
       </div>
       <div class="modal-end flex justify-center" style="flex-wrap: nowrap;">
-        <button class="blue-btn large-btn" @click="onConfirm" @keyup.enter="onConfirm" autofocus v-if="isModalOpen">확인</button>
+        <button class="blue-btn large-btn" @click="onConfirm" ref="confirmBtn"  @keydown="handleKeydown" v-if="isModalOpen">확인</button>
         <button class="gray-btn large-btn" @click="onCancel" v-show="modalType === 'confirm'">취소</button>
         <button class="gray-btn large-btn" @click="onRadioCancel" v-show="modalType === 'radio'">취소</button>
       </div>
     </div>
   </div>
 </template>
+
 <script>
 export default {
   props: {
@@ -46,20 +47,107 @@
         type: "move",
         checkBox: false
       },
-      currentPromise: null
+      currentPromise: null,
+      keyboardEventHandler: null,
+      lastActiveElement: null
     }
   },
   methods: {
+    // 키보드 이벤트 처리기
+    handleKeydown(event) {
+      // 모달 안에서 엔터키가 눌렸을 때
+      if (this.isModalOpen && event.key === 'Enter') {
+        event.preventDefault();
+        event.stopPropagation(); // 다른 요소로 이벤트 전파 방지
+        this.onConfirm(); // 확인 버튼 클릭 효과
+        return false;
+      }
+    },
+    
+    // 모달 열릴 때 전역 이벤트 핸들러 추가
+    addGlobalKeyboardHandler() {
+      if (!this.keyboardEventHandler) {
+        this.keyboardEventHandler = (event) => {
+          // 모달이 열려있고 엔터키를 누를 때만 처리
+          if (this.isModalOpen && (event.key === 'Enter')) {
+            event.preventDefault();
+            event.stopPropagation();
+            
+            if (event.key === 'Enter') {
+              this.onConfirm();
+            }
+            
+            return false;
+          }
+        };
+        
+        // 캡처 단계에서 이벤트를 잡아서 처리
+        document.addEventListener('keydown', this.keyboardEventHandler, true);
+      }
+    },
+    
+    // 모달 닫힐 때 전역 이벤트 핸들러 제거
+    removeGlobalKeyboardHandler() {
+      if (this.keyboardEventHandler) {
+        document.removeEventListener('keydown', this.keyboardEventHandler, true);
+        this.keyboardEventHandler = null;
+      }
+    },
+    
+    // 현재 활성 요소 저장
+    saveActiveElement() {
+      this.lastActiveElement = document.activeElement;
+    },
+    
+    // 이전 활성 요소로 포커스 복원
+    restoreActiveElement() {
+      if (this.lastActiveElement && this.lastActiveElement.focus) {
+        setTimeout(() => {
+          try {
+            this.lastActiveElement.focus();
+          } catch (e) {
+            console.error('포커스 복원 중 오류:', e);
+          }
+        }, 100);
+      }
+    },
+
     // 모달 닫기
     closeModal() {
       this.isModalOpen = false;
       this.modalType = 'alert';
+      this.removeGlobalKeyboardHandler();
+      this.restoreActiveElement();
+      
+      // 확실한 정리를 위한 추가 타이머
+      setTimeout(() => {
+        if (this.keyboardEventHandler) {
+          this.removeGlobalKeyboardHandler();
+        }
+      }, 500);
+      
+      // 모달 닫힘 이벤트 발생 (선택적)
+      this.$emit('modal-closed');
     },
 
     // 일반 모달 표시
     showModal() {
+      this.saveActiveElement();
       this.modalType = 'alert';
       this.isModalOpen = true;
+      this.addGlobalKeyboardHandler();
+      
+      // 모달에 포커스 설정
+      this.$nextTick(() => {
+        if (this.$refs.confirmBtn) {
+          this.$refs.confirmBtn.focus();
+        } else if (this.$refs.modalContainer) {
+          this.$refs.modalContainer.focus();
+        }
+      });
+      
+      // 모달 열림 이벤트 발생 (선택적)
+      this.$emit('modal-opened');
     },
 
     // 확인 버튼 클릭 핸들러
@@ -112,17 +200,47 @@
 
     // confirm 모달 표시 (확인/취소)
     async showConfirm() {
+      this.saveActiveElement();
       this.modalType = 'confirm';
       this.isModalOpen = true;
+      this.addGlobalKeyboardHandler();
+      
+      // 모달에 포커스 설정
+      this.$nextTick(() => {
+        if (this.$refs.confirmBtn) {
+          this.$refs.confirmBtn.focus();
+        } else if (this.$refs.modalContainer) {
+          this.$refs.modalContainer.focus();
+        }
+      });
+      
+      // 모달 열림 이벤트 발생 (선택적)
+      this.$emit('modal-opened');
+      
       return this.createPromise();
     },
 
     // radio confirm 모달 표시 (라디오 옵션)
     async showRadioConfirm() {
+      this.saveActiveElement();
       this.modalType = 'radio';
       this.isModalOpen = true;
       this.moveOrCopy.type = "move";
       this.moveOrCopy.checkBox = false;
+      this.addGlobalKeyboardHandler();
+      
+      // 모달에 포커스 설정
+      this.$nextTick(() => {
+        if (this.$refs.confirmBtn) {
+          this.$refs.confirmBtn.focus();
+        } else if (this.$refs.modalContainer) {
+          this.$refs.modalContainer.focus();
+        }
+      });
+      
+      // 모달 열림 이벤트 발생 (선택적)
+      this.$emit('modal-opened');
+      
       return this.createPromise();
     },
 
@@ -145,6 +263,10 @@
     message(newVal) {
       this.modalMessage = newVal;
     }
+  },
+  // 컴포넌트가 제거될 때 이벤트 리스너 정리
+  beforeDestroy() {
+    this.removeGlobalKeyboardHandler();
   }
 }
 </script>
(파일 끝에 줄바꿈 문자 없음)
client/views/pages/AppRouter.js
--- client/views/pages/AppRouter.js
+++ client/views/pages/AppRouter.js
@@ -187,7 +187,11 @@
         userAuthCheck(to, from, next);
       } else {
         // 로그인 상태가 아니거나 세션이 만료된 경우
+        const wasLoggedIn = store.state.loginUser !== null;
         store.commit("setLoginUser", null); // 로그인 정보 초기화
+        if (wasLoggedIn) {
+          alert("로그인 세션이 만료되었습니다. 다시 로그인해주세요.");
+        }
         next("/login.page");
       }
     })
Add a comment
List