한글뷰어 기능수정 Ver.01

This commit is contained in:
koj729
2026-06-19 17:58:47 +09:00
parent 9268e4e6bc
commit 83b6e891ab
49 changed files with 8741 additions and 446 deletions

View File

@@ -407,6 +407,46 @@
background-color: #ffffff;
}
/* Pagination styling */
.pagination-container {
display: flex;
justify-content: center;
align-items: center;
gap: 6px;
margin-top: 20px;
padding-bottom: 10px;
}
.pagination-btn {
padding: 6px 12px;
border: 1px solid var(--border);
background-color: var(--card-bg);
color: var(--text-main);
border-radius: var(--radius-md);
cursor: pointer;
font-size: 0.85rem;
font-weight: 500;
transition: var(--transition);
}
.pagination-btn:hover:not(:disabled) {
border-color: var(--primary);
color: var(--primary);
background-color: var(--primary-soft);
}
.pagination-btn.active {
background-color: var(--primary);
color: #ffffff;
border-color: var(--primary);
}
.pagination-btn:disabled {
opacity: 0.4;
cursor: not-allowed;
color: var(--text-light);
}
table.admin-table {
width: 100%;
border-collapse: collapse;
@@ -814,7 +854,7 @@
<div class="card-header">
<h3 class="card-title">📢 실시간 배너 공지사항 등록</h3>
</div>
<form class="config-form" style="gap: 20px;" onsubmit="handleBannerSubmit(event)">
<form class="config-form" style="gap: 20px;" onsubmit="submitBannerForm(event)">
<div class="form-row">
<div class="form-group">
<label for="banner-project-select">공지 대상 프로젝트</label>
@@ -1030,6 +1070,8 @@
</tbody>
</table>
</div>
<!-- Pagination Controls -->
<div id="audit-log-pagination" class="pagination-container"></div>
</div>
</div>
@@ -1428,6 +1470,20 @@
}
}
// 날짜 문자열을 클라이언트 로컬 타임존 기반의 YYYY-MM-DD HH:mm:ss 형식으로 변환하는 함수
function formatDate(dateStr) {
if (!dateStr) return '-';
const date = new Date(dateStr);
if (isNaN(date.getTime())) return dateStr;
const YYYY = date.getFullYear();
const MM = String(date.getMonth() + 1).padStart(2, '0');
const DD = String(date.getDate()).padStart(2, '0');
const HH = String(date.getHours()).padStart(2, '0');
const mm = String(date.getMinutes()).padStart(2, '0');
const ss = String(date.getSeconds()).padStart(2, '0');
return `${YYYY}-${MM}-${DD} ${HH}:${mm}:${ss}`;
}
// 로그인 사용자 프로필 로드 함수
async function loadUserProfile() {
try {
@@ -2275,7 +2331,7 @@
}
// --- 7. 활동 로그 조회 탭 (Activity Logs) ---
async function renderAuditLogs() {
async function renderAuditLogs(page = 1) {
const userId = document.getElementById('search-log-user').value.trim();
const projectNm = document.getElementById('search-log-project').value.trim();
const action = document.getElementById('filter-log-action').value.trim();
@@ -2284,16 +2340,22 @@
if (userId) params.append('user_id', userId);
if (projectNm) params.append('project_nm', projectNm);
if (action) params.append('activity', action);
params.append('page', page);
params.append('limit', 20);
let queryUrl = `/api/admin/audit-logs?${params.toString()}`;
try {
const logs = await fetchAPI(queryUrl);
const resData = await fetchAPI(queryUrl);
const logs = resData.data;
const pagination = resData.pagination;
const body = document.getElementById('audit-log-body');
body.innerHTML = '';
if (logs.length === 0) {
if (!logs || logs.length === 0) {
body.innerHTML = `<tr><td colspan="7" style="text-align: center; color: var(--text-light); padding: 24px 0;">조회된 활동 로그 내역이 없습니다.</td></tr>`;
document.getElementById('audit-log-pagination').innerHTML = '';
return;
}
@@ -2305,9 +2367,11 @@
cleanPath = '/' + log.criteria_info.filter(p => p).join('/');
}
const rowNumber = pagination.total - ((pagination.page - 1) * pagination.limit) - idx;
tr.innerHTML = `
<td>${idx + 1}</td>
<td>${log.clean_date ? log.clean_date.replace('T', ' ').substring(0, 19) : '-'}</td>
<td>${rowNumber}</td>
<td>${formatDate(log.clean_date)}</td>
<td><strong>${log.project_nm || log.project_id || '-'}</strong></td>
<td>${log.user_id || '-'}</td>
<td>${log.user_ip || '-'}</td>
@@ -2316,11 +2380,53 @@
`;
body.appendChild(tr);
});
renderPaginationControls(pagination);
} catch (err) {
console.error(err);
}
}
function renderPaginationControls(pagination) {
const container = document.getElementById('audit-log-pagination');
container.innerHTML = '';
const { page, totalPages } = pagination;
if (totalPages <= 1) return;
const prevBtn = document.createElement('button');
prevBtn.className = 'pagination-btn';
prevBtn.innerText = '이전';
prevBtn.disabled = page === 1;
prevBtn.onclick = () => renderAuditLogs(page - 1);
container.appendChild(prevBtn);
const maxPageButtons = 5;
let startPage = Math.max(1, page - Math.floor(maxPageButtons / 2));
let endPage = startPage + maxPageButtons - 1;
if (endPage > totalPages) {
endPage = totalPages;
startPage = Math.max(1, endPage - maxPageButtons + 1);
}
for (let i = startPage; i <= endPage; i++) {
const pageBtn = document.createElement('button');
pageBtn.className = `pagination-btn ${i === page ? 'active' : ''}`;
pageBtn.innerText = i;
pageBtn.onclick = () => renderAuditLogs(i);
container.appendChild(pageBtn);
}
const nextBtn = document.createElement('button');
nextBtn.className = 'pagination-btn';
nextBtn.innerText = '다음';
nextBtn.disabled = page === totalPages;
nextBtn.onclick = () => renderAuditLogs(page + 1);
container.appendChild(nextBtn);
}
// --- 8. 글로벌 삭제 정책 설정 탭 (Policies) ---
async function renderDeletePolicy() {
try {
@@ -2345,7 +2451,7 @@
const tr = document.createElement('tr');
tr.innerHTML = `
<td>${idx + 1}</td>
<td>${l.clean_date ? l.clean_date.replace('T', ' ').substring(0, 19) : '-'}</td>
<td>${formatDate(l.clean_date)}</td>
<td><strong>${l.project_id}</strong></td>
<td style="max-width: 250px; text-overflow: ellipsis; overflow: hidden; white-space: nowrap;">${l.clean_path}</td>
<td>${l.criteria_info}</td>