Files
eapim-admin/WebContent/jsp/dashboard-modern/components/dashboard-socket-detail.jsp
T
youna 972819b492 모던 대시보드 패치
- ApexCharts 기반 실시간 모니터링 대시보드
- 어댑터/배치/서버/소켓/트랜잭션 모니터링 컴포넌트
- 처리량 계산 및 데이터 매핑 서비스
2025-11-14 17:59:06 +09:00

957 lines
33 KiB
Plaintext

<%@ page language="java" contentType="text/html; charset=utf-8"%>
<%@ page import="java.util.*" %>
<!-- 소켓 상세 정보 모달 -->
<div id="socketDetailModal" class="modal modal-modern">
<div class="modal-content">
<div class="modal-header">
<h2 class="modal-title">회선 상세 정보</h2>
<span class="close-modal">&times;</span>
</div>
<div class="modal-body">
<!-- 탭 메뉴 -->
<div class="socket-detail-tabs">
<button class="tab-btn active" data-tab="institution-visual">
<i class="bi bi-pie-chart"></i> 기관 현황
</button>
<button class="tab-btn" data-tab="institution-status">
<i class="bi bi-building"></i> 기관 상태
</button>
<button class="tab-btn" data-tab="socket-status">
<i class="bi bi-plug"></i> 어댑터 상태
</button>
<button class="tab-btn" data-tab="socket-process">
<i class="bi bi-arrow-left-right"></i> 세션 상태
</button>
</div>
<!-- 탭 컨텐츠 -->
<div class="socket-detail-content">
<!-- 기관 연결 현황 시각화 탭 -->
<div id="institution-visual" class="tab-content active">
<div class="visual-stats-summary">
<div class="stats-card total-institutions">
<div class="stats-icon"><i class="bi bi-building"></i></div>
<div class="stats-details">
<div class="stats-number" id="total-institutions-count">0</div>
<div class="stats-label">총 기관</div>
</div>
</div>
<div class="stats-card normal-institutions">
<div class="stats-icon"><i class="bi bi-check-circle"></i></div>
<div class="stats-details">
<div class="stats-number" id="normal-institutions-count">0</div>
<div class="stats-label">정상</div>
</div>
</div>
<div class="stats-card warning-institutions">
<div class="stats-icon"><i class="bi bi-exclamation-triangle"></i></div>
<div class="stats-details">
<div class="stats-number" id="warning-institutions-count">0</div>
<div class="stats-label">경고</div>
</div>
</div>
<div class="stats-card error-institutions">
<div class="stats-icon"><i class="bi bi-x-circle"></i></div>
<div class="stats-details">
<div class="stats-number" id="error-institutions-count">0</div>
<div class="stats-label">오류</div>
</div>
</div>
<div class="stats-card inactive-institutions">
<div class="stats-icon"><i class="bi bi-dash-circle"></i></div>
<div class="stats-details">
<div class="stats-number" id="inactive-institutions-count">0</div>
<div class="stats-label">미사용</div>
</div>
</div>
</div>
<div class="connection-visual-container">
<div id="institution-grid" class="institution-grid"></div>
</div>
</div>
<!-- 기관 상태 탭 -->
<div id="institution-status" class="tab-content">
<div class="institution-status-container">
<table class="institution-status-table modal-table">
<thead>
<tr>
<th>기관명</th>
<th>담당자명</th>
<th>연락처</th>
<th>정상어댑터</th>
<th>오류어댑터</th>
<th>회선상태</th>
</tr>
</thead>
<tbody>
<!-- 데이터가 동적으로 추가됩니다 -->
</tbody>
</table>
</div>
</div>
<!-- 회선 상태 탭 -->
<div id="socket-status" class="tab-content">
<div class="socket-status-container">
<table class="socket-status-table modal-table">
<thead>
<tr>
<th>어댑터 그룹</th>
<th>인스턴스명</th>
<th>어댑터명</th>
<th>어댑터 설명</th>
<th>어댑터 유형</th>
<th>상태</th>
<th>기동 상태</th>
</tr>
</thead>
<tbody>
<!-- 데이터가 동적으로 추가됩니다 -->
</tbody>
</table>
</div>
</div>
<!-- 회선 연결 상태 탭 -->
<div id="socket-process" class="tab-content">
<div class="socket-process-container">
<table class="socket-process-table modal-table">
<thead>
<tr>
<th>어댑터 그룹</th>
<th>인스턴스명</th>
<th>어댑터명</th>
<th>어댑터 설명</th>
<th>최대 연결</th>
<th>현재 연결</th>
<th>송신 수</th>
<th>수신 수</th>
<th>오류 수</th>
<th>상태</th>
</tr>
</thead>
<tbody>
<!-- 데이터가 동적으로 추가됩니다 -->
</tbody>
</table>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-primary refresh-socket-data">
<i class="bi bi-arrow-clockwise" style="color: #ffffff;"></i> 새로고침
</button>
<button class="btn btn-secondary close-modal-btn">닫기</button>
</div>
</div>
</div>
<style>
/* 기존 스타일 강화 */
.modal-modern {
display: none;
position: fixed;
z-index: 1000;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
background-color: rgba(0, 0, 0, 0.5);
backdrop-filter: blur(4px);
}
.modal-modern .modal-content {
position: relative;
background-color: #fff;
margin: 2% auto;
padding: 0;
width: 95%;
max-width: 1400px;
border: none;
border-radius: 16px;
box-shadow: 0 8px 30px rgba(0, 0, 0, 0.12);
animation: modalSlideUp 0.3s;
}
@keyframes modalSlideUp {
from {opacity: 0; transform: translateY(30px);}
to {opacity: 1; transform: translateY(0);}
}
@keyframes modalFadeIn {
from {opacity: 0;}
to {opacity: 1;}
}
.modal-modern .modal-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1.5rem 2rem;
border-bottom: 1px solid #e0e0e0;
background-color: #f8f9fa;
border-radius: 16px 16px 0 0;
}
.modal-modern .modal-title {
margin: 0;
font-size: 1.5rem;
font-weight: 600;
color: #333;
}
.modal-modern .close-modal {
color: #aaa;
font-size: 28px;
font-weight: bold;
cursor: pointer;
transition: color 0.2s;
width: 36px;
height: 36px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
background-color: rgba(0, 0, 0, 0.05);
}
.modal-modern .close-modal:hover {
color: #333;
background-color: rgba(0, 0, 0, 0.1);
}
.modal-modern .modal-body {
padding: 1.5rem 2rem;
max-height: 75vh;
overflow-y: auto;
background-color: #f8f9fa;
}
.modal-modern .modal-footer {
padding: 1.2rem 2rem;
border-top: 1px solid #e0e0e0;
display: flex;
justify-content: flex-end;
gap: 1rem;
border-radius: 0 0 16px 16px;
background-color: #fff;
}
/* 탭 스타일 향상 */
.socket-detail-tabs {
display: flex;
border-bottom: none;
margin-bottom: 1.5rem;
overflow-x: auto;
background-color: #fff;
border-radius: 8px;
padding: 0.5rem;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
}
.tab-btn {
padding: 0.9rem 1.5rem;
background: none;
border: none;
border-radius: 8px;
cursor: pointer;
font-weight: 500;
font-size: 1rem;
color: #666;
transition: all 0.2s;
display: flex;
align-items: center;
gap: 0.5rem;
}
.tab-btn:hover {
color: #333;
background-color: rgba(0, 0, 0, 0.05);
}
.tab-btn.active {
color: white;
background-color: #007bff;
box-shadow: 0 4px 8px rgba(0, 123, 255, 0.2);
}
.tab-content {
display: none;
animation: fadeIn 0.3s;
}
@keyframes fadeIn {
from {opacity: 0;}
to {opacity: 1;}
}
.tab-content.active {
display: block;
}
/* 테이블 스타일 향상 */
.modal-table {
width: 100%;
border-collapse: separate;
border-spacing: 0;
background-color: #fff;
border-radius: 12px;
overflow: hidden;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
}
.modal-table th {
background-color: #007bff;
color: white;
padding: 1.2rem;
text-align: left;
font-weight: 800;
top: 0;
z-index: 10;
}
.modal-table td {
padding: 1rem;
border-bottom: 1px solid #e0e0e0;
}
.modal-table tbody tr {
transition: background-color 0.2s;
}
.modal-table tbody tr:hover {
background-color: rgba(0, 0, 0, 0.03);
}
.modal-table tbody tr:last-child td {
border-bottom: none;
}
/* 버튼 스타일 향상 */
.btn {
padding: 0.8rem 1.5rem;
border: none;
border-radius: 8px;
cursor: pointer;
font-weight: 500;
font-size: inherit;
transition: all 0.25s;
display: flex;
align-items: center;
gap: 0.5rem;
}
.btn-primary {
background-color: #007bff;
color: white;
}
.btn-primary:hover {
background-color: #0069d9;
box-shadow: 0 4px 12px rgba(0, 123, 255, 0.3);
}
.btn-secondary {
background-color: #f1f5f9;
color: #333;
}
.btn-secondary:hover {
background-color: #e2e8f0;
}
/* 로딩 애니메이션 향상 */
.loading-indicator {
display: flex;
justify-content: center;
align-items: center;
height: 200px;
}
.loading-spinner {
border: 4px solid rgba(0, 0, 0, 0.1);
border-radius: 50%;
border-top: 4px solid #007bff;
width: 50px;
height: 50px;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
/* 통계 카드 스타일 향상 */
.visual-stats-summary {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 1rem;
margin-bottom: 1.5rem;
}
.stats-card {
background-color: #fff;
border-radius: 12px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
padding: 1.2rem;
display: flex;
align-items: center;
gap: 1rem;
transition: transform 0.2s, box-shadow 0.2s;
}
.stats-card:hover {
transform: translateY(-4px);
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
}
.stats-icon {
width: 48px;
height: 48px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.4rem;
}
.stats-details {
flex: 1;
}
.stats-number {
font-size: 1.8rem;
font-weight: 700;
line-height: 1.1;
}
.stats-label {
font-size: 0.9rem;
color: #666;
margin-top: 0.2rem;
}
/* 카드 색상 */
.total-institutions .stats-icon {
background-color: rgba(0, 123, 255, 0.3);
color: #007bff;
}
.normal-institutions .stats-icon {
background-color: rgba(40, 167, 69, 0.3);
color: #28a745;
}
.warning-institutions .stats-icon {
background-color: rgba(255, 193, 7, 0.3);
color: #ffc107;
}
.error-institutions .stats-icon {
background-color: rgba(220, 53, 69, 0.3);
color: #dc3545;
}
.inactive-institutions .stats-icon {
background-color: rgba(108, 117, 125, 0.3);
color: #6c757d;
}
/* 기관 카드 그리드 향상 */
.connection-visual-container {
background-color: #fff;
border-radius: 12px;
padding: 1.5rem;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
}
.institution-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 1rem;
}
.institution-card {
background-color: #f8f9fa;
border-radius: 12px;
padding: 1.2rem;
transition: all 0.3s ease;
border-left: 5px solid #ccc;
cursor: pointer;
position: relative;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
}
.institution-card:hover {
transform: translateY(-5px);
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1);
}
.institution-status-indicator {
position: absolute;
top: 15px;
right: 15px;
font-size: 1.2rem;
}
.institution-name {
font-size: 1.1rem;
font-weight: 600;
margin-bottom: 1rem;
color: #333;
padding-right: 2rem;
}
.institution-info {
display: grid;
grid-template-columns: 80px 1fr;
margin-bottom: 0.5rem;
font-size: 0.9rem;
}
.institution-info-label {
color: #666;
}
.institution-stats {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 0.5rem;
margin-top: 1rem;
border-top: 1px solid #e0e0e0;
padding-top: 0.8rem;
}
.institution-stat {
text-align: center;
padding: 0.5rem;
border-radius: 8px;
background-color: rgba(0, 0, 0, 0.03);
}
/* 상태 배지 스타일 */
.status-badge {
display: inline-flex;
align-items: center;
gap: 0.3rem;
padding: 0.4rem 0.8rem;
border-radius: 50px;
font-size: 0.85rem;
font-weight: 600;
white-space: nowrap;
}
.status-badge-normal {
background-color: rgba(40, 167, 69, 0.15);
color: #28a745;
}
.status-badge-warning {
background-color: rgba(255, 193, 7, 0.15);
color: #ffc107;
}
.status-badge-error {
background-color: rgba(220, 53, 69, 0.15);
color: #dc3545;
}
.status-badge-inactive {
background-color: rgba(108, 117, 125, 0.15);
color: #6c757d;
}
/* 반응형 디자인 */
@media (max-width: 1024px) {
.visual-stats-summary {
grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
}
.modal-modern .modal-content {
width: 98%;
margin: 1% auto;
}
.modal-modern .modal-body {
padding: 1rem 1.5rem;
}
}
@media (max-width: 768px) {
.socket-detail-tabs {
padding: 0.3rem;
flex-wrap: wrap;
}
.tab-btn {
padding: 0.8rem 1rem;
font-size: 0.9rem;
flex-grow: 1;
}
.visual-stats-summary {
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 0.8rem;
}
.stats-icon {
width: 40px;
height: 40px;
font-size: 1.2rem;
}
.stats-number {
font-size: 1.5rem;
}
.institution-grid {
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
}
.modal-modern .modal-header,
.modal-modern .modal-footer {
padding: 1rem 1.5rem;
}
}
@media (max-width: 576px) {
.visual-stats-summary {
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
}
.institution-grid {
grid-template-columns: 1fr;
}
.modal-modern .modal-body {
padding: 1rem;
}
}
.institution-card.status-normal {
border-left: 5px solid #98e2a6; /* 파스텔 그린 */
}
.institution-card.status-warning {
border-left: 5px solid #ffe5a3; /* 파스텔 옐로우 */
}
.institution-card.status-error {
border-left: 5px solid #ffb3b3; /* 파스텔 레드 */
}
.institution-card.status-inactive {
border-left: 5px solid #d9d9d9; /* 파스텔 그레이 */
}
</style>
<script>
// 소켓 상세 정보 모달 관련 스크립트
(function() {
// 모달 요소
const modal = document.getElementById('socketDetailModal');
const closeButtons = modal.querySelectorAll('.close-modal, .close-modal-btn');
// 탭 관련 요소
const tabButtons = modal.querySelectorAll('.tab-btn');
const tabContents = modal.querySelectorAll('.tab-content');
// 테이블 요소
const institutionTable = modal.querySelector('.institution-status-table tbody');
const statusTable = modal.querySelector('.socket-status-table tbody');
const processTable = modal.querySelector('.socket-process-table tbody');
// 시각화 요소
const institutionGrid = document.getElementById('institution-grid');
const totalInstitutionsCount = document.getElementById('total-institutions-count');
const normalInstitutionsCount = document.getElementById('normal-institutions-count');
const warningInstitutionsCount = document.getElementById('warning-institutions-count');
const errorInstitutionsCount = document.getElementById('error-institutions-count');
const inactiveInstitutionsCount = document.getElementById('inactive-institutions-count');
// 현재 선택된 서버와 어댑터 그룹
let currentServerName = '';
let currentAdapterGroup = '';
// 모달 닫기 이벤트
closeButtons.forEach(button => {
button.addEventListener('click', () => {
modal.style.display = 'none';
});
});
// 모달 외부 클릭 시 닫기
window.addEventListener('click', (event) => {
if (event.target === modal) {
modal.style.display = 'none';
}
});
// 탭 전환 이벤트
tabButtons.forEach(button => {
button.addEventListener('click', () => {
// 활성 탭 변경
tabButtons.forEach(btn => btn.classList.remove('active'));
button.classList.add('active');
// 탭 컨텐츠 변경
const tabId = button.getAttribute('data-tab');
tabContents.forEach(content => {
content.classList.remove('active');
if (content.id === tabId) {
content.classList.add('active');
}
});
});
});
// 새로고침 버튼 이벤트
const refreshButton = modal.querySelector('.refresh-socket-data');
refreshButton.addEventListener('click', () => {
loadSocketData(currentServerName, currentAdapterGroup);
});
// 소켓 데이터 로드 함수
function loadSocketData(serverName, adapterGroup) {
// 현재 선택된 서버와 어댑터 그룹 저장
currentServerName = serverName || '';
currentAdapterGroup = adapterGroup || '';
// 로딩 표시
institutionTable.innerHTML = '<tr><td colspan="6"><div class="loading-indicator"><div class="loading-spinner"></div></div></td></tr>';
statusTable.innerHTML = '<tr><td colspan="7"><div class="loading-indicator"><div class="loading-spinner"></div></div></td></tr>';
processTable.innerHTML = '<tr><td colspan="10"><div class="loading-indicator"><div class="loading-spinner"></div></div></td></tr>';
institutionGrid.innerHTML = '<div class="loading-indicator"><div class="loading-spinner"></div></div>';
// API 호출
ModernDashboardApi.getSocketCombined(serverName, adapterGroup, function(data) {
if (data) {
// 기관 상태 데이터 표시
updateInstitutionStatusTable(data.institutionStatus);
// 기관 시각화 업데이트
updateInstitutionVisualization(data.institutionStatus);
// 회선 상태 데이터 표시
updateSocketStatusTable(data.socketStatus);
// 회선 연결 상태 데이터 표시
updateSocketProcessTable(data.socketProcess);
}
}, function(xhr, status, error) {
// 에러 처리
const errorMsg = '<div style="padding: 2rem; text-align: center; color: #dc3545;"><i class="fas fa-exclamation-circle" style="font-size: 3rem;"></i><p style="margin-top: 1rem;">데이터를 불러오는 중 오류가 발생했습니다.</p></div>';
institutionTable.innerHTML = '<tr><td colspan="6">' + errorMsg + '</td></tr>';
statusTable.innerHTML = '<tr><td colspan="7">' + errorMsg + '</td></tr>';
processTable.innerHTML = '<tr><td colspan="10">' + errorMsg + '</td></tr>';
institutionGrid.innerHTML = errorMsg;
console.error('소켓 데이터 로드 실패:', error);
});
}
// 기관 상태 테이블 업데이트
function updateInstitutionStatusTable(data) {
if (!data || data.length === 0) {
institutionTable.innerHTML = '<tr><td colspan="6"><div style="padding: 2rem; text-align: center; color: #6c757d;"><i class="fas fa-info-circle" style="font-size: 2rem;"></i><p style="margin-top: 1rem;">표시할 데이터가 없습니다.</p></div></td></tr>';
return;
}
let html = '';
data.forEach(institution => {
let statusClass = '';
let statusText = '';
// 상태에 따른 텍스트 및 클래스 설정
if (institution.lineStatus === 'UNDEFINED') {
statusText = '미사용';
statusClass = 'status-badge status-badge-inactive';
} else if (institution.lineStatus === 'WARN') {
statusText = '경고';
statusClass = 'status-badge status-badge-warning';
} else if (institution.lineStatus === 'ERROR') {
statusText = '오류';
statusClass = 'status-badge status-badge-error';
} else {
statusText = '정상';
statusClass = 'status-badge status-badge-normal';
}
html += '<tr>' +
'<td>' + (institution.institutionName || '-') + '</td>' +
'<td>' + (institution.contactPerson || '-') + '</td>' +
'<td>' + (institution.contactNumber || '-') + '</td>' +
'<td>' + (institution.normalAdapterCount || '0') + '</td>' +
'<td>' + (institution.errorAdapterCount || '0') + '</td>' +
'<td><span class="' + statusClass + '">' + statusText + '</span></td>' +
'</tr>';
});
institutionTable.innerHTML = html;
}
// 기관 시각화 업데이트
function updateInstitutionVisualization(data) {
if (!data || data.length === 0) {
institutionGrid.innerHTML = '<div style="padding: 2rem; text-align: center; color: #6c757d;"><i class="fas fa-info-circle" style="font-size: 2rem;"></i><p style="margin-top: 1rem;">표시할 데이터가 없습니다.</p></div>';
updateStatsCounts(0, 0, 0, 0, 0);
return;
}
let html = '';
let normalCount = 0;
let warningCount = 0;
let errorCount = 0;
let inactiveCount = 0;
data.forEach(institution => {
let statusClass = 'status-normal';
let statusIcon = '<i class="bi bi-check-circle" style="color: #28a745;"></i>';
let statusName = '정상';
// 상태에 따른 시각화 설정
if (institution.lineStatus === 'UNDEFINED') {
statusClass = 'status-inactive';
statusIcon = '<i class="bi bi-dash-circle" style="color: #6c757d;"></i>';
statusName = '미사용';
inactiveCount++;
} else if (institution.lineStatus === 'WARN') {
statusClass = 'status-warning';
statusIcon = '<i class="bi bi-exclamation-triangle" style="color: #ffc107;"></i>';
statusName = '경고';
warningCount++;
} else if (institution.lineStatus === 'ERROR') {
statusClass = 'status-error';
statusIcon = '<i class="bi bi-x-circle" style="color: #dc3545;"></i>';
statusName = '오류';
errorCount++;
} else {
normalCount++;
}
html += '<div class="institution-card ' + statusClass + '" data-code="' + institution.institutionCode + '">' +
'<div class="institution-status-indicator">' + statusIcon + '</div>' +
'<div class="institution-name">' + (institution.institutionName || '미지정 기관') + '</div>' +
'<div class="institution-info">' +
'<span class="institution-info-label">담당자:</span>' +
'<span>' + (institution.contactPerson || '-') + '</span>' +
'</div>' +
'<div class="institution-info">' +
'<span class="institution-info-label">연락처:</span>' +
'<span>' + (institution.contactNumber || '-') + '</span>' +
'</div>' +
'<div class="institution-info">' +
'<span class="institution-info-label">상태:</span>' +
'<span>' + statusName + '</span>' +
'</div>' +
'<div class="institution-stats">' +
'<div class="institution-stat">' +
'<div class="stat-number normal">' + (institution.normalAdapterCount || '0') + '</div>' +
'<div class="stat-label">정상 어댑터</div>' +
'</div>' +
'<div class="institution-stat">' +
'<div class="stat-number error">' + (institution.errorAdapterCount || '0') + '</div>' +
'<div class="stat-label">오류 어댑터</div>' +
'</div>' +
'</div>' +
'</div>';
});
institutionGrid.innerHTML = html;
updateStatsCounts(data.length, normalCount, warningCount, errorCount, inactiveCount);
// 기관 카드 클릭 이벤트 - 해당 기관 정보로 필터링
const institutionCards = institutionGrid.querySelectorAll('.institution-card');
institutionCards.forEach(card => {
card.addEventListener('click', () => {
const institutionCode = card.getAttribute('data-code');
// 여기에 기관 코드로 필터링하는 로직 추가
console.log('기관 선택:', institutionCode);
// 기관에 해당하는 어댑터로 필터링하는 탭으로 이동
const socketStatusTab = document.querySelector('.tab-btn[data-tab="socket-status"]');
socketStatusTab.click();
});
});
}
// 통계 수치 업데이트
function updateStatsCounts(total, normal, warning, error, inactive) {
totalInstitutionsCount.textContent = total;
normalInstitutionsCount.textContent = normal;
warningInstitutionsCount.textContent = warning;
errorInstitutionsCount.textContent = error;
inactiveInstitutionsCount.textContent = inactive;
}
// 회선 상태 테이블 업데이트
function updateSocketStatusTable(data) {
if (!data || !data.rows || data.rows.length === 0) {
statusTable.innerHTML = '<tr><td colspan="7"><div style="padding: 2rem; text-align: center; color: #6c757d;"><i class="fas fa-info-circle" style="font-size: 2rem;"></i><p style="margin-top: 1rem;">표시할 데이터가 없습니다.</p></div></td></tr>';
return;
}
let html = '';
data.rows.forEach(row => {
let statusClass = row.status === 'true' ? 'status-badge status-badge-normal' : 'status-badge status-badge-error';
const statusName = row.status === 'true' ? '정상' : '오류';
html += '<tr>' +
'<td>' + (row.adptrBzwkGroupName || '-') + '</td>' +
'<td>' + (row.eaiSevrInstncName || '-') + '</td>' +
'<td>' + (row.adptrNickName || '-') + '</td>' +
'<td>' + (row.adptrBzwkDesc || '-') + '</td>' +
'<td>' + (row.adptrType || '-') + '</td>' +
'<td><span class="' + statusClass + '">' + statusName + '</span></td>' +
'<td>' + (row.starting || '-') + '</td>' +
'</tr>';
});
statusTable.innerHTML = html;
}
// 회선 연결 상태 테이블 업데이트
function updateSocketProcessTable(data) {
if (!data || !data.rows || data.rows.length === 0) {
processTable.innerHTML = '<tr><td colspan="10"><div style="padding: 2rem; text-align: center; color: #6c757d;"><i class="fas fa-info-circle" style="font-size: 2rem;"></i><p style="margin-top: 1rem;">표시할 데이터가 없습니다.</p></div></td></tr>';
return;
}
let html = '';
data.rows.forEach(row => {
let statusClass = row.status === 'true' ? 'status-badge status-badge-normal' : 'status-badge status-badge-error';
const statusName = row.status === 'true' ? '정상' : '오류';
html += '<tr>' +
'<td>' + (row.adptrBzwkGroupName || '-') + '</td>' +
'<td>' + (row.eaiSevrInstncName || '-') + '</td>' +
'<td>' + (row.adptrBzwkName || '-') + '</td>' +
'<td>' + (row.adptrBzwkDesc || '-') + '</td>' +
'<td>' + (row.maxConnection || '0') + '</td>' +
'<td>' + (row.currentConnection || '0') + '</td>' +
'<td>' + (row.sendCount || '0') + '</td>' +
'<td>' + (row.recvCount || '0') + '</td>' +
'<td>' + (row.errorCount || '0') + '</td>' +
'<td><span class="' + statusClass + '">' + statusName + '</span></td>' +
'</tr>';
});
processTable.innerHTML = html;
}
// 모달 열기 함수 (전역 스코프에 노출)
window.openSocketDetailModal = function(serverName, adapterGroup) {
// 모달 표시
modal.style.display = 'block';
// 데이터 로드
loadSocketData(serverName, adapterGroup);
};
})();
</script>