Merge branch 'main' of http://10.dbnt.co.kr:50501/DBNT/old-geoinfo-or-kr-admin
commit
ca177be827
|
|
@ -0,0 +1,77 @@
|
|||
package geoinfo.admins.apiManagement;
|
||||
|
||||
import java.net.URLEncoder;
|
||||
import java.security.SecureRandom;
|
||||
import java.sql.SQLException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||
import org.apache.poi.ss.usermodel.Sheet;
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONObject;
|
||||
import org.json.simple.parser.JSONParser;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.ModelMap;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import egovframework.com.cmm.service.EgovProperties;
|
||||
import egovframework.rte.psl.dataaccess.util.EgovMap;
|
||||
import egovframework.rte.ptl.mvc.tags.ui.pagination.PaginationInfo;
|
||||
import geoinfo.admins.board.RefrncRoomController;
|
||||
import geoinfo.admins.user.service.GeneralUserMngService;
|
||||
import geoinfo.admins.user.service.HomeTrainingService;
|
||||
import geoinfo.com.EgovExcel;
|
||||
import geoinfo.com.GeoinfoCommon;
|
||||
import geoinfo.comm.util.ScriptUtil;
|
||||
import geoinfo.session.UserInfo;
|
||||
import geoinfo.util.MyUtil;
|
||||
import whois.whoisSMS;
|
||||
|
||||
|
||||
|
||||
@Controller
|
||||
public class ApiManagementController {
|
||||
@Resource(name = "generalUserMngService")
|
||||
private GeneralUserMngService masterService;
|
||||
|
||||
@Resource(name = "homeTrainingService")
|
||||
private HomeTrainingService homeTrainingService;
|
||||
|
||||
/**
|
||||
* 집합교육 화면
|
||||
* @param params
|
||||
* @param model
|
||||
* @param response
|
||||
* @param request
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@RequestMapping(value = "admins/mgmtApi/mgmt-api-index.do")
|
||||
public String goMgmtApiIndex(@RequestParam HashMap<String, Object> params, ModelMap model, HttpServletResponse response, HttpServletRequest request) throws Exception {
|
||||
|
||||
if (!UserInfo.isValidSession(request, response, "admin")) {
|
||||
return "";
|
||||
}
|
||||
|
||||
model.addAttribute("params", params);
|
||||
return "admins/mgmtApi/api-request-statistics-index";
|
||||
}
|
||||
}
|
||||
|
|
@ -17,6 +17,7 @@
|
|||
<!--- 탑메뉴 시작 --->
|
||||
<td width="690" valign="top"><img src="img/top_menu.gif" width="690" height="135" border="0" usemap="#Map2" /></td>
|
||||
<td valign="bottom"><span class="top-menu-item"><a href="/admins/main/main.do?menuId=constructionProjectManagement&pId=construction-project-statistics-index">건설현장 관리</a></span></td>
|
||||
<td valign="bottom"><span class="top-menu-item"><a href="/admins/main/main.do?menuId=mgmtApi&pId=mgmt-api-index">API 관리</a></span></td>
|
||||
<!--- 탑메뉴 끝 --->
|
||||
</tr>
|
||||
</table>
|
||||
|
|
|
|||
|
|
@ -142,6 +142,7 @@ document.addEventListener('keyup', function(e) {
|
|||
|
||||
<td width="690" valign="top"><img src="${pageContext.request.contextPath}/images/admins/frame/top_menu.gif" width="690" height="135" border="0" usemap="#Map2" /></td>
|
||||
<td valign="bottom"><span class="top-menu-item"><a href="/admins/main/main.do?menuId=constructionProjectManagement&pId=construction-project-statistics-index">건설현장 관리</a></span></td>
|
||||
<td valign="bottom"><span class="top-menu-item"><a href="/admins/main/main.do?menuId=mgmtApi&pId=mgmt-api-index">API 관리</a></span></td>
|
||||
<!--- 탑메뉴 끝 --->
|
||||
</tr>
|
||||
</tbody></table>
|
||||
|
|
|
|||
|
|
@ -113,6 +113,7 @@ document.addEventListener('keyup', function(e) {
|
|||
</td>
|
||||
<td width="690" valign="top"><img src="${pageContext.request.contextPath}/images/admins/frame/top_menu.gif" width="690" height="135" border="0" usemap="#Map2" /></td>
|
||||
<td valign="bottom"><span class="top-menu-item"><a href="/admins/main/main.do?menuId=constructionProjectManagement&pId=construction-project-statistics-index">건설현장 관리</a></span></td>
|
||||
<td valign="bottom"><span class="top-menu-item"><a href="/admins/main/main.do?menuId=mgmtApi&pId=mgmt-api-index">API 관리</a></span></td>
|
||||
<!--- 탑메뉴 끝 --->
|
||||
</tr>
|
||||
</table>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,580 @@
|
|||
<%@ 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" />
|
||||
<!-- MUI + Chart.js + jQuery -->
|
||||
<link href="https://cdn.jsdelivr.net/npm/@mui/material@5.15.14/dist/material.min.css" rel="stylesheet">
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
|
||||
|
||||
<style>
|
||||
body { font-family: 'Pretendard', 'Roboto', sans-serif; background-color: #f5f6fa; margin: 0; padding: 20px; }
|
||||
|
||||
.chart-container {
|
||||
background: #fff; border-radius: 12px; box-shadow: 0 2px 8px rgba(0,0,0,0.05);
|
||||
padding: 20px; margin-bottom: 20px;
|
||||
}
|
||||
.chart-container h3 { margin-bottom: 10px; }
|
||||
|
||||
.dashboard-grid {
|
||||
display: grid; grid-template-columns: 1fr 1fr; gap: 20px;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: #fff; border-radius: 12px; box-shadow: 0 2px 8px rgba(0,0,0,0.05); padding: 20px;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.dashboard-btn {
|
||||
background: linear-gradient(135deg, #4285f4, #1a73e8);
|
||||
color: #fff; border: none; border-radius: 20px; padding: 6px 16px;
|
||||
cursor: pointer; font-weight: 600; transition: 0.3s;
|
||||
}
|
||||
.dashboard-btn:hover { opacity: 0.9; }
|
||||
|
||||
.status-item {
|
||||
display: flex; align-items: center; justify-content: space-between;
|
||||
background: #fafafa; border-radius: 10px; padding: 10px 15px; margin-bottom: 8px;
|
||||
}
|
||||
.status-left { display: flex; align-items: center; gap: 10px; }
|
||||
.status-icon {
|
||||
width: 26px; height: 26px; display: flex; justify-content: center; align-items: center; border-radius: 50%;
|
||||
}
|
||||
.success { background-color: #e7f9ed; color: #2ecc71; }
|
||||
.fail { background-color: #fdecea; color: #e74c3c; }
|
||||
.delay { background-color: #eaf3fd; color: #3498db; }
|
||||
.error { background-color: #fff7e6; color: #f1c40f; }
|
||||
|
||||
/* 통제 카드 */
|
||||
.switch-container {
|
||||
max-height: 260px; overflow-y: auto;
|
||||
}
|
||||
|
||||
.api-switch {
|
||||
display: flex; justify-content: space-between; align-items: center;
|
||||
background: #f8f8f8; border-radius: 10px; padding: 12px 15px; margin-bottom: 10px;
|
||||
}
|
||||
.switch-title { font-weight: 600; }
|
||||
.switch-desc { font-size: 12px; color: #777; }
|
||||
|
||||
.mui-switch {
|
||||
position: relative; display: inline-block; width: 48px; height: 26px;
|
||||
}
|
||||
.mui-switch input { opacity: 0; width: 0; height: 0; }
|
||||
.mui-slider {
|
||||
position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0;
|
||||
background-color: #ccc; transition: 0.4s; border-radius: 34px;
|
||||
}
|
||||
.mui-slider:before {
|
||||
position: absolute; content: "OFF"; color: #fff; font-size: 10px;
|
||||
height: 20px; width: 20px; left: 3px; bottom: 3px;
|
||||
background-color: #999; display: flex; justify-content: center; align-items: center;
|
||||
border-radius: 50%; transition: 0.4s;
|
||||
}
|
||||
input:checked + .mui-slider {
|
||||
background-color: #4A90E2;
|
||||
}
|
||||
input:checked + .mui-slider:before {
|
||||
transform: translateX(22px);
|
||||
content: "ON"; background-color: #1A73E8;
|
||||
}
|
||||
|
||||
/* 로그 테이블 */
|
||||
.table-container {
|
||||
margin-top: 25px; background: #fff; border-radius: 12px; padding: 20px;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.05);
|
||||
}
|
||||
table { width: 100%; border-collapse: collapse; }
|
||||
thead { background: #f0f3f8; }
|
||||
th, td { padding: 10px; border-bottom: 1px solid #eee; text-align: left; }
|
||||
th { color: #555; font-weight: 600; }
|
||||
|
||||
.pagination {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
margin-top: 15px;
|
||||
}
|
||||
.pagination button {
|
||||
border: none;
|
||||
background-color: #e2e8f0;
|
||||
color: #334155;
|
||||
padding: 6px 12px;
|
||||
border-radius: 8px;
|
||||
font-size: 13px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
.pagination button.active {
|
||||
background-color: #3b82f6;
|
||||
color: white;
|
||||
}
|
||||
.pagination button:hover:not(.active) {
|
||||
background-color: #cbd5e1;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- 일일 접속량 -->
|
||||
<div class="chart-container">
|
||||
<h3>📈 일일 접속량</h3>
|
||||
<canvas id="trafficChart" height="100"></canvas>
|
||||
</div>
|
||||
|
||||
<div class="dashboard-grid">
|
||||
<!-- API 호출 현황 -->
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3>API 호출 현황</h3>
|
||||
<button class="dashboard-btn" onclick="refreshDashboard()">대시보드</button>
|
||||
</div>
|
||||
|
||||
<div class="status-item">
|
||||
<div class="status-left">
|
||||
<div class="status-icon success">✔</div>
|
||||
<div>
|
||||
<div><strong>호출 성공</strong></div>
|
||||
<small>3초 이내 응답</small>
|
||||
</div>
|
||||
</div>
|
||||
<div><strong id="successRate">0%</strong></div>
|
||||
</div>
|
||||
|
||||
<div class="status-item">
|
||||
<div class="status-left">
|
||||
<div class="status-icon fail">❌</div>
|
||||
<div>
|
||||
<div><strong>호출 실패</strong></div>
|
||||
<small>API 실패</small>
|
||||
</div>
|
||||
</div>
|
||||
<div><strong id="failRate">0%</strong></div>
|
||||
</div>
|
||||
|
||||
<div class="status-item">
|
||||
<div class="status-left">
|
||||
<div class="status-icon delay">🕓</div>
|
||||
<div>
|
||||
<div><strong>호출 지연</strong></div>
|
||||
<small>3초 초과 지연</small>
|
||||
</div>
|
||||
</div>
|
||||
<div><strong id="delayRate">0%</strong></div>
|
||||
</div>
|
||||
|
||||
<div class="status-item">
|
||||
<div class="status-left">
|
||||
<div class="status-icon error">⚠️</div>
|
||||
<div>
|
||||
<div><strong>호출 오류</strong></div>
|
||||
<small>오류 응답</small>
|
||||
</div>
|
||||
</div>
|
||||
<div><strong id="errorRate">0%</strong></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- API 호출 통제 -->
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3>API 호출 통제</h3>
|
||||
<label class="mui-switch">
|
||||
<input type="checkbox" id="globalSwitch" checked>
|
||||
<span class="mui-slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="switch-container" id="apiSwitchList">
|
||||
<div class="api-switch">
|
||||
<div>
|
||||
<div class="switch-title">프로젝트 관련 데이터 갯수(전체 합)</div>
|
||||
<div class="switch-desc">사용자 작업용 API</div>
|
||||
</div>
|
||||
<label class="mui-switch">
|
||||
<input type="checkbox" class="api-toggle" data-api="api1" checked>
|
||||
<span class="mui-slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="api-switch">
|
||||
<div>
|
||||
<div class="switch-title">프로젝트 관련 데이터 갯수 (시추 개별)</div>
|
||||
<div class="switch-desc">사용자 작업용 API</div>
|
||||
</div>
|
||||
<label class="mui-switch">
|
||||
<input type="checkbox" class="api-toggle" data-api="api2" checked>
|
||||
<span class="mui-slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="api-switch">
|
||||
<div>
|
||||
<div class="switch-title">시추정보 관련 데이터 갯수</div>
|
||||
<div class="switch-desc">사용자 작업용 API</div>
|
||||
</div>
|
||||
<label class="mui-switch">
|
||||
<input type="checkbox" class="api-toggle" data-api="api3" checked>
|
||||
<span class="mui-slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<!-- 그 이하 항목들도 동일한 방식으로 반복 -->
|
||||
|
||||
<div class="api-switch">
|
||||
<div>
|
||||
<div class="switch-title">사업(프로젝트)정보</div>
|
||||
<div class="switch-desc">사용자 작업용 API</div>
|
||||
</div>
|
||||
<label class="mui-switch">
|
||||
<input type="checkbox" class="api-toggle" data-api="api4" checked>
|
||||
<span class="mui-slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="api-switch">
|
||||
<div>
|
||||
<div class="switch-title">지질정보</div>
|
||||
<div class="switch-desc">사용자 작업용 API</div>
|
||||
</div>
|
||||
<label class="mui-switch">
|
||||
<input type="checkbox" class="api-toggle" data-api="api5" checked>
|
||||
<span class="mui-slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="api-switch">
|
||||
<div>
|
||||
<div class="switch-title">전기비저항탐사시험</div>
|
||||
<div class="switch-desc">사용자 작업용 API</div>
|
||||
</div>
|
||||
<label class="mui-switch">
|
||||
<input type="checkbox" class="api-toggle" data-api="api6" checked>
|
||||
<span class="mui-slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="api-switch">
|
||||
<div>
|
||||
<div class="switch-title">굴절법탄성파</div>
|
||||
<div class="switch-desc">사용자 작업용 API</div>
|
||||
</div>
|
||||
<label class="mui-switch">
|
||||
<input type="checkbox" class="api-toggle" data-api="api7" checked>
|
||||
<span class="mui-slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="api-switch">
|
||||
<div>
|
||||
<div class="switch-title">시추정보</div>
|
||||
<div class="switch-desc">사용자 작업용 API</div>
|
||||
</div>
|
||||
<label class="mui-switch">
|
||||
<input type="checkbox" class="api-toggle" data-api="api8" checked>
|
||||
<span class="mui-slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="api-switch">
|
||||
<div>
|
||||
<div class="switch-title">지층정보</div>
|
||||
<div class="switch-desc">사용자 작업용 API</div>
|
||||
</div>
|
||||
<label class="mui-switch">
|
||||
<input type="checkbox" class="api-toggle" data-api="api9" checked>
|
||||
<span class="mui-slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="api-switch">
|
||||
<div>
|
||||
<div class="switch-title">표준관입시험</div>
|
||||
<div class="switch-desc">사용자 작업용 API</div>
|
||||
</div>
|
||||
<label class="mui-switch">
|
||||
<input type="checkbox" class="api-toggle" data-api="api10" checked>
|
||||
<span class="mui-slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="api-switch">
|
||||
<div>
|
||||
<div class="switch-title">절리정보</div>
|
||||
<div class="switch-desc">사용자 작업용 API</div>
|
||||
</div>
|
||||
<label class="mui-switch">
|
||||
<input type="checkbox" class="api-toggle" data-api="api11" checked>
|
||||
<span class="mui-slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="api-switch">
|
||||
<div>
|
||||
<div class="switch-title">TCR RQD 시험정보</div>
|
||||
<div class="switch-desc">사용자 작업용 API</div>
|
||||
</div>
|
||||
<label class="mui-switch">
|
||||
<input type="checkbox" class="api-toggle" data-api="api12" checked>
|
||||
<span class="mui-slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="api-switch">
|
||||
<div>
|
||||
<div class="switch-title">DSF 시험정보</div>
|
||||
<div class="switch-desc">사용자 작업용 API</div>
|
||||
</div>
|
||||
<label class="mui-switch">
|
||||
<input type="checkbox" class="api-toggle" data-api="api13" checked>
|
||||
<span class="mui-slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="api-switch">
|
||||
<div>
|
||||
<div class="switch-title">RMR정보</div>
|
||||
<div class="switch-desc">사용자 작업용 API</div>
|
||||
</div>
|
||||
<label class="mui-switch">
|
||||
<input type="checkbox" class="api-toggle" data-api="api14" checked>
|
||||
<span class="mui-slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="api-switch">
|
||||
<div>
|
||||
<div class="switch-title">Q시험정보</div>
|
||||
<div class="switch-desc">사용자 작업용 API</div>
|
||||
</div>
|
||||
<label class="mui-switch">
|
||||
<input type="checkbox" class="api-toggle" data-api="api15" checked>
|
||||
<span class="mui-slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 로그 테이블 -->
|
||||
<div class="table-container">
|
||||
<h3>API 호출 로그</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>API</th>
|
||||
<th>요청방식</th>
|
||||
<th>요청파라미터</th>
|
||||
<th>응답상태</th>
|
||||
<th>처리시간(ms)</th>
|
||||
<th>응답결과</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="apiLogBody">
|
||||
<tr>
|
||||
<td>/API_CHA_085/request</td>
|
||||
<td>POST</td>
|
||||
<td>subCode=deowtj&prvcCode=j43o45k</td>
|
||||
<td>200 OK</td>
|
||||
<td>124</td>
|
||||
<td><span class="status-icon success">✔</span> 성공</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>/API_BH_020/dc332</td>
|
||||
<td>GET</td>
|
||||
<td>user=beta43</td>
|
||||
<td>500 INTERNAL ERROR</td>
|
||||
<td>980</td>
|
||||
<td><span class="status-icon error">⚠️</span> 오류</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>/API_BH_020/dc332</td>
|
||||
<td>GET</td>
|
||||
<td>user=beta43</td>
|
||||
<td>500 INTERNAL ERROR</td>
|
||||
<td>980</td>
|
||||
<td><span class="status-icon delay">🕓</span> 지연</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>/API_BH_020/dc332</td>
|
||||
<td>GET</td>
|
||||
<td>user=beta43</td>
|
||||
<td>403 Unauthorized</td>
|
||||
<td>980</td>
|
||||
<td><span class="status-icon error">❌</span> 실패</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>/API_CHA_085/request</td>
|
||||
<td>POST</td>
|
||||
<td>subCode=deowtj&prvcCode=j43o45k</td>
|
||||
<td>200 OK</td>
|
||||
<td>124</td>
|
||||
<td><span class="status-icon success">✔</span> 성공</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>/API_BH_020/dc332</td>
|
||||
<td>GET</td>
|
||||
<td>user=beta43</td>
|
||||
<td>500 INTERNAL ERROR</td>
|
||||
<td>980</td>
|
||||
<td><span class="status-icon error">⚠️</span> 오류</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>/API_BH_020/dc332</td>
|
||||
<td>GET</td>
|
||||
<td>user=beta43</td>
|
||||
<td>500 INTERNAL ERROR</td>
|
||||
<td>980</td>
|
||||
<td><span class="status-icon delay">🕓</span> 지연</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>/API_BH_020/dc332</td>
|
||||
<td>GET</td>
|
||||
<td>user=beta43</td>
|
||||
<td>403 Unauthorized</td>
|
||||
<td>980</td>
|
||||
<td><span class="status-icon error">❌</span> 실패</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<!-- 페이징 영역 -->
|
||||
<div id="pagination" class="pagination"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// 퍼센트 애니메이션
|
||||
function animateValue(id, start, end, duration) {
|
||||
const obj = document.getElementById(id);
|
||||
let startTime = null;
|
||||
|
||||
function animation(currentTime) {
|
||||
if (!startTime) startTime = currentTime;
|
||||
const progress = Math.min((currentTime - startTime) / duration, 1);
|
||||
obj.innerText = (progress * (end - start) + start).toFixed(1) + "%";
|
||||
if (progress < 1) requestAnimationFrame(animation);
|
||||
}
|
||||
requestAnimationFrame(animation);
|
||||
}
|
||||
|
||||
$(document).ready(function(){
|
||||
animateValue("successRate", 0, 99.5, 1500);
|
||||
animateValue("failRate", 0, 0, 1500);
|
||||
animateValue("delayRate", 0, 0.5, 1500);
|
||||
animateValue("errorRate", 0, 0, 1500);
|
||||
});
|
||||
|
||||
// Chart.js: 일일 접속량
|
||||
const ctx = document.getElementById('trafficChart');
|
||||
new Chart(ctx, {
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: ['01시','02시','03시','04시','05시','06시','07시','08시','09시','10시','11시','12시','13시','14시','15시','16시','17시','18시','19시','20시','21시','22시','23시','24시'],
|
||||
datasets: [{
|
||||
data: [0,10,0,4,54,6,8,1,2,4,354,5,44,120,150,180,130,210,190,50, 0, 10, 0, 0],
|
||||
borderColor: '#4285f4',
|
||||
tension: 0.4,
|
||||
fill: true,
|
||||
backgroundColor: 'rgba(66,133,244,0.1)'
|
||||
}]
|
||||
},
|
||||
options: { plugins: { legend: { display: false } } }
|
||||
});
|
||||
|
||||
// 일괄 On/Off
|
||||
$("#globalSwitch").on("change", function() {
|
||||
const enabled = $(this).is(":checked");
|
||||
$(".api-toggle").prop("checked", enabled).trigger("change");
|
||||
});
|
||||
|
||||
// 개별 토글
|
||||
$(".api-toggle").on("change", function() {
|
||||
const apiName = $(this).data("api");
|
||||
const enabled = $(this).is(":checked");
|
||||
|
||||
$.ajax({
|
||||
url: "/api/control",
|
||||
method: "POST",
|
||||
data: { api: apiName, status: enabled },
|
||||
success: () => console.log(`API ${apiName} → ${enabled ? '활성' : '비활성'}`),
|
||||
// error: () => return false; /*alert("API 상태 변경 실패")*/
|
||||
});
|
||||
});
|
||||
|
||||
function refreshDashboard() {
|
||||
location.reload();
|
||||
}
|
||||
|
||||
|
||||
// 예시 데이터 (100개 생성)
|
||||
const apiLogs = Array.from({ length: 100 }, (_, i) => ({
|
||||
api: i % 2 === 0 ? "/API_CHA_085/request" : "/API_BH_020/dc332",
|
||||
method: ["GET", "POST", "PUT"][Math.floor(Math.random() * 3)],
|
||||
params: `subCode=test${i}&prvcCode=x${i}`,
|
||||
status: [ "200 OK", "404 NOT FOUND", "500 INTERNAL ERROR" ][Math.floor(Math.random() * 3)],
|
||||
time: Math.floor(Math.random() * 500),
|
||||
result: ["성공", "지연", "실패"][Math.floor(Math.random() * 3)]
|
||||
}));
|
||||
|
||||
const rowsPerPage = 10;
|
||||
let currentPage = 1;
|
||||
|
||||
function renderTable(page) {
|
||||
const tableBody = document.getElementById("apiLogBody");
|
||||
tableBody.innerHTML = "";
|
||||
|
||||
const start = (page - 1) * rowsPerPage;
|
||||
const end = start + rowsPerPage;
|
||||
const pageData = apiLogs.slice(start, end);
|
||||
|
||||
pageData.forEach(row => {
|
||||
const tr = document.createElement("tr");
|
||||
tr.innerHTML += '<td>' + row.api + '</td><td>' + row.method + '</td><td>' + row.params + '</td><td>' + row.status + '</td><td>' + row.time + '</td><td>' + getResultIcon(row.result) + ' ' +row.result + '</td>';
|
||||
tableBody.appendChild(tr);
|
||||
});
|
||||
}
|
||||
|
||||
function renderPagination() {
|
||||
const totalPages = Math.ceil(apiLogs.length / rowsPerPage);
|
||||
const pagination = document.getElementById("pagination");
|
||||
pagination.innerHTML = "";
|
||||
|
||||
for (let i = 1; i <= totalPages; i++) {
|
||||
const btn = document.createElement("button");
|
||||
btn.textContent = i;
|
||||
if (i === currentPage) btn.classList.add("active");
|
||||
btn.addEventListener("click", () => {
|
||||
currentPage = i;
|
||||
renderTable(currentPage);
|
||||
renderPagination();
|
||||
});
|
||||
pagination.appendChild(btn);
|
||||
}
|
||||
}
|
||||
|
||||
function getResultIcon(result) {
|
||||
if (result === "성공")
|
||||
return `<span style="color:#22c55e;">✔</span>`;
|
||||
if (result === "실패")
|
||||
return `<span style="color:#ef4444;">⚠</span>`;
|
||||
if (result === "지연")
|
||||
return `<span style="color:#3b82f6;">⏱</span>`;
|
||||
return "";
|
||||
}
|
||||
|
||||
// 초기 렌더링
|
||||
renderTable(currentPage);
|
||||
renderPagination();
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
<%@ 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="fn" uri = "http://java.sun.com/jsp/jstl/functions" %>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<script src="${pageContext.request.contextPath}/js/admins/common.js"></script>
|
||||
<script>
|
||||
|
||||
window.onload = function() {
|
||||
// 페이지 로딩 후 실행될 코드
|
||||
const activeEle = document.getElementById('${pId}');
|
||||
if( activeEle ) {
|
||||
activeEle.classList.add('active');
|
||||
const menuItemEle = findClosestMenuItem(activeEle, 'menu-item');
|
||||
if( menuItemEle ) {
|
||||
menuItemEle.classList.add('active');
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
//상위 element에서 특정 class를 갖는 element를 검색한다.
|
||||
function findClosestMenuItem(element, className) {
|
||||
let currentElement = element.parentElement; // 현재 element의 부모 element부터 시작
|
||||
|
||||
while (currentElement) {
|
||||
if (currentElement.classList.contains(className)) {
|
||||
return currentElement; // 'menu-item' 클래스를 찾으면 해당 element 반환
|
||||
}
|
||||
currentElement = currentElement.parentElement; // 상위 element로 이동
|
||||
}
|
||||
|
||||
return null; // 'menu-item' 클래스를 가진 element를 찾지 못하면 null 반환
|
||||
}
|
||||
|
||||
|
||||
function onClickSubMenuItem(e) {
|
||||
// 클릭된 요소 가져오기
|
||||
const clickedElement = e.target;
|
||||
|
||||
// data-url 속성 값 가져오기
|
||||
const dataUrl = clickedElement.dataset.url;
|
||||
|
||||
goUrl(dataUrl, '${menuId}');
|
||||
|
||||
}
|
||||
</script>
|
||||
<link rel="stylesheet" HREF="${pageContext.request.contextPath}/css/admins/style.css" type="text/css">
|
||||
<style type="text/css">
|
||||
<!--
|
||||
body
|
||||
{
|
||||
background-image: url(${pageContext.request.contextPath}/images/admins/left_bak.jpg);
|
||||
margin-left:0;
|
||||
margin-top:0;
|
||||
margin-right:0;
|
||||
margin-bottom:0;
|
||||
}
|
||||
img { border:0; }
|
||||
-->
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<table width="244" border="0" cellpadding="0" cellspacing="0" >
|
||||
<!-- <tr height=10><td colspan="3"><img src="/admins/img/left_top_border.gif"></td></tr>
|
||||
<tr height=30><td colspan="3"><img src="/admins/img/user/left_title.gif"></td></tr>-->
|
||||
<tr>
|
||||
<td width="244" height="668" valign="top" background="${pageContext.request.contextPath}/images/admins/left_bak.jpg">
|
||||
<table>
|
||||
<tr>
|
||||
<td><img src="${pageContext.request.contextPath}/images/admins/${menuId}/1_tit_01.gif" width="244" height="62" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="menu-item active">
|
||||
<span style="cursor:hand" onClick="javascript:goUrl('api-request-statistics-index', '${menuId}')"><img src="${pageContext.request.contextPath}/images/renew/arrow-right.png" /> API 통계</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- <tr><td colspan="3"> </td></tr>
|
||||
<tr height=177><td colspan="3"><img src="/admins/img/left_logo.gif"></td></tr> -->
|
||||
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 6.3 KiB |
Loading…
Reference in New Issue