refactor: SQL 쿼리 관리 모듈화 및 메일 관리 UI/UX 고도화

This commit is contained in:
2026-03-17 14:27:25 +09:00
parent 74f11d3bd4
commit d0b33edea8
22 changed files with 851 additions and 1324 deletions

View File

@@ -60,15 +60,15 @@
</div>
</main>
<!-- 모달 레이어 (최외각 유지) -->
<div id="authModal" class="activity-modal-overlay" style="display:none;">
<div class="auth-modal-content">
<div class="auth-header">
<i class="fas fa-lock"></i>
<h3>크롤링 권한 인증</h3>
<p>시스템 동기화를 위해 관리자 계정으로 로그인하세요.</p>
<!-- 모달 레이어 (공통 규격 적용) -->
<div id="authModal" class="modal-overlay">
<div class="modal-content" style="max-width: 440px; padding: 40px; text-align: center;" onclick="event.stopPropagation()">
<div class="auth-header" style="margin-bottom: 32px;">
<i class="fas fa-lock" style="font-size: 32px; color: var(--primary-color); margin-bottom: 16px; display: block;"></i>
<h3 style="font-size: 20px; font-weight: 800; color: #111; margin-bottom: 8px;">크롤링 권한 인증</h3>
<p style="font-size: 13px; color: var(--text-sub);">시스템 동기화를 위해 관리자 계정으로 로그인하세요.</p>
</div>
<div class="auth-body">
<div class="auth-body" style="display: flex; flex-direction: column; gap: 20px; text-align: left; margin-bottom: 32px;">
<div class="input-group">
<label>관리자 아이디</label>
<input type="text" id="authId" placeholder="아이디를 입력하세요">
@@ -78,23 +78,22 @@
<input type="password" id="authPw" placeholder="비밀번호를 입력하세요"
onkeyup="if(event.key==='Enter') submitAuth()">
</div>
<div id="authErrorMessage" class="error-text" style="display:none;">크롤링을 할 수 없습니다.</div>
<div id="authErrorMessage" class="error-text" style="display:none; color: var(--error-color); font-size: 12px; font-weight: 600; text-align: center; margin-top: -10px;">크롤링을 할 수 없습니다.</div>
</div>
<div class="auth-footer">
<button class="cancel-btn" onclick="closeAuthModal()">취소</button>
<button class="login-btn" onclick="submitAuth()">인증 및 실행</button>
<div class="auth-footer" style="display: grid; grid-template-columns: 1fr 1.5fr; gap: 12px;">
<button class="btn btn-secondary" style="height: 48px;" onclick="closeAuthModal()">취소</button>
<button class="btn btn-primary" style="height: 48px;" onclick="submitAuth()">인증 및 실행</button>
</div>
</div>
</div>
<div id="activityDetailModal" class="activity-modal-overlay" style="display:none;"
onclick="closeActivityModal(event)">
<div class="activity-modal-content" onclick="event.stopPropagation()">
<div class="modal-header">
<div id="activityDetailModal" class="modal-overlay" onclick="closeActivityModal()">
<div class="modal-content" style="max-width: 600px; padding: 0; overflow: hidden;" onclick="event.stopPropagation()">
<div class="modal-header" style="padding: 20px; margin-bottom: 0;">
<h3 id="modalTitle">상세 목록</h3>
<button class="close-btn" onclick="closeActivityModal()">&times;</button>
<span class="modal-close" onclick="closeActivityModal()">&times;</span>
</div>
<div class="modal-body">
<div class="modal-body" style="padding: 20px; max-height: 70vh; overflow-y: auto;">
<table class="data-table">
<thead>
<tr>
@@ -108,6 +107,9 @@
</tbody>
</table>
</div>
<div style="padding: 16px 20px; border-top: 1px solid var(--border-color); text-align: right; background: #fdfdfd;">
<button class="btn btn-secondary" onclick="closeActivityModal()">닫기</button>
</div>
</div>
</div>

View File

@@ -36,8 +36,31 @@
<h2>문의사항</h2>
<p style="font-size: 13px; color: #666; margin-top: 4px;">시스템 운영 관련 불편사항 및 개선 요청 관리</p>
</div>
<div class="header-actions">
<button class="sync-btn" onclick="loadInquiries()">새로고침</button>
<div class="header-stats" id="headerStats">
<div class="stat-item total">
<span class="stat-label">전체</span>
<span class="stat-value" id="countTotal">0</span>
</div>
<div class="stat-item complete">
<span class="stat-label">완료</span>
<span class="stat-value" id="countComplete">0</span>
</div>
<div class="stat-item working">
<span class="stat-label">작업 중</span>
<span class="stat-value" id="countWorking">0</span>
</div>
<div class="stat-item checking">
<span class="stat-label">확인 중</span>
<span class="stat-value" id="countChecking">0</span>
</div>
<div class="stat-item pending">
<span class="stat-label">개발예정</span>
<span class="stat-value" id="countPending">0</span>
</div>
<div class="stat-item unconfirmed">
<span class="stat-label">미확인</span>
<span class="stat-value" id="countUnconfirmed">0</span>
</div>
</div>
</div>
@@ -114,6 +137,7 @@
<thead>
<tr>
<th width="50">No</th>
<th width="80">이미지</th>
<th width="120">PM 종류</th>
<th width="100">환경</th>
<th width="150">구분</th>
@@ -131,6 +155,24 @@
</table>
</main>
<!-- 이미지 크게 보기 모달 (디자인 가이드 - 화이트 계열 및 우측 하단 닫기 적용) -->
<div id="imageModal" class="modal-overlay" onclick="closeImageModal()">
<div class="modal-content" style="max-width: 960px; width: 92%; padding: 0; overflow: hidden; border-radius: 12px; border: 1px solid #e2e8f0; background: #fff;" onclick="event.stopPropagation()">
<div class="modal-header" style="padding: 16px 24px; margin-bottom: 0; border-bottom: 1px solid #f1f5f9; background: #fff;">
<h3 style="color: #1e5149; font-weight: 700; font-size: 16px;">첨부 이미지 확대 보기</h3>
<span class="modal-close" onclick="closeImageModal()" style="font-size: 24px; color: #94a3b8;">&times;</span>
</div>
<div style="padding: 32px; background: #fff; display: flex; justify-content: center; align-items: center; min-height: 300px; max-height: 75vh; overflow: auto;">
<img id="modalImage" style="max-width: 100%; height: auto; border-radius: 8px; box-shadow: 0 10px 25px -5px rgba(0,0,0,0.1), 0 8px 10px -6px rgba(0,0,0,0.1);">
</div>
<div style="padding: 16px 24px; border-top: 1px solid #f1f5f9; text-align: right; background: #fff;">
<button class="_button-medium" style="background: #1e5149; color: #fff; border: none; padding: 10px 28px; border-radius: 8px; cursor: pointer; transition: background 0.2s;"
onmouseover="this.style.background='#163b36'" onmouseout="this.style.background='#1e5149'"
onclick="closeImageModal()">닫기</button>
</div>
</div>
</div>
<script src="js/common.js"></script>
<script src="js/inquiries.js"></script>
</body>

View File

@@ -132,8 +132,7 @@
<div class="a4-container" id="previewContainer">
<div class="preview-placeholder">파일을 클릭하면<br>미리보기가 표시됩니다.</div>
</div>
</div>
</aside>
</aside>
</div>
{% include 'modals/address_book.html' %}

View File

@@ -1,39 +1,45 @@
<!-- 주소록 모달 -->
<div id="addressBookModal" class="modal-overlay">
<div class="modal-content" style="max-width: 850px;">
<!-- 주소록 모달 (공통 규격 적용) -->
<div id="addressBookModal" class="modal-overlay" onclick="closeAddressBook()">
<div class="modal-content" style="max-width: 850px;" onclick="event.stopPropagation()">
<div class="modal-header">
<h3>공사 관계자 주소록</h3>
<div class="flex-center" style="gap:10px;">
<button class="_button-small" style="border:none;" onclick="toggleAddContactForm()">+ 추가하기</button>
<button class="btn btn-primary" onclick="toggleAddContactForm()">+ 추가하기</button>
<span class="modal-close" onclick="closeAddressBook()">&times;</span>
</div>
</div>
<!-- 주소록 추가 폼 (기본 숨김) -->
<div id="addContactForm"
style="display:none; background:var(--bg-muted); padding:15px; border-radius:8px; margin-bottom:15px; border:1px solid var(--border-color);">
<div style="display:grid; grid-template-columns: 1fr 1fr; gap:10px; margin-bottom:10px;">
<input type="text" id="newContactName" placeholder="성명"
style="padding:8px; border:1px solid #ccc; border-radius:4px; font-size:12px;">
<input type="text" id="newContactDept" placeholder="소속/직위"
style="padding:8px; border:1px solid #ccc; border-radius:4px; font-size:12px;">
<input type="text" id="newContactEmail" placeholder="이메일"
style="padding:8px; border:1px solid #ccc; border-radius:4px; font-size:12px;">
<input type="text" id="newContactPhone" placeholder="연락처"
style="padding:8px; border:1px solid #ccc; border-radius:4px; font-size:12px;">
style="display:none; background:var(--bg-muted); padding:20px; border-radius:12px; margin-bottom:20px; border:1px solid var(--border-color);">
<div style="display:grid; grid-template-columns: 1fr 1fr; gap:12px; margin-bottom:15px;">
<div class="input-group">
<label style="font-size:11px; margin-bottom:4px; display:block;">성명</label>
<input type="text" id="newContactName" placeholder="성명 입력" style="height:36px; padding:0 12px; border:1px solid #ddd; border-radius:6px; width:100%; font-size:13px;">
</div>
<div class="input-group">
<label style="font-size:11px; margin-bottom:4px; display:block;">소속/직위</label>
<input type="text" id="newContactDept" placeholder="소속/직위 입력" style="height:36px; padding:0 12px; border:1px solid #ddd; border-radius:6px; width:100%; font-size:13px;">
</div>
<div class="input-group">
<label style="font-size:11px; margin-bottom:4px; display:block;">이메일</label>
<input type="text" id="newContactEmail" placeholder="이메일 입력" style="height:36px; padding:0 12px; border:1px solid #ddd; border-radius:6px; width:100%; font-size:13px;">
</div>
<div class="input-group">
<label style="font-size:11px; margin-bottom:4px; display:block;">연락처</label>
<input type="text" id="newContactPhone" placeholder="연락처 입력" style="height:36px; padding:0 12px; border:1px solid #ddd; border-radius:6px; width:100%; font-size:13px;">
</div>
</div>
<div class="flex-center" style="gap:8px;">
<button class="_button-medium" style="flex:1; background:var(--primary-color); color:#fff;"
onclick="addContact()">저장</button>
<button class="_button-medium" style="flex:1; background:#718096; color:#fff;"
onclick="toggleAddContactForm()">취소</button>
<div class="flex-center" style="gap:10px;">
<button class="btn btn-primary" style="flex:1;" onclick="addContact()">저장</button>
<button class="btn btn-secondary" style="flex:1;" onclick="toggleAddContactForm()">취소</button>
</div>
</div>
<div class="search-bar" style="background:#fff; padding:0 0 15px 0;">
<input type="text" placeholder="이름, 부서, 연락처 검색..." style="margin-bottom:8px; height: 32px;">
<input type="text" placeholder="이름, 부서, 연락처 검색..." style="width:100%; height: 36px; padding:0 12px; border:1px solid var(--border-color); border-radius:6px;">
</div>
<div style="max-height: 400px; overflow-y: auto;">
<div style="max-height: 400px; overflow-y: auto; border:1px solid var(--border-color); border-radius:8px;">
<table class="data-table">
<thead>
<tr>
@@ -41,7 +47,7 @@
<th>소속/직위</th>
<th>이메일</th>
<th>연락처</th>
<th style="text-align:right;">관리</th>
<th style="text-align:right; padding-right:15px;">관리</th>
</tr>
</thead>
<tbody id="addressBookBody">
@@ -49,6 +55,8 @@
</tbody>
</table>
</div>
<button class="btn-confirm" style="margin-top:20px;" onclick="closeAddressBook()">닫기</button>
<div style="margin-top:20px; text-align:right;">
<button class="btn btn-secondary" style="padding: 8px 32px;" onclick="closeAddressBook()">닫기</button>
</div>
</div>
</div>

View File

@@ -1,22 +1,24 @@
<!-- 경로 선택 모달 -->
<div id="pathModal" class="modal-overlay">
<div class="modal-content">
<!-- 경로 선택 모달 (공통 규격 적용) -->
<div id="pathModal" class="modal-overlay" onclick="closeModal()">
<div class="modal-content" style="max-width: 500px;" onclick="event.stopPropagation()">
<div class="modal-header">
<h3>파일 보관 경로 선택</h3>
<span class="modal-close" onclick="closeModal()">&times;</span>
</div>
<div class="select-group">
<label>탭 (Tab)</label>
<select id="tabSelect" class="modal-select" onchange="updateCategories()"></select>
<div style="display: flex; flex-direction: column; gap: 16px; margin-bottom: 24px;">
<div class="select-group" style="margin-bottom: 0;">
<label>탭 (Tab)</label>
<select id="tabSelect" class="modal-select" onchange="updateCategories()"></select>
</div>
<div class="select-group" style="margin-bottom: 0;">
<label>카테고리 (Category)</label>
<select id="categorySelect" class="modal-select" onchange="updateSubs()"></select>
</div>
<div class="select-group" style="margin-bottom: 0;">
<label>서브카테고리 (Sub-Category)</label>
<select id="subSelect" class="modal-select"></select>
</div>
</div>
<div class="select-group">
<label>카테고리 (Category)</label>
<select id="categorySelect" class="modal-select" onchange="updateSubs()"></select>
</div>
<div class="select-group">
<label>서브카테고리 (Sub-Category)</label>
<select id="subSelect" class="modal-select"></select>
</div>
<button class="btn-confirm" onclick="applyPathSelection()">경로 확정하기</button>
<button class="btn btn-primary" style="width: 100%; height: 44px;" onclick="applyPathSelection()">경로 확정하기</button>
</div>
</div>