Loading...
@@ -88,10 +85,16 @@
데이터를 불러오는 중입니다... 잠시만 기다려 주세요.
+
데이터를 불러오는데 실패했습니다. (서버 오류)
+
+
+ 선택하신 기간에는 조회된 트래픽 데이터가 없습니다. 기간을 다시 설정해주세요.
+
+
@@ -110,20 +113,17 @@
});
// -----------------------------------------------------------
- // 1. CI4 백엔드 엔드포인트를 호출하여 데이터 가져오기 (AJAX) - GET 방식으로 변경됨
+ // 1. CI4 백엔드 엔드포인트를 호출하여 데이터 가져오기 (AJAX)
// -----------------------------------------------------------
async function fetchAggregatedData(startDate, endDate) {
- // PHP 변수를 사용하여 엔드포인트 URL을 구성합니다.
const baseEndpoint = '= base_url("/admin/traffic/data/{$viewDatas['entity']->getPK()}") ?>';
- // GET 요청을 위해 쿼리 파라미터를 생성합니다.
const params = new URLSearchParams({
startDate: startDate,
endDate: endDate
});
- // 최종 엔드포인트 URL: /admin/traffic/data/{PK}?startDate=...&endDate=...
const endpoint = `${baseEndpoint}?${params.toString()}`;
const maxRetries = 3;
@@ -132,7 +132,7 @@
for (let i = 0; i < maxRetries; i++) {
try {
const response = await fetch(endpoint, {
- method: 'GET', // GET 방식으로 유지
+ method: 'GET',
});
const result = await response.json();
@@ -141,7 +141,14 @@
throw new Error(result.message || `HTTP error! Status: ${response.status}`);
}
- return result.data; // Model에서 반환된 데이터 배열
+ // **********************************************
+ // ** 중요: 데이터가 비어있는 경우를 여기서 감지 **
+ // **********************************************
+ if (!result.data || result.data.length === 0) {
+ return []; // 빈 배열 반환하여 데이터 없음 처리
+ }
+
+ return result.data;
} catch (error) {
console.error(`Attempt ${i + 1} failed:`, error);
@@ -149,7 +156,7 @@
throw new Error("서버에서 데이터를 가져오는데 실패했습니다. 콘솔을 확인하세요.");
}
await new Promise(resolve => setTimeout(resolve, delay));
- delay *= 2; // 지수 백오프
+ delay *= 2;
}
}
}
@@ -167,31 +174,39 @@
const dateRangeInfoElement = document.getElementById('dateRangeInfo');
const loadingIndicator = document.getElementById('loadingIndicator');
const errorMessage = document.getElementById('errorMessage');
+ const noDataMessage = document.getElementById('noDataMessage');
const canvas = document.getElementById('trafficChart');
const viewChartBtn = document.getElementById('viewChartBtn');
// UI 초기화 및 로딩 표시
loadingIndicator.style.display = 'block';
errorMessage.style.display = 'none';
+ noDataMessage.style.display = 'none';
canvas.style.opacity = '0';
viewChartBtn.disabled = true;
- // 메인 제목: Kbit/s 정보만
+ // 제목 및 기간 정보 업데이트
chartTitleElement.textContent = `트래픽 속도 추이 (IN/OUT Kbit/s)`;
-
- // 시작일, 마지막일 정보 표시
dateRangeInfoElement.textContent = `기간: ${startDate} 부터 ${endDate} 까지`;
try {
- // CI4 백엔드(Controller -> Model)에서 데이터 가져오기
const aggregatedData = await fetchAggregatedData(startDate, endDate);
- // --- IN, OUT Kbit/s 데이터만 추출 ---
- // Model은 'created_at', 'in_kbits', 'out_kbits'를 반환해야 합니다.
+ if (aggregatedData.length === 0) {
+ // 데이터가 비어 있을 경우
+ noDataMessage.style.display = 'block';
+ if (trafficChart) {
+ trafficChart.destroy(); // 기존 차트 파괴
+ trafficChart = null;
+ }
+ return;
+ }
+
+ // 데이터 추출
const labels = aggregatedData.map(d => d.created_at);
- const inData = aggregatedData.map(d => d.in_kbits);
- const outData = aggregatedData.map(d => d.out_kbits);
- // ----------------------------------
+ // 데이터 타입을 Number로 명시적 변환하여 Chart.js가 숫자로 인식하도록 보장
+ const inData = aggregatedData.map(d => Number(d.in_kbits));
+ const outData = aggregatedData.map(d => Number(d.out_kbits));
drawChart(labels, inData, outData);
@@ -202,7 +217,8 @@
} finally {
loadingIndicator.style.display = 'none';
- canvas.style.opacity = '1';
+ // 차트가 성공적으로 그려졌거나 '데이터 없음' 메시지가 표시된 경우에만 캔버스 영역 표시
+ canvas.style.opacity = (trafficChart || noDataMessage.style.display === 'block') ? '1' : '0';
viewChartBtn.disabled = false;
}
}
@@ -215,79 +231,85 @@
trafficChart.destroy();
}
- trafficChart = new Chart(ctx, {
- type: 'line',
- data: {
- labels: labels,
- datasets: [{
- label: 'IN Kbit/s',
- data: inData,
- borderColor: '#198754', // Bootstrap Success Color (Green)
- backgroundColor: 'rgba(25, 135, 84, 0.1)',
- fill: true,
- tension: 0.3,
- pointRadius: 3,
- pointHoverRadius: 6,
- },
- {
- label: 'OUT Kbit/s',
- data: outData,
- borderColor: '#dc3545', // Bootstrap Danger Color (Red)
- backgroundColor: 'rgba(220, 53, 69, 0.1)',
- fill: true,
- tension: 0.3,
- pointRadius: 3,
- pointHoverRadius: 6,
- }
- ]
- },
- options: {
- responsive: true,
- maintainAspectRatio: false,
- scales: {
- y: {
- beginAtZero: true,
- title: {
- display: true,
- text: 'Kbit/s', // Y축 레이블에 Kbit/s 명시
- font: {
- weight: 'bold'
- }
+ try {
+ trafficChart = new Chart(ctx, {
+ type: 'line',
+ data: {
+ labels: labels,
+ datasets: [{
+ label: 'IN Kbit/s',
+ data: inData,
+ borderColor: '#198754', // Bootstrap Success Color (Green)
+ backgroundColor: 'rgba(25, 135, 84, 0.1)',
+ fill: true,
+ tension: 0.3,
+ pointRadius: 3,
+ pointHoverRadius: 6,
+ },
+ {
+ label: 'OUT Kbit/s',
+ data: outData,
+ borderColor: '#dc3545', // Bootstrap Danger Color (Red)
+ backgroundColor: 'rgba(220, 53, 69, 0.1)',
+ fill: true,
+ tension: 0.3,
+ pointRadius: 3,
+ pointHoverRadius: 6,
}
- },
- x: {
- title: {
- display: true,
- text: '기간',
- font: {
- weight: 'bold'
+ ]
+ },
+ options: {
+ responsive: true,
+ maintainAspectRatio: false,
+ scales: {
+ y: {
+ beginAtZero: true,
+ title: {
+ display: true,
+ text: 'Kbit/s', // Y축 레이블에 Kbit/s 명시
+ font: {
+ weight: 'bold'
+ }
}
},
- ticks: {
- autoSkip: true,
- maxTicksLimit: 20
- }
- }
- },
- plugins: {
- legend: {
- position: 'top',
- labels: {
- usePointStyle: true,
- padding: 20
+ x: {
+ title: {
+ display: true,
+ text: '기간',
+ font: {
+ weight: 'bold'
+ }
+ },
+ ticks: {
+ autoSkip: true,
+ maxTicksLimit: 20
+ }
}
},
- tooltip: {
- mode: 'index',
- intersect: false,
+ plugins: {
+ legend: {
+ position: 'top',
+ labels: {
+ usePointStyle: true,
+ padding: 20
+ }
+ },
+ tooltip: {
+ mode: 'index',
+ intersect: false,
+ }
+ },
+ hover: {
+ mode: 'nearest',
+ intersect: true
}
- },
- hover: {
- mode: 'nearest',
- intersect: true
}
- }
- });
+ });
+ } catch (e) {
+ console.error("Chart.js Initialization Failed:", e);
+ document.getElementById('errorMessage').textContent = `차트 생성 실패: ${e.message}. 브라우저의 콘솔을 확인하세요.`;
+ document.getElementById('errorMessage').style.display = 'block';
+ }
}