377 lines
15 KiB
Plaintext
377 lines
15 KiB
Plaintext
<%@ 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">
|
|
|
|
<style>
|
|
/* 그래프 컨테이너 스타일 */
|
|
.chart-wrapper {
|
|
border: 1px solid #ddd;
|
|
padding: 20px;
|
|
margin-bottom: 30px;
|
|
background: #fff;
|
|
border-radius: 8px;
|
|
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
|
|
}
|
|
.chart-header {
|
|
font-size: 18px;
|
|
font-weight: bold;
|
|
color: #333;
|
|
margin-bottom: 20px;
|
|
padding-bottom: 10px;
|
|
border-bottom: 2px solid #c87202;
|
|
}
|
|
.sub-chart-title {
|
|
text-align: center;
|
|
font-weight: bold;
|
|
margin-bottom: 10px;
|
|
color: #555;
|
|
}
|
|
.sub-chart-box {
|
|
height: 300px;
|
|
position: relative;
|
|
}
|
|
</style>
|
|
|
|
<script>
|
|
var context = "${pageContext.request.contextPath}";
|
|
var myChartInstance = null; // 상단 전체 단계별 차트
|
|
var instChartInstance = null; // 하단 전체 기관별 차트
|
|
|
|
// [1] 문서 로드 완료 시 초기 실행 (Vanilla JS)
|
|
document.addEventListener("DOMContentLoaded", function() {
|
|
moveConstructionUserDetail();
|
|
});
|
|
|
|
// [2] 통계 조회 함수 (Vanilla JS)
|
|
function moveConstructionUserDetail() {
|
|
var params = { constTag: "Y" };
|
|
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) 상단 요약 수치 갱신 (Vanilla JS)
|
|
var totalElem = document.getElementById("total-count");
|
|
if (totalElem) totalElem.textContent = (data.totalCount || 0) + " 건";
|
|
|
|
var busanElem = document.getElementById("busan-count");
|
|
if (data.busanCount !== undefined && busanElem) {
|
|
busanElem.textContent = data.busanCount + " 건";
|
|
}
|
|
|
|
// (2) 상단 전체 단계별 차트 갱신
|
|
updateStageChart(data.stageCounts || {});
|
|
|
|
// (3) [신규] 기관별 상세 그래프 동적 생성 (입력상태, 성과현황)
|
|
createInstitutionDetailCharts(data.institutionStats || []);
|
|
|
|
// (4) 하단 전체 기관 등록 건수 차트 갱신
|
|
// (4)-1 하단 국토부 소속 기관 등록 건수 차트 갱신
|
|
var gm01List = data.institutionStats.filter(function(stat) {
|
|
return stat.gm === "01" && stat.name != "국토교통부 부산지방국토관리청";
|
|
});
|
|
|
|
// (4)-2 하단 국토부 산하 기관 등록 건수 차트 갱신
|
|
var gm02List = data.institutionStats.filter(function(stat) {
|
|
return stat.gm === "02";
|
|
});
|
|
|
|
// 각각 차트 생성
|
|
updateInstitutionChart('institutionChart_gm01', gm01List, '');
|
|
updateInstitutionChart('institutionChart_gm02', gm02List, '');
|
|
}
|
|
|
|
// [상단] 전체 단계별 차트
|
|
function updateStageChart(stageCounts) {
|
|
var chartData = [
|
|
stageCounts.feasibility || 0,
|
|
stageCounts.basicDesign || 0,
|
|
stageCounts.detailDesign || 0,
|
|
stageCounts.construction || 0,
|
|
stageCounts.completion || 0,
|
|
stageCounts.maintenance || 0
|
|
];
|
|
|
|
// 텍스트 업데이트 (Vanilla JS)
|
|
var stageElem = document.getElementById("stage-feasibility");
|
|
if (stageElem) stageElem.textContent = (stageCounts.feasibility || 0) + "건";
|
|
|
|
var canvas = document.getElementById('myChart');
|
|
if(!canvas) return;
|
|
|
|
if (myChartInstance) myChartInstance.destroy();
|
|
|
|
myChartInstance = new Chart(canvas, {
|
|
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 createInstitutionDetailCharts(instStats) {
|
|
var container = document.getElementById("institution-detail-area");
|
|
if (!container) return;
|
|
|
|
container.innerHTML = ""; // 기존 내용 초기화
|
|
|
|
instStats.forEach(function(stat, index) {
|
|
// 라벨 보정
|
|
var name = stat.name;
|
|
if (name === '울산광역시') name = '한국도로공사';
|
|
|
|
// Canvas ID 생성
|
|
var inputChartId = 'inputChart_' + index;
|
|
var perfChartId = 'perfChart_' + index;
|
|
|
|
// HTML 구조 생성
|
|
var html = '';
|
|
html += '<div class="col-sm-12">';
|
|
html += ' <div class="chart-wrapper">';
|
|
html += ' <div class="chart-header">' + name + ' (총 ' + stat.count + '건)</div>';
|
|
html += ' <div class="row">';
|
|
html += ' <div class="col-sm-6">';
|
|
html += ' <div class="sub-chart-title">건설현장 프로젝트 입력상태</div>';
|
|
html += ' <div class="sub-chart-box"><canvas id="' + inputChartId + '"></canvas></div>';
|
|
html += ' </div>';
|
|
html += ' <div class="col-sm-6">';
|
|
html += ' <div class="sub-chart-title">기관별 성과 현황</div>';
|
|
html += ' <div class="sub-chart-box"><canvas id="' + perfChartId + '"></canvas></div>';
|
|
html += ' </div>';
|
|
html += ' </div>';
|
|
html += ' </div>';
|
|
html += '</div>';
|
|
|
|
// DOM에 추가
|
|
var div = document.createElement("div");
|
|
div.className = "row"; // 행 단위로 추가
|
|
div.innerHTML = html;
|
|
container.appendChild(div);
|
|
|
|
// 1) 입력상태 파이 차트 그리기
|
|
drawPieChart(inputChartId, stat.inputStatusData);
|
|
|
|
// 2) 성과현황 막대 차트 그리기
|
|
drawBarChart(perfChartId, stat.performanceData);
|
|
});
|
|
}
|
|
|
|
function drawPieChart(id, dataArr) {
|
|
var canvas = document.getElementById(id);
|
|
if(!canvas) return;
|
|
|
|
new Chart(canvas, {
|
|
type: 'pie',
|
|
data: {
|
|
labels: ['미입력', '입력중', '검수 준비 대기중', '검수중', '수정요청', '검수완료', '등록완료'],
|
|
datasets: [{
|
|
data: dataArr,
|
|
backgroundColor: [
|
|
'#e0e0e0', // 미입력 (회색)
|
|
'#ffcd56', // 입력중 (노랑)
|
|
'#36a2eb', // 검수 준비 대기중 (파랑)
|
|
'#ff6384', // 검수중 (빨강)
|
|
'#ff9f40', // 수정요청 (주황)
|
|
'#4bc0c0', // 검수완료 (청록)
|
|
'#9966ff' // 등록완료 (보라)
|
|
]
|
|
}]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
maintainAspectRatio: false,
|
|
plugins: {
|
|
legend: { position: 'right' }
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
function drawBarChart(id, dataArr) {
|
|
var canvas = document.getElementById(id);
|
|
if(!canvas) return;
|
|
|
|
new Chart(canvas, {
|
|
type: 'bar',
|
|
data: {
|
|
labels: ['타당성조사', '기본설계', '실시설계', '시공중', '준공', '유지보수'],
|
|
datasets: [{
|
|
label: '건수',
|
|
data: dataArr,
|
|
backgroundColor: '#36a2eb',
|
|
borderWidth: 1
|
|
}]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
maintainAspectRatio: false,
|
|
scales: {
|
|
y: { beginAtZero: true, ticks: { stepSize: 1 } }
|
|
},
|
|
plugins: {
|
|
legend: { display: false }
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
// [하단] 전체 기관별 등록 건수 차트
|
|
function updateInstitutionChart(canvasId, instStats, title) {
|
|
var canvas = document.getElementById(canvasId);
|
|
if(!canvas) return;
|
|
|
|
var labels = [];
|
|
var data = [];
|
|
|
|
instStats.forEach(function(stat) {
|
|
var name = stat.name;
|
|
if (name === '울산광역시') name = '한국도로공사';
|
|
labels.push(name);
|
|
data.push(stat.count);
|
|
});
|
|
|
|
new Chart(canvas, {
|
|
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: title }
|
|
}
|
|
},
|
|
plugins: [barValuePlugin] // 👈 이거 추가
|
|
});
|
|
}
|
|
|
|
const barValuePlugin = {
|
|
id: 'barValuePlugin',
|
|
afterDatasetsDraw(chart, args, options) {
|
|
const { ctx } = chart;
|
|
|
|
chart.data.datasets.forEach((dataset, datasetIndex) => {
|
|
const meta = chart.getDatasetMeta(datasetIndex);
|
|
|
|
meta.data.forEach((bar, index) => {
|
|
const value = dataset.data[index];
|
|
if (value === null || value === undefined) return;
|
|
|
|
ctx.save();
|
|
ctx.fillStyle = '#333';
|
|
ctx.font = '12px Arial';
|
|
ctx.textAlign = 'center';
|
|
ctx.textBaseline = 'bottom';
|
|
|
|
ctx.fillText(value, bar.x, bar.y - 5);
|
|
ctx.restore();
|
|
});
|
|
});
|
|
}
|
|
};
|
|
</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" style="margin-top:30px;">
|
|
<div class="col-sm-6">
|
|
<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_gm01"></canvas>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<%-- 산하기관 --%>
|
|
<div class="col-sm-6">
|
|
<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_gm02"></canvas>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 기관별 상세 통계 그래프 영역 (동적 생성) -->
|
|
<div id="institution-detail-area" style="margin-top: 30px;">
|
|
<!-- 여기에 Javascript로 기관별 그래프들이 추가됨 -->
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html> |