Browse Source

Merge branch 'master' of http://gitea.palntour.com/pav/pav-home

feature/auth
이학준 2 years ago
parent
commit
cbb3865981
  1. 4
      .env.development
  2. 4
      .env.production
  3. 7
      src/assets/css/custom.css
  4. 29
      src/components/map/naver/NaverMap.js
  5. 127
      src/components/map/naver/draw/FlightPlanDraw.js
  6. 6
      src/components/map/naver/dron/DronHistory.js
  7. 182
      src/components/map/naver/dron/DronMarker.js
  8. 4
      src/components/map/naver/dron/DronPlan.js
  9. 2
      src/components/map/naver/search/NaverMapSearch.js
  10. 3
      src/containers/basis/flight/plan/FlightPlanDetailContainer.js
  11. 2
      src/modules/basis/flight/apis/basisFlightApi.ts
  12. 1
      src/modules/control/gp/models/controlGpModel.ts
  13. 3
      src/modules/control/gp/sagas/controlGpSaga.ts
  14. 2
      src/modules/control/map/reducers/controlMapReducer.ts
  15. 2
      src/views/control/alarm/ControlAlarmNotice.js
  16. 5
      src/views/control/main/ControlMain.js
  17. 45
      src/views/control/report/ControlReportDetail.js
  18. 786
      src/views/control/setting/ControlSetting.js

4
.env.development

@ -1,3 +1,3 @@
REACT_APP_HOST = http://localhost:8080/
REACT_APP_WS_HOST = ws://localhost:8081/ws
REACT_APP_HOST = http://192.168.0.24:8080/
REACT_APP_WS_HOST = ws://192.168.0.24:8081/ws
REACT_APP_IMAGE_HOST = https://palnet-file.s3.ap-northeast-2.amazonaws.com/

4
.env.production

@ -1,3 +1,3 @@
REACT_APP_HOST = http://control-api.palntour.com/
REACT_APP_WS_HOST = ws://control-websocket.palntour.com/ws
REACT_APP_HOST = http://pav.palntour.com:8080/
REACT_APP_WS_HOST = ws://pav.palntour.com:8081/ws
REACT_APP_IMAGE_HOST = https://palnet-file.s3.ap-northeast-2.amazonaws.com/

7
src/assets/css/custom.css

@ -737,4 +737,9 @@ background-size: 75% auto;
.m_ft{display:flex;align-items:flex-end; justify-content: space-between;}
.m_ft_box{flex:0 0 49%}
.m_ft_box + .m_ft_box{margin-left:1%}
.m_ft_box + .m_ft_box{margin-left:1%}
.layer-content-box .history-btn{border-radius:4px;display:block;width:100%;height:45px;line-height:45px;text-align:center;font-size: 0.875rem;color:#ddd;font-weight:500;}
.layer-content-box .history-btn:hover{border-radius:4px;background:#00cfe8;border-color:#00cfe8;transition: 0.3s ease;-webkit-transition: 0.3s ease;}
.historyModal .drone-ti span{font-weight:500;margin-top:6px}
.historyModal .drone-name{color:#00cfe8;margin:0 10px 0 0;}

29
src/components/map/naver/NaverMap.js

@ -1,26 +1,18 @@
import React, { useEffect, useState } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import dronicon from '../../../assets/control/icon/drone.png';
import { DronMarker } from './dron/DronMarker';
import { DronHistory } from './dron/DronHistory';
import NaverMapControl from './NaverMapControl';
import { NaverMapSearch } from './search/NaverMapSearch';
import { FeatureAirZone } from './feature/FeatureAirZone';
import geoJson from '../geojson/airArea.json';
import SensorZone from "./sensor/SensorZone";
import { controlGroupAuthAction } from '../../../modules/control/gp';
import DronPlan from './dron/DronPlan';
import DronToast from './dron/DronToast';
import { toast } from 'react-toastify';
export const NaverCustomMap = () => {
const dispatch = useDispatch();
const naver = window.naver;
// const { controlGpContains } = useSelector(state => state.controlGpFltPlanState);
const [isMapLoad, setIsMapLoad] = useState(false);
const naver = window.naver;
const [mapObject, setMapObject] = useState(null);
const [arrPolyline, setArrPolyline] = useState([]);
@ -32,16 +24,16 @@ export const NaverCustomMap = () => {
NaverMapInit();
dispatch(controlGroupAuthAction.request());
}, []);
useEffect(() => {
}, [mapObject]);
const NaverMapInit = () => {
const mapOptions = {
center: new naver.maps.LatLng(36.56793936069445, 127.85101412107547),
zoom: 10,
center: new naver.maps.LatLng(37.520357, 126.610166),
// center: new naver.maps.LatLng(36.56793936069445, 127.85101412107547),
// zoom: 10,
zoom: 14,
zoomControl: true,
mapTypeId: naver.maps.MapTypeId.HYBRID,
mapTypeId: naver.maps.MapTypeId.NORMAR,
zoomControlOptions: {
position: naver.maps.Position.TOP_LEFT,
@ -65,6 +57,7 @@ export const NaverCustomMap = () => {
map={mapObject}
naver={naver}
/>
<DronPlan
map={mapObject}
naver={naver}
@ -80,8 +73,8 @@ export const NaverCustomMap = () => {
/>
<FeatureAirZone map={mapObject} naver={naver} features={features} />
<NaverMapSearch map={mapObject} naver={naver} />
<SensorZone map={mapObject} naver={naver} />
{/* <NaverMapSearch map={mapObject} naver={naver} /> */}
{/* <SensorZone map={mapObject} naver={naver} /> */}
</>
) : null}

127
src/components/map/naver/draw/FlightPlanDraw.js

@ -2,7 +2,7 @@ import $ from 'jquery';
import { useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import * as Actions from '../../../../modules/basis/flight/actions/basisFlightAction';
import { InfoModal } from '../../../../components/modal/InfoModal';
import { InfoModal } from '../../../modal/InfoModal';
export const FlightPlanDraw = props => {
const dispatch = useDispatch();
@ -25,7 +25,7 @@ export const FlightPlanDraw = props => {
isOpen: false,
title: '',
desc: ''
});
})
const naver = props.naver;
const map = props.map;
@ -195,11 +195,16 @@ export const FlightPlanDraw = props => {
setPolyline(polyline);
setAreaInfo(polypaths);
} else {
// polyline.setMap(null);
setAlertModal({
isOpen: true,
title: '우회 여부 확인',
desc: '좌표를 두 개 점으로 이어주세요.'
})
polyline.setMap(null);
polyline = '';
}
polyline.setMap(null)
setFigure(polyline)
} else if (polygon) {
@ -212,21 +217,23 @@ export const FlightPlanDraw = props => {
lastDistance = guideline.getDistance();
guideline.getPath().push(polygonpaths[0]);
var distance = guideline.getDistance();
addMileStone(polygonpaths[0], fromMetersToText(distance - lastDistance));
// addMileStone(polygonpaths[0], fromMetersToText(distance - lastDistance));
setMarker(distanceMarker);
distanceMarker.forEach(c => c.setMap(null))
setPolygon(polygon);
setAreaInfo(polygonpaths);
if(polygonpaths.length >= 3) {
setPolygon(polygon);
setAreaInfo(polygonpaths);
} else {
polygon.setMap(null)
polygon = '';
}
polygon.setMap(null)
setFigure(polygon)
}
}
const onClickPolyline = (e) => {
console.log('onClickPolyline')
var coord = e.coord;
@ -246,9 +253,9 @@ export const FlightPlanDraw = props => {
polyline = new naver.maps.Polyline({
strokeLineCap: 'round',
strokeLineJoin: 'round',
// strokeColor: '#283046',
strokeColor: '#ff0000',
// strokeWeight: 3,
strokeColor: '#283046',
// strokeColor: '#ff0000',
strokeWeight: 1,
strokeOpacity: 1,
path: [coord],
map: map
@ -264,7 +271,8 @@ export const FlightPlanDraw = props => {
polyline.getPath().push(coord);
var distance = polyline.getDistance();
addMileStone(coord, fromMetersToText(distance - lastDistance));
// addMileStone(coord, fromMetersToText(distance - lastDistance));
addMileStone(polyline.getPath()._array, fromMetersToText(distance - lastDistance));
lastDistance = distance;
}
}
@ -313,8 +321,13 @@ export const FlightPlanDraw = props => {
polygon.getPath().push(coord);
guideline.getPath().push(coord);
// console.log(polygon.getPath()._array, 'polygon')
// console.log(guideline.getPath()._array.length, 'guide')
// console.log(polygon.getPath()._array.length)
var distance = guideline.getDistance();
addMileStone(coord, fromMetersToText(distance - lastDistance));
// addMileStone(coord, fromMetersToText(distance - lastDistance));
addMileStone(guideline.getPath()._array, fromMetersToText(distance - lastDistance));
lastDistance = distance;
}
}
@ -647,8 +660,8 @@ export const FlightPlanDraw = props => {
new naver.maps.Marker({
position: paths[i],
icon: {
content: '<div style="display:inline-block;padding:5px;text-align:center;background-color:#fff;border:1px solid #000;font-size:13px;color:#737373;"><span>'+ 'Start' +'</span></div>',
anchor: new naver.maps.Point(-5, -5)
content: '<div style="display:inline-block;padding:5px;text-align:center;background-color:#fff;border:1px solid #000;font-size:13px;color:#ff0000;"><span>'+ 'Start' +'</span></div>',
anchor: new naver.maps.Point(45, 35)
}, map: map
})
)
@ -658,12 +671,17 @@ export const FlightPlanDraw = props => {
let text = fromMetersToText(r);
let dis1 = paths[i-1]
let dis2 = paths[i]
let midPoint = new naver.maps.LatLng((dis1.y + dis2.y)/2, (dis1.x + dis2.x)/2);
distanceMarker.push(
new naver.maps.Marker({
position: paths[i],
// position: paths[i],
position: midPoint,
icon: {
content: '<div style="display:inline-block;padding:5px;text-align:center;background-color:#fff;border:1px solid #000;font-size:13px;color:#737373;"><span>'+ text +'</span></div>',
anchor: new naver.maps.Point(-5, -5)
anchor: new naver.maps.Point(20, 35)
}, map: map
})
)
@ -715,48 +733,58 @@ export const FlightPlanDraw = props => {
}
for(let i = 0; i < paths.length+1; i++) {
//start
if(i == 0) {
distanceMarker.push(
new naver.maps.Marker({
position: paths[i],
position: paths[0],
icon: {
content: '<div style="display:inline-block;padding:5px;text-align:center;background-color:#fff;border:1px solid #000;font-size:13px;color:#737373;"><span>'+ 'Start' +'</span></div>',
anchor: new naver.maps.Point(-5, -5)
content: '<div style="display:inline-block;padding:5px;text-align:center;background-color:#fff;border:1px solid #000;font-size:13px;color:#ff0000;"><span>'+ 'Start' +'</span></div>',
anchor: new naver.maps.Point(45, 35)
},
map: map
})
)
//첫좌표이자 마지막 좌표
} else if(i == paths.length) {
var proj = map.getProjection(),
r = proj.getDistance(paths[0], paths[i-1]);
let text = fromMetersToText(r);
let dis1 = paths[0]
let dis2 = paths[i-1]
let midPoint = new naver.maps.LatLng((dis1.y + dis2.y)/2, (dis1.x + dis2.x)/2);
distanceMarker.push(
new naver.maps.Marker({
position: paths[0],
// position: paths[0],
position: midPoint,
icon: {
content: '<div style="display:inline-block;padding:5px;text-align:center;background-color:#fff;border:1px solid #000;font-size:13px;color:#737373;"><span>'+ text +'</span></div>',
anchor: new naver.maps.Point(45, 35)
anchor: new naver.maps.Point(0, 35)
},
map: map
})
)
} else if(i == paths.length-1) {
// let tt = new naver.maps.EPSG3857.getDistance(paths[i], paths[])
//그 외 나머지
} else {
var proj = map.getProjection(),
r = proj.getDistance(paths[i-1], paths[i]);
let text = fromMetersToText(r);
let dis1 = paths[i-1]
let dis2 = paths[i]
let midPoint = new naver.maps.LatLng((dis1.y + dis2.y)/2, (dis1.x + dis2.x)/2);
distanceMarker.push(
new naver.maps.Marker({
position: paths[i],
// position: paths[i],
position: midPoint,
icon: {
content: '<div style="display:inline-block;padding:5px;text-align:center;background-color:#fff;border:1px solid #000;font-size:13px;color:#737373;"><span>'+ text +'</span></div>',
anchor: new naver.maps.Point(-5, -5)
anchor: new naver.maps.Point(20, 35)
},
map: map
})
@ -811,17 +839,29 @@ export const FlightPlanDraw = props => {
//div로 보여주기
const addMileStone = (coord, text) => {
let content;
let midPoint;
let anchor;
if(text == 'Start') {
content = '<div style="display:inline-block;padding:5px;text-align:center;background-color:#fff;border:1px solid #000;font-size:14px;color:#ff0000;"><span>'+ text +'</span></div>'
content = '<div style="display:inline-block;padding:5px;text-align:center;background-color:#fff;border:1px solid #000;font-size:13px;color:#ff0000;"><span>'+ text +'</span></div>'
midPoint = coord
anchor = new naver.maps.Point(45, 35)
} else {
content = '<div style="display:inline-block;padding:5px;text-align:center;background-color:#fff;border:1px solid #000;font-size:13px;color:#ff0000;"><span>'+ text +'</span></div>'
let dis1 = coord[coord.length-2];
let dis2 = coord[coord.length-1];
if(circle) {
midPoint = coord
} else {
midPoint = new naver.maps.LatLng((dis1.y + dis2.y)/2, (dis1.x + dis2.x)/2);
}
anchor = new naver.maps.Point(20, 35)
}
var marker = new naver.maps.Marker({
position: coord,
position: midPoint,
icon: {
content: content,
anchor: new naver.maps.Point(-5, -5)
anchor: anchor
},
// map: map
});
@ -842,20 +882,19 @@ export const FlightPlanDraw = props => {
var km = 1000,
text = meters;
text = parseFloat(meters.toFixed(1)) + 'm';
if(meters >= km) {
text = parseFloat((meters / km).toFixed(1)) + 'km';
} else {
text = parseFloat(meters.toFixed(1)) + 'm';
}
// if(meters >= km) {
// text = parseFloat((meters / km).toFixed(1)) + 'km';
// } else {
// text = parseFloat(meters.toFixed(1)) + 'm';
// }
return text;
}
return(
<InfoModal modal={alertModal} setModal={setAlertModal} />
return(
<InfoModal modal={alertModal} setModal={setAlertModal} />
)
};
export default FlightPlanDraw;
};

6
src/components/map/naver/dron/DronHistory.js

@ -14,9 +14,7 @@ export const DronHistory = props => {
const dispatch = useDispatch();
useEffect(() => {
// console.log('>>>', controlGpHistory);
// polylineRemove();
useEffect(() => {
polylineInit();
}, [controlGpHistory]);
@ -29,7 +27,7 @@ export const DronHistory = props => {
}, [objectId, isClickObject]);
const polylineRemove = () => {
console.log(props.arrPolyline);
// console.log(props.arrPolyline);
if (props.arrPolyline) {
props.arrPolyline.map(item => {
item.setMap(null);

182
src/components/map/naver/dron/DronMarker.js

@ -1,3 +1,4 @@
import $ from 'jquery';
import { useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import '../../../../assets/css/custom.css';
@ -16,40 +17,43 @@ export const DronMarker = props => {
const { objectId, isClickObject } = useSelector(state => state.controlMapReducer);
const [arrMarkers, setArrMarkers] = useState([]);
const [arrInfos, setArrInfos] = useState([]);
let naver = props.naver;
let map = props.map;
let CustomOverlay;
var contentString = ['<div class="iw_inner"> dddd', '</div>'].join('');
var infowindow = new naver.maps.InfoWindow({
content: contentString
});
useEffect(() => {
if(arrMarkers.length != 0) markerInfo(arrMarkers)
}, [arrMarkers])
useEffect(() => {
markerInit();
if (controlGpList) {
controlGpList.forEach(gps => {
if (!gps.controlWarnCd) {
// gps marker가 지도상에 표출된 이후 시점부터 toast 표출
const marker = arrMarkers.find(marker => marker.id === gps.objectId);
if(marker) {
toast.info(
<DronToast
title={`${gps.objectId} 비정상 상황 알림`}
message={'경로 상에 비행 구역을 이탈했습니다.'}
/>
, {
autoClose: 3000,
hideProgressBar: true,
position: toast.POSITION.BOTTOM_RIGHT,
onClick: props => {
if(marker) handlerDronClick(marker);
}
if (gps.controlWarnCd && gps.controlWarnNotyCd) {
toast.info(
<DronToast
title={`${gps.objectId} 비정상 상황 알림`}
message={'경로 상에 비행 구역을 이탈했습니다.'}
/>,
{
// autoClose: 3000,
hideProgressBar: true,
position: toast.POSITION.BOTTOM_RIGHT,
onClick: props => {
handlerDronClick(gps.controlId, gps.objectId);
}
)
}
}
)
}
})
}
@ -86,7 +90,7 @@ export const DronMarker = props => {
//마커를 그린다.
const addMarkers = (position, id, controlId) => {
var marker = new naver.maps.Marker({
let marker = new naver.maps.Marker({
position: position,
title: id,
id: id,
@ -105,23 +109,25 @@ export const DronMarker = props => {
marker.setMap(props.map);
// drone 정보 창
naver.maps.Event.addListener(marker, 'click', function (e) {
handlerDronClick(marker);
handlerDronClick(marker.controlId, marker.id);
});
setArrMarkers(m => [...m, marker]);
// markerInfo(marker, position, id);
};
const handlerDronClick = marker => {
const idntfNum = marker.id;
const contorlId = marker.controlId;
const handlerDronClick = (controlId, idntfNum) => {
// const idntfNum = marker.id;
// const contorlId = marker.controlId;
// 클릭한 식별번호 정보를 가진 그룹 추출
// const group = controlGroupAuthInfo.find(group => group.idntfNum === idntfNum);
//히스토리 불러오기
dispatch(objectClickAction(contorlId));
dispatch(controlGpDtlAction.request(contorlId));
dispatch(objectClickAction(controlId));
dispatch(controlGpDtlAction.request(controlId));
dispatch(controlGpFlightPlanAction.request(idntfNum));
};
@ -130,11 +136,19 @@ export const DronMarker = props => {
marker.setMap(null);
};
const removeInfos = info => {
info.setMap(null);
}
//마커에 위치를 이동한다.
const moveMarkers = (marker, position) => {
marker.setPosition(position);
};
const moveInfos = (info, position) => {
info.setPosition(position);
};
//데이터가 없는 마커를 모두 삭제 한다.
const allRemoveMarkers = () => {
if (arrMarkers && controlGpList) {
@ -152,6 +166,20 @@ export const DronMarker = props => {
dispatch(objectUnClickAction());
}
});
arrInfos.map(info => {
const isExists = controlGpList.find(
item => item.objectId === info._id
);
if (!isExists) {
removeInfos(info);
const arrData = arrInfos.filter(
item => item.id != info._id
);
removeArrInfos(arrData);
dispatch(objectUnClickAction());
}
});
}
};
@ -168,6 +196,7 @@ export const DronMarker = props => {
);
if (isExists) {
moveMarkers(isExists, position);
moveInfos(isExists, position);
} else {
addMarkers(position, item.objectId, item.controlId);
}
@ -178,9 +207,108 @@ export const DronMarker = props => {
}
};
//운항정보 창 셋팅
const infoInit = (marker, gps) => {
CustomOverlay = function(options) {
this._element = $(`
<div class="tooltip-box" style="width: 150px;">
<div class="tooltip-ti">
<span>${marker.id}</span>
</div>
<div class="tooltip-txt>
<div class="tooltip-txt-list">
<div>
<span style="width: 120px; display: inline-block;">속도: ${gps.speed}${gps.speedType}</span>
</div>
<div>
<span style="width: 120px; display: inline-block;">고도: ${gps.elev}${gps.elevType}</span>
</div>
<div>
<span style="width: 120px; display: inline-block;">헤딩방향: ${gps.heading}</span>
</div>
</div>
</div>
</div>
`)
this.setPosition(options.position);
this.setMap(options.map || null);
this.setId(options.id);
};
CustomOverlay.prototype = new naver.maps.OverlayView();
CustomOverlay.prototype.constructor = CustomOverlay;
//메소드 재정의
//필수
CustomOverlay.prototype.onAdd = function() {
var overlayLayer = this.getPanes().overlayLayer;
this._element.appendTo(overlayLayer);
};
CustomOverlay.prototype.draw = function() {
if (!this.getMap()) {
return;
}
var projection = this.getProjection(),
position = this.getPosition(),
pixelPosition = projection.fromCoordToOffset(position);
this._element.css('left', pixelPosition.x);
this._element.css('top', pixelPosition.y);
};
CustomOverlay.prototype.onRemove = function() {
var overlayLayer = this.getPanes().overlayLayer;
this._element.remove();
this._element.off();
};
//속성
CustomOverlay.prototype.setPosition = function(position) {
this._position = position;
this.draw();
};
CustomOverlay.prototype.getPosition = function() {
return this._position;
};
CustomOverlay.prototype.setId = function(id) {
this._id = id;
};
CustomOverlay.prototype.getId = function(id) {
return this._id;
};
}
const removeArrMarkers = arrData => {
setArrMarkers(arrData);
};
const removeArrInfos = arrData => {
setArrInfos(arrData);
};
const markerInfo = (arrMarkers) => {
arrMarkers.forEach((marker, idx) => {
infoInit(marker, controlGpList[idx]);
if(controlGpList.length != 0) {
const info = new CustomOverlay({
position: new naver.maps.LatLng(controlGpList[idx].lat, controlGpList[idx].lng),
map: map,
id: marker.id
});
// console.log(info)
setArrInfos(m => [...m, info]);
}
});
}
return null;
};

4
src/components/map/naver/dron/DronPlan.js

@ -11,9 +11,7 @@ const DronPlan = ({ naver, map }) => {
const { controlGpList } = useSelector(state => state.controlGpState);
const { controlGpFltPlanList } = useSelector(state => state.controlGpFltPlanState);
const { objectId, isClickObject } = useSelector(state => state.controlMapReducer);
const { controlGpContains } = useSelector(state => state.controlGpFltPlanState);
const [area, setArea] = useState(); // 비행 구역 관리
const [buffer, setBuffer] = useState(); // 버퍼 구역 관리
const [controlId, setControlId] = useState(); // 식별번호 저장

2
src/components/map/naver/search/NaverMapSearch.js

@ -14,7 +14,7 @@ export const NaverMapSearch = props => {
var result = response.result, // 검색 결과의 컨테이너
items = result.items; // 검색 결과의 배열
console.log(result);
// console.log(result);
// do Something
}

3
src/containers/basis/flight/plan/FlightPlanDetailContainer.js

@ -388,8 +388,11 @@ const FlightPlanDetailContainer = () => {
}
// 삭제
const handleDelete = () => {
if(!urlParams.planSno || urlParams.planSno){
dispatch(Actions.FLIGHT_PLAN_DELETE.request(urlParams.planSno));
}
dispatch(Actions.FLIGHT_PLAN_GROUP_SELECT({cstmrSno: 0, groupId: '', groupNm: ''}));
}
return (
<CustomDetailLayout title={"비행 계획 신청서"}>

2
src/modules/basis/flight/apis/basisFlightApi.ts

@ -35,7 +35,7 @@ export const flightPlanAPI = {
return res;
},
delete: async (planSno: number) => {
const res = await axios.get(`api/bas/flight/plan/delete/${planSno}`);
const res = await axios.delete(`api/bas/flight/plan/delete/${planSno}`);
return res;
},
listPilot: async (groupId: string) => {

1
src/modules/control/gp/models/controlGpModel.ts

@ -89,6 +89,7 @@ export interface ControlGpData {
controlStartDt: string;
heading: number;
controlWarnCd: boolean;
controlWarnNotyCd: boolean;
}
export interface ControlGroupAuthData {

3
src/modules/control/gp/sagas/controlGpSaga.ts

@ -14,8 +14,7 @@ function* getControlGpSaga(
const data = action.payload;
const state = yield select();
const { objectId, isClickObject } = state.controlMapReducer;
const { controlGroupAuthInfo } = state.controlGroupAuthState;
const { controlGpFltPlanList } = state.controlGpFltPlanState;
const { controlGroupAuthInfo } = state.controlGroupAuthState;
const { controlGpHistory } = state.controlGpHisState;
let gpsData: ControlGpData[] = [];

2
src/modules/control/map/reducers/controlMapReducer.ts

@ -1,6 +1,6 @@
// ** Initial State
const initialState = {
mapType: 'HYBRID',
mapType: 'NORMAL',
objectId: null,
isClickObject: false,
area0001: true, // 비행금지 구역

2
src/views/control/alarm/ControlAlarmNotice.js

@ -2,7 +2,7 @@ import { Bell, ChevronDown, ChevronUp } from "react-feather";
import { ReactComponent as DroneMenuIcon } from '../../../assets/images/drone_menu_icon.svg';
const ControlAlarmNotice = () => {
{/* 알림 위아래 롤링은 구현해주셔야되는데 따른 컴포넌트있으면 그거사용해도됩니다...제가 만들어논거는 45px씩 움직여주면되거든요..저도자세히는모르겠습니다...제이쿼리로만써봐서... */}
{}
return(
<div>

5
src/views/control/main/ControlMain.js

@ -76,6 +76,11 @@ const ControlMain = () => {
<DroneMenuIcon width='30' height='30' />
</button>
</li>
<li>
<button>
<Bell width='20' height='20' />
</button>
</li>
{/* <li>
<button onClick={() => openMenu('weatherList')}>
<Sun size={25} />

45
src/views/control/report/ControlReportDetail.js

@ -1,5 +1,6 @@
import moment from 'moment';
import React from 'react';
import { useState, useEffect } from 'react';
import { X } from 'react-feather';
import { useDispatch, useSelector } from 'react-redux';
import drone_img from '../../../assets/images/drone.jpg';
@ -10,8 +11,10 @@ import {
GET_ARCTFT_TYPE_CD,
GET_WGHT_TYPE_CD
} from '../../../utility/CondeUtil';
import { Button, Modal, ModalHeader, ModalBody, ModalFooter } from 'reactstrap'
const ControlReportDetail = props => {
const [historyModal, setHistoryModal] = useState(false);
const dispatch = useDispatch();
const { controlGpDetail, controlDetail } = useSelector(
@ -34,7 +37,6 @@ const ControlReportDetail = props => {
return '-';
}
};
return (
<div className='left-layer'>
<div className='layer-content'>
@ -49,6 +51,47 @@ const ControlReportDetail = props => {
<X size={20} />
</button>
</div>
<div className='layer-content-box mb-1'>
<button type="button" className='history-btn'onClick={() => setHistoryModal(!historyModal)}>비정상상황 알림내역</button>
</div>
<Modal
isOpen={historyModal}
toggle={() => setHistoryModal(!historyModal)}
className='modal-dialog-centered historyModal'
>
<ModalHeader toggle={() => setHistoryModal(!historyModal)}>
<div className='drone-ti'>
<span className="drone-name">DRONE01</span>
<span>알림내역</span>
</div>
</ModalHeader>
<ModalBody>
<table className='table pal-table'>
<tr>
<th>번호</th>
<th>날짜</th>
<th>내용</th>
</tr>
<tr>
<th>1</th>
<th>2022-08-12 22:12:05</th>
<th>탈출!!비상탈출!!!</th>
</tr>
</table>
</ModalBody>
<ModalFooter>
<Button
color='info'
onClick={() => setHistoryModal(!historyModal)}
>
확인
</Button>
</ModalFooter>
</Modal>
<div className='layer-content-box'>
<div className='drone-ti'>
<img src={drone_yellow} width='40' />

786
src/views/control/setting/ControlSetting.js

@ -5,544 +5,274 @@ import { CgTrees } from 'react-icons/cg';
import { VscRadioTower } from 'react-icons/vsc';
import { useDispatch, useSelector } from 'react-redux';
import {
Button,
InputGroup,
ButtonGroup,
InputGroupAddon,
Input,
CustomInput
Button,
InputGroup,
ButtonGroup,
InputGroupAddon,
Input,
CustomInput
} from 'reactstrap';
import {
areaClickAction, environmentClickAction,
mapTypeChangeAction, sensorClickAction
areaClickAction, environmentClickAction,
mapTypeChangeAction, sensorClickAction
} from '../../../modules/control/map/actions/controlMapActions';
const ControlSetting = props => {
const dispatch = useDispatch();
const dispatch = useDispatch();
const mapControl = useSelector(state => state.controlMapReducer);
const mapControl = useSelector(state => state.controlMapReducer);
// console.log('111111111111111');
// useEffect(() => {
// console.log('111111111111111');
// }, []);
useEffect(() => {
console.log('>>>>', mapControl);
}, [mapControl]);
const handlerMapType = val => {
dispatch(mapTypeChangeAction(val));
};
const handlerMapType = val => {
dispatch(mapTypeChangeAction(val));
};
const handlerAreaClick = val => {
dispatch(areaClickAction(val));
};
const handlerAreaClick = val => {
dispatch(areaClickAction(val));
};
const handlerSensorClick = (val, isChecked) => {
if (isChecked) {
dispatch(sensorClickAction(val));
} else {
dispatch(sensorClickAction(''));
}
};
const handlerSensorClick = (val, isChecked) => {
if(isChecked){
dispatch(sensorClickAction(val));
} else {
dispatch(sensorClickAction(''));
}
};
return (
<div className=''>
<div className='layer-content'>
<div className='layer-ti'>
<h4>지도유형</h4>
{/* <button className='btn-icon' outline color='primary'><X size={20} /></button> */}
</div>
<div className='map-btn'>
<ButtonGroup>
<Button
color={mapControl.mapType === 'HYBRID' ? 'primary' : ''}
onClick={e => handlerMapType('HYBRID')}
>
위성지도
</Button>
<Button
color={mapControl.mapType === 'NORMAL' ? 'primary' : ''}
onClick={e => handlerMapType('NORMAL')}
>
일반지도
</Button>
<Button
color={mapControl.mapType === 'TERRAIN' ? 'primary' : ''}
onClick={e => handlerMapType('TERRAIN')}
>
지형지도
</Button>
</ButtonGroup>
</div>
</div>
{/* <div className='layer-content'>
<div className='layer-ti'>
<h4>지역검색</h4>
</div>
<div className='layer-search'>
<InputGroup>
<Input type='text' placeholder='검색어를 입력하세요' />
<Button color='primary' outline>
<Search size={18} />
</Button>
</InputGroup>
</div>
</div>
<div className='layer-content'>
<div className='layer-ti'>
<h4>드론 중량</h4>
</div>
<div className='layer-content-box'>
<div className='layer-content-info layer-switch-list'>
<dl>
<dt>
<div className='list-left-txt'>전체</div>
<div className='list-right-txt'>
<CustomInput
onClick={e => console.log(1111)}
className='custom-control-primary'
type='switch'
id='test11'
name='test02'
inline
/>
</div>
</dt>
<dt>
<div className='list-left-txt'>250g 이하</div>
<div className='list-right-txt'>
<CustomInput
className='custom-control-primary'
type='switch'
id='test12'
name='test02'
inline
/>
</div>
</dt>
<dt>
<div className='list-left-txt'>250g 초과~2kg 이하</div>
<div className='list-right-txt'>
<CustomInput
className='custom-control-primary'
type='switch'
id='test13'
name='test03'
inline
/>
</div>
</dt>
<dt>
<div className='list-left-txt'>2kg 초과~7kg 이하</div>
<div className='list-right-txt'>
<CustomInput
className='custom-control-primary'
type='switch'
id='test14'
name='test04'
inline
/>
</div>
</dt>
<dt>
<div className='list-left-txt'>7kg 초과~25kg 이하</div>
<div className='list-right-txt'>
<CustomInput
className='custom-control-primary'
type='switch'
id='test15'
name='test05'
inline
/>
</div>
</dt>
<dt>
<div className='list-left-txt'>25kg 초과~150kg 이하</div>
<div className='list-right-txt'>
<CustomInput
className='custom-control-primary'
type='switch'
id='test16'
name='test05'
inline
/>
</div>
</dt>
</dl>
</div>
</div>
</div>
<div className='layer-content'>
<div className='layer-ti'>
<h4>드론 상태</h4>
</div>
<div className='layer-content-box'>
<div className='layer-content-info layer-switch-list'>
<dl>
<dt>
<div className='list-left-txt'>전체</div>
<div className='list-right-txt'>
<CustomInput
className='custom-control-primary'
type='switch'
id='test17'
name='test02'
inline
/>
</div>
</dt>
<dt>
<div className='list-left-txt'>Arming</div>
<div className='list-right-txt'>
<CustomInput
className='custom-control-primary'
type='switch'
id='test18'
name='test02'
inline
/>
</div>
</dt>
<dt>
<div className='list-left-txt'>Landing</div>
<div className='list-right-txt'>
<CustomInput
className='custom-control-primary'
type='switch'
id='test19'
name='test03'
inline
/>
</div>
</dt>
<dt>
<div className='list-left-txt'>Take off</div>
<div className='list-right-txt'>
<CustomInput
className='custom-control-primary'
type='switch'
id='test20'
name='test04'
inline
/>
</div>
</dt>
<dt>
<div className='list-left-txt'>Flight</div>
<div className='list-right-txt'>
<CustomInput
className='custom-control-primary'
type='switch'
id='test21'
name='test05'
inline
/>
</div>
</dt>
</dl>
</div>
</div>
</div> */}
<div className='layer-content'>
<div className='layer-ti'>
<h4>공역 표출 정보</h4>
</div>
<div className='layer-content-box'>
<div className='layer-content-info layer-switch-list'>
<dl>
<dt>
<div className='list-left-txt'>
<span className='dot-icon color-red'></span>
</div>
<div className='list-right-txt'>
<CustomInput
onClick={e => handlerAreaClick('0001')}
className='custom-control-primary'
type='switch'
id='test01'
name='test01'
inline
defaultChecked={mapControl.area0001}
/>
</div>
</dt>
<dt>
<div className='list-left-txt'>
<span className='dot-icon color-pink'></span>
</div>
<div className='list-right-txt'>
<CustomInput
onClick={e => handlerAreaClick('0002')}
className='custom-control-primary'
type='switch'
id='test02'
name='test02'
inline
defaultChecked={mapControl.area0002}
/>
</div>
</dt>
<dt>
<div className='list-left-txt'>
<span className='dot-icon color-orange'></span>()
</div>
<div className='list-right-txt'>
<CustomInput
onClick={e => handlerAreaClick('0003')}
className='custom-control-primary'
type='switch'
id='test03'
name='test03'
inline
defaultChecked={mapControl.area0003}
/>
</div>
</dt>
<dt>
<div className='list-left-txt'>
<span className='dot-icon color-brown'></span>()
</div>
<div className='list-right-txt'>
<CustomInput
onClick={e => handlerAreaClick('0004')}
className='custom-control-primary'
type='switch'
id='test04'
name='test04'
inline
defaultChecked={mapControl.area0004}
/>
</div>
</dt>
<dt>
<div className='list-left-txt'>
<span className='dot-icon color-purple'></span>
</div>
<div className='list-right-txt'>
<CustomInput
onClick={e => handlerAreaClick('0005')}
className='custom-control-primary'
type='switch'
id='test05'
name='test05'
inline
defaultChecked={mapControl.area0005}
/>
</div>
</dt>
<dt>
<div className='list-left-txt'>
<span className='dot-icon color-skyblue'></span>
초경량비행장치공역
</div>
<div className='list-right-txt'>
<CustomInput
onClick={e => handlerAreaClick('0006')}
className='custom-control-primary'
type='switch'
id='test06'
name='test06'
inline
defaultChecked={mapControl.area0006}
/>
</div>
</dt>
</dl>
</div>
</div>
</div>
{/* <div className='layer-content'>
<div className='layer-ti'>
<h4>장애물 표출 정보</h4>
</div>
<div className='layer-content-box'>
<div className='layer-content-info layer-switch-list'>
<dl>
<dt>
<div className='list-left-txt'>
<BiGridAlt size={20} />
전체장애물
</div>
<div className='list-right-txt'>
<CustomInput
className='custom-control-primary'
type='switch'
id='test06'
name='test06'
inline
/>
</div>
</dt>
<dt>
<div className='list-left-txt'>
<BiBuildings size={22} />
고층 건물
</div>
<div className='list-right-txt'>
<CustomInput
className='custom-control-primary'
type='switch'
id='test07'
name='test06'
inline
/>
</div>
</dt>
<dt>
<div className='list-left-txt'>
<VscRadioTower size={22} />
송전탑
</div>
<div className='list-right-txt'>
<CustomInput
className='custom-control-primary'
type='switch'
id='test08'
name='test06'
inline
/>
</div>
</dt>
<dt>
<div className='list-left-txt'>
<CgTrees size={22} />
국립공원
</div>
<div className='list-right-txt'>
<CustomInput
className='custom-control-primary'
type='switch'
id='test09'
name='test06'
inline
/>
</div>
</dt>
</dl>
</div>
</div>
</div>
<div className='layer-content'>
<div className='layer-ti'>
<h4>NOTAM 정보</h4>
</div>
<div className='layer-content-box'>
<div className='layer-content-info layer-switch-list'>
<dl>
<dt>
<div className='list-left-txt'>NOTAM</div>
<div className='list-right-txt'>
<CustomInput
className='custom-control-primary'
type='switch'
id='test10'
name='test06'
inline
/>
</div>
</dt>
</dl>
</div>
</div>
</div> */}
<div className='layer-content'>
<div className='layer-ti'>
<h4>환경지표</h4>
</div>
<div className='layer-content-box'>
<div className='layer-content-info layer-switch-list'>
<dl>
<dt>
<div className='list-left-txt'>
<span className='dot-icon color-red'></span>(DUST)
</div>
<div className='list-right-txt'>
<CustomInput
onChange={e => handlerSensorClick('dust', e.target.checked)}
className='custom-control-primary'
type='switch'
id='sensorDust'
name='sensorDust'
inline
checked={mapControl.sensor === 'dust'}
// defaultChecked={mapControl.sensor === 'dust'}
/>
</div>
</dt>
<dt>
<div className='list-left-txt'>
<span className='dot-icon color-pink'></span>(O3)
</div>
<div className='list-right-txt'>
<CustomInput
onChange={e => handlerSensorClick('o3', e.target.checked)}
className='custom-control-primary'
type='switch'
id='sensorO3'
name='sensorO3'
inline
checked={mapControl.sensor === 'o3'}
// defaultChecked={mapControl.sensor === 'o3'}
/>
</div>
</dt>
<dt>
<div className='list-left-txt'>
<span className='dot-icon color-orange'></span>(No2)
</div>
<div className='list-right-txt'>
<CustomInput
onChange={e => handlerSensorClick('no2', e.target.checked)}
className='custom-control-primary'
type='switch'
id='sensorNo2'
name='sensorNo2'
inline
checked={mapControl.sensor === 'no2'}
// defaultChecked={mapControl.sensor === 'no2'}
/>
</div>
</dt>
<dt>
<div className='list-left-txt'>
<span className='dot-icon color-brown'></span>(Co)
</div>
<div className='list-right-txt'>
<CustomInput
onChange={e => handlerSensorClick('co', e.target.checked)}
className='custom-control-primary'
type='switch'
id='sensorCo'
name='sensorCo'
inline
checked={mapControl.sensor === 'co'}
// defaultChecked={mapControl.sensor === 'co'}
/>
</div>
</dt>
<dt>
<div className='list-left-txt'>
<span className='dot-icon color-purple'></span>(So2)
</div>
<div className='list-right-txt'>
<CustomInput
onChange={e => handlerSensorClick('so2', e.target.checked)}
className='custom-control-primary'
type='switch'
id='sensorSo2'
name='sensorSo2'
inline
checked={mapControl.sensor === 'so2'}
// defaultChecked={mapControl.sensor === 'so2'}
/>
</div>
</dt>
</dl>
</div>
return (
<div className=''>
<div className='layer-content'>
<div className='layer-ti'>
<h4>지도유형</h4>
{/* <button className='btn-icon' outline color='primary'><X size={20} /></button> */}
</div>
<div className='map-btn'>
<ButtonGroup>
<Button
color={mapControl.mapType === 'HYBRID' ? 'primary' : ''}
onClick={e => handlerMapType('HYBRID')}
>
위성지도
</Button>
<Button
color={mapControl.mapType === 'NORMAL' ? 'primary' : ''}
onClick={e => handlerMapType('NORMAL')}
>
일반지도
</Button>
<Button
color={mapControl.mapType === 'TERRAIN' ? 'primary' : ''}
onClick={e => handlerMapType('TERRAIN')}
>
지형지도
</Button>
</ButtonGroup>
</div>
</div>
<div className='layer-content'>
<div className='layer-ti'>
<h4>공역 표출 정보</h4>
</div>
<div className='layer-content-box'>
<div className='layer-content-info layer-switch-list'>
<dl>
<dt>
<div className='list-left-txt'>
<span className='dot-icon color-red'></span>
</div>
<div className='list-right-txt'>
<CustomInput
onClick={e => handlerAreaClick('0001')}
className='custom-control-primary'
type='switch'
id='test01'
name='test01'
inline
defaultChecked={mapControl.area0001}
/>
</div>
</dt>
<dt>
<div className='list-left-txt'>
<span className='dot-icon color-pink'></span>
</div>
<div className='list-right-txt'>
<CustomInput
onClick={e => handlerAreaClick('0002')}
className='custom-control-primary'
type='switch'
id='test02'
name='test02'
inline
defaultChecked={mapControl.area0002}
/>
</div>
</dt>
<dt>
<div className='list-left-txt'>
<span className='dot-icon color-orange'></span>()
</div>
<div className='list-right-txt'>
<CustomInput
onClick={e => handlerAreaClick('0003')}
className='custom-control-primary'
type='switch'
id='test03'
name='test03'
inline
defaultChecked={mapControl.area0003}
/>
</div>
</dt>
<dt>
<div className='list-left-txt'>
<span className='dot-icon color-brown'></span>()
</div>
<div className='list-right-txt'>
<CustomInput
onClick={e => handlerAreaClick('0004')}
className='custom-control-primary'
type='switch'
id='test04'
name='test04'
inline
defaultChecked={mapControl.area0004}
/>
</div>
</dt>
<dt>
<div className='list-left-txt'>
<span className='dot-icon color-purple'></span>
</div>
<div className='list-right-txt'>
<CustomInput
onClick={e => handlerAreaClick('0005')}
className='custom-control-primary'
type='switch'
id='test05'
name='test05'
inline
defaultChecked={mapControl.area0005}
/>
</div>
</dt>
<dt>
<div className='list-left-txt'>
<span className='dot-icon color-skyblue'></span>
초경량비행장치공역
</div>
<div className='list-right-txt'>
<CustomInput
onClick={e => handlerAreaClick('0006')}
className='custom-control-primary'
type='switch'
id='test06'
name='test06'
inline
defaultChecked={mapControl.area0006}
/>
</div>
</dt>
</dl>
</div>
</div>
</div>
{/* <div className='layer-content'>
<div className='layer-ti'>
<h4>환경지표</h4>
</div>
<div className='layer-content-box'>
<div className='layer-content-info layer-switch-list'>
<dl>
<dt>
<div className='list-left-txt'>
<span className='dot-icon color-red'></span>(DUST)
</div>
<div className='list-right-txt'>
<CustomInput
onChange={e => handlerSensorClick('dust', e.target.checked)}
className='custom-control-primary'
type='switch'
id='sensorDust'
name='sensorDust'
inline
checked={mapControl.sensor === 'dust'}
// defaultChecked={mapControl.sensor === 'dust'}
/>
</div>
</dt>
<dt>
<div className='list-left-txt'>
<span className='dot-icon color-pink'></span>(O3)
</div>
<div className='list-right-txt'>
<CustomInput
onChange={e => handlerSensorClick('o3', e.target.checked)}
className='custom-control-primary'
type='switch'
id='sensorO3'
name='sensorO3'
inline
checked={mapControl.sensor === 'o3'}
// defaultChecked={mapControl.sensor === 'o3'}
/>
</div>
</dt>
<dt>
<div className='list-left-txt'>
<span className='dot-icon color-orange'></span>(No2)
</div>
<div className='list-right-txt'>
<CustomInput
onChange={e => handlerSensorClick('no2', e.target.checked)}
className='custom-control-primary'
type='switch'
id='sensorNo2'
name='sensorNo2'
inline
checked={mapControl.sensor === 'no2'}
// defaultChecked={mapControl.sensor === 'no2'}
/>
</div>
</dt>
<dt>
<div className='list-left-txt'>
<span className='dot-icon color-brown'></span>(Co)
</div>
<div className='list-right-txt'>
<CustomInput
onChange={e => handlerSensorClick('co', e.target.checked)}
className='custom-control-primary'
type='switch'
id='sensorCo'
name='sensorCo'
inline
checked={mapControl.sensor === 'co'}
// defaultChecked={mapControl.sensor === 'co'}
/>
</div>
</dt>
<dt>
<div className='list-left-txt'>
<span className='dot-icon color-purple'></span>(So2)
</div>
<div className='list-right-txt'>
<CustomInput
onChange={e => handlerSensorClick('so2', e.target.checked)}
className='custom-control-primary'
type='switch'
id='sensorSo2'
name='sensorSo2'
inline
checked={mapControl.sensor === 'so2'}
// defaultChecked={mapControl.sensor === 'so2'}
/>
</div>
</dt>
</dl>
</div>
</div>
</div> */}
</div>
</div>
</div>
);
);
};
export default ControlSetting;

Loading…
Cancel
Save