geoinfo_admin/src/main/webapp/WEB-INF/views/admins/constructionProjectManagement/construction-project-statis...

263 lines
12 KiB
Plaintext
Raw Normal View History

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ taglib prefix="ui" uri="http://egovframework.gov/ctl/ui"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<!-- Chart.js 라이브러리 -->
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
<link rel="stylesheet" HREF="${pageContext.request.contextPath}/css/admins/style.css" type="text/css">
<script>
var context = "${pageContext.request.contextPath}";
var myChartInstance = null; // 단계별 차트 인스턴스
var instChartInstance = null; // 기관별 차트 인스턴스 (신규)
// [1] 문서 로드 완료 시 초기 실행
document.addEventListener("DOMContentLoaded", function() {
// 초기 로딩 시 검색 조건 없이 전체 통계 조회
moveConstructionUserDetail();
});
// [2] 통계 조회 함수 (Vanilla JS)
function moveConstructionUserDetail() {
// 기본 검색 조건 (필요시 변경 가능)
var params = {
constTag: "Y"
};
// AJAX 요청 (XMLHttpRequest 사용)
var xhr = new XMLHttpRequest();
xhr.open("POST", context + "/admins/constructionProjectManagement/selectStatistics.do", true);
xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) { // 요청 완료
if (xhr.status === 200) { // 성공
try {
var res = JSON.parse(xhr.responseText);
if(res.result == "true" || res.result == true) {
renderStatistics(res.data);
} else {
alert("통계 데이터를 불러오는 중 오류가 발생했습니다: " + (res.message || ""));
}
} catch (e) {
console.error("JSON 파싱 오류:", e);
}
} else {
console.error("AJAX Error:", xhr.statusText);
}
}
};
xhr.send(JSON.stringify(params));
}
// [3] 화면 갱신 함수
function renderStatistics(data) {
// (1) 전체 등록 수
var totalCountElem = document.getElementById("total-count");
if(totalCountElem) totalCountElem.textContent = (data.totalCount || 0) + " 건";
// (2) 지역별 통계
var busanElem = document.getElementById("busan-count");
var daeguElem = document.getElementById("daegu-count");
var sejongElem = document.getElementById("sejong-count");
if(busanElem) busanElem.textContent = "0 건";
if(daeguElem) daeguElem.textContent = "0 건";
if(sejongElem) sejongElem.textContent = "0 건";
// 서버에서 계산된 부산 카운트가 있으면 우선 적용
if(data.busanCount !== undefined && busanElem) {
busanElem.textContent = data.busanCount + " 건";
}
// 기존 리스트 기반 지역 카운트 (필요 시 사용)
if(data.regionList) {
data.regionList.forEach(function(item) {
var region = item.regionName || item.REGION_NAME || "";
var count = item.cnt || item.CNT || 0;
// 부산은 위에서 처리했으므로 제외하거나 중복 처리 가능
if(region.indexOf("대구") >= 0 && daeguElem) daeguElem.textContent = count + " 건";
else if(region.indexOf("세종") >= 0 && sejongElem) sejongElem.textContent = count + " 건";
});
}
// (3) 최근 입력된 건설현장
var recentArea = document.getElementById("recent-project-area");
var recentHtml = '<p class="fw-bold" style="font-size: 18px; color:#c87202;">최근 입력된 건설현장</p>';
if(data.recentList && data.recentList.length > 0) {
data.recentList.forEach(function(project) {
var name = project.constName || project.CONST_NAME || "";
var spot = project.projectStartSpot || project.PROJECT_START_SPOT || "";
var spotShort = spot.split(" ")[0];
recentHtml += '<p>' + name + ' - ' + spotShort + '</p>';
});
} else {
recentHtml += '<p>최근 등록된 데이터가 없습니다.</p>';
}
recentHtml += '<div class="d-flex justify-content-between align-items-center">' +
'<div class="btn-group"><button type="button" class="btn btn-sm btn-outline-secondary">+ 더 보기</button></div></div>';
if(recentArea) recentArea.innerHTML = recentHtml;
// (4) 단계별 건수 차트
updateStageChart(data.stageCounts || {});
// (5) [신규] 기관별 등록 건수 차트 업데이트
updateInstitutionChart(data.institutionStats || []);
}
// 단계별 차트 그리기
function updateStageChart(stageCounts) {
var chartData = [
stageCounts.feasibility || 0,
stageCounts.basicDesign || 0,
stageCounts.detailDesign || 0,
stageCounts.construction || 0,
stageCounts.completion || 0,
stageCounts.maintenance || 0
];
var stageFeasElem = document.getElementById("stage-feasibility");
if(stageFeasElem) stageFeasElem.textContent = (stageCounts.feasibility || 0) + "건";
var ctx = document.getElementById('myChart');
if(!ctx) return;
if (myChartInstance) myChartInstance.destroy();
myChartInstance = new Chart(ctx, {
type: 'bar',
data: {
labels: ['타당성조사', '기본설계', '실시설계', '시공중', '준공', '유지보수'],
datasets: [{
label: '건설현장 단계별 건수',
data: chartData,
backgroundColor: 'rgba(54, 162, 235, 0.2)',
borderColor: 'rgba(54, 162, 235, 1)',
borderWidth: 1
}]
},
options: { scales: { y: { beginAtZero: true } } }
});
}
// [신규] 기관별 차트 그리기 함수
function updateInstitutionChart(instStats) {
var ctx = document.getElementById('institutionChart');
if(!ctx) return;
if (instChartInstance) instChartInstance.destroy();
var labels = [];
var data = [];
// 데이터 분리 및 라벨 보정
instStats.forEach(function(stat) {
var name = stat.name;
// [라벨 보정] '울산광역시' -> '한국도로공사'
if (name === '울산광역시') {
name = '한국도로공사';
}
labels.push(name);
data.push(stat.count);
});
instChartInstance = new Chart(ctx, {
type: 'bar', // 막대 그래프
data: {
labels: labels,
datasets: [{
label: '등록 건수',
data: data,
backgroundColor: 'rgba(75, 192, 192, 0.5)', // 색상 설정
borderColor: 'rgba(75, 192, 192, 1)',
borderWidth: 1
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
y: {
beginAtZero: true,
ticks: { stepSize: 1 } // 정수 단위 표시
}
},
plugins: {
legend: { display: false }, // 범례 숨김 (단일 데이터셋이므로)
title: {
display: true,
text: '기관별 건설현장 등록 현황',
font: { size: 16 }
}
}
}
});
}
</script>
</head>
<body>
<h1>건설현장 통계</h1>
<div class="home-trainning">
<div class="container-fluid">
<div class="row content">
<div class="col-sm-12">
<!-- [신규] 기관별 통계 그래프 영역 추가 (하단 전체 너비) -->
<div class="row" style="margin-top: 30px;">
<div class="col-sm-12">
<div class="well" style="background-color: #fff;">
<p class="fw-bold" style="font-size: 18px; color:#c87202; margin-bottom: 15px;">기관별 등록 건수</p>
<div style="height: 400px;"> <!-- 높이 지정 -->
<canvas id="institutionChart"></canvas>
</div>
</div>
</div>
</div>
<div class="row">
<!-- 최근 입력된 건설현장 -->
<div class="col-sm-4">
<div class="well" id="recent-project-area">
<p class="fw-bold" style="font-size: 18px; color:#c87202;">최근 입력된 건설현장</p>
<p>로딩 중...</p>
</div>
</div>
<!-- 단계별 건수 텍스트 -->
<div class="col-sm-4">
<div class="well">
<p class="fw-bold" style="font-size: 18px; color:#c87202;">단계별 건수</p>
<p><b>타당성조사 및 계획검토:</b> <span id="stage-feasibility">0건</span></p>
<p><b>기본설계:</b> 0건</p>
<p><b>실시설계:</b> 0건</p>
<p><b>시공중:</b> 0건</p>
<p><b>준공:</b> 0건</p>
<p><b>유지보수:</b> 0건</p>
</div>
</div>
<!-- 단계별 건수 그래프 -->
<div class="col-sm-4">
<div class="well">
<canvas id="myChart"></canvas>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>