건설현장 관리 > 발주기관 로그인 내역 - 일별 접속량 차트 추가
parent
dbb58e393c
commit
61be76c392
|
|
@ -995,6 +995,31 @@ public class ConstructionProjectManagementController {
|
|||
return "admins/constructionProjectManagement/construction-user-login-history";
|
||||
}
|
||||
|
||||
/**
|
||||
* API 관리 > 일일접속량 차트
|
||||
* @param params
|
||||
* @param model
|
||||
* @param response
|
||||
* @param request
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@ResponseBody
|
||||
@RequestMapping(value = "/admins/constructionProjectManagement/o_charts.do", method = RequestMethod.POST)
|
||||
public HashMap<String, Object> getMgmtApiOutDataAccessChart(@RequestParam HashMap<String, Object> params, ModelMap model, HttpServletResponse response, HttpServletRequest request) throws Exception {
|
||||
strUtil sUtil = new strUtil();
|
||||
HashMap<String, Object> result = new HashMap<String, Object>();
|
||||
String CHART_DATE = sUtil.checkNull((String)params.get("chartDate"));
|
||||
params.put("CHART_DATE", CHART_DATE);
|
||||
List<EgovMap> listData = masterService.selectUserLoginHistoryChart(params);
|
||||
|
||||
result.put("code", "SUCCESS");
|
||||
result.put("msg", "일별 접속량 데이터 조회를 성공했습니다.");
|
||||
result.put("data", listData);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public void buildExcelDocument(Map<String, Object> model, HSSFWorkbook workbook, HttpServletRequest request, HttpServletResponse response) throws Exception {
|
||||
|
||||
List<?> selectInfoListExcel = (List<?>) model.get("selectInfoListExcel");
|
||||
|
|
|
|||
|
|
@ -54,6 +54,8 @@ public interface GeneralUserMngMapper {
|
|||
|
||||
public List<EgovMap> selectUserLoginHistory(HashMap<String, Object> params) throws Exception;
|
||||
|
||||
public List<EgovMap> selectUserLoginHistoryChart(HashMap<String, Object> params) throws Exception;
|
||||
|
||||
String findProjectMasterCompanyNameByUserid(String userId);
|
||||
|
||||
List<EgovMap> getUserGDisList(HashMap<String, Object> params) throws Exception;
|
||||
|
|
|
|||
|
|
@ -52,6 +52,8 @@ public interface GeneralUserMngService {
|
|||
|
||||
public List<EgovMap> selectUserLoginHistory(HashMap<String, Object> params) throws Exception;
|
||||
|
||||
public List<EgovMap> selectUserLoginHistoryChart(HashMap<String, Object> params) throws Exception;
|
||||
|
||||
public List<EgovMap> getUserGDisList(HashMap<String, Object> params) throws Exception;
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -128,6 +128,11 @@ public class GeneralUserMngServiceImpl implements GeneralUserMngService {
|
|||
return masterMapper.selectUserLoginHistory(params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<EgovMap> selectUserLoginHistoryChart(HashMap<String, Object> params) throws Exception {
|
||||
return masterMapper.selectUserLoginHistoryChart(params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<EgovMap> getUserGDisList(HashMap<String, Object> params) throws Exception {
|
||||
return masterMapper.getUserGDisList(params);
|
||||
|
|
|
|||
|
|
@ -485,6 +485,34 @@
|
|||
]]> -->
|
||||
</select>
|
||||
|
||||
<select id="selectUserLoginHistoryChart" parameterType="map" resultType="egovMap">
|
||||
<!-- SELECT TO_CHAR(d.visit_date, 'YYYY-MM-DD') AS visit_date
|
||||
,COUNT(wmi.USERID) AS visit_count
|
||||
FROM (SELECT TRUNC(TO_DATE(#{chartDate})) - LEVEL + 1 AS visit_date
|
||||
FROM DUAL
|
||||
CONNECT BY LEVEL <![CDATA[<=]]> 10) d
|
||||
LEFT JOIN WEB_REQUEST_LOG wrl ON wrl.DATETIME <![CDATA[>=]]> d.visit_date
|
||||
AND wrl.DATETIME <![CDATA[<]]> d.visit_date + 1
|
||||
INNER JOIN WEB_MEMBER_IN wmi ON wrl.USERID = wmi.USERID
|
||||
AND wmi.CLS = 2
|
||||
GROUP BY d.visit_date
|
||||
ORDER BY d.visit_date -->
|
||||
|
||||
SELECT TO_CHAR(d.visit_date, 'YYYY-MM-DD') AS visit_date
|
||||
,NVL(COUNT(wrl.DATETIME), 0) AS visit_count
|
||||
FROM (SELECT TRUNC(TO_DATE(#{chartDate})) - LEVEL + 1 AS visit_date
|
||||
FROM DUAL
|
||||
CONNECT BY LEVEL <![CDATA[<=]]> 10) d
|
||||
LEFT JOIN WEB_REQUEST_LOG wrl ON wrl.DATETIME <![CDATA[>=]]> d.visit_date
|
||||
AND wrl.DATETIME <![CDATA[<]]> d.visit_date + 1
|
||||
AND EXISTS (SELECT 1
|
||||
FROM WEB_MEMBER_IN WMI
|
||||
WHERE WMI.USERID = wrl.USERID
|
||||
AND WMI.CLS = 2)
|
||||
GROUP BY d.visit_date
|
||||
ORDER BY d.visit_date
|
||||
</select>
|
||||
|
||||
<select id="findProjectMasterCompanyNameByUserid" parameterType="String" resultType="String">
|
||||
<![CDATA[
|
||||
SELECT
|
||||
|
|
|
|||
|
|
@ -7,75 +7,105 @@
|
|||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<script src="${pageContext.request.contextPath}/js/jquery/jquery-1.10.2.min.js"></script>
|
||||
<!-- Bootstrap Datepicker -->
|
||||
<link rel="stylesheet" href="${pageContext.request.contextPath}/js/bootstrap-datepicker-1.9.0-dist/css/bootstrap-datepicker.min.css">
|
||||
<script type="text/javascript" src="${pageContext.request.contextPath}/js/bootstrap-datepicker-1.9.0-dist/js/bootstrap-datepicker.min.js"></script>
|
||||
<script type="text/javascript" src="${pageContext.request.contextPath}/js/bootstrap-datepicker-1.9.0-dist/locales/bootstrap-datepicker.ko.min.js"></script>
|
||||
|
||||
<!-- MUI + Chart.js + jQuery -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||
<script src="${pageContext.request.contextPath}/js/admins/common.js"></script>
|
||||
<link rel="stylesheet" HREF="${pageContext.request.contextPath}/css/admins/style.css" type="text/css">
|
||||
|
||||
<style>
|
||||
.datepicker-wrapper > * {
|
||||
margin-right: 6px;
|
||||
}
|
||||
.datepicker-wrapper .date-next,
|
||||
.datepicker-wrapper .date-prev {
|
||||
border: 1px solid #4285f4;
|
||||
height: 18px;
|
||||
line-height: 18px;
|
||||
padding: 0 2px;
|
||||
margin-right: 1px;
|
||||
border-radius: 3px;
|
||||
background: #ecf3fe;
|
||||
color: #337bed;
|
||||
transition: .3s;
|
||||
}
|
||||
.date-prev:hover, .date-next:hover {
|
||||
cursor: pointer;
|
||||
background: #337bed;
|
||||
color: #ecf3fe;
|
||||
}
|
||||
.title-container, .chart-container {
|
||||
background: #fff; border-radius: 12px; box-shadow: 0 2px 8px rgba(0,0,0,0.05);
|
||||
padding: 20px; margin-bottom: 20px;
|
||||
}
|
||||
.datepicker-dropdown {
|
||||
z-index: 99999 !important;
|
||||
position: absolute;
|
||||
left: 0 !important;
|
||||
background: #fff;
|
||||
border: 1px solid #e6e6e6;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
// --------- 일일 접속량 차트 관련 변수 --------------------
|
||||
let trafficChart; // 전역 변수
|
||||
// --------- 일일 접속량 차트 관련 변수 --------------------
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
var searchTitle = document.getElementById('searchTitle');
|
||||
var searchValue = document.getElementById('searchValue');
|
||||
var searchContainer = searchValue.parentNode;
|
||||
var tildeText = document.createElement('span');
|
||||
tildeText.innerHTML = '~';
|
||||
var searchBgndt = document.createElement('input');
|
||||
var searchEnddt = document.createElement('input');
|
||||
// ----------------------------------------------------
|
||||
// 1. 날짜 선택기 초기화
|
||||
// ----------------------------------------------------
|
||||
|
||||
function createInput(input, id) {
|
||||
input.type = 'text';
|
||||
input.id = id;
|
||||
input.name = id;
|
||||
input.className = 'search';
|
||||
input.style.display = 'inline-block';
|
||||
input.style.width = '12ch';
|
||||
input.placeholder = 'YYYYMMDD';
|
||||
input.style.color = '#000'; // Text color
|
||||
input.maxLength = 8; // Limit input length
|
||||
input.onfocus = function() {
|
||||
this.placeholder = '';
|
||||
this.style.color = '#000'; // Text color
|
||||
};
|
||||
input.onblur = function() {
|
||||
if (this.value === '') {
|
||||
this.placeholder = 'YYYYMMDD';
|
||||
}
|
||||
};
|
||||
}
|
||||
// datepicker
|
||||
$("#chartDate, #count_from_dt, #count_to_dt").datepicker({
|
||||
format: "yyyy-mm-dd",
|
||||
language: "ko",
|
||||
autoclose: true,
|
||||
todayHighlight: true,
|
||||
container: 'body'
|
||||
}).datepicker("setDate", new Date());
|
||||
|
||||
createInput(searchBgndt, 'searchBgndt');
|
||||
createInput(searchEnddt, 'searchEnddt');
|
||||
searchBgndt.style.marginRight = '2px';
|
||||
searchEnddt.style.marginLeft = '2px';
|
||||
searchBgndt.value = "${params.searchBgndt}";
|
||||
searchEnddt.value = "${params.searchEnddt}";
|
||||
// 페이지 로드시 차트 먼저 로드
|
||||
getMgmtApiChart();
|
||||
|
||||
function addInputs() {
|
||||
searchValue.style.display = 'none';
|
||||
searchContainer.insertBefore(searchBgndt, searchValue);
|
||||
searchContainer.insertBefore(tildeText, searchValue);
|
||||
searchContainer.insertBefore(searchEnddt, searchValue);
|
||||
}
|
||||
|
||||
function removeInputs() {
|
||||
if (document.getElementById('searchBgndt')) {
|
||||
searchBgndt.remove();
|
||||
tildeText.remove();
|
||||
searchEnddt.remove();
|
||||
}
|
||||
searchValue.style.display = 'inline-block';
|
||||
}
|
||||
|
||||
if (searchTitle.value == '7') {
|
||||
addInputs();
|
||||
}
|
||||
|
||||
searchTitle.addEventListener('change', function() {
|
||||
if (this.value == '7') {
|
||||
addInputs();
|
||||
} else {
|
||||
removeInputs();
|
||||
}
|
||||
// 날짜 변경 시 차트 다시 로드
|
||||
$(document).on('change', '#chartDate', function() {
|
||||
getMgmtApiChart();
|
||||
});
|
||||
});
|
||||
|
||||
// <> 버튼으로 날짜 변경
|
||||
$(document).on('click', '.date-prev, .date-next', function() {
|
||||
const $input = $('#chartDate');
|
||||
|
||||
// 현재 날짜 가져오기 (yyyy-mm-dd)
|
||||
const currentVal = $input.val();
|
||||
if (!currentVal) return;
|
||||
|
||||
// 문자열 → Date 객체
|
||||
const dateParts = currentVal.split('-');
|
||||
const currentDate = new Date(
|
||||
dateParts[0],
|
||||
dateParts[1] - 1,
|
||||
dateParts[2]
|
||||
);
|
||||
|
||||
// 이전 / 다음 구분
|
||||
if ($(this).hasClass('date-prev')) {
|
||||
currentDate.setDate(currentDate.getDate() - 10);
|
||||
} else {
|
||||
currentDate.setDate(currentDate.getDate() + 10);
|
||||
}
|
||||
|
||||
// datepicker 날짜 변경 (이게 핵심)
|
||||
$input.datepicker('setDate', currentDate);
|
||||
|
||||
// setDate 하면 change 이벤트가 자동으로 발생함
|
||||
});
|
||||
})
|
||||
var context = "${pageContext.request.contextPath}";
|
||||
|
||||
function linkPage(index){
|
||||
|
|
@ -83,43 +113,92 @@ function linkPage(index){
|
|||
$("#searchForm").attr("action", "${pageContext.request.contextPath}/admins/user/02.do").submit();
|
||||
}
|
||||
|
||||
/* function excelDownload(){
|
||||
$("#searchForm").attr("action", "${pageContext.request.contextPath}/admins/user/02_excel.do").submit();
|
||||
$("#searchForm").attr("action", "${pageContext.request.contextPath}/admins/user/02.do");
|
||||
// API 호출 로그 목록 조회
|
||||
function getMgmtApiChart(){
|
||||
var chartDate = $('#chartDate').val();
|
||||
$.ajax({
|
||||
type : "POST",
|
||||
url : "/admins/constructionProjectManagement/o_charts.do" ,
|
||||
data : {chartDate: $('#chartDate').val()},
|
||||
dataType :"json",
|
||||
success : function(res){ // res.code, res.msg, res.data
|
||||
if (res.code == "SUCCESS") {
|
||||
const labels = res.data.map(d => d.visitDate.substring(5));
|
||||
const data = res.data.map(d => d.visitCount);
|
||||
drawTrafficChart(labels, data);
|
||||
} else {
|
||||
alert("API 호출 로그 목록 조회중 오류가 발생하였습니다. 다시 시도해주세요.");
|
||||
}
|
||||
},
|
||||
error : function(response){
|
||||
alert("API 호출 로그 목록 조회중 내부 오류가 발생하였습니다. 다시 시도해주세요.");
|
||||
}
|
||||
});
|
||||
}
|
||||
// Chart.js: 일일 접속량
|
||||
function drawTrafficChart(labels, dataArr) {
|
||||
const ctx = document.getElementById('trafficChart').getContext('2d');
|
||||
|
||||
// 이미 차트가 있으면 갱신
|
||||
if (trafficChart) {
|
||||
trafficChart.data.labels = labels;
|
||||
trafficChart.data.datasets[0].data = dataArr;
|
||||
trafficChart.update();
|
||||
return;
|
||||
}
|
||||
|
||||
// 최초 생성
|
||||
trafficChart = new Chart(ctx, {
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: labels,
|
||||
datasets: [{
|
||||
data: dataArr,
|
||||
borderColor: '#4285f4',
|
||||
backgroundColor: 'rgba(66,133,244,0.1)',
|
||||
tension: 0.4,
|
||||
fill: true,
|
||||
pointRadius: 3
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
plugins: {
|
||||
legend: { display: false }
|
||||
},
|
||||
scales: {
|
||||
y: {
|
||||
beginAtZero: true,
|
||||
ticks: { stepSize: 1 }
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
*/
|
||||
$(function(){
|
||||
var searchTitle = "${params.searchTitle}";
|
||||
searchTitle = searchTitle == "" ? "0" : searchTitle;
|
||||
$("#searchTitle").val(searchTitle);
|
||||
});
|
||||
|
||||
// 엑셀 다운로드
|
||||
function clickExcelDownload(){
|
||||
const params = new URLSearchParams();
|
||||
|
||||
params.append("constTag", "");
|
||||
params.append("constName", "");
|
||||
params.append("constStartDate", "");
|
||||
params.append("constEndDate", "");
|
||||
params.append("constStateCode", "");
|
||||
params.append("projectStateCode", "");
|
||||
params.append("constCompanyName", "");
|
||||
params.append("constCompanyAdmin", "");
|
||||
params.append("constCompanyTel", "");
|
||||
params.append("excelDownload", "Y");
|
||||
|
||||
// 엑셀 다운로드
|
||||
function clickExcelDownload(){
|
||||
const params = new URLSearchParams();
|
||||
// 페이지 정보
|
||||
const pagingEle = document.getElementById('paging');
|
||||
params.append("nPage", "0");
|
||||
params.append("nCount", "10000");
|
||||
|
||||
params.append("constTag", "");
|
||||
params.append("constName", "");
|
||||
params.append("constStartDate", "");
|
||||
params.append("constEndDate", "");
|
||||
params.append("constStateCode", "");
|
||||
params.append("projectStateCode", "");
|
||||
params.append("constCompanyName", "");
|
||||
params.append("constCompanyAdmin", "");
|
||||
params.append("constCompanyTel", "");
|
||||
params.append("excelDownload", "Y");
|
||||
|
||||
// 페이지 정보
|
||||
const pagingEle = document.getElementById('paging');
|
||||
params.append("nPage", "0");
|
||||
params.append("nCount", "10000");
|
||||
|
||||
// AJAX가 아닌 직접 다운로드 요청
|
||||
window.location.href = "/admins/constructionProjectManagement/excel.do?" + params.toString();
|
||||
$('#excelDownload').val("");
|
||||
}
|
||||
// AJAX가 아닌 직접 다운로드 요청
|
||||
window.location.href = "/admins/constructionProjectManagement/excel.do?" + params.toString();
|
||||
$('#excelDownload').val("");
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
|
|
@ -128,10 +207,21 @@ $(function(){
|
|||
<input type="hidden" id="cls" name="cls" value="2" />
|
||||
<table id="Table_Main" width="100%" border="0" cellpadding="0" cellspacing="0">
|
||||
<tr>
|
||||
<td colspan=2><div style="background: #fff; border-radius: 12px; padding: 5px 10px;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.05);"><h3>발주기관 로그인 내역</h3></div></td>
|
||||
<td colspan=2><div class="title-container" style="padding: 5px 10px;"><h3>발주기관 로그인 내역</h3></div></td>
|
||||
</tr>
|
||||
<tr height=20 colspan=2>
|
||||
<td>
|
||||
<div class="chart-container">
|
||||
<div class="datepicker-wrapper" style="position: relative;display: flex;align-items: center;">
|
||||
<h3>📈 일별 접속량</h3>
|
||||
<input type="text" name="chartDate" id="chartDate" class="input" placeholder="클릭하여 날짜 선택">
|
||||
<div class="date-prev"> <</div>
|
||||
<div class="date-next"> ></div>
|
||||
</div>
|
||||
<canvas id="trafficChart" height="100"></canvas>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr height=20 colspan=2><td> </td></tr>
|
||||
<%-- <tr height=25>
|
||||
<!-- START : 엑셀 다운로드 ------------------------------------------------------------------------->
|
||||
<td>
|
||||
|
|
|
|||
Loading…
Reference in New Issue