diff --git a/egovframe-template-simple-react-contribution/src/pages/admin/standards/ApiKeys.jsx b/egovframe-template-simple-react-contribution/src/pages/admin/standards/ApiKeys.jsx
index 7088968..3475d31 100644
--- a/egovframe-template-simple-react-contribution/src/pages/admin/standards/ApiKeys.jsx
+++ b/egovframe-template-simple-react-contribution/src/pages/admin/standards/ApiKeys.jsx
@@ -1,30 +1,180 @@
-import React from 'react';
-import { Link } from 'react-router-dom';
+import React, {useState, useEffect, useCallback, useRef, PureComponent} from 'react';
+import { Link, useLocation } from 'react-router-dom';
+import {BarChart, Bar, Rectangle, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer} from 'recharts';
+
+import Switch from '@mui/material/Switch';
+
+import * as EgovNet from 'api/egovFetch';
import URL from 'constants/url';
import { default as EgovLeftNav } from 'components/leftmenu/EgovLeftNavAdmin';
+import { itemIdxByPage } from 'utils/calc';
+import EgovPaging from 'components/EgovPaging';
+
function ApiKeys(props) {
+ // console.group("EgovAdminPrivacyList");
+ // console.log("[Start] EgovAdminPrivacyList ------------------------------");
+ // console.log("EgovAdminPrivacyList [props] : ", props);
+ const location = useLocation();
+ // console.log("EgovAdminPrivacyList [location] : ", location);
+
+ // eslint-disable-next-line no-unused-vars
+ const [searchCondition, setSearchCondition] = useState(location.state?.searchCondition || { pageIndex: 1, searchCnd: '0', searchWrd: '' });
+ const [paginationInfo, setPaginationInfo] = useState({});
+ const [chartData, setChartData] = useState([]);
+ const [user_id, setuser_id] = useState([]);
+
+ const [listTag, setListTag] = useState([]);
+ // const label = { inputProps: { 'aria-label': '사용여부' } };
+
+ const retrieveList = useCallback((srchCnd) => {
+ // console.groupCollapsed("EgovAdminUsageList.retrieveList()");
+ const retrieveListURL = '/admin/standards/apikey';
+
+ const requestOptions = {
+ method: "POST",
+ headers: {
+ 'Content-type': 'application/json',
+ },
+ body: JSON.stringify(srchCnd)
+ }
+
+ EgovNet.requestFetch(
+ retrieveListURL,
+ requestOptions,
+ (resp) => {
+ setPaginationInfo(resp.result.paginationInfo);
+
+ let mutListTag = [];
+ listTag.push(
데이터가 없습니다.
); // 게시판 목록 초기값
+
+ const resultCnt = parseInt(resp.result.resultCnt);
+ const currentPageNo = resp.result.paginationInfo.pageIndex;
+ const pageSize = resp.result.paginationInfo.rowCnt;
+
+ const startIndex = (currentPageNo - 1) * pageSize;
+ const endIndex = Math.min(startIndex + pageSize, resultCnt);
+
+ // 리스트 항목 구성
+ for (let index = startIndex; index < endIndex; index++) {
+ const listIdx = itemIdxByPage(resultCnt, currentPageNo, 0, index); // pageSize 로 넣으면 listIdx값이 2배씩 줄어서 0으로 수정
+ const item = resp.result.resultList[index];
+
+ mutListTag.push(
+
+
{item.userId}
+
handleApiKeyChart(item)}>{item.apiKey}
+
{item.startDt} ~ {item.endDt}
+
{item.idntyYn === 'Y' ? handleSwitchToggle(item)} /> : handleSwitchToggle(item)} />}
+
+ );
+ }
+ setListTag(mutListTag);
+ },
+ function (resp) {
+ console.log("err response : ", resp);
+ }
+ );
+ // console.groupEnd("EgovAdminPrivacyList.retrieveList()");
+ },[listTag]);
+
+ const CustomTooltip = ({ active, payload, label }) => {
+ if (active && payload && payload.length) {
+ return (
+
+
API 요청 [{user_id}]
+
{`${label} : ${payload[0].value}`}회
+
+ );
+ }
+ return null;
+ };
+
+ const handleSwitchToggle = async (item) => {
+ try {
+ const updateApiEndpoint = '/admin/standards/apiupdate';
+ const requestOptions = {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify(item),
+ };
+
+ const response = await EgovNet.requestFetch(updateApiEndpoint, requestOptions);
+ const data = await response.json();
+
+ if (response.ok) {
+ console.log('Data updated successfully:', data);
+ return { success: true, data };
+ } else {
+ console.error('Failed to update data:', data);
+ return { success: false, error: data };
+ }
+ } catch (error) {
+ console.error('Error during data update:', error);
+ return { success: false, error };
+ }
+ };
+
+ const handleApiKeyChart = (item) => {
+ try {
+ const updateApiEndpoint = '/admin/standards/apiDailyChart';
+ const requestOptions = {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify(item),
+ };
+
+ EgovNet.requestFetch(
+ updateApiEndpoint,
+ requestOptions,
+ (resp) => {
+ let chartDataArray = resp.result.resultList.map((item, index) => ({
+ logdt: item[0], // Assuming logCnt is the x-axis data
+ "API 요청수": item[1], // Assuming menuTitle is the y-axis data
+ }));
+ setChartData(chartDataArray);
+ // item.userId 값 넣기
+ console.log(`User ID: ${item.userId}`);
+ setuser_id(item.userId);
+ },
+ function (resp) {
+ console.log("err response : ", resp);
+ }
+ );
+ } catch (error) {
+ console.error('Error during data update:', error);
+ return { success: false, error };
+ }
+ };
+
+ useEffect(() => {
+ retrieveList(searchCondition);
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, []);
+
+ // console.log("------------------------------EgovAdminPrivacyList [End]");
+ // console.groupEnd("EgovAdminPrivacyList");
- const Location = React.memo(function Location() {
- return (
-
-
- - Home
- - 건설기준 관리
- - API KEY 관리
-
-
- )
- });
return (
{/* */}
-
+
+
+ - Home
+ - 사이트관리
+ - 건설기준 관리
+ - API KEY 관리
+
+
{/* */}
@@ -35,13 +185,51 @@ function ApiKeys(props) {
{/* */}
-
건설기준 관리
+ API KEY 관리
-
API KEY 관리
+ {/* */}
+
+
+ 사용자
+ 발급키
+ 승인기간
+ 승인여부
+
+
+ {listTag}
+
+
+ {/* */}
- 여기에 구현해주세요.
- {/* */}
+
+ {/* */}
+ {
+ retrieveList({ ...searchCondition, pageIndex: passedPage }) //, searchCnd: cndRef.current.value, searchWrd: wrdRef.current.value
+ }} />
+ {/* */}
+
+
+
+
+
+
+
+ } />
+
+ } />
+
+
+
+ {/* */}
diff --git a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/standards/AdminStandardsController.java b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/standards/AdminStandardsController.java
new file mode 100644
index 0000000..d0dc80c
--- /dev/null
+++ b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/standards/AdminStandardsController.java
@@ -0,0 +1,108 @@
+package com.dbnt.kcscbackend.admin.standards;
+
+import com.dbnt.kcscbackend.admin.standards.entity.TnApiKey;
+import com.dbnt.kcscbackend.admin.standards.service.AdminApiService;
+import com.dbnt.kcscbackend.auth.entity.LoginVO;
+import com.dbnt.kcscbackend.config.common.BaseController;
+import com.dbnt.kcscbackend.config.common.ResponseCode;
+import com.dbnt.kcscbackend.config.common.ResultVO;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import lombok.RequiredArgsConstructor;
+import org.springframework.http.MediaType;
+import org.springframework.security.core.annotation.AuthenticationPrincipal;
+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.RestController;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/admin/standards")
+@Tag(name="AdminStandardsController", description = "사이트관리 건설기준관리 메뉴 컨트롤러")
+public class AdminStandardsController extends BaseController {
+
+ private final AdminApiService adminApiService;
+
+ @Operation(
+ summary = "건설기준관리 - API 관리",
+ description = "API 관리",
+ tags = {"AdminStandardsController"}
+ )
+ @ApiResponses(value = {
+ @ApiResponse(responseCode = "200", description = "조회 성공"),
+ @ApiResponse(responseCode = "403", description = "인가된 사용자가 아님")
+ })
+ @RequestMapping(method = RequestMethod.POST, value = "/apikey", consumes = MediaType.APPLICATION_JSON_VALUE)
+ public ResultVO selectApiList(@RequestBody TnApiKey tnApiKey, @AuthenticationPrincipal LoginVO user)
+ throws Exception {
+
+ ResultVO resultVO = new ResultVO();
+ tnApiKey.setQueryInfo();
+ Map
resultMap = adminApiService.selectApiList();
+ int totCnt = Integer.parseInt((String)resultMap.get("resultCnt"));
+ tnApiKey.setContentCnt(totCnt);
+ tnApiKey.setPaginationInfo();
+ resultMap.put("paginationInfo", tnApiKey);
+
+ resultVO.setResultCode(ResponseCode.SUCCESS.getCode());
+ resultVO.setResultMessage(ResponseCode.SUCCESS.getMessage());
+ resultVO.setResult(resultMap);
+ return resultVO;
+ }
+
+ @Operation(
+ summary = "API key 관리",
+ description = "API key 승인여부 수정",
+ tags = {"AdminStandardsController"}
+ )
+ @ApiResponses(value = {
+ @ApiResponse(responseCode = "200", description = "수정 성공"),
+ @ApiResponse(responseCode = "303", description = "만료된 토큰"),
+ @ApiResponse(responseCode = "403", description = "인가된 사용자가 아님")
+ })
+ @RequestMapping(method = RequestMethod.POST, value = "/apiupdate", consumes = MediaType.APPLICATION_JSON_VALUE)
+ public ResultVO modifyApi(@RequestBody TnApiKey tnApiKey, @AuthenticationPrincipal LoginVO user) throws Exception{
+ ResultVO resultVO = new ResultVO();
+
+ TnApiKey existingApiKey = adminApiService.getApiKeyById(tnApiKey.getUserId());
+ if (existingApiKey != null) {
+ existingApiKey.setIdntyYn(existingApiKey.getIdntyYn().equals("Y") ? "N" : "Y");
+ adminApiService.modifyApi(existingApiKey);
+
+ resultVO.setResultCode(ResponseCode.SUCCESS.getCode());
+ } else {
+ resultVO.setResultCode(ResponseCode.SAVE_ERROR.getCode()); // 존재하지 않는 user_id에 대한 처리
+ }
+ return resultVO;
+ }
+
+ @Operation(
+ summary = "API key Chart",
+ description = "API key 클릭시 차트",
+ tags = {"AdminStandardsController"}
+ )
+ @ApiResponses(value = {
+ @ApiResponse(responseCode = "200", description = "수정 성공"),
+ @ApiResponse(responseCode = "303", description = "만료된 토큰"),
+ @ApiResponse(responseCode = "403", description = "인가된 사용자가 아님")
+ })
+ @RequestMapping(method = RequestMethod.POST, value = "/apiDailyChart", consumes = MediaType.APPLICATION_JSON_VALUE)
+ public ResultVO ApiChart(@RequestBody Map dateRange, @AuthenticationPrincipal LoginVO user) throws Exception{
+ ResultVO resultVO = new ResultVO();
+ Map resultMap = new HashMap<>();
+
+ String UserId = dateRange.get("userId");
+
+ resultMap.put("resultList", adminApiService.selectApiDailyCount(UserId));
+ resultVO.setResultCode(ResponseCode.SUCCESS.getCode());
+ resultVO.setResultMessage(ResponseCode.SUCCESS.getMessage());
+ resultVO.setResult(resultMap);
+ return resultVO;
+ }
+}
diff --git a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/standards/entity/TnApiKey.java b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/standards/entity/TnApiKey.java
new file mode 100644
index 0000000..f565c6f
--- /dev/null
+++ b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/standards/entity/TnApiKey.java
@@ -0,0 +1,41 @@
+package com.dbnt.kcscbackend.admin.standards.entity;
+
+import com.dbnt.kcscbackend.config.common.BoardParams;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+import org.hibernate.annotations.DynamicInsert;
+import org.hibernate.annotations.DynamicUpdate;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import javax.persistence.*;
+import java.time.LocalDate;
+
+@Getter
+@Setter
+@Accessors(chain = true)
+@Entity
+@NoArgsConstructor
+@DynamicInsert
+@DynamicUpdate
+@Table(name = "tn_api_key")
+public class TnApiKey extends BoardParams {
+ @Id
+ @Column(name = "user_id")
+ private String userId;
+
+ @Column(name = "api_key")
+ private String apiKey;
+
+ @Column(name = "idnty_yn")
+ private String idntyYn;
+
+ @Column(name = "start_dt")
+ @DateTimeFormat(pattern = "yyyy-MM-dd")
+ private LocalDate startDt;
+
+ @Column(name = "end_dt")
+ @DateTimeFormat(pattern = "yyyy-MM-dd")
+ private LocalDate endDt;
+}
diff --git a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/standards/repository/ApiKeyRepository.java b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/standards/repository/ApiKeyRepository.java
new file mode 100644
index 0000000..cbfcb18
--- /dev/null
+++ b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/standards/repository/ApiKeyRepository.java
@@ -0,0 +1,19 @@
+package com.dbnt.kcscbackend.admin.standards.repository;
+
+import com.dbnt.kcscbackend.admin.standards.entity.TnApiKey;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
+
+import java.util.List;
+
+public interface ApiKeyRepository extends JpaRepository {
+ List findAllByOrderByEndDtDesc();
+
+ @Query(value = "SELECT TO_CHAR(access_dt, 'YYYY-MM-DD') as log_dt, count(1) as log_cnt "
+ + "FROM th_api_log "
+ + "WHERE access_id = :UserId "
+ + "GROUP BY TO_CHAR(access_dt, 'YYYY-MM-DD') "
+ + "ORDER BY log_dt asc", nativeQuery = true)
+ List