Browse Source

대시보드(드론 현황) 작업 및 chart empty 처리

pull/2/head
김장현 10 months ago
parent
commit
e13120e08a
  1. 146
      src/components/dashboard/DashboardStcsArea.js
  2. 87
      src/components/dashboard/DashboardStcsDay.js
  3. 31
      src/containers/main/dash/MainDashContainer.js
  4. 5
      src/modules/main/dash/apis/mainDashApi.ts
  5. 13
      src/modules/main/dash/models/mainDashModel.ts
  6. 23
      src/modules/main/dash/sagas/mainDashSaga.ts

146
src/components/dashboard/DashboardStcsArea.js

@ -40,82 +40,75 @@ const options = {
} }
}; };
const arrColors = [
successColorShade,
warningLightColor,
primaryColorShade,
yellowColor,
blueColor
];
const arrColorsClass = [
'successColorShade',
'warningLightColor',
'primaryColorShade',
'yellowColor',
'blueColor'
];
const titles = { const titles = {
droneStatus: '드론 현황', droneStatus: '드론 현황',
flightsRegion: 'TOP5 지역 별 비행횟수 통계' flightsRegion: 'TOP5 지역 별 비행횟수 통계'
}; };
export const DashboardStcsArea = props => { export const DashboardStcsArea = ({ data, title, setStartDate, startDate }) => {
const [chartData, setChartData] = useState({}); const [chartData, setChartData] = useState({});
const arrColors = [ useEffect(() => {
successColorShade, chartDataInit();
warningLightColor, }, [data]);
primaryColorShade,
yellowColor,
blueColor
];
const arrColorsClass = [
'successColorShade',
'warningLightColor',
'primaryColorShade',
'yellowColor',
'blueColor'
];
const chartDataInit = () => { const chartDataInit = () => {
let arrArea = []; if (data.length > 0) {
let arrValue = []; let arrArea = [];
let arrValue = [];
props.data?.map(item => { data?.map(item => {
arrArea.push(item.typeCd); arrArea.push(item.typeCd);
arrValue.push(item.count); arrValue.push(item.count);
}); });
setChartData({ setChartData({
labels: arrArea, labels: arrArea,
datasets: [ datasets: [
{ {
data: arrValue, data: arrValue,
backgroundColor: arrColors, backgroundColor: arrColors,
borderWidth: 0, borderWidth: 0,
pointStyle: 'rectRounded' pointStyle: 'rectRounded'
} }
] ]
}); });
} else {
setChartData({});
}
}; };
useEffect(() => {
chartDataInit();
}, [props.data]);
return ( return (
<Card> <Card>
<CardHeader className=''> <CardHeader className=''>
<div className='w-100 d-flex justify-content-between'> <div className='w-100 d-flex justify-content-between'>
<CardTitle tag='h4'>{titles[`${props.title}`]}</CardTitle> <CardTitle tag='h4'>{titles[`${title}`]}</CardTitle>
{/* <div className='d-flex align-items-center'>
<Calendar size={14} />
<Flatpickr
options={{
mode: 'single',
dateFormat: "Y-m-d",
defaultDate: ['today'],
}}
className='form-control flat-picker bg-transparent border-0 shadow-none'
/>
</div> */}
<div className='d-flex align-items-center'> <div className='d-flex align-items-center'>
{props.title === 'flightsRegion' && ( {title === 'flightsRegion' && (
<> <>
<div className='datepicker-border-sm'> <div className='datepicker-border-sm'>
<div className='datepicker-custom'> <div className='datepicker-custom'>
<Calendar size={14} /> <Calendar size={14} />
<DatePicker <DatePicker
locale={ko} locale={ko}
selected={props.startDate} selected={startDate}
onChange={date => props.setStartDate(date)} onChange={date => setStartDate(date)}
dateFormat='yyy / MMMM' dateFormat='yyy / MMMM'
showMonthYearPicker showMonthYearPicker
showFullMonthYearPicker showFullMonthYearPicker
@ -134,32 +127,16 @@ export const DashboardStcsArea = props => {
</CardHeader> </CardHeader>
<CardBody> <CardBody>
<div style={{ height: '275px' }}> <div style={{ height: '275px' }}>
<Doughnut {Object.keys(chartData).length > 0 ? (
data={chartData} <Doughnut data={chartData} options={options} height={275} />
options={options} ) : (
height={275} <div className='d-flex justify-content-center align-items-center h-100'>
plugins={{ <p>표시할 데이터가 없습니다.</p>
afterDraw: function (chart) { </div>
let ctx = chart.chart.ctx; )}
let width = chart.chart.width;
let height = chart.chart.height;
chart.clear();
ctx.save();
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText(
'표시할 데이터가 없습니다.',
width / 2,
height / 2
);
ctx.restore();
}
}}
/>
</div> </div>
<div className='doughnut-chart-list'> <div className='doughnut-chart-list'>
{props.data?.map((item, index) => { {data?.map((item, index) => {
return ( return (
<div key={index}> <div key={index}>
<div className='doughnut-chart-list-ti'> <div className='doughnut-chart-list-ti'>
@ -167,23 +144,6 @@ export const DashboardStcsArea = props => {
<span className='ti'>{item.typeCd}</span> <span className='ti'>{item.typeCd}</span>
<span className='ti'>({item.count})</span> <span className='ti'>({item.count})</span>
</div> </div>
{/* <div className='doughnut-chart-list-ti'>
<span className='dot-icon warningLightColor'></span>
<span className='ti'>인천광역시</span>
</div>
<div className='doughnut-chart-list-ti'>
<span className='dot-icon primaryColorShade'></span>
<span className='ti'>충청북도</span>
</div>
<div className='doughnut-chart-list-ti'>
<span className='dot-icon yellowColor'></span>
<span className='ti'>세종시</span>
</div>
<div className='doughnut-chart-list-ti'>
<span className='dot-icon blueColor'></span>
<span className='ti'>제주도</span>
</div> */}
</div> </div>
); );
})} })}

87
src/components/dashboard/DashboardStcsDay.js

@ -1,7 +1,7 @@
import 'react-datepicker/dist/react-datepicker.css'; import 'react-datepicker/dist/react-datepicker.css';
import { ko } from 'date-fns/esm/locale'; import { ko } from 'date-fns/esm/locale';
import { Plus } from 'react-feather'; import { Plus } from 'react-feather';
import { useEffect, useState } from 'react'; import { useEffect, useState, useRef } from 'react';
import { Bar } from 'react-chartjs-2'; import { Bar } from 'react-chartjs-2';
import DatePicker from 'react-datepicker'; import DatePicker from 'react-datepicker';
import { Calendar } from 'react-feather'; import { Calendar } from 'react-feather';
@ -61,7 +61,7 @@ const options = {
}, },
ticks: { ticks: {
stepSize: 1, stepSize: 1,
// min: 0, min: 0,
// max: 400, // max: 400,
fontColor: '#6e6b7bs' fontColor: '#6e6b7bs'
} }
@ -73,33 +73,36 @@ const options = {
export const DashboardStcsDay = ({ startDate, setStartDate, data }) => { export const DashboardStcsDay = ({ startDate, setStartDate, data }) => {
const [chartData, setChartData] = useState({}); const [chartData, setChartData] = useState({});
const chartDataInit = () => { useEffect(() => {
let arrDay = []; chartDataInit();
let arrValue = []; }, [data]);
data?.map(item => { const chartDataInit = () => {
arrDay.push(item.typeCd); if (data.length > 0) {
arrValue.push(item.count); let arrDay = [];
}); let arrValue = [];
setChartData({ data.map(item => {
labels: arrDay, arrDay.push(item.typeCd);
arrValue.push(item.count);
});
datasets: [ setChartData({
{ labels: [...arrDay],
data: arrValue, datasets: [
backgroundColor: successColorShade, {
borderColor: 'transparent', data: [...arrValue],
barThickness: 15 backgroundColor: successColorShade,
} borderColor: 'transparent',
] barThickness: 15
}); }
]
});
} else {
setChartData({});
}
}; };
useEffect(() => {
chartDataInit();
}, [data]);
return ( return (
<Card> <Card>
<CardHeader className='d-flex justify-content-between align-items-sm-center align-items-start flex-sm-row flex-column'> <CardHeader className='d-flex justify-content-between align-items-sm-center align-items-start flex-sm-row flex-column'>
@ -112,7 +115,9 @@ export const DashboardStcsDay = ({ startDate, setStartDate, data }) => {
<DatePicker <DatePicker
locale={ko} locale={ko}
selected={startDate} selected={startDate}
onChange={date => setStartDate(date)} onChange={date => {
setStartDate(date);
}}
dateFormat='yyy / MMMM' dateFormat='yyy / MMMM'
showMonthYearPicker showMonthYearPicker
showFullMonthYearPicker showFullMonthYearPicker
@ -129,31 +134,13 @@ export const DashboardStcsDay = ({ startDate, setStartDate, data }) => {
</CardHeader> </CardHeader>
<CardBody> <CardBody>
<div style={{ height: '400px' }}> <div style={{ height: '400px' }}>
<Bar {Object.keys(chartData).length > 0 ? (
data={chartData} <Bar data={chartData} options={options} height={400} />
options={options} ) : (
height={400} <div className='d-flex justify-content-center align-items-center h-100'>
plugins={{ <p>표시할 데이터가 없습니다.</p>
afterDraw: function (chart) { </div>
if (data.length <= 0) { )}
let ctx = chart.chart.ctx;
let width = chart.chart.width;
let height = chart.chart.height;
chart.clear();
ctx.save();
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText(
'표시할 데이터가 없습니다.',
width / 2,
height / 2
);
ctx.restore();
}
}
}}
/>
</div> </div>
</CardBody> </CardBody>
</Card> </Card>

31
src/containers/main/dash/MainDashContainer.js

@ -23,6 +23,9 @@ export const MainDashContainer = () => {
state => [state.mainDashState.dashboardData], state => [state.mainDashState.dashboardData],
shallowEqual shallowEqual
); );
const { stcsDayList, stcsAreaList } = useSelector(
state => state.mainDashState
);
const { user } = useSelector(state => state.authState, shallowEqual); const { user } = useSelector(state => state.authState, shallowEqual);
const [dayStartDate, setDayStartDate] = useState(new Date()); const [dayStartDate, setDayStartDate] = useState(new Date());
const [areaStartDate, setAreaStartDate] = useState(new Date()); const [areaStartDate, setAreaStartDate] = useState(new Date());
@ -60,13 +63,10 @@ export const MainDashContainer = () => {
); );
}; };
const handlerStcsDayParam = useCallback( const handlerStcsDayParam = date => {
date => { setDayStartDate(date);
setDayStartDate(date); handlerStcsDaySearch(date);
handlerStcsDaySearch(date); };
},
[dayStartDate]
);
const handlerStcsAreaParam = date => { const handlerStcsAreaParam = date => {
setAreaStartDate(date); setAreaStartDate(date);
@ -85,13 +85,9 @@ export const MainDashContainer = () => {
history.push(url); history.push(url);
}; };
useEffect(() => { useEffect(() => {
dispatch( dispatch(Actions.DASHBOARD_DATA.request());
Actions.DASHBOARD_DATA.request({ handlerStcsDaySearch(dayStartDate);
stcsDay: moment(dayStartDate).format('YYYY-MM') handlerStcsAreaSearch(areaStartDate);
})
);
// handlerStcsDaySearch(dayStartDate);
// handlerStcsAreaSearch(areaStartDate);
// handlerGroupSearch(); // handlerGroupSearch();
// handlerDronSearch(); // handlerDronSearch();
}, []); }, []);
@ -136,7 +132,7 @@ export const MainDashContainer = () => {
<DashboardStcsArea <DashboardStcsArea
startDate={areaStartDate} startDate={areaStartDate}
setStartDate={handlerStcsAreaParam} setStartDate={handlerStcsAreaParam}
// data={stcsAreaList} data={dashboardData?.dronSituation || []}
title='droneStatus' title='droneStatus'
/> />
</Col> </Col>
@ -148,10 +144,9 @@ export const MainDashContainer = () => {
<DashboardStcsDay <DashboardStcsDay
startDate={dayStartDate} startDate={dayStartDate}
setStartDate={handlerStcsDayParam} setStartDate={handlerStcsDayParam}
data={dashboardData?.stcsDayList || []} data={stcsDayList || []}
/> />
</Col> </Col>
<Col lg={4} md={12} className='dashboard-chart'> <Col lg={4} md={12} className='dashboard-chart'>
{ {
// top5 지역 별 바행횟수 // top5 지역 별 바행횟수
@ -159,7 +154,7 @@ export const MainDashContainer = () => {
<DashboardStcsArea <DashboardStcsArea
startDate={areaStartDate} startDate={areaStartDate}
setStartDate={handlerStcsAreaParam} setStartDate={handlerStcsAreaParam}
// data={stcsAreaList} data={stcsAreaList || []}
title='flightsRegion' title='flightsRegion'
/> />
</Col> </Col>

5
src/modules/main/dash/apis/mainDashApi.ts

@ -8,7 +8,7 @@ export const mainDashAPI = {
addQueryPrefix: true, addQueryPrefix: true,
arrayFormat: 'repeat' arrayFormat: 'repeat'
}); });
console.log(data);
return await axios.get(`api/main/dash/stcs/day${queryString}`); return await axios.get(`api/main/dash/stcs/day${queryString}`);
}, },
stcsArea: async (data: string) => { stcsArea: async (data: string) => {
@ -42,5 +42,8 @@ export const mainDashAPI = {
}, },
dailyFlightCount: async () => { dailyFlightCount: async () => {
return await axios.get('api/main/dash/stcs/dailyflight'); return await axios.get('api/main/dash/stcs/dailyflight');
},
dronSituation: async () => {
return await axios.get('api/main/dash/stcs/dron-flight/');
} }
}; };

13
src/modules/main/dash/models/mainDashModel.ts

@ -12,6 +12,17 @@ export enum EDateType {
tomorrow = '명일' tomorrow = '명일'
} }
export enum EDronStatus {
inFlight = '비행 중',
flightComplete = '비행 완료',
flightWaiting = '비행 대기 중 '
}
export interface IDronSituation {
typeCd: string;
count: number;
}
export interface IDailyFlightPlan { export interface IDailyFlightPlan {
dateType: string; dateType: string;
plan: number; plan: number;
@ -61,10 +72,10 @@ export interface DronListData {
} }
export interface IDashBoardData { export interface IDashBoardData {
stcsDayList: StcsDayData[];
dailyFlightWarn: IDailyFlightWarn[]; dailyFlightWarn: IDailyFlightWarn[];
dailyFlightCount: IDailyFlightCount[]; dailyFlightCount: IDailyFlightCount[];
dailyFlightPlan: IDailyFlightPlan[]; dailyFlightPlan: IDailyFlightPlan[];
dronSituation: IDronSituation[];
} }
export interface IDashBoardRq { export interface IDashBoardRq {

23
src/modules/main/dash/sagas/mainDashSaga.ts

@ -1,5 +1,6 @@
import { call, put, takeEvery, all } from '@redux-saga/core/effects'; import { call, put, takeEvery, all } from '@redux-saga/core/effects';
import { ActionType } from 'typesafe-actions'; import { ActionType } from 'typesafe-actions';
import { EDronStatus } from '../models/mainDashModel';
import * as MessageActions from '../../../comn/message/actions/comnMessageAction'; import * as MessageActions from '../../../comn/message/actions/comnMessageAction';
import * as Actions from '../actions/mainDashAction'; import * as Actions from '../actions/mainDashAction';
import * as Apis from '../apis/mainDashApi'; import * as Apis from '../apis/mainDashApi';
@ -121,20 +122,17 @@ function* dashboardData(
action: ActionType<typeof Actions.DASHBOARD_DATA.request> action: ActionType<typeof Actions.DASHBOARD_DATA.request>
) { ) {
try { try {
const params = action.payload;
/* /*
stcsDayList:
dailyFlightPlan: 일일 dailyFlightPlan: 일일
dailyFlightCount: 일일 dailyFlightCount: 일일
dailyFlighWarn: 일일 dailyFlighWarn: 일일
*/ */
const { stcsDayList, dailyFlighWarn, dailyFlightPlan, dailyFlightCount } = const { dailyFlighWarn, dailyFlightPlan, dailyFlightCount, dronSituation } =
yield all({ yield all({
stcsDayList: call(Apis.mainDashAPI.stcsDay, { yyyymm: params.stcsDay }),
dailyFlighWarn: call(Apis.mainDashAPI.dailyFlightWarn), dailyFlighWarn: call(Apis.mainDashAPI.dailyFlightWarn),
dailyFlightPlan: call(Apis.mainDashAPI.dailyFlightPlan), dailyFlightPlan: call(Apis.mainDashAPI.dailyFlightPlan),
dailyFlightCount: call(Apis.mainDashAPI.dailyFlightCount) dailyFlightCount: call(Apis.mainDashAPI.dailyFlightCount),
dronSituation: call(Apis.mainDashAPI.dronSituation)
}); });
// if (errorCode) { // if (errorCode) {
@ -150,15 +148,24 @@ function* dashboardData(
// return; // return;
// } // }
let dronSituationArr: { typeCd: string; count: number }[] = [];
Object.keys(dronSituation.data).forEach(i => {
dronSituationArr.push({
typeCd: EDronStatus[`${i}`],
count: Number(dronSituation.data[i])
});
});
yield put( yield put(
Actions.DASHBOARD_DATA.success({ Actions.DASHBOARD_DATA.success({
stcsDayList: stcsDayList.data,
dailyFlightWarn: dailyFlighWarn.data.slice( dailyFlightWarn: dailyFlighWarn.data.slice(
0, 0,
dailyFlightPlan.data.length - 1 dailyFlightPlan.data.length - 1
), ),
dailyFlightCount: dailyFlightCount.data, dailyFlightCount: dailyFlightCount.data,
dailyFlightPlan: dailyFlightPlan.data dailyFlightPlan: dailyFlightPlan.data,
dronSituation: dronSituationArr
}) })
); );
} catch (error) { } catch (error) {

Loading…
Cancel
Save