대시보드 사용자 접속현황 그래프(6개월 전으로 해놓음)
parent
20a84b6d1e
commit
0e16df04a4
File diff suppressed because it is too large
Load Diff
|
|
@ -13,6 +13,7 @@
|
|||
"react-loader-spinner": "^5.4.5",
|
||||
"react-router-dom": "^6.4.0",
|
||||
"react-scripts": "5.0.1",
|
||||
"recharts": "^2.10.3",
|
||||
"styled-components": "^6.0.9",
|
||||
"web-vitals": "^2.1.4"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,27 +1,29 @@
|
|||
import React, { useState, useEffect, useCallback } from 'react';
|
||||
import { Link, useLocation } from 'react-router-dom';
|
||||
import React, {useState, useEffect, useCallback, PureComponent} from 'react';
|
||||
import {Link, useLocation} from 'react-router-dom';
|
||||
import {BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer} from 'recharts';
|
||||
|
||||
import * as EgovNet from 'api/egovFetch';
|
||||
import URL from 'constants/url';
|
||||
import CODE from 'constants/code';
|
||||
|
||||
import { default as EgovLeftNav } from 'components/leftmenu/EgovLeftNavAdmin';
|
||||
import {default as EgovLeftNav} from 'components/leftmenu/EgovLeftNavAdmin';
|
||||
|
||||
function EgovAdminScheduleList(props) {
|
||||
console.group("EgovAdminScheduleList");
|
||||
console.log("[Start] EgovAdminScheduleList ------------------------------");
|
||||
console.log("EgovAdminScheduleList [props] : ", props);
|
||||
|
||||
|
||||
const location = useLocation();
|
||||
console.log("EgovAdminScheduleList [location] : ", location);
|
||||
|
||||
const DATE = new Date();
|
||||
const TODAY = new Date(DATE.getFullYear(), DATE.getMonth(), DATE.getDate());
|
||||
|
||||
const [searchCondition, setSearchCondition] = useState(location.state?.searchCondition || { schdulSe: '', year: TODAY.getFullYear(), month: TODAY.getMonth(), date: TODAY.getDate() });
|
||||
const [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 [dailyUserLogList, setDailyUserLogList] = useState([]);
|
||||
|
||||
const innerConsole = (...args) => {
|
||||
console.log(...args);
|
||||
|
|
@ -45,14 +47,14 @@ function EgovAdminScheduleList(props) {
|
|||
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() });
|
||||
setSearchCondition({...searchCondition, year: changedDate.getFullYear(), month: changedDate.getMonth(), date: changedDate.getDate()});
|
||||
}
|
||||
|
||||
const retrieveList = useCallback((srchcnd) => {
|
||||
console.groupCollapsed("EgovAdminScheduleList.retrieveList()");
|
||||
|
||||
const retrieveListURL = '/schedule/month'+EgovNet.getQueryString(srchcnd);
|
||||
|
||||
const retrieveListURL = '/schedule/month' + EgovNet.getQueryString(srchcnd);
|
||||
|
||||
const requestOptions = {
|
||||
method: "GET",
|
||||
headers: {
|
||||
|
|
@ -70,7 +72,7 @@ function EgovAdminScheduleList(props) {
|
|||
}
|
||||
);
|
||||
console.groupEnd("EgovAdminScheduleList.retrieveList()");
|
||||
},[]);
|
||||
}, []);
|
||||
|
||||
const drawCalendar = () => {
|
||||
console.groupCollapsed("EgovAdminScheduleList.drawCalendar()");
|
||||
|
|
@ -138,7 +140,7 @@ function EgovAdminScheduleList(props) {
|
|||
|
||||
let mutCalendarTagList = [];
|
||||
let keyIdx = 0;
|
||||
|
||||
|
||||
//draw Calendar
|
||||
monthArr.forEach((week, weekIdx) => {
|
||||
console.log();
|
||||
|
|
@ -151,7 +153,8 @@ function EgovAdminScheduleList(props) {
|
|||
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 />
|
||||
<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));
|
||||
|
|
@ -161,11 +164,11 @@ function EgovAdminScheduleList(props) {
|
|||
if (iUseDate >= iBeginDate && iUseDate <= iEndDate) {
|
||||
return (
|
||||
<>
|
||||
<Link to={{pathname: URL.ADMIN_SCHEDULE_DETAIL}}
|
||||
state={{schdulId : schedule.schdulId}}
|
||||
key={keyIdx++}>{schedule.schdulNm}
|
||||
<Link to={{pathname: URL.ADMIN_SCHEDULE_DETAIL}}
|
||||
state={{schdulId: schedule.schdulId}}
|
||||
key={keyIdx++}>{schedule.schdulNm}
|
||||
</Link>
|
||||
<br />
|
||||
<br/>
|
||||
</>
|
||||
);
|
||||
} else return <></>
|
||||
|
|
@ -176,7 +179,8 @@ function EgovAdminScheduleList(props) {
|
|||
} else {//일정 없는 경우
|
||||
return (
|
||||
<td key={keyIdx++}>
|
||||
<Link to={{pathname: URL.ADMIN_SCHEDULE_CREATE}} state={{iUseDate : mutsUseYearMonth + sDate + "000000"}} className="day" key={keyIdx++}>{day}</Link><br />
|
||||
<Link to={{pathname: URL.ADMIN_SCHEDULE_CREATE}} state={{iUseDate: mutsUseYearMonth + sDate + "000000"}} className="day"
|
||||
key={keyIdx++}>{day}</Link><br/>
|
||||
</td>);
|
||||
}
|
||||
} else if (day === 0) {// 이전달/다음달 구현
|
||||
|
|
@ -190,7 +194,7 @@ function EgovAdminScheduleList(props) {
|
|||
console.groupEnd("EgovAdminScheduleList.drawCalendar()");
|
||||
}
|
||||
|
||||
const Location = React.memo(function Location() {
|
||||
const Location = React.memo(function Location() {
|
||||
return (
|
||||
<div className="location">
|
||||
<ul>
|
||||
|
|
@ -204,21 +208,123 @@ function EgovAdminScheduleList(props) {
|
|||
|
||||
useEffect(() => {
|
||||
retrieveList(searchCondition);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [searchCondition]);
|
||||
|
||||
useEffect(() => {
|
||||
drawCalendar();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [scheduleList]);
|
||||
|
||||
const getDailyUserLogList = useCallback(() => {
|
||||
console.groupCollapsed("EgovAdminScheduleList.getDailyUserLogList()");
|
||||
|
||||
const dailyUserLogListURL = '/admin/dashboard/daily-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()");
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
getDailyUserLogList();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
const data = dailyUserLogList.map(item => ({
|
||||
logDt: item.logDt,
|
||||
uv: item.mobileCnt,
|
||||
"사용자 접속현황": item.logCnt,
|
||||
amt: item.pcCnt,
|
||||
}));
|
||||
|
||||
const getIntroOfPage = (label) => {
|
||||
if (label === 'Page A') {
|
||||
return "Page A is about men's clothing";
|
||||
}
|
||||
if (label === 'Page B') {
|
||||
return "Page B is about women's dress";
|
||||
}
|
||||
if (label === 'Page C') {
|
||||
return "Page C is about women's bag";
|
||||
}
|
||||
if (label === 'Page D') {
|
||||
return 'Page D is about household goods';
|
||||
}
|
||||
if (label === 'Page E') {
|
||||
return 'Page E is about food';
|
||||
}
|
||||
if (label === 'Page F') {
|
||||
return 'Page F is about baby food';
|
||||
}
|
||||
return '';
|
||||
};
|
||||
|
||||
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>
|
||||
<p className="intro">{getIntroOfPage(label)}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
class Example 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 />
|
||||
<Location/>
|
||||
{/* <!--// Location --> */}
|
||||
|
||||
<div className="layout">
|
||||
|
|
@ -235,15 +341,19 @@ function EgovAdminScheduleList(props) {
|
|||
|
||||
<h2 className="tit_2">일정관리</h2>
|
||||
|
||||
<div style={{width: 1000, height: 300}}>
|
||||
<Example/>
|
||||
</div>
|
||||
|
||||
{/* <!-- 검색조건 --> */}
|
||||
<div className="condition">
|
||||
<ul>
|
||||
<li>
|
||||
<label className="f_select" htmlFor="sel1">
|
||||
<select name="schdulSe" id="sel1" title="조건"
|
||||
onChange={e => {
|
||||
setSearchCondition({ ...searchCondition, schdulSe: e.target.value });
|
||||
}}
|
||||
onChange={e => {
|
||||
setSearchCondition({...searchCondition, schdulSe: e.target.value});
|
||||
}}
|
||||
>
|
||||
<option value="">전체</option>
|
||||
<option value="1">회의</option>
|
||||
|
|
@ -256,28 +366,28 @@ function EgovAdminScheduleList(props) {
|
|||
</li>
|
||||
<li className="half L">
|
||||
<button className="prev"
|
||||
onClick={() => {
|
||||
changeDate(CODE.DATE_YEAR, -1);
|
||||
}}
|
||||
onClick={() => {
|
||||
changeDate(CODE.DATE_YEAR, -1);
|
||||
}}
|
||||
></button>
|
||||
<span>{searchCondition.year}</span>
|
||||
<button className="next"
|
||||
onClick={() => {
|
||||
changeDate(CODE.DATE_YEAR, 1);
|
||||
}}
|
||||
onClick={() => {
|
||||
changeDate(CODE.DATE_YEAR, 1);
|
||||
}}
|
||||
></button>
|
||||
</li>
|
||||
<li className="half R">
|
||||
<button className="prev"
|
||||
onClick={() => {
|
||||
changeDate(CODE.DATE_MONTH, -1);
|
||||
}}
|
||||
onClick={() => {
|
||||
changeDate(CODE.DATE_MONTH, -1);
|
||||
}}
|
||||
></button>
|
||||
<span>{(searchCondition.month + 1)}</span>
|
||||
<button className="next"
|
||||
onClick={() => {
|
||||
changeDate(CODE.DATE_MONTH, 1);
|
||||
}}
|
||||
onClick={() => {
|
||||
changeDate(CODE.DATE_MONTH, 1);
|
||||
}}
|
||||
></button>
|
||||
</li>
|
||||
</ul>
|
||||
|
|
@ -287,18 +397,18 @@ function EgovAdminScheduleList(props) {
|
|||
<div className="calendar_list">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>일</th>
|
||||
<th>월</th>
|
||||
<th>화</th>
|
||||
<th>수</th>
|
||||
<th>목</th>
|
||||
<th>금</th>
|
||||
<th>토</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>일</th>
|
||||
<th>월</th>
|
||||
<th>화</th>
|
||||
<th>수</th>
|
||||
<th>목</th>
|
||||
<th>금</th>
|
||||
<th>토</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{calendarTag}
|
||||
{calendarTag}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,55 @@
|
|||
package com.dbnt.kcscbackend.admin.dashboard;
|
||||
|
||||
import com.dbnt.kcscbackend.admin.dashboard.service.AdminDashboardService;
|
||||
import com.dbnt.kcscbackend.config.common.BaseController;
|
||||
import com.dbnt.kcscbackend.config.common.ResultVO;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/admin/dashboard")
|
||||
@Tag(name="AdminDashboardController", description = "사이트관리 대시보드")
|
||||
public class AdminDashboardController extends BaseController {
|
||||
|
||||
private final AdminDashboardService adminDashboardService;
|
||||
|
||||
@Operation(
|
||||
summary = "기본코드 그룹 조회",
|
||||
description = "기본코드 그룹 조회",
|
||||
tags = {"AdminConfigController"}
|
||||
)
|
||||
@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);
|
||||
|
||||
System.out.println("@@@ localdate : " + endDate);
|
||||
|
||||
// 3개월 전 날짜 계산
|
||||
LocalDate startDate = endDate.minusMonths(3);
|
||||
|
||||
resultMap.put("dailyUserLogList", adminDashboardService.selectDailyUserLogList(startDate, endDate));
|
||||
resultVO.setResult(resultMap);
|
||||
return resultVO;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
package com.dbnt.kcscbackend.admin.dashboard.entity;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
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.LocalDate;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Entity
|
||||
@NoArgsConstructor
|
||||
@DynamicInsert
|
||||
@DynamicUpdate
|
||||
@Table(name = "tn_daily_user_log")
|
||||
public class TnDailyUserLog {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Column(name = "dul_seq")
|
||||
private Long dulSeq;
|
||||
|
||||
@Column(name = "log_dt")
|
||||
private LocalDate logDt;
|
||||
|
||||
@Column(name = "log_cnt")
|
||||
private Integer logCnt;
|
||||
|
||||
@Column(name = "mobile_cnt")
|
||||
private Integer mobileCnt;
|
||||
|
||||
@Column(name = "pc_cnt")
|
||||
private Integer pcCnt;
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package com.dbnt.kcscbackend.admin.dashboard.repository;
|
||||
|
||||
import com.dbnt.kcscbackend.admin.dashboard.entity.TnDailyUserLog;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
public interface TnDailyUserLogRepository extends JpaRepository<TnDailyUserLog, Long> {
|
||||
List<TnDailyUserLog> findByLogDtBetweenOrderByLogDt(LocalDate startDate, LocalDate endDate);
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package com.dbnt.kcscbackend.admin.dashboard.service;
|
||||
|
||||
import com.dbnt.kcscbackend.admin.dashboard.entity.TnDailyUserLog;
|
||||
import com.dbnt.kcscbackend.admin.dashboard.repository.TnDailyUserLogRepository;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.egovframe.rte.fdl.cmmn.EgovAbstractServiceImpl;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class AdminDashboardService extends EgovAbstractServiceImpl {
|
||||
private final TnDailyUserLogRepository tnDailyUserLogRepository;
|
||||
|
||||
public List<TnDailyUserLog> selectDailyUserLogList(LocalDate startDate, LocalDate endDate) {
|
||||
return tnDailyUserLogRepository.findByLogDtBetweenOrderByLogDt(startDate, endDate);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue