데이터가 없습니다.
); // 게시판 목록 초기값
+
+ 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 (
+
{/* */}
-
+
+
+ - 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/egovframe-template-simple-react-contribution/src/pages/standardCode/StandardCodeList.jsx b/egovframe-template-simple-react-contribution/src/pages/standardCode/list/StandardCodeList.jsx
similarity index 85%
rename from egovframe-template-simple-react-contribution/src/pages/standardCode/StandardCodeList.jsx
rename to egovframe-template-simple-react-contribution/src/pages/standardCode/list/StandardCodeList.jsx
index b80f276..d742d88 100644
--- a/egovframe-template-simple-react-contribution/src/pages/standardCode/StandardCodeList.jsx
+++ b/egovframe-template-simple-react-contribution/src/pages/standardCode/list/StandardCodeList.jsx
@@ -8,13 +8,52 @@ import {AiFillFileMarkdown, AiFillStar} from "react-icons/ai";
function StandardCodeList(props) {
const {listCode} = useParams();
- const [show, setshow] = useState(false);
- const [groupseq, setgroupseq] = useState();
+ const [show, setShow] = useState(false);
+ const [groupSeq, setgroupSeq] = useState();
- function showhandling(e) {
+ console.group("StandardCodeList");
+ console.log("[Start] StandardCodeList ------------------------------");
+ console.log("StandardCodeList [props] : ", props);
+ console.log("listcode----------------------------" + listCode);
+
+ const location = useLocation();
+ console.log("StandardCodeList [location] : ", location);
+
+ const category1Ref = useRef();
+ const category2Ref = useRef();
+ const category3Ref = useRef();
+ const wrdRef = useRef();
+
+ // eslint-disable-next-line no-unused-vars
+ const [searchCondition, setSearchCondition] = useState(location.state?.searchCondition || {
+ pageIndex: 1,
+ tab: listCode?.substring(0, 2),
+ category1: listCode?.substring(2, 4),
+ category2: listCode?.substring(4, 6),
+ searchWrd: ''
+ });// 기존 조회에서 접근 했을 시 || 신규로 접근 했을 시
+ const [masterBoard, setMasterBoard] = useState({});
+
+ /* 검색기능 추가 변수*/
+ const [listData, setlistData] = useState([]);
+ const [filterData, setFilterData] = useState('');
+ const [category1List, setCategory1List] = useState([]);
+ const [category2List, setCategory2List] = useState([]);
+ const [category3List, setCategory3List] = useState([]);
+ const [resultCnt, setResultCnt] = useState(0);
+
+ /* 탭 */
+ const [activeTab, setActiveTab] = useState(10);
+ const [subTabsVisible, setSubTabsVisible] = useState(false);
+
+ function close() {
+ setShow(false);
+ }
+
+ function showHandling(e) {
const param = e.currentTarget.dataset;
- const groupseq = param.groupseq;
- console.log(groupseq);
+ const groupSeq = param.groupSeq;
+ console.log(groupSeq);
EgovNet.requestFetch(
'/standardCode/codeListModal.do',
{
@@ -23,7 +62,7 @@ function StandardCodeList(props) {
'Content-type': 'application/json'
},
body: JSON.stringify(
- groupseq
+ groupSeq
)
}, (resp) => {
console.log(resp + "------------------------resp")
@@ -50,52 +89,14 @@ function StandardCodeList(props) {
)
}
- setgroupseq(
);
+ setgroupSeq();
}
)
- setshow(true);
+ setShow(true);
}
- function close() {
- setshow(false);
- }
-
- console.group("StandardCodeList");
- console.log("[Start] StandardCodeList ------------------------------");
- console.log("StandardCodeList [props] : ", props);
- console.log("listcode----------------------------" + listCode);
-
- const location = useLocation();
- console.log("StandardCodeList [location] : ", location);
-
- const category1Ref = useRef();
- const category2Ref = useRef();
- const category3Ref = useRef();
- const wrdRef = useRef();
-
- // eslint-disable-next-line no-unused-vars
- const [searchCondition, setSearchCondition] = useState(location.state?.searchCondition || {
- pageIndex: 1,
- tab: listCode.substring(0, 2),
- category1: listCode.substring(2, 4),
- category2: listCode.substring(4, 6),
- searchWrd: ''
- });// 기존 조회에서 접근 했을 시 || 신규로 접근 했을 시
- const [masterBoard, setMasterBoard] = useState({});
-
- /* 검색기능 추가 변수*/
- const [listdata, setlistdata] = useState([]);
- const [filterData, setfilterData] = useState('');
- const [category1List, setCategory1List] = useState([]);
- const [category2List, setCategory2List] = useState([]);
- const [category3List, setCategory3List] = useState([]);
- const [resultCnt, setResultCnt] = useState(0);
-
- /* 탭 */
- const [activeTab, setActiveTab] = useState(10);
- const [subTabsVisible, setSubTabsVisible] = useState(false);
-
+
const handleTabClick = (tabName) => {
setActiveTab(tabName);
@@ -135,7 +136,7 @@ function StandardCodeList(props) {
(resp) => {
setMasterBoard(resp.result.tnDocumentInfo);
/*검색을 위한 리스트 state에 저장*/
- setlistdata(resp.result.resultList);
+ setlistData(resp.result.resultList);
setCategory1List(resp.result.category1List);
setCategory2List(resp.result.category2List);
setCategory3List(resp.result.category3List);
@@ -159,49 +160,31 @@ function StandardCodeList(props) {
return (
- {/* */}
- Home
- 건설기준코드
- - {masterBoard && masterBoard.bbsNm}
+ - 건설기준코드 검색
- {/* */}
-
- {/* */}
-
- {/* */}
-
- {/* */}
-
-
건설기준코드
+ 건설기준코드 검색
-
-
설계기준, 표준시방서 내용을 열람할 수 있습니다.
-
- {/* */}
{/* */}
-
-
-
- handleTabClick(10)}>설계기준
- handleTabClick(20)}>표준시방서
- handleTabClick(40)}>전문시방서
- 통합 다운로드
-
-
-
{subTabsVisible && (
@@ -315,7 +291,7 @@ function StandardCodeList(props) {
{/*검색기능 filterData가 없는경우 모든 데이터 출력*/}
- {listdata.filter(item => {
+ {listData.filter(item => {
if (item.groupNm.includes(filterData)) {
return item
}
@@ -327,7 +303,7 @@ function StandardCodeList(props) {
{item.middleCategory}
{item.kcscCd}
{item.groupNm}
-
+
{item.contentcount > 0 ?
내용보기 : null}
{item.docFileGrpId == null ? null :
}
@@ -343,7 +319,7 @@ function StandardCodeList(props) {
{/* */}
{/* */}
-
+
{/* */}
diff --git a/egovframe-template-simple-react-contribution/src/pages/standardCode/StandardCodeListModal.js b/egovframe-template-simple-react-contribution/src/pages/standardCode/list/StandardCodeListModal.js
similarity index 100%
rename from egovframe-template-simple-react-contribution/src/pages/standardCode/StandardCodeListModal.js
rename to egovframe-template-simple-react-contribution/src/pages/standardCode/list/StandardCodeListModal.js
diff --git a/egovframe-template-simple-react-contribution/src/pages/standardCode/BookmarkModal.js b/egovframe-template-simple-react-contribution/src/pages/standardCode/viewer/BookmarkModal.js
similarity index 98%
rename from egovframe-template-simple-react-contribution/src/pages/standardCode/BookmarkModal.js
rename to egovframe-template-simple-react-contribution/src/pages/standardCode/viewer/BookmarkModal.js
index cb66c8c..38b8add 100644
--- a/egovframe-template-simple-react-contribution/src/pages/standardCode/BookmarkModal.js
+++ b/egovframe-template-simple-react-contribution/src/pages/standardCode/viewer/BookmarkModal.js
@@ -1,6 +1,6 @@
import {React, useCallback, useEffect, useState} from "react";
import Modal from "react-bootstrap/Modal";
-import * as EgovNet from "../../api/egovFetch";
+import * as EgovNet from "../../../api/egovFetch";
import {VwDiv} from "./Vw.style";
import Col from "react-bootstrap/Col";
import Row from "react-bootstrap/Row";
diff --git a/egovframe-template-simple-react-contribution/src/pages/standardCode/Sb.style.js b/egovframe-template-simple-react-contribution/src/pages/standardCode/viewer/Sb.style.js
similarity index 100%
rename from egovframe-template-simple-react-contribution/src/pages/standardCode/Sb.style.js
rename to egovframe-template-simple-react-contribution/src/pages/standardCode/viewer/Sb.style.js
diff --git a/egovframe-template-simple-react-contribution/src/pages/standardCode/SbItem.js b/egovframe-template-simple-react-contribution/src/pages/standardCode/viewer/SbItem.js
similarity index 100%
rename from egovframe-template-simple-react-contribution/src/pages/standardCode/SbItem.js
rename to egovframe-template-simple-react-contribution/src/pages/standardCode/viewer/SbItem.js
diff --git a/egovframe-template-simple-react-contribution/src/pages/standardCode/Vw.style.js b/egovframe-template-simple-react-contribution/src/pages/standardCode/viewer/Vw.style.js
similarity index 100%
rename from egovframe-template-simple-react-contribution/src/pages/standardCode/Vw.style.js
rename to egovframe-template-simple-react-contribution/src/pages/standardCode/viewer/Vw.style.js
diff --git a/egovframe-template-simple-react-contribution/src/pages/standardCode/viewer.js b/egovframe-template-simple-react-contribution/src/pages/standardCode/viewer/viewer.js
similarity index 99%
rename from egovframe-template-simple-react-contribution/src/pages/standardCode/viewer.js
rename to egovframe-template-simple-react-contribution/src/pages/standardCode/viewer/viewer.js
index 312283c..7645660 100644
--- a/egovframe-template-simple-react-contribution/src/pages/standardCode/viewer.js
+++ b/egovframe-template-simple-react-contribution/src/pages/standardCode/viewer/viewer.js
@@ -1,7 +1,7 @@
import React, { useState, useEffect, useCallback } from 'react';
import { useLocation, useParams } from 'react-router-dom';
import SbItem from './SbItem'
-import Loading from '../../components/Loading'
+import Loading from '../../../components/Loading'
import BookmarkModal from './BookmarkModal';
import {SbContainer} from './Sb.style'
import {VwDiv, VwPtag} from './Vw.style'
@@ -10,9 +10,9 @@ import Row from 'react-bootstrap/Row';
import Col from 'react-bootstrap/Col';
import Modal from 'react-bootstrap/Modal';
import * as EgovNet from 'api/egovFetch';
-import {getLocalItem} from "../../utils/storage";
-import CODE from "../../constants/code";
-import {parseJwt} from "../../utils/parseJwt";
+import {getLocalItem} from "../../../utils/storage";
+import CODE from "../../../constants/code";
+import {parseJwt} from "../../../utils/parseJwt";
function CodeViewer(props) {
const [treeLoading, setTreeLoading] = useState(true);
diff --git a/egovframe-template-simple-react-contribution/src/pages/standardCode/viwerComponents.js b/egovframe-template-simple-react-contribution/src/pages/standardCode/viewer/viwerComponents.js
similarity index 99%
rename from egovframe-template-simple-react-contribution/src/pages/standardCode/viwerComponents.js
rename to egovframe-template-simple-react-contribution/src/pages/standardCode/viewer/viwerComponents.js
index df95218..1f986fb 100644
--- a/egovframe-template-simple-react-contribution/src/pages/standardCode/viwerComponents.js
+++ b/egovframe-template-simple-react-contribution/src/pages/standardCode/viewer/viwerComponents.js
@@ -1,4 +1,4 @@
-import * as EgovNet from "../../api/egovFetch";
+import * as EgovNet from "../../../api/egovFetch";
import React, {useEffect, useState} from "react";
import SbItem from "./SbItem";
import {Col, Row} from "react-bootstrap";
diff --git a/egovframe-template-simple-react-contribution/src/routes/index.jsx b/egovframe-template-simple-react-contribution/src/routes/index.jsx
index a087981..e3c8edc 100644
--- a/egovframe-template-simple-react-contribution/src/routes/index.jsx
+++ b/egovframe-template-simple-react-contribution/src/routes/index.jsx
@@ -110,11 +110,11 @@ import AdminLogsFileDownloadStatus from 'pages/admin/logs/FileDownloadStatus';
//건설기준코드
-import CodeViewer from 'pages/standardCode/viewer';
+import CodeViewer from 'pages/standardCode/viewer/viewer';
import * as EgovNet from 'api/egovFetch'; // jwt토큰 위조 검사 때문에 추가
import initPage from 'js/ui';
-import StandardCodeList from "../pages/standardCode/StandardCodeList";
+import StandardCodeList from "../pages/standardCode/list/StandardCodeList";
const RootRoutes = () => {
//useLocation객체를 이용하여 정규표현식을 사용한 /admin/~ 으로 시작하는 경로와 비교에 사용(아래 1줄) */}
@@ -329,6 +329,7 @@ const SecondRoutes = () => {
{/*기준코드리스트*/}
} />
+ } />
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