Compare commits

..

No commits in common. "432cad27ab1e31df6dde53701aa88cb30ec85f96" and "98d2da2e2117a528ec1fe89254b4a2f9fdeeca98" have entirely different histories.

106 changed files with 2041 additions and 5747 deletions

File diff suppressed because it is too large Load Diff

View File

@ -3,8 +3,6 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"@ant-design/colors": "^6.0.0",
"@ant-design/icons": "^4.7.0",
"@emotion/react": "^11.11.3",
"@emotion/styled": "^11.11.0",
"@material-ui/core": "^4.12.4",
@ -12,25 +10,19 @@
"@mui/icons-material": "^5.15.6",
"@mui/material": "^5.14.19",
"@mui/styles": "^5.15.3",
"apexcharts": "^3.45.2",
"bootstrap": "^5.3.2",
"date-fns": "^3.2.0",
"prop-types": "^15.8.1",
"qs": "^6.11.0",
"react": "^18.2.0",
"react-apexcharts": "^1.4.0",
"react-bootstrap": "^2.9.0",
"react-copy-to-clipboard": "^5.1.0",
"react-csv": "^2.2.2",
"react-datepicker": "^4.8.0",
"react-dom": "^18.2.0",
"react-element-to-jsx-string": "^15.0.0",
"react-icons": "^4.11.0",
"react-loader-spinner": "^5.4.5",
"react-quill": "^2.0.0",
"react-router-dom": "^6.4.0",
"react-scripts": "5.0.1",
"react-syntax-highlighter": "^15.5.0",
"recharts": "^2.10.3",
"styled-components": "^6.0.9",
"web-vitals": "^2.1.4"

View File

@ -1,6 +1,4 @@
import RootRoutes from './routes';
import ThemeCustomization from 'themes';
import ScrollTop from 'components/ScrollTop';
import React from 'react';
import 'bootstrap/dist/css/bootstrap.min.css';
@ -14,11 +12,9 @@ import './css/Custom/customMain.css'
function App() {
return (
<ThemeCustomization>
<ScrollTop>
<div className="wrap">
<RootRoutes />
</ScrollTop>
</ThemeCustomization>
</div>
)
}

View File

@ -29,11 +29,7 @@ export function requestFetch(url, requestOptions, handler, errorHandler) {
const accessToken = getLocalItem('accessToken');
const sessionUser = parseJwt(accessToken);
const sessionUserId = sessionUser?.id || null;
if(accessToken && new Date(sessionUser.exp*1000) < new Date()){
//만료된 토큰 재발급 절차 진행.
accessTokenRefresh(url, requestOptions, handler, errorHandler);
}else{
const refreshToken = getLocalItem('refreshToken');
if(sessionUserId != null){
if( !requestOptions['headers'] ) requestOptions['headers']={}
if( !requestOptions['headers']['Authorization'] ) requestOptions['headers']['Authorization']=null;
@ -52,13 +48,15 @@ export function requestFetch(url, requestOptions, handler, errorHandler) {
fetch(SERVER_URL + url, requestOptions)
.then(response => {// response Stream. Not completion object
//console.log("requestFetch [Response Stream] ", response);
return response.json();
})
.then((resp) => {
if (Number(resp.resultCode) === Number(CODE.RCV_ERROR_AUTH)) {
alert("로그인이 해제되었습니다.")
window.location.href = "/login"
}else{
//accessToken 갱신 요청
accessTokenRefresh(url, requestOptions, handler, errorHandler);
return resp;
} else {
return resp;
}
})
@ -89,7 +87,7 @@ export function requestFetch(url, requestOptions, handler, errorHandler) {
console.log("requestFetch finally end");
console.groupEnd("requestFetch");
});
}
}
function accessTokenRefresh(url, requestOptions, handler, errorHandler){

View File

@ -115,7 +115,7 @@ function EgovHeader({ loginUser, onChangeLogin }) {
{/* <!-- All menu : web --> */}
<div className={`all_menu WEB ${menuDiv?"open":"closed"}`}>
<h2 className="blind">전체메뉴</h2>
<div className="inner row">
<div className="inner">
<div className="col">
<h3>건설기준코드</h3>
<ul>

View File

@ -1,16 +1,10 @@
import React, {useEffect, useState} from 'react';
import React from 'react';
import {Blocks} from "react-loader-spinner";
import {LoadingDiv} from "./Loading.style";
function Loading ({loadingState}) {
const [visible, setVisible] = useState(loadingState);
useEffect(() => {
setVisible(loadingState)
}, [loadingState]);
function Loading () {
return (
<LoadingDiv $visible={visible}>
<LoadingDiv>
<Blocks
height="150"
width="150"

View File

@ -4,5 +4,4 @@ export const LoadingDiv = styled.div`
min-height: 83vh;
padding-top: calc(40vh - 150px);
padding-left: calc(54vw - 150px);
display: ${props=>props.$visible?"block":"none"};
`

View File

@ -1,26 +0,0 @@
import PropTypes from 'prop-types';
import { useEffect } from 'react';
import { useLocation } from 'react-router-dom';
// ==============================|| NAVIGATION - SCROLL TO TOP ||============================== //
const ScrollTop = ({ children }) => {
const location = useLocation();
const { pathname } = location;
useEffect(() => {
window.scrollTo({
top: 0,
left: 0,
behavior: 'smooth'
});
}, [pathname]);
return children || null;
};
ScrollTop.propTypes = {
children: PropTypes.node
};
export default ScrollTop;

View File

@ -1,70 +0,0 @@
import PropTypes from 'prop-types';
// material-ui
import { Box, Chip, Grid, Stack, Typography } from '@mui/material';
// project import
import MainCard from 'components/cards/MainCard';
// assets
import { RiseOutlined, FallOutlined } from '@ant-design/icons';
// ==============================|| STATISTICS - ECOMMERCE CARD ||============================== //
const AnalyticEcommerce = ({ color, title, count, percentage, isLoss, extra }) => (
<MainCard contentSX={{ p: 2.25 }}>
<Stack spacing={0.5}>
<Typography variant="h6" color="textSecondary">
{title}
</Typography>
<Grid container alignItems="center">
<Grid item>
<Typography variant="h4" color="inherit">
{count}
</Typography>
</Grid>
{percentage && (
<Grid item>
<Chip
variant="combined"
color={color}
icon={
<>
{!isLoss && <RiseOutlined style={{ fontSize: '0.75rem', color: 'inherit' }} />}
{isLoss && <FallOutlined style={{ fontSize: '0.75rem', color: 'inherit' }} />}
</>
}
label={`${percentage}%`}
sx={{ ml: 1.25, pl: 1 }}
size="small"
/>
</Grid>
)}
</Grid>
</Stack>
<Box sx={{ pt: 2.25 }}>
<Typography variant="caption" color="textSecondary">
지난달{' '}
<Typography component="span" variant="caption" sx={{ color: `${color || 'primary'}.main` }}>
{extra}
</Typography>{' '}
건이 기록되었습니다.
</Typography>
</Box>
</MainCard>
);
AnalyticEcommerce.propTypes = {
color: PropTypes.string,
title: PropTypes.string,
count: PropTypes.string,
percentage: PropTypes.number,
isLoss: PropTypes.bool,
extra: PropTypes.oneOfType([PropTypes.node, PropTypes.string])
};
AnalyticEcommerce.defaultProps = {
color: 'primary'
};
export default AnalyticEcommerce;

View File

@ -1,103 +0,0 @@
import PropTypes from 'prop-types';
import { forwardRef } from 'react';
// material-ui
import { useTheme } from '@mui/material/styles';
import { Card, CardContent, CardHeader, Divider, Typography } from '@mui/material';
// project import
import Highlighter from '../third-party/Highlighter';
// header style
const headerSX = {
p: 2.5,
'& .MuiCardHeader-action': { m: '0px auto', alignSelf: 'center' }
};
// ==============================|| CUSTOM - MAIN CARD ||============================== //
const MainCard = forwardRef(
(
{
border = true,
boxShadow,
children,
content = true,
contentSX = {},
darkTitle,
elevation,
secondary,
shadow,
sx = {},
title,
codeHighlight,
...others
},
ref
) => {
const theme = useTheme();
boxShadow = theme.palette.mode === 'dark' ? boxShadow || true : boxShadow;
return (
<Card
elevation={elevation || 0}
ref={ref}
{...others}
sx={{
border: border ? '1px solid' : 'none',
borderRadius: 2,
borderColor: theme.palette.mode === 'dark' ? theme.palette.divider : theme.palette.grey.A800,
boxShadow: boxShadow && (!border || theme.palette.mode === 'dark') ? shadow || theme.customShadows.z1 : 'inherit',
':hover': {
boxShadow: boxShadow ? shadow || theme.customShadows.z1 : 'inherit'
},
'& pre': {
m: 0,
p: '16px !important',
fontFamily: theme.typography.fontFamily,
fontSize: '0.75rem'
},
...sx
}}
>
{/* card header and action */}
{!darkTitle && title && (
<CardHeader sx={headerSX} titleTypographyProps={{ variant: 'subtitle1' }} title={title} action={secondary} />
)}
{darkTitle && title && <CardHeader sx={headerSX} title={<Typography variant="h3">{title}</Typography>} action={secondary} />}
{/* card content */}
{content && <CardContent sx={contentSX}>{children}</CardContent>}
{!content && children}
{/* card footer - clipboard & highlighter */}
{codeHighlight && (
<>
<Divider sx={{ borderStyle: 'dashed' }} />
<Highlighter codeHighlight={codeHighlight} main>
{children}
</Highlighter>
</>
)}
</Card>
);
}
);
MainCard.propTypes = {
border: PropTypes.bool,
boxShadow: PropTypes.bool,
contentSX: PropTypes.object,
darkTitle: PropTypes.bool,
divider: PropTypes.bool,
elevation: PropTypes.number,
secondary: PropTypes.node,
shadow: PropTypes.string,
sx: PropTypes.object,
title: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
codeHighlight: PropTypes.bool,
content: PropTypes.bool,
children: PropTypes.node
};
export default MainCard;

View File

@ -18,16 +18,15 @@ import FormDialog from '../../components/alert/FormDialog';
function generate(items, element, onClickListner,nameKey,
idKey) {
function generate(items, element, onClickListner) {
return items.map((value, index) =>
React.cloneElement(element, {
key: value[nameKey],
key: value,
},
<Card fullWidth sx={{ '&': { boxShadow: 'none' } }}>
<CardActionArea fullWidth sx={{ px: 1 }}>
<ListItemText
primary={value[nameKey]}
primary={value}
key={index}
data-index={index}
onClick={(e) => {onClickListner(e, index);}}
@ -100,9 +99,7 @@ function ListCreateUpdateDelete(props) {
}
>
</ListItem>,
onClickItem,
props.nameKey,
props.idKey
onClickItem
)}
</List>
</Demo>

View File

@ -28,10 +28,12 @@ function ListLabelInputs(props) {
useEffect(function () {
setItems(props.items);
console.log( props.items );
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [props]);
useEffect(function () {
console.log( items );
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [items]);

View File

@ -1,65 +0,0 @@
import PropTypes from 'prop-types';
import { useState } from 'react';
// material-ui
import { Box, CardActions, Collapse, Divider, IconButton, Tooltip } from '@mui/material';
// third-party
import { CopyToClipboard } from 'react-copy-to-clipboard';
import reactElementToJSXString from 'react-element-to-jsx-string';
// project import
import SyntaxHighlight from 'utils/SyntaxHighlight';
// assets
import { CodeOutlined, CopyOutlined } from '@ant-design/icons';
// ==============================|| CLIPBOARD & HIGHLIGHTER ||============================== //
const Highlighter = ({ children }) => {
const [highlight, setHighlight] = useState(false);
return (
<Box sx={{ position: 'relative' }}>
<CardActions sx={{ justifyContent: 'flex-end', p: 1, mb: highlight ? 1 : 0 }}>
<Box sx={{ display: 'flex', position: 'inherit', right: 0, top: 6 }}>
<CopyToClipboard text={reactElementToJSXString(children, { showFunctions: true, maxInlineAttributesLineLength: 100 })}>
<Tooltip title="Copy the source" placement="top-end">
<IconButton color="secondary" size="small" sx={{ fontSize: '0.875rem' }}>
<CopyOutlined />
</IconButton>
</Tooltip>
</CopyToClipboard>
<Divider orientation="vertical" variant="middle" flexItem sx={{ mx: 1 }} />
<Tooltip title="Show the source" placement="top-end">
<IconButton
sx={{ fontSize: '0.875rem' }}
size="small"
color={highlight ? 'primary' : 'secondary'}
onClick={() => setHighlight(!highlight)}
>
<CodeOutlined />
</IconButton>
</Tooltip>
</Box>
</CardActions>
<Collapse in={highlight}>
{highlight && (
<SyntaxHighlight>
{reactElementToJSXString(children, {
showFunctions: true,
showDefaultProps: false,
maxInlineAttributesLineLength: 100
})}
</SyntaxHighlight>
)}
</Collapse>
</Box>
);
};
Highlighter.propTypes = {
children: PropTypes.node
};
export default Highlighter;

View File

@ -46,27 +46,14 @@
.code_list .result .List_Codes >div:nth-child(7){
font-size: 14px;
}
.standard_code_modal .head >span:nth-child(1),.standard_code_modal .result .list_item >div:nth-child(1){width: 12%;}
.standard_code_modal .head >span:nth-child(2),.standard_code_modal .result .list_item >div:nth-child(2){width: 15%;}
.standard_code_modal .head >span:nth-child(3),.standard_code_modal .result .list_item >div:nth-child(3){width: 10%;}
.standard_code_result{
max-height: 520px;
overflow-y: auto;
}
.download_list{
max-height: 550px;
overflow-y: auto;
}
.codeListContent{
padding: 10px 0;
width: 100%;
.codelistcontent{
padding: 0 0;
width: 80%;
}
.StandardCodeList{
max-width: 100%;
}
.listTableDiv{
.listtablediv{
padding: 0 !important;
}
.vieweratag{

View File

@ -50,7 +50,7 @@ body {min-width: 1400px;}
.c_wrap .layout {display: table; width: 100%; table-layout: fixed; padding-bottom: 20px;} /* added by lim padding-bottom: 20px; */
/* sub navigation */
.c_wrap .layout .nav:not(.tabs) {display: table-cell; width: 220px; vertical-align: top;} /* changed by lim width: 260px; */
.c_wrap .layout .nav {display: table-cell; width: 220px; vertical-align: top;} /* changed by lim width: 260px; */
.c_wrap .layout .nav .inner {border: 1px solid #dde2e5; border-radius: 10px;}
.nav_title{padding: 35px 30px 26px 30px;} /* changed by lim border-bottom: 4px solid #dde2e5; */
.c_wrap .layout .nav h2 {color: #222; font-size: 24px;}

View File

@ -1,199 +0,0 @@
import React, { useState, useEffect, useCallback, useRef } from 'react';
import { Link, useLocation } from 'react-router-dom';
import * as EgovNet from 'api/egovFetch';
import URL from 'constants/url';
import { default as EgovLeftNav } from 'components/leftmenu/EgovLeftNavAdmin';
import EgovPaging from 'components/EgovPaging';
import { itemIdxByPage } from 'utils/calc';
function EgovAdminBoardList(props) {
console.group("EgovAdminBoardList");
console.log("[Start] EgovAdminBoardList ------------------------------");
console.log("EgovAdminBoardList [props] : ", props);
const location = useLocation();
console.log("EgovAdminBoardList [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 cndRef = useRef();
const wrdRef = useRef();
const [listTag, setListTag] = useState([]);
const retrieveList = useCallback((srchCnd) => {
console.groupCollapsed("EgovAdminBoardList.retrieveList()");
const retrieveListURL = '/cop/bbs/selectBBSMasterInfsAPI.do';
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(<p className="no_data" key="0">검색된 결과가 없습니다.</p>); //
const resultCnt = parseInt(resp.result.resultCnt);
const currentPageNo = resp.result.paginationInfo.currentPageNo;
const pageSize = resp.result.paginationInfo.pageSize;
//
resp.result.resultList.forEach(function (item, index) {
if (index === 0) mutListTag = []; //
const listIdx = itemIdxByPage(resultCnt , currentPageNo, pageSize, index);
mutListTag.push(
<Link
to={{pathname: URL.ADMIN_BOARD_MODIFY}}
state={{
bbsId: item.bbsId,
searchCondition: searchCondition
}}
key={listIdx}
className="list_item">
<div>{listIdx}</div>
<div>{item.bbsNm}</div>
<div>{item.bbsTyCodeNm}</div>
<div>{item.bbsAttrbCodeNm}</div>
<div>{item.frstRegisterPnttm}</div>
<div>{item.useAt === "Y" ? "사용" : "사용안함"}</div>
</Link>
);
});
setListTag(mutListTag);
},
function (resp) {
console.log("err response : ", resp);
}
);
console.groupEnd("EgovAdminBoardList.retrieveList()");
},[listTag, searchCondition]);
useEffect(() => {
retrieveList(searchCondition);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
console.log("------------------------------EgovAdminBoardList [End]");
console.groupEnd("EgovAdminBoardList");
return (
<div className="container">
<div className="c_wrap">
{/* <!-- Location --> */}
<div className="location">
<ul>
<li><Link to={URL.MAIN} className="home">Home</Link></li>
<li><Link to={URL.ADMIN}>사이트관리</Link></li>
<li>게시판생성 관리</li>
</ul>
</div>
{/* <!--// Location --> */}
<div className="layout">
{/* <!-- Navigation --> */}
<EgovLeftNav></EgovLeftNav>
{/* <!--// Navigation --> */}
<div className="contents BOARD_CREATE_LIST" id="contents">
{/* <!-- 본문 --> */}
<div className="top_tit">
<h1 className="tit_1">사이트관리</h1>
</div>
<h2 className="tit_2">게시판생성 관리</h2>
{/* <!-- 검색조건 --> */}
<div className="condition">
<ul>
<li className="third_1 L">
<span className="lb">검색유형선택</span>
<label className="f_select" htmlFor="searchCnd">
<select id="searchCnd" name="searchCnd" title="검색유형선택" ref={cndRef}
onChange={e => {
cndRef.current.value = e.target.value;
}}
>
<option value="0">게시판명</option>
<option value="1">게시판유형</option>
</select>
</label>
</li>
<li className="third_2 R">
<span className="lb">검색어</span>
<span className="f_search w_400">
<input type="text" name="" defaultValue={searchCondition && searchCondition.searchWrd} placeholder="" ref={wrdRef}
onChange={e => {
wrdRef.current.value = e.target.value;
}}
/>
<button type="button"
onClick={() => {
retrieveList({ ...searchCondition, pageIndex: 1, searchCnd: cndRef.current.value, searchWrd: wrdRef.current.value });
}}>조회</button>
</span>
</li>
<li>
<Link to={URL.ADMIN_BOARD_CREATE} className="btn btn_blue_h46 pd35">등록</Link>
</li>
</ul>
</div>
{/* <!--// 검색조건 --> */}
{/* <!-- 게시판목록 --> */}
<div className="board_list BRD006">
<div className="head">
<span>번호</span>
<span>게시판명</span>
<span>게시판유형</span>
<span>게시판속성</span>
<span>생성일</span>
<span>사용여부</span>
</div>
<div className="result">
{listTag}
</div>
</div>
{/* <!--// 게시판목록 --> */}
<div className="board_bot">
{/* <!-- Paging --> */}
<EgovPaging pagination={paginationInfo} moveToPage={passedPage => {
retrieveList({ ...searchCondition, pageIndex: passedPage, searchCnd: cndRef.current.value, searchWrd: wrdRef.current.value })
}} />
{/* <!--/ Paging --> */}
</div>
{/* <!--// 본문 --> */}
</div>
</div>
</div>
</div>
);
}
export default EgovAdminBoardList;

View File

@ -1,17 +1,15 @@
import React, {useState, useEffect, useRef} from 'react';
import {Link, useNavigate, useLocation, useParams} from 'react-router-dom';
import Modal from "react-bootstrap/Modal";
import React, { useState, useEffect, useRef } from 'react';
import { Link, useNavigate, useLocation } from 'react-router-dom';
import * as EgovNet from 'api/egovFetch';
import URL from 'constants/url';
import CODE from 'constants/code';
import {default as EgovLeftNav} from 'components/leftmenu/EgovLeftNavAdmin';
import { default as EgovLeftNav } from 'components/leftmenu/EgovLeftNavAdmin';
import EgovRadioButtonGroup from 'components/EgovRadioButtonGroup';
import {Form} from "react-bootstrap";
function EgovAdminBoardEdit({props, reloadFunction}) {
function EgovAdminBoardEdit(props) {
console.group("EgovAdminBoardEdit");
console.log("[Start] EgovAdminBoardEdit ------------------------------");
console.log("EgovAdminBoardEdit [props] : ", props);
@ -22,141 +20,411 @@ function EgovAdminBoardEdit({props, reloadFunction}) {
console.log("EgovAdminBoardEdit [location] : ", location);
let item = null;
item = props;
console.log("@@@ item : " + JSON.stringify(item));
const replyPosblAtRadioGroup = [{ value: "Y", label: "가능" }, { value: "N", label: "불가능" }];
const fileAtchPosblAtRadioGroup = [{ value: "Y", label: "가능" }, { value: "N", label: "불가능" }];
const bbsTyCodeOptions = [{ value: "", label: "선택" }, { value: "BBST01", label: "일반게시판" }, { value: "BBST03", label: "공지게시판" }];
const bbsAttrbCodeOptions = [{ value: "", label: "선택" }, { value: "BBSA02", label: "갤러리" }, { value: "BBSA03", label: "일반게시판" }];
const posblAtchFileNumberOptions = [{ value: 0, label: "선택하세요" }, { value: 1, label: "1개" }, { value: 2, label: "2개" }, { value: 3, label: "3개" }];
const bbsId = location.state?.bbsId || "";
const [modeInfo, setModeInfo] = useState(item != null ? {mode: props.mode} : {mode: CODE.MODE_CREATE});
const [modeInfo, setModeInfo] = useState({ mode: props.mode });
const [boardDetail, setBoardDetail] = useState({});
console.log("@@@ mode : " + modeInfo.mode);
const initMode = () => {
switch (props.mode) {
case CODE.MODE_CREATE:
setModeInfo({
...modeInfo,
modeTitle: "등록",
editURL: '/cop/bbs/insertBBSMasterInfAPI.do'
});
break;
case CODE.MODE_MODIFY:
setModeInfo({
...modeInfo,
modeTitle: "수정",
editURL: `/cop/bbs/updateBBSMasterInfAPI/${bbsId}.do`
});
break;
default:
navigate({pathname: URL.ERROR}, {state: {msg : ""}});
}
retrieveDetail();
}
const retrieveDetail = () => {
if (modeInfo.mode === CODE.MODE_CREATE) {// /
setBoardDetail({
tmplatId: "TMPLAT_BOARD_DEFAULT", //Template
replyPosblAt: "Y", //
fileAtchPosblAt: "Y" //
});
return;
}
const retrieveDetailURL = '/cop/bbs/selectBBSMasterInfAPI.do';
const requestOptions = {
method: "POST",
headers: {
'Content-type': 'application/json',
},
body: JSON.stringify({
bbsId: bbsId
})
}
EgovNet.requestFetch(retrieveDetailURL,
requestOptions,
function (resp) {
//
if (modeInfo.mode === CODE.MODE_MODIFY) {
setBoardDetail(resp.result.boardMasterVO);
}
}
);
}
const formValidator = (formData) => {
if (formData.get('bbsNm') === null || formData.get('bbsNm') === "") {
alert("게시판명은 필수 값입니다.");
return false;
}
if (formData.get('bbsIntrcn') === null || formData.get('bbsIntrcn') === "") {
alert("게시판 소개는 필수 값입니다.");
return false;
}
if (formData.get('bbsTyCode') === null || formData.get('bbsTyCode') === "") {
alert("게시판 유형은 필수 값입니다.");
return false;
}
if (formData.get('bbsAttrbCode') === null || formData.get('bbsAttrbCode') === "") {
alert("게시판 속성은 필수 값입니다.");
return false;
}
if (formData.get('posblAtchFileNumber') === null || formData.get('posblAtchFileNumber') === "") {
alert("첨부파일 가능 숫자는 필수 값입니다.");
return false;
}
return true;
};
const formObjValidator = (checkRef) => {
if(checkRef.current[0].value === ""){
alert("게시판명은 필수 값입니다.");
return false;
}
if(checkRef.current[1].value === ""){
alert("게시판 소개는 필수 값입니다.");
return false;
}
if(checkRef.current[2].value === "0"){
alert("첨부파일 가능 숫자는 필수 값입니다.");
return false;
}
return true;
};
const updateBoard = () => {
let modeStr = modeInfo.mode === CODE.MODE_CREATE ? "POST" : "PUT";
let requestOptions ={};
if (modeStr === "POST") {
const formData = new FormData();
for (let key in boardDetail) {
formData.append(key, boardDetail[key]);
//console.log("boardDetail [%s] ", key, boardDetail[key]);
}
if (formValidator(formData)) {
requestOptions = {
method: modeStr,
headers: {
},
body: formData
}
EgovNet.requestFetch(modeInfo.editURL,
requestOptions,
(resp) => {
if (Number(resp.resultCode) === Number(CODE.RCV_SUCCESS)) {
navigate({ pathname: URL.ADMIN_BOARD });
} else {
navigate({pathname: URL.ERROR}, {state: {msg : resp.resultMessage}});
}
}
);
};
} else {
if (formObjValidator(checkRef)) {
requestOptions = {
method: modeStr,
headers: {
'Content-type': 'application/json',
},
body: JSON.stringify({...boardDetail})
}
EgovNet.requestFetch(modeInfo.editURL,
requestOptions,
(resp) => {
if (Number(resp.resultCode) === Number(CODE.RCV_SUCCESS)) {
navigate({ pathname: URL.ADMIN_BOARD });
} else {
navigate({pathname: URL.ERROR}, {state: {msg : resp.resultMessage}});
}
}
);
}
}
};
const deleteBoardArticle = (bbsId) => {
const deleteBoardURL = `/cop/bbs/deleteBBSMasterInfAPI/${bbsId}.do`;
const requestOptions = {
method: "PUT",
headers: {
'Content-type': 'application/json',
},
body: JSON.stringify({
bbsId: bbsId
})
}
EgovNet.requestFetch(deleteBoardURL,
requestOptions,
(resp) => {
console.log("====>>> board delete= ", resp);
if (Number(resp.resultCode) === Number(CODE.RCV_SUCCESS)) {
alert("게시글이 삭제되었습니다.")
navigate(URL.ADMIN_BOARD, { replace: true });
} else {
alert("ERR : " + resp.resultMessage);
}
}
);
}
const getSelectedLabel = (objArray, findLabel = "") => {
let foundValueLabelObj = objArray.find(o => o['value'] === findLabel);
return foundValueLabelObj['label'];
}
useEffect(() => {
initMode();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const initMode = () => {
if (modeInfo.mode === CODE.MODE_MODIFY) {
setBoardDetail(item);
}
}
function editBoard(e) {
e.preventDefault();
e.stopPropagation();
const form = e.target;
const info = {
bbsId: form.bbsId.value,
bbsTitle: form.bbsTitle.value,
bbsDesc: form.bbsDesc.value
}
if (modeInfo.mode === CODE.MODE_MODIFY) {
info.bbsSeq = props.bbsSeq;
}
EgovNet.requestFetch(
'/admin/boards/board-mgt',
{
method: "PUT",
headers: {
'Content-type': 'application/json'
},
body: JSON.stringify(info)
},
(resp) => {
if (Number(resp.resultCode) === Number(CODE.RCV_SUCCESS)) {
alert("저장되었습니다.");
reloadFunction();
} else if (Number(resp.resultCode) === Number(CODE.RCV_ERROR_AUTH)) {
console.log("토큰 갱신중.")
} else {
alert(resp.result.resultMessage)
}
}
)
}
function deleteBoard(bbs){
if(window.confirm("삭제하시겠습니까?")) {
EgovNet.requestFetch(
'/admin/boards/board-mgt',
{
method: "DELETE",
headers: {
'Content-type': 'application/json'
},
body: JSON.stringify(bbs)
},
(resp) => {
if (Number(resp.resultCode) === Number(CODE.RCV_SUCCESS)) {
alert("삭제되었습니다.")
reloadFunction();
} else if (Number(resp.resultCode) === Number(CODE.RCV_ERROR_AUTH)) {
console.log("토큰 갱신중.")
} else {
alert(resp.result.resultMessage)
}
}
)
}
}
console.log("------------------------------EgovAdminBoardEdit [End]");
console.groupEnd("EgovAdminBoardEdit");
return (
<>
{/* <!-- 본문 --> */}
<Modal.Header closeButton>
<Modal.Title>
{modeInfo.mode === CODE.MODE_CREATE && '게시판 생성'}
{modeInfo.mode === CODE.MODE_MODIFY && '게시판 수정'}
</Modal.Title>
</Modal.Header>
<div className="container">
<div className="c_wrap">
{/* <!-- Location --> */}
<div className="location">
<ul>
<li><Link to={URL.MAIN} className="home">Home</Link></li>
<li><Link to={URL.ADMIN}>사이트관리</Link></li>
<li>게시판생성 관리</li>
</ul>
</div>
{/* <!--// Location --> */}
<div className="layout">
{/* <!-- Navigation --> */}
<EgovLeftNav></EgovLeftNav>
{/* <!--// Navigation --> */}
<div className="contents BOARD_CREATE_REG" id="contents">
{/* <!-- 본문 --> */}
<div className="top_tit">
<h1 className="tit_1">사이트관리</h1>
</div>
{modeInfo.mode === CODE.MODE_CREATE &&
<h2 className="tit_2">게시판 생성</h2>
}
{modeInfo.mode === CODE.MODE_MODIFY &&
<h2 className="tit_2">게시판 수정</h2>
}
<Modal.Body>
<div className="board_view2">
<Form onSubmit={(e) => {editBoard(e)}} noValidate>
<dl>
<dt><label htmlFor="bbsId">게시판 ID</label><span className="req">필수</span></dt>
<dt><label htmlFor="bbsNm">게시판명</label><span className="req">필수</span></dt>
<dd>
<Form.Control className="f_input2 w_full" type="text" name="bbsId" placeholder="게시판 ID" required
defaultValue={props?.bbsId} readOnly={props!==undefined}/>
<input className="f_input2 w_full" type="text" name="bbsNm" title="" id="bbsNm" placeholder=""
defaultValue={boardDetail.bbsNm}
onChange={e => setBoardDetail({ ...boardDetail, bbsNm: e.target.value })}
ref={el => (checkRef.current[0] = el)}
/>
</dd>
</dl>
<dl>
<dt><label htmlFor="bbsTitle">게시판명</label><span className="req">필수</span></dt>
<dt><label htmlFor="bbsIntrcn">게시판 소개</label><span className="req">필수</span></dt>
<dd>
<Form.Control className="f_input2 w_full" type="text" name="bbsTitle" placeholder="게시판명" required
defaultValue={props?.bbsTitle}/>
<textarea className="f_txtar w_full h_100" name="bbsIntrcn" id="bbsIntrcn" cols="30" rows="10" placeholder=""
defaultValue={boardDetail.bbsIntrcn}
onChange={e => setBoardDetail({ ...boardDetail, bbsIntrcn: e.target.value })}
ref={el => (checkRef.current[1] = el)}
></textarea>
</dd>
</dl>
<dl>
<dt><label htmlFor="bbsDesc">게시판 소개</label><span className="req">필수</span></dt>
<dt>게시판 유형<span className="req">필수</span></dt>
<dd>
<Form.Control className="f_txtar w_full h_100" as="textarea" name="bbsDesc" placeholder="게시판 소개" required
defaultValue={props?.bbsDesc}/>
{/* 수정/조회 일때 변경 불가 */}
{modeInfo.mode === CODE.MODE_CREATE &&
<label className="f_select w_130" htmlFor="bbsTyCode">
<select
id="bbsTyCode"
name="bbsTyCode"
title="게시판유형선택"
onChange={(e) => setBoardDetail({ ...boardDetail, bbsTyCode: e.target.value })}
value={boardDetail.bbsTyCode}
>
{bbsTyCodeOptions.map((option, i) => {
return (
<option value={option.value} key={option.value}>
{option.label}
</option>
)
})}
</select>
</label>
}
{modeInfo.mode === CODE.MODE_MODIFY &&
<span>
{boardDetail.bbsTyCode && getSelectedLabel(bbsTyCodeOptions, boardDetail.bbsTyCode)}
</span>
}
</dd>
</dl>
<dl>
<dt>게시판 속성<span className="req">필수</span></dt>
<dd>
{/* 등록 일때 변경 가능 */}
{modeInfo.mode === CODE.MODE_CREATE &&
<label className="f_select w_130" htmlFor="bbsAttrbCode">
<select
id="bbsAttrbCode"
name="bbsAttrbCode"
title="게시판속성선택"
onChange={(e) => setBoardDetail({ ...boardDetail, bbsAttrbCode: e.target.value })}
value={boardDetail.bbsAttrbCode}
>
{bbsAttrbCodeOptions.map((option, i) => {
return (
<option value={option.value} key={option.value}>
{option.label}
</option>
)
})}
</select>
</label>
}
{/* 수정/조회 일때 변경 불가 */}
{modeInfo.mode === CODE.MODE_MODIFY &&
<span>
{boardDetail.bbsAttrbCode && getSelectedLabel(bbsAttrbCodeOptions, boardDetail.bbsAttrbCode)}
</span>
}
</dd>
</dl>
<dl>
<dt>답장가능여부<span className="req">필수</span></dt>
<dd>
{/* 등록 일때 변경 가능 */}
{modeInfo.mode === CODE.MODE_CREATE &&
<EgovRadioButtonGroup
name="replyPosblAt"
radioGroup={replyPosblAtRadioGroup}
setValue={boardDetail.replyPosblAt}
setter={(v) => setBoardDetail({ ...boardDetail, replyPosblAt: v })} />
}
{/* 수정/조회 일때 변경 불가 */}
{modeInfo.mode === CODE.MODE_MODIFY &&
<span>
{boardDetail.replyPosblAt && getSelectedLabel(replyPosblAtRadioGroup, boardDetail.replyPosblAt)}
</span>
}
</dd>
</dl>
<dl>
<dt>파일첨부가능여부<span className="req">필수</span></dt>
<dd>
<EgovRadioButtonGroup
name="fileAtchPosblAt"
radioGroup={fileAtchPosblAtRadioGroup}
setValue={boardDetail.fileAtchPosblAt}
setter={(v) => setBoardDetail({ ...boardDetail, fileAtchPosblAt: v })} />
</dd>
</dl>
<dl>
<dt><label htmlFor="schdulDeptName">첨부파일가능파일 숫자</label><span className="req">필수</span></dt>
<dd>
<label className="f_select " htmlFor="posblAtchFileNumber">
<select
id="posblAtchFileNumber"
name="posblAtchFileNumber"
title="첨부가능파일 숫자선택"
onChange={(e) => setBoardDetail({ ...boardDetail, posblAtchFileNumber: e.target.value })}
value={boardDetail.posblAtchFileNumber}
ref={el => (checkRef.current[2] = el)}
>
{posblAtchFileNumberOptions.map((option, i) => {
return (
<option value={option.value} key={option.value}>
{option.label}
</option>
)
})}
</select>
</label>
</dd>
</dl>
{/* <!-- 버튼영역 --> */}
<div className="board_btn_area">
<div className="left_col btn1">
<button type="submit" className="btn btn_skyblue_h46 w_100">저장
</button>
<button className="btn btn_skyblue_h46 w_100"
onClick={() => updateBoard()}>저장</button>
{modeInfo.mode === CODE.MODE_MODIFY &&
<button type={"button"} className="btn btn_skyblue_h46 w_100" onClick={()=>{deleteBoard(props)}}>삭제</button>
<button className="btn btn_skyblue_h46 w_100" onClick={() => {
deleteBoardArticle(boardDetail.bbsId);
}}>삭제</button>
}
</div>
<div className="right_col btn1">
<button type={"button"} className="btn btn_blue_h46 w_100" onClick={()=>{reloadFunction()}}>목록</button>
<Link to={URL.ADMIN_BOARD} className="btn btn_blue_h46 w_100">목록</Link>
</div>
</div>
{/* <!--// 버튼영역 --> */}
</Form>
</div>
</Modal.Body>
</>
{/* <!--// 본문 --> */}
</div>
</div>
</div>
</div>
);
}

View File

@ -1,41 +1,13 @@
import React, { useState, useEffect, useCallback } from 'react';
import { Link, useLocation } from 'react-router-dom';
import React from 'react';
import * as EgovNet from 'api/egovFetch';
import URL from 'constants/url';
import { default as EgovLeftNav } from 'components/leftmenu/EgovLeftNavAdmin';
function StandardCodeMgt(props) {
function Keywords(props) {
return (
<div className="container">
<div className="c_wrap">
{/* <!-- Location --> */}
<div className="location">
<ul>
<li><Link to={URL.MAIN} className="home">Home</Link></li>
<li><Link to={URL.ADMIN} >사이트관리</Link></li>
<li>게시판현황</li>
<li>키워드 관리</li>
</ul>
</div>
{/* <!--// Location --> */}
<div className="layout">
{/* <!-- Navigation --> */}
<EgovLeftNav></EgovLeftNav>
{/* <!--// Navigation --> */}
<div className="contents NOTICE_LIST" id="contents">
<div className="top_tit">
<h1 className="tit_1">키워드 관리</h1>
</div>
</div>
</div>
</div>
Keywords
</div>
);
}
export default StandardCodeMgt;
export default Keywords;

View File

@ -3,12 +3,11 @@ import { Link, useLocation } from 'react-router-dom';
import * as EgovNet from 'api/egovFetch';
import URL from 'constants/url';
import CODE from 'constants/code';
import { default as EgovLeftNav } from 'components/leftmenu/EgovLeftNavAdmin';
import Modal from "react-bootstrap/Modal";
import EgovAdminBoardEdit from "../board/EgovAdminBoardEdit";
import {format} from "date-fns";
import EgovPaging from 'components/EgovPaging';
import { itemIdxByPage } from 'utils/calc';
function EgovAdminBoardList(props) {
console.group("EgovAdminBoardList");
@ -21,15 +20,10 @@ function EgovAdminBoardList(props) {
// eslint-disable-next-line no-unused-vars
const [searchCondition, setSearchCondition] = useState(location.state?.searchCondition || { pageIndex: 1, searchCnd: '0', searchWrd: '' });// ||
const [paginationInfo, setPaginationInfo] = useState({});
const [listTag, setListTag] = useState([]);
const [show, setShow] = useState(false);
const [modalBody, setModalBody] = useState();
const handleClose = () => setShow(false);
const handleShow = () => setShow(true);
const retrieveList = useCallback(() => {
handleClose();
console.groupCollapsed("AdminBoardList.retrieveList()");
const retrieveListURL = '/admin/boards/board-list';
@ -55,15 +49,14 @@ function EgovAdminBoardList(props) {
if (index === 0) mutListTag = []; //
mutListTag.push(
<div className="list_item">
<Link className="list_item">
<div>{item.bbsSeq}</div>
<div>{item.bbsId}</div>
<div>{item.bbsTitle}</div>
<div>{item.frstCrtId}</div>
<div>{item.frstCrtDt ? format(item.frstCrtDt, "yyyy-MM-dd HH:mm") : ""}</div>
<div>{item.lastChgDt ? format(item.lastChgDt, "yyyy-MM-dd HH:mm") : ""}</div>
<div><button className={"btn btn_blue_h31 px-1"} onClick={()=>{editBoard(item)}}>수정</button></div>
</div>
<div>{item.frstCrtDt}</div>
<div>{item.lastChgDt}</div>
</Link>
);
});
@ -82,14 +75,6 @@ function EgovAdminBoardList(props) {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
function editBoard(item){
handleShow();
if(item != undefined) {
item.mode = CODE.MODE_MODIFY;
}
setModalBody(<EgovAdminBoardEdit props={item} reloadFunction={retrieveList}/>)
}
console.log("------------------------------EgovAdminBoardList [End]");
console.groupEnd("EgovAdminBoardList");
return (
@ -165,7 +150,6 @@ function EgovAdminBoardList(props) {
<span>작성자</span>
<span>작성일</span>
<span>수정일</span>
<span><button className={"btn btn_blue_h31 px-1"} onClick={()=>{editBoard(undefined)}}>추가</button></span>
</div>
<div className="result">
{listTag}
@ -185,9 +169,6 @@ function EgovAdminBoardList(props) {
</div>
</div>
</div>
<Modal show={show} onHide={handleClose} keyboard={false}>
{modalBody}
</Modal>
</div>

View File

@ -1,41 +1,13 @@
import React, { useState, useEffect, useCallback } from 'react';
import { Link, useLocation } from 'react-router-dom';
import React from 'react';
import * as EgovNet from 'api/egovFetch';
import URL from 'constants/url';
import { default as EgovLeftNav } from 'components/leftmenu/EgovLeftNavAdmin';
function StandardCodeMgt(props) {
function Posts(props) {
return (
<div className="container">
<div className="c_wrap">
{/* <!-- Location --> */}
<div className="location">
<ul>
<li><Link to={URL.MAIN} className="home">Home</Link></li>
<li><Link to={URL.ADMIN} >사이트관리</Link></li>
<li>게시판현황</li>
<li>게시물 관리</li>
</ul>
</div>
{/* <!--// Location --> */}
<div className="layout">
{/* <!-- Navigation --> */}
<EgovLeftNav></EgovLeftNav>
{/* <!--// Navigation --> */}
<div className="contents NOTICE_LIST" id="contents">
<div className="top_tit">
<h1 className="tit_1">게시물 관리</h1>
</div>
</div>
</div>
</div>
Posts
</div>
);
}
export default StandardCodeMgt;
export default Posts;

View File

@ -1,41 +1,13 @@
import React, { useState, useEffect, useCallback } from 'react';
import { Link, useLocation } from 'react-router-dom';
import React from 'react';
import * as EgovNet from 'api/egovFetch';
import URL from 'constants/url';
import { default as EgovLeftNav } from 'components/leftmenu/EgovLeftNavAdmin';
function StandardCodeMgt(props) {
function AboutSiteMgt(props) {
return (
<div className="container">
<div className="c_wrap">
{/* <!-- Location --> */}
<div className="location">
<ul>
<li><Link to={URL.MAIN} className="home">Home</Link></li>
<li><Link to={URL.ADMIN} >사이트관리</Link></li>
<li>환경설정</li>
<li>관련사이트 관리</li>
</ul>
</div>
{/* <!--// Location --> */}
<div className="layout">
{/* <!-- Navigation --> */}
<EgovLeftNav></EgovLeftNav>
{/* <!--// Navigation --> */}
<div className="contents NOTICE_LIST" id="contents">
<div className="top_tit">
<h1 className="tit_1">관련사이트 관리</h1>
</div>
</div>
</div>
</div>
AboutSiteMgt
</div>
);
}
export default StandardCodeMgt;
export default AboutSiteMgt;

View File

@ -1,8 +1,25 @@
import React, { useState, useEffect } from 'react';
import { Link } from 'react-router-dom';
import { styled } from '@mui/material/styles';
import Box from '@mui/material/Box';
import * as EgovNet from 'api/egovFetch';
import Paper from '@mui/material/Paper';
import List from '@mui/material/List';
import ListItem from '@mui/material/ListItem';
import EditIcon from '@mui/icons-material/Edit';
import ListItemAvatar from '@mui/material/ListItemAvatar';
import ListItemIcon from '@mui/material/ListItemIcon';
import ListItemText from '@mui/material/ListItemText';
import Avatar from '@mui/material/Avatar';
import IconButton from '@mui/material/IconButton';
import FormGroup from '@mui/material/FormGroup';
import FormControlLabel from '@mui/material/FormControlLabel';
import Checkbox from '@mui/material/Checkbox';
import Grid from '@mui/material/Grid';
import Typography from '@mui/material/Typography';
import FolderIcon from '@mui/icons-material/Folder';
import DeleteIcon from '@mui/icons-material/Delete';
import AddIcon from '@mui/icons-material/Add';
import AddBoxOutlinedIcon from '@mui/icons-material/AddBoxOutlined';
@ -18,12 +35,13 @@ import { default as EgovLeftNav } from 'components/leftmenu/EgovLeftNavAdmin';
function CommitteeCodeMgt(props) {
const [searchCondition, setSearchCondition] = useState({ paramCodeGroup: null, paramCodeLevel: 'LV_01' });
const [dense, setDense] = useState(false);
const [secondary, setSecondary] = useState(false);
const [depth01List, setDepth01List] = useState([]);
const [depth02List, setDepth02List] = useState([]);
const [depth03List, setDepth03List] = useState([]);
const [depth04List, setDepth04List] = useState([]);
const [depth01List, setDepth01List] = useState(["중앙건설기술심의", "테스트2"]);
const [depth02List, setDepth02List] = useState(["123", "테스트2"]);
const [depth03List, setDepth03List] = useState(["다람쥐", "쳇바퀴"]);
const [depth04List, setDepth04List] = useState(["임시 텍스트", "text"]);
const [summaryArray, setSummaryArray] = useState({});
const [depth01SelectedIndex, setDepth01SelectedIndex] = React.useState();
@ -31,70 +49,13 @@ function CommitteeCodeMgt(props) {
const [depth03SelectedIndex, setDepth03SelectedIndex] = React.useState();
const [depth04SelectedIndex, setDepth04SelectedIndex] = React.useState();
// '' item , '' .
useEffect(function () {
// 2 .
if( typeof depth01SelectedIndex !== 'undefined' ) {
setSearchCondition({ paramCodeGroup: depth01List[depth01SelectedIndex].orgId, paramCodeLevel: 'LV_02' });
//setDepth02List([]);
}
if( typeof depth02SelectedIndex !== 'undefined' ) {
setSearchCondition({ paramCodeGroup: depth02List[depth02SelectedIndex].orgId, paramCodeLevel: 'LV_03' });
//setDepth03List([]);
}
if( typeof depth03SelectedIndex !== 'undefined' ) {
setSearchCondition({ paramCodeGroup: depth03List[depth03SelectedIndex].orgId, paramCodeLevel: 'LV_04' });
//setDepth04List([]);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [depth01SelectedIndex, depth02SelectedIndex, depth03SelectedIndex]);
// .
useEffect(function () {
if( typeof searchCondition !== 'undefined' ) {
getList(searchCondition);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [searchCondition]);
const requestOptions = {
method: "GET",
headers: {
'Content-type': 'application/json'
}
}
const getList = (searchCondition) => {
EgovNet.requestFetch(`/admin/config/committee-code-management?paramCodeGroup=${searchCondition.paramCodeGroup}&paramCodeLevel=${searchCondition.paramCodeLevel}`,
requestOptions,
function (resp) {
if( searchCondition.paramCodeLevel === 'LV_01' ) {
setDepth01List(resp.result.list);
} else if( searchCondition.paramCodeLevel === 'LV_02' ) {
setDepth02List(resp.result.list);
} else if( searchCondition.paramCodeLevel === 'LV_03' ) {
setDepth03List(resp.result.list);
} else if( searchCondition.paramCodeLevel === 'LV_04' ) {
setDepth04List(resp.result.list);
}
}
);
}
useEffect(function () {
setSummaryArray(
{
"중앙건설기술심의" : depth01List[depth01SelectedIndex] && depth01List[depth01SelectedIndex].orgNm ? depth01List[depth01SelectedIndex].orgNm : "",
"총괄위원회" : depth02List[depth02SelectedIndex] && depth02List[depth02SelectedIndex].orgNm ? depth02List[depth02SelectedIndex].orgNm : "",
"건설기준위원회" : depth03List[depth03SelectedIndex] && depth03List[depth03SelectedIndex].orgNm ? depth03List[depth03SelectedIndex].orgNm : "",
"실무위원회" : depth04List[depth04SelectedIndex] && depth04List[depth04SelectedIndex].orgNm ? depth04List[depth04SelectedIndex].orgNm : "",
"중앙건설기술심의" : depth01List[depth01SelectedIndex],
"총괄위원회" : depth02List[depth02SelectedIndex],
"건설기준위원회" : depth03List[depth03SelectedIndex],
"실무위원회" : depth04List[depth04SelectedIndex],
}
);
console.log(`${depth01List[depth01SelectedIndex]}[${depth01SelectedIndex}]`);
@ -109,6 +70,12 @@ function CommitteeCodeMgt(props) {
depth03SelectedIndex,
depth04SelectedIndex]);
useEffect(function () {
console.log( summaryArray );
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [summaryArray]);
const Location = React.memo(function Location() {
return (
@ -123,8 +90,6 @@ function CommitteeCodeMgt(props) {
)
});
return (
<div className="container">
<div className="c_wrap">
@ -142,6 +107,7 @@ function CommitteeCodeMgt(props) {
<div className="top_tit">
<h1 className="tit_1">위원회 코드 관리</h1>
</div>
<Box
sx={{
display: 'flex',
@ -153,13 +119,11 @@ function CommitteeCodeMgt(props) {
},
}}
>
<ListCreateUpdateDelete title="중앙건설기술심의" items={depth01List} setItemIndex={setDepth01SelectedIndex} nameKey="orgNm" idKey="orgId" />
<ListCreateUpdateDelete title="총괄위원회" items={depth02List} setItemIndex={setDepth02SelectedIndex} nameKey="orgNm" idKey="orgId" />
<ListCreateUpdateDelete title="건설기준위원회" items={depth03List} setItemIndex={setDepth03SelectedIndex} nameKey="orgNm" idKey="orgId" />
<ListCreateUpdateDelete title="실무위원회" items={depth04List} setItemIndex={setDepth04SelectedIndex} nameKey="orgNm" idKey="orgId" />
<ListCreateUpdateDelete title="중앙건설기술심의" items={depth01List} setItemIndex={setDepth01SelectedIndex}/>
<ListCreateUpdateDelete title="총괄위원회" items={depth02List} setItemIndex={setDepth02SelectedIndex}/>
<ListCreateUpdateDelete title="건설기준위원회" items={depth03List} setItemIndex={setDepth03SelectedIndex}/>
<ListCreateUpdateDelete title="실무위원회" items={depth04List} setItemIndex={setDepth04SelectedIndex}/>
</Box>
{ true &&
<Box
sx={{
display: 'flex',
@ -172,8 +136,6 @@ function CommitteeCodeMgt(props) {
>
<ListLabelInputs title="위원회 코드정보" items={summaryArray} />
</Box>
}
{/* <!--// 본문 --> */}
</div>

View File

@ -1,39 +1,11 @@
import React, { useState, useEffect, useCallback } from 'react';
import { Link, useLocation } from 'react-router-dom';
import React from 'react';
import * as EgovNet from 'api/egovFetch';
import URL from 'constants/url';
import { default as EgovLeftNav } from 'components/leftmenu/EgovLeftNavAdmin';
function StandardCodeMgt(props) {
return (
<div className="container">
<div className="c_wrap">
{/* <!-- Location --> */}
<div className="location">
<ul>
<li><Link to={URL.MAIN} className="home">Home</Link></li>
<li><Link to={URL.ADMIN} >사이트관리</Link></li>
<li>환경설정</li>
<li>건설기준코드 관리</li>
</ul>
</div>
{/* <!--// Location --> */}
<div className="layout">
{/* <!-- Navigation --> */}
<EgovLeftNav></EgovLeftNav>
{/* <!--// Navigation --> */}
<div className="contents NOTICE_LIST" id="contents">
<div className="top_tit">
<h1 className="tit_1">건설기준코드 관리</h1>
</div>
</div>
</div>
</div>
StandardCodeMgt
</div>
);
}

View File

@ -1,4 +1,4 @@
import React, {useState, useEffect, useCallback} from 'react';
import React, {useState, useEffect, useCallback, useRef, PureComponent} from 'react';
import { Link, useLocation } from 'react-router-dom';
import {LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer} from 'recharts';
@ -145,7 +145,6 @@ function FileConnections(props) {
}
);
// console.groupEnd("EgovAdminPrivacyList.retrieveList()");
// eslint-disable-next-line react-hooks/exhaustive-deps
},[listTag]);
const CustomTooltip = ({ active, payload, label }) => {

View File

@ -1,4 +1,4 @@
import React, {useState, useEffect, useCallback} from 'react';
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';
@ -85,7 +85,6 @@ function MenuConnections(props) {
}
);
// console.groupEnd("EgovAdminPrivacyList.retrieveList()");
// eslint-disable-next-line react-hooks/exhaustive-deps
},[listTag]);
const CustomTooltip = ({ active, payload, label }) => {

View File

@ -1,4 +1,4 @@
import React, { useState, useEffect, useCallback } from 'react';
import React, { useState, useEffect, useCallback, useRef } from 'react';
import { Link, useLocation } from 'react-router-dom';
import * as EgovNet from 'api/egovFetch';
@ -77,7 +77,6 @@ function PrivacyConnections(props) {
}
);
// console.groupEnd("EgovAdminPrivacyList.retrieveList()");
// eslint-disable-next-line react-hooks/exhaustive-deps
},[listTag]);
useEffect(() => {

View File

@ -1,4 +1,4 @@
import React, {useState, useEffect, useCallback} from 'react';
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';
@ -84,7 +84,6 @@ function UserConnections(props) {
}
);
// console.groupEnd("EgovAdminPrivacyList.retrieveList()");
// eslint-disable-next-line react-hooks/exhaustive-deps
},[listTag]);
const CustomTooltip = ({ active, payload, label }) => {

View File

@ -1,166 +0,0 @@
import PropTypes from 'prop-types';
import { useState } from 'react';
import { Link as RouterLink } from 'react-router-dom';
// material-ui
import { Box, Link, Table, TableBody, TableCell, TableContainer, TableHead, TableRow } from '@mui/material';
function createData(trackingNo, title, dt, name) {
return { trackingNo, title, dt, name };
}
const rows = [
createData(1, '흙막이 가시설 띠장 전단 설계시 플래지 ...', '2024-02-04 13:22', '홍길동'),
createData(2, '콘크리트 벽체 설계기준 적용 유무 확인 ...', '2024-02-04 13:22', '홍길동'),
createData(3, '한중콘크리트 초기양생 관련', '2024-02-04 13:22', '홍길동'),
createData(4, 'KDS 21 30 00 : 2022가설흙...', '2024-02-04 13:22', '홍길동'),
createData(5, '인테리어필름 시방서 관련', '2024-02-04 13:22', '홍길동'),
createData(6, '고온고압증기양생기포콘크리트(ALC) 구조', '2024-02-04 13:22', '홍길동'),
createData(7, '지반을 최저등급으로 가정한 경우란', '2024-02-04 13:22', '홍길동')
];
function descendingComparator(a, b, orderBy) {
if (b[orderBy] < a[orderBy]) {
return -1;
}
if (b[orderBy] > a[orderBy]) {
return 1;
}
return 0;
}
function getComparator(order, orderBy) {
return order === 'desc' ? (a, b) => descendingComparator(a, b, orderBy) : (a, b) => -descendingComparator(a, b, orderBy);
}
function stableSort(array, comparator) {
const stabilizedThis = array.map((el, index) => [el, index]);
stabilizedThis.sort((a, b) => {
const order = comparator(a[0], b[0]);
if (order !== 0) {
return order;
}
return a[1] - b[1];
});
return stabilizedThis.map((el) => el[0]);
}
// ==============================|| ORDER TABLE - HEADER CELL ||============================== //
const headCells = [
{
id: 'trackingNo',
align: 'left',
disablePadding: false,
label: 'No.'
},
{
id: 'title',
align: 'center',
disablePadding: true,
label: '제목'
},
{
id: 'dt',
align: 'center',
disablePadding: false,
label: '작성일자'
},
{
id: 'name',
align: 'center',
disablePadding: false,
label: '작성자'
},
];
// ==============================|| ORDER TABLE - HEADER ||============================== //
function OrderTableHead({ order, orderBy }) {
return (
<TableHead>
<TableRow>
{headCells.map((headCell) => (
<TableCell
key={headCell.id}
align={headCell.align}
padding={headCell.disablePadding ? 'none' : 'normal'}
sortDirection={orderBy === headCell.id ? order : false}
sx={{ width:headCell.id === 'trackingNo' ? '10%' :
headCell.id === 'title' ? '50%' :
headCell.id === 'dt' ? '25%' : '15%', }}
>
{headCell.label}
</TableCell>
))}
</TableRow>
</TableHead>
);
}
OrderTableHead.propTypes = {
order: PropTypes.string,
orderBy: PropTypes.string
};
// ==============================|| ORDER TABLE ||============================== //
export default function OrderTable() {
const [order] = useState('asc');
const [orderBy] = useState('trackingNo');
const [selected] = useState([]);
const isSelected = (trackingNo) => selected.indexOf(trackingNo) !== -1;
return (
<Box>
<TableContainer
sx={{
width: '100%',
overflowX: 'auto',
position: 'relative',
display: 'block',
maxWidth: '100%',
'& td, & th': { whiteSpace: 'nowrap' }
}}
>
<Table
aria-labelledby="tableTitle"
sx={{
'& .MuiTableCell-root:first-of-type': {
pl: 2
},
'& .MuiTableCell-root:last-of-type': {
pr: 0
}
}}
>
<OrderTableHead order={order} orderBy={orderBy} />
<TableBody>
{stableSort(rows, getComparator(order, orderBy)).map((row, index) => {
const isItemSelected = isSelected(row.trackingNo);
const labelId = `enhanced-table-checkbox-${index}`;
return (
<TableRow
hover
role="checkbox"
sx={{ '&:last-child td, &:last-child th': { border: 0 } }}
aria-checked={isItemSelected}
tabIndex={-1}
key={row.trackingNo}
selected={isItemSelected}
>
<TableCell width="10%" align="left" component="th" id={labelId} scope="row">{row.trackingNo}</TableCell>
<TableCell width="50%" align="left"><Link color="secondary" component={RouterLink} to="" sx={{ overflow: 'hidden', textOverflow: 'ellipsis', display: 'block'}}>{row.title}</Link></TableCell>
<TableCell width="25%" align="center">{row.dt}</TableCell>
<TableCell width="15%" align="center">{row.name}</TableCell>
</TableRow>
);
})}
</TableBody>
</Table>
</TableContainer>
</Box>
);
}

View File

@ -0,0 +1,202 @@
import React, { useState, useEffect } from 'react';
import { Link, useLocation, useNavigate } from 'react-router-dom';
import * as EgovNet from 'api/egovFetch';
import URL from 'constants/url';
import CODE from 'constants/code';
import { default as EgovLeftNav } from 'components/leftmenu/EgovLeftNavAdmin';
import EgovAttachFile from 'components/EgovAttachFile';
function EgovAdminScheduleDetail(props) {
console.group("EgovAdminScheduleDetail");
console.log("[Start] EgovAdminScheduleDetail ------------------------------");
console.log("EgovAdminScheduleDetail [props] : ", props);
const navigate = useNavigate();
const location = useLocation();
console.log("EgovAdminScheduleDetail [location] : ", location);
const [scheduleDetail, setScheduleDetail] = useState({});
const [boardAttachFiles, setBoardAttachFiles] = useState();
const [user, setUser] = useState({});
const retrieveDetail = () => {
const retrieveDetailURL = `/schedule/${location.state?.schdulId}`;
const requestOptions = {
method: "GET",
headers: {
'Content-type': 'application/json',
}
}
EgovNet.requestFetch(retrieveDetailURL,
requestOptions,
function (resp) {
let rawScheduleDetail = resp.result.scheduleDetail;
rawScheduleDetail.startDateTime = convertDate(rawScheduleDetail.schdulBgnde);
rawScheduleDetail.endDateTime = convertDate(rawScheduleDetail.schdulEndde);
rawScheduleDetail.reptitSeCodeNm = getCodeName(resp.result.reptitSeCode, resp.result.scheduleDetail.reptitSeCode);
rawScheduleDetail.schdulIpcrCodeNm = getCodeName(resp.result.schdulIpcrCode, resp.result.scheduleDetail.schdulIpcrCode);
rawScheduleDetail.schdulSeNm = getCodeName(resp.result.schdulSe, resp.result.scheduleDetail.schdulSe);
setScheduleDetail(rawScheduleDetail);
setUser(resp.result.user);
setBoardAttachFiles(resp.result.resultFiles);
}
);
}
const convertDate = (str) => {
let year = str.substring(0, 4);
let month = str.substring(4, 6);
let date = str.substring(6, 8);
let hour = str.substring(8, 10);
let minute = str.substring(10, 12);
return {
year: year,
month: month,
date: date,
hour: hour,
minute: minute,
dateForm: year + "년 " + month + "월 " + date + "일 " + hour + "시 " + minute + "분 "
}
}
const getCodeName = (codeArr, code) => {
return (
codeArr.map((codeObj) => {
if (codeObj.code === code.trim()) return codeObj.codeNm
else return "";
})
);
};
const onClickDeleteSchedule = (schdulId) => {
const deleteBoardURL = `/schedule/${schdulId}`;
const requestOptions = {
method: "DELETE",
headers: {
'Content-type': 'application/json',
}
}
EgovNet.requestFetch(deleteBoardURL,
requestOptions,
(resp) => {
console.log("====>>> Schdule delete= ", resp);
if (Number(resp.resultCode) === Number(CODE.RCV_SUCCESS)) {
alert("게시글이 삭제되었습니다.")
navigate(URL.ADMIN_SCHEDULE ,{ replace: true });
} else {
// alert("ERR : " + resp.message);
navigate({pathname: URL.ERROR}, {state: {msg : resp.resultMessage}});
}
}
);
}
useEffect(function () {
retrieveDetail();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
console.log("------------------------------EgovAdminScheduleDetail [End]");
console.groupEnd("EgovAdminScheduleDetail");
return (
<div className="container">
<div className="c_wrap">
{/* <!-- Location --> */}
<div className="location">
<ul>
<li><Link to={URL.MAIN} className="home">Home</Link></li>
<li><Link to={URL.ADMIN}>사이트관리</Link></li>
<li>일정관리</li>
</ul>
</div>
{/* <!--// Location --> */}
<div className="layout">
{/* <!-- Navigation --> */}
<EgovLeftNav></EgovLeftNav>
{/* <!--// Navigation --> */}
<div className="contents SITE_GALLARY_VIEW" id="contents">
{/* <!-- 본문 --> */}
<div className="top_tit">
<h1 className="tit_1">사이트관리</h1>
</div>
<h2 className="tit_2">일정관리 상세보기</h2>
{/* <!-- 게시판 상세보기 --> */}
<div className="board_view2">
<dl>
<dt>일정구분</dt>
<dd>{scheduleDetail.schdulSeNm}</dd>
</dl>
<dl>
<dt>중요도</dt>
<dd>{scheduleDetail.schdulIpcrCodeNm}</dd>
</dl>
<dl>
<dt>부서</dt>
<dd>{scheduleDetail.schdulDeptName}</dd>
</dl>
<dl>
<dt>일정명</dt>
<dd>{scheduleDetail.schdulNm}</dd>
</dl>
<dl>
<dt>일정내용</dt>
<dd>{scheduleDetail.schdulCn}</dd>
</dl>
<dl>
<dt>반복구분</dt>
<dd>{scheduleDetail.reptitSeCodeNm}</dd>
</dl>
<dl>
<dt>날짜/시간</dt>
<dd> {scheduleDetail.startDateTime?.dateForm} ~ {scheduleDetail.endDateTime?.dateForm}</dd>
</dl>
<dl>
<dt>담당자</dt>
<dd>{scheduleDetail.schdulChargerName}</dd>
</dl>
<EgovAttachFile boardFiles={boardAttachFiles} />
{/* <!-- 버튼영역 --> */}
<div className="board_btn_area">
{user.id &&
<div className="left_col btn1">
<Link to={{pathname: URL.ADMIN_SCHEDULE_MODIFY}}
state={{
schdulId: location.state?.schdulId
}}
className="btn btn_skyblue_h46 w_100">수정</Link>
<button className="btn btn_skyblue_h46 w_100"
onClick={(e) => {
onClickDeleteSchedule(location.state?.schdulId);
}}>삭제</button>
</div>
}
<div className="right_col btn1">
<Link to={URL.ADMIN_SCHEDULE} className="btn btn_blue_h46 w_100">목록</Link>
</div>
</div>
{/* <!--// 버튼영역 --> */}
</div>
{/* <!-- 게시판 상세보기 --> */}
{/* <!--// 본문 --> */}
</div>
</div>
</div>
</div>
);
}
export default EgovAdminScheduleDetail;

View File

@ -0,0 +1,364 @@
import React, { useState, useEffect } from 'react';
import { Link, useLocation, useNavigate } from 'react-router-dom';
import DatePicker from "react-datepicker";
import * as EgovNet from 'api/egovFetch';
import URL from 'constants/url';
import CODE from 'constants/code';
import { default as EgovLeftNav } from 'components/leftmenu/EgovLeftNavAdmin';
import EgovAttachFile from 'components/EgovAttachFile';
import EgovRadioButtonGroup from 'components/EgovRadioButtonGroup';
import 'react-datepicker/dist/react-datepicker.css';
function EgovAdminScheduleEdit(props) {
console.group("EgovAdminScheduleEdit");
console.log("[Start] EgovAdminScheduleEdit ------------------------------");
console.log("EgovAdminScheduleEdit [props] : ", props);
const navigate = useNavigate();
const location = useLocation();
console.log("EgovAdminScheduleEdit [location] : ", location);
const reptitSeCodeRadioGroup = [{ value: "1", label: "당일" }, { value: "2", label: "반복" }, { value: "3", label: "연속" }];
const [modeInfo, setModeInfo] = useState({ mode: props.mode });
const [scheduleDetail, setScheduleDetail] = useState({ schdulDeptName: "관리자부서", schdulChargerName: "관리자", schdulKindCode: 2, reptitSeCode: "1", startDate: new Date(), endDate: new Date() });
const [boardAttachFiles, setBoardAttachFiles] = useState();
const [schdulBgndeHH, setSchdulBgndeHH] = useState();
const [schdulBgndeMM, setSchdulBgndeMM] = useState();
const [schdulEnddeHH, setSchdulEnddeHH] = useState();
const [schdulEnddeMM, setSchdulEnddeMM] = useState();
const initMode = () => {
switch (props.mode) {
case CODE.MODE_CREATE:
setModeInfo({
...modeInfo,
modeTitle: "등록",
method : "POST",
editURL: '/schedule'
});
break;
case CODE.MODE_MODIFY:
setModeInfo({
...modeInfo,
modeTitle: "수정",
method : "PUT",
editURL: '/schedule'
});
break;
default:
navigate({pathname: URL.ERROR}, {state: {msg : ""}});
}
retrieveDetail();
}
const convertDate = (str) => {
let year = str.substring(0, 4);
let month = str.substring(4, 6);
let date = str.substring(6, 8);
let hour = str.substring(8, 10);
let minute = str.substring(10, 12);
return new Date(year, month - 1, date, hour, minute)
}
const retrieveDetail = () => {
if (modeInfo.mode === CODE.MODE_CREATE) {// /
setScheduleDetail({
...scheduleDetail,
schdulBgnde: location.state.iUseDate,
schdulEndde: location.state.iUseDate,
startDate: convertDate(location.state.iUseDate),
endDate: convertDate(location.state.iUseDate),
});
return;
}
const retrieveDetailURL = `/schedule/${location.state?.schdulId}`;
const requestOptions = {
method: "GET",
headers: {
'Content-type': 'application/json'
}
}
EgovNet.requestFetch(retrieveDetailURL,
requestOptions,
function (resp) {
let rawScheduleDetail = resp.result.scheduleDetail;
//
setScheduleDetail({
...scheduleDetail,
...rawScheduleDetail,
startDate: convertDate(rawScheduleDetail.schdulBgnde),
endDate: convertDate(rawScheduleDetail.schdulEndde),
atchFileId : rawScheduleDetail.atchFileId.trim(),
});
setBoardAttachFiles(resp.result.resultFiles);
}
);
}
const updateSchedule = () => {
const formData = new FormData();
for (let key in scheduleDetail) {
formData.append(key, scheduleDetail[key]);
console.log("scheduleDetail [%s] ", key, scheduleDetail[key]);
}
if (formValidator(formData)) {
const requestOptions = {
method: modeInfo.method,
body: formData
}
if (modeInfo.mode === CODE.MODE_MODIFY) {
modeInfo.editURL = `${modeInfo.editURL}/${location.state?.schdulId}`;
}
EgovNet.requestFetch(modeInfo.editURL,
requestOptions,
(resp) => {
if (Number(resp.resultCode) === Number(CODE.RCV_SUCCESS)) {
navigate({ pathname: URL.ADMIN_SCHEDULE });
} else {
navigate({pathname: URL.ERROR}, {state: {msg : resp.resultMessage}});
}
}
);
}
}
const formValidator = (formData) => {
if (formData.get('schdulNm') === null || formData.get('schdulNm') === "") {
alert("일정명은 필수 값입니다.");
return false;
}
if (formData.get('schdulCn') === null || formData.get('schdulCn') === "") {
alert("일정내용은 필수 값입니다.");
return false;
}
if (formData.get('schdulSe') === null || formData.get('schdulSe') === "") {
alert("일정구분은 필수 값입니다.");
return false;
}
if (formData.get('schdulIpcrCode') === null || formData.get('schdulIpcrCode') === "") {
alert("중요도는 필수 값입니다.");
return false;
}
if (formData.get('reptitSeCode') === null ||formData.get('reptitSeCode') === "") {
alert("반복구분은 필수 값입니다.");
return false;
}
if (formData.get('schdulBgnde') > formData.get('schdulEndde')) {
alert("종료일시는 시작일시보다 앞 설 수 없습니다.");
return false;
}
return true;
}
const getDateFourteenDigit = (date) => {
return getYYYYMMDD(date).toString() + makeTwoDigit(date.getHours()) + makeTwoDigit(date.getMinutes()) + makeTwoDigit(date.getSeconds());
}
const getYYYYMMDD = (date) => {
return date.getFullYear().toString() + makeTwoDigit(Number(date.getMonth() + 1)) + makeTwoDigit(date.getDate());
}
const makeTwoDigit = (number) => {
return number < 10 ? "0" + number : number.toString();
}
useEffect(function () {
initMode();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
console.log("------------------------------EgovAdminScheduleEdit [End]");
console.groupEnd("EgovAdminScheduleEdit");
return (
<div className="container">
<div className="c_wrap">
{/* <!-- Location --> */}
<div className="location">
<ul>
<li><Link to={URL.MAIN} className="home">Home</Link></li>
<li><Link to={URL.ADMIN}>사이트관리</Link></li>
<li>일정관리</li>
</ul>
</div>
{/* <!--// Location --> */}
<div className="layout">
{/* <!-- Navigation --> */}
<EgovLeftNav></EgovLeftNav>
{/* <!--// Navigation --> */}
<div className="contents SITE_SCHDULE_REG" id="contents">
{/* <!-- 본문 --> */}
<div className="top_tit">
<h1 className="tit_1">사이트관리</h1>
</div>
<h2 className="tit_2">일정관리 상세보기</h2>
{/* <!-- 게시판 상세보기 --> */}
<div className="board_view2">
<dl>
<dt>일정구분<span className="req">필수</span></dt>
<dd>
<label className="f_select w_130" htmlFor="schdulSe">
<select id="schdulSe" name="schdulSe" title="일정구분"
value={scheduleDetail.schdulSe}
onChange={(e) => setScheduleDetail({ ...scheduleDetail, schdulSe: e.target.value })}>
<option value="">선택</option>
<option value="1">회의</option>
<option value="2">세미나</option>
<option value="3">강의</option>
<option value="4">교육</option>
<option value="5">기타</option>
</select>
</label>
</dd>
</dl>
<dl>
<dt>중요도<span className="req">필수</span></dt>
<dd>
<label className="f_select w_130" htmlFor="schdulIpcrCode">
<select id="schdulIpcrCode" name="schdulIpcrCode" title="중요도"
value={scheduleDetail.schdulIpcrCode}
onChange={(e) => setScheduleDetail({ ...scheduleDetail, schdulIpcrCode: e.target.value })}>
<option value="">선택</option>
<option value="A">높음</option>
<option value="B">보통</option>
<option value="C">낮음</option>
</select>
</label>
</dd>
</dl>
<dl>
<dt><label htmlFor="schdulDeptName">부서</label><span className="req">필수</span></dt>
<dd>
<input className="f_input2 w_full" type="text" name="schdulDeptName" title="부서" id="schdulDeptName"
value={scheduleDetail.schdulDeptName} readOnly
/>
</dd>
</dl>
<dl>
<dt><label htmlFor="schdulNm">일정명</label><span className="req">필수</span></dt>
<dd>
<input className="f_input2 w_full" type="text" name="schdulNm" title="부서" id="schdulNm" placeholder="일정 테스트"
defaultValue={scheduleDetail.schdulNm}
onChange={(e) => setScheduleDetail({ ...scheduleDetail, schdulNm: e.target.value })} />
</dd>
</dl>
<dl>
<dt><label htmlFor="schdulCn">일정내용</label><span className="req">필수</span></dt>
<dd>
<textarea className="f_txtar w_full h_100" name="schdulCn" id="schdulCn" cols="30" rows="10" placeholder="일정내용"
defaultValue={scheduleDetail.schdulCn}
onChange={(e) => setScheduleDetail({ ...scheduleDetail, schdulCn: e.target.value })}
></textarea>
</dd>
</dl>
<dl>
<dt>반복구분<span className="req">필수</span></dt>
<dd>
<EgovRadioButtonGroup
name="reptitSeCode"
radioGroup={reptitSeCodeRadioGroup}
setValue={scheduleDetail.reptitSeCode.trim()}
setter={(v) => setScheduleDetail({ ...scheduleDetail, reptitSeCode: v })} />
</dd>
</dl>
<dl>
<dt>날짜/시간<span className="req">필수</span></dt>
<dd className="datetime">
<span className="line_break">
<DatePicker
selected={scheduleDetail.startDate}
name="schdulBgnde"
className="f_input"
dateFormat="yyyy-MM-dd HH:mm"
showTimeInput
onChange={(date) => {
console.log("setStartDate : ", date);
setScheduleDetail({ ...scheduleDetail, schdulBgnde: getDateFourteenDigit(date), schdulBgndeYYYMMDD: getYYYYMMDD(date), schdulBgndeHH: date.getHours(), schdulBgndeMM: date.getMinutes(), startDate: date });
setSchdulBgndeHH(date.getHours());
setSchdulBgndeMM(date.getMinutes());
}} />
<input type="hidden" name="schdulBgndeHH" defaultValue={schdulBgndeHH} readOnly />
<input type="hidden" name="schdulBgndeMM" defaultValue={schdulBgndeMM} readOnly />
<span className="f_inn_txt">~</span>
</span>
<span className="line_break">
<DatePicker
selected={scheduleDetail.endDate}
name="schdulEndde"
className="f_input"
dateFormat="yyyy-MM-dd HH:mm"
showTimeInput
minDate={scheduleDetail.startDate}
onChange={(date) => {
console.log("setEndDate: ", date);
setScheduleDetail({ ...scheduleDetail, schdulEndde: getDateFourteenDigit(date), schdulEnddeYYYMMDD: getYYYYMMDD(date), schdulEnddeHH: date.getHours(), schdulEnddeMM: date.getMinutes(), endDate: date });
setSchdulEnddeHH(date.getHours());
setSchdulEnddeMM(date.getMinutes());
}
} />
<input type="hidden" name="schdulEnddeHH" defaultValue={schdulEnddeHH} readOnly />
<input type="hidden" name="schdulEnddeMM" defaultValue={schdulEnddeMM} readOnly />
</span>
</dd>
</dl>
<dl>
<dt><label htmlFor="schdulChargerName">담당자</label><span className="req">필수</span></dt>
<dd>
<input className="f_input2 w_full" type="text" name="schdulChargerName" id="schdulChargerName" defaultValue="관리자" readOnly
/>
</dd>
</dl>
<EgovAttachFile
fnChangeFile={(attachfile) => {
console.log("====>>> Changed attachfile file = ", attachfile);
const arrayConcat = { ...scheduleDetail}; // ( for)
for ( let i = 0; i < attachfile.length; i++) {
arrayConcat[`file_${i}`] = attachfile[i];
}
setScheduleDetail(arrayConcat);
}}
fnDeleteFile={(deletedFile) => {
console.log("====>>> Delete deletedFile = ", deletedFile);
setBoardAttachFiles(deletedFile);
}}
boardFiles={boardAttachFiles}
mode={props.mode} />
{/* <!-- 버튼영역 --> */}
<div className="board_btn_area">
<div className="left_col btn1">
<button className="btn btn_skyblue_h46 w_100"
onClick={() => updateSchedule()}
> 저장</button>
<a href="#!" className="btn btn_skyblue_h46 w_100">삭제</a>
</div>
<div className="right_col btn1">
<Link to={URL.ADMIN_SCHEDULE} className="btn btn_blue_h46 w_100">목록</Link>
</div>
</div>
{/* <!--// 버튼영역 --> */}
</div>
{/* <!-- 게시판 상세보기 --> */}
{/* <!--// 본문 --> */}
</div>
</div>
</div>
</div >
);
}
export default EgovAdminScheduleEdit;

View File

@ -1,221 +1,328 @@
import React, {useState, useEffect, useCallback} from 'react'; // PureComponent
import {Link} from 'react-router-dom'; //useLocation
// import {BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer} from 'recharts';
import React, {useState, useEffect, useCallback, PureComponent} from 'react';
import {Link, useLocation} from 'react-router-dom';
import {BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer} from 'recharts';
import * as EgovNet from 'api/egovFetch';
import URL from 'constants/url';
// import CODE from 'constants/code';
// material-ui
import { Box, Button, Grid, Stack, Typography } from '@mui/material';
import MainCard from 'components/cards/MainCard';
import BbsTable from './BbsTable';
import IncomeAreaChart from './IncomeAreaChart';
import MonthlyBarChart from './MonthlyBarChart';
import ReportAreaChart from './ReportAreaChart';
import AnalyticEcommerce from 'components/cards/AnalyticEcommerce';
import CODE from 'constants/code';
import {default as EgovLeftNav} from 'components/leftmenu/EgovLeftNavAdmin';
function EgovAdminDashboard(props) {
// console.group("EgovAdminScheduleList");
// console.log("[Start] EgovAdminScheduleList ------------------------------");
// console.log("EgovAdminScheduleList [props] : ", props);
function EgovAdminScheduleList(props) {
console.group("EgovAdminScheduleList");
console.log("[Start] EgovAdminScheduleList ------------------------------");
console.log("EgovAdminScheduleList [props] : ", props);
// const location = useLocation();
// console.log("EgovAdminScheduleList [location] : ", location);
const location = useLocation();
console.log("EgovAdminScheduleList [location] : ", location);
const DATE = new Date();
// const TODAY = new Date(DATE.getFullYear(), DATE.getMonth(), DATE.getDate());
//
// const [searchCondition, setSearchCondition] = useState(location.state?.searchCondition || {schdulSe: '', year: TODAY.getFullYear(), month: TODAY.getMonth(), date: TODAY.getDate()});
// const [calendarTag, setCalendarTag] = useState([]);
//
// const [scheduleList, setScheduleList] = useState([]);
const TODAY = new Date(DATE.getFullYear(), DATE.getMonth(), DATE.getDate());
// const innerConsole = (...args) => {
// console.log(...args);
// }
const [searchCondition, setSearchCondition] = useState(location.state?.searchCondition || {schdulSe: '', year: TODAY.getFullYear(), month: TODAY.getMonth(), date: TODAY.getDate()});
const [calendarTag, setCalendarTag] = useState([]);
// const changeDate = (target, amount) => {
// let changedDate;
//
// if (target === CODE.DATE_YEAR) {
// changedDate = new Date(searchCondition.year + amount, searchCondition.month, searchCondition.date);
// }
//
// if (target === CODE.DATE_MONTH) {
// changedDate = new Date(searchCondition.year, searchCondition.month + amount, searchCondition.date);
// }
// setSearchCondition({...searchCondition, year: changedDate.getFullYear(), month: changedDate.getMonth(), date: changedDate.getDate()});
// }
const [scheduleList, setScheduleList] = useState([]);
const [dailyUserLogList, setDailyUserLogList] = useState([]);
// const retrieveList = useCallback((srchcnd) => {
// console.groupCollapsed("EgovAdminScheduleList.retrieveList()");
//
// const retrieveListURL = '/schedule/month' + EgovNet.getQueryString(srchcnd);
//
// const requestOptions = {
// method: "GET",
// headers: {
// 'Content-type': 'application/json',
// }
// }
//
// EgovNet.requestFetch(retrieveListURL,
// requestOptions,
// (resp) => {
// setScheduleList(resp.result.resultList);
// },
// function (resp) {
// console.log("err response : ", resp);
// }
// );
// console.groupEnd("EgovAdminScheduleList.retrieveList()");
// }, []);
const innerConsole = (...args) => {
console.log(...args);
}
const getLastDateOfMonth = (year, month) => {
const LAST_DATE_SUPPLMENT = 1;
return new Date(year, month + LAST_DATE_SUPPLMENT, 0);
}
const getFirstDateOfMonth = (year, month) => {
return new Date(year, month, 1);
}
// const Location = React.memo(function Location() {
// return (
// <div className="location">
// <ul>
// <li><Link to={URL.MAIN} className="home">Home</Link></li>
// <li><Link to={URL.ADMIN}></Link></li>
// <li>Dashboard</li>
// </ul>
// </div>
// )
// });
const changeDate = (target, amount) => {
let changedDate;
// useEffect(() => {
// //retrieveList(searchCondition); disabled by thkim
// // eslint-disable-next-line react-hooks/exhaustive-deps
// }, [searchCondition]);
if (target === CODE.DATE_YEAR) {
changedDate = new Date(searchCondition.year + amount, searchCondition.month, searchCondition.date);
}
// const [dailyUserLogList, setDailyUserLogList] = useState([]);
// const [isDailyChart, setIsDailyChart] = useState(true);
//
// const getDailyUserLogList = useCallback(() => {
// // console.groupCollapsed("EgovAdminScheduleList.getDailyUserLogList()");
// //
// // console.log("@@@ isDailyChart : " + isDailyChart);
//
// const dailyUserLogListURL = isDailyChart ? '/admin/dashboard/daily-user-log-list' : '/admin/dashboard/monthly-user-log-list';
//
// const requestOptions = {
// method: "GET",
// headers: {
// 'Content-type': 'application/json',
// }
// }
//
// EgovNet.requestFetch(dailyUserLogListURL,
// requestOptions,
// (resp) => {
// setDailyUserLogList(resp.result.dailyUserLogList);
// // console.log("@@@ : " + dailyUserLogList);
// },
// function (resp) {
// // console.log("err response : ", resp);
// }
// );
// // console.groupEnd("EgovAdminScheduleList.getDailyUserLogList()");
// // eslint-disable-next-line react-hooks/exhaustive-deps
// }, [isDailyChart]);
//
// useEffect(() => {
// getDailyUserLogList();
// // eslint-disable-next-line react-hooks/exhaustive-deps
// }, [isDailyChart]);
//
// const handleChartToggle = () => {
// setIsDailyChart(!isDailyChart);
// };
//
// const ChartToggle = ({onToggle}) => {
//
// const handleToggle = () => {
// onToggle(!isDailyChart);
// };
//
// return (
// <button onClick={handleToggle}>
// {isDailyChart ? '' : ''}
// </button>
// )
// }
//
// const data = dailyUserLogList.map(item => ({
// logDt: item.logDt,
// uv: item.mobileCnt,
// " ": item.logCnt,
// amt: item.pcCnt,
// }));
//
// const CustomTooltip = ({active, payload, label}) => {
// if (active && payload && payload.length) {
// return (
// <div className="custom-tooltip">
// <p className="desc"> </p>
// <p className="label">{`${label} : ${payload[0].value}`}</p>
// </div>
// );
// }
//
// return null;
// };
if (target === CODE.DATE_MONTH) {
changedDate = new Date(searchCondition.year, searchCondition.month + amount, searchCondition.date);
}
setSearchCondition({...searchCondition, year: changedDate.getFullYear(), month: changedDate.getMonth(), date: changedDate.getDate()});
}
// class UserLogChart extends PureComponent {
// render() {
// return (
// <ResponsiveContainer width="100%" height="100%">
// <BarChart
// width={500}
// height={300}
// data={data}
// margin={{
// top: 5,
// right: 30,
// left: 20,
// bottom: 5,
// }}
// >
// <CartesianGrid strokeDasharray="3 3"/>
// <XAxis dataKey="logDt"/>
// <YAxis/>
// <Tooltip content={<CustomTooltip/>}/>
// <Legend/>
// <Bar dataKey=" " barSize={20} fill="#87CEFA"/>
// </BarChart>
// </ResponsiveContainer>
// );
// }
// }
const retrieveList = useCallback((srchcnd) => {
console.groupCollapsed("EgovAdminScheduleList.retrieveList()");
// console.log("------------------------------EgovAdminScheduleList [End]");
// console.groupEnd("EgovAdminScheduleList");
const retrieveListURL = '/schedule/month' + EgovNet.getQueryString(srchcnd);
// const [value, setValue] = useState('today');
const [slot, setSlot] = useState('week');
const [totalDownloads, setTotalDownloads] = useState(0);
const requestOptions = {
method: "GET",
headers: {
'Content-type': 'application/json',
}
}
// state
const handleTotalDownloads = (sum) => {
setTotalDownloads(sum);
EgovNet.requestFetch(retrieveListURL,
requestOptions,
(resp) => {
setScheduleList(resp.result.resultList);
},
function (resp) {
console.log("err response : ", resp);
}
);
console.groupEnd("EgovAdminScheduleList.retrieveList()");
}, []);
const drawCalendar = () => {
console.groupCollapsed("EgovAdminScheduleList.drawCalendar()");
const PREV_MONTH_ADDITION = -1;
let lastOfLastMonth = getLastDateOfMonth(searchCondition.year, searchCondition.month + PREV_MONTH_ADDITION);
let firstOfThisMonth = getFirstDateOfMonth(searchCondition.year, searchCondition.month);
let lastOfThisMonth = getLastDateOfMonth(searchCondition.year, searchCondition.month);
console.log("lastOfLastMonth : ", lastOfLastMonth, lastOfLastMonth.getDay());
console.log("firstOfThisMonth :", firstOfThisMonth, firstOfThisMonth.getDay());
console.log("lastOfThisMonth :", lastOfThisMonth, lastOfThisMonth.getDay());
console.log("scheduleList : ", scheduleList);
let firstDayOfThisMonth = firstOfThisMonth.getDay();
let lastDateOfThisMonth = lastOfThisMonth.getDate();
console.log("firstDayOfThisMonth", firstDayOfThisMonth, "lastDateOfThisMonth", lastDateOfThisMonth)
let monthArr = [];
let weekArr = [];
// firstWeek Date Set START
let firstWeekDateCount = 0;
for (let day = 0; day < 7; day++) {
if (day < firstDayOfThisMonth) { //
weekArr.push(0);
firstWeekDateCount = 0;
} else {
weekArr.push(++firstWeekDateCount);
}
}
monthArr.push(weekArr);
console.log("FirstWeek monthArr : ", monthArr);
// firstWeek Date Set END
// otherWeek Date Set START
let dayCount = 0;
weekArr = [];//
for (let day = firstWeekDateCount + 1; day <= lastDateOfThisMonth; day++) {
if (dayCount % 7 !== 6) {
weekArr.push(day);
} else {
weekArr.push(day);
monthArr.push(weekArr);
weekArr = [];
dayCount = -1;
}
dayCount++;
}
// otherWeek Date Set END
// lastWeek Date Set START
if (weekArr.length > 0) {//
for (let day = weekArr.length; day < 7; day++) {
weekArr.push(0);
}
monthArr.push(weekArr);
}
// lastWeek Date Set END
console.log("OtherWeek monthArr : ", monthArr);
let mutsUseYearMonth = searchCondition.year.toString() + ((searchCondition.month + 1).toString().length === 1 ? "0" + (searchCondition.month + 1).toString() : (searchCondition.month + 1).toString());
console.log("mutsUseYearMonth : ", mutsUseYearMonth);
let mutCalendarTagList = [];
let keyIdx = 0;
//draw Calendar
monthArr.forEach((week, weekIdx) => {
console.log();
mutCalendarTagList.push(
<tr key={keyIdx++}>{
week.map((day, dayIdx) => {
if (day !== 0) {//
let sDate = day.toString().length === 1 ? "0" + day.toString() : day.toString();
let iUseDate = Number(mutsUseYearMonth + sDate);
if (scheduleList.length > 0) {//
return (
<td key={keyIdx++}>
<Link to={{pathname: URL.ADMIN_SCHEDULE_CREATE}} state={{iUseDate: mutsUseYearMonth + sDate + "000000"}} className="day"
key={keyIdx++}>{day}</Link><br/>
{
scheduleList.map((schedule, scheduleIdx) => {
let iBeginDate = Number(schedule.schdulBgnde.substring(0, 8));
let iEndDate = Number(schedule.schdulEndde.substring(0, 8));
innerConsole("scheduleList ", day, scheduleIdx, iBeginDate, iUseDate, iEndDate, iUseDate >= iBeginDate && iUseDate <= iEndDate);
innerConsole("schedule.schdulId ", schedule.schdulId);
if (iUseDate >= iBeginDate && iUseDate <= iEndDate) {
return (
<>
<Link to={{pathname: URL.ADMIN_SCHEDULE_DETAIL}}
state={{schdulId: schedule.schdulId}}
key={keyIdx++}>{schedule.schdulNm}
</Link>
<br/>
</>
);
} else return <></>
})
}
</td>
);
} else {//
return (
<td key={keyIdx++}>
<Link to={{pathname: URL.ADMIN_SCHEDULE_CREATE}} state={{iUseDate: mutsUseYearMonth + sDate + "000000"}} className="day"
key={keyIdx++}>{day}</Link><br/>
</td>);
}
} else if (day === 0) {// /
return (<td key={keyIdx++}></td>);
} else return <></>
})
}</tr>);
})
console.log("mutCalendarTagList : ", mutCalendarTagList);
setCalendarTag(mutCalendarTagList);
console.groupEnd("EgovAdminScheduleList.drawCalendar()");
}
const Location = React.memo(function Location() {
return (
<div className="location">
<ul>
<li><Link to={URL.MAIN} className="home">Home</Link></li>
<li><Link to={URL.ADMIN}>사이트관리</Link></li>
<li>일정관리</li>
</ul>
</div>
)
});
useEffect(() => {
//retrieveList(searchCondition); disabled by thkim
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [searchCondition]);
useEffect(() => {
drawCalendar();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [scheduleList]);
const [isDailyChart, setChart] = useState(true);
const getDailyUserLogList = useCallback(() => {
console.groupCollapsed("EgovAdminScheduleList.getDailyUserLogList()");
console.log("@@@ isDailyChart : " + isDailyChart);
const dailyUserLogListURL = isDailyChart ? '/admin/dashboard/daily-user-log-list' : '/admin/dashboard/monthly-user-log-list';
const requestOptions = {
method: "GET",
headers: {
'Content-type': 'application/json',
}
}
EgovNet.requestFetch(dailyUserLogListURL,
requestOptions,
(resp) => {
setDailyUserLogList(resp.result.dailyUserLogList);
console.log("@@@ : " + dailyUserLogList);
},
function (resp) {
console.log("err response : ", resp);
}
);
console.groupEnd("EgovAdminScheduleList.getDailyUserLogList()");
}, [isDailyChart]);
useEffect(() => {
getDailyUserLogList();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isDailyChart]);
const handleChartToggle = () => {
setChart(!isDailyChart);
};
const ChartToggle = ({onToggle}) => {
const handleToggle = () => {
onToggle(!isDailyChart);
};
return (
<button onClick={handleToggle}>
{isDailyChart ? '월별차트보기' : '일별차트보기'}
</button>
)
}
const data = dailyUserLogList.map(item => ({
logDt: item.logDt,
uv: item.mobileCnt,
"사용자 접속현황": item.logCnt,
amt: item.pcCnt,
}));
const CustomTooltip = ({active, payload, label}) => {
if (active && payload && payload.length) {
return (
<div className="custom-tooltip">
<p className="desc">사용자 접속 현황</p>
<p className="label">{`${label} : ${payload[0].value}`}</p>
</div>
);
}
return null;
};
class UserLogChart extends PureComponent {
static demoUrl = 'https://codesandbox.io/s/tooltip-with-customized-content-lyxvs';
render() {
return (
<ResponsiveContainer width="100%" height="100%">
<BarChart
width={500}
height={300}
data={data}
margin={{
top: 5,
right: 30,
left: 20,
bottom: 5,
}}
>
<CartesianGrid strokeDasharray="3 3"/>
<XAxis dataKey="logDt"/>
<YAxis/>
<Tooltip content={<CustomTooltip/>}/>
<Legend/>
<Bar dataKey="사용자 접속현황" barSize={20} fill="#87CEFA"/>
</BarChart>
</ResponsiveContainer>
);
}
}
console.log("------------------------------EgovAdminScheduleList [End]");
console.groupEnd("EgovAdminScheduleList");
return (
<div className="container">
<div className="c_wrap">
{/* <!-- Location --> */}
<div className="location">
<ul>
<li><Link to={URL.MAIN} className="home">Home</Link></li>
<li><Link to={URL.ADMIN} >사이트관리</Link></li>
<li>Dashboard</li>
</ul>
</div>
<Location/>
{/* <!--// Location --> */}
<div className="layout">
@ -227,132 +334,16 @@ function EgovAdminDashboard(props) {
{/* <!-- 본문 --> */}
<div className="top_tit">
<h1 className="tit_1">Dashboard</h1>
<h1 className="tit_1">사이트관리</h1>
</div>
<Grid container rowSpacing={4.5} columnSpacing={2.75}>
{/* row 1 */}
{/*<Grid item xs={12} sx={{ mb: -2.25 }}>*/}
{/* <Typography variant="h5">Dashboard</Typography>*/}
{/*</Grid>*/}
<Grid item xs={12} sm={6} md={4} lg={3}>
<AnalyticEcommerce title={`총접속자수 (${DATE.getMonth() + 1}월)`} count="442,236" percentage={59.3} extra="35,000" />
</Grid>
<Grid item xs={12} sm={6} md={4} lg={3}>
<AnalyticEcommerce title={`건설기준 오류건수 (${DATE.getMonth() + 1}월)`} count="78,250" percentage={70.5} extra="8,900" />
</Grid>
<Grid item xs={12} sm={6} md={4} lg={3}>
<AnalyticEcommerce title={`기준코드 등록건수 (${DATE.getMonth() + 1}월)`} count="18,800" percentage={27.4} isLoss color="warning" extra="1,943" />
</Grid>
<Grid item xs={12} sm={6} md={4} lg={3}>
<AnalyticEcommerce title={`민원건수 (${DATE.getMonth() + 1}월)`} count="5" percentage={80} isLoss color="warning" extra="1" />
</Grid>
<h2 className="tit_2"></h2>
<Grid item md={8} sx={{ display: { sm: 'none', md: 'block', lg: 'none' } }} />
<ChartToggle isDailyChart={isDailyChart} onToggle={handleChartToggle}/>
{/* row 2 */}
<Grid item xs={12} md={7} lg={8}>
<Grid container alignItems="center" justifyContent="space-between">
<Grid item>
<Typography variant="h5">{ DATE.getFullYear() } 메뉴접속 / 방문수 </Typography>
</Grid>
<Grid item>
<Stack direction="row" alignItems="center" spacing={0}>
<Button
size="small"
onClick={() => setSlot('month')}
color={slot === 'month' ? 'primary' : 'secondary'}
variant={slot === 'month' ? 'outlined' : 'text'}
>
Month
</Button>
<Button
size="small"
onClick={() => setSlot('week')}
color={slot === 'week' ? 'primary' : 'secondary'}
variant={slot === 'week' ? 'outlined' : 'text'}
>
Week
</Button>
</Stack>
</Grid>
</Grid>
<MainCard content={false} sx={{ mt: 1.5 }}>
<Box sx={{ pt: 1, pr: 2 }}>
<IncomeAreaChart slot={slot} />
</Box>
</MainCard>
</Grid>
<Grid item xs={12} md={5} lg={4}>
<Grid container alignItems="center" justifyContent="space-between">
<Grid item>
<Typography variant="h5">다운로드수</Typography>
</Grid>
<Grid item />
</Grid>
<MainCard sx={{ mt: 2 }} content={false}>
<Box sx={{ p: 3, pb: 0 }}>
<Stack spacing={2}>
<Typography variant="h3" color="textSecondary">
주간 현황
</Typography>
<Typography variant="h6"> {totalDownloads}</Typography>
</Stack>
</Box>
<MonthlyBarChart onDataFetched={handleTotalDownloads} />
</MainCard>
</Grid>
{/* row 3 */}
<Grid item xs={12} md={7} lg={8}>
<Grid container alignItems="center" justifyContent="space-between">
<Grid item>
<Typography variant="h5">최근 문의사항</Typography>
</Grid>
<Grid item />
</Grid>
<MainCard sx={{ mt: 2 }} content={false}>
<BbsTable />
</MainCard>
</Grid>
<Grid item xs={12} md={5} lg={4}>
<Grid container alignItems="center" justifyContent="space-between">
<Grid item>
<Typography variant="h5">접속 방법</Typography>
</Grid>
<Grid item />
</Grid>
<MainCard sx={{ mt: 2 }} content={false}>
<ReportAreaChart />
</MainCard>
</Grid>
</Grid>
{/*<ChartToggle isDailyChart={isDailyChart} onToggle={handleChartToggle}/>*/}
{/*<div style={{width: 1000, height: 300}}>*/}
{/* <ResponsiveContainer width="100%" height="100%">*/}
{/* <BarChart*/}
{/* width={500}*/}
{/* height={300}*/}
{/* data={data}*/}
{/* margin={{*/}
{/* top: 5,*/}
{/* right: 30,*/}
{/* left: 20,*/}
{/* bottom: 5,*/}
{/* }}*/}
{/* >*/}
{/* <CartesianGrid strokeDasharray="3 3"/>*/}
{/* <XAxis dataKey="logDt"/>*/}
{/* <YAxis/>*/}
{/* <Tooltip content={<CustomTooltip/>}/>*/}
{/* <Legend/>*/}
{/* <Bar dataKey="사용자 접속현황" barSize={20} fill="#87CEFA"/>*/}
{/* </BarChart>*/}
{/* </ResponsiveContainer>*/}
{/*</div>*/}
<div style={{width: 1000, height: 300}}>
<UserLogChart/>
</div>
</div>
</div>
</div>
@ -360,4 +351,4 @@ function EgovAdminDashboard(props) {
);
}
export default EgovAdminDashboard;
export default EgovAdminScheduleList;

View File

@ -1,156 +0,0 @@
import PropTypes from 'prop-types';
import { useState, useEffect, useCallback } from 'react';
// material-ui
import { useTheme } from '@mui/material/styles';
// third-party
import ReactApexChart from 'react-apexcharts';
import * as EgovNet from 'api/egovFetch';
// chart options
const areaChartOptions = {
chart: {
height: 450,
type: 'area',
toolbar: {
show: false
}
},
dataLabels: {
enabled: false
},
stroke: {
curve: 'smooth',
width: 2
},
grid: {
strokeDashArray: 0
}
};
// ==============================|| INCOME AREA CHART ||============================== //
const IncomeAreaChart = ({ slot }) => {
const theme = useTheme();
const { primary, secondary } = theme.palette.text;
const line = theme.palette.divider;
const [options, setOptions] = useState(areaChartOptions);
const [menuMonthlyList, setMenuMonthlyList] = useState([]);
const [menuDailyList, setMenuDailyList] = useState([]);
const [loginMonthlyList, setLoginMonthlyList] = useState([]);
const [loginDailyList, setLoginDailyList] = useState([]);
//
const retrieveList = useCallback(() => {
const retrieveListURL = '/admin/dashboard/menu-login'
const requestOptions = {
method: "POST",
headers: {
'Content-type': 'application/json',
},
// body: JSON.stringify()
}
EgovNet.requestFetch(retrieveListURL,
requestOptions,
(resp) => {
setMenuMonthlyList(resp.result.menuMonthlyList);
setMenuDailyList(resp.result.menuDailyList);
setLoginMonthlyList(resp.result.loginMonthlyList);
setLoginDailyList(resp.result.loginDailyList);
},
function (resp) {
console.log("err response : ", resp);
}
);
// eslint-disable-next-lie react-hooks/exhaustive-deps
}, []);
useEffect(() => {
retrieveList();
setOptions((prevState) => ({
...prevState,
colors: [theme.palette.primary.main, theme.palette.primary[700]],
xaxis: {
categories:
slot === 'month'
? ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
labels: {
style: {
colors: [
secondary,
secondary,
secondary,
secondary,
secondary,
secondary,
secondary,
secondary,
secondary,
secondary,
secondary,
secondary
]
}
},
axisBorder: {
show: true,
color: line
},
tickAmount: slot === 'month' ? 11 : 7
},
yaxis: {
labels: {
style: {
colors: [secondary]
}
}
},
grid: {
borderColor: line
},
tooltip: {
theme: 'light'
}
}));
}, [primary, secondary, line, theme, slot, retrieveList]);
const [series, setSeries] = useState([
{
name: 'Menu Views',
data: menuDailyList
},
{
name: 'Login Count',
data: loginDailyList
}
]);
useEffect(() => {
setSeries([
{
name: 'Menu Views',
data: slot === 'month' ? menuMonthlyList : menuDailyList
},
{
name: 'Login Count',
data: slot === 'month' ? loginMonthlyList : loginDailyList
}
]);
}, [slot, menuMonthlyList, menuDailyList, loginMonthlyList, loginDailyList]);
return <ReactApexChart options={options} series={series} type="area" height={450} />;
};
IncomeAreaChart.propTypes = {
slot: PropTypes.string
};
export default IncomeAreaChart;

View File

@ -1,125 +0,0 @@
import {useCallback, useEffect, useState} from 'react';
// material-ui
import { useTheme } from '@mui/material/styles';
// third-party
import ReactApexChart from 'react-apexcharts';
import * as EgovNet from 'api/egovFetch';
// chart options
const barChartOptions = {
chart: {
type: 'bar',
height: 365,
toolbar: {
show: false
}
},
plotOptions: {
bar: {
columnWidth: '45%',
borderRadius: 4
}
},
dataLabels: {
enabled: true
},
xaxis: {
categories: ['Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su'],
axisBorder: {
show: false
},
axisTicks: {
show: false
}
},
yaxis: {
show: false
},
grid: {
show: false
}
};
// ==============================|| MONTHLY BAR CHART ||============================== //
const MonthlyBarChart = ({ onDataFetched }) => {
const theme = useTheme();
const { primary, secondary } = theme.palette.text;
const info = theme.palette.info.light;
const [options, setOptions] = useState(barChartOptions);
const [fileDailyList, setFileDailyList] = useState([]);
//
const retrieveList = useCallback(() => {
const retrieveListURL = '/admin/dashboard/file'
const requestOptions = {
method: "POST",
headers: {
'Content-type': 'application/json',
},
// body: JSON.stringify()
}
EgovNet.requestFetch(retrieveListURL,
requestOptions,
(resp) => {
setFileDailyList(resp.result.fileDailyList);
const sum = resp.result.fileDailyList.reduce((accumulator, currentValue) => accumulator + currentValue, 0);
onDataFetched(sum);
},
function (resp) {
console.log("err response : ", resp);
}
);
// eslint-disable-next-lie react-hooks/exhaustive-deps
}, []);
const [series, setSeries] = useState([
{
name: '다운로드수',
data: fileDailyList
}
]);
useEffect(() => {
retrieveList();
}, [onDataFetched]);
useEffect(() => {
setSeries([
{
data: fileDailyList
},
]);
setOptions((prevState) => ({
...prevState,
colors: [info],
xaxis: {
labels: {
style: {
colors: [secondary, secondary, secondary, secondary, secondary, secondary, secondary]
}
}
},
tooltip: {
theme: 'light'
},
}));
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [primary, info, secondary, fileDailyList]);
return (
<div id="chart">
<ReactApexChart options={options} series={series} type="bar" height={365} />
</div>
);
};
export default MonthlyBarChart;

View File

@ -1,83 +0,0 @@
import { useEffect, useState } from 'react';
// material-ui
import { useTheme } from '@mui/material/styles';
// third-party
import ReactApexChart from 'react-apexcharts';
// chart options
const areaChartOptions = {
chart: {
type: 'donut',
},
plotOptions: {
pie: {
startAngle: -90,
endAngle: 90,
offsetY: 10,
expandOnClick:false,
}
},
dataLabels: {
enabled: true
},
title: {
text: '2024년 2월',
align: 'center'
},
responsive: [{
breakpoint: 480,
options: {
chart: {
width: 200
},
legend: {
position: 'bottom'
}
}
}],
grid: {
padding: {
bottom: -150
}
},
};
// ==============================|| REPORT AREA CHART ||============================== //
const ReportAreaChart = () => {
const theme = useTheme();
const { primary, secondary } = theme.palette.text;
const line = theme.palette.divider;
const [options, setOptions] = useState(areaChartOptions);
useEffect(() => {
setOptions((prevState) => ({
...prevState,
labels: ['PC', 'Mobile'],
colors: ['#448EF7', '#FFC107'],
// colors: [theme.palette.warning.main],
grid: {
borderColor: line
},
tooltip: {
theme: 'light'
},
legend: {
position: 'bottom',
labels: {
colors: 'grey.500'
}
}
}));
}, [primary, secondary, line, theme]);
const [series] = useState([90, 10]);
return <ReactApexChart options={options} series={series} type="donut" />;
};
export default ReportAreaChart;

View File

@ -35,9 +35,11 @@ function InfoDisclosure(props) {
<div className="contents " id="contents">
{/* <!-- 본문 --> */}
<div className="top_tit">
<h1 className="tit_1">건설기준 내용 관리</h1>
<h1 className="tit_1">건설기준 관리</h1>
</div>
<h2 className="tit_2">건설기준 내용 관리</h2>
여기에 구현해주세요.
{/* <!--// 본문 --> */}
</div>

View File

@ -35,9 +35,11 @@ function ReferenceCodes(props) {
<div className="contents " id="contents">
{/* <!-- 본문 --> */}
<div className="top_tit">
<h1 className="tit_1">참조코드 관리</h1>
<h1 className="tit_1">건설기준 관리</h1>
</div>
<h2 className="tit_2">참조코드 관리</h2>
여기에 구현해주세요.
{/* <!--// 본문 --> */}
</div>

View File

@ -35,9 +35,10 @@ function SimilarityCheck(props) {
<div className="contents " id="contents">
{/* <!-- 본문 --> */}
<div className="top_tit">
<h1 className="tit_1">유사성 검사</h1>
<h1 className="tit_1">건설기준 관리</h1>
</div>
<h2 className="tit_2">유사성 검사</h2>
여기에 구현해주세요.
{/* <!--// 본문 --> */}

View File

@ -1,4 +1,4 @@
import React, { useState } from 'react';
import React, { useState, useEffect, useRef } from 'react';
import {Link, useLocation, useNavigate} from 'react-router-dom';
import * as EgovNet from 'api/egovFetch';
@ -7,7 +7,7 @@ import CODE from "constants/code";
import Row from 'react-bootstrap/Row';
import Col from 'react-bootstrap/Col';
import { setLocalItem } from 'utils/storage';
import { getLocalItem, setLocalItem, setSessionItem } from 'utils/storage';
import InfoShareChk from "./InfoShareChk";
function Join(props) {
@ -21,6 +21,7 @@ function Join(props) {
const [userInfo, setUserInfo] = useState({ id: '', password: '', passwordChk: '', userNm: '', email: '', phoneNum: ''});
const [infoShareChk, setInfoShareChk] = useState(false);
const [submitFlag, setSubmitFlag] = useState(true);
const submitFormHandler = (e) => {
console.log("JoinContent submitFormHandler()");

View File

@ -1,88 +0,0 @@
import React, {useEffect, useState} from "react";
import {Button, Modal, Nav} from "react-bootstrap";
import Col from "react-bootstrap/Col";
import Row from "react-bootstrap/Row";
import * as EgovNet from "api/egovFetch";
function DownloadModal({closeFn}){
const [tab, setTab] = useState(10);
const [subTabsVisible, setSubTabsVisible] = useState(false);
const [listData, setListData] = useState([]);
useEffect(() => {
EgovNet.requestFetch('/standardCode/standard-code-download-list?listCode='+tab,
{
method: "GET",
headers: {
'Content-type': 'application/json',
}
},
(resp) => {
setListData(resp.result.resultList);
},
function (resp) {
console.log("err response : ", resp);
}
);
}, [tab]);
return(
<>
<Modal.Header closeButton>
<Modal.Title id="example-modal-sizes-title-lg">통합다운로드</Modal.Title>
</Modal.Header>
<Modal.Body>
<Row className={"justify-content-start py-1 mx-1"}>
<Col xs={"auto px-1"}>
<div className={`tab ${tab === 10 ? 'active' : ''}`}
onClick={() => {setTab(10); setSubTabsVisible(false)}}>설계기준</div>
</Col>
<Col xs={"auto px-1"}>
<div className={`tab ${tab === 20 ? 'active' : ''}`}
onClick={() => {setTab(20); setSubTabsVisible(false)}}>표준시방서</div>
</Col>
<Col xs={"auto px-1"}>
<div className={`tab ${[40, 50, 60, 70, 80, 90].includes(tab) ? 'active' : ''}`}
onClick={() => {setTab(40); setSubTabsVisible(true)}}>전문시방서</div>
</Col>
</Row>
{subTabsVisible && (
<Nav className={"tabs"} variant={"tabs"} >
<Nav.Item><Nav.Link className={`${tab === 40 ? 'active' : ''}`} onClick={() => {setTab(40)}}>서울특별시</Nav.Link></Nav.Item>
<Nav.Item><Nav.Link className={`${tab === 50 ? 'active' : ''}`} onClick={() => {setTab(50)}}>고속도로공사</Nav.Link></Nav.Item>
<Nav.Item><Nav.Link className={`${tab === 60 ? 'active' : ''}`} onClick={() => {setTab(60)}}>한국농어촌공사</Nav.Link></Nav.Item>
<Nav.Item><Nav.Link className={`${tab === 70 ? 'active' : ''}`} onClick={() => {setTab(70)}}>철도건설공사</Nav.Link></Nav.Item>
<Nav.Item><Nav.Link className={`${tab === 80 ? 'active' : ''}`} onClick={() => {setTab(80)}}>LH한국토지주택공사</Nav.Link></Nav.Item>
<Nav.Item><Nav.Link className={`${tab === 90 ? 'active' : ''}`} onClick={() => {setTab(90)}}>K-Water</Nav.Link></Nav.Item>
</Nav>
)}
<div className="board_list standard_code_modal download_list">
<div className="head">
<span>구분</span>
<span>코드</span>
<span>다운로드</span>
</div>
<div className={"result"}>
{listData.filter(item => {
return item;
}).map(item => {
return (
<div className="list_item">
<div className="mainCategory">{item.groupNm}</div>
<div className="middleCategory">{item.groupCurCd}</div>
<div className="kcscCd">
<Button size={"sm"} variant={"outline-secondary"}>다운로드</Button>
</div>
</div>
)
})}
</div>
</div>
</Modal.Body>
<Modal.Footer><Button onClick={closeFn}>닫기</Button></Modal.Footer>
</>
)
}
export default DownloadModal;

View File

@ -1,46 +0,0 @@
import React, {useState} from "react";
import {AiFillStar} from "react-icons/ai";
import {getLocalItem} from "utils/storage";
import * as EgovNet from "../../../api/egovFetch";
function FavoriteIcon({item}){
const [favoriteChk, setFavoriteChk] = useState(item.favoriteChk);
function favoriteStateChange(groupSeq, checked){
EgovNet.requestFetch(
'/standardCode/document-favorite',
{
method: "POST",
headers: {
'Content-type': 'application/json',
},
body:JSON.stringify({groupSeq: groupSeq, active: checked})
},
(resp) => {
},
function (resp) {
console.log("err response : ", resp);
}
);
}
return (
<div className="star clickable"
onClick={()=>{
const accessToken = getLocalItem('accessToken')
if(accessToken) {
favoriteStateChange(item.groupSeq, !favoriteChk)
setFavoriteChk(!favoriteChk)
}else{
alert("로그인 후 이용 가능한 서비스 입니다.")
}
}}>
<AiFillStar color={favoriteChk?'#FFC000':''}/>
</div>
);
}
export default FavoriteIcon;

View File

@ -1,47 +0,0 @@
import React, {useEffect, useState} from "react";
import {Button, Modal, Nav} from "react-bootstrap";
import Col from "react-bootstrap/Col";
import Row from "react-bootstrap/Row";
import * as EgovNet from "api/egovFetch";
function HistoryModal({closeFn, standardCode}){
return(
<>
<Modal.Header closeButton>
<Modal.Title id="example-modal-sizes-title-lg">개정이력</Modal.Title>
</Modal.Header>
<Modal.Body>
<div>코드 : {standardCode.kcscCd}</div>
<div className="board_list standard_code_modal">
<div className="head">
<span>고시일</span>
<span>기준코드</span>
<span>신구건설기준비교</span>
</div>
<div className={"result"}>
{standardCode.historyList.filter(history => {
return history;
}).map(history => {
return (
<div className="list_item">
<div className="mainCategory">{history.rvsnYmd.split('T')[0]}</div>
<div className="middleCategory">
<Button size={"sm"} variant={"outline-secondary"}>다운로드</Button>
</div>
<div className="kcscCd">
<Button size={"sm"} variant={"outline-secondary"}>다운로드</Button>
</div>
</div>
)
})}
</div>
</div>
</Modal.Body>
<Modal.Footer><Button onClick={closeFn}>닫기</Button></Modal.Footer>
</>
)
}
export default HistoryModal;

View File

@ -1,17 +1,119 @@
import React from 'react';
import Col from "react-bootstrap/Col";
import Row from "react-bootstrap/Row";
import FavoriteIcon from "./FavoriteIcon";
import Button from "react-bootstrap/Button";
import React, {useState, useEffect, useCallback, useRef} from 'react';
import {Link, useLocation, useParams} from 'react-router-dom';
function StandardCodeList({listData, filterData, getHistoryModal}) {
import * as EgovNet from 'api/egovFetch';
import URL from 'constants/url';
import {StandardCodeListModal, StandardCodeListModalTable} from './StandardCodeListModal'
import {AiFillFileMarkdown, AiFillStar} from "react-icons/ai";
import StandardCodeSearchForm from "./StandardCodeSearchForm";
function historyBtn(item){
getHistoryModal(item);
function StandardCodeList({}) {
const {listCode} = useParams();
const [listData, setListData] = useState([])
const [filterData, setFilterData] = useState('');
const [resultCnt, setResultCnt] = useState(0);
const [groupSeq, setGroupSeq] = useState();
const [show, setShow] = useState(false);
function close() {
setShow(false);
}
function showHandling(e) {
const param = e.currentTarget.dataset;
const groupSeq = param.groupSeq;
console.log(groupSeq);
EgovNet.requestFetch(
'/standardCode/codeListModal.do',
{
method: "POST",
headers: {
'Content-type': 'application/json'
},
body: JSON.stringify(
groupSeq
)
}, (resp) => {
console.log(resp + "------------------------resp")
const body = [];
const head = [];
if (resp.length > 0) {
resp.forEach(function (item, index) {
const formattedDate = item.aplcnBgngYmd.match(/\d{4}-\d{2}-\d{2}/)[0];
const url = "https://www.kcsc.re.kr/file/DownloadGrp/" + item.docFileGrpId;
body.push(
<tr>
<td>{formattedDate}</td>
<td><a href={url}><AiFillFileMarkdown/></a></td>
<td></td>
</tr>)
})
head.push(
<tr>
<td>년도</td>
<td>기준코드</td>
<td>신구건설기준비교</td>
</tr>
)
}
setGroupSeq(<StandardCodeListModalTable head={head} content={body}/>);
}
)
setShow(true);
}
const retrieveList = useCallback((searchCondition) => {
if(searchCondition?.tab){
EgovNet.requestFetch('/standardCode/standard-code-list'+EgovNet.convParams(searchCondition),
{
method: "GET",
headers: {
'Content-type': 'application/json',
}
},
(resp) => {
setListData(resp.result.resultList);
setResultCnt(resp.result.resultCnt);
},
function (resp) {
console.log("err response : ", resp);
}
);
}
}, []);
return (
<div className={"result standard_code_result"}>
<div className="StandardCodeList container">
<div className="c_wrap codelistcontent">
<div className="location">
<ul>
<li><Link to={URL.MAIN} className="home">Home</Link></li>
<li><Link to='#'>건설기준코드</Link></li>
<li><Link to={URL.STANDARD_CODE_LIST}>건설기준코드 검색</Link></li>
</ul>
</div>
<div className="layout">
<div className="contents NOTICE_LIST listtablediv">
<div className="top_tit">
<h2 className="tit_1">건설기준코드 검색</h2>
</div>
<StandardCodeSearchForm param={listCode} reloadFunction={retrieveList}/>
<div><span>전체 {resultCnt} </span></div>
{/* <!-- 게시판목록 --> */}
<div className="board_list code_list">
<div className="head">
<span>대분류</span>
<span>중분류</span>
<span>코드번호</span>
<span>코드명</span>
<span>개정이력</span>
<span>보기</span>
<span>즐겨찾기</span>
</div>
<div className="result">
{listData.filter(item => {
if (item.groupNm.includes(filterData)) {
return item
@ -23,45 +125,20 @@ function StandardCodeList({listData, filterData, getHistoryModal}) {
<div className="mainCategory">{item.mainCategory}</div>
<div className="middleCategory">{item.middleCategory}</div>
<div className="kcscCd">{item.kcscCd}</div>
<div className="groupNm">{item.groupNm}<br/><span className={"text-danger"}>{item.rvsnRemark}</span></div>
<div className="Revisionhistory">
<Button size={"sm"} variant={"outline-secondary"} onClick={()=>{historyBtn(item)}}>개정 이력</Button>
</div>
<div className="fille">
<Row className={"justify-content-start"}>
{item.historyList.filter(history => {
return history;
}).map(history => {
let buttonClass = "btn btn-sm docInfoBtn docInfoActive "
let pClass = "yearInfo yearInfoActive";
if(history.docEr === 'E'){
buttonClass += "btn-success "
}else{
buttonClass += "btn-primary "
}
return (
<Col xs={"auto"} className={"px-1"}>
<input type="button"
className={buttonClass}
value={history.docEr==='E'?'제':'개'}
onClick={()=>{
const rvsnYmd = new Date(history.rvsnYmd)
rvsnYmd.setHours(rvsnYmd.getHours()+9)
window.open("/standardCode/viewer/"+history.kcscCd+":"+rvsnYmd.toISOString().split('T')[0]);
}}
/>
<br/>
<p className={pClass}>{history.docYr}</p>
</Col>
)
})}
</Row>
</div>
<FavoriteIcon item={item}/>
<div className="groupNm">{item.groupNm}</div>
<div className="Revisionhistory"><a className="vieweratag" onClick={showHandling} data-groupSeq={item.groupSeq}>개정이력</a></div>
<div className="fille">{item.contentcount > 0 ? <a className="vieweratag" href={"/standardCode/viewer/" + item.kcscCd}>내용보기</a> : null}</div>
<div className="star"><AiFillStar/></div>
</div>
)
})}
</div>
</div>
<StandardCodeListModal size={"lg"} show={show} content={groupSeq} onClose={close} title={"개정이력"}/>
</div>
</div>
</div>
</div>
);
}

View File

@ -0,0 +1,30 @@
import {Button, Modal, ModalBody, ModalFooter, ModalHeader, ModalTitle} from "react-bootstrap";
function StandardCodeListModal({show,content,onClose,title,size}){
return(
<Modal size={size} show={show} aria-labelledby="example-modal-sizes-title-lg">
<ModalHeader>
<ModalTitle id="example-modal-sizes-title-lg">{title}</ModalTitle>
</ModalHeader>
<ModalBody>
{content}
</ModalBody>
<ModalFooter><Button onClick={onClose}>닫기</Button></ModalFooter>
</Modal>)
}
function StandardCodeListModalTable({head,content}){
return(
<table>
<thead>
{head}
</thead>
<tbody>
{content}
</tbody>
</table>
)
}
export {StandardCodeListModal,StandardCodeListModalTable};

View File

@ -1,111 +0,0 @@
import React, {useState, useCallback} from 'react';
import {useParams} from 'react-router-dom';
import * as EgovNet from 'api/egovFetch';
import DownloadModal from './DownloadModal'
import StandardCodeSearchForm from "./StandardCodeSearchForm";
import Loading from "components/Loading";
import StandardCodeList from "./StandardCodeList";
import Modal from "react-bootstrap/Modal";
import HistoryModal from "./HistoryModal";
function StandardCodePage({}) {
const {listCode} = useParams();
const [listData, setListData] = useState([])
const [listLoading, setListLoading] = useState(true);
const [filterData, setFilterData] = useState('');
const [resultCnt, setResultCnt] = useState(0);
const [remarkCnt, setRemarkCnt] = useState(0);
const [modalContent, setModalContent] = useState([]);
const [show, setShow] = useState(false);
function close() {
setShow(false);
}
const retrieveList = useCallback((searchCondition) => {
setListLoading(true)
EgovNet.requestFetch('/standardCode/standard-code-list'+EgovNet.convParams(searchCondition),
{
method: "GET",
headers: {
'Content-type': 'application/json',
}
},
(resp) => {
setListData(resp.result.resultList);
setResultCnt(resp.result.resultCnt.allCnt);
setRemarkCnt(resp.result.resultCnt.remarkCnt);
setListLoading(false)
},
function (resp) {
console.log("err response : ", resp);
}
);
}, []);
function downloadModal(){
setShow(true);
setModalContent(<DownloadModal closeFn={close}/>)
}
function historyModal(item){
setShow(true);
setModalContent(<HistoryModal closeFn={close} standardCode={item}/>)
}
return (
<div className="">
<div className="c_wrap">
{/*<div className="location">
<ul>
<li><Link to={URL.MAIN} className="home">Home</Link></li>
<li>건설기준코드</li>
<li><Link to={URL.STANDARD_CODE_LIST} >건설기준코드 검색</Link></li>
</ul>
</div>*/}
<div className="layout">
<div className="contents NOTICE_LIST" id="contents">
{/*<div className="top_tit">
<h1 className="tit_1">건설기준코드 검색</h1>
</div>*/}
<div className="StandardCodeList container">
<div className="c_wrap codeListContent">
<div className="layout">
<div className="contents NOTICE_LIST listTableDiv">
<StandardCodeSearchForm param={listCode?listCode:'10'} reloadFunction={retrieveList} resultCnt={resultCnt} remarkCnt={remarkCnt} downloadModal={downloadModal}/>
<div className="board_list code_list">
<div className="head">
<span>대분류</span>
<span>중분류</span>
<span>코드번호</span>
<span>코드명</span>
<span>개정이력</span>
<span className={"text-start"}>보기</span>
<span>즐겨찾기</span>
</div>
{
listLoading?(<Loading loadingState={true}/>):(
<StandardCodeList listData={listData} filterData={filterData} getHistoryModal={historyModal}/>
)
}
</div>
<Modal size={"lg"} show={show} onHide={close}>
{modalContent}
</Modal>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
);
}
export default StandardCodePage;

View File

@ -1,41 +1,16 @@
import React, {useEffect, useState} from "react";
import {Nav} from "react-bootstrap";
import Row from "react-bootstrap/Row";
import Col from "react-bootstrap/Col";
import {Link} from "react-router-dom";
import Button from "react-bootstrap/Button";
import * as EgovNet from "../../../api/egovFetch";
function StandardCodeSearchForm({param, reloadFunction, resultCnt, remarkCnt, downloadModal}){
function StandardCodeSearchForm({param, reloadFunction}){
const [searchCondition, setSearchCondition] = useState({
pageIndex: 1,
tab: Number(param?.substring(0, 2)),
category1: param?.substring(2, 4),
category2: param?.substring(4, 6),
category3: param?.substring(6, 8),
searchWrd: ''
});
const [subTabsVisible, setSubTabsVisible] = useState(false);
const [cat1SelectOption, setCat1SelectOption] = useState([])
const [cat2SelectOption, setCat2SelectOption] = useState([])
const [cat3SelectOption, setCat3SelectOption] = useState([])
function getSelectBoxOption(groupCd, handler){
EgovNet.requestFetch(
'/standardCode/category-option?listCode='+groupCd,
{
method: "GET",
headers: {
'Content-type': 'application/json',
}
},
handler,
function (resp) {
console.log("err response : ", resp);
}
);
}
useEffect(() => {
if(searchCondition.tab){
if(searchCondition.tab !== 10 && searchCondition.tab !== 20){
@ -47,43 +22,6 @@ function StandardCodeSearchForm({param, reloadFunction, resultCnt, remarkCnt, do
reloadFunction(searchCondition)
}, [searchCondition]);
useEffect(() => {
setSearchCondition({...searchCondition, category1: '', category2: '', category3: ''})
const groupCd = searchCondition.tab;
getSelectBoxOption(groupCd, (resp)=>{
const options = [];
resp.result.groupList.forEach(function (item, index){
options.push(<option value={item.groupCurCd}>{item.groupNm}</option>)
})
setCat1SelectOption(options)
})
}, [searchCondition.tab]);
useEffect(() => {
setSearchCondition({...searchCondition, category2: '', category3: ''})
const groupCd = searchCondition.tab+searchCondition.category1;
getSelectBoxOption(groupCd, (resp)=>{
const options = [];
resp.result.groupList.forEach(function (item, index){
options.push(<option value={item.groupCurCd}>{item.groupNm}</option>)
})
setCat2SelectOption(options)
})
}, [searchCondition.category1]);
useEffect(() => {
setSearchCondition({...searchCondition, category3: ''})
const groupCd = searchCondition.tab+searchCondition.category1+searchCondition.category2;
getSelectBoxOption(groupCd, (resp)=>{
const options = [];
resp.result.groupList.forEach(function (item, index){
options.push(<option value={item.groupCurCd}>{item.groupNm}</option>)
})
setCat3SelectOption(options)
})
}, [searchCondition.category2]);
return (
<>
<div className="condition">
@ -102,61 +40,45 @@ function StandardCodeSearchForm({param, reloadFunction, resultCnt, remarkCnt, do
</li>
<li className="third_1 L">
<label className="f_select" htmlFor="sel1">
<select id="sel1" title="조건" value={searchCondition.category1}
onChange={(e)=>{setSearchCondition({...searchCondition, category1: e.target.value})}}>
<select id="sel1" title="조건" value={searchCondition.category1}>
<option value="">전체</option>
{cat1SelectOption}
</select>
</label>
</li>
<li className="third_1 L">
<label className="f_select w_306" htmlFor="sel1">
<select id="sel2" title="조건" value={searchCondition.category2}
onChange={(e)=>{setSearchCondition({...searchCondition, category2: e.target.value})}}>
<option value="">전체</option>
{cat2SelectOption}
</select>
</label>
</li>
<li className="third_1 L">
<label className="f_select w_306" htmlFor="sel1">
<select id="sel3" title="조건" value={searchCondition.category3}
onChange={(e)=>{setSearchCondition({...searchCondition, category3: e.target.value})}}>
<option value="">전체</option>
{cat3SelectOption}
</select>
</label>
</li>
<li className="third_1 L">
{remarkCnt?(
<span>전체 {resultCnt} / <span className={"text-danger"}>{remarkCnt}</span> </span>
):(
<span>전체 {resultCnt} </span>
)}
</select>
</label>
</li>
<li className="third_1 L">
<div className={`tab`} onClick={downloadModal}>통합 다운로드</div>
<label className="f_select w_306" htmlFor="sel1">
<select id="sel2" title="조건" value={searchCondition.category2}>
<option value="">전체</option>
</select>
</label>
</li>
<li className="third_1 L">
<label className="f_select w_306" htmlFor="sel1">
<select id="sel3" title="조건" value={searchCondition.category3} >
<option value="">전체</option>
</select>
</label>
</li>
<li className="third_1 L">
<div className={`tab`}>통합 다운로드</div>
</li>
</ul>
</div>
<Row className={"justify-content-between"}>
<Col>
{subTabsVisible && (
<Nav className={"tabs"} variant={"tabs"} >
<Nav.Item><Nav.Link className={`${searchCondition.tab === 40 ? 'active' : ''}`} onClick={() => {setSearchCondition({...searchCondition, tab: 40})}}>서울특별시</Nav.Link></Nav.Item>
<Nav.Item><Nav.Link className={`${searchCondition.tab === 50 ? 'active' : ''}`} onClick={() => {setSearchCondition({...searchCondition, tab: 50})}}>고속도로공사</Nav.Link></Nav.Item>
<Nav.Item><Nav.Link className={`${searchCondition.tab === 60 ? 'active' : ''}`} onClick={() => {setSearchCondition({...searchCondition, tab: 60})}}>한국농어촌공사</Nav.Link></Nav.Item>
<Nav.Item><Nav.Link className={`${searchCondition.tab === 70 ? 'active' : ''}`} onClick={() => {setSearchCondition({...searchCondition, tab: 70})}}>철도건설공사</Nav.Link></Nav.Item>
<Nav.Item><Nav.Link className={`${searchCondition.tab === 80 ? 'active' : ''}`} onClick={() => {setSearchCondition({...searchCondition, tab: 80})}}>LH한국토지주택공사</Nav.Link></Nav.Item>
<Nav.Item><Nav.Link className={`${searchCondition.tab === 90 ? 'active' : ''}`} onClick={() => {setSearchCondition({...searchCondition, tab: 90})}}>K-Water</Nav.Link></Nav.Item>
</Nav>
<div className="right_col">
<div className="mini_board">
<ul>
<div className={`tab ${searchCondition.tab === 40 ? 'active' : ''}`} onClick={() => {setSearchCondition({...searchCondition, tab: 40})}}>서울특별시</div>
<div className={`tab ${searchCondition.tab === 50 ? 'active' : ''}`} onClick={() => {setSearchCondition({...searchCondition, tab: 50})}}>고속도로공사</div>
<div className={`tab ${searchCondition.tab === 60 ? 'active' : ''}`} onClick={() => {setSearchCondition({...searchCondition, tab: 60})}}>한국농어촌공사</div>
<div className={`tab ${searchCondition.tab === 70 ? 'active' : ''}`} onClick={() => {setSearchCondition({...searchCondition, tab: 70})}}>철도건설공사</div>
<div className={`tab ${searchCondition.tab === 80 ? 'active' : ''}`} onClick={() => {setSearchCondition({...searchCondition, tab: 80})}}>LH한국토지주택공사</div>
<div className={`tab ${searchCondition.tab === 90 ? 'active' : ''}`} onClick={() => {setSearchCondition({...searchCondition, tab: 90})}}>K-Water</div>
</ul>
</div>
</div>
)}
</Col>
<Col xs={"auto"}>
<Button href={"/standardCode/info"} size={"sm"} variant={"secondary"}>건설기준코드 안내</Button>
</Col>
</Row>
</>
);
}

View File

@ -49,13 +49,17 @@ const BookmarkModal = ({docCode, docPart, ymd}) => {
})
const getCodeInfo = useCallback(() => {
console.groupCollapsed("EgovMain.getCodeInfo()");
EgovNet.requestFetch(
'/standardCode/code-info?docCode='+docCode,
'/standardCode/getCodeInfo.do',
{
method: "GET",
method: "POST",
headers: {
'Content-type': 'application/json'
}
},
body: JSON.stringify({
docCode: docCode
})
},
(resp) => {
const docInfo = resp.result.docInfo;

View File

@ -1,47 +0,0 @@
import React, {useEffect, useState} from "react";
import {SbContainer} from "./Sb.style";
import SbItem from "./SbItem";
import * as EgovNet from "api/egovFetch";
function ViewerTree({docCode, updateDocCode, setTreeLoading}){
const [tree, setTree] = useState([]);
function getCodeTree(){
EgovNet.requestFetch(
'/standardCode/code-tree',
{
method: "GET",
headers: {
'Content-type': 'application/json'
}
},
(resp) => {
const menuData = resp.result.codeTree;
//
// https://garve32.tistory.com/52
const nest = (menuData, parent_seq = null, link = 'parent_seq') =>
menuData.filter(item => item[link] === parent_seq)
.map(item => ({ ...item, childrens: nest(menuData, item.seq) }));
setTree(nest(menuData));
setTreeLoading(false);
},
function (resp) {
console.log("err response : ", resp);
}
);
}
useEffect(() => {
getCodeTree()
}, []);
return (
<SbContainer>
{tree.map((subItem) =>
<SbItem item={subItem} openDocCode={docCode} updateDocCode={updateDocCode} />
)}
</SbContainer>
);
}
export default ViewerTree;

View File

@ -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,21 +10,18 @@ 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 Button from "react-bootstrap/Button";
import {InputGroup} from "react-bootstrap";
import ViewerTree from "./ViewerTree";
import {getLocalItem} from "../../../utils/storage";
import CODE from "../../../constants/code";
import {parseJwt} from "../../../utils/parseJwt";
function CodeViewer(props) {
const [treeLoading, setTreeLoading] = useState(true);
const [docLoading, setDocLoading] = useState(true);
const {linkedDocCode} = useParams();
const [docCode, setDocCode] = useState(linkedDocCode !== undefined?linkedDocCode.split(':')[0]:props.docCode);
const [ymd, setYmd] = useState(linkedDocCode !== undefined?linkedDocCode.split(':')[1]:props.ymd);
const [docInfo, setDocInfo] = useState();
const [codeTree, setCodeTree] = useState();
const [docSummary, setDocSummary] = useState();
const [docDetail, setDocDetail] = useState();
const [errorSelector, setErrorSelector] = useState();
@ -32,8 +29,6 @@ function CodeViewer(props) {
const [show, setShow] = useState(false);
const [bookMarkModal, setBookMarkModal] = useState();
const [colList, setColList] = useState([3,2,7]);
const sessionUser = parseJwt(getLocalItem('accessToken'));
const sessionUserSe = sessionUser?.userSe;
@ -49,21 +44,65 @@ function CodeViewer(props) {
console.log("viewer [docCode] : ", docCode);
const updateDocCode = (docCode)=>{
setDocLoading(true);
setDocSummary([<div></div>])
setDocDetail([<div>불러오는중</div>])
setDocInfo([])
setDocCode(docCode);
getCodeInfo(docCode);
getCodeDetailInfo(docCode);
}
const getCodeTree = ()=>{
EgovNet.requestFetch(
'/standardCode/getCodeTree.do',
{
method: "POST",
headers: {
'Content-type': 'application/json'
},
body: JSON.stringify({})
},
(resp) => {
const menuData = resp.result.codeTree;
// 코드 목록 트리 구성
// https://garve32.tistory.com/52 참고
const nest = (menuData, parent_seq = null, link = 'parent_seq') =>
menuData.filter(item => item[link] === parent_seq)
.map(item => ({ ...item, childrens: nest(menuData, item.seq) }));
const tree = nest(menuData);
let treeTag = [];
if(tree.length>0){
treeTag.push(
<SbContainer>
{tree.map((subItem) =>
<SbItem item={subItem} openDocCode={docCode} updateDocCode={updateDocCode} />
)}
</SbContainer>
)
}else{
treeTag.push(<div>검색된 결과가 없습니다.</div>); // 코드 목록 초기값
}
setCodeTree(treeTag);
setTreeLoading(false);
},
function (resp) {
console.log("err response : ", resp);
}
);
}
const getCodeInfo = useCallback((docCode) => {
console.groupCollapsed("EgovMain.getCodeInfo()");
EgovNet.requestFetch(
'/standardCode/code-info?docCode='+docCode,
'/standardCode/getCodeInfo.do',
{
method: "GET",
method: "POST",
headers: {
'Content-type': 'application/json'
}
},
body: JSON.stringify({
docCode: docCode
})
},
(resp) => {
const docInfo = resp.result.docInfo;
@ -268,7 +307,6 @@ function CodeViewer(props) {
clickBtn.parentElement.querySelector("p").className += " yearInfoActive"
getCodeDetailInfo(clickBtn.dataset.doccode, clickBtn.dataset.ymd);
})
const actionAppend = (el) => {
if(!el) return;
if(el.childNodes.length===0){
@ -382,15 +420,9 @@ function CodeViewer(props) {
}
)
}
function treeControl(){
if(colList[0]===3){
setColList([0,3,9]);
}else{
setColList([3,2,7]);
}
}
useEffect(() => {
getCodeTree();
getCodeInfo(docCode);
getCodeDetailInfo(docCode);
}, []);
@ -399,9 +431,8 @@ function CodeViewer(props) {
console.groupEnd("viewer");
return (
<>
{/*{treeLoading || docLoading? ():()}*/}
<Loading loadingState={treeLoading || docLoading}/>
<Row className={`mx-0 ${treeLoading || docLoading?'d-none':''}`}>
{treeLoading || docLoading? (<Loading/>):(
<Row className="mx-0">
<Col xs={12} className="border-bottom">
<Row>
<Col xs={3}></Col>
@ -412,36 +443,26 @@ function CodeViewer(props) {
<Col xs={"auto"}>{docInfo}</Col>
<Col>
<input type="button" className="btn btn-sm btn-primary optionBtn" value="연혁"/>
<input type="button" className="btn btn-sm btn-primary optionBtn" value="2단비교"/>
<input type="button" className="btn btn-sm btn-primary optionBtn" value="신구조문"/>
<input type="button" className="btn btn-sm btn-primary optionBtn" value="첨부파일"/>
<input type="button" className="btn btn-sm btn-primary optionBtn" value="비교"/>
</Col>
</Row>
</Col>
<Col xs={"auto"}>
<InputGroup>
<Form.Control type="text" size={"sm"} placeholder={"문서 내 검색"}/>
{errorSelector}
</InputGroup>
</Col>
<Col xs={"auto"}>{errorSelector}</Col>
</Row>
</Col>
</Row>
</Col>
<Col xs={colList[0]} className={`border-end viewerDiv ${colList[0]===3?'':'d-none'}`}>
{/*{codeTree}*/}
<ViewerTree docCode={docCode} updateDocCode={updateDocCode} setTreeLoading={setTreeLoading}/>
<Col xs={3} className="border-end viewerDiv">
{codeTree}
</Col>
<Col xs={colList[1]} className="border-end viewerDiv">
<div>
<Button size={"sm"} variant={"outline-secondary"} onClick={treeControl}>{colList[0]===3?'트리 접기':'트리 펼치기'}</Button>
</div>
<Col xs={2} className="border-end viewerDiv">
{docSummary}
</Col>
<Col xs={colList[2]} className="viewerDiv detailInfoDiv" ref={actionAppend}>
<Col xs={7} className="viewerDiv detailInfoDiv" ref={actionAppend}>
{docDetail}
</Col>
</Row>
)}
<Modal show={show} onHide={handleClose} size="xl" keyboard={false} scrollable>
{bookMarkModal}
</Modal>
@ -450,8 +471,8 @@ function CodeViewer(props) {
}
CodeViewer.defaultProps = {
docCode: 'KDS 11 10 15',
docName: '지반계측'
docCode: 'KCS 24 31 10',
docName: '용접(한계상태설계법)'
}
export default CodeViewer;

View File

@ -47,8 +47,8 @@ import EgovGalleryEdit from 'pages/inform/gallery/EgovGalleryEdit';
//ADMIN
import EgovAdminScheduleList from 'pages/admin/schedule/EgovAdminScheduleList';
// import EgovAdminScheduleDetail from 'pages/admin/schedule/EgovAdminScheduleDetail';
// import EgovAdminScheduleEdit from 'pages/admin/schedule/EgovAdminScheduleEdit';
import EgovAdminScheduleDetail from 'pages/admin/schedule/EgovAdminScheduleDetail';
import EgovAdminScheduleEdit from 'pages/admin/schedule/EgovAdminScheduleEdit';
import EgovAdminBoardList from 'pages/admin/board/EgovAdminBoardList';
import EgovAdminBoardEdit from 'pages/admin/board/EgovAdminBoardEdit';
@ -94,7 +94,7 @@ import AdminContentsPopUp from 'pages/admin/contents/PopUp';
import AdminContentsPopUpEditor from 'pages/admin/contents/PopUp/PopupEditor'; // - / /
import AdminContentsStandardResearch from 'pages/admin/contents/StandardResearch'; // - /
import AdminContentsStandardResearchEditor from 'pages/admin/contents/StandardResearch/StandardResearchEditor'; // / /
// import AdminContentsTextMessages from 'pages/admin/contents/TextMessages'; // - /
import AdminContentsTextMessages from 'pages/admin/contents/TextMessages'; // - /
// -
import AdminCommitteeProgressStatus from 'pages/admin/committee/ProgressStatus'; // - /
@ -110,13 +110,11 @@ import AdminLogsFileDownloadStatus from 'pages/admin/logs/FileDownloadStatus';
//
import CodeViewer from 'pages/standardCode/viewer/CodeViewer';
import StandardCodePage from "../pages/standardCode/list/StandardCodePage";
import StandardCodeInfo from "../pages/standardCode/info/StandardCodeInfo";
import CodeViewer from 'pages/standardCode/viewer/viewer';
import * as EgovNet from 'api/egovFetch'; // jwt
import initPage from 'js/ui';
import StandardCodeList from "../pages/standardCode/list/StandardCodeList";
const RootRoutes = () => {
//useLocation /admin/~ ( 1) */}
@ -138,8 +136,6 @@ const RootRoutes = () => {
(resp) => {
if (resp === false) {
setMounted(false);
alert("관리자 전용 페이지입니다.")
window.location.href="/";
} else {
setMounted(true); // true .
}
@ -252,9 +248,9 @@ const SecondRoutes = () => {
{/* ADMIN */}
<Route path={URL.ADMIN} element={<Navigate to={URL.ADMIN_SCHEDULE} />} />
<Route path={URL.ADMIN_SCHEDULE} element={<EgovAdminScheduleList />} />
{/*<Route path={URL.ADMIN_SCHEDULE_DETAIL} element={<EgovAdminScheduleDetail />} />*/}
{/*<Route path={URL.ADMIN_SCHEDULE_CREATE} element={<EgovAdminScheduleEdit mode={CODE.MODE_CREATE} />} />*/}
{/*<Route path={URL.ADMIN_SCHEDULE_MODIFY} element={<EgovAdminScheduleEdit mode={CODE.MODE_MODIFY} />} />*/}
<Route path={URL.ADMIN_SCHEDULE_DETAIL} element={<EgovAdminScheduleDetail />} />
<Route path={URL.ADMIN_SCHEDULE_CREATE} element={<EgovAdminScheduleEdit mode={CODE.MODE_CREATE} />} />
<Route path={URL.ADMIN_SCHEDULE_MODIFY} element={<EgovAdminScheduleEdit mode={CODE.MODE_MODIFY} />} />
<Route path={URL.ADMIN_BOARD} element={<EgovAdminBoardList />} />
<Route path={URL.ADMIN_BOARD_CREATE} element={<EgovAdminBoardEdit mode={CODE.MODE_CREATE} />} />
@ -308,7 +304,7 @@ const SecondRoutes = () => {
<Route path={URL.ADMIN__CONTENTS__STANDARDS_RESEARCH} element={<AdminContentsStandardResearch />} />
<Route path={URL.ADMIN__CONTENTS__STANDARDS_RESEARCH__CREATE} element={<AdminContentsStandardResearchEditor mode={CODE.MODE_CREATE} />} />
<Route path={URL.ADMIN__CONTENTS__STANDARDS_RESEARCH__MODIFY} element={<AdminContentsStandardResearchEditor mode={CODE.MODE_MODIFY} />} />
{/*<Route path={URL.ADMIN__CONTENTS__TEXT_MESSAGES} element={<AdminContentsTextMessages />} />*/}
<Route path={URL.ADMIN__CONTENTS__TEXT_MESSAGES} element={<AdminContentsTextMessages />} />
{/* 관리자 - 위원회 관리 */}
<Route path={URL.ADMIN__COMMITTEE__PROGRESS_STATUS} element={<AdminCommitteeProgressStatus />} />
@ -331,10 +327,9 @@ const SecondRoutes = () => {
<Route path={URL.STANDARD_CODE_VIEWER} element={<CodeViewer mode={CODE.MODE_READ} />} />
<Route path={URL.STANDARD_CODE_VIEWER_LINK} element={<CodeViewer mode={CODE.MODE_READ} />} />
<Route path={URL.STANDARD_CODE_INFO} element={<StandardCodeInfo />} />
{/*기준코드리스트*/}
<Route path={URL.STANDARD_CODE_LIST} element={<StandardCodePage />} />
<Route path={URL.STANDARD_CODE_LIST_LINK} element={<StandardCodePage />} />
<Route path={URL.STANDARD_CODE_LIST} element={<StandardCodeList />} />
<Route path={URL.STANDARD_CODE_LIST_LINK} element={<StandardCodeList />} />
</Routes>
<EgovFooter />

View File

@ -1,64 +0,0 @@
import PropTypes from 'prop-types';
import { useMemo } from 'react';
// material-ui
import { CssBaseline, StyledEngineProvider } from '@mui/material';
import { createTheme, ThemeProvider } from '@mui/material/styles';
// project import
import Palette from './palette';
import Typography from './typography';
import CustomShadows from './shadows';
import componentsOverride from './overrides';
// ==============================|| DEFAULT THEME - MAIN ||============================== //
export default function ThemeCustomization({ children }) {
const theme = Palette('light', 'default');
// eslint-disable-next-line react-hooks/exhaustive-deps
const themeTypography = Typography(`'Public Sans', sans-serif`);
const themeCustomShadows = useMemo(() => CustomShadows(theme), [theme]);
const themeOptions = useMemo(
() => ({
breakpoints: {
values: {
xs: 0,
sm: 768,
md: 1024,
lg: 1266,
xl: 1536
}
},
direction: 'ltr',
mixins: {
toolbar: {
minHeight: 60,
paddingTop: 8,
paddingBottom: 8
}
},
palette: theme.palette,
customShadows: themeCustomShadows,
typography: themeTypography
}),
[theme, themeTypography, themeCustomShadows]
);
const themes = createTheme(themeOptions);
themes.components = componentsOverride(themes);
return (
<StyledEngineProvider injectFirst>
<ThemeProvider theme={themes}>
<CssBaseline />
{children}
</ThemeProvider>
</StyledEngineProvider>
);
}
ThemeCustomization.propTypes = {
children: PropTypes.node
};

View File

@ -1,15 +0,0 @@
// ==============================|| OVERRIDES - BADGE ||============================== //
export default function Badge(theme) {
return {
MuiBadge: {
styleOverrides: {
standard: {
minWidth: theme.spacing(2),
height: theme.spacing(2),
padding: theme.spacing(0.5)
}
}
}
};
}

View File

@ -1,28 +0,0 @@
// ==============================|| OVERRIDES - BUTTON ||============================== //
export default function Button(theme) {
const disabledStyle = {
'&.Mui-disabled': {
backgroundColor: theme.palette.grey[200]
}
};
return {
MuiButton: {
defaultProps: {
disableElevation: true
},
styleOverrides: {
root: {
fontWeight: 400
},
contained: {
...disabledStyle
},
outlined: {
...disabledStyle
}
}
}
};
}

View File

@ -1,16 +0,0 @@
// ==============================|| OVERRIDES - CARD CONTENT ||============================== //
export default function CardContent() {
return {
MuiCardContent: {
styleOverrides: {
root: {
padding: 20,
'&:last-child': {
paddingBottom: 20
}
}
}
}
};
}

View File

@ -1,13 +0,0 @@
// ==============================|| OVERRIDES - CHECKBOX ||============================== //
export default function Checkbox(theme) {
return {
MuiCheckbox: {
styleOverrides: {
root: {
color: theme.palette.secondary[300]
}
}
}
};
}

View File

@ -1,40 +0,0 @@
// ==============================|| OVERRIDES - CHIP ||============================== //
export default function Chip(theme) {
return {
MuiChip: {
styleOverrides: {
root: {
borderRadius: 4,
'&:active': {
boxShadow: 'none'
}
},
sizeLarge: {
fontSize: '1rem',
height: 40
},
light: {
color: theme.palette.primary.main,
backgroundColor: theme.palette.primary.lighter,
borderColor: theme.palette.primary.light,
'&.MuiChip-lightError': {
color: theme.palette.error.main,
backgroundColor: theme.palette.error.lighter,
borderColor: theme.palette.error.light
},
'&.MuiChip-lightSuccess': {
color: theme.palette.success.main,
backgroundColor: theme.palette.success.lighter,
borderColor: theme.palette.success.light
},
'&.MuiChip-lightWarning': {
color: theme.palette.warning.main,
backgroundColor: theme.palette.warning.lighter,
borderColor: theme.palette.warning.light
}
}
}
}
};
}

View File

@ -1,28 +0,0 @@
// ==============================|| OVERRIDES - ICON BUTTON ||============================== //
export default function IconButton(theme) {
return {
MuiIconButton: {
styleOverrides: {
root: {
borderRadius: 4
},
sizeLarge: {
width: theme.spacing(5.5),
height: theme.spacing(5.5),
fontSize: '1.25rem'
},
sizeMedium: {
width: theme.spacing(4.5),
height: theme.spacing(4.5),
fontSize: '1rem'
},
sizeSmall: {
width: theme.spacing(3.75),
height: theme.spacing(3.75),
fontSize: '0.75rem'
}
}
}
};
}

View File

@ -1,25 +0,0 @@
// ==============================|| OVERRIDES - INPUT LABEL ||============================== //
export default function InputLabel(theme) {
return {
MuiInputLabel: {
styleOverrides: {
root: {
color: theme.palette.grey[600]
},
outlined: {
lineHeight: '0.8em',
'&.MuiInputLabel-sizeSmall': {
lineHeight: '1em'
},
'&.MuiInputLabel-shrink': {
background: theme.palette.background.paper,
padding: '0 8px',
marginLeft: -6,
lineHeight: '1.4375em'
}
}
}
}
};
}

View File

@ -1,17 +0,0 @@
// ==============================|| OVERRIDES - LINER PROGRESS ||============================== //
export default function LinearProgress() {
return {
MuiLinearProgress: {
styleOverrides: {
root: {
height: 6,
borderRadius: 100
},
bar: {
borderRadius: 100
}
}
}
};
}

View File

@ -1,11 +0,0 @@
// ==============================|| OVERRIDES - LINK ||============================== //
export default function Link() {
return {
MuiLink: {
defaultProps: {
underline: 'hover'
}
}
};
}

View File

@ -1,13 +0,0 @@
// ==============================|| OVERRIDES - LIST ITEM ICON ||============================== //
export default function ListItemIcon() {
return {
MuiListItemIcon: {
styleOverrides: {
root: {
minWidth: 24
}
}
}
};
}

View File

@ -1,47 +0,0 @@
// material-ui
import { alpha } from '@mui/material/styles';
// ==============================|| OVERRIDES - OUTLINED INPUT ||============================== //
export default function OutlinedInput(theme) {
return {
MuiOutlinedInput: {
styleOverrides: {
input: {
padding: '10.5px 14px 10.5px 12px'
},
notchedOutline: {
borderColor: theme.palette.grey[300]
},
root: {
'&:hover .MuiOutlinedInput-notchedOutline': {
borderColor: theme.palette.primary.light
},
'&.Mui-focused': {
boxShadow: `0 0 0 2px ${alpha(theme.palette.primary.main, 0.2)}`,
'& .MuiOutlinedInput-notchedOutline': {
border: `1px solid ${theme.palette.primary.light}`
}
},
'&.Mui-error': {
'&:hover .MuiOutlinedInput-notchedOutline': {
borderColor: theme.palette.error.light
},
'&.Mui-focused': {
boxShadow: `0 0 0 2px ${alpha(theme.palette.error.main, 0.2)}`,
'& .MuiOutlinedInput-notchedOutline': {
border: `1px solid ${theme.palette.error.light}`
}
}
}
},
inputSizeSmall: {
padding: '7.5px 8px 7.5px 12px'
},
inputMultiline: {
padding: 0
}
}
}
};
}

View File

@ -1,14 +0,0 @@
// ==============================|| OVERRIDES - TAB ||============================== //
export default function Tab(theme) {
return {
MuiTab: {
styleOverrides: {
root: {
minHeight: 46,
color: theme.palette.text.primary
}
}
}
};
}

View File

@ -1,20 +0,0 @@
// ==============================|| OVERRIDES - TABLE CELL ||============================== //
export default function TableCell(theme) {
return {
MuiTableCell: {
styleOverrides: {
root: {
fontSize: '0.875rem',
padding: 12,
borderColor: theme.palette.divider
},
head: {
fontWeight: 600,
paddingTop: 20,
paddingBottom: 20
}
}
}
};
}

View File

@ -1,13 +0,0 @@
// ==============================|| OVERRIDES - TABS ||============================== //
export default function Tabs() {
return {
MuiTabs: {
styleOverrides: {
vertical: {
overflow: 'visible'
}
}
}
};
}

View File

@ -1,13 +0,0 @@
// ==============================|| OVERRIDES - TYPOGRAPHY ||============================== //
export default function Typography() {
return {
MuiTypography: {
styleOverrides: {
gutterBottom: {
marginBottom: 12
}
}
}
};
}

View File

@ -1,41 +0,0 @@
// third-party
import { merge } from 'lodash';
// project import
import Badge from './Badge';
import Button from './Button';
import CardContent from './CardContent';
import Checkbox from './Checkbox';
import Chip from './Chip';
import IconButton from './IconButton';
import InputLabel from './InputLabel';
import LinearProgress from './LinearProgress';
import Link from './Link';
import ListItemIcon from './ListItemIcon';
import OutlinedInput from './OutlinedInput';
import Tab from './Tab';
import TableCell from './TableCell';
import Tabs from './Tabs';
import Typography from './Typography';
// ==============================|| OVERRIDES - MAIN ||============================== //
export default function ComponentsOverrides(theme) {
return merge(
Button(theme),
Badge(theme),
CardContent(),
Checkbox(theme),
Chip(theme),
IconButton(theme),
InputLabel(theme),
LinearProgress(),
Link(),
ListItemIcon(),
OutlinedInput(theme),
Tab(theme),
TableCell(theme),
Tabs(),
Typography()
);
}

View File

@ -1,60 +0,0 @@
// material-ui
import { createTheme } from '@mui/material/styles';
// third-party
import { presetPalettes } from '@ant-design/colors';
// project import
import ThemeOption from './theme';
// ==============================|| DEFAULT THEME - PALETTE ||============================== //
const Palette = (mode) => {
const colors = presetPalettes;
const greyPrimary = [
'#ffffff',
'#fafafa',
'#f5f5f5',
'#f0f0f0',
'#d9d9d9',
'#bfbfbf',
'#8c8c8c',
'#595959',
'#262626',
'#141414',
'#000000'
];
const greyAscent = ['#fafafa', '#bfbfbf', '#434343', '#1f1f1f'];
const greyConstant = ['#fafafb', '#e6ebf1'];
colors.grey = [...greyPrimary, ...greyAscent, ...greyConstant];
const paletteColor = ThemeOption(colors);
return createTheme({
palette: {
mode,
common: {
black: '#000',
white: '#fff'
},
...paletteColor,
text: {
primary: paletteColor.grey[700],
secondary: paletteColor.grey[500],
disabled: paletteColor.grey[400]
},
action: {
disabled: paletteColor.grey[300]
},
divider: paletteColor.grey[200],
background: {
paper: paletteColor.grey[0],
// default: paletteColor.grey.A50 // 뒷배경 색이 깔려서 주석처리함
}
}
});
};
export default Palette;

View File

@ -1,13 +0,0 @@
// material-ui
import { alpha } from '@mui/material/styles';
// ==============================|| DEFAULT THEME - CUSTOM SHADOWS ||============================== //
const CustomShadows = (theme) => ({
button: `0 2px #0000000b`,
text: `0 -1px 0 rgb(0 0 0 / 12%)`,
z1: `0px 2px 8px ${alpha(theme.palette.grey[900], 0.15)}`
// only available in paid version
});
export default CustomShadows;

View File

@ -1,92 +0,0 @@
// ==============================|| PRESET THEME - THEME SELECTOR ||============================== //
const Theme = (colors) => {
const { blue, red, gold, cyan, green, grey } = colors;
const greyColors = {
0: grey[0],
50: grey[1],
100: grey[2],
200: grey[3],
300: grey[4],
400: grey[5],
500: grey[6],
600: grey[7],
700: grey[8],
800: grey[9],
900: grey[10],
A50: grey[15],
A100: grey[11],
A200: grey[12],
A400: grey[13],
A700: grey[14],
A800: grey[16]
};
const contrastText = '#fff';
return {
primary: {
lighter: blue[0],
100: blue[1],
200: blue[2],
light: blue[3],
400: blue[4],
main: blue[5],
dark: blue[6],
700: blue[7],
darker: blue[8],
900: blue[9],
contrastText
},
secondary: {
lighter: greyColors[100],
100: greyColors[100],
200: greyColors[200],
light: greyColors[300],
400: greyColors[400],
main: greyColors[500],
600: greyColors[600],
dark: greyColors[700],
800: greyColors[800],
darker: greyColors[900],
A100: greyColors[0],
A200: greyColors.A400,
A300: greyColors.A700,
contrastText: greyColors[0]
},
error: {
lighter: red[0],
light: red[2],
main: red[4],
dark: red[7],
darker: red[9],
contrastText
},
warning: {
lighter: gold[0],
light: gold[3],
main: gold[5],
dark: gold[7],
darker: gold[9],
contrastText: greyColors[100]
},
info: {
lighter: cyan[0],
light: cyan[3],
main: cyan[5],
dark: cyan[7],
darker: cyan[9],
contrastText
},
success: {
lighter: green[0],
light: green[3],
main: green[5],
dark: green[7],
darker: green[9],
contrastText
},
grey: greyColors
};
};
export default Theme;

View File

@ -1,71 +0,0 @@
// ==============================|| DEFAULT THEME - TYPOGRAPHY ||============================== //
const Typography = (fontFamily) => ({
htmlFontSize: 16,
fontFamily,
fontWeightLight: 300,
fontWeightRegular: 400,
fontWeightMedium: 500,
fontWeightBold: 600,
h1: {
fontWeight: 600,
fontSize: '2.375rem',
lineHeight: 1.21
},
h2: {
fontWeight: 600,
fontSize: '1.875rem',
lineHeight: 1.27
},
h3: {
fontWeight: 600,
fontSize: '1.5rem',
lineHeight: 1.33
},
h4: {
fontWeight: 600,
fontSize: '1.25rem',
lineHeight: 1.4
},
h5: {
fontWeight: 600,
fontSize: '1rem',
lineHeight: 1.5
},
h6: {
fontWeight: 400,
fontSize: '0.875rem',
lineHeight: 1.57
},
caption: {
fontWeight: 400,
fontSize: '0.75rem',
lineHeight: 1.66
},
body1: {
fontSize: '0.875rem',
lineHeight: 1.57
},
body2: {
fontSize: '0.75rem',
lineHeight: 1.66
},
subtitle1: {
fontSize: '0.875rem',
fontWeight: 600,
lineHeight: 1.57
},
subtitle2: {
fontSize: '0.75rem',
fontWeight: 500,
lineHeight: 1.66
},
overline: {
lineHeight: 1.66
},
button: {
textTransform: 'capitalize'
}
});
export default Typography;

View File

@ -1,19 +0,0 @@
import PropTypes from 'prop-types';
// third-party
import SyntaxHighlighter from 'react-syntax-highlighter';
import { a11yDark } from 'react-syntax-highlighter/dist/esm/styles/hljs';
// ==============================|| CODE HIGHLIGHTER ||============================== //
export default function SyntaxHighlight({ children, ...others }) {
return (
<SyntaxHighlighter language="javacript" showLineNumbers style={a11yDark} {...others}>
{children}
</SyntaxHighlighter>
);
}
SyntaxHighlight.propTypes = {
children: PropTypes.node
};

File diff suppressed because it is too large Load Diff

View File

@ -1,11 +1,7 @@
package com.dbnt.kcscbackend.admin.boards;
import com.dbnt.kcscbackend.admin.boards.entity.TnBbs;
import com.dbnt.kcscbackend.admin.boards.service.AdminBoardsService;
import com.dbnt.kcscbackend.admin.config.entity.TcMenu;
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;
@ -13,27 +9,21 @@ 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.validation.Errors;
import org.springframework.validation.FieldError;
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 javax.validation.Valid;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequiredArgsConstructor
@RequestMapping("/admin/boards")
@Tag(name = "AdminBoardsController", description = "사이트관리 게시판현황")
@Tag(name="AdminBoardsController", description = "사이트관리 게시판현황")
public class AdminBoardsController extends BaseController {
private final AdminBoardsService adminBoardsService;
/* ---- 게시판관리 ----- */
@Operation(
summary = "게시판 목록 조회",
description = "게시판 목록 조회",
@ -52,82 +42,4 @@ public class AdminBoardsController extends BaseController {
resultVO.setResult(resultMap);
return resultVO;
}
@Operation(
summary = "게시판 저장",
description = "게시판 저장",
tags = {"AdminBoardsController"}
)
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "저장 성공"),
@ApiResponse(responseCode = "403", description = "인가된 사용자가 아님")
})
@RequestMapping(method = RequestMethod.PUT, value = "/board-mgt")
public ResultVO saveBoardMgt(@RequestBody @Valid TnBbs bbs, Errors errors, @AuthenticationPrincipal LoginVO user) {
ResultVO resultVO = new ResultVO();
if (user == null) {
resultVO.setResultCode(ResponseCode.TOKEN_EXPIRED.getCode());
} else {
if (errors.hasErrors()) {
StringBuilder msg = new StringBuilder();
for (FieldError error : errors.getFieldErrors()) {
msg.append(error.getDefaultMessage());
msg.append("\n");
}
resultVO.setResultCode(ResponseCode.INPUT_CHECK_ERROR.getCode());
resultVO.setResultMessage(msg.toString());
} else {
System.out.println("@@@ bbs.getBbsSeq() : " + bbs.getBbsSeq());
adminBoardsService.saveBoard(bbs, user.getId());
resultVO.setResultCode(ResponseCode.SUCCESS.getCode());
}
}
return resultVO;
}
@Operation(
summary = "게시판 삭제",
description = "게시판 삭제",
tags = {"AdminBoardsController"}
)
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "삭제 성공"),
@ApiResponse(responseCode = "403", description = "인가된 사용자가 아님")
})
@RequestMapping(method = RequestMethod.DELETE, value = "/board-mgt")
public ResultVO removeBoardMgt(@RequestBody TnBbs bbs, @AuthenticationPrincipal LoginVO user) {
ResultVO resultVO = new ResultVO();
if (user == null) {
resultVO.setResultCode(ResponseCode.TOKEN_EXPIRED.getCode());
} else {
String result = adminBoardsService.deleteBoard(bbs, user.getId());
if (result == null) {
resultVO.setResultCode(ResponseCode.SUCCESS.getCode());
} else if (result.equals("notFind")) {
resultVO.setResultCode(ResponseCode.SAVE_ERROR.getCode());
resultVO.setResultMessage("대상이 존재하지 않습니다.");
}
}
return resultVO;
}
/* ---- 게시물관리 ----- */
@Operation(
summary = "게시물 목록 조회",
description = "게시물 목록 조회",
tags = {"AdminBoardsController"}
)
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "조회 성공"),
@ApiResponse(responseCode = "403", description = "인가된 사용자가 아님")
})
@RequestMapping(method = RequestMethod.GET, value = "/post-list", consumes = MediaType.APPLICATION_JSON_VALUE)
public ResultVO getPostList() throws Exception {
ResultVO resultVO = new ResultVO();
Map<String, Object> resultMap = new HashMap<>();
resultMap.put("boardList", adminBoardsService.selectBoardList());
resultVO.setResult(resultMap);
return resultVO;
}
}

View File

@ -6,8 +6,7 @@ import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;
import javax.persistence.*;
import javax.validation.constraints.NotBlank;
import java.time.LocalDateTime;
import java.time.LocalDate;
@Getter
@Setter
@ -23,25 +22,22 @@ public class TnBbs {
private Long bbsSeq;
@Column(name = "bbs_id", nullable = false)
@NotBlank(message = "게시판 ID를 입력해주세요.")
private String bbsId;
@Column(name = "bbs_title", nullable = false)
@NotBlank(message = "게시판 이름을 입력해주세요.")
private String bbsTitle;
@Column(name = "bbs_desc")
@NotBlank(message = "게시판 설명을 입력해주세요.")
private String bbsDesc;
@Column(name = "bbs_type")
private String bbsType;
@Column(name = "bbs_ans_yn", nullable = false)
private String bbsAnsYn;
private char bbsAnsYn;
@Column(name = "bbs_repl_yn", nullable = false)
private String bbsReplYn;
private char bbsReplYn;
@Column(name = "read_role_grp_id")
private String readRoleGrpId;
@ -56,16 +52,16 @@ public class TnBbs {
private String frstCrtId;
@Column(name = "frst_crt_dt", nullable = false)
private LocalDateTime frstCrtDt;
private LocalDate frstCrtDt;
@Column(name = "last_chg_id")
private String lastChgId;
@Column(name = "last_chg_dt")
private LocalDateTime lastChgDt;
private LocalDate lastChgDt;
@Column(name = "use_yn", nullable = false)
private String useYn;
private char useYn;
@Column(name = "oldd_seq")
private Long olddSeq;

View File

@ -1,83 +0,0 @@
package com.dbnt.kcscbackend.admin.boards.entity;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;
import javax.persistence.*;
import java.time.LocalDateTime;
@Getter
@Setter
@Entity
@NoArgsConstructor
@DynamicInsert
@DynamicUpdate
@Table(name = "tn_bbs_contents")
public class TnBbsContents {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "bbs_cont_seq")
private Integer bbsContSeq;
@Column(name = "bbs_seq", nullable = false)
private Integer bbsSeq;
@Column(name = "bbs_cont_title")
private String bbsContTitle;
@Column(name = "bbs_contents", columnDefinition = "TEXT")
private String bbsContents;
@Column(name = "bbs_cont_seq_group")
private Integer bbsContSeqGroup;
@Column(name = "bbs_cont_seq_parent")
private Integer bbsContSeqParent;
@Column(name = "bbs_cont_level", nullable = false)
private Integer bbsContLevel;
@Column(name = "bbs_cont_sort")
private Integer bbsContSort;
@Column(name = "file_grp_id")
private String fileGrpId;
@Column(name = "bbs_read_cnt", nullable = false)
private Integer bbsReadCnt;
@Column(name = "fixed_yn", nullable = false)
private String fixedYn;
@Column(name = "secret_yn", nullable = false)
private String secretYn;
@Column(name = "secret_pwd")
private String secretPwd;
@Column(name = "doc_info_seq")
private Integer docInfoSeq;
@Column(name = "ip_address", nullable = false)
private String ipAddress;
@Column(name = "frst_crt_id", nullable = false)
private String frstCrtId;
@Column(name = "frst_crt_dt", nullable = false)
private LocalDateTime frstCrtDt;
@Column(name = "last_chg_id")
private String lastChgId;
@Column(name = "last_chg_dt")
private LocalDateTime lastChgDt;
@Column(name = "use_yn", nullable = false)
private String useYn;
@Column(name = "old_seq")
private Integer oldSeq;
}

View File

@ -1,8 +0,0 @@
package com.dbnt.kcscbackend.admin.boards.repository;
import com.dbnt.kcscbackend.admin.boards.entity.TnBbsContents;
import org.springframework.data.jpa.repository.JpaRepository;
public interface TnBbsContentsRepository extends JpaRepository<TnBbsContents, Long> {
}

View File

@ -2,13 +2,7 @@ package com.dbnt.kcscbackend.admin.boards.repository;
import com.dbnt.kcscbackend.admin.boards.entity.TnBbs;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import java.util.List;
public interface TnBbsRepository extends JpaRepository<TnBbs, Long> {
@Query(value = "SELECT * FROM tn_bbs WHERE use_yn = 'Y' ORDER BY bbs_seq DESC", nativeQuery = true)
List<TnBbs> findAllByOrderByBbsSeqDesc();
}

View File

@ -1,71 +1,19 @@
package com.dbnt.kcscbackend.admin.boards.service;
import com.dbnt.kcscbackend.admin.boards.entity.TnBbs;
import com.dbnt.kcscbackend.admin.boards.entity.TnBbsContents;
import com.dbnt.kcscbackend.admin.boards.repository.TnBbsContentsRepository;
import com.dbnt.kcscbackend.admin.boards.repository.TnBbsRepository;
import com.dbnt.kcscbackend.admin.config.entity.TcMenu;
import lombok.RequiredArgsConstructor;
import org.egovframe.rte.fdl.cmmn.EgovAbstractServiceImpl;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
@Service
@RequiredArgsConstructor
public class AdminBoardsService extends EgovAbstractServiceImpl {
private final TnBbsRepository tnBbsRepository;
private final TnBbsContentsRepository tnBbsContentsRepository;
public List<TnBbs> selectBoardList() {
return tnBbsRepository.findAllByOrderByBbsSeqDesc();
}
public Optional<TnBbs> selectBoard(Long bbsSeq) {
return tnBbsRepository.findById(bbsSeq);
}
@Transactional
public void saveBoard(TnBbs bbs, String userId) {
if (bbs.getBbsSeq() == null) {
bbs.setFrstCrtDt(LocalDateTime.now());
bbs.setFrstCrtId(userId);
bbs.setBbsAnsYn("N");
bbs.setBbsReplYn("N");
bbs.setUseYn("Y");
tnBbsRepository.save(bbs);
} else {
TnBbs savedBoard = tnBbsRepository.findById(bbs.getBbsSeq()).orElse(null);
savedBoard.setBbsId(bbs.getBbsId());
savedBoard.setBbsTitle(bbs.getBbsTitle());
savedBoard.setBbsDesc(bbs.getBbsDesc());
//savedBoard.setUseYn("Y");
savedBoard.setLastChgId(userId);
savedBoard.setLastChgDt(LocalDateTime.now());
tnBbsRepository.save(savedBoard);
}
}
@Transactional
public String deleteBoard(TnBbs bbs, String userId) {
TnBbs savedBoard = tnBbsRepository.findById(bbs.getBbsSeq()).orElse(null);
if (savedBoard == null) {
return "notFind";
} else {
savedBoard.setUseYn("N");
savedBoard.setLastChgDt(LocalDateTime.now());
savedBoard.setLastChgId(userId);
tnBbsRepository.save(savedBoard);
return null;
}
}
public List<TnBbsContents> selectPostList() {
return tnBbsContentsRepository.findAll();
}
public List<TnBbs> selectBoardList() { return tnBbsRepository.findAll(); }
}

View File

@ -1,8 +1,6 @@
package com.dbnt.kcscbackend.admin.config;
import com.dbnt.kcscbackend.admin.config.entity.TcMenu;
import com.dbnt.kcscbackend.admin.config.service.AdminCommitteeCodeManagementService;
import com.dbnt.kcscbackend.admin.standardResearch.service.AdminStandardResearchService;
import com.dbnt.kcscbackend.commonCode.entity.TcCodeGrp;
import com.dbnt.kcscbackend.commonCode.entity.TcCodeItem;
import com.dbnt.kcscbackend.admin.config.service.AdminConfigService;
@ -11,21 +9,20 @@ import com.dbnt.kcscbackend.commonCode.service.CommonCodeService;
import com.dbnt.kcscbackend.config.common.BaseController;
import com.dbnt.kcscbackend.config.common.ResponseCode;
import com.dbnt.kcscbackend.config.common.ResultVO;
import io.swagger.annotations.ApiParam;
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.data.domain.Pageable;
import org.springframework.http.MediaType;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.validation.Errors;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.*;
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 javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.time.LocalDateTime;
import java.util.HashMap;
@ -40,9 +37,6 @@ public class AdminConfigController extends BaseController {
private final AdminConfigService adminConfigService;
private final CommonCodeService commonCodeService;
@Resource(name = "adminCommitteeCodeManagementService")
private AdminCommitteeCodeManagementService adminCommitteeCodeManagementService;
@Operation(
summary = "기본코드 그룹 조회",
description = "기본코드 그룹 조회",
@ -356,50 +350,4 @@ public class AdminConfigController extends BaseController {
return resultVO;
}
@Operation(
summary = "'위원회 코드 관리' 페이지에서 목록 불러오는 API",
description = "관리자 단에서 '환경설정' > '위원회코드 관리' 페이지에서 목록 불러오는 API",
tags = {"AdminConfigController"}
)
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "조회 성공"),
@ApiResponse(responseCode = "303", description = "만료된 토큰"),
@ApiResponse(responseCode = "403", description = "인가된 사용자가 아님")
})
@GetMapping(value = "/committee-code-management")
public ResultVO getCommitteeCodeManagement(
@AuthenticationPrincipal LoginVO user,
HttpServletRequest request,
@ApiParam(value="상위 code") @RequestParam(required=true) String paramCodeGroup,
@ApiParam(value="code level") @RequestParam(required=true) String paramCodeLevel
) throws Exception {
ResultVO resultVO = new ResultVO();
if(user == null) {
resultVO.setResultCode(ResponseCode.TOKEN_EXPIRED.getCode());
} else {
try {
Long upCmtSeq = null;
if (!paramCodeGroup.equals("null")) {
upCmtSeq = Long.parseLong(paramCodeGroup);
}
resultVO = adminCommitteeCodeManagementService.getCommitteeCodeManagement(resultVO, request, user, upCmtSeq, paramCodeLevel);
} catch (Exception e) {
resultVO.setResultCode(ResponseCode.FAILED.getCode());
resultVO.setResultMessage(e.getMessage());
}
}
System.out.println(
"\n--------------------------------------------------------------\n" +
request.getRequestURI() + " OUT:" +
"\n--------------------------------------------------------------\n" +
"resultVO.toString():" + "\n" +
resultVO.toString() + "\n" +
"\n--------------------------------------------------------------\n"
);
return resultVO;
}
}

View File

@ -1,20 +0,0 @@
package com.dbnt.kcscbackend.admin.config.service;
import com.dbnt.kcscbackend.admin.standardResearch.model.CreateStandardResearchVO;
import com.dbnt.kcscbackend.admin.standardResearch.model.UpdateStandardResearchVO;
import com.dbnt.kcscbackend.auth.entity.LoginVO;
import com.dbnt.kcscbackend.config.common.ResultVO;
import io.swagger.annotations.ApiParam;
import org.springframework.data.domain.Pageable;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import javax.servlet.http.HttpServletRequest;
public interface AdminCommitteeCodeManagementService {
public ResultVO createCommitteeCodeManagement(ResultVO resultVO, HttpServletRequest request, LoginVO user, final MultipartHttpServletRequest multiRequest, CreateStandardResearchVO createStandardResearchVO) throws Exception;
public ResultVO getCommitteeCodeManagement(ResultVO resultVO, HttpServletRequest request, LoginVO user, Long upCmtSeq, String cmtType) throws Exception;
public ResultVO setCommitteeCodeManagement(ResultVO resultVO, HttpServletRequest request, LoginVO user, UpdateStandardResearchVO updateStandardResearchVO, Long popupId) throws Exception;
public ResultVO deleteCommitteeCodeManagement(ResultVO resultVO, HttpServletRequest request, LoginVO user, Long popupId) throws Exception;
}

View File

@ -1,75 +0,0 @@
package com.dbnt.kcscbackend.admin.config.service.impl;
import com.dbnt.kcscbackend.admin.config.service.AdminCommitteeCodeManagementService;
import com.dbnt.kcscbackend.admin.standardResearch.model.CreateStandardResearchVO;
import com.dbnt.kcscbackend.admin.standardResearch.model.UpdateStandardResearchVO;
import com.dbnt.kcscbackend.auth.entity.LoginVO;
import com.dbnt.kcscbackend.commonCode.repository.TnCmtOrgRepository;
import com.dbnt.kcscbackend.config.common.ResponseCode;
import com.dbnt.kcscbackend.config.common.ResultVO;
import lombok.RequiredArgsConstructor;
import org.egovframe.rte.fdl.cmmn.EgovAbstractServiceImpl;
import org.egovframe.rte.ptl.mvc.tags.ui.pagination.PaginationInfo;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import javax.servlet.http.HttpServletRequest;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Service("adminCommitteeCodeManagementService")
@RequiredArgsConstructor
public class AdminCommitteeCodeManagementServiceImpl extends EgovAbstractServiceImpl implements AdminCommitteeCodeManagementService {
private final TnCmtOrgRepository tnCmtOrgRepository;
@Override
public ResultVO createCommitteeCodeManagement(ResultVO resultVO, HttpServletRequest request, LoginVO user, MultipartHttpServletRequest multiRequest, CreateStandardResearchVO createStandardResearchVO) throws Exception {
return null;
}
@Override
public ResultVO getCommitteeCodeManagement(ResultVO resultVO, HttpServletRequest request, LoginVO user, Long upCmtSeq, String cmtType) throws Exception {
System.out.println(
"\n--------------------------------------------------------------\n" +
request.getRequestURI() + " IN:" +
"\n--------------------------------------------------------------\n" +
"user.getEmail():" + "\n" +
user.getEmail() + "\n" +
"\n--------------------------------------------------------------\n"
);
List<Map<String, Object>> list = tnCmtOrgRepository.findByUseYnAndUpCmtSeqAndCmtTypeOrderByCmtOrder("Y", upCmtSeq, cmtType).stream()
.map(item -> {
Map<String, Object> returnMap = new HashMap<>();
returnMap.put("orgId", item.getCmtSeq());
returnMap.put("orgNm", item.getCmtNm());
returnMap.put("orgDesc", item.getCmtDesc());
return returnMap;
})
.collect(Collectors.toList());
Map<String, Object> dto = new HashMap<String, Object>();
dto.put("list", list);
resultVO.setResult(dto);
resultVO.setResultCode(ResponseCode.SUCCESS.getCode());
resultVO.setResultMessage(ResponseCode.SUCCESS.getMessage());
return resultVO;
}
@Override
public ResultVO setCommitteeCodeManagement(ResultVO resultVO, HttpServletRequest request, LoginVO user, UpdateStandardResearchVO updateStandardResearchVO, Long popupId) throws Exception {
return null;
}
@Override
public ResultVO deleteCommitteeCodeManagement(ResultVO resultVO, HttpServletRequest request, LoginVO user, Long popupId) throws Exception {
return null;
}
}

View File

@ -1,10 +1,8 @@
package com.dbnt.kcscbackend.admin.dashboard;
//import com.dbnt.kcscbackend.admin.dashboard.dto.MonthlyUserLogDTO;
import com.dbnt.kcscbackend.admin.dashboard.dto.MonthlyUserLogDTO;
import com.dbnt.kcscbackend.admin.dashboard.service.AdminDashboardService;
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;
@ -12,8 +10,6 @@ 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;
@ -34,116 +30,57 @@ public class AdminDashboardController extends BaseController {
private final AdminDashboardService adminDashboardService;
@Operation(
summary = "해당년도 메뉴/방문자수 월/요일별 조회",
description = "해당년도 메뉴/방문자수 월/요일별 조회",
summary = "일별 사용자 현황 차트 조회",
description = "일별 사용자 현황 차트 조회",
tags = {"AdminDashboardController"}
)
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "조회 성공"),
@ApiResponse(responseCode = "403", description = "인가된 사용자가 아님")
})
@RequestMapping(method = RequestMethod.POST, value = "/menu-login", consumes = MediaType.APPLICATION_JSON_VALUE)
public ResultVO getMenuVisit(@AuthenticationPrincipal LoginVO user)
throws Exception {
@RequestMapping(method = RequestMethod.GET, value = "/daily-user-log-list", consumes = MediaType.APPLICATION_JSON_VALUE)
public ResultVO getDailyUserLogList() throws Exception {
ResultVO resultVO = new ResultVO();
Map<String, Object> resultMap = new HashMap<>();
resultMap.put("menuMonthlyList", adminDashboardService.selectMenuMonthly());
resultMap.put("menuDailyList", adminDashboardService.selectMenuDaily());
resultMap.put("loginMonthlyList", adminDashboardService.selectLoginMonthly());
resultMap.put("loginDailyList", adminDashboardService.selectLoginDaily());
// 현재 날짜
// todo endDate 뒤에 .minus 지워야함
LocalDate endDate = LocalDate.now().minusMonths(6);
// 3개월 전 날짜 계산
LocalDate startDate = endDate.minusMonths(3);
resultVO.setResultCode(ResponseCode.SUCCESS.getCode());
resultVO.setResultMessage(ResponseCode.SUCCESS.getMessage());
resultMap.put("dailyUserLogList", adminDashboardService.selectDailyUserLogList(startDate, endDate));
resultVO.setResult(resultMap);
return resultVO;
}
@Operation(
summary = "이번주 다운로드 조회",
description = "이번주 다운로드 조회",
summary = "월별 사용자 현황 차트 조회",
description = "월별 사용자 현황 차트 조회",
tags = {"AdminDashboardController"}
)
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "조회 성공"),
@ApiResponse(responseCode = "403", description = "인가된 사용자가 아님")
})
@RequestMapping(method = RequestMethod.POST, value = "/file", consumes = MediaType.APPLICATION_JSON_VALUE)
public ResultVO getfile(@AuthenticationPrincipal LoginVO user)
throws Exception {
@RequestMapping(method = RequestMethod.GET, value = "/monthly-user-log-list", consumes = MediaType.APPLICATION_JSON_VALUE)
public ResultVO getMonthlyUserLogList() throws Exception {
ResultVO resultVO = new ResultVO();
Map<String, Object> resultMap = new HashMap<>();
resultMap.put("fileDailyList", adminDashboardService.selectFileDaily());
// 현재 날짜
// todo endDate 뒤에 .minus 지워야함
LocalDate endDate = LocalDate.now().minusMonths(6);
// 3개월 전 날짜 계산
LocalDate startDate = endDate.minusMonths(3);
resultVO.setResultCode(ResponseCode.SUCCESS.getCode());
resultVO.setResultMessage(ResponseCode.SUCCESS.getMessage());
List<Object[]> result = adminDashboardService.selectMonthlyUserLogList(startDate, endDate);
List<MonthlyUserLogDTO> monthlyUserLogDTOList = result.stream()
.map(row -> new MonthlyUserLogDTO((String) row[0], (BigInteger) row[1]))
.collect(Collectors.toList());
resultMap.put("dailyUserLogList", monthlyUserLogDTOList);
resultVO.setResult(resultMap);
return resultVO;
}
// @Operation(
// summary = "일별 사용자 현황 차트 조회",
// description = "일별 사용자 현황 차트 조회",
// tags = {"AdminDashboardController"}
// )
// @ApiResponses(value = {
// @ApiResponse(responseCode = "200", description = "조회 성공"),
// @ApiResponse(responseCode = "403", description = "인가된 사용자가 아님")
// })
// @RequestMapping(method = RequestMethod.GET, value = "/daily-user-log-list", consumes = MediaType.APPLICATION_JSON_VALUE)
// public ResultVO getDailyUserLogList() throws Exception {
// ResultVO resultVO = new ResultVO();
// Map<String, Object> resultMap = new HashMap<>();
//
// // 현재 날짜
// // todo endDate 뒤에 .minus 지워야함
// LocalDate endDate = LocalDate.now().minusMonths(6);
// // 3개월 전 날짜 계산
// LocalDate startDate = endDate.minusMonths(3);
//
// resultMap.put("dailyUserLogList", adminDashboardService.selectDailyUserLogList(startDate, endDate));
// resultVO.setResult(resultMap);
// return resultVO;
// }
//
// @Operation(
// summary = "월별 사용자 현황 차트 조회",
// description = "월별 사용자 현황 차트 조회",
// tags = {"AdminDashboardController"}
// )
// @ApiResponses(value = {
// @ApiResponse(responseCode = "200", description = "조회 성공"),
// @ApiResponse(responseCode = "403", description = "인가된 사용자가 아님")
// })
// @RequestMapping(method = RequestMethod.GET, value = "/monthly-user-log-list", consumes = MediaType.APPLICATION_JSON_VALUE)
// public ResultVO getMonthlyUserLogList() throws Exception {
// ResultVO resultVO = new ResultVO();
// Map<String, Object> resultMap = new HashMap<>();
//
// // 현재 날짜
// // todo endDate 뒤에 .minus 지워야함
// LocalDate endDate = LocalDate.now().minusMonths(6);
// // 3개월 전 날짜 계산
// LocalDate startDate = endDate.minusMonths(3);
//
// List<Object[]> result = adminDashboardService.selectMonthlyUserLogList(startDate, endDate);
// List<MonthlyUserLogDTO> monthlyUserLogDTOList = result.stream()
// .map(row -> new MonthlyUserLogDTO((String) row[0], (BigInteger) row[1]))
// .collect(Collectors.toList());
//
// resultMap.put("dailyUserLogList", monthlyUserLogDTOList);
// resultVO.setResult(resultMap);
// return resultVO;
// }
}

View File

@ -1,83 +0,0 @@
package com.dbnt.kcscbackend.admin.dashboard.repository;
import com.dbnt.kcscbackend.admin.logs.entity.TnDailyMenuLog;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import java.util.List;
public interface MenuMonthlyRepository extends JpaRepository<TnDailyMenuLog, Long> {
@Query(value = "WITH all_months AS (" +
" SELECT generate_series(DATE_TRUNC('year', CURRENT_DATE), DATE_TRUNC('year', CURRENT_DATE) + INTERVAL '11 month', INTERVAL '1 month') AS month_start" +
")" +
"SELECT COALESCE(SUM(tn.log_cnt), 0) AS log_cnt " +
"FROM all_months " +
"LEFT JOIN tn_daily_menu_log tn ON TO_CHAR(all_months.month_start, 'yyyy-mm') = TO_CHAR(tn.log_dt, 'yyyy-mm') " +
"GROUP BY TO_CHAR(all_months.month_start, 'yyyy-mm') " +
"ORDER BY TO_CHAR(all_months.month_start, 'yyyy-mm') ASC", nativeQuery = true)
List<Long> MenuMonthlyList();
@Query(value = "WITH all_days AS (" +
" SELECT generate_series(" +
" DATE_TRUNC('year', now())," +
" DATE_TRUNC('year', now()) + INTERVAL '1 year' - INTERVAL '1 day'," +
" INTERVAL '1 day'" +
" ) AS day" +
")" +
"SELECT COALESCE(SUM(tn.log_cnt), 0) AS log_cnt " +
"FROM all_days ad " +
"LEFT JOIN tn_daily_menu_log tn ON ad.day = DATE_TRUNC('day', tn.log_dt) " +
"GROUP BY TO_CHAR(ad.day, 'Day') " +
"ORDER BY MIN(ad.day)", nativeQuery = true)
List<Long> MenuDailyList();
@Query(value = "WITH all_months AS (" +
" SELECT generate_series(" +
" DATE_TRUNC('year', now())," +
" DATE_TRUNC('year', now()) + INTERVAL '11 month'," +
" INTERVAL '1 month'" +
" ) AS month_start" +
")" +
"SELECT COALESCE(SUM(tn.log_cnt), 0) AS log_cnt " +
"FROM all_months " +
"LEFT JOIN tn_daily_user_log tn ON TO_CHAR(all_months.month_start, 'yyyy-mm') = TO_CHAR(tn.log_dt, 'yyyy-mm') " +
"GROUP BY TO_CHAR(all_months.month_start, 'yyyy-mm') " +
"ORDER BY TO_CHAR(all_months.month_start, 'yyyy-mm') ASC", nativeQuery = true)
List<Long> LoginMonthlyList();
@Query(value = "WITH all_days AS (" +
" SELECT generate_series(" +
" DATE_TRUNC('year', CURRENT_DATE)," +
" DATE_TRUNC('year', CURRENT_DATE) + INTERVAL '1 year' - INTERVAL '1 day'," +
" INTERVAL '1 day'" +
" ) AS day" +
")" +
"SELECT COALESCE(SUM(tn.log_cnt), 0) AS log_cnt " +
"FROM all_days ad " +
"LEFT JOIN tn_daily_user_log tn ON ad.day = tn.log_dt " +
"GROUP BY TO_CHAR(ad.day, 'Day') " +
"ORDER BY MIN(ad.day)", nativeQuery = true)
List<Long> LoginDailyList();
@Query(value = "WITH all_days AS (" +
" SELECT generate_series(" +
" DATE_TRUNC('year', CURRENT_DATE)," +
" DATE_TRUNC('year', CURRENT_DATE) + INTERVAL '1 year' - INTERVAL '1 day'," +
" INTERVAL '1 day'" +
" ) AS day" +
")" +
"SELECT COALESCE(COUNT(tn.access_dt), 0) AS log_cnt " +
"FROM all_days ad " +
"LEFT JOIN (SELECT access_dt FROM public.th_attach_file_log WHERE\n" +
" access_dt >= CURRENT_DATE - INTERVAL '6 day') tn ON ad.day = DATE_TRUNC('day', tn.access_dt) " +
"GROUP BY TO_CHAR(ad.day, 'Day') " +
"ORDER BY MIN(ad.day)", nativeQuery = true)
List<Long> FileDailyList();
}

View File

@ -1,38 +1,24 @@
package com.dbnt.kcscbackend.admin.dashboard.service;
//import com.dbnt.kcscbackend.admin.dashboard.entity.TnDailyUserLog;
import com.dbnt.kcscbackend.admin.dashboard.repository.MenuMonthlyRepository;
//import com.dbnt.kcscbackend.admin.dashboard.repository.TnDailyUserLogRepository;
import com.dbnt.kcscbackend.admin.dashboard.entity.TnDailyUserLog;
import com.dbnt.kcscbackend.admin.dashboard.repository.TnDailyUserLogRepository;
import lombok.RequiredArgsConstructor;
import org.egovframe.rte.fdl.cmmn.EgovAbstractServiceImpl;
import org.springframework.stereotype.Service;
//import java.time.LocalDate;
import java.time.LocalDate;
import java.util.List;
@Service
@RequiredArgsConstructor
public class AdminDashboardService extends EgovAbstractServiceImpl {
// private final TnDailyUserLogRepository tnDailyUserLogRepository;
private final MenuMonthlyRepository menuMonthlyRepository;
private final TnDailyUserLogRepository tnDailyUserLogRepository;
public List<Long> selectMenuMonthly() { return menuMonthlyRepository.MenuMonthlyList(); }
public List<TnDailyUserLog> selectDailyUserLogList(LocalDate startDate, LocalDate endDate) {
return tnDailyUserLogRepository.findByLogDtBetweenOrderByLogDt(startDate, endDate);
}
public List<Long> selectMenuDaily() { return menuMonthlyRepository.MenuDailyList(); }
public List<Long> selectLoginMonthly() { return menuMonthlyRepository.LoginMonthlyList(); }
public List<Long> selectLoginDaily() { return menuMonthlyRepository.LoginDailyList(); }
public List<Long> selectFileDaily() { return menuMonthlyRepository.FileDailyList(); }
// public List<TnDailyUserLog> selectDailyUserLogList(LocalDate startDate, LocalDate endDate) {
// return tnDailyUserLogRepository.findByLogDtBetweenOrderByLogDt(startDate, endDate);
// }
//
// public List<Object[]> selectMonthlyUserLogList(LocalDate startDate, LocalDate endDate) {
// return tnDailyUserLogRepository.selectMonthlyUserLogStatistics(startDate, endDate);
// }
public List<Object[]> selectMonthlyUserLogList(LocalDate startDate, LocalDate endDate) {
return tnDailyUserLogRepository.selectMonthlyUserLogStatistics(startDate, endDate);
}
}

View File

@ -1,6 +1,8 @@
package com.dbnt.kcscbackend.admin.standardResearch;
import com.dbnt.kcscbackend.admin.contents.popUp.model.CreatePopupVO;
import com.dbnt.kcscbackend.admin.contents.popUp.model.UpdatePopupVO;
import com.dbnt.kcscbackend.admin.contents.popUp.utils.EgovFileMngUtil;
import com.dbnt.kcscbackend.admin.standardResearch.model.CreateStandardResearchVO;
import com.dbnt.kcscbackend.admin.standardResearch.model.UpdateStandardResearchVO;
@ -9,6 +11,7 @@ import com.dbnt.kcscbackend.auth.entity.LoginVO;
import com.dbnt.kcscbackend.config.common.ResponseCode;
import com.dbnt.kcscbackend.config.common.ResultVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiParam;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;

View File

@ -179,7 +179,7 @@ public class EgovLoginApiController extends BaseController {
if (refreshToken != null){
String serverToken = refreshToken.getRefreshToken();
if(egovJwtTokenUtil.getUserSeFromToken(clientToken).equals(egovJwtTokenUtil.getUserSeFromToken(serverToken))){
return egovJwtTokenUtil.getUserIdFromToken(clientToken).equals("admin");
return true;
}
}
return false;

View File

@ -35,9 +35,6 @@ public class LoginVO implements Serializable{
*/
private static final long serialVersionUID = -8274004534207618049L;
@Schema(description = "사용자 번호")
private Integer userSeq;
@Schema(description = "아이디")
@Pattern(regexp = "^[a-zA-Z]{1}[a-zA-Z0-9_]{4,11}$")
@NotBlank(message = "아이디를 입력해주세요.")

View File

@ -8,6 +8,5 @@ import java.util.List;
public interface TnCmtOrgRepository extends JpaRepository<TnCmtOrg, TnCmtOrg.TnCmtOrgId> {
List<TnCmtOrg> findByUseYnAndUpCmtSeqOrderByCmtOrder(String useYn, Long upCmtSeq);
TnCmtOrg findByUseYnAndCmtSeq(String useYn, Long cmtSeq);
List<TnCmtOrg> findByUseYnAndUpCmtSeqAndCmtTypeOrderByCmtOrder(String useYn, Long upCmtSeq, String cmtType);
}

View File

@ -67,7 +67,6 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
LoginVO loginVO = new LoginVO();
if( verificationFlag ){
logger.debug("jwtToken validated");
loginVO.setUserSeq(Integer.parseInt(jwtTokenUtil.getUserSeqFromToken(jwtToken)));
loginVO.setId(id);
loginVO.setUserSe( jwtTokenUtil.getUserSeFromToken(jwtToken) );
// loginVO.setUniqId( jwtTokenUtil.getInfoFromToken("uniqId",jwtToken) );

View File

@ -57,8 +57,7 @@ public class CustomUrlAuthenticationSuccessHandler extends SimpleUrlAuthenticati
MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter();
MediaType jsonMimeType = MediaType.APPLICATION_JSON;
HashMap<String, Object> resultMap = new HashMap<>();
/*if(securityUser.getUserId().equals("admin") && !adminIpList.contains(ClientUtils.getRemoteIP(request))){
if(securityUser.getUserId().equals("admin") && !adminIpList.contains(ClientUtils.getRemoteIP(request))){
resultMap.put("resultCode", ResponseCode.FAILED.getCode());
resultMap.put("resultMessage", "관리자 계정은 지정된 아이피에서만 접속할 수 있습니다.\n필요한 경우 관리자에게 요청하십시오.\n접속자 아이피: "+ClientUtils.getRemoteIP(request));
}else{
@ -70,13 +69,7 @@ public class CustomUrlAuthenticationSuccessHandler extends SimpleUrlAuthenticati
// response.addHeader("Authorization", "BEARER "+accessToken);
// Cookie refreshTokenCookie = new Cookie("refreshToken", refreshToken);
// response.addCookie(refreshTokenCookie);
}*/
String accessToken = jwtTokenUtil.generateAccessToken(securityUser, request.getRemoteAddr());
String refreshToken = jwtTokenUtil.generateRefreshTokenToken(securityUser, request.getRemoteAddr());
resultMap.put("resultCode", ResponseCode.SUCCESS.getCode());
resultMap.put("accessToken", accessToken);
resultMap.put("refreshToken", refreshToken);
}
if (jsonConverter.canWrite(resultMap.getClass(), jsonMimeType)) {
jsonConverter.write(resultMap, jsonMimeType, new ServletServerHttpResponse(response));

View File

@ -83,7 +83,7 @@ public class SecurityConfig {
"/swagger-ui/**",
/*기준코드 조회*/
"/standardCode/**"
"/standardCode/**.do"
};
private static final String[] ORIGINS_WHITELIST = {
"http://localhost:3000",

View File

@ -6,7 +6,6 @@ import com.dbnt.kcscbackend.config.common.ResponseCode;
import com.dbnt.kcscbackend.config.common.ResultVO;
import com.dbnt.kcscbackend.standardCode.entity.TnDocumentCodeList;
import com.dbnt.kcscbackend.standardCode.entity.TnDocumentContent;
import com.dbnt.kcscbackend.standardCode.entity.TnDocumentFavorites;
import com.dbnt.kcscbackend.standardCode.entity.TnDocumentInfo;
import com.dbnt.kcscbackend.standardCode.service.StandardCodeService;
import com.dbnt.kcscbackend.standardCode.service.StandardCodeVO;
@ -61,7 +60,7 @@ public class StandardCodeController extends BaseController {
@ApiResponse(responseCode = "200", description = "조회 성공"),
@ApiResponse(responseCode = "403", description = "인가된 사용자가 아님")
})
@RequestMapping(method = RequestMethod.GET, value = "/code-tree")
@RequestMapping(method = RequestMethod.POST, value = "/getCodeTree.do", consumes = MediaType.APPLICATION_JSON_VALUE)
public ResultVO getCodeTree() throws Exception {
ResultVO resultVO = new ResultVO();
Map<String, Object> resultMap = new HashMap<>();
@ -99,8 +98,8 @@ public class StandardCodeController extends BaseController {
@ApiResponse(responseCode = "200", description = "조회 성공"),
@ApiResponse(responseCode = "403", description = "인가된 사용자가 아님")
})
@GetMapping(value = "/code-info", consumes = MediaType.APPLICATION_JSON_VALUE)
public ResultVO getCodeInfo(StandardCodeVO param, @AuthenticationPrincipal LoginVO user)
@PostMapping(value = "/getCodeInfo.do", consumes = MediaType.APPLICATION_JSON_VALUE)
public ResultVO getCodeInfo(@RequestBody StandardCodeVO param, @AuthenticationPrincipal LoginVO user)
throws Exception {
ResultVO resultVO = new ResultVO();
Map<String, Object> resultMap = new HashMap<>();
@ -152,10 +151,25 @@ public class StandardCodeController extends BaseController {
ResultVO resultVO = new ResultVO();
Map<String, Object> resultMap = new HashMap<>();
tnDocumentInfo.makeListCode();
tnDocumentInfo.setUserSeq(user.getUserSeq());
resultMap.put("resultList", standardCodeService.selectStandardCodeList(tnDocumentInfo));
resultMap.put("resultCnt", standardCodeService.selectStandardCodeListCnt(tnDocumentInfo));
String tab = tnDocumentInfo.getTab() != null ? tnDocumentInfo.getTab() : "";
String category1 = tnDocumentInfo.getCategory1() != null ? tnDocumentInfo.getCategory1() : "";
String category2 = tnDocumentInfo.getCategory2() != null ? tnDocumentInfo.getCategory2() : "";
String category3 = tnDocumentInfo.getCategory3() != null ? tnDocumentInfo.getCategory3() : "";
Integer categorySeq1 = standardCodeService.selectStandardCodeGroupSeq(tab);
Integer categorySeq2 = standardCodeService.selectStandardCodeGroupSeq(tab + category1);
Integer categorySeq3 = standardCodeService.selectStandardCodeGroupSeq(tab + category1 + category2);
resultMap.put("category1List", standardCodeService.selectStandardCodeCategoryList(categorySeq1));
resultMap.put("category2List", standardCodeService.selectStandardCodeCategoryList(categorySeq2));
resultMap.put("category3List", standardCodeService.selectStandardCodeCategoryList(categorySeq3));
tnDocumentInfo.setListCode(tab + category1 + category2 + category3);
List<TnDocumentCodeList> tnDocumentCodeList = standardCodeService.selectStandardCodeList(tnDocumentInfo);
resultMap.put("resultList", tnDocumentCodeList);
Integer totCnt = tnDocumentCodeList.get(0).getContentcount();
resultMap.put("resultCnt", totCnt);
resultMap.put("user", user);
resultVO.setResultCode(ResponseCode.SUCCESS.getCode());
resultVO.setResultMessage(ResponseCode.SUCCESS.getMessage());
@ -163,84 +177,6 @@ public class StandardCodeController extends BaseController {
return resultVO;
}
@Operation(
summary = "건설기준코드 다운로드 리스트 조회",
description = "건설기준코드 다운로드 리스트 조회",
tags = {"StandardCodeController"}
)
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "조회 성공"),
@ApiResponse(responseCode = "403", description = "인가된 사용자가 아님")
})
@GetMapping(value = "/standard-code-download-list")
public ResultVO selectStandardCodeDownloadList(TnDocumentInfo tnDocumentInfo, @AuthenticationPrincipal LoginVO user)
throws Exception {
ResultVO resultVO = new ResultVO();
Map<String, Object> resultMap = new HashMap<>();
String listCode = tnDocumentInfo.getListCode();
if(listCode.equals("60")){
listCode += "______";
}else{
listCode += "____";
}
resultMap.put("resultList", standardCodeService.selectTnDocumentGroupToGroupFullCdLike(listCode));
resultVO.setResultCode(ResponseCode.SUCCESS.getCode());
resultVO.setResultMessage(ResponseCode.SUCCESS.getMessage());
resultVO.setResult(resultMap);
return resultVO;
}
@Operation(
summary = "건설기준코드 검색조건 옵션 조회",
description = "건설기준코드 검색조건 옵션 조회",
tags = {"StandardCodeController"}
)
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "조회 성공"),
@ApiResponse(responseCode = "403", description = "인가된 사용자가 아님")
})
@GetMapping(value = "/category-option")
public ResultVO getCategoryOption(TnDocumentInfo tnDocumentInfo) throws Exception {
ResultVO resultVO = new ResultVO();
Map<String, Object> resultMap = new HashMap<>();
resultMap.put("groupList", standardCodeService.selectTnDocumentGroupToGroupFullCdLike(tnDocumentInfo.getListCode()+"__"));
resultVO.setResultCode(ResponseCode.SUCCESS.getCode());
resultVO.setResultMessage(ResponseCode.SUCCESS.getMessage());
resultVO.setResult(resultMap);
return resultVO;
}
@Operation(
summary = "건설기준코드 즐겨찾기 추가, 삭제",
description = "건설기준코드 즐겨찾기 추가, 삭제",
tags = {"StandardCodeController"}
)
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "수정 성공"),
@ApiResponse(responseCode = "403", description = "인가된 사용자가 아님")
})
@PostMapping(value = "/document-favorite")
public ResultVO setDocumentFavorite(@RequestBody TnDocumentFavorites favorites, @AuthenticationPrincipal LoginVO loginUser) throws Exception {
ResultVO resultVO = new ResultVO();
if(favorites.getActive()==null){
resultVO.setResultCode(ResponseCode.SAVE_ERROR.getCode());
resultVO.setResultMessage(ResponseCode.SAVE_ERROR.getMessage());
return resultVO;
}
if(favorites.getActive()){
standardCodeService.saveFavorites(loginUser.getUserSeq(), favorites.getGroupSeq());
}else{
standardCodeService.deleteFavorites(loginUser.getUserSeq(), favorites.getGroupSeq());
}
resultVO.setResultCode(ResponseCode.SUCCESS.getCode());
resultVO.setResultMessage(ResponseCode.SUCCESS.getMessage());
return resultVO;
}
@Operation(
summary = "건설기준코드 개정이력 조회",
description = "건설기준코드 개정이력 조회",

View File

@ -10,7 +10,6 @@ import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Transient;
import java.util.List;
@Getter
@Setter
@ -29,24 +28,15 @@ public class TnDocumentCodeList {
private String middleCategory;
@Column(name = "group_nm")
private String groupNm;
@Column(name = "rvsn_remark")
private String rvsnRemark;
@Column(name = "kcsc_cd")
private String kcscCd;
@Column(name = "doc_file_grp_id")
private String docFileGrpId;
@Column(name = "contentcount")
private Integer contentcount;
@Column(name = "parent_group_seq")
private String parentGroupSeq;
@Column(name = "group_full_cd")
private String groupFullCd;
@Transient
private Integer allCnt;
@Transient
private Integer remarkCnt;
@Transient
private Boolean favoriteChk;
@Transient
private List<TnDocumentInfo> historyList;
}

View File

@ -1,40 +0,0 @@
package com.dbnt.kcscbackend.standardCode.entity;
import lombok.*;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;
import org.springframework.format.annotation.DateTimeFormat;
import javax.persistence.*;
import java.io.Serializable;
import java.time.LocalDateTime;
@Getter
@Setter
@Entity
@NoArgsConstructor
@DynamicInsert
@DynamicUpdate
@Table(name = "tn_document_favorites")
@IdClass(TnDocumentFavorites.TnDocumentFavoritesId.class)
public class TnDocumentFavorites {
@Id
@Column(name = "user_seq")
private Integer userSeq;
@Id
@Column(name = "group_seq")
private Integer groupSeq;
@Transient
private Boolean active;
@Embeddable
@Data
@NoArgsConstructor
@AllArgsConstructor
public static class TnDocumentFavoritesId implements Serializable {
private Integer userSeq;
private Integer groupSeq;
}
}

View File

@ -1,6 +1,5 @@
package com.dbnt.kcscbackend.standardCode.entity;
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import lombok.NoArgsConstructor;
@ -93,18 +92,11 @@ public class TnDocumentInfo {
@Transient
private String searchWrd;
@Transient
private String tab = "";
private String tab;
@Transient
private String category1 = "";
private String category1;
@Transient
private String category2 = "";
private String category2;
@Transient
private String category3 = "";
@Transient
private Integer userSeq;
@JsonIgnore
public void makeListCode(){
setListCode(getTab()+getCategory1()+getCategory2()+getCategory3());
}
private String category3;
}

Some files were not shown because too many files have changed in this diff Show More