Compare commits
47 Commits
98d2da2e21
...
432cad27ab
| Author | SHA1 | Date |
|---|---|---|
|
|
432cad27ab | |
|
|
a357df161d | |
|
|
ff036473d7 | |
|
|
694f0ef918 | |
|
|
bf3a460610 | |
|
|
f210629907 | |
|
|
1fd7ba0fb1 | |
|
|
cbfb9b2ca3 | |
|
|
6ca96a65ad | |
|
|
a2fcdfe569 | |
|
|
60521e4995 | |
|
|
e825207231 | |
|
|
a63a47a7b8 | |
|
|
b84bb9a7a9 | |
|
|
8e22399ec4 | |
|
|
f14ee3b03d | |
|
|
701e813fbb | |
|
|
2ec64ceac0 | |
|
|
9e3a856d23 | |
|
|
b5003f30d2 | |
|
|
7c5a94ed38 | |
|
|
3bf8cb065a | |
|
|
7a141fff89 | |
|
|
a476f3e00c | |
|
|
1f5485249b | |
|
|
1cd9cf8202 | |
|
|
94963507c4 | |
|
|
76ce7a9a36 | |
|
|
64e4b07953 | |
|
|
cdd6f726c2 | |
|
|
a7bdd5093f | |
|
|
720033ece6 | |
|
|
52e6aed96e | |
|
|
dc0046a3c1 | |
|
|
7936704abd | |
|
|
2bbd80d40b | |
|
|
ebe40f2f3e | |
|
|
33f3654222 | |
|
|
c7440cbc0d | |
|
|
f0fdfbfcbb | |
|
|
67852a87d0 | |
|
|
2ac1241ef1 | |
|
|
7136da0529 | |
|
|
d413c605cd | |
|
|
c308ec3691 | |
|
|
3657c16a15 | |
|
|
47e4fda988 |
File diff suppressed because it is too large
Load Diff
|
|
@ -3,6 +3,8 @@
|
|||
"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",
|
||||
|
|
@ -10,19 +12,25 @@
|
|||
"@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"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
import RootRoutes from './routes';
|
||||
import ThemeCustomization from 'themes';
|
||||
import ScrollTop from 'components/ScrollTop';
|
||||
import React from 'react';
|
||||
|
||||
import 'bootstrap/dist/css/bootstrap.min.css';
|
||||
|
|
@ -12,9 +14,11 @@ import './css/Custom/customMain.css'
|
|||
function App() {
|
||||
|
||||
return (
|
||||
<div className="wrap">
|
||||
<ThemeCustomization>
|
||||
<ScrollTop>
|
||||
<RootRoutes />
|
||||
</div>
|
||||
</ScrollTop>
|
||||
</ThemeCustomization>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,7 +29,11 @@ export function requestFetch(url, requestOptions, handler, errorHandler) {
|
|||
const accessToken = getLocalItem('accessToken');
|
||||
const sessionUser = parseJwt(accessToken);
|
||||
const sessionUserId = sessionUser?.id || null;
|
||||
const refreshToken = getLocalItem('refreshToken');
|
||||
|
||||
if(accessToken && new Date(sessionUser.exp*1000) < new Date()){
|
||||
//만료된 토큰 재발급 절차 진행.
|
||||
accessTokenRefresh(url, requestOptions, handler, errorHandler);
|
||||
}else{
|
||||
if(sessionUserId != null){
|
||||
if( !requestOptions['headers'] ) requestOptions['headers']={}
|
||||
if( !requestOptions['headers']['Authorization'] ) requestOptions['headers']['Authorization']=null;
|
||||
|
|
@ -48,14 +52,12 @@ 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)) {
|
||||
//accessToken 갱신 요청
|
||||
accessTokenRefresh(url, requestOptions, handler, errorHandler);
|
||||
return resp;
|
||||
alert("로그인이 해제되었습니다.")
|
||||
window.location.href = "/login"
|
||||
}else{
|
||||
return resp;
|
||||
}
|
||||
|
|
@ -87,7 +89,7 @@ export function requestFetch(url, requestOptions, handler, errorHandler) {
|
|||
console.log("requestFetch finally end");
|
||||
console.groupEnd("requestFetch");
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function accessTokenRefresh(url, requestOptions, handler, errorHandler){
|
||||
|
|
|
|||
|
|
@ -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">
|
||||
<div className="inner row">
|
||||
<div className="col">
|
||||
<h3>건설기준코드</h3>
|
||||
<ul>
|
||||
|
|
|
|||
|
|
@ -1,10 +1,16 @@
|
|||
import React from 'react';
|
||||
import React, {useEffect, useState} from 'react';
|
||||
import {Blocks} from "react-loader-spinner";
|
||||
import {LoadingDiv} from "./Loading.style";
|
||||
|
||||
function Loading () {
|
||||
function Loading ({loadingState}) {
|
||||
const [visible, setVisible] = useState(loadingState);
|
||||
|
||||
useEffect(() => {
|
||||
setVisible(loadingState)
|
||||
}, [loadingState]);
|
||||
|
||||
return (
|
||||
<LoadingDiv>
|
||||
<LoadingDiv $visible={visible}>
|
||||
<Blocks
|
||||
height="150"
|
||||
width="150"
|
||||
|
|
|
|||
|
|
@ -4,4 +4,5 @@ export const LoadingDiv = styled.div`
|
|||
min-height: 83vh;
|
||||
padding-top: calc(40vh - 150px);
|
||||
padding-left: calc(54vw - 150px);
|
||||
display: ${props=>props.$visible?"block":"none"};
|
||||
`
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
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;
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
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;
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
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;
|
||||
|
|
@ -18,15 +18,16 @@ import FormDialog from '../../components/alert/FormDialog';
|
|||
|
||||
|
||||
|
||||
function generate(items, element, onClickListner) {
|
||||
function generate(items, element, onClickListner,nameKey,
|
||||
idKey) {
|
||||
return items.map((value, index) =>
|
||||
React.cloneElement(element, {
|
||||
key: value,
|
||||
key: value[nameKey],
|
||||
},
|
||||
<Card fullWidth sx={{ '&': { boxShadow: 'none' } }}>
|
||||
<CardActionArea fullWidth sx={{ px: 1 }}>
|
||||
<ListItemText
|
||||
primary={value}
|
||||
primary={value[nameKey]}
|
||||
key={index}
|
||||
data-index={index}
|
||||
onClick={(e) => {onClickListner(e, index);}}
|
||||
|
|
@ -99,7 +100,9 @@ function ListCreateUpdateDelete(props) {
|
|||
}
|
||||
>
|
||||
</ListItem>,
|
||||
onClickItem
|
||||
onClickItem,
|
||||
props.nameKey,
|
||||
props.idKey
|
||||
)}
|
||||
</List>
|
||||
</Demo>
|
||||
|
|
|
|||
|
|
@ -28,12 +28,10 @@ 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]);
|
||||
|
|
|
|||
65
egovframe-template-simple-react-contribution/src/components/third-party/Highlighter.js
vendored
Normal file
65
egovframe-template-simple-react-contribution/src/components/third-party/Highlighter.js
vendored
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
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;
|
||||
|
|
@ -46,14 +46,27 @@
|
|||
.code_list .result .List_Codes >div:nth-child(7){
|
||||
font-size: 14px;
|
||||
}
|
||||
.codelistcontent{
|
||||
padding: 0 0;
|
||||
width: 80%;
|
||||
|
||||
.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%;
|
||||
}
|
||||
.StandardCodeList{
|
||||
max-width: 100%;
|
||||
}
|
||||
.listtablediv{
|
||||
.listTableDiv{
|
||||
padding: 0 !important;
|
||||
}
|
||||
.vieweratag{
|
||||
|
|
|
|||
|
|
@ -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 {display: table-cell; width: 220px; vertical-align: top;} /* changed by lim width: 260px; */
|
||||
.c_wrap .layout .nav:not(.tabs) {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;}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,199 @@
|
|||
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;
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
import React, {useState, useEffect, useRef} from 'react';
|
||||
import { Link, useNavigate, useLocation } from 'react-router-dom';
|
||||
import {Link, useNavigate, useLocation, useParams} from 'react-router-dom';
|
||||
import Modal from "react-bootstrap/Modal";
|
||||
|
||||
import * as EgovNet from 'api/egovFetch';
|
||||
import URL from 'constants/url';
|
||||
|
|
@ -7,9 +8,10 @@ import CODE from 'constants/code';
|
|||
|
||||
import {default as EgovLeftNav} from 'components/leftmenu/EgovLeftNavAdmin';
|
||||
import EgovRadioButtonGroup from 'components/EgovRadioButtonGroup';
|
||||
import {Form} from "react-bootstrap";
|
||||
|
||||
|
||||
function EgovAdminBoardEdit(props) {
|
||||
function EgovAdminBoardEdit({props, reloadFunction}) {
|
||||
console.group("EgovAdminBoardEdit");
|
||||
console.log("[Start] EgovAdminBoardEdit ------------------------------");
|
||||
console.log("EgovAdminBoardEdit [props] : ", props);
|
||||
|
|
@ -20,411 +22,141 @@ function EgovAdminBoardEdit(props) {
|
|||
|
||||
console.log("EgovAdminBoardEdit [location] : ", location);
|
||||
|
||||
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 || "";
|
||||
let item = null;
|
||||
item = props;
|
||||
console.log("@@@ item : " + JSON.stringify(item));
|
||||
|
||||
const [modeInfo, setModeInfo] = useState({ mode: props.mode });
|
||||
const [modeInfo, setModeInfo] = useState(item != null ? {mode: props.mode} : {mode: CODE.MODE_CREATE});
|
||||
const [boardDetail, setBoardDetail] = useState({});
|
||||
|
||||
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'];
|
||||
}
|
||||
console.log("@@@ mode : " + modeInfo.mode);
|
||||
|
||||
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 (
|
||||
<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">
|
||||
<>
|
||||
{/* <!-- 본문 --> */}
|
||||
<Modal.Header closeButton>
|
||||
<Modal.Title>
|
||||
{modeInfo.mode === CODE.MODE_CREATE && '게시판 생성'}
|
||||
{modeInfo.mode === CODE.MODE_MODIFY && '게시판 수정'}
|
||||
</Modal.Title>
|
||||
</Modal.Header>
|
||||
|
||||
<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="bbsNm">게시판명</label><span className="req">필수</span></dt>
|
||||
<dt><label htmlFor="bbsId">게시판 ID</label><span className="req">필수</span></dt>
|
||||
<dd>
|
||||
<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)}
|
||||
/>
|
||||
<Form.Control className="f_input2 w_full" type="text" name="bbsId" placeholder="게시판 ID" required
|
||||
defaultValue={props?.bbsId} readOnly={props!==undefined}/>
|
||||
</dd>
|
||||
</dl>
|
||||
<dl>
|
||||
<dt><label htmlFor="bbsIntrcn">게시판 소개</label><span className="req">필수</span></dt>
|
||||
<dt><label htmlFor="bbsTitle">게시판명</label><span className="req">필수</span></dt>
|
||||
<dd>
|
||||
<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>
|
||||
<Form.Control className="f_input2 w_full" type="text" name="bbsTitle" placeholder="게시판명" required
|
||||
defaultValue={props?.bbsTitle}/>
|
||||
</dd>
|
||||
</dl>
|
||||
<dl>
|
||||
<dt>게시판 유형<span className="req">필수</span></dt>
|
||||
<dt><label htmlFor="bbsDesc">게시판 소개</label><span className="req">필수</span></dt>
|
||||
<dd>
|
||||
{/* 수정/조회 일때 변경 불가 */}
|
||||
{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>
|
||||
<Form.Control className="f_txtar w_full h_100" as="textarea" name="bbsDesc" placeholder="게시판 소개" required
|
||||
defaultValue={props?.bbsDesc}/>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
{/* <!-- 버튼영역 --> */}
|
||||
<div className="board_btn_area">
|
||||
<div className="left_col btn1">
|
||||
<button className="btn btn_skyblue_h46 w_100"
|
||||
onClick={() => updateBoard()}>저장</button>
|
||||
<button type="submit" className="btn btn_skyblue_h46 w_100">저장
|
||||
</button>
|
||||
{modeInfo.mode === CODE.MODE_MODIFY &&
|
||||
<button className="btn btn_skyblue_h46 w_100" onClick={() => {
|
||||
deleteBoardArticle(boardDetail.bbsId);
|
||||
}}>삭제</button>
|
||||
<button type={"button"} className="btn btn_skyblue_h46 w_100" onClick={()=>{deleteBoard(props)}}>삭제</button>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div className="right_col btn1">
|
||||
<Link to={URL.ADMIN_BOARD} className="btn btn_blue_h46 w_100">목록</Link>
|
||||
<button type={"button"} className="btn btn_blue_h46 w_100" onClick={()=>{reloadFunction()}}>목록</button>
|
||||
</div>
|
||||
</div>
|
||||
{/* <!--// 버튼영역 --> */}
|
||||
</Form>
|
||||
</div>
|
||||
|
||||
{/* <!--// 본문 --> */}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Modal.Body>
|
||||
</>
|
||||
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,41 @@
|
|||
import React from 'react';
|
||||
import React, { useState, useEffect, useCallback } from 'react';
|
||||
import { Link, useLocation } from 'react-router-dom';
|
||||
|
||||
import * as EgovNet from 'api/egovFetch';
|
||||
import URL from 'constants/url';
|
||||
|
||||
function Keywords(props) {
|
||||
import { default as EgovLeftNav } from 'components/leftmenu/EgovLeftNavAdmin';
|
||||
|
||||
function StandardCodeMgt(props) {
|
||||
|
||||
return (
|
||||
<div className="container">
|
||||
Keywords
|
||||
<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>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Keywords;
|
||||
export default StandardCodeMgt;
|
||||
|
|
@ -3,11 +3,12 @@ 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 EgovPaging from 'components/EgovPaging';
|
||||
|
||||
import { itemIdxByPage } from 'utils/calc';
|
||||
import Modal from "react-bootstrap/Modal";
|
||||
import EgovAdminBoardEdit from "../board/EgovAdminBoardEdit";
|
||||
import {format} from "date-fns";
|
||||
|
||||
function EgovAdminBoardList(props) {
|
||||
console.group("EgovAdminBoardList");
|
||||
|
|
@ -20,10 +21,15 @@ 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';
|
||||
|
|
@ -49,14 +55,15 @@ function EgovAdminBoardList(props) {
|
|||
if (index === 0) mutListTag = []; // 목록 초기화
|
||||
|
||||
mutListTag.push(
|
||||
<Link className="list_item">
|
||||
<div className="list_item">
|
||||
<div>{item.bbsSeq}</div>
|
||||
<div>{item.bbsId}</div>
|
||||
<div>{item.bbsTitle}</div>
|
||||
<div>{item.frstCrtId}</div>
|
||||
<div>{item.frstCrtDt}</div>
|
||||
<div>{item.lastChgDt}</div>
|
||||
</Link>
|
||||
<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>
|
||||
);
|
||||
});
|
||||
|
||||
|
|
@ -75,6 +82,14 @@ 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 (
|
||||
|
|
@ -150,6 +165,7 @@ 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}
|
||||
|
|
@ -169,6 +185,9 @@ function EgovAdminBoardList(props) {
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Modal show={show} onHide={handleClose} keyboard={false}>
|
||||
{modalBody}
|
||||
</Modal>
|
||||
</div>
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,13 +1,41 @@
|
|||
import React from 'react';
|
||||
import React, { useState, useEffect, useCallback } from 'react';
|
||||
import { Link, useLocation } from 'react-router-dom';
|
||||
|
||||
import * as EgovNet from 'api/egovFetch';
|
||||
import URL from 'constants/url';
|
||||
|
||||
function Posts(props) {
|
||||
import { default as EgovLeftNav } from 'components/leftmenu/EgovLeftNavAdmin';
|
||||
|
||||
function StandardCodeMgt(props) {
|
||||
|
||||
return (
|
||||
<div className="container">
|
||||
Posts
|
||||
<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>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Posts;
|
||||
export default StandardCodeMgt;
|
||||
|
|
@ -1,13 +1,41 @@
|
|||
import React from 'react';
|
||||
import React, { useState, useEffect, useCallback } from 'react';
|
||||
import { Link, useLocation } from 'react-router-dom';
|
||||
|
||||
import * as EgovNet from 'api/egovFetch';
|
||||
import URL from 'constants/url';
|
||||
|
||||
function AboutSiteMgt(props) {
|
||||
import { default as EgovLeftNav } from 'components/leftmenu/EgovLeftNavAdmin';
|
||||
|
||||
function StandardCodeMgt(props) {
|
||||
|
||||
return (
|
||||
<div className="container">
|
||||
AboutSiteMgt
|
||||
<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>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default AboutSiteMgt;
|
||||
export default StandardCodeMgt;
|
||||
|
|
@ -1,25 +1,8 @@
|
|||
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 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';
|
||||
|
||||
import * as EgovNet from 'api/egovFetch';
|
||||
|
||||
|
||||
|
||||
|
|
@ -35,13 +18,12 @@ import { default as EgovLeftNav } from 'components/leftmenu/EgovLeftNavAdmin';
|
|||
|
||||
function CommitteeCodeMgt(props) {
|
||||
|
||||
const [dense, setDense] = useState(false);
|
||||
const [secondary, setSecondary] = useState(false);
|
||||
const [searchCondition, setSearchCondition] = useState({ paramCodeGroup: null, paramCodeLevel: 'LV_01' });
|
||||
|
||||
const [depth01List, setDepth01List] = useState(["중앙건설기술심의", "테스트2"]);
|
||||
const [depth02List, setDepth02List] = useState(["123", "테스트2"]);
|
||||
const [depth03List, setDepth03List] = useState(["다람쥐", "쳇바퀴"]);
|
||||
const [depth04List, setDepth04List] = useState(["임시 텍스트", "text"]);
|
||||
const [depth01List, setDepth01List] = useState([]);
|
||||
const [depth02List, setDepth02List] = useState([]);
|
||||
const [depth03List, setDepth03List] = useState([]);
|
||||
const [depth04List, setDepth04List] = useState([]);
|
||||
const [summaryArray, setSummaryArray] = useState({});
|
||||
|
||||
const [depth01SelectedIndex, setDepth01SelectedIndex] = React.useState();
|
||||
|
|
@ -49,13 +31,70 @@ 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}¶mCodeLevel=${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],
|
||||
"총괄위원회" : depth02List[depth02SelectedIndex],
|
||||
"건설기준위원회" : depth03List[depth03SelectedIndex],
|
||||
"실무위원회" : depth04List[depth04SelectedIndex],
|
||||
"중앙건설기술심의" : 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 : "",
|
||||
}
|
||||
);
|
||||
console.log(`${depth01List[depth01SelectedIndex]}[${depth01SelectedIndex}]`);
|
||||
|
|
@ -70,12 +109,6 @@ 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 (
|
||||
|
|
@ -90,6 +123,8 @@ function CommitteeCodeMgt(props) {
|
|||
)
|
||||
});
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<div className="container">
|
||||
<div className="c_wrap">
|
||||
|
|
@ -107,7 +142,6 @@ function CommitteeCodeMgt(props) {
|
|||
<div className="top_tit">
|
||||
<h1 className="tit_1">위원회 코드 관리</h1>
|
||||
</div>
|
||||
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
|
|
@ -119,11 +153,13 @@ function CommitteeCodeMgt(props) {
|
|||
},
|
||||
}}
|
||||
>
|
||||
<ListCreateUpdateDelete title="중앙건설기술심의" items={depth01List} setItemIndex={setDepth01SelectedIndex}/>
|
||||
<ListCreateUpdateDelete title="총괄위원회" items={depth02List} setItemIndex={setDepth02SelectedIndex}/>
|
||||
<ListCreateUpdateDelete title="건설기준위원회" items={depth03List} setItemIndex={setDepth03SelectedIndex}/>
|
||||
<ListCreateUpdateDelete title="실무위원회" items={depth04List} setItemIndex={setDepth04SelectedIndex}/>
|
||||
<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" />
|
||||
|
||||
</Box>
|
||||
{ true &&
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
|
|
@ -136,6 +172,8 @@ function CommitteeCodeMgt(props) {
|
|||
>
|
||||
<ListLabelInputs title="위원회 코드정보" items={summaryArray} />
|
||||
</Box>
|
||||
}
|
||||
|
||||
|
||||
{/* <!--// 본문 --> */}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,11 +1,39 @@
|
|||
import React from 'react';
|
||||
import React, { useState, useEffect, useCallback } 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';
|
||||
|
||||
function StandardCodeMgt(props) {
|
||||
|
||||
return (
|
||||
<div className="container">
|
||||
StandardCodeMgt
|
||||
<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>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, {useState, useEffect, useCallback, useRef, PureComponent} from 'react';
|
||||
import React, {useState, useEffect, useCallback} from 'react';
|
||||
import { Link, useLocation } from 'react-router-dom';
|
||||
|
||||
import {LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer} from 'recharts';
|
||||
|
|
@ -145,6 +145,7 @@ function FileConnections(props) {
|
|||
}
|
||||
);
|
||||
// console.groupEnd("EgovAdminPrivacyList.retrieveList()");
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
},[listTag]);
|
||||
|
||||
const CustomTooltip = ({ active, payload, label }) => {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, {useState, useEffect, useCallback, useRef, PureComponent} from 'react';
|
||||
import React, {useState, useEffect, useCallback} from 'react';
|
||||
import { Link, useLocation } from 'react-router-dom';
|
||||
import {BarChart, Bar, Rectangle, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer} from 'recharts';
|
||||
|
||||
|
|
@ -85,6 +85,7 @@ function MenuConnections(props) {
|
|||
}
|
||||
);
|
||||
// console.groupEnd("EgovAdminPrivacyList.retrieveList()");
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
},[listTag]);
|
||||
|
||||
const CustomTooltip = ({ active, payload, label }) => {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useState, useEffect, useCallback, useRef } from 'react';
|
||||
import React, { useState, useEffect, useCallback } from 'react';
|
||||
import { Link, useLocation } from 'react-router-dom';
|
||||
|
||||
import * as EgovNet from 'api/egovFetch';
|
||||
|
|
@ -77,6 +77,7 @@ function PrivacyConnections(props) {
|
|||
}
|
||||
);
|
||||
// console.groupEnd("EgovAdminPrivacyList.retrieveList()");
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
},[listTag]);
|
||||
|
||||
useEffect(() => {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, {useState, useEffect, useCallback, useRef, PureComponent} from 'react';
|
||||
import React, {useState, useEffect, useCallback} from 'react';
|
||||
import { Link, useLocation } from 'react-router-dom';
|
||||
import {BarChart, Bar, Rectangle, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer} from 'recharts';
|
||||
|
||||
|
|
@ -84,6 +84,7 @@ function UserConnections(props) {
|
|||
}
|
||||
);
|
||||
// console.groupEnd("EgovAdminPrivacyList.retrieveList()");
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
},[listTag]);
|
||||
|
||||
const CustomTooltip = ({ active, payload, label }) => {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,166 @@
|
|||
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>
|
||||
);
|
||||
}
|
||||
|
|
@ -1,202 +0,0 @@
|
|||
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;
|
||||
|
|
@ -1,364 +0,0 @@
|
|||
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;
|
||||
|
|
@ -1,328 +1,221 @@
|
|||
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 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 * as EgovNet from 'api/egovFetch';
|
||||
import URL from 'constants/url';
|
||||
import CODE from 'constants/code';
|
||||
// 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 {default as EgovLeftNav} from 'components/leftmenu/EgovLeftNavAdmin';
|
||||
|
||||
function EgovAdminScheduleList(props) {
|
||||
console.group("EgovAdminScheduleList");
|
||||
console.log("[Start] EgovAdminScheduleList ------------------------------");
|
||||
console.log("EgovAdminScheduleList [props] : ", props);
|
||||
function EgovAdminDashboard(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 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 [searchCondition, setSearchCondition] = useState(location.state?.searchCondition || {schdulSe: '', year: TODAY.getFullYear(), month: TODAY.getMonth(), date: TODAY.getDate()});
|
||||
const [calendarTag, setCalendarTag] = useState([]);
|
||||
// const innerConsole = (...args) => {
|
||||
// console.log(...args);
|
||||
// }
|
||||
|
||||
const [scheduleList, setScheduleList] = useState([]);
|
||||
const [dailyUserLogList, setDailyUserLogList] = 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 innerConsole = (...args) => {
|
||||
console.log(...args);
|
||||
}
|
||||
// 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 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 changeDate = (target, amount) => {
|
||||
let changedDate;
|
||||
// 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>
|
||||
// )
|
||||
// });
|
||||
|
||||
if (target === CODE.DATE_YEAR) {
|
||||
changedDate = new Date(searchCondition.year + amount, searchCondition.month, searchCondition.date);
|
||||
}
|
||||
// useEffect(() => {
|
||||
// //retrieveList(searchCondition); disabled by thkim
|
||||
// // eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
// }, [searchCondition]);
|
||||
|
||||
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 [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;
|
||||
// };
|
||||
|
||||
const retrieveList = useCallback((srchcnd) => {
|
||||
console.groupCollapsed("EgovAdminScheduleList.retrieveList()");
|
||||
// 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 retrieveListURL = '/schedule/month' + EgovNet.getQueryString(srchcnd);
|
||||
// console.log("------------------------------EgovAdminScheduleList [End]");
|
||||
// console.groupEnd("EgovAdminScheduleList");
|
||||
|
||||
const requestOptions = {
|
||||
method: "GET",
|
||||
headers: {
|
||||
'Content-type': 'application/json',
|
||||
}
|
||||
}
|
||||
// const [value, setValue] = useState('today');
|
||||
const [slot, setSlot] = useState('week');
|
||||
const [totalDownloads, setTotalDownloads] = useState(0);
|
||||
|
||||
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);
|
||||
// 총 다운로드 수를 받아온 후 state 업데이트
|
||||
const handleTotalDownloads = (sum) => {
|
||||
setTotalDownloads(sum);
|
||||
};
|
||||
|
||||
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 --> */}
|
||||
<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 --> */}
|
||||
|
||||
<div className="layout">
|
||||
|
|
@ -334,16 +227,132 @@ function EgovAdminScheduleList(props) {
|
|||
{/* <!-- 본문 --> */}
|
||||
|
||||
<div className="top_tit">
|
||||
<h1 className="tit_1">사이트관리</h1>
|
||||
<h1 className="tit_1">Dashboard</h1>
|
||||
</div>
|
||||
|
||||
<h2 className="tit_2"></h2>
|
||||
<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>
|
||||
|
||||
<ChartToggle isDailyChart={isDailyChart} onToggle={handleChartToggle}/>
|
||||
<Grid item md={8} sx={{ display: { sm: 'none', md: 'block', lg: 'none' } }} />
|
||||
|
||||
<div style={{width: 1000, height: 300}}>
|
||||
<UserLogChart/>
|
||||
</div>
|
||||
{/* 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>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -351,4 +360,4 @@ function EgovAdminScheduleList(props) {
|
|||
);
|
||||
}
|
||||
|
||||
export default EgovAdminScheduleList;
|
||||
export default EgovAdminDashboard;
|
||||
|
|
@ -0,0 +1,156 @@
|
|||
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;
|
||||
|
|
@ -0,0 +1,125 @@
|
|||
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;
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
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;
|
||||
|
|
@ -35,11 +35,9 @@ 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>
|
||||
|
|
|
|||
|
|
@ -35,11 +35,9 @@ 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>
|
||||
|
|
|
|||
|
|
@ -35,10 +35,9 @@ 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>
|
||||
|
||||
여기에 구현해주세요.
|
||||
{/* <!--// 본문 --> */}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useState, useEffect, useRef } from 'react';
|
||||
import React, { useState } 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 { getLocalItem, setLocalItem, setSessionItem } from 'utils/storage';
|
||||
import { setLocalItem } from 'utils/storage';
|
||||
import InfoShareChk from "./InfoShareChk";
|
||||
|
||||
function Join(props) {
|
||||
|
|
@ -21,7 +21,6 @@ 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()");
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,88 @@
|
|||
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;
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
|
||||
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;
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
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;
|
||||
|
|
@ -1,119 +1,17 @@
|
|||
import React, {useState, useEffect, useCallback, useRef} from 'react';
|
||||
import {Link, useLocation, useParams} from 'react-router-dom';
|
||||
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 * 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 StandardCodeList({listData, filterData, getHistoryModal}) {
|
||||
|
||||
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 historyBtn(item){
|
||||
getHistoryModal(item);
|
||||
}
|
||||
|
||||
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="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">
|
||||
<div className={"result standard_code_result"}>
|
||||
{listData.filter(item => {
|
||||
if (item.groupNm.includes(filterData)) {
|
||||
return item
|
||||
|
|
@ -125,20 +23,45 @@ function StandardCodeList({}) {
|
|||
<div className="mainCategory">{item.mainCategory}</div>
|
||||
<div className="middleCategory">{item.middleCategory}</div>
|
||||
<div className="kcscCd">{item.kcscCd}</div>
|
||||
<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 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>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
<StandardCodeListModal size={"lg"} show={show} content={groupSeq} onClose={close} title={"개정이력"}/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,30 +0,0 @@
|
|||
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};
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
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;
|
||||
|
||||
|
|
@ -1,16 +1,41 @@
|
|||
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}){
|
||||
function StandardCodeSearchForm({param, reloadFunction, resultCnt, remarkCnt, downloadModal}){
|
||||
|
||||
const [searchCondition, setSearchCondition] = useState({
|
||||
pageIndex: 1,
|
||||
tab: Number(param?.substring(0, 2)),
|
||||
category1: param?.substring(2, 4),
|
||||
category2: param?.substring(4, 6),
|
||||
searchWrd: ''
|
||||
category3: param?.substring(6, 8),
|
||||
});
|
||||
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){
|
||||
|
|
@ -22,6 +47,43 @@ function StandardCodeSearchForm({param, reloadFunction}){
|
|||
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">
|
||||
|
|
@ -40,45 +102,61 @@ function StandardCodeSearchForm({param, reloadFunction}){
|
|||
</li>
|
||||
<li className="third_1 L">
|
||||
<label className="f_select" htmlFor="sel1">
|
||||
<select id="sel1" title="조건" value={searchCondition.category1}>
|
||||
<select id="sel1" title="조건" value={searchCondition.category1}
|
||||
onChange={(e)=>{setSearchCondition({...searchCondition, category1: e.target.value})}}>
|
||||
<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}>
|
||||
<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} >
|
||||
<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">
|
||||
<div className={`tab`}>통합 다운로드</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
{subTabsVisible && (
|
||||
<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>
|
||||
{remarkCnt?(
|
||||
<span>전체 {resultCnt} / <span className={"text-danger"}>{remarkCnt}</span> 건</span>
|
||||
):(
|
||||
<span>전체 {resultCnt} 건</span>
|
||||
)}
|
||||
|
||||
</li>
|
||||
<li className="third_1 L">
|
||||
<div className={`tab`} onClick={downloadModal}>통합 다운로드</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>
|
||||
)}
|
||||
</Col>
|
||||
<Col xs={"auto"}>
|
||||
<Button href={"/standardCode/info"} size={"sm"} variant={"secondary"}>건설기준코드 안내</Button>
|
||||
</Col>
|
||||
</Row>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,17 +49,13 @@ const BookmarkModal = ({docCode, docPart, ymd}) => {
|
|||
})
|
||||
|
||||
const getCodeInfo = useCallback(() => {
|
||||
console.groupCollapsed("EgovMain.getCodeInfo()");
|
||||
EgovNet.requestFetch(
|
||||
'/standardCode/getCodeInfo.do',
|
||||
'/standardCode/code-info?docCode='+docCode,
|
||||
{
|
||||
method: "POST",
|
||||
method: "GET",
|
||||
headers: {
|
||||
'Content-type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
docCode: docCode
|
||||
})
|
||||
}
|
||||
},
|
||||
(resp) => {
|
||||
const docInfo = resp.result.docInfo;
|
||||
|
|
@ -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,18 +10,21 @@ import Row from 'react-bootstrap/Row';
|
|||
import Col from 'react-bootstrap/Col';
|
||||
import Modal from 'react-bootstrap/Modal';
|
||||
import * as EgovNet from 'api/egovFetch';
|
||||
import {getLocalItem} from "../../../utils/storage";
|
||||
import CODE from "../../../constants/code";
|
||||
import {parseJwt} from "../../../utils/parseJwt";
|
||||
import {getLocalItem} from "utils/storage";
|
||||
import CODE from "constants/code";
|
||||
import {parseJwt} from "utils/parseJwt";
|
||||
import Button from "react-bootstrap/Button";
|
||||
import {InputGroup} from "react-bootstrap";
|
||||
import ViewerTree from "./ViewerTree";
|
||||
|
||||
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();
|
||||
|
|
@ -29,6 +32,8 @@ 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;
|
||||
|
|
@ -44,65 +49,21 @@ function CodeViewer(props) {
|
|||
console.log("viewer [docCode] : ", docCode);
|
||||
|
||||
const updateDocCode = (docCode)=>{
|
||||
setDocSummary([<div></div>])
|
||||
setDocDetail([<div>불러오는중</div>])
|
||||
setDocInfo([])
|
||||
setDocLoading(true);
|
||||
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/getCodeInfo.do',
|
||||
'/standardCode/code-info?docCode='+docCode,
|
||||
{
|
||||
method: "POST",
|
||||
method: "GET",
|
||||
headers: {
|
||||
'Content-type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
docCode: docCode
|
||||
})
|
||||
}
|
||||
},
|
||||
(resp) => {
|
||||
const docInfo = resp.result.docInfo;
|
||||
|
|
@ -307,6 +268,7 @@ 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){
|
||||
|
|
@ -420,9 +382,15 @@ function CodeViewer(props) {
|
|||
}
|
||||
)
|
||||
}
|
||||
function treeControl(){
|
||||
if(colList[0]===3){
|
||||
setColList([0,3,9]);
|
||||
}else{
|
||||
setColList([3,2,7]);
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
getCodeTree();
|
||||
getCodeInfo(docCode);
|
||||
getCodeDetailInfo(docCode);
|
||||
}, []);
|
||||
|
|
@ -431,8 +399,9 @@ function CodeViewer(props) {
|
|||
console.groupEnd("viewer");
|
||||
return (
|
||||
<>
|
||||
{treeLoading || docLoading? (<Loading/>):(
|
||||
<Row className="mx-0">
|
||||
{/*{treeLoading || docLoading? ():()}*/}
|
||||
<Loading loadingState={treeLoading || docLoading}/>
|
||||
<Row className={`mx-0 ${treeLoading || docLoading?'d-none':''}`}>
|
||||
<Col xs={12} className="border-bottom">
|
||||
<Row>
|
||||
<Col xs={3}></Col>
|
||||
|
|
@ -443,26 +412,36 @@ 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="비교"/>
|
||||
<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="첨부파일"/>
|
||||
</Col>
|
||||
</Row>
|
||||
</Col>
|
||||
<Col xs={"auto"}>{errorSelector}</Col>
|
||||
<Col xs={"auto"}>
|
||||
<InputGroup>
|
||||
<Form.Control type="text" size={"sm"} placeholder={"문서 내 검색"}/>
|
||||
{errorSelector}
|
||||
</InputGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
</Col>
|
||||
</Row>
|
||||
</Col>
|
||||
<Col xs={3} className="border-end viewerDiv">
|
||||
{codeTree}
|
||||
<Col xs={colList[0]} className={`border-end viewerDiv ${colList[0]===3?'':'d-none'}`}>
|
||||
{/*{codeTree}*/}
|
||||
<ViewerTree docCode={docCode} updateDocCode={updateDocCode} setTreeLoading={setTreeLoading}/>
|
||||
</Col>
|
||||
<Col xs={2} className="border-end viewerDiv">
|
||||
<Col xs={colList[1]} className="border-end viewerDiv">
|
||||
<div>
|
||||
<Button size={"sm"} variant={"outline-secondary"} onClick={treeControl}>{colList[0]===3?'트리 접기':'트리 펼치기'}</Button>
|
||||
</div>
|
||||
{docSummary}
|
||||
</Col>
|
||||
<Col xs={7} className="viewerDiv detailInfoDiv" ref={actionAppend}>
|
||||
<Col xs={colList[2]} className="viewerDiv detailInfoDiv" ref={actionAppend}>
|
||||
{docDetail}
|
||||
</Col>
|
||||
</Row>
|
||||
)}
|
||||
<Modal show={show} onHide={handleClose} size="xl" keyboard={false} scrollable>
|
||||
{bookMarkModal}
|
||||
</Modal>
|
||||
|
|
@ -471,8 +450,8 @@ function CodeViewer(props) {
|
|||
}
|
||||
|
||||
CodeViewer.defaultProps = {
|
||||
docCode: 'KCS 24 31 10',
|
||||
docName: '용접(한계상태설계법)'
|
||||
docCode: 'KDS 11 10 15',
|
||||
docName: '지반계측'
|
||||
}
|
||||
|
||||
export default CodeViewer;
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
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;
|
||||
|
|
@ -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,11 +110,13 @@ import AdminLogsFileDownloadStatus from 'pages/admin/logs/FileDownloadStatus';
|
|||
|
||||
|
||||
//건설기준코드
|
||||
import CodeViewer from 'pages/standardCode/viewer/viewer';
|
||||
import CodeViewer from 'pages/standardCode/viewer/CodeViewer';
|
||||
import StandardCodePage from "../pages/standardCode/list/StandardCodePage";
|
||||
import StandardCodeInfo from "../pages/standardCode/info/StandardCodeInfo";
|
||||
|
||||
|
||||
import * as EgovNet from 'api/egovFetch'; // jwt토큰 위조 검사 때문에 추가
|
||||
import initPage from 'js/ui';
|
||||
import StandardCodeList from "../pages/standardCode/list/StandardCodeList";
|
||||
|
||||
const RootRoutes = () => {
|
||||
//useLocation객체를 이용하여 정규표현식을 사용한 /admin/~ 으로 시작하는 경로와 비교에 사용(아래 1줄) */}
|
||||
|
|
@ -136,6 +138,8 @@ const RootRoutes = () => {
|
|||
(resp) => {
|
||||
if (resp === false) {
|
||||
setMounted(false);
|
||||
alert("관리자 전용 페이지입니다.")
|
||||
window.location.href="/";
|
||||
} else {
|
||||
setMounted(true); // 이 값으로 true 일 때만 페이지를 렌더링이 되는 변수 사용.
|
||||
}
|
||||
|
|
@ -248,9 +252,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} />} />
|
||||
|
|
@ -304,7 +308,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 />} />
|
||||
|
|
@ -327,9 +331,10 @@ 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={<StandardCodeList />} />
|
||||
<Route path={URL.STANDARD_CODE_LIST_LINK} element={<StandardCodeList />} />
|
||||
<Route path={URL.STANDARD_CODE_LIST} element={<StandardCodePage />} />
|
||||
<Route path={URL.STANDARD_CODE_LIST_LINK} element={<StandardCodePage />} />
|
||||
|
||||
</Routes>
|
||||
<EgovFooter />
|
||||
|
|
|
|||
|
|
@ -0,0 +1,64 @@
|
|||
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
|
||||
};
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
// ==============================|| OVERRIDES - BADGE ||============================== //
|
||||
|
||||
export default function Badge(theme) {
|
||||
return {
|
||||
MuiBadge: {
|
||||
styleOverrides: {
|
||||
standard: {
|
||||
minWidth: theme.spacing(2),
|
||||
height: theme.spacing(2),
|
||||
padding: theme.spacing(0.5)
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// ==============================|| 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
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
// ==============================|| OVERRIDES - CARD CONTENT ||============================== //
|
||||
|
||||
export default function CardContent() {
|
||||
return {
|
||||
MuiCardContent: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
padding: 20,
|
||||
'&:last-child': {
|
||||
paddingBottom: 20
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
// ==============================|| OVERRIDES - CHECKBOX ||============================== //
|
||||
|
||||
export default function Checkbox(theme) {
|
||||
return {
|
||||
MuiCheckbox: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
color: theme.palette.secondary[300]
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
// ==============================|| 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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// ==============================|| 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'
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
// ==============================|| 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'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
// ==============================|| OVERRIDES - LINER PROGRESS ||============================== //
|
||||
|
||||
export default function LinearProgress() {
|
||||
return {
|
||||
MuiLinearProgress: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
height: 6,
|
||||
borderRadius: 100
|
||||
},
|
||||
bar: {
|
||||
borderRadius: 100
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
// ==============================|| OVERRIDES - LINK ||============================== //
|
||||
|
||||
export default function Link() {
|
||||
return {
|
||||
MuiLink: {
|
||||
defaultProps: {
|
||||
underline: 'hover'
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
// ==============================|| OVERRIDES - LIST ITEM ICON ||============================== //
|
||||
|
||||
export default function ListItemIcon() {
|
||||
return {
|
||||
MuiListItemIcon: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
minWidth: 24
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
// 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
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
// ==============================|| OVERRIDES - TAB ||============================== //
|
||||
|
||||
export default function Tab(theme) {
|
||||
return {
|
||||
MuiTab: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
minHeight: 46,
|
||||
color: theme.palette.text.primary
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
// ==============================|| 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
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
// ==============================|| OVERRIDES - TABS ||============================== //
|
||||
|
||||
export default function Tabs() {
|
||||
return {
|
||||
MuiTabs: {
|
||||
styleOverrides: {
|
||||
vertical: {
|
||||
overflow: 'visible'
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
// ==============================|| OVERRIDES - TYPOGRAPHY ||============================== //
|
||||
|
||||
export default function Typography() {
|
||||
return {
|
||||
MuiTypography: {
|
||||
styleOverrides: {
|
||||
gutterBottom: {
|
||||
marginBottom: 12
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
// 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()
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
// 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;
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
// 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;
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
// ==============================|| 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;
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
// ==============================|| 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;
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
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
|
|
@ -1,7 +1,11 @@
|
|||
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;
|
||||
|
|
@ -9,10 +13,15 @@ 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;
|
||||
|
||||
|
|
@ -24,6 +33,7 @@ public class AdminBoardsController extends BaseController {
|
|||
|
||||
private final AdminBoardsService adminBoardsService;
|
||||
|
||||
/* ---- 게시판관리 ----- */
|
||||
@Operation(
|
||||
summary = "게시판 목록 조회",
|
||||
description = "게시판 목록 조회",
|
||||
|
|
@ -42,4 +52,82 @@ 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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,8 @@ import org.hibernate.annotations.DynamicInsert;
|
|||
import org.hibernate.annotations.DynamicUpdate;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.time.LocalDate;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
|
|
@ -22,22 +23,25 @@ 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 char bbsAnsYn;
|
||||
private String bbsAnsYn;
|
||||
|
||||
@Column(name = "bbs_repl_yn", nullable = false)
|
||||
private char bbsReplYn;
|
||||
private String bbsReplYn;
|
||||
|
||||
@Column(name = "read_role_grp_id")
|
||||
private String readRoleGrpId;
|
||||
|
|
@ -52,16 +56,16 @@ public class TnBbs {
|
|||
private String frstCrtId;
|
||||
|
||||
@Column(name = "frst_crt_dt", nullable = false)
|
||||
private LocalDate frstCrtDt;
|
||||
private LocalDateTime frstCrtDt;
|
||||
|
||||
@Column(name = "last_chg_id")
|
||||
private String lastChgId;
|
||||
|
||||
@Column(name = "last_chg_dt")
|
||||
private LocalDate lastChgDt;
|
||||
private LocalDateTime lastChgDt;
|
||||
|
||||
@Column(name = "use_yn", nullable = false)
|
||||
private char useYn;
|
||||
private String useYn;
|
||||
|
||||
@Column(name = "oldd_seq")
|
||||
private Long olddSeq;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,83 @@
|
|||
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;
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
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> {
|
||||
|
||||
}
|
||||
|
|
@ -2,7 +2,13 @@ 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();
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,19 +1,71 @@
|
|||
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.findAll(); }
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
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;
|
||||
|
|
@ -9,20 +11,21 @@ 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.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.validation.Valid;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.HashMap;
|
||||
|
|
@ -37,6 +40,9 @@ public class AdminConfigController extends BaseController {
|
|||
private final AdminConfigService adminConfigService;
|
||||
private final CommonCodeService commonCodeService;
|
||||
|
||||
@Resource(name = "adminCommitteeCodeManagementService")
|
||||
private AdminCommitteeCodeManagementService adminCommitteeCodeManagementService;
|
||||
|
||||
@Operation(
|
||||
summary = "기본코드 그룹 조회",
|
||||
description = "기본코드 그룹 조회",
|
||||
|
|
@ -350,4 +356,50 @@ 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
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;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
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;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +1,10 @@
|
|||
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;
|
||||
|
|
@ -10,6 +12,8 @@ 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;
|
||||
|
|
@ -30,57 +34,116 @@ 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.GET, value = "/daily-user-log-list", consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||
public ResultVO getDailyUserLogList() throws Exception {
|
||||
@RequestMapping(method = RequestMethod.POST, value = "/menu-login", consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||
public ResultVO getMenuVisit(@AuthenticationPrincipal LoginVO user)
|
||||
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("menuMonthlyList", adminDashboardService.selectMenuMonthly());
|
||||
resultMap.put("menuDailyList", adminDashboardService.selectMenuDaily());
|
||||
resultMap.put("loginMonthlyList", adminDashboardService.selectLoginMonthly());
|
||||
resultMap.put("loginDailyList", adminDashboardService.selectLoginDaily());
|
||||
|
||||
resultMap.put("dailyUserLogList", adminDashboardService.selectDailyUserLogList(startDate, endDate));
|
||||
resultVO.setResultCode(ResponseCode.SUCCESS.getCode());
|
||||
resultVO.setResultMessage(ResponseCode.SUCCESS.getMessage());
|
||||
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.GET, value = "/monthly-user-log-list", consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||
public ResultVO getMonthlyUserLogList() throws Exception {
|
||||
@RequestMapping(method = RequestMethod.POST, value = "/file", consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||
public ResultVO getfile(@AuthenticationPrincipal LoginVO user)
|
||||
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("fileDailyList", adminDashboardService.selectFileDaily());
|
||||
|
||||
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.setResultCode(ResponseCode.SUCCESS.getCode());
|
||||
resultVO.setResultMessage(ResponseCode.SUCCESS.getMessage());
|
||||
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;
|
||||
// }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,83 @@
|
|||
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();
|
||||
}
|
||||
|
||||
|
|
@ -1,24 +1,38 @@
|
|||
package com.dbnt.kcscbackend.admin.dashboard.service;
|
||||
|
||||
import com.dbnt.kcscbackend.admin.dashboard.entity.TnDailyUserLog;
|
||||
import com.dbnt.kcscbackend.admin.dashboard.repository.TnDailyUserLogRepository;
|
||||
//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 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 TnDailyUserLogRepository tnDailyUserLogRepository;
|
||||
private final MenuMonthlyRepository menuMonthlyRepository;
|
||||
|
||||
public List<TnDailyUserLog> selectDailyUserLogList(LocalDate startDate, LocalDate endDate) {
|
||||
return tnDailyUserLogRepository.findByLogDtBetweenOrderByLogDt(startDate, endDate);
|
||||
}
|
||||
public List<Long> selectMenuMonthly() { return menuMonthlyRepository.MenuMonthlyList(); }
|
||||
|
||||
public List<Object[]> selectMonthlyUserLogList(LocalDate startDate, LocalDate endDate) {
|
||||
return tnDailyUserLogRepository.selectMonthlyUserLogStatistics(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);
|
||||
// }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
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;
|
||||
|
|
@ -11,7 +9,6 @@ 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;
|
||||
|
|
|
|||
|
|
@ -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 true;
|
||||
return egovJwtTokenUtil.getUserIdFromToken(clientToken).equals("admin");
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -35,6 +35,9 @@ 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 = "아이디를 입력해주세요.")
|
||||
|
|
|
|||
|
|
@ -8,5 +8,6 @@ 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);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ 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) );
|
||||
|
|
|
|||
|
|
@ -57,7 +57,8 @@ 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{
|
||||
|
|
@ -69,7 +70,13 @@ 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));
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ public class SecurityConfig {
|
|||
"/swagger-ui/**",
|
||||
|
||||
/*기준코드 조회*/
|
||||
"/standardCode/**.do"
|
||||
"/standardCode/**"
|
||||
};
|
||||
private static final String[] ORIGINS_WHITELIST = {
|
||||
"http://localhost:3000",
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ 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;
|
||||
|
|
@ -60,7 +61,7 @@ public class StandardCodeController extends BaseController {
|
|||
@ApiResponse(responseCode = "200", description = "조회 성공"),
|
||||
@ApiResponse(responseCode = "403", description = "인가된 사용자가 아님")
|
||||
})
|
||||
@RequestMapping(method = RequestMethod.POST, value = "/getCodeTree.do", consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||
@RequestMapping(method = RequestMethod.GET, value = "/code-tree")
|
||||
public ResultVO getCodeTree() throws Exception {
|
||||
ResultVO resultVO = new ResultVO();
|
||||
Map<String, Object> resultMap = new HashMap<>();
|
||||
|
|
@ -98,8 +99,8 @@ public class StandardCodeController extends BaseController {
|
|||
@ApiResponse(responseCode = "200", description = "조회 성공"),
|
||||
@ApiResponse(responseCode = "403", description = "인가된 사용자가 아님")
|
||||
})
|
||||
@PostMapping(value = "/getCodeInfo.do", consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||
public ResultVO getCodeInfo(@RequestBody StandardCodeVO param, @AuthenticationPrincipal LoginVO user)
|
||||
@GetMapping(value = "/code-info", consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||
public ResultVO getCodeInfo(StandardCodeVO param, @AuthenticationPrincipal LoginVO user)
|
||||
throws Exception {
|
||||
ResultVO resultVO = new ResultVO();
|
||||
Map<String, Object> resultMap = new HashMap<>();
|
||||
|
|
@ -151,25 +152,10 @@ public class StandardCodeController extends BaseController {
|
|||
ResultVO resultVO = new ResultVO();
|
||||
Map<String, Object> resultMap = new HashMap<>();
|
||||
|
||||
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);
|
||||
tnDocumentInfo.makeListCode();
|
||||
tnDocumentInfo.setUserSeq(user.getUserSeq());
|
||||
resultMap.put("resultList", standardCodeService.selectStandardCodeList(tnDocumentInfo));
|
||||
resultMap.put("resultCnt", standardCodeService.selectStandardCodeListCnt(tnDocumentInfo));
|
||||
|
||||
resultVO.setResultCode(ResponseCode.SUCCESS.getCode());
|
||||
resultVO.setResultMessage(ResponseCode.SUCCESS.getMessage());
|
||||
|
|
@ -177,6 +163,84 @@ 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 = "건설기준코드 개정이력 조회",
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import javax.persistence.Column;
|
|||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Transient;
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
|
|
@ -28,15 +29,24 @@ 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;
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,40 @@
|
|||
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;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
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;
|
||||
|
|
@ -92,11 +93,18 @@ 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;
|
||||
private String category3 = "";
|
||||
@Transient
|
||||
private Integer userSeq;
|
||||
|
||||
@JsonIgnore
|
||||
public void makeListCode(){
|
||||
setListCode(getTab()+getCategory1()+getCategory2()+getCategory3());
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue